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;
|
|||
|
}
|