609 lines
26 KiB
C++
609 lines
26 KiB
C++
// vcdiff_wrapper.cpp
|
|
// HDiffPatch
|
|
/*
|
|
The MIT License (MIT)
|
|
Copyright (c) 2022 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 "vcdiff_wrapper.h"
|
|
#include "vcpatch_code_table.h"
|
|
#include "../libHDiffPatch/HDiff/match_block.h"
|
|
#include "../libHDiffPatch/HDiff/private_diff/mem_buf.h"
|
|
#include "../libHDiffPatch/HDiff/private_diff/limit_mem_diff/stream_serialize.h"
|
|
#include "../libHDiffPatch/HPatch/patch.h"
|
|
#include <stdexcept> //std::runtime_error
|
|
#include <algorithm> //std::inplace_merge
|
|
#define _check(value,info) { if (!(value)) { throw std::runtime_error(info); } }
|
|
static const hpatch_byte kVcDiffType[3]={('V'|(1<<7)),('C'|(1<<7)),('D'|(1<<7))};
|
|
#define kVcDiffVersion 0
|
|
static const char* kHDiffzAppHead_a="$hdiffz-VCDIFF&7zXZ#a";
|
|
|
|
namespace hdiff_private{
|
|
|
|
static size_t fixRedundentEncoding(std::vector<hpatch_byte>& buf,hpatch_StreamPos_t buf_pos,
|
|
const TPlaceholder& update_pos,hpatch_StreamPos_t updateLen){
|
|
const size_t pkSize=hpatch_packUInt_size(updateLen);
|
|
const size_t upkSize=(size_t)update_pos.size();
|
|
assert(pkSize<=upkSize);
|
|
const size_t retSize=upkSize-pkSize;
|
|
if (retSize==0) return 0;
|
|
// [ buf ]
|
|
// [update_pos-buf_pos]
|
|
// [ pkSize ]
|
|
size_t upki=(size_t)(update_pos.pos-buf_pos);
|
|
size_t pki=upki+retSize;
|
|
hpatch_byte* bufpki=buf.data()+pki;
|
|
hpatch_byte* bufpki_end=bufpki+pkSize;
|
|
_check(hpatch_packUInt(&bufpki,bufpki_end,updateLen),"update packed len error!");
|
|
_check(bufpki==bufpki_end,"update packed len error!");
|
|
memmove(buf.data()+retSize,buf.data(),upki);
|
|
return retSize;
|
|
}
|
|
|
|
static void _getSrcWindow(const TCovers& covers,size_t coveri,size_t coveriEnd,
|
|
hpatch_StreamPos_t* out_srcPos,hpatch_StreamPos_t* out_srcEnd){
|
|
if (coveri==coveriEnd){
|
|
*out_srcPos=0;
|
|
*out_srcEnd=0;
|
|
return;
|
|
}
|
|
hpatch_StreamPos_t srcPos=~(hpatch_StreamPos_t)0;
|
|
hpatch_StreamPos_t srcEnd=0;
|
|
for (size_t i=coveri;i<coveriEnd;++i){
|
|
TCover c; covers.covers(i,&c);
|
|
hpatch_StreamPos_t pos=c.oldPos;
|
|
srcPos=(pos<srcPos)?pos:srcPos;
|
|
pos+=c.length;
|
|
srcEnd=(pos<srcEnd)?srcEnd:pos;
|
|
}
|
|
*out_srcPos=srcPos;
|
|
*out_srcEnd=srcEnd;
|
|
}
|
|
|
|
static hpatch_StreamPos_t _getTargetWindow(hpatch_StreamPos_t targetPos,hpatch_StreamPos_t targetPosEnd,
|
|
const TCovers& covers,size_t coveri,size_t* coveriEnd,size_t kMaxTargetWindowsSize){
|
|
hpatch_StreamPos_t targetLen=0;
|
|
const size_t count=covers.coverCount();
|
|
*coveriEnd=coveri;
|
|
for (size_t i=coveri;i<=count;++i){
|
|
TCover c;
|
|
if (i<count){
|
|
covers.covers(i,&c);
|
|
}else{
|
|
c.oldPos=hpatch_kNullStreamPos;
|
|
c.newPos=targetPosEnd;
|
|
c.length=0;
|
|
}
|
|
hpatch_StreamPos_t pos=c.newPos;
|
|
assert(pos>=targetPos);
|
|
if (pos>targetPos){
|
|
hpatch_StreamPos_t targetInc=(pos-targetPos);
|
|
if (targetLen+targetInc<kMaxTargetWindowsSize){
|
|
targetLen+=targetInc;
|
|
targetPos+=targetInc;
|
|
}else{
|
|
targetLen=kMaxTargetWindowsSize;
|
|
break;//ok
|
|
}
|
|
}
|
|
|
|
if (i<count){
|
|
hpatch_StreamPos_t targetInc=c.length;
|
|
if (targetLen+targetInc<=kMaxTargetWindowsSize){
|
|
*coveriEnd=i+1;
|
|
targetLen+=targetInc;
|
|
targetPos+=targetInc;
|
|
}else{
|
|
assert(targetLen>0);
|
|
break;//ok
|
|
}
|
|
}
|
|
}
|
|
return targetLen;
|
|
}
|
|
|
|
|
|
static const hpatch_byte _code_NULL_MODE = 255;
|
|
static inline bool _code_is_empty(hpatch_byte type) { return type==vcdiff_code_NOOP; }
|
|
struct vccode_t{
|
|
hpatch_byte type;
|
|
hpatch_byte mode;
|
|
hpatch_StreamPos_t size;
|
|
hpatch_StreamPos_t addr;
|
|
inline vccode_t(){ set_empty(); }
|
|
inline bool is_empty()const { return _code_is_empty(type); }
|
|
inline void set_empty(){
|
|
type=vcdiff_code_NOOP;
|
|
mode=_code_NULL_MODE;
|
|
size=hpatch_kNullStreamPos;
|
|
addr=hpatch_kNullStreamPos;
|
|
}
|
|
inline void set_add_code(hpatch_StreamPos_t _size){
|
|
type=vcdiff_code_ADD;
|
|
mode=_code_NULL_MODE;
|
|
size=_size;
|
|
addr=hpatch_kNullStreamPos;
|
|
}
|
|
inline void set_copy_code(hpatch_StreamPos_t _size,hpatch_byte _mode,hpatch_StreamPos_t _addr){
|
|
type=vcdiff_code_COPY;
|
|
mode=_mode;
|
|
size=_size;
|
|
addr=_addr;
|
|
}
|
|
};
|
|
|
|
struct vc_encoder{
|
|
vc_encoder(std::vector<hpatch_byte>& inst,std::vector<hpatch_byte>& addr)
|
|
:near_array(&_self_hear_near_array[2]),near_index(0),here(0),out_inst(inst),out_addr(addr){
|
|
inst.clear();
|
|
addr.clear();
|
|
memset(same_array,0,sizeof(same_array));
|
|
memset(_self_hear_near_array,0,sizeof(_self_hear_near_array));
|
|
}
|
|
|
|
void encode(const TCovers& covers,size_t coveri,
|
|
hpatch_StreamPos_t targetPos,hpatch_StreamPos_t targetLen,
|
|
hpatch_StreamPos_t srcWindowPos,hpatch_StreamPos_t srcWindowLen){
|
|
size_t count=covers.coverCount();
|
|
const hpatch_StreamPos_t targetEnd=targetPos+targetLen;
|
|
here=targetPos;
|
|
for (size_t i=coveri;i<=count;++i){
|
|
TCover c;
|
|
if (i<count){
|
|
covers.covers(i,&c);
|
|
}else{
|
|
c.oldPos=hpatch_kNullStreamPos;
|
|
c.newPos=targetPos+targetLen;
|
|
c.length=0;
|
|
}
|
|
|
|
if (here<c.newPos){
|
|
hpatch_StreamPos_t targetInc=c.newPos-here;
|
|
if (here+targetInc>targetEnd)
|
|
targetInc=targetEnd-here;
|
|
if (targetInc>0){
|
|
curCode.set_add_code(targetInc);
|
|
emit_code();
|
|
here+=targetInc;
|
|
}
|
|
if (here==targetEnd)
|
|
break; //ok
|
|
}
|
|
if (c.length>0){
|
|
hpatch_StreamPos_t targetInc=c.length;
|
|
if (here+targetInc>targetEnd)
|
|
break; //ok
|
|
hpatch_StreamPos_t addr=c.oldPos-srcWindowPos;
|
|
hpatch_StreamPos_t subAddr=addr;
|
|
hpatch_byte mode=_get_mode(targetPos,srcWindowLen,&subAddr);
|
|
curCode.set_copy_code(targetInc,mode,subAddr);
|
|
emit_code();
|
|
here+=targetInc;
|
|
vcdiff_update_addr(same_array,near_array,&near_index,addr);
|
|
}
|
|
}
|
|
|
|
assert(curCode.is_empty());
|
|
emit_code();
|
|
assert(prevCode.is_empty());
|
|
}
|
|
private:
|
|
hpatch_StreamPos_t same_array[vcdiff_s_same*256];
|
|
hpatch_StreamPos_t _self_hear_near_array[2+vcdiff_s_near];
|
|
hpatch_StreamPos_t* near_array;
|
|
hpatch_StreamPos_t near_index;
|
|
hpatch_StreamPos_t here;
|
|
std::vector<hpatch_byte>& out_inst;
|
|
std::vector<hpatch_byte>& out_addr;
|
|
vccode_t prevCode;
|
|
vccode_t curCode;
|
|
|
|
inline void _emit_inst(hpatch_byte inst){
|
|
out_inst.push_back(inst);
|
|
}
|
|
inline void _emit_addr(hpatch_byte mode,hpatch_StreamPos_t addr){
|
|
if (mode<(2+vcdiff_s_near))
|
|
packUInt(out_addr,addr);
|
|
else
|
|
out_addr.push_back((hpatch_byte)addr);
|
|
}
|
|
inline void _emit_size(hpatch_StreamPos_t size){
|
|
packUInt(out_inst,size);
|
|
}
|
|
hpatch_byte _get_mode(hpatch_StreamPos_t targetPos,hpatch_StreamPos_t srcWindowLen,hpatch_StreamPos_t* paddr){
|
|
hpatch_StreamPos_t addr=*paddr;
|
|
_self_hear_near_array[1]=addr*2-(srcWindowLen+here-targetPos);
|
|
hpatch_StreamPos_t minSubAddr=addr;
|
|
hpatch_byte minSubi=0;
|
|
for (hpatch_byte i=0;i<(2+vcdiff_s_near);i++){
|
|
hpatch_StreamPos_t subAddr=addr-_self_hear_near_array[i];
|
|
if (subAddr<=127){
|
|
*paddr=subAddr;
|
|
return i;
|
|
}
|
|
if (subAddr<minSubAddr){
|
|
minSubAddr=subAddr;
|
|
minSubi=i;
|
|
}
|
|
}
|
|
size_t samei=(size_t)(addr%(vcdiff_s_same*256));
|
|
if (same_array[samei]==addr){
|
|
*paddr=samei%256;
|
|
return (hpatch_byte)(samei/256)+(2+vcdiff_s_near);
|
|
}
|
|
*paddr=minSubAddr;
|
|
return minSubi;
|
|
}
|
|
|
|
void emit_code(){
|
|
const hpatch_byte _type_pos=curCode.type;
|
|
if (prevCode.is_empty())
|
|
std::swap(prevCode,curCode);
|
|
if (prevCode.is_empty()) return;
|
|
if (curCode.is_empty()&&(!_code_is_empty(_type_pos))) return;
|
|
switch (prevCode.type){
|
|
case vcdiff_code_ADD: {
|
|
if ((prevCode.size<=4)&&(curCode.type==vcdiff_code_COPY)){ // encode 2 type?
|
|
if ((curCode.size==4)&&(curCode.mode>=6)){
|
|
_emit_inst((hpatch_byte)(235+(curCode.mode-6)*4+(prevCode.size-1)));
|
|
_emit_addr(curCode.mode,curCode.addr);
|
|
prevCode.set_empty();
|
|
curCode.set_empty();
|
|
break;
|
|
}else if ((2>=(hpatch_StreamPos_t)(curCode.size-4))&&(curCode.mode<6)){
|
|
_emit_inst((hpatch_byte)(163+curCode.mode*12+(prevCode.size-1)*3+(curCode.size-4)));
|
|
_emit_addr(curCode.mode,curCode.addr);
|
|
prevCode.set_empty();
|
|
curCode.set_empty();
|
|
break;
|
|
}
|
|
}
|
|
//encode 1 type
|
|
assert(prevCode.size>0);
|
|
if (prevCode.size<=17) {
|
|
_emit_inst((hpatch_byte)(prevCode.size+1));
|
|
}else{
|
|
_emit_inst(1);
|
|
_emit_size(prevCode.size);
|
|
}
|
|
prevCode=curCode;
|
|
curCode.set_empty();
|
|
} break;
|
|
case vcdiff_code_COPY: {
|
|
if ((prevCode.size==4)&&(curCode.size==1)&&(curCode.type==vcdiff_code_ADD)){ // encode 2 type?
|
|
_emit_inst(247+prevCode.mode);
|
|
_emit_addr(prevCode.mode,prevCode.addr);
|
|
prevCode.set_empty();
|
|
curCode.set_empty();
|
|
break;
|
|
}
|
|
//encode 1 type
|
|
if (14>=(hpatch_StreamPos_t)(prevCode.size-4)){ // 4--18
|
|
_emit_inst((hpatch_byte)(19+prevCode.mode*16+(prevCode.size-3)));
|
|
}else{
|
|
_emit_inst(19+prevCode.mode*16);
|
|
_emit_size(prevCode.size);
|
|
}
|
|
_emit_addr(prevCode.mode,prevCode.addr);
|
|
prevCode=curCode;
|
|
curCode.set_empty();
|
|
} break;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
static inline void _flushBuf(TDiffStream& outDiff,std::vector<hpatch_byte>& buf){
|
|
outDiff.pushBack(buf.data(),buf.size());
|
|
buf.clear();
|
|
}
|
|
|
|
struct TVcCompress{
|
|
inline TVcCompress():encoder(0),compressPlugin(0){}
|
|
inline ~TVcCompress(){ if (encoder) compressPlugin->compress_close(compressPlugin->compress,encoder); }
|
|
vcdiff_compressHandle encoder;
|
|
const vcdiff_TCompress* compressPlugin;
|
|
};
|
|
|
|
static bool compressVcDiffData(std::vector<hpatch_byte>& out_code,TVcCompress* compress,const hpatch_TStreamInput* data){
|
|
hpatch_StreamPos_t uncompressSize=data->streamSize;
|
|
const size_t _kMinDataSizeByCompress=32;
|
|
if (uncompressSize>_kMinDataSizeByCompress){
|
|
out_code.clear();
|
|
packUInt(out_code,uncompressSize);
|
|
const size_t pkSize=out_code.size();
|
|
|
|
const vcdiff_TCompress* compressPlugin=compress->compressPlugin;
|
|
const hpatch_BOOL isWriteHead=(compress->encoder==0);
|
|
if (compress->encoder==0){
|
|
compress->encoder=compressPlugin->compress_open(compressPlugin->compress);
|
|
_check(compress->encoder!=0,"compressVcDiffData() compressPlugin->compress_open");
|
|
}
|
|
|
|
hpatch_StreamPos_t maxCodeSize=compressPlugin->compress->maxCompressedSize(data->streamSize);
|
|
assert(maxCodeSize+pkSize==(size_t)(maxCodeSize+pkSize));
|
|
out_code.resize(pkSize+(size_t)maxCodeSize);
|
|
hpatch_TStreamOutput codeStream;
|
|
mem_as_hStreamOutput(&codeStream,out_code.data()+pkSize,out_code.data()+out_code.size());
|
|
hpatch_StreamPos_t codeSize=compressPlugin->compress_encode(compress->encoder,&codeStream,data,
|
|
isWriteHead,hpatch_FALSE);
|
|
_check(codeSize>0,"compressVcDiffData() compressPlugin->compress_encode");
|
|
out_code.resize(pkSize+(size_t)codeSize); //ok
|
|
return true;
|
|
}else{
|
|
assert(uncompressSize==(size_t)uncompressSize);
|
|
out_code.resize((size_t)uncompressSize);
|
|
_check(data->read(data,0,out_code.data(),out_code.data()+out_code.size()),
|
|
"compressVcDiffData() data->read");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void serialize_vcdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
|
|
const TCovers& covers,const hpatch_TStreamOutput* out_diff,
|
|
const vcdiff_TCompress* compressPlugin,size_t kMaxTargetWindowsSize){
|
|
std::vector<hpatch_byte> buf;
|
|
TDiffStream outDiff(out_diff);
|
|
{//head
|
|
pushBack(buf,kVcDiffType,sizeof(kVcDiffType));
|
|
buf.push_back(kVcDiffVersion);
|
|
const bool isHaveCompresser=(compressPlugin!=0)&&(compressPlugin->compress_type!=kVcDiff_compressorID_no);
|
|
const bool isHDiffzAppHead_a=isHaveCompresser;
|
|
hpatch_byte Hdr_Indicator = ((isHaveCompresser?1:0)<<0) // VCD_DECOMPRESS
|
|
| (0<<1) // VCD_CODETABLE, no custom code table
|
|
| ((isHDiffzAppHead_a?1:0)<<2); // VCD_APPHEADER
|
|
buf.push_back(Hdr_Indicator);
|
|
if (isHaveCompresser)
|
|
buf.push_back(compressPlugin->compress_type);
|
|
else
|
|
compressPlugin=0;
|
|
if (isHDiffzAppHead_a){
|
|
packUInt(buf,strlen(kHDiffzAppHead_a));
|
|
pushCStr(buf,kHDiffzAppHead_a);
|
|
}
|
|
_flushBuf(outDiff,buf);
|
|
}
|
|
|
|
const hpatch_StreamPos_t targetPosEnd=newData->streamSize;
|
|
hpatch_StreamPos_t targetPos=0;
|
|
size_t coveri=0;
|
|
std::vector<hpatch_byte> inst;
|
|
std::vector<hpatch_byte> addr;
|
|
std::vector<hpatch_byte> addr_z;
|
|
TVcCompress compressList[3];
|
|
compressList[0].compressPlugin=compressPlugin;
|
|
compressList[1].compressPlugin=compressPlugin;
|
|
compressList[2].compressPlugin=compressPlugin;
|
|
hpatch_StreamPos_t srcPos,srcEnd;
|
|
_getSrcWindow(covers,0,covers.coverCount(),&srcPos,&srcEnd);
|
|
while (targetPos<targetPosEnd){
|
|
size_t coveriEnd;
|
|
const hpatch_StreamPos_t targetLen=_getTargetWindow(targetPos,targetPosEnd,covers,coveri,&coveriEnd,kMaxTargetWindowsSize);
|
|
{//used same one lagre srcWindowSize
|
|
if (srcPos<srcEnd){
|
|
buf.push_back(VCD_SOURCE); //Win_Indicator
|
|
packUInt(buf,(hpatch_StreamPos_t)(srcEnd-srcPos));
|
|
packUInt(buf,srcPos);//srcPos
|
|
}else{
|
|
buf.push_back(0); //Win_Indicator, no src window
|
|
}
|
|
_flushBuf(outDiff,buf);
|
|
}
|
|
{
|
|
vc_encoder encoder(inst,addr);
|
|
encoder.encode(covers,coveri,targetPos,targetLen,srcPos,srcEnd-srcPos);
|
|
}
|
|
|
|
TNewDataDiffStream _newDataDiff(covers,newData,coveri,targetPos,targetPos+targetLen);
|
|
if (compressPlugin==0){
|
|
hpatch_StreamPos_t deltaLen = hpatch_packUInt_size(targetLen)+1+hpatch_packUInt_size(_newDataDiff.streamSize)
|
|
+hpatch_packUInt_size(inst.size())+hpatch_packUInt_size(addr.size())
|
|
+_newDataDiff.streamSize+inst.size()+addr.size();
|
|
packUInt(buf,deltaLen);
|
|
packUInt(buf,targetLen);
|
|
buf.push_back(0); //Delta_Indicator
|
|
packUInt(buf,_newDataDiff.streamSize);
|
|
packUInt(buf,inst.size());
|
|
packUInt(buf,addr.size());
|
|
_flushBuf(outDiff,buf);
|
|
|
|
outDiff.pushStream(&_newDataDiff);
|
|
outDiff.pushBack(inst.data(),inst.size());
|
|
outDiff.pushBack(addr.data(),addr.size());
|
|
}else{
|
|
hpatch_TStreamInput _instStream;
|
|
hpatch_TStreamInput _addrStream;
|
|
mem_as_hStreamInput(&_instStream,inst.data(),inst.data()+inst.size());
|
|
mem_as_hStreamInput(&_addrStream,addr.data(),addr.data()+addr.size());
|
|
|
|
bool addr_is_z=compressVcDiffData(addr_z,&compressList[0],&_addrStream);
|
|
std::vector<hpatch_byte>& inst_z=addr;
|
|
bool inst_is_z=compressVcDiffData(inst_z,&compressList[1],&_instStream);
|
|
std::vector<hpatch_byte>& data_z=inst;
|
|
bool data_is_z=compressVcDiffData(data_z,&compressList[2],&_newDataDiff);
|
|
hpatch_byte Delta_Indicator=((data_is_z?1:0)<<0)|((inst_is_z?1:0)<<1)|((addr_is_z?1:0)<<2);
|
|
hpatch_StreamPos_t deltaLen = hpatch_packUInt_size(targetLen)+1+hpatch_packUInt_size(data_z.size())
|
|
+hpatch_packUInt_size(inst_z.size())+hpatch_packUInt_size(addr_z.size())
|
|
+(hpatch_StreamPos_t)data_z.size()+inst_z.size()+addr_z.size();
|
|
packUInt(buf,deltaLen);
|
|
packUInt(buf,targetLen);
|
|
buf.push_back(Delta_Indicator);
|
|
packUInt(buf,data_z.size());
|
|
packUInt(buf,inst_z.size());
|
|
packUInt(buf,addr_z.size());
|
|
_flushBuf(outDiff,buf);
|
|
|
|
outDiff.pushBack(data_z.data(),data_z.size());
|
|
outDiff.pushBack(inst_z.data(),inst_z.size());
|
|
outDiff.pushBack(addr_z.data(),addr_z.size());
|
|
}
|
|
coveri=coveriEnd;
|
|
targetPos+=targetLen;
|
|
} //window loop
|
|
assert(coveri==covers.coverCount());
|
|
assert(targetPos==targetPosEnd);
|
|
}
|
|
|
|
template<class _TCover,class _TLen>
|
|
static void _clipCovers(std::vector<_TCover>& covers,_TLen limitMaxCoverLen){
|
|
const size_t cCount=covers.size();
|
|
for (size_t i=0;i<cCount;++i){
|
|
_TCover& c=covers[i];
|
|
if (c.length>limitMaxCoverLen){
|
|
_TLen allLen=c.length;
|
|
size_t clip=(size_t)(((hpatch_StreamPos_t)allLen+limitMaxCoverLen-1)/limitMaxCoverLen);
|
|
_TLen clipLen=(_TLen)(((hpatch_StreamPos_t)allLen+clip-1)/clip);
|
|
_TCover nc=c;
|
|
c.length=clipLen;
|
|
for (size_t j=1;j<clip;++j){
|
|
nc.oldPos+=clipLen;
|
|
nc.newPos+=clipLen;
|
|
allLen-=clipLen;
|
|
nc.length=(j+1<clip)?clipLen:allLen;
|
|
covers.push_back(nc);
|
|
}
|
|
}
|
|
}
|
|
if (covers.size()>cCount){
|
|
std::inplace_merge(covers.data(),covers.data()+cCount,covers.data()+covers.size(),
|
|
hdiff_private::cover_cmp_by_new_t<_TCover>());
|
|
}
|
|
}
|
|
|
|
void _create_vcdiff(const hpatch_byte* newData,const hpatch_byte* cur_newData_end,const hpatch_byte* newData_end,
|
|
const hpatch_byte* oldData,const hpatch_byte* cur_oldData_end,const hpatch_byte* oldData_end,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
int kMinSingleMatchScore,bool isUseBigCacheMatch,
|
|
ICoverLinesListener* coverLinesListener,size_t threadNum){
|
|
std::vector<hpatch_TCover_sz> covers;
|
|
const bool isCanExtendCover=false;
|
|
get_match_covers_by_sstring(newData,cur_newData_end,oldData,cur_oldData_end,covers,
|
|
kMinSingleMatchScore,isUseBigCacheMatch,coverLinesListener,
|
|
threadNum,isCanExtendCover);
|
|
_clipCovers(covers,(size_t)vcdiff_kMaxTargetWindowsSize/2);
|
|
const TCovers _covers((void*)covers.data(),covers.size(),
|
|
sizeof(*covers.data())==sizeof(hpatch_TCover32));
|
|
|
|
hdiff_TStreamInput newStream;
|
|
hdiff_TStreamInput oldStream;
|
|
mem_as_hStreamInput(&newStream,newData,newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
|
|
serialize_vcdiff(&newStream,&oldStream,_covers,out_diff,compressPlugin,vcdiff_kMaxTargetWindowsSize);
|
|
}
|
|
|
|
}//end namespace hdiff_private
|
|
|
|
using namespace hdiff_private;
|
|
|
|
void create_vcdiff(const hpatch_byte* newData,const hpatch_byte* newData_end,
|
|
const hpatch_byte* oldData,const hpatch_byte* oldData_end,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
int kMinSingleMatchScore,bool isUseBigCacheMatch,
|
|
ICoverLinesListener* coverLinesListener,size_t threadNum){
|
|
_create_vcdiff(newData,newData_end,newData_end,oldData,oldData_end,oldData_end,
|
|
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
|
|
coverLinesListener,threadNum);
|
|
}
|
|
void create_vcdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
int kMinSingleMatchScore,bool isUseBigCacheMatch,
|
|
ICoverLinesListener* coverLinesListener,size_t threadNum){
|
|
TAutoMem oldAndNewData;
|
|
loadOldAndNewStream(oldAndNewData,oldData,newData);
|
|
size_t old_size=oldData?(size_t)oldData->streamSize:0;
|
|
hpatch_byte* pOldData=oldAndNewData.data();
|
|
hpatch_byte* pNewData=pOldData+old_size;
|
|
hpatch_byte* pNewDataEnd=pNewData+(size_t)newData->streamSize;
|
|
_create_vcdiff(pNewData,pNewDataEnd,pNewDataEnd,pOldData,pOldData+old_size,pOldData+old_size,
|
|
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
|
|
coverLinesListener,threadNum);
|
|
}
|
|
|
|
void create_vcdiff_stream(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
size_t kMatchBlockSize,const hdiff_TMTSets_s* mtsets){
|
|
TCoversBuf covers(newData->streamSize,oldData->streamSize);
|
|
get_match_covers_by_block(newData,oldData,&covers,kMatchBlockSize,mtsets);
|
|
if (covers._isCover32)
|
|
_clipCovers(covers.m_covers_limit,(hpatch_uint32_t)vcdiff_kMaxTargetWindowsSize/2);
|
|
else
|
|
_clipCovers(covers.m_covers_larger,(hpatch_StreamPos_t)vcdiff_kMaxTargetWindowsSize/2);
|
|
covers.update();
|
|
serialize_vcdiff(newData,oldData,covers,out_diff,compressPlugin,vcdiff_kMaxTargetWindowsSize);
|
|
}
|
|
|
|
|
|
void create_vcdiff_block(hpatch_byte* newData,hpatch_byte* newData_end,
|
|
hpatch_byte* oldData,hpatch_byte* oldData_end,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
int kMinSingleMatchScore,bool isUseBigCacheMatch,
|
|
size_t matchBlockSize,size_t threadNum){
|
|
if (matchBlockSize==0){
|
|
_create_vcdiff(newData,newData_end,newData_end,oldData,oldData_end,oldData_end,
|
|
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,0,threadNum);
|
|
return;
|
|
}
|
|
TCoversOptimMB<TMatchBlock> coversOp(newData,newData_end,oldData,oldData_end,matchBlockSize,threadNum);
|
|
_create_vcdiff(newData,coversOp.matchBlock->newData_end_cur,newData_end,
|
|
oldData,coversOp.matchBlock->oldData_end_cur,oldData_end,
|
|
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,&coversOp,threadNum);
|
|
}
|
|
void create_vcdiff_block(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
|
|
const hpatch_TStreamOutput* out_diff,const vcdiff_TCompress* compressPlugin,
|
|
int kMinSingleMatchScore,bool isUseBigCacheMatch,
|
|
size_t matchBlockSize,size_t threadNum){
|
|
TAutoMem oldAndNewData;
|
|
loadOldAndNewStream(oldAndNewData,oldData,newData);
|
|
size_t old_size=oldData?(size_t)oldData->streamSize:0;
|
|
hpatch_byte* pOldData=oldAndNewData.data();
|
|
hpatch_byte* pNewData=pOldData+old_size;
|
|
create_vcdiff_block(pNewData,pNewData+(size_t)newData->streamSize,pOldData,pOldData+old_size,
|
|
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
|
|
matchBlockSize,threadNum);
|
|
}
|
|
|
|
bool check_vcdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
|
|
const hpatch_TStreamInput* diffStream,hpatch_TDecompress* decompressPlugin){
|
|
const size_t kACacheBufSize=hdiff_kFileIOBufBestSize;
|
|
TAutoMem _cache(kACacheBufSize*(1+5));
|
|
_TCheckOutNewDataStream out_newData(newData,_cache.data(),kACacheBufSize);
|
|
_test_rt(vcpatch_with_cache(&out_newData,oldData,diffStream,decompressPlugin,hpatch_TRUE,
|
|
_cache.data()+kACacheBufSize,_cache.data_end()));
|
|
_test_rt(out_newData.isWriteFinish());
|
|
return true;
|
|
}
|
|
bool check_vcdiff(const hpatch_byte* newData,const hpatch_byte* newData_end,
|
|
const hpatch_byte* oldData,const hpatch_byte* oldData_end,
|
|
const hpatch_byte* diffData,const hpatch_byte* diffData_end,
|
|
hpatch_TDecompress* decompressPlugin){
|
|
hdiff_TStreamInput newStream;
|
|
hdiff_TStreamInput oldStream;
|
|
hdiff_TStreamInput diffStream;
|
|
mem_as_hStreamInput(&newStream,newData,newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
mem_as_hStreamInput(&diffStream,diffData,diffData_end);
|
|
return check_vcdiff(&newStream,&oldStream,&diffStream,decompressPlugin);
|
|
} |