iw5-mod/deps/HDiffPatch/libHDiffPatch/HPatchLite/hpatch_lite.c

187 lines
6.5 KiB
C

//hpatch_lite.c
//
/*
The MIT License (MIT)
Copyright (c) 2020-2022 HouSisong All Rights Reserved.
*/
#include "hpatch_lite.h"
#include "hpatch_lite_input_cache.h"
#define _hpi_FALSE hpi_FALSE
//hpi_size_t __debug_check_false_x=0; //for debug
//#define _hpi_FALSE (1/__debug_check_false_x)
#if (_IS_RUN_MEM_SAFE_CHECK)
# define __RUN_MEM_SAFE_CHECK
#endif
#define _CHECK(code) { if (!(code)) return _hpi_FALSE; }
#ifdef __RUN_MEM_SAFE_CHECK
# define _SAFE_CHECK(checkv) _CHECK(checkv)
#else
# define _SAFE_CHECK(checkv)
#endif
#define _TInputCache _hpi_TInputCache
#define _cache_read_1byte _hpi_cache_read_1byte
#define _cache_update _hpi_cache_update
#define _cache_success_finish _hpi_cache_success_finish
hpi_BOOL _cache_update(struct _TInputCache* self){
// [ cache buf ]
hpi_size_t len=self->cache_end;
assert(len==self->cache_begin); //empty
if (!self->read_code(self->inputStream,self->cache_buf,&len))
len=0;
// | len| |
self->cache_begin=0;
self->cache_end=len;
return len!=0;
}
hpi_fast_uint8 _cache_read_1byte(struct _TInputCache* self){
if (self->cache_begin!=self->cache_end){
__cache_read_1byte:
return self->cache_buf[self->cache_begin++];
}
if(_cache_update(self))
goto __cache_read_1byte;
else
return 0;
}
static hpi_pos_t _cache_unpackUInt(_TInputCache* self,hpi_pos_t v,hpi_fast_uint8 isNext){
while (isNext){
hpi_fast_uint8 b=_cache_read_1byte(self);
v=(v<<7)|(b&127);
isNext=b>>7;
}
return v;
}
static hpi_BOOL _patch_copy_diff(hpatchi_listener_t* out_newData,
_TInputCache* diff,hpi_pos_t copyLength){
while (copyLength>0){
hpi_size_t decodeStep=diff->cache_end-diff->cache_begin;
if (decodeStep==0){
_CHECK(_cache_update(diff));
decodeStep=diff->cache_end-diff->cache_begin;
}
if (decodeStep>copyLength)
decodeStep=(hpi_size_t)copyLength;
_CHECK(out_newData->write_new(out_newData,diff->cache_buf+diff->cache_begin,decodeStep));
diff->cache_begin+=decodeStep;
copyLength-=(hpi_pos_t)decodeStep;
}
return hpi_TRUE;
}
static hpi_force_inline void addData(hpi_byte* dst,const hpi_byte* src,hpi_size_t length){
while (length--) { *dst++ += *src++; } }
static hpi_BOOL _patch_add_old_withClip(hpatchi_listener_t* old_and_new,_TInputCache* diff,hpi_BOOL isNotNeedSubDiff,
hpi_size_t oldPos,hpi_size_t addLength,hpi_byte* temp_cache){
while (addLength>0){
hpi_size_t decodeStep=diff->cache_end;
if (!isNotNeedSubDiff){
decodeStep-=diff->cache_begin;
if (decodeStep==0){
_cache_update(diff);
decodeStep=diff->cache_end-diff->cache_begin;
}
}
_CHECK(decodeStep>0);
if (decodeStep>addLength)
decodeStep=(hpi_size_t)addLength;
_CHECK(old_and_new->read_old(old_and_new,oldPos,temp_cache,(hpi_pos_t)decodeStep));
if (!isNotNeedSubDiff){
addData(temp_cache,diff->cache_buf+diff->cache_begin,decodeStep);
diff->cache_begin+=decodeStep;
}
_CHECK(old_and_new->write_new(old_and_new,temp_cache,decodeStep));
oldPos+=decodeStep;
addLength-=decodeStep;
}
return hpi_TRUE;
}
static hpi_pos_t _hpi_readSize(const hpi_byte* buf,hpi_size_t len){
hpi_pos_t v=0;
while(len--){
v=(v<<8)|(hpi_pos_t)buf[len];
}
return v;
}
hpi_BOOL hpatch_lite_open(hpi_TInputStreamHandle diff_data,hpi_TInputStream_read read_diff,
hpi_compressType* out_compress_type,hpi_pos_t* out_newSize,hpi_pos_t* out_uncompressSize){
#define kHPatchLite_versionCode 1
hpi_size_t lenn=hpi_kHeadSize;
hpi_size_t lenu;
hpi_byte buf[hpi_kHeadSize>sizeof(hpi_pos_t)?hpi_kHeadSize:sizeof(hpi_pos_t)];
_CHECK(read_diff(diff_data,buf,&lenn));
//HPatchLite type tag 2byte, version code(high 2bit)
lenu=buf[3];
_SAFE_CHECK((lenn==hpi_kHeadSize)&(buf[0]=='h')&(buf[1]=='I')&((lenu>>6)==kHPatchLite_versionCode));
*out_compress_type=buf[2]; //compress type
lenn=lenu&7; //newSize bytes(low 3bit)
lenu=(lenu>>3)&7; //uncompressSize bytes(mid 3bit)
_SAFE_CHECK((lenn<=sizeof(hpi_pos_t))&(lenu<=sizeof(hpi_pos_t)));
_CHECK(read_diff(diff_data,buf,&lenn));
*out_newSize=_hpi_readSize(buf,lenn);
_CHECK(read_diff(diff_data,buf,&lenu));
*out_uncompressSize=_hpi_readSize(buf,lenu);
return hpi_TRUE;
}
hpi_BOOL hpatch_lite_patch(hpatchi_listener_t* listener,hpi_pos_t newSize,
hpi_byte* temp_cache,hpi_size_t temp_cache_size){
_TInputCache diff;
hpi_pos_t coverCount;
hpi_pos_t newPosBack=0;
hpi_pos_t oldPosBack=0;
{
assert(temp_cache);
_SAFE_CHECK(temp_cache_size>=hpi_kMinCacheSize);
temp_cache_size>>=1;
diff.cache_begin=temp_cache_size;
diff.cache_end=temp_cache_size;
diff.cache_buf=temp_cache+temp_cache_size;
diff.inputStream=listener->diff_data;
diff.read_code=listener->read_diff;
}
coverCount=_cache_unpackUInt(&diff,0,hpi_TRUE);
while (coverCount--){
hpi_pos_t cover_oldPos;
hpi_pos_t cover_newPos;
hpi_pos_t cover_length;
hpi_BOOL isNotNeedSubDiff;
{//read cover
cover_length=_cache_unpackUInt(&diff,0,hpi_TRUE);
{
hpi_fast_uint8 tag=_cache_read_1byte(&diff);
cover_oldPos=_cache_unpackUInt(&diff,tag&31,tag&(1<<5));
isNotNeedSubDiff=(tag>>7);
if (tag&(1<<6))
cover_oldPos=oldPosBack-cover_oldPos;
else
cover_oldPos+=oldPosBack;
}
cover_newPos=_cache_unpackUInt(&diff,0,hpi_TRUE);
cover_newPos+=newPosBack;
}
_SAFE_CHECK(cover_newPos>=newPosBack);
if (newPosBack<cover_newPos)
_CHECK(_patch_copy_diff(listener,&diff,cover_newPos-newPosBack));
_CHECK(_patch_add_old_withClip(listener,&diff,isNotNeedSubDiff,cover_oldPos,cover_length,temp_cache));
newPosBack=cover_newPos+cover_length;
oldPosBack=cover_oldPos+cover_length;
_SAFE_CHECK((cover_length>0)|(coverCount==0));
}
return (newSize==newPosBack)&_cache_success_finish(&diff);
}