847 lines
36 KiB
C++
847 lines
36 KiB
C++
//unit_test.cpp
|
|
// for unitTest
|
|
//
|
|
/*
|
|
The MIT License (MIT)
|
|
Copyright (c) 2012-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 <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stddef.h>//for ptrdiff_t
|
|
#include <stdlib.h>
|
|
#include "math.h"
|
|
#include "../libHDiffPatch/HDiff/diff.h"
|
|
#include "../libHDiffPatch/HDiff/diff_for_hpatch_lite.h"
|
|
#include "../libHDiffPatch/HPatch/patch.h"
|
|
#include "../libHDiffPatch/HPatchLite/hpatch_lite.h"
|
|
#include "../libHDiffPatch/HDiff/private_diff/limit_mem_diff/stream_serialize.h"
|
|
#include "../libhsync/sync_make/sync_make.h"
|
|
#include "../libhsync/sync_client/sync_client.h"
|
|
using namespace hdiff_private;
|
|
typedef unsigned char TByte;
|
|
typedef ptrdiff_t TInt;
|
|
typedef size_t TUInt;
|
|
const long kRandTestCount=20000;
|
|
//#define _AttackPacth_ON
|
|
|
|
//===== select compress plugin =====
|
|
#define _CompressPlugin_no
|
|
//#define _CompressPlugin_zlib
|
|
//#define _CompressPlugin_bz2
|
|
//#define _CompressPlugin_lzma
|
|
//#define _CompressPlugin_lzma2
|
|
//#define _CompressPlugin_lz4
|
|
//#define _CompressPlugin_lz4hc
|
|
//#define _CompressPlugin_zstd
|
|
//#define _CompressPlugin_brotli
|
|
//#define _CompressPlugin_lzham
|
|
//#define _CompressPlugin_tuz
|
|
|
|
#define IS_NOTICE_compress_canceled 0 //for test, close compress fail notice
|
|
#define IS_REUSE_compress_handle 1 //for test, must in single thread
|
|
#include "../compress_plugin_demo.h"
|
|
#include "../decompress_plugin_demo.h"
|
|
|
|
#ifndef _CompressPlugin_no
|
|
#include "../dict_compress_plugin_demo.h" // https://github.com/sisong/hsynz
|
|
#include "../dict_decompress_plugin_demo.h" // https://github.com/sisong/hsynz
|
|
#endif
|
|
|
|
#define _ChecksumPlugin_crc32
|
|
#include "../checksum_plugin_demo.h"
|
|
|
|
#ifdef _CompressPlugin_no
|
|
const hdiff_TCompress* compressPlugin=0;
|
|
hpatch_TDecompress* decompressPlugin=0;
|
|
hpi_compressType compressHpiType=hpi_compressType_no;
|
|
#endif
|
|
#ifdef _CompressPlugin_zlib
|
|
const hdiff_TCompress* compressPlugin=&zlibCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&zlibDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_zlib;
|
|
#endif
|
|
#ifdef _CompressPlugin_bz2
|
|
const hdiff_TCompress* compressPlugin=&bz2CompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&bz2DecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_bz2;
|
|
#endif
|
|
#ifdef _CompressPlugin_lzma
|
|
const hdiff_TCompress* compressPlugin=&lzmaCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&lzmaDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_lzma;
|
|
#endif
|
|
#ifdef _CompressPlugin_lzma2
|
|
const hdiff_TCompress* compressPlugin=&lzma2CompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&lzma2DecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_lzma2;
|
|
#endif
|
|
#ifdef _CompressPlugin_lz4
|
|
const hdiff_TCompress* compressPlugin=&lz4CompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&lz4DecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_lz4;
|
|
#endif
|
|
#ifdef _CompressPlugin_lz4hc
|
|
const hdiff_TCompress* compressPlugin=&lz4hcCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&lz4DecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_lz4;
|
|
#endif
|
|
#ifdef _CompressPlugin_zstd
|
|
const hdiff_TCompress* compressPlugin=&zstdCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&zstdDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_zstd;
|
|
#endif
|
|
#ifdef _CompressPlugin_brotli
|
|
const hdiff_TCompress* compressPlugin=&brotliCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&brotliDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_brotli;
|
|
#endif
|
|
#ifdef _CompressPlugin_lzham
|
|
const hdiff_TCompress* compressPlugin=&lzhamCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&lzhamDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_lzham;
|
|
#endif
|
|
#ifdef _CompressPlugin_tuz
|
|
const hdiff_TCompress* compressPlugin=&tuzCompressPlugin.base;
|
|
hpatch_TDecompress* decompressPlugin=&tuzDecompressPlugin;
|
|
hpi_compressType compressHpiType=hpi_compressType_tuz;
|
|
#endif
|
|
|
|
static hsync_TDictCompress* _getDictCompressPlugin(){
|
|
#if defined(_CompressPlugin_zlib)
|
|
static TDictCompressPlugin_zlib _zlibDictCompressPlugin=zlibDictCompressPlugin;
|
|
_zlibDictCompressPlugin.compress_level=6;
|
|
return &_zlibDictCompressPlugin.base;
|
|
#elif defined(_CompressPlugin_zstd)
|
|
static TDictCompressPlugin_zstd _zstdDictCompressPlugin=zstdDictCompressPlugin;
|
|
_zstdDictCompressPlugin.compress_level=18;
|
|
return &_zstdDictCompressPlugin.base;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#define _IS_USES_MY_RAND
|
|
#ifdef _IS_USES_MY_RAND
|
|
class CMyRand{
|
|
public:
|
|
unsigned int _my_holdrand;
|
|
public:
|
|
inline CMyRand():_my_holdrand(1){}
|
|
inline int _my_rand(){
|
|
unsigned int result=_my_holdrand * 214013 + 2531011 ;
|
|
_my_holdrand = result;
|
|
return (result>>16) & RAND_MAX;
|
|
}
|
|
};
|
|
static CMyRand _MyRand;
|
|
inline int _rand(){ return _MyRand._my_rand(); }
|
|
inline void _srand(unsigned int seed){ _MyRand._my_holdrand=seed; }
|
|
#else
|
|
#define _rand rand
|
|
#define _srand srand
|
|
#endif
|
|
|
|
|
|
int testCompress(const char* str,const char* error_tag){
|
|
assert( ((compressPlugin==0)&&(decompressPlugin==0))
|
|
||((compressPlugin!=0)&&(decompressPlugin!=0)));
|
|
if (compressPlugin==0) return 0;
|
|
assert(decompressPlugin->is_can_open(compressPlugin->compressType()));
|
|
|
|
const TByte* data=(const TByte*)str;
|
|
const size_t dataSize=strlen(str);
|
|
std::vector<TByte> code((size_t)compressPlugin->maxCompressedSize(dataSize));
|
|
size_t codeSize=hdiff_compress_mem(compressPlugin,code.data(),code.data()+code.size(),
|
|
data,data+dataSize);
|
|
if (codeSize>code.size()) {
|
|
printf("\n testCompress compress error!!! tag:%s\n",error_tag); return 1; }
|
|
code.resize(codeSize);
|
|
|
|
std::vector<TByte> undata(dataSize);
|
|
if (!hpatch_deccompress_mem(decompressPlugin,code.data(),code.data()+code.size(),
|
|
undata.data(),undata.data()+undata.size())) {
|
|
printf("\n testCompress decompress error!!! tag:%s\n",error_tag); return 1; }
|
|
if (0!=memcmp(str,undata.data(),undata.size())) {
|
|
printf("\n testCompress decompress data error!!! tag:%s\n",error_tag); return 1; }
|
|
return 0;
|
|
}
|
|
|
|
|
|
static bool _patch_mem_stream(TByte* newData,TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,
|
|
const TByte* diff,const TByte* diff_end){
|
|
struct hpatch_TStreamOutput out_newStream;
|
|
struct hpatch_TStreamInput oldStream;
|
|
struct hpatch_TStreamInput diffStream;
|
|
mem_as_hStreamOutput(&out_newStream,newData,newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
mem_as_hStreamInput(&diffStream,diff,diff_end);
|
|
|
|
return 0!=patch_stream(&out_newStream,&oldStream,&diffStream);
|
|
}
|
|
|
|
static bool check_diff_stream(const TByte* newData,const TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,
|
|
const TByte* diff,const TByte* diff_end){
|
|
std::vector<TByte> testNewData(newData_end-newData);
|
|
TByte* testNewData0=testNewData.data();
|
|
|
|
if (!_patch_mem_stream(testNewData0,testNewData0+testNewData.size(),
|
|
oldData,oldData_end,diff,diff_end))
|
|
return false;
|
|
for (TUInt i=0; i<(TUInt)testNewData.size(); ++i) {
|
|
if (testNewData[i]!=newData[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static hpatch_TChecksum* hsynzDefaultChecksum=&crc32ChecksumPlugin;
|
|
|
|
struct TSyncInfoListener:public ISyncInfoListener{
|
|
inline TSyncInfoListener(){
|
|
infoImport=this;
|
|
findDecompressPlugin=_findDecompressPlugin;
|
|
onLoadedNewSyncInfo=0;
|
|
onNeedSyncInfo=0;
|
|
findChecksumPlugin=_findChecksumPlugin;
|
|
}
|
|
static hpatch_TChecksum* _findChecksumPlugin(ISyncInfoListener* listener,const char* strongChecksumType){
|
|
return hsynzDefaultChecksum;
|
|
}
|
|
static hsync_TDictDecompress* _findDecompressPlugin(ISyncInfoListener* listener,const char* compressType,size_t dictSize){
|
|
#if defined(_CompressPlugin_zlib)
|
|
static TDictDecompressPlugin_zlib _zlibDictDecompressPlugin=zlibDictDecompressPlugin;
|
|
_zlibDictDecompressPlugin.dict_bits=(hpatch_byte)_dictSizeToDictBits(dictSize);
|
|
return &_zlibDictDecompressPlugin.base;
|
|
#elif defined(_CompressPlugin_zstd)
|
|
static TDictDecompressPlugin_zstd _zstdDictDecompressPlugin=zstdDictDecompressPlugin;
|
|
_zstdDictDecompressPlugin.dictSize=dictSize;
|
|
return &_zstdDictDecompressPlugin.base;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
struct TReadSyncDataListener:public IReadSyncDataListener{
|
|
const std::vector<TByte>& _hzData;
|
|
inline explicit TReadSyncDataListener(const std::vector<TByte>& hsynzData):_hzData(hsynzData){
|
|
readSyncDataImport=this;
|
|
onNeedSyncInfo=0;
|
|
readSyncDataBegin=0;
|
|
readSyncData=_readSyncData;
|
|
readSyncDataEnd=0;
|
|
}
|
|
static hpatch_BOOL _readSyncData(struct IReadSyncDataListener* listener,uint32_t blockIndex,
|
|
hpatch_StreamPos_t posInNewSyncData,hpatch_StreamPos_t posInNeedSyncData,
|
|
unsigned char* out_syncDataBuf,uint32_t syncDataSize){
|
|
const TReadSyncDataListener* self=(const TReadSyncDataListener*)listener->readSyncDataImport;
|
|
const std::vector<TByte>& src=self->_hzData;
|
|
if (posInNewSyncData+syncDataSize>src.size()) return hpatch_FALSE;
|
|
memcpy(out_syncDataBuf,src.data()+(size_t)posInNewSyncData,syncDataSize);
|
|
return hpatch_TRUE;
|
|
}
|
|
};
|
|
|
|
static std::vector<TByte> _hsyniData;
|
|
static std::vector<TByte> _hsynzData;
|
|
static std::vector<TByte> _new_hsyniData;
|
|
static std::vector<TByte> _new_hsynzData;
|
|
static void _create_hsynz_diff(const TByte* newData,const TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,
|
|
std::vector<TByte>& out_diff){
|
|
TSyncClient_resultType ret=kSyncClient_ok;
|
|
struct hpatch_TStreamInput newStream;
|
|
mem_as_hStreamInput(&newStream,newData,newData_end);
|
|
_hsyniData.clear();
|
|
_hsynzData.clear();
|
|
_new_hsyniData.clear();
|
|
_new_hsynzData.clear();
|
|
TVectorAsStreamOutput hiStream(_hsyniData);
|
|
TVectorAsStreamOutput hzStream(_hsynzData);
|
|
create_sync_data(&newStream,&hiStream,&hzStream,
|
|
hsynzDefaultChecksum,_getDictCompressPlugin(),0,kSyncBlockSize_min);
|
|
|
|
//local diff
|
|
struct hpatch_TStreamInput oldStream;
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
out_diff.clear();
|
|
TVectorAsStreamOutput diffStream(out_diff);
|
|
TSyncInfoListener syncInfoListener;
|
|
TReadSyncDataListener readSyncDataListener(_hsynzData);
|
|
TNewDataSyncInfo newSyncInfo={0};
|
|
hiStream.streamSize=hiStream.dst.size();
|
|
ret=TNewDataSyncInfo_open(&newSyncInfo,(const hpatch_TStreamInput*)&hiStream,&syncInfoListener);
|
|
if (ret!=0) throw std::runtime_error("TNewDataSyncInfo_open() error!");
|
|
ret=sync_local_diff(&syncInfoListener,&readSyncDataListener,&oldStream,
|
|
&newSyncInfo,&diffStream,kSyncDiff_default,0,1);
|
|
TNewDataSyncInfo_close(&newSyncInfo);
|
|
if (ret!=0) throw std::runtime_error("sync_local_diff() error!");
|
|
}
|
|
|
|
static hpatch_BOOL _hsynz_local_patch(unsigned char* out_newData,unsigned char* out_newData_end,
|
|
const unsigned char* oldData,const unsigned char* oldData_end,
|
|
const unsigned char* diff,const unsigned char* diff_end){
|
|
TSyncClient_resultType ret=kSyncClient_ok;
|
|
struct hpatch_TStreamOutput out_newStream;
|
|
struct hpatch_TStreamInput oldStream;
|
|
struct hpatch_TStreamInput diffStream;
|
|
struct hpatch_TStreamInput hiStream;
|
|
mem_as_hStreamOutput(&out_newStream,out_newData,out_newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
mem_as_hStreamInput(&diffStream,diff,diff_end);
|
|
const std::vector<TByte>& hsyniData=_new_hsyniData.empty()?_hsyniData:_new_hsyniData;
|
|
mem_as_hStreamInput(&hiStream,hsyniData.data(),hsyniData.data()+hsyniData.size());
|
|
TSyncInfoListener syncInfoListener;
|
|
TNewDataSyncInfo newSyncInfo={0};
|
|
ret=TNewDataSyncInfo_open(&newSyncInfo,&hiStream,&syncInfoListener);
|
|
if (ret!=0){
|
|
#ifdef _AttackPacth_ON
|
|
return hpatch_FALSE;
|
|
#else
|
|
throw std::runtime_error("TNewDataSyncInfo_open() error!");
|
|
#endif
|
|
}
|
|
ret=sync_local_patch(&syncInfoListener,&diffStream,&oldStream,&newSyncInfo,&out_newStream,0,1);
|
|
TNewDataSyncInfo_close(&newSyncInfo);
|
|
if (ret!=0){
|
|
#ifdef _AttackPacth_ON
|
|
return hpatch_FALSE;
|
|
#else
|
|
throw std::runtime_error("sync_local_patch() error!");
|
|
#endif
|
|
}
|
|
return hpatch_TRUE;
|
|
}
|
|
|
|
static hpatch_BOOL _hsynz_sync_patch(unsigned char* out_newData,unsigned char* out_newData_end,
|
|
const unsigned char* oldData,const unsigned char* oldData_end){
|
|
TSyncClient_resultType ret=kSyncClient_ok;
|
|
struct hpatch_TStreamOutput out_newStream;
|
|
struct hpatch_TStreamInput oldStream;
|
|
struct hpatch_TStreamInput hiStream;
|
|
mem_as_hStreamOutput(&out_newStream,out_newData,out_newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
const std::vector<TByte>& hsyniData=_new_hsyniData.empty()?_hsyniData:_new_hsyniData;
|
|
const std::vector<TByte>& hsynzData=_new_hsynzData.empty()?_hsynzData:_new_hsynzData;
|
|
mem_as_hStreamInput(&hiStream,hsyniData.data(),hsyniData.data()+hsyniData.size());
|
|
TSyncInfoListener syncInfoListener;
|
|
TNewDataSyncInfo newSyncInfo={0};
|
|
TReadSyncDataListener readSyncDataListener(hsynzData);
|
|
ret=TNewDataSyncInfo_open(&newSyncInfo,&hiStream,&syncInfoListener);
|
|
if (ret!=0){
|
|
#ifdef _AttackPacth_ON
|
|
return hpatch_FALSE;
|
|
#else
|
|
throw std::runtime_error("TNewDataSyncInfo_open() error!");
|
|
#endif
|
|
}
|
|
ret=sync_patch(&syncInfoListener,&readSyncDataListener,&oldStream,&newSyncInfo,&out_newStream,0,0,0,1);
|
|
TNewDataSyncInfo_close(&newSyncInfo);
|
|
if (ret!=0){
|
|
#ifdef _AttackPacth_ON
|
|
return hpatch_FALSE;
|
|
#else
|
|
throw std::runtime_error("sync_patch() error!");
|
|
#endif
|
|
}
|
|
return hpatch_TRUE;
|
|
}
|
|
|
|
static std::vector<TByte> _newTempData;
|
|
bool _check_hsynz_local_patch(const TByte* newData,const TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,
|
|
const TByte* diff,const TByte* diff_end){
|
|
_newTempData.resize(newData_end-newData);
|
|
memset(_newTempData.data(),0,_newTempData.size());
|
|
if (!_hsynz_local_patch(_newTempData.data(),_newTempData.data()+_newTempData.size(),
|
|
oldData,oldData_end,diff,diff_end)) return false;
|
|
if (0!=memcmp(_newTempData.data(),newData,_newTempData.size()))
|
|
#ifdef _AttackPacth_ON
|
|
return false;
|
|
#else
|
|
throw std::runtime_error("_check_hsynz_local_patch() error!");
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool _check_hsynz_sync_patch(const TByte* newData,const TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end){
|
|
_newTempData.resize(newData_end-newData);
|
|
memset(_newTempData.data(),0,_newTempData.size());
|
|
if (!_hsynz_sync_patch(_newTempData.data(),_newTempData.data()+_newTempData.size(),
|
|
oldData,oldData_end)) return false;
|
|
if (0!=memcmp(_newTempData.data(),newData,_newTempData.size()))
|
|
#ifdef _AttackPacth_ON
|
|
return false;
|
|
#else
|
|
throw std::runtime_error("_check_hsynz_sync_patch() error!");
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
enum TDiffType{
|
|
kDiffO,
|
|
kDiffZ,
|
|
kDiffZs,
|
|
kDiffS,
|
|
kDiffSs,
|
|
kDiffi,
|
|
kHSynz,
|
|
};
|
|
static const size_t kDiffTypeCount=kHSynz+1;
|
|
|
|
#ifdef _AttackPacth_ON
|
|
|
|
hpatch_BOOL _sspatch_onDiffInfo(struct sspatch_listener_t* listener,
|
|
const hpatch_singleCompressedDiffInfo* info,
|
|
hpatch_TDecompress** out_decompressPlugin,
|
|
unsigned char** out_temp_cache,
|
|
unsigned char** out_temp_cacheEnd){
|
|
size_t temp_cache_size=info->stepMemSize+hpatch_kFileIOBufBetterSize*3;
|
|
static TAutoMem _buf;
|
|
if (_buf.size()<temp_cache_size)
|
|
_buf.realloc(temp_cache_size);
|
|
unsigned char* temp_cache=_buf.data();
|
|
*out_temp_cache=temp_cache;
|
|
*out_temp_cacheEnd=temp_cache+temp_cache_size;
|
|
*out_decompressPlugin=decompressPlugin;
|
|
return hpatch_TRUE;
|
|
}
|
|
|
|
struct TPatchiListener:public hpatchi_listener_t{
|
|
hpatch_decompressHandle decompresser;
|
|
hpatch_TDecompress* decompressPlugin;
|
|
inline TPatchiListener():decompresser(0){}
|
|
inline ~TPatchiListener(){ if (decompresser) decompressPlugin->close(decompressPlugin,decompresser); }
|
|
const hpi_byte* diffData_cur;
|
|
const hpi_byte* diffData_end;
|
|
hpatch_TStreamInput diffStream;
|
|
hpi_pos_t uncompressSize;
|
|
const hpi_byte* newData_cur;
|
|
const hpi_byte* newData_end;
|
|
const hpi_byte* oldData;
|
|
const hpi_byte* oldData_end;
|
|
|
|
static hpi_BOOL _read_diff(hpi_TInputStreamHandle inputStream,hpi_byte* out_data,hpi_size_t* data_size){
|
|
TPatchiListener& self=*(TPatchiListener*)inputStream;
|
|
const hpi_byte* cur=self.diffData_cur;
|
|
size_t d_size=self.diffData_end-cur;
|
|
size_t r_size=*data_size;
|
|
if (r_size>d_size){
|
|
r_size=d_size;
|
|
*data_size=(hpi_size_t)r_size;
|
|
}
|
|
memcpy(out_data,cur,r_size);
|
|
self.diffData_cur=cur+r_size;
|
|
return hpi_TRUE;
|
|
}
|
|
static hpi_BOOL _read_diff_dec(hpi_TInputStreamHandle inputStream,hpi_byte* out_data,hpi_size_t* data_size){
|
|
TPatchiListener& self=*(TPatchiListener*)inputStream;
|
|
hpi_size_t r_size=*data_size;
|
|
if (r_size>self.uncompressSize){
|
|
r_size=(hpi_size_t)self.uncompressSize;
|
|
*data_size=(hpi_size_t)self.uncompressSize;
|
|
}
|
|
if (!self.decompressPlugin->decompress_part(self.decompresser,out_data,out_data+r_size))
|
|
return hpi_FALSE;
|
|
self.uncompressSize-=r_size;
|
|
return hpi_TRUE;
|
|
}
|
|
static hpi_BOOL _write_new(struct hpatchi_listener_t* listener,const hpi_byte* data,hpi_size_t data_size){
|
|
TPatchiListener& self=*(TPatchiListener*)listener;
|
|
if (data_size>(size_t)(self.newData_end-self.newData_cur))
|
|
return hpi_FALSE;
|
|
if (0!=memcmp(self.newData_cur,data,data_size))
|
|
return hpi_FALSE;
|
|
self.newData_cur+=data_size;
|
|
return hpi_TRUE;
|
|
}
|
|
static hpi_BOOL _read_old(struct hpatchi_listener_t* listener,hpi_pos_t read_from_pos,hpi_byte* out_data,hpi_size_t data_size){
|
|
TPatchiListener& self=*(TPatchiListener*)listener;
|
|
size_t dsize=self.oldData_end-self.oldData;
|
|
if ((read_from_pos>dsize)|(data_size>(size_t)(dsize-read_from_pos))) return hpi_FALSE;
|
|
memcpy(out_data,self.oldData+(size_t)read_from_pos,data_size);
|
|
return hpi_TRUE;
|
|
}
|
|
};
|
|
|
|
|
|
long attackPacth(TByte* out_newData,TByte* out_newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,
|
|
const TByte* diffData,const TByte* diffData_end,
|
|
const char* error_tag,TDiffType diffType){
|
|
switch (diffType){
|
|
case kDiffO: {
|
|
hpatch_BOOL rt0=patch(out_newData,out_newData_end,oldData,oldData_end,diffData,diffData_end);
|
|
hpatch_BOOL rt1=_patch_mem_stream(out_newData,out_newData_end,oldData,oldData_end,diffData,diffData_end);
|
|
if (rt0!=rt1){
|
|
printf("\n attackPacth error!!! tag:%s\n",error_tag);
|
|
return 1;
|
|
}
|
|
} break;
|
|
case kDiffZ: {
|
|
patch_decompress_mem(out_newData,out_newData_end,oldData,oldData_end,
|
|
diffData,diffData_end,decompressPlugin);
|
|
} break;
|
|
case kDiffS: {
|
|
sspatch_listener_t listener={0,_sspatch_onDiffInfo,0};
|
|
patch_single_stream_mem(&listener,out_newData,out_newData_end,oldData,oldData_end,
|
|
diffData,diffData_end,0);
|
|
} break;
|
|
case kDiffi: {
|
|
hpi_compressType compressType;
|
|
check_lite_diff_open(diffData,diffData_end,&compressType);
|
|
check_lite_diff(out_newData,out_newData_end,oldData,oldData_end,
|
|
diffData,diffData_end,decompressPlugin);
|
|
} break;
|
|
case kHSynz: {
|
|
_hsynz_local_patch(out_newData,out_newData_end,oldData,oldData_end,diffData,diffData_end);
|
|
_hsynz_sync_patch(out_newData,out_newData_end,oldData,oldData_end);
|
|
} break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
long attackPacth(TInt newSize,const TByte* oldData,const TByte* oldData_end,
|
|
const TByte* _diffData,const TByte* _diffData_end,int seed,TDiffType diffType){
|
|
char tag[250]="\0";
|
|
_srand(seed);
|
|
const int kLoopCount=1000;
|
|
long exceptionCount=0;
|
|
std::vector<TByte> _newData(newSize);
|
|
TByte* newData=_newData.data();
|
|
TByte* newData_end=newData+_newData.size();
|
|
const TInt diffSize=_diffData_end-_diffData;
|
|
std::vector<TByte> new_diffData(diffSize);
|
|
TByte* diffData=new_diffData.data();
|
|
TByte* diffData_end=diffData+diffSize;
|
|
if (diffType==kHSynz){
|
|
_new_hsyniData.resize(_hsyniData.size());
|
|
_new_hsynzData.resize(_hsynzData.size());
|
|
}
|
|
|
|
try {
|
|
for (int i=0; i<kLoopCount; ++i) {
|
|
sprintf(tag, "attackPacth exceptionCount=%ld testSeed=%d i=%ld",exceptionCount,seed,i);
|
|
if (diffType==kHSynz){
|
|
const int hisize=(int)_hsyniData.size();
|
|
memcpy(_new_hsyniData.data(),_hsyniData.data(),hisize);
|
|
int randCount=(int)(1+_rand()*(1.0/RAND_MAX)*_rand()*(1.0/RAND_MAX)*hisize/2);
|
|
TByte* hiData=_new_hsyniData.data();
|
|
for (int r=0; r<randCount; ++r)
|
|
hiData[_rand()%hisize]=_rand();
|
|
|
|
const int hzsize=(int)_hsynzData.size();
|
|
if (hzsize>0){
|
|
memcpy(_new_hsynzData.data(),_hsynzData.data(),hzsize);
|
|
randCount=(int)(1+_rand()*(1.0/RAND_MAX)*_rand()*(1.0/RAND_MAX)*hzsize/8);
|
|
TByte* hzData=_new_hsynzData.data();
|
|
for (int r=0; r<randCount; ++r)
|
|
hzData[_rand()%hzsize]=_rand();
|
|
}
|
|
}
|
|
|
|
memcpy(diffData,_diffData,diffSize);
|
|
const int randCount=(int)(1+_rand()*(1.0/RAND_MAX)*_rand()*(1.0/RAND_MAX)*diffSize/4);
|
|
for (int r=0; r<randCount; ++r)
|
|
diffData[_rand()%diffSize]=_rand();
|
|
|
|
exceptionCount+=attackPacth(newData,newData_end,oldData,oldData_end,diffData,diffData_end,tag,diffType);
|
|
}
|
|
return exceptionCount;
|
|
} catch (...) {
|
|
printf("exception!!! tag:%s\n",tag);
|
|
return exceptionCount+1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
long test(const TByte* newData,const TByte* newData_end,
|
|
const TByte* oldData,const TByte* oldData_end,const char* tag,hpatch_StreamPos_t* out_diffSizes){
|
|
printf("%s newSize:%ld oldSize:%ld ",tag, (long)(newData_end-newData), (long)(oldData_end-oldData));
|
|
long result=0;
|
|
{//test diffs
|
|
std::vector<TByte> diffData;
|
|
create_single_compressed_diff(newData,newData_end,oldData,oldData_end,diffData,compressPlugin);
|
|
if (out_diffSizes) out_diffSizes[kDiffS]+=diffData.size();
|
|
if (!check_single_compressed_diff(newData,newData_end,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),decompressPlugin)){
|
|
printf("\n diffs error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffs:%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffS);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test diffs stream
|
|
std::vector<TByte> diffData;
|
|
struct hpatch_TStreamInput newStream;
|
|
struct hpatch_TStreamInput oldStream;
|
|
TVectorAsStreamOutput out_diffStream(diffData);
|
|
mem_as_hStreamInput(&newStream,newData,newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
|
|
create_single_compressed_diff_stream(&newStream,&oldStream,&out_diffStream,compressPlugin,1<<4);
|
|
if (out_diffSizes) out_diffSizes[kDiffSs]+=diffData.size();
|
|
struct hpatch_TStreamInput in_diffStream;
|
|
mem_as_hStreamInput(&in_diffStream,diffData.data(),diffData.data()+diffData.size());
|
|
if (!check_single_compressed_diff(&newStream,&oldStream,&in_diffStream,decompressPlugin)){
|
|
printf("\n diffs stream error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffs(stream):%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffS);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test diffz
|
|
std::vector<TByte> diffData;
|
|
create_compressed_diff(newData,newData_end,oldData,oldData_end,diffData,compressPlugin);
|
|
if (out_diffSizes) out_diffSizes[kDiffZ]+=diffData.size();
|
|
if (!check_compressed_diff(newData,newData_end,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),decompressPlugin)){
|
|
printf("\n diffz error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffz:%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffZ);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test diffz stream
|
|
std::vector<TByte> diffData;
|
|
struct hpatch_TStreamInput newStream;
|
|
struct hpatch_TStreamInput oldStream;
|
|
TVectorAsStreamOutput out_diffStream(diffData);
|
|
mem_as_hStreamInput(&newStream,newData,newData_end);
|
|
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
|
|
|
|
create_compressed_diff_stream(&newStream,&oldStream,&out_diffStream,compressPlugin,1<<4);
|
|
if (out_diffSizes) out_diffSizes[kDiffZs]+=diffData.size();
|
|
struct hpatch_TStreamInput in_diffStream;
|
|
mem_as_hStreamInput(&in_diffStream,diffData.data(),diffData.data()+diffData.size());
|
|
if (!check_compressed_diff(&newStream,&oldStream,&in_diffStream,decompressPlugin)){
|
|
printf("\n diffz stream error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffz(stream):%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffZ);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test diffi
|
|
std::vector<TByte> diffData;
|
|
hdiffi_TCompress compressPlugini={compressPlugin,compressHpiType};
|
|
create_lite_diff(newData,newData_end,oldData,oldData_end,diffData,&compressPlugini);
|
|
if (out_diffSizes) out_diffSizes[kDiffi]+=diffData.size();
|
|
if (!check_lite_diff(newData,newData_end,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),decompressPlugin)){
|
|
printf("\n diffi error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffi:%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffi);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test diff
|
|
std::vector<TByte> diffData;
|
|
create_diff(newData,newData_end,oldData,oldData_end, diffData);
|
|
if (out_diffSizes) out_diffSizes[kDiffO]+=diffData.size();
|
|
if ((!check_diff(newData,newData_end,oldData,oldData_end,diffData.data(),diffData.data()+diffData.size()))
|
|
||(!check_diff_stream(newData,newData_end,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size())) ){
|
|
printf("\n diffo error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" diffo:%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kDiffO);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
{//test hsynz
|
|
std::vector<TByte> diffData;
|
|
_create_hsynz_diff(newData,newData_end,oldData,oldData_end,diffData);
|
|
if (out_diffSizes) out_diffSizes[kHSynz]+=diffData.size();
|
|
if ((!_check_hsynz_local_patch(newData,newData_end,oldData,oldData_end,diffData.data(),diffData.data()+diffData.size()))
|
|
||(!_check_hsynz_sync_patch(newData,newData_end,oldData,oldData_end))){
|
|
printf("\n hsynz error!!! tag:%s\n",tag);
|
|
++result;
|
|
}else{
|
|
printf(" hsynz:%ld", (long)(diffData.size()));
|
|
#ifdef _AttackPacth_ON
|
|
long exceptionCount=attackPacth(newData_end-newData,oldData,oldData_end,
|
|
diffData.data(),diffData.data()+diffData.size(),_rand(),kHSynz);
|
|
if (exceptionCount>0) return exceptionCount;
|
|
#endif
|
|
}
|
|
}
|
|
printf("\n");
|
|
return result;
|
|
}
|
|
|
|
static inline long test(const char* newStr,const char* oldStr,const char* error_tag){
|
|
const TByte* newData=(const TByte*)newStr;
|
|
const TByte* oldData=(const TByte*)oldStr;
|
|
return test(newData,newData+strlen(newStr),oldData,oldData+strlen(oldStr),error_tag,0);
|
|
}
|
|
|
|
|
|
void setRandDataSize(int kMaxDataSize,std::vector<TByte>& oldData,std::vector<TByte>& newData,
|
|
double sunSizeMin,double subSizeMax){
|
|
const TInt oldSize=(TInt)(_rand()*(1.0/RAND_MAX)*_rand()*(1.0/RAND_MAX)*kMaxDataSize);
|
|
const TInt newSize=(TInt)(oldSize*(sunSizeMin+_rand()*(1.0/RAND_MAX)*(subSizeMax-sunSizeMin)));
|
|
newData.resize(newSize);
|
|
oldData.resize(oldSize);
|
|
}
|
|
|
|
void setRandData(std::vector<TByte>& data){
|
|
for (TInt i=0; i<(TInt)data.size(); ++i)
|
|
data[i]=_rand();
|
|
}
|
|
|
|
|
|
int main(int argc, const char * argv[]){
|
|
clock_t time1=clock();
|
|
long errorCount=0;
|
|
errorCount+=testCompress("","c1");
|
|
errorCount+=testCompress("1","c2");
|
|
errorCount+=testCompress("12","c3");
|
|
errorCount+=testCompress("123","c4");
|
|
errorCount+=testCompress("123456789876543212345677654321234567765432","c5");
|
|
|
|
errorCount+=test("", "", "1");
|
|
errorCount+=test("", "1", "2");
|
|
errorCount+=test("1", "", "3");
|
|
errorCount+=test("1", "1", "4");
|
|
errorCount+=test("22", "11", "5");
|
|
errorCount+=test("22", "22", "6");
|
|
errorCount+=test("1234567890", "1234567890", "7");
|
|
errorCount+=test("123456789876543212345677654321234567765432", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "8");
|
|
errorCount+=test("123456789876543212345677654321234567765432asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "9");
|
|
errorCount+=test("asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr123456789876543212345677654321234567765432", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "10");
|
|
errorCount+=test("a123456789876543212345677654321234567765432asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "11");
|
|
errorCount+=test("123456789876543212345677654321234567765432asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr1", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "12");
|
|
errorCount+=test("a123456789876543212345677654321234567765432asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr1", "asadsdasfefw45fg4gacasc234fervsvdfdsfef4g4gr", "13");
|
|
|
|
{
|
|
const char* _strData14="a1234567898765432123456776djng5;wsvdoivnkdnvdfnvnkljdfdfkjfnvdlfknvvdfnvknfnk54321234567765432asaddjbvdjvbdfbvb"
|
|
"dfve.kskj3bt3jht38985iojtjn76i7khjmfgyrdjrj5jsdasfefw45fg4gacasc234fervsvdfdghn6767kk7887oklo990gr232eqwdscdsfef4g4gr1";
|
|
const TByte* data14=(const TByte*)_strData14;
|
|
const size_t dataSize=strlen(_strData14);
|
|
hpatch_StreamPos_t diffSize14[kDiffTypeCount]={0};
|
|
errorCount+=test(data14, data14+dataSize,data14, data14+dataSize, "14",diffSize14);
|
|
for (int i=0;i<kDiffTypeCount;++i){
|
|
if (diffSize14[i]>=dataSize){
|
|
++errorCount;
|
|
printf("error!!! tag:%s\n","14 test diff size");
|
|
}
|
|
}
|
|
}
|
|
|
|
const int kMaxDataSize=1024*32;
|
|
|
|
std::vector<int> seeds(kRandTestCount);
|
|
_srand(0);
|
|
for (int i=0; i<kRandTestCount; ++i)
|
|
seeds[i]=((unsigned int)_rand())*(unsigned int)(RAND_MAX+1)+(unsigned int)_rand();
|
|
|
|
hpatch_StreamPos_t sumNewSize=0;
|
|
hpatch_StreamPos_t sumOldSize=0;
|
|
hpatch_StreamPos_t sumDiffSizes[kDiffTypeCount]={0};
|
|
std::vector<TByte> _newData;
|
|
std::vector<TByte> _oldData;
|
|
for (TInt i=0; i<kRandTestCount; ++i) {
|
|
char tag[256];
|
|
#if defined(_MSC_VER)&&(_MSC_VER>=1400) //VC2005
|
|
sprintf_s(tag,256, "error==%ld testSeed=%d",errorCount,seeds[i]);
|
|
#else
|
|
sprintf(tag, "error==%ld testSeed=%d",errorCount,seeds[i]);
|
|
#endif
|
|
|
|
_srand(seeds[i]);
|
|
|
|
setRandDataSize(kMaxDataSize,_oldData,_newData,0.7,1.5);
|
|
setRandData(_oldData);
|
|
setRandData(_newData);
|
|
const TInt oldSize=(TInt)_oldData.size();
|
|
const TInt newSize=(TInt)_newData.size();
|
|
const TInt kMaxCopyCount=(TInt)sqrt((double)oldSize);
|
|
TByte* newData=_newData.data();
|
|
TByte* oldData=_oldData.data();
|
|
const TInt copyCount=0+(TInt)((1-_rand()*(1.0/RAND_MAX)*_rand()*(1.0/RAND_MAX))*kMaxCopyCount*1);
|
|
const TInt kMaxCopyLength=(TInt)(1+_rand()*(1.0/RAND_MAX)*kMaxCopyCount*16);
|
|
for (TInt ci=0; ci<copyCount; ++ci) {
|
|
const TInt length=1+(TInt)(_rand()*(1.0/RAND_MAX)*kMaxCopyLength);
|
|
if ((length>oldSize*4/5)||(length>newSize*4/5)) {
|
|
continue;
|
|
}
|
|
const TInt oldPos=(oldSize-length==0)?0:(TInt)(_rand()*(1.0/RAND_MAX)*(oldSize-length));
|
|
const TInt newPos=(newSize-length==0)?0:(TInt)(_rand()*(1.0/RAND_MAX)*(newSize-length));
|
|
memcpy(&newData[0]+newPos, &oldData[0]+oldPos, length);
|
|
}
|
|
errorCount+=test(&newData[0],&newData[0]+newSize,&oldData[0],&oldData[0]+oldSize,tag,sumDiffSizes);
|
|
sumNewSize+=newSize;
|
|
sumOldSize+=oldSize;
|
|
}
|
|
|
|
printf("\nchecked:%ld errorCount:%ld\n",kRandTestCount,errorCount);
|
|
printf("newSize:100%% oldSize:%2.2f%% diffO:%2.2f%% diffZ:%2.2f%%(s:%2.2f%%)"
|
|
" diffS:%2.2f%%(s:%2.2f%%) diffi:%2.2f%% hsynz:%2.2f%%\n",
|
|
sumOldSize*100.0/sumNewSize,sumDiffSizes[kDiffO]*100.0/sumNewSize,
|
|
sumDiffSizes[kDiffZ]*100.0/sumNewSize,sumDiffSizes[kDiffZs]*100.0/sumNewSize,
|
|
sumDiffSizes[kDiffS]*100.0/sumNewSize,sumDiffSizes[kDiffSs]*100.0/sumNewSize,
|
|
sumDiffSizes[kDiffi]*100.0/sumNewSize,sumDiffSizes[kHSynz]*100.0/sumNewSize);
|
|
clock_t time2=clock();
|
|
printf("\nrun time:%.1f s\n",(time2-time1)*(1.0/CLOCKS_PER_SEC));
|
|
|
|
return (int)errorCount;
|
|
}
|