2385 lines
105 KiB
C
2385 lines
105 KiB
C
//patch.c
|
||
//
|
||
/*
|
||
The MIT License (MIT)
|
||
Copyright (c) 2012-2018 HouSisong
|
||
|
||
Permission is hereby granted, free of charge, to any person
|
||
obtaining a copy of this software and associated documentation
|
||
files (the "Software"), to deal in the Software without
|
||
restriction, including without limitation the rights to use,
|
||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
copies of the Software, and to permit persons to whom the
|
||
Software is furnished to do so, subject to the following
|
||
conditions:
|
||
|
||
The above copyright notice and this permission notice shall be
|
||
included in all copies of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
OTHER DEALINGS IN THE SOFTWARE.
|
||
*/
|
||
#include "patch.h"
|
||
#if (_IS_NEED_CACHE_OLD_BY_COVERS)
|
||
# include <stdlib.h> //qsort
|
||
#endif
|
||
#include "patch_private.h"
|
||
|
||
#ifndef _IS_RUN_MEM_SAFE_CHECK
|
||
# define _IS_RUN_MEM_SAFE_CHECK 1
|
||
#endif
|
||
|
||
#if (_IS_RUN_MEM_SAFE_CHECK)
|
||
//__RUN_MEM_SAFE_CHECK用来启动内存访问越界检查,用以防御可能被意外或故意损坏的数据.
|
||
# define __RUN_MEM_SAFE_CHECK
|
||
#endif
|
||
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
# define _SAFE_CHECK_DO(code) do{ if (!(code)) return _hpatch_FALSE; }while(0)
|
||
#else
|
||
# define _SAFE_CHECK_DO(code) do{ code; }while(0)
|
||
#endif
|
||
|
||
#define _hpatch_FALSE hpatch_FALSE
|
||
//hpatch_uint __hpatch_debug_check_false_x=0; //for debug
|
||
//#define _hpatch_FALSE (1/__hpatch_debug_check_false_x)
|
||
|
||
typedef unsigned char TByte;
|
||
|
||
|
||
//变长正整数编码方案(x bit额外类型标志位,x<=7),从高位开始输出1--n byte:
|
||
// x0* 7-x bit
|
||
// x1* 0* 7+7-x bit
|
||
// x1* 1* 0* 7+7+7-x bit
|
||
// x1* 1* 1* 0* 7+7+7+7-x bit
|
||
// x1* 1* 1* 1* 0* 7+7+7+7+7-x bit
|
||
// ......
|
||
hpatch_BOOL hpatch_packUIntWithTag(TByte** out_code,TByte* out_code_end,
|
||
hpatch_StreamPos_t uValue,hpatch_uint highTag,
|
||
const hpatch_uint kTagBit){//写入整数并前进指针.
|
||
TByte* pcode=*out_code;
|
||
const hpatch_StreamPos_t kMaxValueWithTag=((hpatch_StreamPos_t)1<<(7-kTagBit))-1;
|
||
TByte codeBuf[hpatch_kMaxPackedUIntBytes];
|
||
TByte* codeEnd=codeBuf;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
//static const hpatch_uint kPackMaxTagBit=7;
|
||
//assert((0<=kTagBit)&&(kTagBit<=kPackMaxTagBit));
|
||
//assert((highTag>>kTagBit)==0);
|
||
#endif
|
||
while (uValue>kMaxValueWithTag) {
|
||
*codeEnd=uValue&((1<<7)-1); ++codeEnd;
|
||
uValue>>=7;
|
||
}
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((out_code_end-pcode)<(1+(codeEnd-codeBuf))) return _hpatch_FALSE;
|
||
#endif
|
||
*pcode=(TByte)( (TByte)uValue | (highTag<<(8-kTagBit))
|
||
| (((codeBuf!=codeEnd)?1:0)<<(7-kTagBit)) );
|
||
++pcode;
|
||
while (codeBuf!=codeEnd) {
|
||
--codeEnd;
|
||
*pcode=(*codeEnd) | (((codeBuf!=codeEnd)?1:0)<<7);
|
||
++pcode;
|
||
}
|
||
*out_code=pcode;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_uint hpatch_packUIntWithTag_size(hpatch_StreamPos_t uValue,const hpatch_uint kTagBit){
|
||
const hpatch_StreamPos_t kMaxValueWithTag=((hpatch_StreamPos_t)1<<(7-kTagBit))-1;
|
||
hpatch_uint size=0;
|
||
while (uValue>kMaxValueWithTag) {
|
||
++size;
|
||
uValue>>=7;
|
||
}
|
||
++size;
|
||
return size;
|
||
}
|
||
|
||
hpatch_BOOL hpatch_unpackUIntWithTag(const TByte** src_code,const TByte* src_code_end,
|
||
hpatch_StreamPos_t* result,const hpatch_uint kTagBit){//读出整数并前进指针.
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
//const hpatch_uint kPackMaxTagBit=7;
|
||
#endif
|
||
hpatch_StreamPos_t value;
|
||
TByte code;
|
||
const TByte* pcode=*src_code;
|
||
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
//assert(kTagBit<=kPackMaxTagBit);
|
||
if (src_code_end<=pcode) return _hpatch_FALSE;
|
||
#endif
|
||
code=*pcode; ++pcode;
|
||
value=code&((1<<(7-kTagBit))-1);
|
||
if ((code&(1<<(7-kTagBit)))!=0){
|
||
do {
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((value>>(sizeof(value)*8-7))!=0) return _hpatch_FALSE;//cannot save 7bit
|
||
if (src_code_end==pcode) return _hpatch_FALSE;
|
||
#endif
|
||
code=*pcode; ++pcode;
|
||
value=(value<<7) | (code&((1<<7)-1));
|
||
} while ((code&(1<<7))!=0);
|
||
}
|
||
(*src_code)=pcode;
|
||
*result=value;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
|
||
static hpatch_BOOL _read_mem_stream(const hpatch_TStreamInput* stream,hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
const unsigned char* src=(const unsigned char*)stream->streamImport;
|
||
hpatch_size_t readLen=out_data_end-out_data;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (readFromPos>stream->streamSize) return _hpatch_FALSE;
|
||
if (readLen>(hpatch_StreamPos_t)(stream->streamSize-readFromPos)) return _hpatch_FALSE;
|
||
#endif
|
||
memcpy(out_data,src+readFromPos,readLen);
|
||
return hpatch_TRUE;
|
||
}
|
||
const hpatch_TStreamInput* mem_as_hStreamInput(hpatch_TStreamInput* out_stream,
|
||
const unsigned char* mem,const unsigned char* mem_end){
|
||
out_stream->streamImport=(void*)mem;
|
||
out_stream->streamSize=mem_end-mem;
|
||
out_stream->read=_read_mem_stream;
|
||
return out_stream;
|
||
}
|
||
|
||
static hpatch_BOOL _write_mem_stream(const hpatch_TStreamOutput* stream,hpatch_StreamPos_t writeToPos,
|
||
const unsigned char* data,const unsigned char* data_end){
|
||
unsigned char* out_dst=(unsigned char*)stream->streamImport;
|
||
hpatch_size_t writeLen=data_end-data;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (writeToPos>stream->streamSize) return _hpatch_FALSE;
|
||
if (writeLen>(hpatch_StreamPos_t)(stream->streamSize-writeToPos)) return _hpatch_FALSE;
|
||
#endif
|
||
memcpy(out_dst+writeToPos,data,writeLen);
|
||
return hpatch_TRUE;
|
||
}
|
||
typedef hpatch_BOOL (*_read_mem_stream_t)(const hpatch_TStreamOutput* stream,hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end);
|
||
const hpatch_TStreamOutput* mem_as_hStreamOutput(hpatch_TStreamOutput* out_stream,
|
||
unsigned char* mem,unsigned char* mem_end){
|
||
out_stream->streamImport=mem;
|
||
out_stream->streamSize=mem_end-mem;
|
||
out_stream->read_writed=(_read_mem_stream_t)_read_mem_stream;
|
||
out_stream->write=_write_mem_stream;
|
||
return out_stream;
|
||
}
|
||
|
||
hpatch_BOOL hpatch_deccompress_mem(hpatch_TDecompress* decompressPlugin,
|
||
const unsigned char* code,const unsigned char* code_end,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
hpatch_decompressHandle dec=0;
|
||
hpatch_BOOL result,colose_rt;
|
||
hpatch_TStreamInput codeStream;
|
||
mem_as_hStreamInput(&codeStream,code,code_end);
|
||
dec=decompressPlugin->open(decompressPlugin,(out_data_end-out_data),
|
||
&codeStream,0,codeStream.streamSize);
|
||
if (dec==0) return _hpatch_FALSE;
|
||
result=decompressPlugin->decompress_part(dec,out_data,out_data_end);
|
||
colose_rt=decompressPlugin->close(decompressPlugin,dec);
|
||
assert(colose_rt);
|
||
return result;
|
||
}
|
||
|
||
|
||
////////
|
||
//patch by memory
|
||
|
||
static const hpatch_uint kSignTagBit=1;
|
||
|
||
static hpatch_BOOL _bytesRle_load(TByte* out_data,TByte* out_dataEnd,
|
||
const TByte* rle_code,const TByte* rle_code_end);
|
||
static void addData(TByte* dst,const TByte* src,hpatch_size_t length);
|
||
hpatch_inline
|
||
static hpatch_BOOL _unpackUIntWithTag(const TByte** src_code,const TByte* src_code_end,
|
||
hpatch_size_t* result,const hpatch_uint kTagBit){
|
||
if (sizeof(hpatch_size_t)==sizeof(hpatch_StreamPos_t)){
|
||
return hpatch_unpackUIntWithTag(src_code,src_code_end,(hpatch_StreamPos_t*)result,kTagBit);
|
||
}else{
|
||
hpatch_StreamPos_t u64=0;
|
||
hpatch_BOOL rt=hpatch_unpackUIntWithTag(src_code,src_code_end,&u64,kTagBit);
|
||
hpatch_size_t u=(hpatch_size_t)u64;
|
||
*result=u;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
return rt&(u==u64);
|
||
#else
|
||
return rt;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
#define unpackUIntWithTagTo(puint,src_code,src_code_end,kTagBit) \
|
||
_SAFE_CHECK_DO(_unpackUIntWithTag(src_code,src_code_end,puint,kTagBit))
|
||
#define unpackUIntTo(puint,src_code,src_code_end) \
|
||
unpackUIntWithTagTo(puint,src_code,src_code_end,0)
|
||
|
||
hpatch_BOOL patch(TByte* out_newData,TByte* out_newData_end,
|
||
const TByte* oldData,const TByte* oldData_end,
|
||
const TByte* serializedDiff,const TByte* serializedDiff_end){
|
||
const TByte *code_lengths, *code_lengths_end,
|
||
*code_inc_newPos, *code_inc_newPos_end,
|
||
*code_inc_oldPos, *code_inc_oldPos_end,
|
||
*code_newDataDiff, *code_newDataDiff_end;
|
||
hpatch_size_t coverCount;
|
||
|
||
assert(out_newData<=out_newData_end);
|
||
assert(oldData<=oldData_end);
|
||
assert(serializedDiff<=serializedDiff_end);
|
||
unpackUIntTo(&coverCount,&serializedDiff, serializedDiff_end);
|
||
{ //head
|
||
hpatch_size_t lengthSize,inc_newPosSize,inc_oldPosSize,newDataDiffSize;
|
||
unpackUIntTo(&lengthSize,&serializedDiff, serializedDiff_end);
|
||
unpackUIntTo(&inc_newPosSize,&serializedDiff, serializedDiff_end);
|
||
unpackUIntTo(&inc_oldPosSize,&serializedDiff, serializedDiff_end);
|
||
unpackUIntTo(&newDataDiffSize,&serializedDiff, serializedDiff_end);
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (lengthSize>(hpatch_size_t)(serializedDiff_end-serializedDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
code_lengths=serializedDiff; serializedDiff+=lengthSize;
|
||
code_lengths_end=serializedDiff;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (inc_newPosSize>(hpatch_size_t)(serializedDiff_end-serializedDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
code_inc_newPos=serializedDiff; serializedDiff+=inc_newPosSize;
|
||
code_inc_newPos_end=serializedDiff;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (inc_oldPosSize>(hpatch_size_t)(serializedDiff_end-serializedDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
code_inc_oldPos=serializedDiff; serializedDiff+=inc_oldPosSize;
|
||
code_inc_oldPos_end=serializedDiff;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (newDataDiffSize>(hpatch_size_t)(serializedDiff_end-serializedDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
code_newDataDiff=serializedDiff; serializedDiff+=newDataDiffSize;
|
||
code_newDataDiff_end=serializedDiff;
|
||
}
|
||
|
||
//decode rle ; rle data begin==cur serializedDiff;
|
||
_SAFE_CHECK_DO(_bytesRle_load(out_newData, out_newData_end, serializedDiff, serializedDiff_end));
|
||
|
||
{ //patch
|
||
const hpatch_size_t newDataSize=(hpatch_size_t)(out_newData_end-out_newData);
|
||
hpatch_size_t oldPosBack=0;
|
||
hpatch_size_t newPosBack=0;
|
||
hpatch_size_t i;
|
||
for (i=0; i<coverCount; ++i){
|
||
hpatch_size_t copyLength,addLength, oldPos,inc_oldPos,inc_oldPos_sign;
|
||
unpackUIntTo(©Length,&code_inc_newPos, code_inc_newPos_end);
|
||
unpackUIntTo(&addLength,&code_lengths, code_lengths_end);
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (code_inc_oldPos>=code_inc_oldPos_end) return _hpatch_FALSE;
|
||
#endif
|
||
inc_oldPos_sign=(*code_inc_oldPos)>>(8-kSignTagBit);
|
||
unpackUIntWithTagTo(&inc_oldPos,&code_inc_oldPos, code_inc_oldPos_end, kSignTagBit);
|
||
if (inc_oldPos_sign==0)
|
||
oldPos=oldPosBack+inc_oldPos;
|
||
else
|
||
oldPos=oldPosBack-inc_oldPos;
|
||
if (copyLength>0){
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (copyLength>(hpatch_size_t)(newDataSize-newPosBack)) return _hpatch_FALSE;
|
||
if (copyLength>(hpatch_size_t)(code_newDataDiff_end-code_newDataDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
memcpy(out_newData+newPosBack,code_newDataDiff,copyLength);
|
||
code_newDataDiff+=copyLength;
|
||
newPosBack+=copyLength;
|
||
}
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ( (addLength>(hpatch_size_t)(newDataSize-newPosBack)) ) return _hpatch_FALSE;
|
||
if ( (oldPos>(hpatch_size_t)(oldData_end-oldData)) ||
|
||
(addLength>(hpatch_size_t)(oldData_end-oldData-oldPos)) ) return _hpatch_FALSE;
|
||
#endif
|
||
addData(out_newData+newPosBack,oldData+oldPos,addLength);
|
||
oldPosBack=oldPos;
|
||
newPosBack+=addLength;
|
||
}
|
||
|
||
if (newPosBack<newDataSize){
|
||
hpatch_size_t copyLength=newDataSize-newPosBack;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (copyLength>(hpatch_size_t)(code_newDataDiff_end-code_newDataDiff)) return _hpatch_FALSE;
|
||
#endif
|
||
memcpy(out_newData+newPosBack,code_newDataDiff,copyLength);
|
||
code_newDataDiff+=copyLength;
|
||
//newPosBack=newDataSize;
|
||
}
|
||
}
|
||
|
||
if ( (code_lengths==code_lengths_end)
|
||
&&(code_inc_newPos==code_inc_newPos_end)
|
||
&&(code_inc_oldPos==code_inc_oldPos_end)
|
||
&&(code_newDataDiff==code_newDataDiff_end))
|
||
return hpatch_TRUE;
|
||
else
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
hpatch_inline static void addData(TByte* dst,const TByte* src,hpatch_size_t length){
|
||
while (length--) { *dst++ += *src++; }
|
||
}
|
||
|
||
static hpatch_BOOL _bytesRle_load(TByte* out_data,TByte* out_dataEnd,
|
||
const TByte* rle_code,const TByte* rle_code_end){
|
||
const TByte* ctrlBuf,*ctrlBuf_end;
|
||
hpatch_size_t ctrlSize;
|
||
unpackUIntTo(&ctrlSize,&rle_code,rle_code_end);
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (ctrlSize>(hpatch_size_t)(rle_code_end-rle_code)) return _hpatch_FALSE;
|
||
#endif
|
||
ctrlBuf=rle_code;
|
||
rle_code+=ctrlSize;
|
||
ctrlBuf_end=rle_code;
|
||
while (ctrlBuf_end-ctrlBuf>0){
|
||
enum TByteRleType type=(enum TByteRleType)((*ctrlBuf)>>(8-kByteRleType_bit));
|
||
hpatch_size_t length;
|
||
unpackUIntWithTagTo(&length,&ctrlBuf,ctrlBuf_end,kByteRleType_bit);
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (length>=(hpatch_size_t)(out_dataEnd-out_data)) return _hpatch_FALSE;
|
||
#endif
|
||
++length;
|
||
switch (type){
|
||
case kByteRleType_rle0:{
|
||
memset(out_data,0,length);
|
||
out_data+=length;
|
||
}break;
|
||
case kByteRleType_rle255:{
|
||
memset(out_data,255,length);
|
||
out_data+=length;
|
||
}break;
|
||
case kByteRleType_rle:{
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (1>(hpatch_size_t)(rle_code_end-rle_code)) return _hpatch_FALSE;
|
||
#endif
|
||
memset(out_data,*rle_code,length);
|
||
++rle_code;
|
||
out_data+=length;
|
||
}break;
|
||
case kByteRleType_unrle:{
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (length>(hpatch_size_t)(rle_code_end-rle_code)) return _hpatch_FALSE;
|
||
#endif
|
||
memcpy(out_data,rle_code,length);
|
||
rle_code+=length;
|
||
out_data+=length;
|
||
}break;
|
||
}
|
||
}
|
||
|
||
if ( (ctrlBuf==ctrlBuf_end)
|
||
&&(rle_code==rle_code_end)
|
||
&&(out_data==out_dataEnd))
|
||
return hpatch_TRUE;
|
||
else
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
//----------------------
|
||
//patch by stream
|
||
|
||
static hpatch_BOOL _TStreamInputClip_read(const hpatch_TStreamInput* stream,
|
||
hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
TStreamInputClip* self=(TStreamInputClip*)stream->streamImport;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (readFromPos+(out_data_end-out_data)>self->base.streamSize) return _hpatch_FALSE;
|
||
#endif
|
||
return self->srcStream->read(self->srcStream,readFromPos+self->clipBeginPos,out_data,out_data_end);
|
||
}
|
||
void TStreamInputClip_init(TStreamInputClip* self,const hpatch_TStreamInput* srcStream,
|
||
hpatch_StreamPos_t clipBeginPos,hpatch_StreamPos_t clipEndPos){
|
||
assert(self!=0);
|
||
assert(srcStream!=0);
|
||
assert(clipBeginPos<=clipEndPos);
|
||
assert(clipEndPos<=srcStream->streamSize);
|
||
self->srcStream=srcStream;
|
||
self->clipBeginPos=clipBeginPos;
|
||
self->base.streamImport=self;
|
||
self->base.streamSize=clipEndPos-clipBeginPos;
|
||
self->base.read=_TStreamInputClip_read;
|
||
}
|
||
|
||
static hpatch_BOOL _TStreamOutputClip_write(const hpatch_TStreamOutput* stream,
|
||
hpatch_StreamPos_t writePos,
|
||
const unsigned char* data,const unsigned char* data_end){
|
||
TStreamOutputClip* self=(TStreamOutputClip*)stream->streamImport;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (writePos+(data_end-data)>self->base.streamSize) return _hpatch_FALSE;
|
||
#endif
|
||
return self->srcStream->write(self->srcStream,writePos+self->clipBeginPos,data,data_end);
|
||
}
|
||
|
||
void TStreamOutputClip_init(TStreamOutputClip* self,const hpatch_TStreamOutput* srcStream,
|
||
hpatch_StreamPos_t clipBeginPos,hpatch_StreamPos_t clipEndPos){
|
||
assert(self!=0);
|
||
assert(srcStream!=0);
|
||
assert(clipBeginPos<=clipEndPos);
|
||
assert(clipEndPos<=srcStream->streamSize);
|
||
self->srcStream=srcStream;
|
||
self->clipBeginPos=clipBeginPos;
|
||
self->base.streamImport=self;
|
||
self->base.streamSize=clipEndPos-clipBeginPos;
|
||
((TStreamInputClip*)self)->base.read=_TStreamInputClip_read;
|
||
self->base.write=_TStreamOutputClip_write;
|
||
}
|
||
|
||
|
||
|
||
//assert(hpatch_kStreamCacheSize>=hpatch_kMaxPluginTypeLength+1);
|
||
struct __private_hpatch_check_kMaxCompressTypeLength {
|
||
char _[(hpatch_kStreamCacheSize>=(hpatch_kMaxPluginTypeLength+1))?1:-1];};
|
||
|
||
hpatch_BOOL _TStreamCacheClip_readType_end(TStreamCacheClip* sclip,TByte endTag,
|
||
char out_type[hpatch_kMaxPluginTypeLength+1]){
|
||
const TByte* type_begin;
|
||
hpatch_size_t i;
|
||
hpatch_size_t readLen=hpatch_kMaxPluginTypeLength+1;
|
||
if (readLen>_TStreamCacheClip_leaveSize(sclip))
|
||
readLen=(hpatch_size_t)_TStreamCacheClip_leaveSize(sclip);
|
||
type_begin=_TStreamCacheClip_accessData(sclip,readLen);
|
||
if (type_begin==0) return _hpatch_FALSE;//not found
|
||
for (i=0; i<readLen; ++i) {
|
||
if (type_begin[i]!=endTag)
|
||
continue;
|
||
else{
|
||
memcpy(out_type,type_begin,i); out_type[i]='\0';
|
||
_TStreamCacheClip_skipData_noCheck(sclip,i+1);
|
||
return hpatch_TRUE;
|
||
}
|
||
}
|
||
return _hpatch_FALSE;//not found
|
||
}
|
||
|
||
hpatch_BOOL _TStreamCacheClip_updateCache(TStreamCacheClip* sclip){
|
||
TByte* buf0=&sclip->cacheBuf[0];
|
||
const hpatch_StreamPos_t streamSize=sclip->streamPos_end-sclip->streamPos;
|
||
hpatch_size_t readSize=sclip->cacheBegin;
|
||
if (readSize>streamSize)
|
||
readSize=(hpatch_size_t)streamSize;
|
||
if (readSize==0) return hpatch_TRUE;
|
||
if (!_TStreamCacheClip_isCacheEmpty(sclip)){
|
||
memmove(buf0+(hpatch_size_t)(sclip->cacheBegin-readSize),
|
||
buf0+sclip->cacheBegin,_TStreamCacheClip_cachedSize(sclip));
|
||
}
|
||
if (!sclip->srcStream->read(sclip->srcStream,sclip->streamPos,
|
||
buf0+(sclip->cacheEnd-readSize),buf0+sclip->cacheEnd))
|
||
return _hpatch_FALSE;//read error
|
||
sclip->cacheBegin-=readSize;
|
||
sclip->streamPos+=readSize;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TStreamCacheClip_skipData(TStreamCacheClip* sclip,hpatch_StreamPos_t skipLongSize){
|
||
while (skipLongSize>0) {
|
||
hpatch_size_t len=sclip->cacheEnd;
|
||
if (len>skipLongSize)
|
||
len=(hpatch_size_t)skipLongSize;
|
||
if (_TStreamCacheClip_accessData(sclip,len)){
|
||
_TStreamCacheClip_skipData_noCheck(sclip,len);
|
||
skipLongSize-=len;
|
||
}else{
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
//assert(hpatch_kStreamCacheSize>=hpatch_kMaxPackedUIntBytes);
|
||
struct __private_hpatch_check_hpatch_kMaxPackedUIntBytes {
|
||
char _[(hpatch_kStreamCacheSize>=hpatch_kMaxPackedUIntBytes)?1:-1]; };
|
||
|
||
hpatch_BOOL _TStreamCacheClip_unpackUIntWithTag(TStreamCacheClip* sclip,hpatch_StreamPos_t* result,const hpatch_uint kTagBit){
|
||
TByte* curCode,*codeBegin;
|
||
hpatch_size_t readSize=hpatch_kMaxPackedUIntBytes;
|
||
const hpatch_StreamPos_t dataSize=_TStreamCacheClip_leaveSize(sclip);
|
||
if (readSize>dataSize)
|
||
readSize=(hpatch_size_t)dataSize;
|
||
codeBegin=_TStreamCacheClip_accessData(sclip,readSize);
|
||
if (codeBegin==0) return _hpatch_FALSE;
|
||
curCode=codeBegin;
|
||
_SAFE_CHECK_DO(hpatch_unpackUIntWithTag((const TByte**)&curCode,codeBegin+readSize,result,kTagBit));
|
||
_TStreamCacheClip_skipData_noCheck(sclip,(hpatch_size_t)(curCode-codeBegin));
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TStreamCacheClip_readDataTo(TStreamCacheClip* sclip,TByte* out_buf,TByte* bufEnd){
|
||
hpatch_size_t readLen=_TStreamCacheClip_cachedSize(sclip);
|
||
hpatch_size_t outLen=bufEnd-out_buf;
|
||
if (readLen>=outLen)
|
||
readLen=outLen;
|
||
memcpy(out_buf,&sclip->cacheBuf[sclip->cacheBegin],readLen);
|
||
sclip->cacheBegin+=readLen;
|
||
outLen-=readLen;
|
||
if (outLen){
|
||
out_buf += readLen;
|
||
if (outLen<(sclip->cacheEnd>>1)){
|
||
if (!_TStreamCacheClip_updateCache(sclip)) return _hpatch_FALSE;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (outLen>_TStreamCacheClip_cachedSize(sclip)) return _hpatch_FALSE;
|
||
#endif
|
||
return _TStreamCacheClip_readDataTo(sclip, out_buf, bufEnd);
|
||
}else{
|
||
if (!sclip->srcStream->read(sclip->srcStream,sclip->streamPos,
|
||
out_buf,bufEnd)) return _hpatch_FALSE;
|
||
sclip->streamPos+=outLen;
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TStreamCacheClip_addDataTo(TStreamCacheClip* self,unsigned char* dst,hpatch_size_t addLen){
|
||
const unsigned char* src=_TStreamCacheClip_readData(self,addLen);
|
||
if (src==0) return _hpatch_FALSE;
|
||
addData(dst,src,addLen);
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _decompress_read(const hpatch_TStreamInput* stream,
|
||
const hpatch_StreamPos_t readFromPos,
|
||
TByte* out_data,TByte* out_data_end){
|
||
_TDecompressInputStream* self=(_TDecompressInputStream*)stream->streamImport;
|
||
return self->decompressPlugin->decompress_part(self->decompressHandle,out_data,out_data_end);
|
||
}
|
||
hpatch_BOOL getStreamClip(TStreamCacheClip* out_clip,_TDecompressInputStream* out_stream,
|
||
hpatch_StreamPos_t dataSize,hpatch_StreamPos_t compressedSize,
|
||
const hpatch_TStreamInput* stream,hpatch_StreamPos_t* pCurStreamPos,
|
||
hpatch_TDecompress* decompressPlugin,TByte* aCache,hpatch_size_t cacheSize){
|
||
hpatch_StreamPos_t curStreamPos=*pCurStreamPos;
|
||
if (compressedSize==0){
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((curStreamPos+dataSize)<curStreamPos) return _hpatch_FALSE;
|
||
if ((curStreamPos+dataSize)>stream->streamSize) return _hpatch_FALSE;
|
||
#endif
|
||
if (out_clip)
|
||
_TStreamCacheClip_init(out_clip,stream,curStreamPos,curStreamPos+dataSize,aCache,cacheSize);
|
||
curStreamPos+=dataSize;
|
||
}else{
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((curStreamPos+compressedSize)<curStreamPos) return _hpatch_FALSE;
|
||
if ((curStreamPos+compressedSize)>stream->streamSize) return _hpatch_FALSE;
|
||
#endif
|
||
if (out_clip){
|
||
out_stream->IInputStream.streamImport=out_stream;
|
||
out_stream->IInputStream.streamSize=dataSize;
|
||
out_stream->IInputStream.read=_decompress_read;
|
||
out_stream->decompressPlugin=decompressPlugin;
|
||
if (out_stream->decompressHandle==0){
|
||
out_stream->decompressHandle=decompressPlugin->open(decompressPlugin,dataSize,stream,
|
||
curStreamPos,curStreamPos+compressedSize);
|
||
if (!out_stream->decompressHandle) return _hpatch_FALSE;
|
||
}else{
|
||
if (decompressPlugin->reset_code==0) return _hpatch_FALSE;
|
||
if (!decompressPlugin->reset_code(out_stream->decompressHandle,dataSize,stream,curStreamPos,
|
||
curStreamPos+compressedSize)) return _hpatch_FALSE;
|
||
}
|
||
_TStreamCacheClip_init(out_clip,&out_stream->IInputStream,0,
|
||
out_stream->IInputStream.streamSize,aCache,cacheSize);
|
||
}
|
||
curStreamPos+=compressedSize;
|
||
}
|
||
*pCurStreamPos=curStreamPos;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
///////
|
||
|
||
static hpatch_inline hpatch_BOOL __TOutStreamCache_writeStream(_TOutStreamCache* self,const TByte* data,hpatch_size_t dataSize){
|
||
if (!self->dstStream->write(self->dstStream,self->writeToPos,data,data+dataSize))
|
||
return _hpatch_FALSE;
|
||
self->writeToPos+=dataSize;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_flush(_TOutStreamCache* self){
|
||
hpatch_size_t curSize=self->cacheCur;
|
||
if (curSize>0){
|
||
if (!__TOutStreamCache_writeStream(self,self->cacheBuf,curSize))
|
||
return _hpatch_FALSE;
|
||
self->cacheCur=0;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_write(_TOutStreamCache* self,const TByte* data,hpatch_size_t dataSize){
|
||
while (dataSize>0) {
|
||
hpatch_size_t copyLen;
|
||
hpatch_size_t curSize=self->cacheCur;
|
||
if ((dataSize>=self->cacheEnd)&&(curSize==0)){
|
||
return __TOutStreamCache_writeStream(self,data,dataSize);
|
||
}
|
||
copyLen=self->cacheEnd-curSize;
|
||
copyLen=(copyLen<=dataSize)?copyLen:dataSize;
|
||
memcpy(self->cacheBuf+curSize,data,copyLen);
|
||
self->cacheCur=curSize+copyLen;
|
||
data+=copyLen;
|
||
dataSize-=copyLen;
|
||
if (self->cacheCur==self->cacheEnd){
|
||
if (!_TOutStreamCache_flush(self))
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_fill(_TOutStreamCache* self,hpatch_byte fillValue,hpatch_StreamPos_t fillLength){
|
||
while (fillLength>0){
|
||
hpatch_size_t curSize=self->cacheCur;
|
||
hpatch_size_t runStep=self->cacheEnd-curSize;
|
||
runStep=(runStep<=fillLength)?runStep:(hpatch_size_t)fillLength;
|
||
memset(self->cacheBuf+curSize,fillValue,runStep);
|
||
self->cacheCur=curSize+runStep;
|
||
fillLength-=runStep;
|
||
if (self->cacheCur==self->cacheEnd){
|
||
if (!_TOutStreamCache_flush(self))
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_copyFromStream(_TOutStreamCache* self,const hpatch_TStreamInput* src,
|
||
hpatch_StreamPos_t srcPos,hpatch_StreamPos_t copyLength){
|
||
while (copyLength>0){
|
||
hpatch_size_t curSize=self->cacheCur;
|
||
hpatch_size_t runStep=self->cacheEnd-curSize;
|
||
hpatch_byte* buf=self->cacheBuf+curSize;
|
||
runStep=(runStep<=copyLength)?runStep:(hpatch_size_t)copyLength;
|
||
if (!src->read(src,srcPos,buf,buf+runStep))
|
||
return _hpatch_FALSE;
|
||
srcPos+=runStep;
|
||
self->cacheCur=curSize+runStep;
|
||
copyLength-=runStep;
|
||
if (self->cacheCur==self->cacheEnd){
|
||
if (!_TOutStreamCache_flush(self))
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_copyFromClip(_TOutStreamCache* self,TStreamCacheClip* src,hpatch_StreamPos_t copyLength){
|
||
while (copyLength>0){
|
||
const TByte* data;
|
||
hpatch_size_t runStep=(src->cacheEnd<=copyLength)?src->cacheEnd:(hpatch_size_t)copyLength;
|
||
data=_TStreamCacheClip_readData(src,runStep);
|
||
if (data==0) return
|
||
_hpatch_FALSE;
|
||
if (!_TOutStreamCache_write(self,data,runStep))
|
||
return _hpatch_FALSE;
|
||
copyLength-=runStep;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL _TOutStreamCache_copyFromSelf(_TOutStreamCache* self,hpatch_StreamPos_t aheadLength,hpatch_StreamPos_t copyLength){
|
||
// [ writed ]
|
||
// [ cached buf | empty buf ]
|
||
const hpatch_TStreamInput* src=(const hpatch_TStreamInput*)self->dstStream;
|
||
hpatch_StreamPos_t srcPos=self->writeToPos+self->cacheCur-aheadLength;
|
||
if (src->read==0) //can't read
|
||
return _hpatch_FALSE;
|
||
if ((aheadLength<1)|(aheadLength>self->writeToPos+self->cacheCur))
|
||
return _hpatch_FALSE;
|
||
|
||
if (srcPos+copyLength<=self->writeToPos){//copy from stream
|
||
// [ copyLength ]
|
||
__copy_in_stream:
|
||
return _TOutStreamCache_copyFromStream(self,src,srcPos,copyLength);
|
||
}else if (srcPos>=self->writeToPos){ //copy in mem
|
||
// [ copyLength ]
|
||
__copy_in_mem:
|
||
while (copyLength>0){
|
||
hpatch_byte* dstBuf=self->cacheBuf+self->cacheCur;
|
||
hpatch_byte* srcBuf=dstBuf-(hpatch_size_t)aheadLength;
|
||
hpatch_size_t runLen=(self->cacheCur+copyLength<=self->cacheEnd)?(hpatch_size_t)copyLength:(self->cacheEnd-self->cacheCur);
|
||
hpatch_size_t i;
|
||
for (i=0;i<runLen;i++)
|
||
dstBuf[i]=srcBuf[i];
|
||
copyLength-=runLen;
|
||
self->cacheCur+=runLen;
|
||
if (self->cacheCur==self->cacheEnd){
|
||
if (!_TOutStreamCache_flush(self))
|
||
return _hpatch_FALSE;
|
||
runLen=(hpatch_size_t)((aheadLength<=copyLength)?aheadLength:copyLength);
|
||
memmove(self->cacheBuf,self->cacheBuf+self->cacheEnd-(hpatch_size_t)aheadLength,runLen);
|
||
self->cacheCur=runLen;
|
||
copyLength-=runLen;
|
||
}else{
|
||
assert(copyLength==0);
|
||
}
|
||
}
|
||
return hpatch_TRUE;
|
||
}else if (self->writeToPos+self->cacheCur<=srcPos+self->cacheEnd){
|
||
// small data in stream,can as copy in mem
|
||
hpatch_byte* dstBuf=self->cacheBuf+self->cacheCur;
|
||
hpatch_size_t runLen=(hpatch_size_t)(self->writeToPos-srcPos);
|
||
if (!src->read(src,srcPos,dstBuf,dstBuf+runLen))
|
||
return _hpatch_FALSE;
|
||
//srcPos+=runLen; //not used
|
||
copyLength-=runLen;
|
||
self->cacheCur+=runLen;
|
||
if (self->cacheCur==self->cacheEnd){
|
||
while (hpatch_TRUE){
|
||
if (self->cacheCur==self->cacheEnd){
|
||
if (!_TOutStreamCache_flush(self))
|
||
return _hpatch_FALSE;
|
||
}
|
||
if (copyLength>0){
|
||
runLen=(self->cacheEnd<=copyLength)?self->cacheEnd:(hpatch_size_t)copyLength;
|
||
//srcPos+=runLen; //not used
|
||
copyLength-=runLen;
|
||
self->cacheCur=runLen;
|
||
}else{
|
||
return hpatch_TRUE;
|
||
}
|
||
}
|
||
}else{
|
||
goto __copy_in_mem;
|
||
}
|
||
}else{
|
||
goto __copy_in_stream;
|
||
}
|
||
}
|
||
|
||
|
||
typedef struct _TBytesRle_load_stream{
|
||
hpatch_StreamPos_t memCopyLength;
|
||
hpatch_StreamPos_t memSetLength;
|
||
TByte memSetValue;
|
||
TStreamCacheClip ctrlClip;
|
||
TStreamCacheClip rleCodeClip;
|
||
} _TBytesRle_load_stream;
|
||
|
||
hpatch_inline
|
||
static void _TBytesRle_load_stream_init(_TBytesRle_load_stream* loader){
|
||
loader->memSetLength=0;
|
||
loader->memSetValue=0;//nil;
|
||
loader->memCopyLength=0;
|
||
_TStreamCacheClip_init(&loader->ctrlClip,0,0,0,0,0);
|
||
_TStreamCacheClip_init(&loader->rleCodeClip,0,0,0,0,0);
|
||
}
|
||
|
||
hpatch_inline static void memSet_add(TByte* dst,const TByte src,hpatch_size_t length){
|
||
while (length--) { (*dst++) += src; }
|
||
}
|
||
|
||
static hpatch_BOOL _TBytesRle_load_stream_mem_add(_TBytesRle_load_stream* loader,
|
||
hpatch_size_t* _decodeSize,TByte** _out_data){
|
||
hpatch_size_t decodeSize=*_decodeSize;
|
||
TByte* out_data=*_out_data;
|
||
TStreamCacheClip* rleCodeClip=&loader->rleCodeClip;
|
||
|
||
hpatch_StreamPos_t memSetLength=loader->memSetLength;
|
||
if (memSetLength!=0){
|
||
hpatch_size_t memSetStep=((memSetLength<=decodeSize)?(hpatch_size_t)memSetLength:decodeSize);
|
||
const TByte byteSetValue=loader->memSetValue;
|
||
if (out_data!=0){
|
||
if (byteSetValue!=0)
|
||
memSet_add(out_data,byteSetValue,memSetStep);
|
||
out_data+=memSetStep;
|
||
}
|
||
decodeSize-=memSetStep;
|
||
loader->memSetLength=memSetLength-memSetStep;
|
||
}
|
||
while ((loader->memCopyLength>0)&&(decodeSize>0)) {
|
||
TByte* rleData;
|
||
hpatch_size_t decodeStep=rleCodeClip->cacheEnd;
|
||
if (decodeStep>loader->memCopyLength)
|
||
decodeStep=(hpatch_size_t)loader->memCopyLength;
|
||
if (decodeStep>decodeSize)
|
||
decodeStep=decodeSize;
|
||
rleData=_TStreamCacheClip_readData(rleCodeClip,decodeStep);
|
||
if (rleData==0) return _hpatch_FALSE;
|
||
if (out_data){
|
||
addData(out_data,rleData,decodeStep);
|
||
out_data+=decodeStep;
|
||
}
|
||
decodeSize-=decodeStep;
|
||
loader->memCopyLength-=decodeStep;
|
||
}
|
||
*_decodeSize=decodeSize;
|
||
*_out_data=out_data;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_inline
|
||
static hpatch_BOOL _TBytesRle_load_stream_isFinish(const _TBytesRle_load_stream* loader){
|
||
return(loader->memSetLength==0)
|
||
&&(loader->memCopyLength==0)
|
||
&&(_TStreamCacheClip_isFinish(&loader->rleCodeClip))
|
||
&&(_TStreamCacheClip_isFinish(&loader->ctrlClip));
|
||
}
|
||
|
||
|
||
|
||
#define _clip_unpackUIntWithTagTo(puint,sclip,kTagBit) \
|
||
{ if (!_TStreamCacheClip_unpackUIntWithTag(sclip,puint,kTagBit)) return _hpatch_FALSE; }
|
||
#define _clip_unpackUIntTo(puint,sclip) _clip_unpackUIntWithTagTo(puint,sclip,0)
|
||
|
||
static hpatch_BOOL _TBytesRle_load_stream_decode_add(_TBytesRle_load_stream* loader,
|
||
TByte* out_data,hpatch_size_t decodeSize){
|
||
if (!_TBytesRle_load_stream_mem_add(loader,&decodeSize,&out_data))
|
||
return _hpatch_FALSE;
|
||
|
||
while ((decodeSize>0)&&(!_TStreamCacheClip_isFinish(&loader->ctrlClip))){
|
||
enum TByteRleType type;
|
||
hpatch_StreamPos_t length;
|
||
const TByte* pType=_TStreamCacheClip_accessData(&loader->ctrlClip,1);
|
||
if (pType==0) return _hpatch_FALSE;
|
||
type=(enum TByteRleType)((*pType)>>(8-kByteRleType_bit));
|
||
_clip_unpackUIntWithTagTo(&length,&loader->ctrlClip,kByteRleType_bit);
|
||
++length;
|
||
switch (type){
|
||
case kByteRleType_rle0:{
|
||
loader->memSetLength=length;
|
||
loader->memSetValue=0;
|
||
}break;
|
||
case kByteRleType_rle255:{
|
||
loader->memSetLength=length;
|
||
loader->memSetValue=255;
|
||
}break;
|
||
case kByteRleType_rle:{
|
||
const TByte* pSetValue=_TStreamCacheClip_readData(&loader->rleCodeClip,1);
|
||
if (pSetValue==0) return _hpatch_FALSE;
|
||
loader->memSetValue=*pSetValue;
|
||
loader->memSetLength=length;
|
||
}break;
|
||
case kByteRleType_unrle:{
|
||
loader->memCopyLength=length;
|
||
}break;
|
||
}
|
||
if (!_TBytesRle_load_stream_mem_add(loader,&decodeSize,&out_data)) return _hpatch_FALSE;
|
||
}
|
||
|
||
if (decodeSize==0)
|
||
return hpatch_TRUE;
|
||
else
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
#define _TBytesRle_load_stream_decode_skip(loader,decodeSize) \
|
||
_TBytesRle_load_stream_decode_add(loader,0,decodeSize)
|
||
|
||
static hpatch_BOOL _patch_add_old_with_rle(_TOutStreamCache* outCache,_TBytesRle_load_stream* rle_loader,
|
||
const hpatch_TStreamInput* old,hpatch_StreamPos_t oldPos,
|
||
hpatch_StreamPos_t addLength,TByte* aCache,hpatch_size_t aCacheSize){
|
||
while (addLength>0){
|
||
hpatch_size_t decodeStep=aCacheSize;
|
||
if (decodeStep>addLength)
|
||
decodeStep=(hpatch_size_t)addLength;
|
||
if (!old->read(old,oldPos,aCache,aCache+decodeStep)) return _hpatch_FALSE;
|
||
if (!_TBytesRle_load_stream_decode_add(rle_loader,aCache,decodeStep)) return _hpatch_FALSE;
|
||
if (!_TOutStreamCache_write(outCache,aCache,decodeStep)) return _hpatch_FALSE;
|
||
oldPos+=decodeStep;
|
||
addLength-=decodeStep;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
typedef struct _TCovers{
|
||
hpatch_TCovers ICovers;
|
||
hpatch_StreamPos_t coverCount;
|
||
hpatch_StreamPos_t oldPosBack;
|
||
hpatch_StreamPos_t newPosBack;
|
||
TStreamCacheClip* code_inc_oldPosClip;
|
||
TStreamCacheClip* code_inc_newPosClip;
|
||
TStreamCacheClip* code_lengthsClip;
|
||
hpatch_BOOL isOldPosBackNeedAddLength;
|
||
} _TCovers;
|
||
|
||
static hpatch_StreamPos_t _covers_leaveCoverCount(const hpatch_TCovers* covers){
|
||
const _TCovers* self=(const _TCovers*)covers;
|
||
return self->coverCount;
|
||
}
|
||
static hpatch_BOOL _covers_close_nil(hpatch_TCovers* covers){
|
||
//empty
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _covers_read_cover(hpatch_TCovers* covers,hpatch_TCover* out_cover){
|
||
_TCovers* self=(_TCovers*)covers;
|
||
hpatch_StreamPos_t oldPosBack=self->oldPosBack;
|
||
hpatch_StreamPos_t newPosBack=self->newPosBack;
|
||
hpatch_StreamPos_t coverCount=self->coverCount;
|
||
if (coverCount>0)
|
||
self->coverCount=coverCount-1;
|
||
else
|
||
return _hpatch_FALSE;
|
||
|
||
{
|
||
hpatch_StreamPos_t copyLength,coverLength, oldPos,inc_oldPos;
|
||
TByte inc_oldPos_sign;
|
||
const TByte* pSign=_TStreamCacheClip_accessData(self->code_inc_oldPosClip,1);
|
||
if (pSign)
|
||
inc_oldPos_sign=(*pSign)>>(8-kSignTagBit);
|
||
else
|
||
return _hpatch_FALSE;
|
||
_clip_unpackUIntWithTagTo(&inc_oldPos,self->code_inc_oldPosClip,kSignTagBit);
|
||
oldPos=(inc_oldPos_sign==0)?(oldPosBack+inc_oldPos):(oldPosBack-inc_oldPos);
|
||
_clip_unpackUIntTo(©Length,self->code_inc_newPosClip);
|
||
_clip_unpackUIntTo(&coverLength,self->code_lengthsClip);
|
||
newPosBack+=copyLength;
|
||
oldPosBack=oldPos;
|
||
oldPosBack+=(self->isOldPosBackNeedAddLength)?coverLength:0;
|
||
|
||
out_cover->oldPos=oldPos;
|
||
out_cover->newPos=newPosBack;
|
||
out_cover->length=coverLength;
|
||
newPosBack+=coverLength;
|
||
}
|
||
self->oldPosBack=oldPosBack;
|
||
self->newPosBack=newPosBack;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _covers_is_finish(const struct hpatch_TCovers* covers){
|
||
_TCovers* self=(_TCovers*)covers;
|
||
return _TStreamCacheClip_isFinish(self->code_lengthsClip)
|
||
&& _TStreamCacheClip_isFinish(self->code_inc_newPosClip)
|
||
&& _TStreamCacheClip_isFinish(self->code_inc_oldPosClip);
|
||
}
|
||
|
||
|
||
static void _covers_init(_TCovers* covers,hpatch_StreamPos_t coverCount,
|
||
TStreamCacheClip* code_inc_oldPosClip,
|
||
TStreamCacheClip* code_inc_newPosClip,
|
||
TStreamCacheClip* code_lengthsClip,
|
||
hpatch_BOOL isOldPosBackNeedAddLength){
|
||
covers->ICovers.leave_cover_count=_covers_leaveCoverCount;
|
||
covers->ICovers.read_cover=_covers_read_cover;
|
||
covers->ICovers.is_finish=_covers_is_finish;
|
||
covers->ICovers.close=_covers_close_nil;
|
||
covers->coverCount=coverCount;
|
||
covers->newPosBack=0;
|
||
covers->oldPosBack=0;
|
||
covers->code_inc_oldPosClip=code_inc_oldPosClip;
|
||
covers->code_inc_newPosClip=code_inc_newPosClip;
|
||
covers->code_lengthsClip=code_lengthsClip;
|
||
covers->isOldPosBackNeedAddLength=isOldPosBackNeedAddLength;
|
||
}
|
||
|
||
static hpatch_BOOL _rle_decode_skip(struct _TBytesRle_load_stream* rle_loader,hpatch_StreamPos_t copyLength){
|
||
while (copyLength>0) {
|
||
hpatch_size_t len=(~(hpatch_size_t)0);
|
||
if (len>copyLength)
|
||
len=(hpatch_size_t)copyLength;
|
||
if (!_TBytesRle_load_stream_decode_skip(rle_loader,len)) return _hpatch_FALSE;
|
||
copyLength-=len;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL patchByClip(_TOutStreamCache* outCache,
|
||
const hpatch_TStreamInput* oldData,
|
||
hpatch_TCovers* covers,
|
||
TStreamCacheClip* code_newDataDiffClip,
|
||
struct _TBytesRle_load_stream* rle_loader,
|
||
TByte* temp_cache,hpatch_size_t cache_size){
|
||
const hpatch_StreamPos_t newDataSize=_TOutStreamCache_leaveSize(outCache);
|
||
const hpatch_StreamPos_t oldDataSize=oldData->streamSize;
|
||
hpatch_StreamPos_t coverCount=covers->leave_cover_count(covers);
|
||
hpatch_StreamPos_t newPosBack=0;
|
||
assert(cache_size>=hpatch_kMaxPackedUIntBytes);
|
||
|
||
while (coverCount--){
|
||
hpatch_TCover cover;
|
||
if(!covers->read_cover(covers,&cover)) return _hpatch_FALSE;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (cover.newPos<newPosBack) return _hpatch_FALSE;
|
||
if (cover.length>(hpatch_StreamPos_t)(newDataSize-cover.newPos)) return _hpatch_FALSE;
|
||
if (cover.oldPos>oldDataSize) return _hpatch_FALSE;
|
||
if (cover.length>(hpatch_StreamPos_t)(oldDataSize-cover.oldPos)) return _hpatch_FALSE;
|
||
#endif
|
||
if (newPosBack<cover.newPos){
|
||
hpatch_StreamPos_t copyLength=cover.newPos-newPosBack;
|
||
if (!_TOutStreamCache_copyFromClip(outCache,code_newDataDiffClip,copyLength)) return _hpatch_FALSE;
|
||
if (!_rle_decode_skip(rle_loader,copyLength)) return _hpatch_FALSE;
|
||
}
|
||
if (!_patch_add_old_with_rle(outCache,rle_loader,oldData,cover.oldPos,cover.length,
|
||
temp_cache,cache_size)) return _hpatch_FALSE;
|
||
newPosBack=cover.newPos+cover.length;
|
||
}
|
||
|
||
if (newPosBack<newDataSize){
|
||
hpatch_StreamPos_t copyLength=newDataSize-newPosBack;
|
||
if (!_TOutStreamCache_copyFromClip(outCache,code_newDataDiffClip,copyLength)) return _hpatch_FALSE;
|
||
if (!_rle_decode_skip(rle_loader,copyLength)) return _hpatch_FALSE;
|
||
newPosBack=newDataSize;
|
||
}
|
||
if (!_TOutStreamCache_flush(outCache))
|
||
return _hpatch_FALSE;
|
||
if ( _TBytesRle_load_stream_isFinish(rle_loader)
|
||
&& covers->is_finish(covers)
|
||
&& _TOutStreamCache_isFinish(outCache)
|
||
&& _TStreamCacheClip_isFinish(code_newDataDiffClip)
|
||
&& (newPosBack==newDataSize) )
|
||
return hpatch_TRUE;
|
||
else
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
|
||
#define _kCachePatCount 8
|
||
|
||
#define _cache_alloc(dst,dst_type,memSize,temp_cache,temp_cache_end){ \
|
||
if ((hpatch_size_t)(temp_cache_end-temp_cache) < \
|
||
sizeof(hpatch_StreamPos_t)+(memSize)) return hpatch_FALSE; \
|
||
(dst)=(dst_type*)_hpatch_align_upper(temp_cache,sizeof(hpatch_StreamPos_t));\
|
||
temp_cache=(TByte*)(dst)+(hpatch_size_t)(memSize); \
|
||
}
|
||
|
||
typedef struct _TPackedCovers{
|
||
_TCovers base;
|
||
TStreamCacheClip code_inc_oldPosClip;
|
||
TStreamCacheClip code_inc_newPosClip;
|
||
TStreamCacheClip code_lengthsClip;
|
||
} _TPackedCovers;
|
||
|
||
typedef struct _THDiffHead{
|
||
hpatch_StreamPos_t coverCount;
|
||
hpatch_StreamPos_t lengthSize;
|
||
hpatch_StreamPos_t inc_newPosSize;
|
||
hpatch_StreamPos_t inc_oldPosSize;
|
||
hpatch_StreamPos_t newDataDiffSize;
|
||
hpatch_StreamPos_t headEndPos;
|
||
hpatch_StreamPos_t coverEndPos;
|
||
} _THDiffHead;
|
||
|
||
static hpatch_BOOL read_diff_head(_THDiffHead* out_diffHead,
|
||
const hpatch_TStreamInput* serializedDiff){
|
||
hpatch_StreamPos_t diffPos0;
|
||
const hpatch_StreamPos_t diffPos_end=serializedDiff->streamSize;
|
||
TByte temp_cache[hpatch_kStreamCacheSize];
|
||
TStreamCacheClip diffHeadClip;
|
||
_TStreamCacheClip_init(&diffHeadClip,serializedDiff,0,diffPos_end,temp_cache,hpatch_kStreamCacheSize);
|
||
_clip_unpackUIntTo(&out_diffHead->coverCount,&diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffHead->lengthSize,&diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffHead->inc_newPosSize,&diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffHead->inc_oldPosSize,&diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffHead->newDataDiffSize,&diffHeadClip);
|
||
diffPos0=(hpatch_StreamPos_t)(_TStreamCacheClip_readPosOfSrcStream(&diffHeadClip));
|
||
out_diffHead->headEndPos=diffPos0;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (out_diffHead->lengthSize>(hpatch_StreamPos_t)(diffPos_end-diffPos0)) return _hpatch_FALSE;
|
||
#endif
|
||
diffPos0+=out_diffHead->lengthSize;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (out_diffHead->inc_newPosSize>(hpatch_StreamPos_t)(diffPos_end-diffPos0)) return _hpatch_FALSE;
|
||
#endif
|
||
diffPos0+=out_diffHead->inc_newPosSize;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (out_diffHead->inc_oldPosSize>(hpatch_StreamPos_t)(diffPos_end-diffPos0)) return _hpatch_FALSE;
|
||
#endif
|
||
diffPos0+=out_diffHead->inc_oldPosSize;
|
||
out_diffHead->coverEndPos=diffPos0;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (out_diffHead->newDataDiffSize>(hpatch_StreamPos_t)(diffPos_end-diffPos0)) return _hpatch_FALSE;
|
||
#endif
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _packedCovers_open(_TPackedCovers** out_self,
|
||
_THDiffHead* out_diffHead,
|
||
const hpatch_TStreamInput* serializedDiff,
|
||
TByte* temp_cache,TByte* temp_cache_end){
|
||
hpatch_size_t cacheSize;
|
||
_TPackedCovers* self=0;
|
||
_cache_alloc(self,_TPackedCovers,sizeof(_TPackedCovers),temp_cache,temp_cache_end);
|
||
cacheSize=(temp_cache_end-temp_cache)/3;
|
||
{
|
||
hpatch_StreamPos_t diffPos0;
|
||
if (!read_diff_head(out_diffHead,serializedDiff)) return _hpatch_FALSE;
|
||
diffPos0=out_diffHead->headEndPos;
|
||
_TStreamCacheClip_init(&self->code_lengthsClip,serializedDiff,diffPos0,
|
||
diffPos0+out_diffHead->lengthSize,temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
diffPos0+=out_diffHead->lengthSize;
|
||
_TStreamCacheClip_init(&self->code_inc_newPosClip,serializedDiff,diffPos0,
|
||
diffPos0+out_diffHead->inc_newPosSize,temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
diffPos0+=out_diffHead->inc_newPosSize;
|
||
_TStreamCacheClip_init(&self->code_inc_oldPosClip,serializedDiff,diffPos0,
|
||
diffPos0+out_diffHead->inc_oldPosSize,temp_cache,cacheSize);
|
||
}
|
||
|
||
_covers_init(&self->base,out_diffHead->coverCount,&self->code_inc_oldPosClip,
|
||
&self->code_inc_newPosClip,&self->code_lengthsClip,hpatch_FALSE);
|
||
*out_self=self;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _patch_stream_with_cache(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* serializedDiff,
|
||
hpatch_TCovers* cached_covers,
|
||
TByte* temp_cache,TByte* temp_cache_end){
|
||
struct _THDiffHead diffHead;
|
||
TStreamCacheClip code_newDataDiffClip;
|
||
struct _TBytesRle_load_stream rle_loader;
|
||
hpatch_TCovers* pcovers=0;
|
||
hpatch_StreamPos_t diffPos0;
|
||
const hpatch_StreamPos_t diffPos_end=serializedDiff->streamSize;
|
||
const hpatch_size_t cacheSize=(temp_cache_end-temp_cache)/(cached_covers?(_kCachePatCount-3):_kCachePatCount);
|
||
|
||
assert(out_newData!=0);
|
||
assert(out_newData->write!=0);
|
||
assert(oldData!=0);
|
||
assert(oldData->read!=0);
|
||
assert(serializedDiff!=0);
|
||
assert(serializedDiff->read!=0);
|
||
|
||
//covers
|
||
if (cached_covers==0){
|
||
struct _TPackedCovers* packedCovers;
|
||
if (!_packedCovers_open(&packedCovers,&diffHead,serializedDiff,temp_cache+cacheSize*(_kCachePatCount-3),
|
||
temp_cache_end)) return _hpatch_FALSE;
|
||
pcovers=&packedCovers->base.ICovers; //not need close before return
|
||
}else{
|
||
pcovers=cached_covers;
|
||
if (!read_diff_head(&diffHead,serializedDiff)) return _hpatch_FALSE;
|
||
}
|
||
//newDataDiff
|
||
diffPos0=diffHead.coverEndPos;
|
||
_TStreamCacheClip_init(&code_newDataDiffClip,serializedDiff,diffPos0,
|
||
diffPos0+diffHead.newDataDiffSize,temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
diffPos0+=diffHead.newDataDiffSize;
|
||
|
||
{//rle
|
||
hpatch_StreamPos_t rleCtrlSize;
|
||
hpatch_StreamPos_t rlePos0;
|
||
TStreamCacheClip* rleHeadClip=&rle_loader.ctrlClip;//rename, share address
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (cacheSize<hpatch_kMaxPackedUIntBytes) return _hpatch_FALSE;
|
||
#endif
|
||
_TStreamCacheClip_init(rleHeadClip,serializedDiff,diffPos0,diffPos_end,
|
||
temp_cache,hpatch_kMaxPackedUIntBytes);
|
||
_clip_unpackUIntTo(&rleCtrlSize,rleHeadClip);
|
||
rlePos0=(hpatch_StreamPos_t)(_TStreamCacheClip_readPosOfSrcStream(rleHeadClip));
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (rleCtrlSize>(hpatch_StreamPos_t)(diffPos_end-rlePos0)) return _hpatch_FALSE;
|
||
#endif
|
||
_TBytesRle_load_stream_init(&rle_loader);
|
||
_TStreamCacheClip_init(&rle_loader.ctrlClip,serializedDiff,rlePos0,rlePos0+rleCtrlSize,
|
||
temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
_TStreamCacheClip_init(&rle_loader.rleCodeClip,serializedDiff,rlePos0+rleCtrlSize,diffPos_end,
|
||
temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
}
|
||
{
|
||
_TOutStreamCache outCache;
|
||
_TOutStreamCache_init(&outCache,out_newData,temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
return patchByClip(&outCache,oldData,pcovers,&code_newDataDiffClip,
|
||
&rle_loader,temp_cache,cacheSize);
|
||
}
|
||
}
|
||
|
||
|
||
hpatch_BOOL read_diffz_head(hpatch_compressedDiffInfo* out_diffInfo,_THDiffzHead* out_head,
|
||
const hpatch_TStreamInput* compressedDiff){
|
||
TStreamCacheClip _diffHeadClip;
|
||
TStreamCacheClip* diffHeadClip=&_diffHeadClip;
|
||
TByte temp_cache[hpatch_kStreamCacheSize];
|
||
_TStreamCacheClip_init(&_diffHeadClip,compressedDiff,0,compressedDiff->streamSize,
|
||
temp_cache,hpatch_kStreamCacheSize);
|
||
{//type
|
||
const char* kVersionType="HDIFF13";
|
||
char* tempType=out_diffInfo->compressType;
|
||
if (!_TStreamCacheClip_readType_end(diffHeadClip,'&',tempType)) return _hpatch_FALSE;
|
||
if (0!=strcmp(tempType,kVersionType)) return _hpatch_FALSE;
|
||
}
|
||
{//read compressType
|
||
if (!_TStreamCacheClip_readType_end(diffHeadClip,'\0',
|
||
out_diffInfo->compressType)) return _hpatch_FALSE;
|
||
out_head->typesEndPos=_TStreamCacheClip_readPosOfSrcStream(diffHeadClip);
|
||
}
|
||
_clip_unpackUIntTo(&out_diffInfo->newDataSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->oldDataSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->coverCount,diffHeadClip);
|
||
out_head->compressSizeBeginPos=_TStreamCacheClip_readPosOfSrcStream(diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->cover_buf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->compress_cover_buf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->rle_ctrlBuf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->compress_rle_ctrlBuf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->rle_codeBuf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->compress_rle_codeBuf_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->newDataDiff_size,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_head->compress_newDataDiff_size,diffHeadClip);
|
||
out_head->headEndPos=_TStreamCacheClip_readPosOfSrcStream(diffHeadClip);
|
||
|
||
out_diffInfo->compressedCount=((out_head->compress_cover_buf_size)?1:0)
|
||
+((out_head->compress_rle_ctrlBuf_size)?1:0)
|
||
+((out_head->compress_rle_codeBuf_size)?1:0)
|
||
+((out_head->compress_newDataDiff_size)?1:0);
|
||
if (out_head->compress_cover_buf_size>0)
|
||
out_head->coverEndPos=out_head->headEndPos+out_head->compress_cover_buf_size;
|
||
else
|
||
out_head->coverEndPos=out_head->headEndPos+out_head->cover_buf_size;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL getCompressedDiffInfo(hpatch_compressedDiffInfo* out_diffInfo,
|
||
const hpatch_TStreamInput* compressedDiff){
|
||
_THDiffzHead head;
|
||
assert(out_diffInfo!=0);
|
||
assert(compressedDiff!=0);
|
||
assert(compressedDiff->read!=0);
|
||
return read_diffz_head(out_diffInfo,&head,compressedDiff);
|
||
}
|
||
|
||
#define _clear_return(exitValue) { result=exitValue; goto clear; }
|
||
|
||
#define _kCacheDecCount 6
|
||
|
||
static
|
||
hpatch_BOOL _patch_decompress_cache(const hpatch_TStreamOutput* out_newData,
|
||
hpatch_TStreamInput* once_in_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* compressedDiff,
|
||
hpatch_TDecompress* decompressPlugin,
|
||
hpatch_TCovers* cached_covers,
|
||
TByte* temp_cache, TByte* temp_cache_end){
|
||
TStreamCacheClip coverClip;
|
||
TStreamCacheClip code_newDataDiffClip;
|
||
struct _TBytesRle_load_stream rle_loader;
|
||
_THDiffzHead head;
|
||
hpatch_compressedDiffInfo diffInfo;
|
||
_TDecompressInputStream decompressers[4];
|
||
hpatch_size_t i;
|
||
hpatch_StreamPos_t coverCount;
|
||
hpatch_BOOL result=hpatch_TRUE;
|
||
hpatch_StreamPos_t diffPos0=0;
|
||
const hpatch_StreamPos_t diffPos_end=compressedDiff->streamSize;
|
||
const hpatch_size_t cacheSize=(temp_cache_end-temp_cache)/(cached_covers?(_kCacheDecCount-1):_kCacheDecCount);
|
||
if (cacheSize<=hpatch_kMaxPluginTypeLength) return _hpatch_FALSE;
|
||
assert(out_newData!=0);
|
||
assert(out_newData->write!=0);
|
||
assert(oldData!=0);
|
||
assert(oldData->read!=0);
|
||
assert(compressedDiff!=0);
|
||
assert(compressedDiff->read!=0);
|
||
{//head
|
||
if (!read_diffz_head(&diffInfo,&head,compressedDiff)) return _hpatch_FALSE;
|
||
if ((diffInfo.oldDataSize!=oldData->streamSize)
|
||
||(diffInfo.newDataSize!=out_newData->streamSize)) return _hpatch_FALSE;
|
||
|
||
if ((decompressPlugin==0)&&(diffInfo.compressedCount!=0)) return _hpatch_FALSE;
|
||
if ((decompressPlugin)&&(diffInfo.compressedCount>0))
|
||
if (!decompressPlugin->is_can_open(diffInfo.compressType)) return _hpatch_FALSE;
|
||
diffPos0=head.headEndPos;
|
||
}
|
||
|
||
for (i=0;i<sizeof(decompressers)/sizeof(_TDecompressInputStream);++i)
|
||
decompressers[i].decompressHandle=0;
|
||
_TBytesRle_load_stream_init(&rle_loader);
|
||
|
||
if (cached_covers){
|
||
diffPos0=head.coverEndPos;
|
||
}else{
|
||
if (!getStreamClip(&coverClip,&decompressers[0],
|
||
head.cover_buf_size,head.compress_cover_buf_size,compressedDiff,&diffPos0,
|
||
decompressPlugin,temp_cache+cacheSize*(_kCacheDecCount-1),cacheSize)) _clear_return(_hpatch_FALSE);
|
||
}
|
||
if (!getStreamClip(&rle_loader.ctrlClip,&decompressers[1],
|
||
head.rle_ctrlBuf_size,head.compress_rle_ctrlBuf_size,compressedDiff,&diffPos0,
|
||
decompressPlugin,temp_cache,cacheSize)) _clear_return(_hpatch_FALSE);
|
||
temp_cache+=cacheSize;
|
||
if (!getStreamClip(&rle_loader.rleCodeClip,&decompressers[2],
|
||
head.rle_codeBuf_size,head.compress_rle_codeBuf_size,compressedDiff,&diffPos0,
|
||
decompressPlugin,temp_cache,cacheSize)) _clear_return(_hpatch_FALSE);
|
||
temp_cache+=cacheSize;
|
||
if (!getStreamClip(&code_newDataDiffClip,&decompressers[3],
|
||
head.newDataDiff_size,head.compress_newDataDiff_size,compressedDiff,&diffPos0,
|
||
decompressPlugin,temp_cache,cacheSize)) _clear_return(_hpatch_FALSE);
|
||
temp_cache+=cacheSize;
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (diffPos0!=diffPos_end) _clear_return(_hpatch_FALSE);
|
||
#endif
|
||
|
||
coverCount=head.coverCount;
|
||
{
|
||
_TCovers covers;
|
||
hpatch_TCovers* pcovers=0;
|
||
_TOutStreamCache outCache;
|
||
_TOutStreamCache_init(&outCache,out_newData,temp_cache,cacheSize);
|
||
temp_cache+=cacheSize;
|
||
if (cached_covers){
|
||
pcovers=cached_covers;
|
||
}else{
|
||
_covers_init(&covers,coverCount,&coverClip,&coverClip,&coverClip,hpatch_TRUE);
|
||
pcovers=&covers.ICovers; //not need close before return
|
||
}
|
||
result=patchByClip(&outCache,oldData,pcovers,&code_newDataDiffClip,&rle_loader,
|
||
temp_cache,cacheSize);
|
||
//if ((pcovers!=cached_covers)&&(!pcovers->close(pcovers))) result=_hpatch_FALSE;
|
||
}
|
||
clear:
|
||
for (i=0;i<sizeof(decompressers)/sizeof(_TDecompressInputStream);++i) {
|
||
if (decompressers[i].decompressHandle){
|
||
if (!decompressPlugin->close(decompressPlugin,decompressers[i].decompressHandle))
|
||
result=_hpatch_FALSE;
|
||
decompressers[i].decompressHandle=0;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
hpatch_inline static hpatch_BOOL _cache_load_all(const hpatch_TStreamInput* data,
|
||
TByte* cache,TByte* cache_end){
|
||
assert((hpatch_size_t)(cache_end-cache)==data->streamSize);
|
||
return data->read(data,0,cache,cache_end);
|
||
}
|
||
|
||
typedef struct _TCompressedCovers{
|
||
_TCovers base;
|
||
TStreamCacheClip coverClip;
|
||
_TDecompressInputStream decompresser;
|
||
} _TCompressedCovers;
|
||
|
||
static hpatch_BOOL _compressedCovers_close(hpatch_TCovers* covers){
|
||
hpatch_BOOL result=hpatch_TRUE;
|
||
_TCompressedCovers* self=(_TCompressedCovers*)covers;
|
||
if (self){
|
||
if (self->decompresser.decompressHandle){
|
||
result=self->decompresser.decompressPlugin->close(self->decompresser.decompressPlugin,
|
||
self->decompresser.decompressHandle);
|
||
self->decompresser.decompressHandle=0;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static hpatch_BOOL _compressedCovers_open(_TCompressedCovers** out_self,
|
||
hpatch_compressedDiffInfo* out_diffInfo,
|
||
const hpatch_TStreamInput* compressedDiff,
|
||
hpatch_TDecompress* decompressPlugin,
|
||
TByte* temp_cache,TByte* temp_cache_end){
|
||
_THDiffzHead head;
|
||
hpatch_StreamPos_t diffPos0=0;
|
||
_TCompressedCovers* self=0;
|
||
_cache_alloc(self,_TCompressedCovers,sizeof(_TCompressedCovers),temp_cache,temp_cache_end);
|
||
if (!read_diffz_head(out_diffInfo,&head,compressedDiff)) return _hpatch_FALSE;
|
||
diffPos0=head.headEndPos;
|
||
if (head.compress_cover_buf_size>0){
|
||
if (decompressPlugin==0) return _hpatch_FALSE;
|
||
if (!decompressPlugin->is_can_open(out_diffInfo->compressType)) return _hpatch_FALSE;
|
||
}
|
||
|
||
_covers_init(&self->base,head.coverCount,&self->coverClip,
|
||
&self->coverClip,&self->coverClip,hpatch_TRUE);
|
||
self->base.ICovers.close=_compressedCovers_close;
|
||
memset(&self->decompresser,0, sizeof(self->decompresser));
|
||
if (!getStreamClip(&self->coverClip,&self->decompresser,
|
||
head.cover_buf_size,head.compress_cover_buf_size,
|
||
compressedDiff,&diffPos0,decompressPlugin,
|
||
temp_cache,temp_cache_end-temp_cache)) {
|
||
return _hpatch_FALSE;
|
||
};
|
||
*out_self=self;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
#if (_IS_NEED_CACHE_OLD_BY_COVERS)
|
||
|
||
typedef struct _TArrayCovers{
|
||
hpatch_TCovers ICovers;
|
||
void* pCCovers;
|
||
hpatch_size_t coverCount;
|
||
hpatch_size_t cur_index;
|
||
hpatch_BOOL is32;
|
||
} _TArrayCovers;
|
||
|
||
|
||
typedef struct hpatch_TCCover32{
|
||
hpatch_uint32_t oldPos;
|
||
hpatch_uint32_t newPos;
|
||
hpatch_uint32_t length;
|
||
hpatch_uint32_t cachePos; //todo:放到临时内存中,用完释放?逻辑会比较复杂;
|
||
} hpatch_TCCover32;
|
||
|
||
typedef struct hpatch_TCCover64{
|
||
hpatch_StreamPos_t oldPos;
|
||
hpatch_StreamPos_t newPos;
|
||
hpatch_StreamPos_t length;
|
||
hpatch_StreamPos_t cachePos;
|
||
} hpatch_TCCover64;
|
||
|
||
#define _arrayCovers_get(self,i,item) (((self)->is32)? \
|
||
((const hpatch_uint32_t*)(self)->pCCovers)[(i)*4+(item)]:\
|
||
((const hpatch_StreamPos_t*)(self)->pCCovers)[(i)*4+(item)])
|
||
#define _arrayCovers_get_oldPos(self,i) _arrayCovers_get(self,i,0)
|
||
#define _arrayCovers_get_len(self,i) _arrayCovers_get(self,i,2)
|
||
#define _arrayCovers_get_cachePos(self,i) _arrayCovers_get(self,i,3)
|
||
|
||
#define _arrayCovers_set(self,i,item,v) { if ((self)->is32){ \
|
||
((hpatch_uint32_t*)(self)->pCCovers)[(i)*4+(item)]=(hpatch_uint32_t)(v); }else{ \
|
||
((hpatch_StreamPos_t*)(self)->pCCovers)[(i)*4+(item)]=(v); } }
|
||
#define _arrayCovers_set_cachePos(self,i,v) _arrayCovers_set(self,i,3,v)
|
||
|
||
hpatch_inline static hpatch_StreamPos_t arrayCovers_memSize(hpatch_StreamPos_t coverCount,hpatch_BOOL is32){
|
||
return coverCount*(is32?sizeof(hpatch_TCCover32):sizeof(hpatch_TCCover64));
|
||
}
|
||
|
||
static hpatch_BOOL _arrayCovers_is_finish(const hpatch_TCovers* covers){
|
||
const _TArrayCovers* self=(const _TArrayCovers*)covers;
|
||
return (self->coverCount==self->cur_index);
|
||
}
|
||
static hpatch_StreamPos_t _arrayCovers_leaveCoverCount(const hpatch_TCovers* covers){
|
||
const _TArrayCovers* self=(const _TArrayCovers*)covers;
|
||
return self->coverCount-self->cur_index;
|
||
}
|
||
static hpatch_BOOL _arrayCovers_read_cover(struct hpatch_TCovers* covers,hpatch_TCover* out_cover){
|
||
_TArrayCovers* self=(_TArrayCovers*)covers;
|
||
hpatch_size_t i=self->cur_index;
|
||
if (i<self->coverCount){
|
||
if (self->is32){
|
||
const hpatch_TCCover32* pCover=((const hpatch_TCCover32*)self->pCCovers)+i;
|
||
out_cover->oldPos=pCover->oldPos;
|
||
out_cover->newPos=pCover->newPos;
|
||
out_cover->length=pCover->length;
|
||
}else{
|
||
const hpatch_TCCover64* pCover=((const hpatch_TCCover64*)self->pCCovers)+i;
|
||
out_cover->oldPos=pCover->oldPos;
|
||
out_cover->newPos=pCover->newPos;
|
||
out_cover->length=pCover->length;
|
||
}
|
||
self->cur_index=i+1;
|
||
return hpatch_TRUE;
|
||
}else{
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
|
||
static hpatch_BOOL _arrayCovers_load(_TArrayCovers** out_self,hpatch_TCovers* src_covers,
|
||
hpatch_BOOL isUsedCover32,hpatch_BOOL* out_isReadError,
|
||
TByte** ptemp_cache,TByte* temp_cache_end){
|
||
TByte* temp_cache=*ptemp_cache;
|
||
hpatch_StreamPos_t _coverCount=src_covers->leave_cover_count(src_covers);
|
||
hpatch_StreamPos_t memSize=arrayCovers_memSize(_coverCount,isUsedCover32);
|
||
hpatch_size_t i;
|
||
void* pCovers;
|
||
_TArrayCovers* self=0;
|
||
hpatch_size_t coverCount=(hpatch_size_t)_coverCount;
|
||
|
||
*out_isReadError=hpatch_FALSE;
|
||
if (coverCount!=_coverCount) return hpatch_FALSE;
|
||
|
||
_cache_alloc(self,_TArrayCovers,sizeof(_TArrayCovers),temp_cache,temp_cache_end);
|
||
_cache_alloc(pCovers,void,memSize,temp_cache,temp_cache_end);
|
||
if (isUsedCover32){
|
||
hpatch_TCCover32* pdst=(hpatch_TCCover32*)pCovers;
|
||
for (i=0;i<coverCount;++i,++pdst) {
|
||
hpatch_TCover cover;
|
||
if (!src_covers->read_cover(src_covers,&cover))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
pdst->oldPos=(hpatch_uint32_t)cover.oldPos;
|
||
pdst->newPos=(hpatch_uint32_t)cover.newPos;
|
||
pdst->length=(hpatch_uint32_t)cover.length;
|
||
}
|
||
}else{
|
||
hpatch_TCCover64* pdst=(hpatch_TCCover64*)pCovers;
|
||
for (i=0;i<coverCount;++i,++pdst) {
|
||
if (!src_covers->read_cover(src_covers,(hpatch_TCover*)pdst))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
}
|
||
}
|
||
if (!src_covers->is_finish(src_covers))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
|
||
self->pCCovers=pCovers;
|
||
self->is32=isUsedCover32;
|
||
self->coverCount=coverCount;
|
||
self->cur_index=0;
|
||
self->ICovers.close=_covers_close_nil;
|
||
self->ICovers.is_finish=_arrayCovers_is_finish;
|
||
self->ICovers.leave_cover_count=_arrayCovers_leaveCoverCount;
|
||
self->ICovers.read_cover=_arrayCovers_read_cover;
|
||
*out_self=self;
|
||
*ptemp_cache=temp_cache;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
#define _arrayCovers_comp(_uint_t,_x,_y,item){ \
|
||
_uint_t x=((const _uint_t*)_x)[item]; \
|
||
_uint_t y=((const _uint_t*)_y)[item]; \
|
||
return (x<y)?(-1):((x>y)?1:0); \
|
||
}
|
||
#ifdef _MSC_VER
|
||
# define __CALL_BACK_C __cdecl
|
||
#else
|
||
# define __CALL_BACK_C
|
||
#endif
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_old_32(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_uint32_t,_x,_y,0);
|
||
}
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_old(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_StreamPos_t,_x,_y,0);
|
||
}
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_new_32(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_uint32_t,_x,_y,1);
|
||
}
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_new(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_StreamPos_t,_x,_y,1);
|
||
}
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_len_32(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_uint32_t,_x,_y,2);
|
||
}
|
||
static hpatch_int __CALL_BACK_C _arrayCovers_comp_by_len(const void* _x, const void *_y){
|
||
_arrayCovers_comp(hpatch_StreamPos_t,_x,_y,2);
|
||
}
|
||
|
||
static void _arrayCovers_sort_by_old(_TArrayCovers* self){
|
||
if (self->is32)
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover32),_arrayCovers_comp_by_old_32);
|
||
else
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover64),_arrayCovers_comp_by_old);
|
||
}
|
||
static void _arrayCovers_sort_by_new(_TArrayCovers* self){
|
||
if (self->is32)
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover32),_arrayCovers_comp_by_new_32);
|
||
else
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover64),_arrayCovers_comp_by_new);
|
||
}
|
||
static void _arrayCovers_sort_by_len(_TArrayCovers* self){
|
||
if (self->is32)
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover32),_arrayCovers_comp_by_len_32);
|
||
else
|
||
qsort(self->pCCovers,self->coverCount,sizeof(hpatch_TCCover64),_arrayCovers_comp_by_len);
|
||
}
|
||
|
||
static hpatch_size_t _getMaxCachedLen(const _TArrayCovers* src_covers,
|
||
TByte* temp_cache,TByte* temp_cache_end,TByte* cache_buf_end){
|
||
const hpatch_size_t kMaxCachedLen =~((hpatch_size_t)0);//允许缓存的最长单个数据长度;
|
||
hpatch_StreamPos_t mlen=0;
|
||
hpatch_StreamPos_t sum=0;
|
||
const hpatch_size_t coverCount=src_covers->coverCount;
|
||
hpatch_size_t i;
|
||
_TArrayCovers cur_covers=*src_covers;
|
||
hpatch_size_t cacheSize=temp_cache_end-temp_cache;
|
||
hpatch_StreamPos_t memSize=arrayCovers_memSize(src_covers->coverCount,src_covers->is32);
|
||
_cache_alloc(cur_covers.pCCovers,void,memSize,temp_cache,temp_cache_end); //fail return 0
|
||
memcpy(cur_covers.pCCovers,src_covers->pCCovers,(hpatch_size_t)memSize);
|
||
_arrayCovers_sort_by_len(&cur_covers);
|
||
|
||
for (i=0; i<coverCount;++i) {
|
||
mlen=_arrayCovers_get_len(&cur_covers,i);
|
||
sum+=mlen;
|
||
if (sum<=cacheSize){
|
||
continue;
|
||
}else{
|
||
--mlen;
|
||
break;
|
||
}
|
||
}
|
||
if (mlen>kMaxCachedLen)
|
||
mlen=kMaxCachedLen;
|
||
return (hpatch_size_t)mlen;
|
||
}
|
||
|
||
static hpatch_size_t _set_cache_pos(_TArrayCovers* covers,hpatch_size_t maxCachedLen,
|
||
hpatch_StreamPos_t* poldPosBegin,hpatch_StreamPos_t* poldPosEnd){
|
||
const hpatch_size_t coverCount=covers->coverCount;
|
||
const hpatch_size_t kMinCacheCoverCount=coverCount/8+1; //控制最小缓存数量,否则缓存的意义太小;
|
||
hpatch_StreamPos_t oldPosBegin=hpatch_kNullStreamPos;
|
||
hpatch_StreamPos_t oldPosEnd=0;
|
||
hpatch_size_t cacheCoverCount=0;
|
||
hpatch_size_t sum=0;//result
|
||
hpatch_size_t i;
|
||
for (i=0; i<coverCount;++i) {
|
||
hpatch_StreamPos_t clen=_arrayCovers_get_len(covers,i);
|
||
if (clen<=maxCachedLen){
|
||
hpatch_StreamPos_t oldPos;
|
||
_arrayCovers_set_cachePos(covers,i,sum);
|
||
sum+=(hpatch_size_t)clen;
|
||
++cacheCoverCount;
|
||
|
||
oldPos=_arrayCovers_get_oldPos(covers,i);
|
||
if (oldPos<oldPosBegin) oldPosBegin=oldPos;
|
||
if (oldPos+clen>oldPosEnd) oldPosEnd=oldPos+clen;
|
||
}
|
||
}
|
||
if (cacheCoverCount<kMinCacheCoverCount)
|
||
return 0;//fail
|
||
*poldPosBegin=oldPosBegin;
|
||
*poldPosEnd=oldPosEnd;
|
||
return sum;
|
||
}
|
||
|
||
//一个比较简单的缓存策略:
|
||
// 1. 根据缓冲区大小限制,选择出最短的一批覆盖线来缓存;
|
||
// 2. 顺序访问一次oldData文件,填充这些缓存;
|
||
// 3. 顺序访问时跳过中间过大的对缓存无用的区域;
|
||
|
||
static hpatch_BOOL _cache_old_load(const hpatch_TStreamInput*oldData,
|
||
hpatch_StreamPos_t oldPos,hpatch_StreamPos_t oldPosAllEnd,
|
||
_TArrayCovers* arrayCovers,hpatch_size_t maxCachedLen,hpatch_size_t sumCacheLen,
|
||
TByte* old_cache,TByte* old_cache_end,TByte* cache_buf_end){
|
||
const hpatch_size_t kMinSpaceLen =(1<<(20+2));//跳过seekTime*speed长度的空间(SSD可以更小)时间上划得来,否则就顺序访问;
|
||
const hpatch_size_t kAccessPageSize=(1<<(10+2));//页面对齐访问;
|
||
hpatch_BOOL result=hpatch_TRUE;
|
||
hpatch_size_t cur_i=0,i;
|
||
const hpatch_size_t coverCount=arrayCovers->coverCount;
|
||
TByte* cache_buf=old_cache_end;
|
||
assert((hpatch_size_t)(old_cache_end-old_cache)>=sumCacheLen);
|
||
|
||
if ((hpatch_size_t)(cache_buf_end-cache_buf)>=kAccessPageSize*2){
|
||
cache_buf=(TByte*)_hpatch_align_upper(cache_buf,kAccessPageSize);
|
||
if ((hpatch_size_t)(cache_buf_end-cache_buf)>=(kMinSpaceLen>>1))
|
||
cache_buf_end=cache_buf+(kMinSpaceLen>>1);
|
||
else
|
||
cache_buf_end=(TByte*)_hpatch_align_lower(cache_buf_end,kAccessPageSize);
|
||
}
|
||
oldPos=_hpatch_align_type_lower(hpatch_StreamPos_t,oldPos,kAccessPageSize);
|
||
if (oldPos<kMinSpaceLen) oldPos=0;
|
||
|
||
_arrayCovers_sort_by_old(arrayCovers);
|
||
while ((oldPos<oldPosAllEnd)&(cur_i<coverCount)) {
|
||
hpatch_StreamPos_t oldPosEnd;
|
||
hpatch_size_t readLen=(cache_buf_end-cache_buf);
|
||
if (readLen>(oldPosAllEnd-oldPos)) readLen=(hpatch_size_t)(oldPosAllEnd-oldPos);
|
||
if (!oldData->read(oldData,oldPos,cache_buf,
|
||
cache_buf+readLen)) { result=_hpatch_FALSE; break; } //error
|
||
oldPosEnd=oldPos+readLen;
|
||
for (i=cur_i;i<coverCount;++i){
|
||
hpatch_StreamPos_t ioldPos,ioldPosEnd;
|
||
hpatch_StreamPos_t ilen=_arrayCovers_get_len(arrayCovers,i);
|
||
if (ilen>maxCachedLen){//覆盖线比较长不需要缓存,下一个覆盖线;
|
||
if (i==cur_i)
|
||
++cur_i;
|
||
continue;
|
||
}
|
||
ioldPos=_arrayCovers_get_oldPos(arrayCovers,i);
|
||
ioldPosEnd=ioldPos+ilen;
|
||
if (ioldPosEnd>oldPos){
|
||
// [oldPos oldPosEnd]
|
||
// ioldPosEnd]----or----]
|
||
if (ioldPos<oldPosEnd){//有交集,需要cache
|
||
// [----or----[ioldPos ioldPosEnd]----or----]
|
||
hpatch_StreamPos_t from;
|
||
hpatch_size_t copyLen;
|
||
hpatch_StreamPos_t dstPos=_arrayCovers_get_cachePos(arrayCovers,i);
|
||
//assert(dstPos<=(hpatch_size_t)(old_cache_end-old_cache));
|
||
if (ioldPos>=oldPos){
|
||
// [ioldPos ioldPosEnd]----or----]
|
||
from=ioldPos;
|
||
}else{
|
||
// [ioldPos ioldPosEnd]----or----]
|
||
from=oldPos;
|
||
dstPos+=(oldPos-ioldPos);
|
||
}
|
||
copyLen=(hpatch_size_t)(((ioldPosEnd<=oldPosEnd)?ioldPosEnd:oldPosEnd)-from);
|
||
//assert(dstPos+copyLen<=(hpatch_size_t)(old_cache_end-old_cache));
|
||
//assert(sumCacheLen>=copyLen);
|
||
memcpy(old_cache+(hpatch_size_t)dstPos,cache_buf+(from-oldPos),copyLen);
|
||
sumCacheLen-=copyLen;
|
||
if ((i==cur_i)&(oldPosEnd>=ioldPosEnd))
|
||
++cur_i;
|
||
}else{//后面覆盖线暂时都不会与当前数据有交集了,下一块数据;
|
||
// [oldPos oldPosEnd]
|
||
// [ioldPos ioldPosEnd]
|
||
if ((i==cur_i)&&(ioldPos-oldPosEnd>=kMinSpaceLen))
|
||
oldPosEnd=_hpatch_align_type_lower(hpatch_StreamPos_t,ioldPos,kAccessPageSize);
|
||
break;
|
||
}
|
||
}else{//当前覆盖线已经落后于当前数据,下一个覆盖线;
|
||
// [oldPos oldPosEnd]
|
||
// [ioldPos ioldPosEnd]
|
||
if (i==cur_i)
|
||
++cur_i;
|
||
}
|
||
}
|
||
oldPos=oldPosEnd;
|
||
}
|
||
_arrayCovers_sort_by_new(arrayCovers);
|
||
assert(sumCacheLen==0);
|
||
return result;
|
||
}
|
||
|
||
typedef struct _cache_old_TStreamInput{
|
||
_TArrayCovers arrayCovers;
|
||
hpatch_BOOL isInHitCache;
|
||
hpatch_size_t maxCachedLen;
|
||
hpatch_StreamPos_t readFromPos;
|
||
hpatch_StreamPos_t readFromPosEnd;
|
||
const TByte* caches;
|
||
const TByte* cachesEnd;
|
||
const hpatch_TStreamInput* oldData;
|
||
} _cache_old_TStreamInput;
|
||
|
||
static hpatch_BOOL _cache_old_StreamInput_read(const hpatch_TStreamInput* stream,
|
||
hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
_cache_old_TStreamInput* self=(_cache_old_TStreamInput*)stream->streamImport;
|
||
hpatch_StreamPos_t dataLen=(hpatch_size_t)(self->readFromPosEnd-self->readFromPos);
|
||
hpatch_size_t readLen;
|
||
if (dataLen==0){//next cover
|
||
hpatch_StreamPos_t oldPos;
|
||
hpatch_size_t i=self->arrayCovers.cur_index++;
|
||
if (i>=self->arrayCovers.coverCount) return _hpatch_FALSE;//error;
|
||
oldPos=_arrayCovers_get_oldPos(&self->arrayCovers,i);
|
||
dataLen=_arrayCovers_get_len(&self->arrayCovers,i);
|
||
self->isInHitCache=(dataLen<=self->maxCachedLen);
|
||
self->readFromPos=oldPos;
|
||
self->readFromPosEnd=oldPos+dataLen;
|
||
}
|
||
readLen=out_data_end-out_data;
|
||
if ((readLen>dataLen)||(self->readFromPos!=readFromPos)) return _hpatch_FALSE; //error
|
||
self->readFromPos=readFromPos+readLen;
|
||
if (self->isInHitCache){
|
||
assert(readLen<=(hpatch_size_t)(self->cachesEnd-self->caches));
|
||
memcpy(out_data,self->caches,readLen);
|
||
self->caches+=readLen;
|
||
return hpatch_TRUE;
|
||
}else{
|
||
return self->oldData->read(self->oldData,readFromPos,out_data,out_data_end);
|
||
}
|
||
}
|
||
|
||
static hpatch_BOOL _cache_old(hpatch_TStreamInput** out_cachedOld,const hpatch_TStreamInput* oldData,
|
||
_TArrayCovers* arrayCovers,hpatch_BOOL* out_isReadError,
|
||
TByte* temp_cache,TByte** ptemp_cache_end,TByte* cache_buf_end){
|
||
_cache_old_TStreamInput* self;
|
||
TByte* temp_cache_end=*ptemp_cache_end;
|
||
hpatch_StreamPos_t oldPosBegin;
|
||
hpatch_StreamPos_t oldPosEnd;
|
||
hpatch_size_t sumCacheLen;
|
||
hpatch_size_t maxCachedLen;
|
||
*out_isReadError=hpatch_FALSE;
|
||
_cache_alloc(*out_cachedOld,hpatch_TStreamInput,sizeof(hpatch_TStreamInput),
|
||
temp_cache,temp_cache_end);
|
||
_cache_alloc(self,_cache_old_TStreamInput,sizeof(_cache_old_TStreamInput),
|
||
temp_cache,temp_cache_end);
|
||
|
||
maxCachedLen=_getMaxCachedLen(arrayCovers,temp_cache,temp_cache_end,cache_buf_end);
|
||
if (maxCachedLen==0) return hpatch_FALSE;
|
||
sumCacheLen=_set_cache_pos(arrayCovers,maxCachedLen,&oldPosBegin,&oldPosEnd);
|
||
if (sumCacheLen==0) return hpatch_FALSE;
|
||
temp_cache_end=temp_cache+sumCacheLen;
|
||
|
||
if (!_cache_old_load(oldData,oldPosBegin,oldPosEnd,arrayCovers,maxCachedLen,sumCacheLen,
|
||
temp_cache,temp_cache_end,cache_buf_end))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
|
||
{//out
|
||
self->arrayCovers=*arrayCovers;
|
||
self->arrayCovers.cur_index=0;
|
||
self->isInHitCache=hpatch_FALSE;
|
||
self->maxCachedLen=maxCachedLen;
|
||
self->caches=temp_cache;
|
||
self->cachesEnd=temp_cache_end;
|
||
self->readFromPos=0;
|
||
self->readFromPosEnd=0;
|
||
self->oldData=oldData;
|
||
(*out_cachedOld)->streamImport=self;
|
||
(*out_cachedOld)->streamSize=oldData->streamSize;
|
||
(*out_cachedOld)->read=_cache_old_StreamInput_read;
|
||
*ptemp_cache_end=temp_cache_end;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
#endif //_IS_NEED_CACHE_OLD_BY_COVERS
|
||
|
||
|
||
static hpatch_BOOL _patch_cache(hpatch_TCovers** out_covers,
|
||
const hpatch_TStreamInput** poldData,hpatch_StreamPos_t newDataSize,
|
||
const hpatch_TStreamInput* diffData,hpatch_BOOL isCompressedDiff,
|
||
hpatch_TDecompress* decompressPlugin,size_t kCacheCount,
|
||
TByte** ptemp_cache,TByte** ptemp_cache_end,hpatch_BOOL* out_isReadError){
|
||
const hpatch_TStreamInput* oldData=*poldData;
|
||
const hpatch_size_t kMinCacheSize=hpatch_kStreamCacheSize*kCacheCount;
|
||
#if (_IS_NEED_CACHE_OLD_BY_COVERS)
|
||
const hpatch_size_t kBestACacheSize=hpatch_kFileIOBufBetterSize; //内存足够时比较好的hpatch_kStreamCacheSize值;
|
||
const hpatch_size_t _minActiveSize=(1<<20)*8;
|
||
const hpatch_StreamPos_t _betterActiveSize=kBestACacheSize*kCacheCount*2+oldData->streamSize/8;
|
||
const hpatch_size_t kActiveCacheOldMemorySize = //尝试激活CacheOld功能的内存下限;
|
||
(_betterActiveSize>_minActiveSize)?_minActiveSize:(hpatch_size_t)_betterActiveSize;
|
||
#endif //_IS_NEED_CACHE_OLD_BY_COVERS
|
||
TByte* temp_cache=*ptemp_cache;
|
||
TByte* temp_cache_end=*ptemp_cache_end;
|
||
*out_isReadError=hpatch_FALSE;
|
||
if ((hpatch_size_t)(temp_cache_end-temp_cache)>=oldData->streamSize+kMinCacheSize
|
||
+sizeof(hpatch_TStreamInput)+sizeof(hpatch_StreamPos_t)){//load all oldData
|
||
hpatch_TStreamInput* replace_oldData=0;
|
||
_cache_alloc(replace_oldData,hpatch_TStreamInput,sizeof(hpatch_TStreamInput),
|
||
temp_cache,temp_cache_end);
|
||
if (!_cache_load_all(oldData,temp_cache_end-oldData->streamSize,
|
||
temp_cache_end)){ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
|
||
mem_as_hStreamInput(replace_oldData,temp_cache_end-oldData->streamSize,temp_cache_end);
|
||
temp_cache_end-=oldData->streamSize;
|
||
// [ patch cache | oldData cache ]
|
||
// [ (cacheSize-oldData->streamSize) | (oldData->streamSize) ]
|
||
*out_covers=0;
|
||
*poldData=replace_oldData;
|
||
*ptemp_cache=temp_cache;
|
||
*ptemp_cache_end=temp_cache_end;
|
||
return hpatch_TRUE;
|
||
}
|
||
#if (_IS_NEED_CACHE_OLD_BY_COVERS)
|
||
else if ((hpatch_size_t)(temp_cache_end-temp_cache)>=kActiveCacheOldMemorySize) {
|
||
hpatch_BOOL isUsedCover32;
|
||
TByte* temp_cache_end_back=temp_cache_end;
|
||
_TArrayCovers* arrayCovers=0;
|
||
assert((hpatch_size_t)(temp_cache_end-temp_cache)>kBestACacheSize*kCacheCount);
|
||
assert(kBestACacheSize>sizeof(_TCompressedCovers)+sizeof(_TPackedCovers));
|
||
if (isCompressedDiff){
|
||
hpatch_compressedDiffInfo diffInfo;
|
||
_TCompressedCovers* compressedCovers=0;
|
||
if (!_compressedCovers_open(&compressedCovers,&diffInfo,diffData,decompressPlugin,
|
||
temp_cache_end-kBestACacheSize-sizeof(_TCompressedCovers),temp_cache_end))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
if ((oldData->streamSize!=diffInfo.oldDataSize)||(newDataSize!=diffInfo.newDataSize))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
temp_cache_end-=kBestACacheSize+sizeof(_TCompressedCovers);
|
||
// [ ... | compressedCovers cache ]
|
||
// [ (cacheSize-kBestACacheSize) | (kBestACacheSize) ]
|
||
*out_covers=&compressedCovers->base.ICovers;
|
||
isUsedCover32=(diffInfo.oldDataSize|diffInfo.newDataSize)<((hpatch_StreamPos_t)1<<32);
|
||
}else{
|
||
_TPackedCovers* packedCovers=0;
|
||
_THDiffHead diffHead;
|
||
hpatch_StreamPos_t oldDataSize=oldData->streamSize;
|
||
if (!_packedCovers_open(&packedCovers,&diffHead,diffData,
|
||
temp_cache_end-kBestACacheSize*3-sizeof(_TPackedCovers),temp_cache_end))
|
||
{ *out_isReadError=hpatch_TRUE; return _hpatch_FALSE; }
|
||
temp_cache_end-=kBestACacheSize*3+sizeof(_TPackedCovers);
|
||
// [ ... | packedCovers cache ]
|
||
// [ (cacheSize-kBestACacheSize*3) | (kBestACacheSize*3) ]
|
||
*out_covers=&packedCovers->base.ICovers;
|
||
isUsedCover32=(oldDataSize|newDataSize)<((hpatch_StreamPos_t)1<<32);
|
||
}
|
||
|
||
if (!_arrayCovers_load(&arrayCovers,*out_covers,isUsedCover32,
|
||
out_isReadError,&temp_cache,temp_cache_end-kBestACacheSize)){
|
||
if (*out_isReadError) return _hpatch_FALSE;
|
||
// [ patch cache | *edCovers cache ]
|
||
// [ (cacheSize-kBestACacheSize*?) | (kBestACacheSize*?) ]
|
||
*ptemp_cache=temp_cache;
|
||
*ptemp_cache_end=temp_cache_end;
|
||
return hpatch_FALSE;
|
||
}else{
|
||
// [ arrayCovers cache | ... ]
|
||
// [((new temp_cache)-(old temp_cache))| (cacheSize-(arrayCovers cache size)) ]
|
||
TByte* old_cache_end;
|
||
hpatch_TStreamInput* replace_oldData=0;
|
||
assert(!(*out_isReadError));
|
||
if (!((*out_covers)->close(*out_covers))) return _hpatch_FALSE;
|
||
*out_covers=&arrayCovers->ICovers;
|
||
temp_cache_end=temp_cache_end_back; //free compressedCovers or packedCovers memory
|
||
old_cache_end=temp_cache_end-kBestACacheSize*kCacheCount;
|
||
// [ arrayCovers cache | ... | patch reserve cache ]
|
||
// [ | ... | (kBestACacheSize*kCacheCount) ]
|
||
if (((hpatch_size_t)(temp_cache_end-temp_cache)<=kBestACacheSize*kCacheCount)
|
||
||(!_cache_old(&replace_oldData,oldData,arrayCovers,out_isReadError,
|
||
temp_cache,&old_cache_end,temp_cache_end))){
|
||
if (*out_isReadError) return _hpatch_FALSE;
|
||
// [ arrayCovers cache | patch cache ]
|
||
*ptemp_cache=temp_cache;
|
||
*ptemp_cache_end=temp_cache_end;
|
||
return hpatch_FALSE;
|
||
}else{
|
||
// [ arrayCovers cache | oldData cache | patch cache ]
|
||
// [ | |(temp_cache_end-(new old_cache_end))]
|
||
assert(!(*out_isReadError));
|
||
assert((hpatch_size_t)(temp_cache_end-old_cache_end)>=kBestACacheSize*kCacheCount);
|
||
temp_cache=old_cache_end;
|
||
|
||
*poldData=replace_oldData;
|
||
*ptemp_cache=temp_cache;
|
||
*ptemp_cache_end=temp_cache_end;
|
||
return hpatch_TRUE;
|
||
}
|
||
}
|
||
}
|
||
#endif//_IS_NEED_CACHE_OLD_BY_COVERS
|
||
return hpatch_FALSE;//not cache oldData
|
||
}
|
||
|
||
hpatch_BOOL patch_stream_with_cache(const struct hpatch_TStreamOutput* out_newData,
|
||
const struct hpatch_TStreamInput* oldData,
|
||
const struct hpatch_TStreamInput* serializedDiff,
|
||
TByte* temp_cache,TByte* temp_cache_end){
|
||
hpatch_BOOL result;
|
||
hpatch_TCovers* covers=0;//not need close before return
|
||
hpatch_BOOL isReadError=hpatch_FALSE;
|
||
_patch_cache(&covers,&oldData,out_newData->streamSize,serializedDiff,hpatch_FALSE,0,
|
||
_kCachePatCount,&temp_cache,&temp_cache_end,&isReadError);
|
||
if (isReadError) return _hpatch_FALSE;
|
||
result=_patch_stream_with_cache(out_newData,oldData,serializedDiff,covers,
|
||
temp_cache,temp_cache_end);
|
||
//if ((covers!=0)&&(!covers->close(covers))) result=_hpatch_FALSE;
|
||
return result;
|
||
}
|
||
|
||
hpatch_BOOL patch_stream(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* serializedDiff){
|
||
TByte temp_cache[hpatch_kStreamCacheSize*_kCachePatCount];
|
||
return _patch_stream_with_cache(out_newData,oldData,serializedDiff,0,
|
||
temp_cache,temp_cache+sizeof(temp_cache)/sizeof(TByte));
|
||
}
|
||
|
||
hpatch_BOOL patch_decompress_with_cache(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* compressedDiff,
|
||
hpatch_TDecompress* decompressPlugin,
|
||
TByte* temp_cache,TByte* temp_cache_end){
|
||
hpatch_BOOL result;
|
||
hpatch_TCovers* covers=0; //need close before return
|
||
hpatch_BOOL isReadError=hpatch_FALSE;
|
||
_patch_cache(&covers,&oldData,out_newData->streamSize,compressedDiff,hpatch_TRUE,
|
||
decompressPlugin,_kCacheDecCount,&temp_cache,&temp_cache_end,&isReadError);
|
||
if (isReadError) return _hpatch_FALSE;
|
||
result=_patch_decompress_cache(out_newData,0,oldData,compressedDiff,decompressPlugin,
|
||
covers,temp_cache,temp_cache_end);
|
||
if ((covers!=0)&&(!covers->close(covers))) result=_hpatch_FALSE;
|
||
return result;
|
||
}
|
||
|
||
hpatch_BOOL patch_decompress(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* compressedDiff,
|
||
hpatch_TDecompress* decompressPlugin){
|
||
TByte temp_cache[hpatch_kStreamCacheSize*_kCacheDecCount];
|
||
return _patch_decompress_cache(out_newData,0,oldData,compressedDiff,decompressPlugin,
|
||
0,temp_cache,temp_cache+sizeof(temp_cache)/sizeof(TByte));
|
||
}
|
||
|
||
hpatch_BOOL hpatch_coverList_open_serializedDiff(hpatch_TCoverList* out_coverList,
|
||
const hpatch_TStreamInput* serializedDiff){
|
||
TByte* temp_cache;
|
||
TByte* temp_cache_end;
|
||
_TPackedCovers* packedCovers=0;
|
||
_THDiffHead diffHead;
|
||
assert((out_coverList!=0)&&(out_coverList->ICovers==0));
|
||
temp_cache=out_coverList->_buf;
|
||
temp_cache_end=temp_cache+sizeof(out_coverList->_buf);
|
||
if (!_packedCovers_open(&packedCovers,&diffHead,serializedDiff,
|
||
temp_cache,temp_cache_end))
|
||
return _hpatch_FALSE;
|
||
out_coverList->ICovers=&packedCovers->base.ICovers;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL hpatch_coverList_open_compressedDiff(hpatch_TCoverList* out_coverList,
|
||
const hpatch_TStreamInput* compressedDiff,
|
||
hpatch_TDecompress* decompressPlugin){
|
||
TByte* temp_cache;
|
||
TByte* temp_cache_end;
|
||
_TCompressedCovers* compressedCovers=0;
|
||
hpatch_compressedDiffInfo diffInfo;
|
||
assert((out_coverList!=0)&&(out_coverList->ICovers==0));
|
||
temp_cache=out_coverList->_buf;
|
||
temp_cache_end=temp_cache+sizeof(out_coverList->_buf);
|
||
if (!_compressedCovers_open(&compressedCovers,&diffInfo,compressedDiff,decompressPlugin,
|
||
temp_cache,temp_cache_end))
|
||
return _hpatch_FALSE;
|
||
out_coverList->ICovers=&compressedCovers->base.ICovers;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
//
|
||
|
||
#define _kCacheSgCount 3
|
||
|
||
hpatch_BOOL patch_single_compressed_diff(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* singleCompressedDiff,
|
||
hpatch_StreamPos_t diffData_pos,
|
||
hpatch_StreamPos_t uncompressedSize,
|
||
hpatch_StreamPos_t compressedSize,
|
||
hpatch_TDecompress* decompressPlugin,
|
||
hpatch_StreamPos_t coverCount,hpatch_size_t stepMemSize,
|
||
unsigned char* temp_cache,unsigned char* temp_cache_end,
|
||
sspatch_coversListener_t* coversListener){
|
||
hpatch_BOOL result;
|
||
hpatch_TUncompresser_t uncompressedStream;
|
||
hpatch_StreamPos_t diffData_posEnd;
|
||
memset(&uncompressedStream,0,sizeof(uncompressedStream));
|
||
if (compressedSize==0){
|
||
decompressPlugin=0;
|
||
}else{
|
||
if (decompressPlugin==0) return _hpatch_FALSE;
|
||
}
|
||
diffData_posEnd=(decompressPlugin?compressedSize:uncompressedSize)+diffData_pos;
|
||
if (diffData_posEnd>singleCompressedDiff->streamSize) return _hpatch_FALSE;
|
||
if (decompressPlugin){
|
||
if (!compressed_stream_as_uncompressed(&uncompressedStream,uncompressedSize,decompressPlugin,singleCompressedDiff,
|
||
diffData_pos,diffData_posEnd)) return _hpatch_FALSE;
|
||
singleCompressedDiff=&uncompressedStream.base;
|
||
diffData_pos=0;
|
||
diffData_posEnd=singleCompressedDiff->streamSize;
|
||
}
|
||
result=patch_single_stream_diff(out_newData,oldData,singleCompressedDiff,diffData_pos,diffData_posEnd,
|
||
coverCount,stepMemSize,temp_cache,temp_cache_end,coversListener);
|
||
if (decompressPlugin)
|
||
close_compressed_stream_as_uncompressed(&uncompressedStream);
|
||
return result;
|
||
}
|
||
|
||
static const size_t _kStepMemSizeSafeLimit =(1<<20)*16;
|
||
hpatch_BOOL getSingleCompressedDiffInfo(hpatch_singleCompressedDiffInfo* out_diffInfo,
|
||
const hpatch_TStreamInput* singleCompressedDiff,
|
||
hpatch_StreamPos_t diffInfo_pos){
|
||
TStreamCacheClip _diffHeadClip;
|
||
TStreamCacheClip* diffHeadClip=&_diffHeadClip;
|
||
TByte temp_cache[hpatch_kStreamCacheSize];
|
||
_TStreamCacheClip_init(&_diffHeadClip,singleCompressedDiff,diffInfo_pos,singleCompressedDiff->streamSize,
|
||
temp_cache,hpatch_kStreamCacheSize);
|
||
{//type
|
||
const char* kVersionType="HDIFFSF20";
|
||
char* tempType=out_diffInfo->compressType;
|
||
if (!_TStreamCacheClip_readType_end(diffHeadClip,'&',tempType)) return _hpatch_FALSE;
|
||
if (0!=strcmp(tempType,kVersionType)) return _hpatch_FALSE;
|
||
}
|
||
{//read compressType
|
||
if (!_TStreamCacheClip_readType_end(diffHeadClip,'\0',
|
||
out_diffInfo->compressType)) return _hpatch_FALSE;
|
||
}
|
||
_clip_unpackUIntTo(&out_diffInfo->newDataSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->oldDataSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->coverCount,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->stepMemSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->uncompressedSize,diffHeadClip);
|
||
_clip_unpackUIntTo(&out_diffInfo->compressedSize,diffHeadClip);
|
||
out_diffInfo->diffDataPos=_TStreamCacheClip_readPosOfSrcStream(diffHeadClip)-diffInfo_pos;
|
||
if (out_diffInfo->compressedSize>out_diffInfo->uncompressedSize)
|
||
return _hpatch_FALSE;
|
||
if (out_diffInfo->stepMemSize>(out_diffInfo->newDataSize>=_kStepMemSizeSafeLimit?out_diffInfo->newDataSize:_kStepMemSizeSafeLimit))
|
||
return _hpatch_FALSE;
|
||
if (out_diffInfo->stepMemSize>out_diffInfo->uncompressedSize)
|
||
return _hpatch_FALSE;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _TUncompresser_read(const struct hpatch_TStreamInput* stream,hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
hpatch_TUncompresser_t* self=(hpatch_TUncompresser_t*)stream->streamImport;
|
||
return self->_decompressPlugin->decompress_part(self->_decompressHandle,out_data,out_data_end);
|
||
}
|
||
|
||
hpatch_BOOL compressed_stream_as_uncompressed(hpatch_TUncompresser_t* uncompressedStream,hpatch_StreamPos_t uncompressedSize,
|
||
hpatch_TDecompress* decompressPlugin,const hpatch_TStreamInput* compressedStream,
|
||
hpatch_StreamPos_t compressed_pos,hpatch_StreamPos_t compressed_end){
|
||
hpatch_TUncompresser_t* self=uncompressedStream;
|
||
assert(decompressPlugin!=0);
|
||
assert(self->_decompressHandle==0);
|
||
self->_decompressHandle=decompressPlugin->open(decompressPlugin,uncompressedSize,compressedStream,
|
||
compressed_pos,compressed_end);
|
||
if (self->_decompressHandle==0) return _hpatch_FALSE;
|
||
self->_decompressPlugin=decompressPlugin;
|
||
|
||
self->base.streamImport=self;
|
||
self->base.streamSize=uncompressedSize;
|
||
self->base.read=_TUncompresser_read;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
void close_compressed_stream_as_uncompressed(hpatch_TUncompresser_t* uncompressedStream){
|
||
hpatch_TUncompresser_t* self=uncompressedStream;
|
||
if (self==0) return;
|
||
if (self->_decompressHandle==0) return;
|
||
self->_decompressPlugin->close(self->_decompressPlugin,self->_decompressHandle);
|
||
self->_decompressHandle=0;
|
||
}
|
||
|
||
typedef struct{
|
||
const unsigned char* code;
|
||
const unsigned char* code_end;
|
||
hpatch_size_t len0;
|
||
hpatch_size_t lenv;
|
||
hpatch_BOOL isNeedDecode0;
|
||
} rle0_decoder_t;
|
||
|
||
static void _rle0_decoder_init(rle0_decoder_t* self,const unsigned char* code,const unsigned char* code_end){
|
||
self->code=code;
|
||
self->code_end=code_end;
|
||
self->len0=0;
|
||
self->lenv=0;
|
||
self->isNeedDecode0=hpatch_TRUE;
|
||
}
|
||
|
||
static hpatch_BOOL _rle0_decoder_add(rle0_decoder_t* self,TByte* out_data,hpatch_size_t decodeSize){
|
||
if (self->len0){
|
||
_0_process:
|
||
if (self->len0>=decodeSize){
|
||
self->len0-=decodeSize;
|
||
return hpatch_TRUE;
|
||
}else{
|
||
decodeSize-=self->len0;
|
||
out_data+=self->len0;
|
||
self->len0=0;
|
||
goto _decode_v_process;
|
||
}
|
||
}
|
||
|
||
if (self->lenv){
|
||
_v_process:
|
||
if (self->lenv>=decodeSize){
|
||
addData(out_data,self->code,decodeSize);
|
||
self->code+=decodeSize;
|
||
self->lenv-=decodeSize;
|
||
return hpatch_TRUE;
|
||
}else{
|
||
addData(out_data,self->code,self->lenv);
|
||
out_data+=self->lenv;
|
||
decodeSize-=self->lenv;
|
||
self->code+=self->lenv;
|
||
self->lenv=0;
|
||
goto _decode_0_process;
|
||
}
|
||
}
|
||
|
||
assert(decodeSize>0);
|
||
if (self->isNeedDecode0){
|
||
hpatch_StreamPos_t len0;
|
||
_decode_0_process:
|
||
self->isNeedDecode0=hpatch_FALSE;
|
||
if (!hpatch_unpackUInt(&self->code,self->code_end,&len0)) return _hpatch_FALSE;
|
||
if (len0!=(hpatch_size_t)len0) return _hpatch_FALSE;
|
||
self->len0=(hpatch_size_t)len0;
|
||
goto _0_process;
|
||
}else{
|
||
hpatch_StreamPos_t lenv;
|
||
_decode_v_process:
|
||
self->isNeedDecode0=hpatch_TRUE;
|
||
if (!hpatch_unpackUInt(&self->code,self->code_end,&lenv)) return _hpatch_FALSE;
|
||
if (lenv>(size_t)(self->code_end-self->code)) return _hpatch_FALSE;
|
||
self->lenv=(hpatch_size_t)lenv;
|
||
goto _v_process;
|
||
}
|
||
}
|
||
|
||
|
||
static hpatch_BOOL _patch_add_old_with_rle0(_TOutStreamCache* outCache,rle0_decoder_t* rle0_decoder,
|
||
const hpatch_TStreamInput* old,hpatch_StreamPos_t oldPos,
|
||
hpatch_StreamPos_t addLength,TByte* aCache,hpatch_size_t aCacheSize){
|
||
while (addLength>0){
|
||
hpatch_size_t decodeStep=aCacheSize;
|
||
if (decodeStep>addLength)
|
||
decodeStep=(hpatch_size_t)addLength;
|
||
if (!old->read(old,oldPos,aCache,aCache+decodeStep)) return _hpatch_FALSE;
|
||
if (!_rle0_decoder_add(rle0_decoder,aCache,decodeStep)) return _hpatch_FALSE;
|
||
if (!_TOutStreamCache_write(outCache,aCache,decodeStep)) return _hpatch_FALSE;
|
||
oldPos+=decodeStep;
|
||
addLength-=decodeStep;
|
||
}
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
hpatch_BOOL sspatch_covers_nextCover(sspatch_covers_t* self){
|
||
hpatch_BOOL inc_oldPos_sign=(*(self->covers_cache))>>(8-1);
|
||
self->lastOldEnd=self->cover.oldPos+self->cover.length;
|
||
self->lastNewEnd=self->cover.newPos+self->cover.length;
|
||
if (!hpatch_unpackUIntWithTag(&self->covers_cache,self->covers_cacheEnd,&self->cover.oldPos,1)) return _hpatch_FALSE;
|
||
if (inc_oldPos_sign==0)
|
||
self->cover.oldPos+=self->lastOldEnd;
|
||
else
|
||
self->cover.oldPos=self->lastOldEnd-self->cover.oldPos;
|
||
if (!hpatch_unpackUInt(&self->covers_cache,self->covers_cacheEnd,&self->cover.newPos)) return _hpatch_FALSE;
|
||
self->cover.newPos+=self->lastNewEnd;
|
||
if (!hpatch_unpackUInt(&self->covers_cache,self->covers_cacheEnd,&self->cover.length)) return _hpatch_FALSE;
|
||
return hpatch_TRUE;
|
||
}
|
||
|
||
|
||
hpatch_BOOL patch_single_stream_diff(const hpatch_TStreamOutput* out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* uncompressedDiffData,
|
||
hpatch_StreamPos_t diffData_pos,
|
||
hpatch_StreamPos_t diffData_posEnd,
|
||
hpatch_StreamPos_t coverCount,hpatch_size_t stepMemSize,
|
||
unsigned char* temp_cache,unsigned char* temp_cache_end,
|
||
sspatch_coversListener_t* coversListener){
|
||
unsigned char* step_cache=temp_cache;
|
||
hpatch_size_t cache_size;
|
||
TStreamCacheClip inClip;
|
||
_TOutStreamCache outCache;
|
||
sspatch_covers_t covers;
|
||
assert(diffData_posEnd<=uncompressedDiffData->streamSize);
|
||
sspatch_covers_init(&covers);
|
||
if (coversListener) assert(coversListener->onStepCovers);
|
||
{//cache
|
||
if ((size_t)(temp_cache_end-temp_cache)<stepMemSize+hpatch_kStreamCacheSize*_kCacheSgCount) return _hpatch_FALSE;
|
||
temp_cache+=stepMemSize;
|
||
cache_size=(temp_cache_end-temp_cache)/_kCacheSgCount;
|
||
_TStreamCacheClip_init(&inClip,uncompressedDiffData,diffData_pos,diffData_posEnd,
|
||
temp_cache,cache_size);
|
||
temp_cache+=cache_size;
|
||
_TOutStreamCache_init(&outCache,out_newData,temp_cache+cache_size,cache_size);
|
||
}
|
||
while (coverCount) {//step loop
|
||
rle0_decoder_t rle0_decoder;
|
||
{//read step info
|
||
unsigned char* covers_cacheEnd;
|
||
unsigned char* bufRle_cache_end;
|
||
{
|
||
hpatch_StreamPos_t bufCover_size;
|
||
hpatch_StreamPos_t bufRle_size;
|
||
_clip_unpackUIntTo(&bufCover_size,&inClip);
|
||
_clip_unpackUIntTo(&bufRle_size,&inClip);
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((bufCover_size>stepMemSize)|(bufRle_size>stepMemSize)|
|
||
(bufCover_size+bufRle_size>stepMemSize)) return _hpatch_FALSE;
|
||
#endif
|
||
covers_cacheEnd=step_cache+(size_t)bufCover_size;
|
||
bufRle_cache_end=covers_cacheEnd+(size_t)bufRle_size;
|
||
}
|
||
if (coversListener&&coversListener->onStepCoversReset)
|
||
coversListener->onStepCoversReset(coversListener,coverCount);
|
||
if (!_TStreamCacheClip_readDataTo(&inClip,step_cache,bufRle_cache_end))
|
||
return _hpatch_FALSE;
|
||
if (coversListener)
|
||
coversListener->onStepCovers(coversListener,step_cache,covers_cacheEnd);
|
||
sspatch_covers_setCoversCache(&covers,step_cache,covers_cacheEnd);
|
||
_rle0_decoder_init(&rle0_decoder,covers_cacheEnd,bufRle_cache_end);
|
||
}
|
||
while (sspatch_covers_isHaveNextCover(&covers)) {//cover loop
|
||
if (!sspatch_covers_nextCover(&covers))
|
||
return _hpatch_FALSE;
|
||
if (covers.cover.newPos>covers.lastNewEnd){
|
||
if (!_TOutStreamCache_copyFromClip(&outCache,&inClip,covers.cover.newPos-covers.lastNewEnd))
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
--coverCount;
|
||
if (covers.cover.length){
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if ((covers.cover.oldPos>oldData->streamSize)|
|
||
(covers.cover.length>(hpatch_StreamPos_t)(oldData->streamSize-covers.cover.oldPos))) return _hpatch_FALSE;
|
||
#endif
|
||
if (!_patch_add_old_with_rle0(&outCache,&rle0_decoder,oldData,covers.cover.oldPos,covers.cover.length,
|
||
temp_cache,cache_size)) return _hpatch_FALSE;
|
||
}else{
|
||
#ifdef __RUN_MEM_SAFE_CHECK
|
||
if (coverCount!=0) return _hpatch_FALSE;
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!_TOutStreamCache_flush(&outCache))
|
||
return _hpatch_FALSE;
|
||
if (_TStreamCacheClip_isFinish(&inClip)&_TOutStreamCache_isFinish(&outCache)&(coverCount==0))
|
||
return hpatch_TRUE;
|
||
else
|
||
return _hpatch_FALSE;
|
||
}
|
||
|
||
|
||
static hpatch_BOOL _TDiffToSingleStream_read(const struct hpatch_TStreamInput* stream,hpatch_StreamPos_t readFromPos,
|
||
unsigned char* out_data,unsigned char* out_data_end){
|
||
//[ |readedSize ]
|
||
// [ |cachedBufBegin _TDiffToSingleStream_kBufSize]
|
||
// readFromPos[out_data out_data_end]
|
||
TDiffToSingleStream* self=(TDiffToSingleStream*)stream->streamImport;
|
||
hpatch_StreamPos_t readedSize=self->readedSize;
|
||
while (1){
|
||
size_t rLen=out_data_end-out_data;
|
||
if (readFromPos==readedSize){
|
||
hpatch_BOOL result=self->diffStream->read(self->diffStream,readedSize,out_data,out_data_end);
|
||
self->readedSize=readedSize+rLen;
|
||
if ((self->isInSingleStream)||(rLen>_TDiffToSingleStream_kBufSize)){
|
||
self->cachedBufBegin=_TDiffToSingleStream_kBufSize;
|
||
}else{
|
||
//cache
|
||
if (rLen>=_TDiffToSingleStream_kBufSize){
|
||
memcpy(self->buf,out_data_end-_TDiffToSingleStream_kBufSize,_TDiffToSingleStream_kBufSize);
|
||
self->cachedBufBegin = 0;
|
||
}else{
|
||
size_t new_cachedBufBegin;
|
||
if (self->cachedBufBegin>=rLen){
|
||
new_cachedBufBegin=self->cachedBufBegin-rLen;
|
||
memmove(self->buf+new_cachedBufBegin,self->buf+self->cachedBufBegin,_TDiffToSingleStream_kBufSize-self->cachedBufBegin);
|
||
}else{
|
||
new_cachedBufBegin=0;
|
||
memmove(self->buf,self->buf+rLen,_TDiffToSingleStream_kBufSize-rLen);
|
||
}
|
||
memcpy(self->buf+(_TDiffToSingleStream_kBufSize-rLen),out_data,rLen);
|
||
self->cachedBufBegin=new_cachedBufBegin;
|
||
}
|
||
}
|
||
return result;
|
||
}else{
|
||
size_t cachedSize=_TDiffToSingleStream_kBufSize-self->cachedBufBegin;
|
||
size_t bufSize=(size_t)(readedSize-readFromPos);
|
||
if ((readFromPos<readedSize)&(bufSize<=cachedSize)){
|
||
if (rLen>bufSize)
|
||
rLen=bufSize;
|
||
memcpy(out_data,self->buf+(_TDiffToSingleStream_kBufSize-bufSize),rLen);
|
||
out_data+=rLen;
|
||
readFromPos+=rLen;
|
||
if (out_data==out_data_end)
|
||
return hpatch_TRUE;
|
||
else
|
||
continue;
|
||
}else{
|
||
return _hpatch_FALSE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void TDiffToSingleStream_init(TDiffToSingleStream* self,const hpatch_TStreamInput* diffStream){
|
||
self->base.streamImport=self;
|
||
self->base.streamSize=diffStream->streamSize;
|
||
self->base.read=_TDiffToSingleStream_read;
|
||
self->base._private_reserved=0;
|
||
self->diffStream=diffStream;
|
||
self->readedSize=0;
|
||
self->cachedBufBegin=_TDiffToSingleStream_kBufSize;
|
||
self->isInSingleStream=hpatch_FALSE;
|
||
}
|
||
|
||
hpatch_BOOL patch_single_stream(sspatch_listener_t* listener,
|
||
const hpatch_TStreamOutput* __out_newData,
|
||
const hpatch_TStreamInput* oldData,
|
||
const hpatch_TStreamInput* singleCompressedDiff,
|
||
hpatch_StreamPos_t diffInfo_pos,
|
||
sspatch_coversListener_t* coversListener){
|
||
hpatch_BOOL result=hpatch_TRUE;
|
||
hpatch_TDecompress* decompressPlugin=0;
|
||
unsigned char* temp_cache=0;
|
||
unsigned char* temp_cacheEnd=0;
|
||
hpatch_singleCompressedDiffInfo diffInfo;
|
||
hpatch_TStreamOutput _out_newData=*__out_newData;
|
||
hpatch_TStreamOutput* out_newData=&_out_newData;
|
||
TDiffToSingleStream _toSStream;
|
||
assert((listener)&&(listener->onDiffInfo));
|
||
TDiffToSingleStream_init(&_toSStream,singleCompressedDiff);
|
||
singleCompressedDiff=&_toSStream.base;
|
||
|
||
if (!getSingleCompressedDiffInfo(&diffInfo,singleCompressedDiff,diffInfo_pos))
|
||
return _hpatch_FALSE;
|
||
if (diffInfo.newDataSize>out_newData->streamSize)
|
||
return _hpatch_FALSE;
|
||
out_newData->streamSize=diffInfo.newDataSize;
|
||
if (diffInfo.oldDataSize!=oldData->streamSize)
|
||
return _hpatch_FALSE;
|
||
if (!listener->onDiffInfo(listener,&diffInfo,&decompressPlugin,&temp_cache,&temp_cacheEnd))
|
||
return _hpatch_FALSE;
|
||
|
||
if ((temp_cache==0)||(temp_cache>=temp_cacheEnd))
|
||
result=_hpatch_FALSE;
|
||
if (result){
|
||
result=patch_single_compressed_diff(out_newData,oldData,singleCompressedDiff,diffInfo.diffDataPos,
|
||
diffInfo.uncompressedSize,diffInfo.compressedSize,decompressPlugin,
|
||
diffInfo.coverCount,(size_t)diffInfo.stepMemSize,
|
||
temp_cache,temp_cacheEnd,coversListener);
|
||
}
|
||
if (listener->onPatchFinish)
|
||
listener->onPatchFinish(listener,temp_cache,temp_cacheEnd);
|
||
return result;
|
||
}
|