1486 lines
62 KiB
C
1486 lines
62 KiB
C
//hpatchz.c
|
|
// patch tool
|
|
//
|
|
/*
|
|
This is the HDiffPatch copyright.
|
|
|
|
Copyright (c) 2012-2021 HouSisong All Rights Reserved.
|
|
|
|
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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h> //fprintf
|
|
#include "libHDiffPatch/HPatch/patch.h"
|
|
#include "_clock_for_demo.h"
|
|
#include "_atosize.h"
|
|
#include "file_for_patch.h"
|
|
#include "dirDiffPatch/dir_patch/dir_patch.h"
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
#include "hpatch_dir_listener.h"
|
|
#endif
|
|
|
|
#ifndef _IS_NEED_MAIN
|
|
# define _IS_NEED_MAIN 1
|
|
#endif
|
|
#ifndef _IS_NEED_CMDLINE
|
|
# define _IS_NEED_CMDLINE 1
|
|
#endif
|
|
#ifndef _IS_NEED_SINGLE_STREAM_DIFF
|
|
# define _IS_NEED_SINGLE_STREAM_DIFF 1
|
|
#endif
|
|
#ifndef _IS_NEED_BSDIFF
|
|
# define _IS_NEED_BSDIFF 1
|
|
#endif
|
|
#ifndef _IS_NEED_VCDIFF
|
|
# define _IS_NEED_VCDIFF 1
|
|
#endif
|
|
#ifndef _IS_NEED_SFX
|
|
# define _IS_NEED_SFX 1
|
|
#endif
|
|
|
|
#ifndef _IS_NEED_DEFAULT_CompressPlugin
|
|
# define _IS_NEED_DEFAULT_CompressPlugin 1
|
|
#endif
|
|
#if (_IS_NEED_ALL_CompressPlugin)
|
|
# undef _IS_NEED_DEFAULT_CompressPlugin
|
|
# define _IS_NEED_DEFAULT_CompressPlugin 1
|
|
#endif
|
|
#if (_IS_NEED_DEFAULT_CompressPlugin)
|
|
//===== select needs decompress plugins or change to your plugin=====
|
|
# define _CompressPlugin_zlib
|
|
# define _CompressPlugin_bz2
|
|
# define _CompressPlugin_lzma
|
|
# define _CompressPlugin_lzma2
|
|
# define _CompressPlugin_zstd
|
|
#if (_IS_NEED_VCDIFF)
|
|
# define _CompressPlugin_7zXZ
|
|
#endif
|
|
#endif
|
|
#if (_IS_NEED_ALL_CompressPlugin)
|
|
//===== select needs decompress plugins or change to your plugin=====
|
|
# define _CompressPlugin_lz4 // || _CompressPlugin_lz4hc
|
|
# define _CompressPlugin_brotli
|
|
# define _CompressPlugin_lzham
|
|
# define _CompressPlugin_tuz
|
|
#endif
|
|
|
|
#if (_IS_NEED_BSDIFF)
|
|
# include "bsdiff_wrapper/bspatch_wrapper.h"
|
|
# ifndef _CompressPlugin_bz2
|
|
# define _CompressPlugin_bz2 //bsdiff4 need bz2
|
|
# endif
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
# include "vcdiff_wrapper/vcpatch_wrapper.h"
|
|
#endif
|
|
|
|
#include "decompress_plugin_demo.h"
|
|
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
|
|
#ifndef _IS_NEED_DEFAULT_ChecksumPlugin
|
|
# define _IS_NEED_DEFAULT_ChecksumPlugin 1
|
|
#endif
|
|
#if (_IS_NEED_ALL_ChecksumPlugin)
|
|
# undef _IS_NEED_DEFAULT_ChecksumPlugin
|
|
# define _IS_NEED_DEFAULT_ChecksumPlugin 1
|
|
#endif
|
|
#if (_IS_NEED_DEFAULT_ChecksumPlugin)
|
|
//===== select needs checksum plugins or change to your plugin=====
|
|
# define _ChecksumPlugin_crc32 // 32 bit effective //need zlib
|
|
# define _ChecksumPlugin_fadler64 // ? 63 bit effective
|
|
#endif
|
|
#if (_IS_NEED_ALL_ChecksumPlugin)
|
|
//===== select needs checksum plugins or change to your plugin=====
|
|
# define _ChecksumPlugin_adler32 // ? 29 bit effective
|
|
# define _ChecksumPlugin_adler64 // ? 30 bit effective
|
|
# define _ChecksumPlugin_fadler32 // ~ 32 bit effective
|
|
# define _ChecksumPlugin_fadler128// ? 81 bit effective
|
|
# define _ChecksumPlugin_md5 // 128 bit
|
|
# define _ChecksumPlugin_blake3 // 256 bit
|
|
# define _ChecksumPlugin_xxh3 // 64 bit fast
|
|
# define _ChecksumPlugin_xxh128 // 128 bit fast
|
|
#endif
|
|
|
|
#include "checksum_plugin_demo.h"
|
|
#endif
|
|
|
|
#if (_IS_NEED_CMDLINE)
|
|
static void printVersion(){
|
|
printf("HDiffPatch::hpatchz v" HDIFFPATCH_VERSION_STRING "\n");
|
|
}
|
|
|
|
static void printHelpInfo(){
|
|
printf(" -h (or -?)\n"
|
|
" output usage info.\n");
|
|
}
|
|
|
|
static void printUsage(){
|
|
printVersion();
|
|
printf("\n");
|
|
printf("patch usage: hpatchz [options] oldPath diffFile outNewPath\n"
|
|
#if (_IS_NEED_SFX)
|
|
"create SFX: hpatchz [-X-exe#selfExecuteFile] diffFile -X#outSelfExtractArchive\n"
|
|
"run SFX: selfExtractArchive [[options] oldPath -X outNewPath]\n"
|
|
"extract SFX: selfExtractArchive (same as: selfExtractArchive -f \"\" -X "
|
|
# ifdef _WIN32
|
|
"\".\\\")\n"
|
|
# else
|
|
"\"./\")\n"
|
|
# endif
|
|
#endif
|
|
" if oldPath is empty input parameter \"\"\n"
|
|
"memory options:\n"
|
|
" -s[-cacheSize] \n"
|
|
" DEFAULT -s-4m; oldPath loaded as Stream;\n"
|
|
" cacheSize can like 262144 or 256k or 512m or 2g etc....\n"
|
|
" requires (cacheSize + 4*decompress buffer size)+O(1) bytes of memory.\n"
|
|
" if diffFile is single compressed diffData(created by hdiffz -SD-stepSize), then requires\n"
|
|
" (cacheSize+ stepSize + 1*decompress buffer size)+O(1) bytes of memory;\n"
|
|
#if (_IS_NEED_BSDIFF||_IS_NEED_VCDIFF)
|
|
" if diffFile is created by"
|
|
#if (_IS_NEED_BSDIFF)
|
|
" hdiffz -BSD,bsdiff4,"
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
" hdiffz -VCD,xdelta3,open-vcdiff,"
|
|
#endif
|
|
" then requires\n"
|
|
" (cacheSize + 3*decompress buffer size)+O(1) bytes of memory;\n"
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
" if diffFile is VCDIFF: if created by hdiffz -VCD, then recommended patch by -s;\n"
|
|
" if created by xdelta3,open-vcdiff, then recommended patch by -m.\n"
|
|
#endif
|
|
" -m oldPath all loaded into Memory;\n"
|
|
" requires (oldFileSize + 4*decompress buffer size)+O(1) bytes of memory.\n"
|
|
" if diffFile is single compressed diffData(created by hdiffz -SD-stepSize), then requires\n"
|
|
" (oldFileSize+ stepSize + 1*decompress buffer size)+O(1) bytes of memory.\n"
|
|
#if (_IS_NEED_BSDIFF)
|
|
" if diffFile is created by hdiffz -BSD,bsdiff4, then requires\n"
|
|
" (oldFileSize + 3*decompress buffer size)+O(1) bytes of memory.\n"
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
" if diffFile is VCDIFF(created by hdiffz -VCD,xdelta3,open-vcdiff), then requires\n"
|
|
" (sourceWindowSize+targetWindowSize + 3*decompress buffer size)+O(1) bytes of memory.\n"
|
|
#endif
|
|
"special options:\n"
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" -C-checksumSets\n"
|
|
" set Checksum data for directory patch, DEFAULT -C-new-copy;\n"
|
|
" checksumSets support (can choose multiple):\n"
|
|
" -C-diff checksum diffFile;\n"
|
|
" -C-old checksum old reference files;\n"
|
|
" -C-new checksum new files edited from old reference files;\n"
|
|
" -C-copy checksum new files copy from old same files;\n"
|
|
" -C-no no checksum;\n"
|
|
" -C-all same as: -C-diff-old-new-copy;\n"
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
" -C-no or -C-new\n"
|
|
" if diffFile is VCDIFF, then to close or open checksum, DEFAULT -C-new.\n"
|
|
#endif
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" -n-maxOpenFileNumber\n"
|
|
" limit Number of open files at same time when stream directory patch;\n"
|
|
" maxOpenFileNumber>=8, DEFAULT -n-24, the best limit value by different\n"
|
|
" operating system.\n"
|
|
#endif
|
|
" -f Force overwrite, ignore write path already exists;\n"
|
|
" DEFAULT (no -f) not overwrite and then return error;\n"
|
|
" support oldPath outNewPath same path!(patch to tempPath and overwrite old)\n"
|
|
" if used -f and outNewPath is exist file:\n"
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" if patch output file, will overwrite;\n"
|
|
#else
|
|
" will overwrite;\n"
|
|
#endif
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" if patch output directory, will always return error;\n"
|
|
#endif
|
|
" if used -f and outNewPath is exist directory:\n"
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" if patch output file, will always return error;\n"
|
|
#else
|
|
" will always return error;\n"
|
|
#endif
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
" if patch output directory, will overwrite, but not delete\n"
|
|
" needless existing files in directory.\n"
|
|
#endif
|
|
" -v output Version info.\n"
|
|
);
|
|
printHelpInfo();
|
|
printf("\n");
|
|
}
|
|
#endif// _IS_NEED_CMDLINE
|
|
|
|
typedef enum THPatchResult {
|
|
HPATCH_SUCCESS=0,
|
|
HPATCH_OPTIONS_ERROR=1,
|
|
HPATCH_OPENREAD_ERROR,
|
|
HPATCH_OPENWRITE_ERROR,
|
|
HPATCH_FILEREAD_ERROR,
|
|
HPATCH_FILEWRITE_ERROR, // 5 //see 24
|
|
HPATCH_FILEDATA_ERROR,
|
|
HPATCH_FILECLOSE_ERROR,
|
|
HPATCH_MEM_ERROR, //see 22
|
|
HPATCH_HDIFFINFO_ERROR,
|
|
HPATCH_COMPRESSTYPE_ERROR, // 10
|
|
HPATCH_HPATCH_ERROR,
|
|
HPATCH_PATHTYPE_ERROR, //adding begin v3.0
|
|
HPATCH_TEMPPATH_ERROR,
|
|
HPATCH_DELETEPATH_ERROR,
|
|
HPATCH_RENAMEPATH_ERROR, // 15
|
|
HPATCH_SPATCH_ERROR,
|
|
HPATCH_BSPATCH_ERROR,
|
|
HPATCH_VCPATCH_ERROR,
|
|
|
|
HPATCH_DECOMPRESSER_OPEN_ERROR=20,
|
|
HPATCH_DECOMPRESSER_CLOSE_ERROR,
|
|
HPATCH_DECOMPRESSER_MEM_ERROR,
|
|
HPATCH_DECOMPRESSER_DECOMPRESS_ERROR,
|
|
HPATCH_FILEWRITE_NO_SPACE_ERROR,
|
|
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
DIRPATCH_DIRDIFFINFO_ERROR=101,
|
|
DIRPATCH_CHECKSUMTYPE_ERROR,
|
|
DIRPATCH_CHECKSUMSET_ERROR,
|
|
DIRPATCH_CHECKSUM_DIFFDATA_ERROR,
|
|
DIRPATCH_CHECKSUM_OLDDATA_ERROR, // 105
|
|
DIRPATCH_CHECKSUM_NEWDATA_ERROR,
|
|
DIRPATCH_CHECKSUM_COPYDATA_ERROR,
|
|
DIRPATCH_PATCH_ERROR,
|
|
DIRPATCH_LAOD_DIRDIFFDATA_ERROR,
|
|
DIRPATCH_OPEN_OLDPATH_ERROR, // 110
|
|
DIRPATCH_OPEN_NEWPATH_ERROR,
|
|
DIRPATCH_CLOSE_OLDPATH_ERROR,
|
|
DIRPATCH_CLOSE_NEWPATH_ERROR,
|
|
DIRPATCH_PATCHBEGIN_ERROR,
|
|
DIRPATCH_PATCHFINISH_ERROR, // 115
|
|
DIRPATCH_PATCH_FILE_ERROR,
|
|
#endif
|
|
#if (_IS_NEED_SFX)
|
|
HPATCH_CREATE_SFX_DIFFFILETYPE_ERROR=201,
|
|
HPATCH_CREATE_SFX_SFXTYPE_ERROR,
|
|
HPATCH_CREATE_SFX_EXECUTETAG_ERROR,
|
|
HPATCH_RUN_SFX_NOTSFX_ERROR,
|
|
HPATCH_RUN_SFX_DIFFOFFSERT_ERROR, // 205
|
|
#endif
|
|
} THPatchResult;
|
|
|
|
int hpatch(const char* oldFileName,const char* diffFileName,const char* outNewFileName,
|
|
hpatch_BOOL isLoadOldAll,size_t patchCacheSize,hpatch_StreamPos_t diffDataOffert,
|
|
hpatch_StreamPos_t diffDataSize,hpatch_BOOL vcpatch_isChecksum);
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
int hpatch_dir(const char* oldPath,const char* diffFileName,const char* outNewPath,
|
|
hpatch_BOOL isLoadOldAll,size_t patchCacheSize,size_t kMaxOpenFileNumber,
|
|
TDirPatchChecksumSet* checksumSet,IHPatchDirListener* hlistener,
|
|
hpatch_StreamPos_t diffDataOffert,hpatch_StreamPos_t diffDataSize);
|
|
#endif
|
|
#if (_IS_NEED_SFX)
|
|
int createSfx(const char* selfExecuteFileName,const char* diffFileName,const char* out_sfxFileName);
|
|
hpatch_BOOL getDiffDataOffertInSfx(hpatch_StreamPos_t* out_diffDataOffert,hpatch_StreamPos_t* out_diffDataSize);
|
|
#endif
|
|
|
|
#if (_IS_NEED_MAIN)
|
|
int hpatch_cmd_line(int argc, const char * argv[]);
|
|
# if (_IS_USED_WIN32_UTF8_WAPI)
|
|
int wmain(int argc,wchar_t* argv_w[]){
|
|
char* argv_utf8[hpatch_kPathMaxSize*3/sizeof(char*)];
|
|
if (!_wFileNames_to_utf8((const wchar_t**)argv_w,argc,argv_utf8,sizeof(argv_utf8)))
|
|
return HPATCH_OPTIONS_ERROR;
|
|
SetDefaultStringLocale();
|
|
return hpatch_cmd_line(argc,(const char**)argv_utf8);
|
|
}
|
|
# else
|
|
int main(int argc, const char * argv[]){
|
|
return hpatch_cmd_line(argc,argv);
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#if ((_IS_NEED_DIR_DIFF_PATCH)||(_IS_NEED_VCDIFF))
|
|
static hpatch_BOOL _toChecksumSet(const char* psets,TDirPatchChecksumSet* checksumSet){
|
|
while (hpatch_TRUE) {
|
|
const char* pend=findUntilEnd(psets,'-');
|
|
size_t len=(size_t)(pend-psets);
|
|
if (len==0) return hpatch_FALSE; //error no set
|
|
if ((len==3)&&(0==memcmp(psets,"new",len))){
|
|
checksumSet->isCheck_newRefData=hpatch_TRUE;
|
|
}else if ((len==3)&&(0==memcmp(psets,"all",len))){
|
|
checksumSet->isCheck_dirDiffData=hpatch_TRUE;
|
|
checksumSet->isCheck_oldRefData=hpatch_TRUE;
|
|
checksumSet->isCheck_newRefData=hpatch_TRUE;
|
|
checksumSet->isCheck_copyFileData=hpatch_TRUE;
|
|
}else if ((len==2)&&(0==memcmp(psets,"no",len))){
|
|
checksumSet->isCheck_dirDiffData=hpatch_FALSE;
|
|
checksumSet->isCheck_oldRefData=hpatch_FALSE;
|
|
checksumSet->isCheck_newRefData=hpatch_FALSE;
|
|
checksumSet->isCheck_copyFileData=hpatch_FALSE;
|
|
}else
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if ((len==4)&&(0==memcmp(psets,"diff",len))){
|
|
checksumSet->isCheck_dirDiffData=hpatch_TRUE;
|
|
}else if ((len==3)&&(0==memcmp(psets,"old",len))){
|
|
checksumSet->isCheck_oldRefData=hpatch_TRUE;
|
|
}else if ((len==4)&&(0==memcmp(psets,"copy",len))){
|
|
checksumSet->isCheck_copyFileData=hpatch_TRUE;
|
|
}else
|
|
#endif
|
|
{
|
|
return hpatch_FALSE;//error unknow set
|
|
}
|
|
if (*pend=='\0')
|
|
return hpatch_TRUE; //ok
|
|
else
|
|
psets=pend+1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#define _return_check(value,exitCode,errorInfo){ \
|
|
if (!(value)) { LOG_ERR(errorInfo " ERROR!\n"); return exitCode; } }
|
|
|
|
#define _options_check(value,errorInfo){ \
|
|
if (!(value)) { LOG_ERR("options " errorInfo " ERROR!\n\n"); \
|
|
printHelpInfo(); return HPATCH_OPTIONS_ERROR; } }
|
|
|
|
#define kPatchCacheSize_min (hpatch_kStreamCacheSize*8)
|
|
#define kPatchCacheSize_bestmin ((size_t)1<<21)
|
|
#define kPatchCacheSize_default ((size_t)1<<22)
|
|
|
|
#define _kNULL_VALUE (-1)
|
|
#define _kNULL_SIZE (~(size_t)0)
|
|
|
|
#if (_IS_NEED_CMDLINE)
|
|
#define _isSwapToPatchTag(tag) (0==strcmp("--patch",tag))
|
|
|
|
int isSwapToPatchMode(int argc,const char* argv[]){
|
|
int i;
|
|
for (i=1;i<argc;++i){
|
|
if (_isSwapToPatchTag(argv[i]))
|
|
return hpatch_TRUE;
|
|
}
|
|
#if (_IS_NEED_SFX)
|
|
if (getDiffDataOffertInSfx(0,0))
|
|
return hpatch_TRUE;
|
|
#endif
|
|
return hpatch_FALSE;
|
|
}
|
|
|
|
int hpatch_cmd_line(int argc, const char * argv[]){
|
|
hpatch_BOOL isLoadOldAll=_kNULL_VALUE;
|
|
hpatch_BOOL isForceOverwrite=_kNULL_VALUE;
|
|
hpatch_BOOL isOutputHelp=_kNULL_VALUE;
|
|
hpatch_BOOL isOutputVersion=_kNULL_VALUE;
|
|
hpatch_BOOL isOldPathInputEmpty=_kNULL_VALUE;
|
|
#if (_IS_NEED_SFX)
|
|
hpatch_BOOL isRunSFX=_kNULL_VALUE;
|
|
const char* out_SFX=0;
|
|
const char* selfExecuteFile=0;
|
|
#endif
|
|
size_t patchCacheSize=0;
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
size_t kMaxOpenFileNumber=_kNULL_SIZE; //only used in stream dir patch
|
|
#endif
|
|
#if ((_IS_NEED_DIR_DIFF_PATCH)||(_IS_NEED_VCDIFF))
|
|
TDirPatchChecksumSet checksumSet={0,hpatch_FALSE,hpatch_TRUE,hpatch_TRUE,hpatch_FALSE}; //DEFAULT
|
|
#endif
|
|
hpatch_BOOL vcpatch_isChecksum=hpatch_TRUE;
|
|
#define kMax_arg_values_size 3
|
|
const char* arg_values[kMax_arg_values_size]={0};
|
|
int arg_values_size=0;
|
|
int i;
|
|
if (argc<=1){
|
|
printUsage();
|
|
return HPATCH_OPTIONS_ERROR;
|
|
}
|
|
for (i=1; i<argc; ++i) {
|
|
const char* op=argv[i];
|
|
_options_check(op!=0,"?");
|
|
if (_isSwapToPatchTag(op))
|
|
continue;
|
|
if (op[0]!='-'){
|
|
hpatch_BOOL isEmpty=(strlen(op)==0);
|
|
_options_check(arg_values_size<kMax_arg_values_size,"input count");
|
|
if (isEmpty){
|
|
if (isOldPathInputEmpty==_kNULL_VALUE)
|
|
isOldPathInputEmpty=hpatch_TRUE;
|
|
else
|
|
_options_check(!isEmpty,"?"); //error return
|
|
}else{
|
|
if (isOldPathInputEmpty==_kNULL_VALUE)
|
|
isOldPathInputEmpty=hpatch_FALSE;
|
|
}
|
|
arg_values[arg_values_size]=op; //path: file or directory
|
|
++arg_values_size;
|
|
continue;
|
|
}
|
|
_options_check((op!=0)&&(op[0]=='-'),"?");
|
|
switch (op[1]) {
|
|
case 'm':{
|
|
_options_check((isLoadOldAll==_kNULL_VALUE)&&(op[2]=='\0'),"-m");
|
|
isLoadOldAll=hpatch_TRUE;
|
|
} break;
|
|
case 's':{
|
|
_options_check((isLoadOldAll==_kNULL_VALUE)&&((op[2]=='-')||(op[2]=='\0')),"-s");
|
|
isLoadOldAll=hpatch_FALSE; //stream
|
|
if (op[2]=='-'){
|
|
const char* pnum=op+3;
|
|
_options_check(kmg_to_size(pnum,strlen(pnum),&patchCacheSize),"-s-?");
|
|
}else{
|
|
patchCacheSize=kPatchCacheSize_default;
|
|
}
|
|
} break;
|
|
#if (_IS_NEED_SFX)
|
|
case 'X':{
|
|
if (op[2]=='#'){
|
|
const char* pnum=op+3;
|
|
_options_check(out_SFX==0,"-X#?");
|
|
out_SFX=pnum;
|
|
_options_check(strlen(out_SFX)>0,"-X#?");
|
|
}else if (op[2]=='-'){
|
|
_options_check(selfExecuteFile==0,"-X-?");
|
|
if ((op[3]=='e')&&(op[4]=='x')&&(op[5]=='e')&&(op[6]=='#')){
|
|
selfExecuteFile=op+7;
|
|
_options_check(strlen(selfExecuteFile)>0,"-X-exe#?");
|
|
}else{
|
|
_options_check(hpatch_FALSE,"-X-?");
|
|
}
|
|
}else{
|
|
_options_check((isRunSFX==_kNULL_VALUE)&&(op[2]=='\0'),"-X");
|
|
isRunSFX=hpatch_TRUE;
|
|
}
|
|
} break;
|
|
#endif
|
|
case 'f':{
|
|
_options_check((isForceOverwrite==_kNULL_VALUE)&&(op[2]=='\0'),"-f");
|
|
isForceOverwrite=hpatch_TRUE;
|
|
} break;
|
|
#if ((_IS_NEED_DIR_DIFF_PATCH)||(_IS_NEED_VCDIFF))
|
|
case 'C':{
|
|
const char* psets=op+3;
|
|
_options_check((op[2]=='-'),"-C-?");
|
|
memset(&checksumSet,0,sizeof(checksumSet));//all set false
|
|
_options_check(_toChecksumSet(psets,&checksumSet),"-C-?");
|
|
} break;
|
|
#endif
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
case 'n':{
|
|
const char* pnum=op+3;
|
|
_options_check((kMaxOpenFileNumber==_kNULL_SIZE)&&(op[2]=='-'),"-n");
|
|
_options_check(kmg_to_size(pnum,strlen(pnum),&kMaxOpenFileNumber),"-n-?");
|
|
_options_check((kMaxOpenFileNumber!=_kNULL_SIZE),"-n-?");
|
|
} break;
|
|
#endif
|
|
case '?':
|
|
case 'h':{
|
|
_options_check((isOutputHelp==_kNULL_VALUE)&&(op[2]=='\0'),"-h");
|
|
isOutputHelp=hpatch_TRUE;
|
|
} break;
|
|
case 'v':{
|
|
_options_check((isOutputVersion==_kNULL_VALUE)&&(op[2]=='\0'),"-v");
|
|
isOutputVersion=hpatch_TRUE;
|
|
} break;
|
|
default: {
|
|
_options_check(hpatch_FALSE,"-?");
|
|
} break;
|
|
}//switch
|
|
}
|
|
|
|
if (isOutputHelp==_kNULL_VALUE)
|
|
isOutputHelp=hpatch_FALSE;
|
|
if (isOutputVersion==_kNULL_VALUE)
|
|
isOutputVersion=hpatch_FALSE;
|
|
if (isForceOverwrite==_kNULL_VALUE)
|
|
isForceOverwrite=hpatch_FALSE;
|
|
#if (_IS_NEED_SFX)
|
|
if (isRunSFX==_kNULL_VALUE)
|
|
isRunSFX=hpatch_FALSE;
|
|
if (arg_values_size==0){
|
|
hpatch_StreamPos_t _diffDataOffert=0;
|
|
hpatch_StreamPos_t _diffDataSize=0;
|
|
if (getDiffDataOffertInSfx(&_diffDataOffert,&_diffDataSize)){//autoExtractSFX
|
|
isForceOverwrite=hpatch_TRUE;
|
|
isRunSFX=hpatch_TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
if (isOutputHelp||isOutputVersion){
|
|
if (isOutputHelp)
|
|
printUsage();//with version
|
|
else
|
|
printVersion();
|
|
#if (_IS_NEED_SFX)
|
|
if ((arg_values_size==0)&&(!isRunSFX)&&(out_SFX==0)&&(selfExecuteFile==0))
|
|
#else
|
|
if (arg_values_size==0)
|
|
#endif
|
|
return 0; //ok
|
|
}
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (kMaxOpenFileNumber==_kNULL_SIZE)
|
|
kMaxOpenFileNumber=kMaxOpenFileNumber_default_patch;
|
|
if (kMaxOpenFileNumber<kMaxOpenFileNumber_default_min)
|
|
kMaxOpenFileNumber=kMaxOpenFileNumber_default_min;
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
vcpatch_isChecksum=checksumSet.isCheck_newRefData;
|
|
#endif
|
|
|
|
if (isLoadOldAll==_kNULL_VALUE){
|
|
isLoadOldAll=hpatch_FALSE;
|
|
patchCacheSize=kPatchCacheSize_default;
|
|
}
|
|
if (isOldPathInputEmpty==_kNULL_VALUE)
|
|
isOldPathInputEmpty=hpatch_FALSE;
|
|
|
|
#if (_IS_NEED_SFX)
|
|
if ((out_SFX!=0)||(selfExecuteFile!=0)){ //create SFX
|
|
_options_check(out_SFX!=0,"-X#?");
|
|
_options_check(!isRunSFX, "-X");
|
|
_options_check(arg_values_size==1,"-X# input count");
|
|
{
|
|
const char* diffFileName =arg_values[0];
|
|
if (selfExecuteFile==0) selfExecuteFile=argv[0];
|
|
if (!isForceOverwrite){
|
|
hpatch_TPathType outPathType;
|
|
_return_check(hpatch_getPathStat(out_SFX,&outPathType,0),
|
|
HPATCH_PATHTYPE_ERROR,"get outSelfExtractArchive type");
|
|
_return_check(outPathType==kPathType_notExist,
|
|
HPATCH_PATHTYPE_ERROR,"outSelfExtractArchive already exists, overwrite");
|
|
}
|
|
return createSfx(selfExecuteFile,diffFileName,out_SFX);
|
|
}
|
|
}else if (isRunSFX){//patch run as SFX mode
|
|
_options_check((arg_values_size==2)||(arg_values_size==0),"-X input count");
|
|
}else
|
|
#endif
|
|
{//patch default mode
|
|
_options_check(arg_values_size==3,"input count");
|
|
}
|
|
{//patch
|
|
const char* oldPath =0;
|
|
const char* diffFileName=0;
|
|
const char* outNewPath =0;
|
|
#if (_IS_NEED_SFX)
|
|
# ifdef _WIN32
|
|
const char* kSFX_curDefaultPath=".\\";
|
|
# else
|
|
const char* kSFX_curDefaultPath="./";
|
|
# endif
|
|
const char* kSFX_emptyPath="";
|
|
#endif
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
TDirDiffInfo dirDiffInfo;
|
|
hpatch_BOOL isOutDir;
|
|
#endif
|
|
hpatch_BOOL isSamePath;
|
|
hpatch_StreamPos_t diffDataOffert=0;
|
|
hpatch_StreamPos_t diffDataSize=0;
|
|
#if (_IS_NEED_SFX)
|
|
if (isRunSFX){
|
|
printf("run as SFX mode!\n");
|
|
_return_check(getDiffDataOffertInSfx(&diffDataOffert,&diffDataSize),
|
|
HPATCH_RUN_SFX_NOTSFX_ERROR,"not found diff data in selfExecuteFile");
|
|
diffFileName=argv[0];//selfExecuteFileName
|
|
if (arg_values_size==0){//autoExtractSFX
|
|
oldPath =kSFX_emptyPath;
|
|
outNewPath =kSFX_curDefaultPath;
|
|
}else{
|
|
oldPath =arg_values[0];
|
|
outNewPath =arg_values[1];
|
|
}
|
|
//continue
|
|
}else
|
|
#endif
|
|
{
|
|
oldPath =arg_values[0];
|
|
diffFileName=arg_values[1];
|
|
outNewPath =arg_values[2];
|
|
}
|
|
|
|
isSamePath=hpatch_getIsSamePath(oldPath,outNewPath);
|
|
_return_check(!hpatch_getIsSamePath(oldPath,diffFileName),
|
|
HPATCH_PATHTYPE_ERROR,"oldPath diffFile same path");
|
|
_return_check(!hpatch_getIsSamePath(outNewPath,diffFileName),
|
|
HPATCH_PATHTYPE_ERROR,"outNewPath diffFile same path");
|
|
if (!isForceOverwrite){
|
|
hpatch_TPathType outNewPathType;
|
|
_return_check(hpatch_getPathStat(outNewPath,&outNewPathType,0),
|
|
HPATCH_PATHTYPE_ERROR,"get outNewPath type");
|
|
_return_check(outNewPathType==kPathType_notExist,
|
|
HPATCH_PATHTYPE_ERROR,"outNewPath already exists, overwrite");
|
|
}
|
|
if (isSamePath)
|
|
_return_check(isForceOverwrite,HPATCH_PATHTYPE_ERROR,"oldPath outNewPath same path, overwrite");
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
_return_check(getDirDiffInfoByFile(diffFileName,&dirDiffInfo,diffDataOffert,diffDataSize),
|
|
HPATCH_OPENREAD_ERROR,"input diffFile open read");
|
|
isOutDir=(dirDiffInfo.isDirDiff)&&(dirDiffInfo.newPathIsDir);
|
|
#endif
|
|
if (!isSamePath){ // out new file or new dir
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (dirDiffInfo.isDirDiff){
|
|
return hpatch_dir(oldPath,diffFileName,outNewPath,isLoadOldAll,patchCacheSize,kMaxOpenFileNumber,
|
|
&checksumSet,&defaultPatchDirlistener,diffDataOffert,diffDataSize);
|
|
}else
|
|
#endif
|
|
{
|
|
return hpatch(oldPath,diffFileName,outNewPath,isLoadOldAll,
|
|
patchCacheSize,diffDataOffert,diffDataSize,vcpatch_isChecksum);
|
|
}
|
|
}else
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (!isOutDir)
|
|
#endif
|
|
{ // isSamePath==true and out to file
|
|
int result;
|
|
char newTempName[hpatch_kPathMaxSize];
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (dirDiffInfo.isDirDiff)
|
|
_return_check(!dirDiffInfo.oldPathIsDir,
|
|
HPATCH_PATHTYPE_ERROR,"can not use file overwrite oldDirectory");
|
|
#endif
|
|
// 1. patch to newTempName
|
|
// 2. if patch ok then { delelte oldPath; rename newTempName to oldPath; }
|
|
// if patch error then { delelte newTempName; }
|
|
_return_check(hpatch_getTempPathName(outNewPath,newTempName,newTempName+hpatch_kPathMaxSize),
|
|
HPATCH_TEMPPATH_ERROR,"getTempPathName(outNewPath)");
|
|
printf("NOTE: outNewPath temp file will be rename to oldPath name after patch!\n");
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (dirDiffInfo.isDirDiff){
|
|
result=hpatch_dir(oldPath,diffFileName,newTempName,isLoadOldAll,patchCacheSize,
|
|
kMaxOpenFileNumber,&checksumSet,&defaultPatchDirlistener,
|
|
diffDataOffert,diffDataSize);
|
|
}else
|
|
#endif
|
|
{
|
|
result=hpatch(oldPath,diffFileName,newTempName,isLoadOldAll,
|
|
patchCacheSize,diffDataOffert,diffDataSize,vcpatch_isChecksum);
|
|
}
|
|
if (result==HPATCH_SUCCESS){
|
|
_return_check(hpatch_removeFile(oldPath),
|
|
HPATCH_DELETEPATH_ERROR,"removeFile(oldPath)");
|
|
_return_check(hpatch_renamePath(newTempName,oldPath),
|
|
HPATCH_RENAMEPATH_ERROR,"renamePath(temp,oldPath)");
|
|
printf("outNewPath temp file renamed to oldPath name!\n");
|
|
}else{//patch error
|
|
if (!hpatch_removeFile(newTempName)){
|
|
printf("WARNING: can't remove temp file \"");
|
|
hpatch_printPath_utf8(newTempName); printf("\"\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
else{ // isDirDiff==true isSamePath==true and out to dir
|
|
int result;
|
|
char newTempDir[hpatch_kPathMaxSize];
|
|
assert(dirDiffInfo.isDirDiff);
|
|
_return_check(dirDiffInfo.oldPathIsDir,
|
|
HPATCH_PATHTYPE_ERROR,"can not use directory overwrite oldFile");
|
|
_return_check(hpatch_getTempPathName(outNewPath,newTempDir,newTempDir+hpatch_kPathMaxSize),
|
|
HPATCH_TEMPPATH_ERROR,"getTempPathName(outNewPath)");
|
|
printf("NOTE: all in outNewPath temp directory will be move to oldDirectory after patch!\n");
|
|
result=hpatch_dir(oldPath,diffFileName,newTempDir,isLoadOldAll,patchCacheSize,kMaxOpenFileNumber,
|
|
&checksumSet,&tempDirPatchListener,diffDataOffert,diffDataSize);
|
|
if (result==HPATCH_SUCCESS){
|
|
printf("all in outNewPath temp directory moved to oldDirectory!\n");
|
|
}else if(!hpatch_isPathNotExist(newTempDir)){
|
|
printf("WARNING: not remove temp directory \"");
|
|
hpatch_printPath_utf8(newTempDir); printf("\"\n");
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif //_IS_NEED_CMDLINE
|
|
|
|
#define check_on_error(errorType) { \
|
|
if (result==HPATCH_SUCCESS) result=errorType; if (!_isInClear){ goto clear; } }
|
|
#define check(value,errorType,errorInfo) { \
|
|
if (!(value)){ LOG_ERR(errorInfo " ERROR!\n"); check_on_error(errorType); } }
|
|
|
|
#if (_HPATCH_IS_USED_errno)
|
|
# define check_ferr(fileError,errorType,errorInfo){ \
|
|
if (fileError){ \
|
|
result=HPATCH_SUCCESS; \
|
|
if (ENOSPC==(fileError)){ \
|
|
check(hpatch_FALSE,HPATCH_FILEWRITE_NO_SPACE_ERROR,errorInfo); \
|
|
}else{ \
|
|
check(hpatch_FALSE,errorType,errorInfo); } } }
|
|
#else
|
|
# define check_ferr(fileError,errorType,errorInfo) { \
|
|
if (fileError) { result=HPATCH_SUCCESS; check(hpatch_FALSE,errorType,errorInfo); } }
|
|
#endif
|
|
|
|
#define check_dec(decError) { \
|
|
switch (decError){ \
|
|
case hpatch_dec_ok: break; \
|
|
case hpatch_dec_mem_error: check(0,HPATCH_DECOMPRESSER_MEM_ERROR,"decompressPlugin alloc memory"); \
|
|
case hpatch_dec_open_error: check(0,HPATCH_DECOMPRESSER_OPEN_ERROR,"decompressPlugin open"); \
|
|
case hpatch_dec_close_error: check(0,HPATCH_DECOMPRESSER_CLOSE_ERROR,"decompressPlugin close"); \
|
|
default: { assert(decError==hpatch_dec_error); \
|
|
check(0,HPATCH_DECOMPRESSER_DECOMPRESS_ERROR,"decompressPlugin decompress"); } break; \
|
|
} }
|
|
|
|
#define _try_rt_dec(dec) { if (dec.is_can_open(compressType)) return &dec; }
|
|
|
|
static const hpatch_TDecompress* __find_decompressPlugin(const char* compressType){
|
|
#ifdef _CompressPlugin_zlib
|
|
_try_rt_dec(zlibDecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_bz2
|
|
_try_rt_dec(bz2DecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_lzma
|
|
_try_rt_dec(lzmaDecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_lzma2
|
|
_try_rt_dec(lzma2DecompressPlugin);
|
|
#endif
|
|
#if (defined(_CompressPlugin_lz4) || (defined(_CompressPlugin_lz4hc)))
|
|
_try_rt_dec(lz4DecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_zstd
|
|
_try_rt_dec(zstdDecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_brotli
|
|
_try_rt_dec(brotliDecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_lzham
|
|
_try_rt_dec(lzhamDecompressPlugin);
|
|
#endif
|
|
#ifdef _CompressPlugin_tuz
|
|
_try_rt_dec(tuzDecompressPlugin);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if (_IS_NEED_VCDIFF)
|
|
static hpatch_BOOL getVcDiffDecompressPlugin(hpatch_TDecompress* out_decompressPlugin,
|
|
const hpatch_VcDiffInfo* vcdInfo,char* out_compressType){
|
|
const hpatch_TDecompress* decompressPlugin=0;
|
|
|
|
out_compressType[0]='\0';
|
|
memset(out_decompressPlugin,0,sizeof(*out_decompressPlugin));
|
|
switch (vcdInfo->compressorID){
|
|
case 0: return hpatch_TRUE;
|
|
#ifdef _CompressPlugin_7zXZ
|
|
case kVcDiff_compressorID_7zXZ:{
|
|
static const char* _7zXZCompressType="7zXZ";
|
|
_init_CompressPlugin_7zXZ();
|
|
if (vcdInfo->isHDiffzAppHead_a)
|
|
decompressPlugin=&_7zXZDecompressPlugin_a;
|
|
else
|
|
decompressPlugin=&_7zXZDecompressPlugin;
|
|
memcpy(out_compressType,_7zXZCompressType,strlen(_7zXZCompressType)+1);
|
|
} break;
|
|
#endif
|
|
default: return hpatch_FALSE; //now unsupport
|
|
}
|
|
if (strlen(out_compressType)>0)
|
|
printf("hpatchz run vcpatch with decompress plugin: \"%s\"\n",out_compressType);
|
|
if (decompressPlugin){
|
|
*out_decompressPlugin=*decompressPlugin;
|
|
out_decompressPlugin->decError=hpatch_dec_ok;
|
|
}
|
|
return hpatch_TRUE;
|
|
}
|
|
#endif
|
|
|
|
static hpatch_BOOL getDecompressPlugin(const hpatch_compressedDiffInfo* diffInfo,
|
|
hpatch_TDecompress* out_decompressPlugin){
|
|
const hpatch_TDecompress* decompressPlugin=0;
|
|
memset(out_decompressPlugin,0,sizeof(*out_decompressPlugin));
|
|
if (diffInfo->compressedCount>0){
|
|
decompressPlugin=__find_decompressPlugin(diffInfo->compressType);
|
|
if ((0==decompressPlugin)||(decompressPlugin->open==0)) return hpatch_FALSE; //error
|
|
}
|
|
if (strlen(diffInfo->compressType)>0)
|
|
printf("hpatchz run with decompress plugin: \"%s\" (need decompress %d)\n",
|
|
diffInfo->compressType,diffInfo->compressedCount);
|
|
if (decompressPlugin){
|
|
*out_decompressPlugin=*decompressPlugin;
|
|
out_decompressPlugin->decError=hpatch_dec_ok;
|
|
}
|
|
return hpatch_TRUE;
|
|
}
|
|
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
static hpatch_inline
|
|
hpatch_BOOL _trySetChecksum(hpatch_TChecksum** out_checksumPlugin,const char* checksumType,
|
|
hpatch_TChecksum* testChecksumPlugin){
|
|
assert(0==*out_checksumPlugin);
|
|
if (0!=strcmp(checksumType,testChecksumPlugin->checksumType())) return hpatch_FALSE;
|
|
*out_checksumPlugin=testChecksumPlugin;
|
|
return hpatch_TRUE;
|
|
}
|
|
#define __setChecksum(_checksumPlugin) \
|
|
if (_trySetChecksum(out_checksumPlugin,checksumType,_checksumPlugin)) return hpatch_TRUE;
|
|
|
|
static hpatch_BOOL findChecksum(hpatch_TChecksum** out_checksumPlugin,const char* checksumType){
|
|
*out_checksumPlugin=0;
|
|
if (strlen(checksumType)==0) return hpatch_TRUE;
|
|
#ifdef _ChecksumPlugin_crc32
|
|
__setChecksum(&crc32ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_adler32
|
|
__setChecksum(&adler32ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_adler64
|
|
__setChecksum(&adler64ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_fadler32
|
|
__setChecksum(&fadler32ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_fadler64
|
|
__setChecksum(&fadler64ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_fadler128
|
|
__setChecksum(&fadler128ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_md5
|
|
__setChecksum(&md5ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_blake3
|
|
__setChecksum(&blake3ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_xxh3
|
|
__setChecksum(&xxh3ChecksumPlugin);
|
|
#endif
|
|
#ifdef _ChecksumPlugin_xxh128
|
|
__setChecksum(&xxh128ChecksumPlugin);
|
|
#endif
|
|
return hpatch_FALSE;
|
|
}
|
|
#endif
|
|
|
|
#define _free_mem(p) { if (p) { free(p); p=0; } }
|
|
|
|
static TByte* getPatchMemCache(hpatch_BOOL isLoadOldAll,size_t patchCacheSize,size_t mustAppendMemSize,
|
|
hpatch_StreamPos_t oldDataSize,size_t* out_memCacheSize){
|
|
TByte* temp_cache=0;
|
|
size_t temp_cache_size;
|
|
{
|
|
hpatch_StreamPos_t limitCacheSize;
|
|
const hpatch_StreamPos_t bestMaxCacheSize=oldDataSize+kPatchCacheSize_bestmin;
|
|
if (isLoadOldAll){
|
|
limitCacheSize=bestMaxCacheSize;
|
|
}else{
|
|
limitCacheSize=(patchCacheSize<kPatchCacheSize_min)?kPatchCacheSize_min:patchCacheSize;
|
|
limitCacheSize=(limitCacheSize<bestMaxCacheSize)?limitCacheSize:bestMaxCacheSize;
|
|
}
|
|
if (limitCacheSize>(size_t)(_kNULL_SIZE-mustAppendMemSize))//too large
|
|
limitCacheSize=(size_t)(_kNULL_SIZE-mustAppendMemSize);
|
|
temp_cache_size=(size_t)limitCacheSize;
|
|
}
|
|
while (temp_cache_size>=kPatchCacheSize_min){
|
|
temp_cache=(TByte*)malloc(mustAppendMemSize+temp_cache_size);
|
|
if (temp_cache) break;
|
|
temp_cache_size>>=1;
|
|
}
|
|
*out_memCacheSize=(temp_cache)?(mustAppendMemSize+temp_cache_size):0;
|
|
return temp_cache;
|
|
}
|
|
|
|
int hpatch(const char* oldFileName,const char* diffFileName,const char* outNewFileName,
|
|
hpatch_BOOL isLoadOldAll,size_t patchCacheSize,hpatch_StreamPos_t diffDataOffert,
|
|
hpatch_StreamPos_t diffDataSize,hpatch_BOOL vcpatch_isChecksum){
|
|
int result=HPATCH_SUCCESS;
|
|
int _isInClear=hpatch_FALSE;
|
|
double time0=clock_s();
|
|
#if (_IS_NEED_SINGLE_STREAM_DIFF)
|
|
hpatch_BOOL isSingleStreamDiff=hpatch_FALSE;
|
|
hpatch_singleCompressedDiffInfo sdiffInfo;
|
|
#endif
|
|
#if (_IS_NEED_BSDIFF)
|
|
hpatch_BOOL isBsDiff=hpatch_FALSE;
|
|
hpatch_BsDiffInfo bsdiffInfo;
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
hpatch_BOOL isVcDiff=hpatch_FALSE;
|
|
hpatch_VcDiffInfo vcdiffInfo;
|
|
#endif
|
|
hpatch_TDecompress _decompressPlugin={0};
|
|
hpatch_TDecompress* decompressPlugin=&_decompressPlugin;
|
|
hpatch_TFileStreamOutput newData;
|
|
hpatch_TFileStreamInput diffData;
|
|
hpatch_TFileStreamInput oldData;
|
|
hpatch_TStreamInput* poldData=&oldData.base;
|
|
TByte* temp_cache=0;
|
|
size_t temp_cache_size;
|
|
hpatch_StreamPos_t savedNewSize=0;
|
|
int patch_result=HPATCH_SUCCESS;
|
|
hpatch_TFileStreamInput_init(&oldData);
|
|
hpatch_TFileStreamInput_init(&diffData);
|
|
hpatch_TFileStreamOutput_init(&newData);
|
|
{//open
|
|
printf( "old : \""); if (oldFileName) hpatch_printPath_utf8(oldFileName);
|
|
printf("\"\ndiff: \""); hpatch_printPath_utf8(diffFileName);
|
|
printf("\"\nout : \""); hpatch_printPath_utf8(outNewFileName);
|
|
printf("\"\n");
|
|
if ((0==oldFileName)||(0==strlen(oldFileName))){
|
|
mem_as_hStreamInput(&oldData.base,0,0);
|
|
}else{
|
|
check(hpatch_TFileStreamInput_open(&oldData,oldFileName),
|
|
HPATCH_OPENREAD_ERROR,"open oldFile for read");
|
|
}
|
|
check(hpatch_TFileStreamInput_open(&diffData,diffFileName),
|
|
HPATCH_OPENREAD_ERROR,"open diffFile for read");
|
|
#if (_IS_NEED_SFX)
|
|
if (diffDataOffert>0){ //run sfx
|
|
check(hpatch_TFileStreamInput_setOffset(&diffData,diffDataOffert),
|
|
HPATCH_RUN_SFX_DIFFOFFSERT_ERROR,"readed sfx diffFile offset");
|
|
check(diffData.base.streamSize>=diffDataSize,
|
|
HPATCH_RUN_SFX_DIFFOFFSERT_ERROR,"readed sfx diffFile size");
|
|
diffData.base.streamSize=diffDataSize;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
{
|
|
hpatch_compressedDiffInfo diffInfo;
|
|
if (!getCompressedDiffInfo(&diffInfo,&diffData.base)){
|
|
check(!diffData.fileError,HPATCH_FILEREAD_ERROR,"read diffFile");
|
|
#if (_IS_NEED_SINGLE_STREAM_DIFF)
|
|
if (getSingleCompressedDiffInfo(&sdiffInfo,&diffData.base,0)){
|
|
memcpy(diffInfo.compressType,sdiffInfo.compressType,strlen(sdiffInfo.compressType)+1);
|
|
diffInfo.compressedCount=(sdiffInfo.compressType[0]!='\0')?1:0;
|
|
diffInfo.newDataSize=sdiffInfo.newDataSize;
|
|
diffInfo.oldDataSize=sdiffInfo.oldDataSize;
|
|
check(sdiffInfo.stepMemSize==(size_t)sdiffInfo.stepMemSize,HPATCH_MEM_ERROR,"stepMemSize too large");
|
|
if (patchCacheSize<hpatch_kStreamCacheSize*3)
|
|
patchCacheSize=hpatch_kStreamCacheSize*3;
|
|
isSingleStreamDiff=hpatch_TRUE;
|
|
printf("patch single compressed diffData!\n");
|
|
}else
|
|
#endif
|
|
#if (_IS_NEED_BSDIFF)
|
|
if (getBsDiffInfo(&bsdiffInfo,&diffData.base)){
|
|
const char* bsCompressType="bz2";
|
|
*decompressPlugin=_bz2DecompressPlugin_unsz;
|
|
decompressPlugin->decError=hpatch_dec_ok;
|
|
memcpy(diffInfo.compressType,bsCompressType,strlen(bsCompressType)+1);
|
|
diffInfo.compressedCount=3;
|
|
diffInfo.newDataSize=bsdiffInfo.newDataSize;
|
|
diffInfo.oldDataSize=poldData->streamSize; //not saved oldDataSize
|
|
isBsDiff=hpatch_TRUE;
|
|
printf("patch bsdiff4 diffData!\n");
|
|
}else
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
if (getVcDiffInfo(&vcdiffInfo,&diffData.base,hpatch_TRUE)){
|
|
if (getVcDiffDecompressPlugin(decompressPlugin,&vcdiffInfo,diffInfo.compressType)){
|
|
if (decompressPlugin->open) diffInfo.compressedCount=3;
|
|
else diffInfo.compressedCount=0;
|
|
}else{
|
|
LOG_ERR("can not decompress VCDIFF compressID \"%d\" data ERROR!\n",vcdiffInfo.compressorID);
|
|
check_on_error(HPATCH_COMPRESSTYPE_ERROR);
|
|
}
|
|
diffInfo.newDataSize=vcdiffInfo.sumTargetWindowsSize;
|
|
diffInfo.oldDataSize=poldData->streamSize; //not saved oldDataSize
|
|
isVcDiff=hpatch_TRUE;
|
|
printf("patch VCDIFF diffData!\n");
|
|
}else
|
|
#endif
|
|
check(hpatch_FALSE,HPATCH_HDIFFINFO_ERROR,"is hdiff file? get diffInfo");
|
|
}
|
|
if (poldData->streamSize!=diffInfo.oldDataSize){
|
|
LOG_ERR("oldFile dataSize %" PRIu64 " != diffFile saved oldDataSize %" PRIu64 " ERROR!\n",
|
|
poldData->streamSize,diffInfo.oldDataSize);
|
|
check_on_error(HPATCH_FILEDATA_ERROR);
|
|
}
|
|
if ((decompressPlugin->open==0)&&(!getDecompressPlugin(&diffInfo,decompressPlugin))){
|
|
LOG_ERR("can not decompress \"%s\" data ERROR!\n",diffInfo.compressType);
|
|
check_on_error(HPATCH_COMPRESSTYPE_ERROR);
|
|
}
|
|
if (decompressPlugin->open==0) decompressPlugin=0;
|
|
savedNewSize=diffInfo.newDataSize;
|
|
}
|
|
check(hpatch_TFileStreamOutput_open(&newData, outNewFileName,savedNewSize),
|
|
HPATCH_OPENWRITE_ERROR,"open out newFile for write");
|
|
#if (_IS_NEED_VCDIFF)
|
|
if (isVcDiff)
|
|
hpatch_TFileStreamOutput_setRandomOut(&newData,hpatch_TRUE);
|
|
#endif
|
|
printf("oldDataSize : %" PRIu64 "\ndiffDataSize: %" PRIu64 "\nnewDataSize : %" PRIu64 "\n",
|
|
poldData->streamSize,diffData.base.streamSize,newData.base.streamSize);
|
|
{
|
|
hpatch_StreamPos_t maxWindowSize=poldData->streamSize;
|
|
hpatch_size_t mustAppendMemSize=0;
|
|
#if (_IS_NEED_VCDIFF)
|
|
if (isVcDiff){
|
|
hpatch_StreamPos_t maxSrcTargetSize=vcdiffInfo.maxSrcWindowsSize+vcdiffInfo.maxTargetWindowsSize;
|
|
maxWindowSize=((!vcdiffInfo.isHDiffzAppHead_a)&&(maxSrcTargetSize<=maxWindowSize+64*(1<<20)))?
|
|
maxSrcTargetSize:vcdiffInfo.maxSrcWindowsSize;
|
|
}
|
|
#endif
|
|
#if (_IS_NEED_SINGLE_STREAM_DIFF)
|
|
if (isSingleStreamDiff)
|
|
mustAppendMemSize=(size_t)sdiffInfo.stepMemSize;
|
|
#endif
|
|
temp_cache=getPatchMemCache(isLoadOldAll,patchCacheSize,mustAppendMemSize,maxWindowSize, &temp_cache_size);
|
|
}
|
|
check(temp_cache,HPATCH_MEM_ERROR,"alloc cache memory");
|
|
#if (_IS_NEED_SINGLE_STREAM_DIFF)
|
|
if (isSingleStreamDiff){
|
|
check(temp_cache_size>=sdiffInfo.stepMemSize+hpatch_kStreamCacheSize*3,HPATCH_MEM_ERROR,"alloc cache memory");
|
|
if (!patch_single_compressed_diff(&newData.base,poldData,&diffData.base,sdiffInfo.diffDataPos,
|
|
sdiffInfo.uncompressedSize,sdiffInfo.compressedSize,decompressPlugin,
|
|
sdiffInfo.coverCount,(size_t)sdiffInfo.stepMemSize,
|
|
temp_cache,temp_cache+temp_cache_size,0))
|
|
patch_result=HPATCH_SPATCH_ERROR;
|
|
}else
|
|
#endif
|
|
#if (_IS_NEED_BSDIFF)
|
|
if (isBsDiff){
|
|
if (!bspatch_with_cache(&newData.base,poldData,&diffData.base,decompressPlugin,
|
|
temp_cache,temp_cache+temp_cache_size))
|
|
patch_result=HPATCH_BSPATCH_ERROR;
|
|
}else
|
|
#endif
|
|
#if (_IS_NEED_VCDIFF)
|
|
if (isVcDiff){
|
|
if (!vcpatch_with_cache(&newData.base,poldData,&diffData.base,decompressPlugin,
|
|
vcpatch_isChecksum,temp_cache,temp_cache+temp_cache_size))
|
|
patch_result=HPATCH_VCPATCH_ERROR;
|
|
}else
|
|
#endif
|
|
{
|
|
if (!patch_decompress_with_cache(&newData.base,poldData,&diffData.base,decompressPlugin,
|
|
temp_cache,temp_cache+temp_cache_size))
|
|
patch_result=HPATCH_HPATCH_ERROR;
|
|
}
|
|
if (patch_result!=HPATCH_SUCCESS){
|
|
check(!oldData.fileError,HPATCH_FILEREAD_ERROR,"oldFile read");
|
|
check(!diffData.fileError,HPATCH_FILEREAD_ERROR,"diffFile read");
|
|
check_ferr(newData.fileError,HPATCH_FILEWRITE_ERROR,"out newFile write");
|
|
check_dec(_decompressPlugin.decError);
|
|
check(hpatch_FALSE,patch_result,"patch run");
|
|
}
|
|
if (newData.out_length!=newData.base.streamSize){
|
|
LOG_ERR("out newFile dataSize %" PRIu64 " != diffFile saved newDataSize %" PRIu64 " ERROR!\n",
|
|
newData.out_length,newData.base.streamSize);
|
|
check_on_error(HPATCH_FILEDATA_ERROR);
|
|
}
|
|
printf(" patch ok!\n");
|
|
|
|
clear:
|
|
_isInClear=hpatch_TRUE;
|
|
check(hpatch_TFileStreamOutput_close(&newData),HPATCH_FILECLOSE_ERROR,"out newFile close");
|
|
check(hpatch_TFileStreamInput_close(&diffData),HPATCH_FILECLOSE_ERROR,"diffFile close");
|
|
check(hpatch_TFileStreamInput_close(&oldData),HPATCH_FILECLOSE_ERROR,"oldFile close");
|
|
_free_mem(temp_cache);
|
|
printf("\nhpatchz time: %.3f s\n",(clock_s()-time0));
|
|
return result;
|
|
}
|
|
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
int hpatch_dir(const char* oldPath,const char* diffFileName,const char* outNewPath,
|
|
hpatch_BOOL isLoadOldAll,size_t patchCacheSize,size_t kMaxOpenFileNumber,
|
|
TDirPatchChecksumSet* checksumSet,IHPatchDirListener* hlistener,
|
|
hpatch_StreamPos_t diffDataOffert,hpatch_StreamPos_t diffDataSize){
|
|
int result=HPATCH_SUCCESS;
|
|
int _isInClear=hpatch_FALSE;
|
|
double time0=clock_s();
|
|
hpatch_TFileStreamInput diffData;
|
|
TDirPatcher dirPatcher;
|
|
const TDirDiffInfo* dirDiffInfo=0;
|
|
TByte* p_temp_mem=0;
|
|
TByte* temp_cache=0;
|
|
size_t temp_cache_size;
|
|
size_t min_temp_cache_size=kPatchCacheSize_min;
|
|
hpatch_TDecompress _decompressPlugin={0};
|
|
const hpatch_TStreamInput* oldStream=0;
|
|
const hpatch_TStreamOutput* newStream=0;
|
|
hpatch_TFileStreamInput_init(&diffData);
|
|
TDirPatcher_init(&dirPatcher);
|
|
if (oldPath) assert(0!=strcmp(oldPath,outNewPath));
|
|
{//dir diff info
|
|
hpatch_BOOL rt;
|
|
hpatch_TPathType oldType;
|
|
if ((0==oldPath)||(0==strlen(oldPath))){
|
|
oldType=kPathType_file; //as empty file
|
|
}else{
|
|
check(hpatch_getPathStat(oldPath,&oldType,0),HPATCH_PATHTYPE_ERROR,"get oldPath type");
|
|
check((oldType!=kPathType_notExist),HPATCH_PATHTYPE_ERROR,"oldPath not exist");
|
|
}
|
|
check(hpatch_TFileStreamInput_open(&diffData,diffFileName),HPATCH_OPENREAD_ERROR,"open diffFile for read");
|
|
#if (_IS_NEED_SFX)
|
|
if (diffDataOffert>0){ //run sfx
|
|
check(hpatch_TFileStreamInput_setOffset(&diffData,diffDataOffert),
|
|
HPATCH_RUN_SFX_DIFFOFFSERT_ERROR,"readed sfx diffFile offset");
|
|
check(diffData.base.streamSize>=diffDataSize,
|
|
HPATCH_RUN_SFX_DIFFOFFSERT_ERROR,"readed sfx diffFile size");
|
|
diffData.base.streamSize=diffDataSize;
|
|
}
|
|
#endif
|
|
rt=TDirPatcher_open(&dirPatcher,&diffData.base,&dirDiffInfo);
|
|
if((!rt)||(!dirDiffInfo->isDirDiff)){
|
|
check(!diffData.fileError,HPATCH_FILEREAD_ERROR,"read diffFile");
|
|
check(hpatch_FALSE,DIRPATCH_DIRDIFFINFO_ERROR,"is hdiff file? get dir diff info");
|
|
}
|
|
if (dirDiffInfo->oldPathIsDir){
|
|
check(kPathType_dir==oldType,HPATCH_PATHTYPE_ERROR,"input old path need dir");
|
|
}else{
|
|
check(kPathType_file==oldType,HPATCH_PATHTYPE_ERROR,"input old path need file");
|
|
}
|
|
printf( dirDiffInfo->oldPathIsDir?"old dir: \"":"old file: \"");
|
|
if (oldPath) hpatch_printPath_utf8(oldPath);
|
|
if ((oldPath)&&dirDiffInfo->oldPathIsDir&&(!hpatch_getIsDirName(oldPath)))
|
|
printf("%c",kPatch_dirSeparator);
|
|
printf( "\"\ndiffFile: \"");
|
|
hpatch_printPath_utf8(diffFileName);
|
|
printf(dirDiffInfo->newPathIsDir?"\"\nout dir: \"":"\"\nout file: \"");
|
|
hpatch_printPath_utf8(outNewPath);
|
|
if (dirDiffInfo->newPathIsDir&&(!hpatch_getIsDirName(outNewPath))) printf("%c",kPatch_dirSeparator);
|
|
printf("\"\n");
|
|
}
|
|
{//decompressPlugin
|
|
hpatch_TDecompress* decompressPlugin=&_decompressPlugin;
|
|
hpatch_compressedDiffInfo hdiffInfo;
|
|
hdiffInfo=dirDiffInfo->hdiffInfo;
|
|
hdiffInfo.compressedCount+=(dirDiffInfo->dirDataIsCompressed)?1:0;
|
|
if(!getDecompressPlugin(&hdiffInfo,decompressPlugin)){
|
|
LOG_ERR("can not decompress \"%s\" data ERROR!\n",hdiffInfo.compressType);
|
|
check_on_error(HPATCH_COMPRESSTYPE_ERROR);
|
|
}
|
|
if (decompressPlugin->open==0) decompressPlugin=0;
|
|
//load dir data
|
|
check(TDirPatcher_loadDirData(&dirPatcher,decompressPlugin,oldPath,outNewPath),
|
|
DIRPATCH_LAOD_DIRDIFFDATA_ERROR,"load dir data in diffFile");
|
|
}
|
|
check(hlistener->patchBegin(hlistener,&dirPatcher),
|
|
DIRPATCH_PATCHBEGIN_ERROR,"dir patch begin");
|
|
{// checksumPlugin
|
|
int wantChecksumCount = checksumSet->isCheck_dirDiffData+checksumSet->isCheck_oldRefData+
|
|
checksumSet->isCheck_newRefData+checksumSet->isCheck_copyFileData;
|
|
assert(checksumSet->checksumPlugin==0);
|
|
if (wantChecksumCount>0){
|
|
if (strlen(dirDiffInfo->checksumType)==0){
|
|
memset(checksumSet,0,sizeof(*checksumSet));
|
|
printf(" NOTE: no checksum saved in diffFile,can not do checksum\n");
|
|
}else{
|
|
if (!findChecksum(&checksumSet->checksumPlugin,dirDiffInfo->checksumType)){
|
|
LOG_ERR("not found checksumType \"%s\" ERROR!\n",dirDiffInfo->checksumType);
|
|
check_on_error(DIRPATCH_CHECKSUMTYPE_ERROR);
|
|
}
|
|
printf("hpatchz run with checksum plugin: \"%s\" (need checksum %d)\n",
|
|
dirDiffInfo->checksumType,wantChecksumCount);
|
|
if (!TDirPatcher_checksum(&dirPatcher,checksumSet)){
|
|
check(!TDirPatcher_isDiffDataChecksumError(&dirPatcher),
|
|
DIRPATCH_CHECKSUM_DIFFDATA_ERROR,"diffFile checksum");
|
|
check(hpatch_FALSE,DIRPATCH_CHECKSUMSET_ERROR,"diffFile set checksum");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{//info
|
|
const _TDirDiffHead* head=&dirPatcher.dirDiffHead;
|
|
printf("DirPatch new path count: %" PRIu64 " (fileCount:%" PRIu64 ")\n",(hpatch_StreamPos_t)head->newPathCount,
|
|
(hpatch_StreamPos_t)(head->sameFilePairCount+head->newRefFileCount));
|
|
printf(" copy from old count: %" PRIu64 " (dataSize: %" PRIu64 ")\n",
|
|
(hpatch_StreamPos_t)head->sameFilePairCount,head->sameFileSize);
|
|
printf(" ref old file count: %" PRIu64 "\n",(hpatch_StreamPos_t)head->oldRefFileCount);
|
|
printf(" ref new file count: %" PRIu64 "\n",(hpatch_StreamPos_t)head->newRefFileCount);
|
|
printf("oldRefSize : %" PRIu64 "\ndiffDataSize: %" PRIu64 "\nnewRefSize : %" PRIu64 " (all newSize: %" PRIu64 ")\n",
|
|
dirDiffInfo->hdiffInfo.oldDataSize,diffData.base.streamSize,dirDiffInfo->hdiffInfo.newDataSize,
|
|
dirDiffInfo->hdiffInfo.newDataSize+head->sameFileSize);
|
|
}
|
|
{//mem cache
|
|
size_t mustAppendMemSize=0;
|
|
#if (_IS_NEED_SINGLE_STREAM_DIFF)
|
|
if (dirDiffInfo->isSingleCompressedDiff){
|
|
mustAppendMemSize+=(size_t)dirDiffInfo->sdiffInfo.stepMemSize;
|
|
min_temp_cache_size+=(size_t)dirDiffInfo->sdiffInfo.stepMemSize;
|
|
}
|
|
#endif
|
|
p_temp_mem=getPatchMemCache(isLoadOldAll,patchCacheSize,mustAppendMemSize,
|
|
dirDiffInfo->hdiffInfo.oldDataSize, &temp_cache_size);
|
|
check(p_temp_mem,HPATCH_MEM_ERROR,"alloc cache memory");
|
|
temp_cache=p_temp_mem;
|
|
}
|
|
{//old data
|
|
if (temp_cache_size>=dirDiffInfo->hdiffInfo.oldDataSize+min_temp_cache_size){
|
|
// all old while auto cache by patch; not need open old files at same time
|
|
kMaxOpenFileNumber=kMaxOpenFileNumber_limit_min;
|
|
}
|
|
check(TDirPatcher_openOldRefAsStream(&dirPatcher,kMaxOpenFileNumber,&oldStream),
|
|
DIRPATCH_OPEN_OLDPATH_ERROR,"open oldFile");
|
|
}
|
|
{//new data
|
|
check(TDirPatcher_openNewDirAsStream(&dirPatcher,&hlistener->base,&newStream),
|
|
DIRPATCH_OPEN_NEWPATH_ERROR,"open newFile");
|
|
}
|
|
//patch
|
|
if(!TDirPatcher_patch(&dirPatcher,newStream,oldStream,temp_cache,temp_cache+temp_cache_size)){
|
|
check_dec(_decompressPlugin.decError);
|
|
check(!TDirPatcher_isOldRefDataChecksumError(&dirPatcher),
|
|
DIRPATCH_CHECKSUM_OLDDATA_ERROR,"oldFile checksum");
|
|
check(!TDirPatcher_isCopyDataChecksumError(&dirPatcher),
|
|
DIRPATCH_CHECKSUM_COPYDATA_ERROR,"copyOldFile checksum");
|
|
check(!TDirPatcher_isNewRefDataChecksumError(&dirPatcher),
|
|
DIRPATCH_CHECKSUM_NEWDATA_ERROR,"newFile checksum");
|
|
check(hpatch_FALSE,DIRPATCH_PATCH_ERROR,"dir patch run");
|
|
}
|
|
clear:
|
|
_isInClear=hpatch_TRUE;
|
|
check(hlistener->patchFinish(hlistener,result==HPATCH_SUCCESS),DIRPATCH_PATCHFINISH_ERROR,"dir patch finish");
|
|
check(TDirPatcher_closeNewDirStream(&dirPatcher),DIRPATCH_CLOSE_NEWPATH_ERROR,"newPath close");
|
|
check(TDirPatcher_closeOldRefStream(&dirPatcher),DIRPATCH_CLOSE_OLDPATH_ERROR,"oldPath close");
|
|
TDirPatcher_close(&dirPatcher);
|
|
check_ferr(dirPatcher.fileError,DIRPATCH_PATCH_FILE_ERROR,"dir patch file");
|
|
check_ferr(hlistener->fileError,DIRPATCH_PATCH_FILE_ERROR,"dir patch file");
|
|
check(hpatch_TFileStreamInput_close(&diffData),HPATCH_FILECLOSE_ERROR,"diffFile close");
|
|
_free_mem(p_temp_mem);
|
|
printf("\nhpatchz dir patch time: %.3f s\n",(clock_s()-time0));
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#if (_IS_NEED_SFX)
|
|
#define _sfx_guid_size 16
|
|
#define _sfx_guid_node_size (_sfx_guid_size+sizeof(hpatch_uint32_t)+sizeof(hpatch_uint64_t))
|
|
//_sfx_guid_node:{fd6c3a9d-1498-4a5d-a9d5-7303a82fd08e-ffffffff-ffffffffffffffff}
|
|
TByte _sfx_guid_node[_sfx_guid_node_size]={
|
|
0xfd,0x6c,0x3a,0x9d,
|
|
0x14,0x98,
|
|
0x4a,0x5d,
|
|
0xa9,0xd5,
|
|
0x73,0x03,0xa8,0x2f,0xd0,0x8e,
|
|
0xff,0xff,0xff,0xff, // saved diffDataOffert , selfExecute fileSize < 4GB
|
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; // diffDataSize
|
|
|
|
static TByte* _search(TByte* src,TByte* src_end,const TByte* sub,const TByte* sub_end){
|
|
size_t sub_len=(size_t)(sub_end-sub);
|
|
TByte* search_last=src_end-sub_len;
|
|
TByte c0;
|
|
if (sub_len==0) return src;
|
|
if ((size_t)(src_end-src)<sub_len) return src_end;
|
|
c0=*sub;
|
|
for (;src<=search_last;++src) {
|
|
if (c0!=*src){
|
|
continue;
|
|
}else{
|
|
hpatch_BOOL is_eq=hpatch_TRUE;
|
|
size_t i;
|
|
for (i=1; i<sub_len;++i) {
|
|
if (sub[i]!=src[i]){
|
|
is_eq=hpatch_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (!is_eq)
|
|
continue;
|
|
else
|
|
return src;
|
|
}
|
|
}
|
|
return src_end;
|
|
}
|
|
|
|
static int createSfx_notCheckDiffFile_byStream(const hpatch_TStreamInput* selfExecute,
|
|
const hpatch_TStreamInput* diffData,
|
|
const hpatch_TStreamOutput* out_sfxData){
|
|
int result=HPATCH_SUCCESS;
|
|
int _isInClear=hpatch_FALSE;
|
|
TByte* buf=0;
|
|
TByte* pmem=0;
|
|
hpatch_StreamPos_t writePos=0;
|
|
hpatch_BOOL isFoundGuid=hpatch_FALSE;
|
|
const hpatch_StreamPos_t diffDataOffert=selfExecute->streamSize;
|
|
const hpatch_StreamPos_t diffDataSize=diffData->streamSize;
|
|
{//mem
|
|
pmem=(TByte*)malloc(_sfx_guid_node_size+hpatch_kFileIOBufBetterSize);
|
|
check(pmem!=0,HPATCH_MEM_ERROR,"createSfx() malloc");
|
|
memset(pmem,0,_sfx_guid_node_size);
|
|
buf=pmem+_sfx_guid_node_size; // [ _sfx_guid_node_size | hpatch_kFileIOBufBetterSize ]
|
|
}
|
|
{//copy exe ,find guid pos and write diffDataOffset
|
|
const hpatch_uint32_t dataSize=(hpatch_uint32_t)(selfExecute->streamSize);
|
|
hpatch_StreamPos_t readPos=0;
|
|
check(dataSize==selfExecute->streamSize,
|
|
HPATCH_CREATE_SFX_SFXTYPE_ERROR,"createSfx() selfExecute fileSize");
|
|
while (readPos < dataSize) {
|
|
TByte* wbuf=0;
|
|
const TByte* wbuf_end=0;
|
|
TByte* rbuf_end=0;
|
|
size_t readLen=hpatch_kFileIOBufBetterSize;
|
|
if (readLen+readPos > dataSize)
|
|
readLen=(size_t)(dataSize - readPos);
|
|
rbuf_end=buf+readLen;
|
|
check(selfExecute->read(selfExecute,readPos,buf,rbuf_end),
|
|
HPATCH_FILEREAD_ERROR,"createSfx() read selfExecute");
|
|
wbuf=(readPos!=0)?pmem:buf;
|
|
if (!isFoundGuid){ //find in [wbuf..rbuf_end)
|
|
TByte* pos=_search(wbuf,rbuf_end,_sfx_guid_node,_sfx_guid_node+_sfx_guid_node_size);
|
|
if (pos!=rbuf_end){
|
|
size_t i;
|
|
isFoundGuid=hpatch_TRUE;
|
|
for (i=0; i<sizeof(hpatch_uint32_t); ++i){
|
|
size_t di=_sfx_guid_size+i;
|
|
assert(pos[di]==0xff);
|
|
pos[di]=(TByte)(diffDataOffert>>(8*i));
|
|
}
|
|
for (i=0; i<sizeof(hpatch_uint64_t); ++i){
|
|
size_t di=_sfx_guid_size+sizeof(hpatch_uint32_t)+i;
|
|
assert(pos[di]==0xff);
|
|
pos[di]=(TByte)(diffDataSize>>(8*i));
|
|
}
|
|
}
|
|
}
|
|
wbuf_end=(readPos+readLen<dataSize)?(rbuf_end-_sfx_guid_node_size):rbuf_end;
|
|
check(out_sfxData->write(out_sfxData,writePos,wbuf,wbuf_end),
|
|
HPATCH_FILEWRITE_ERROR,"createSfx() write sfxData");
|
|
memcpy(pmem,rbuf_end-_sfx_guid_node_size,_sfx_guid_node_size);
|
|
readPos+=readLen;
|
|
writePos+=(size_t)(wbuf_end-wbuf);
|
|
}
|
|
}
|
|
assert(writePos==diffDataOffert);
|
|
check(isFoundGuid,HPATCH_CREATE_SFX_SFXTYPE_ERROR,"createSfx() selfExecute type");
|
|
{//copy diffData
|
|
const hpatch_StreamPos_t dataSize=diffData->streamSize;
|
|
hpatch_StreamPos_t readPos=0;
|
|
while (readPos < dataSize) {
|
|
size_t readLen=hpatch_kFileIOBufBetterSize;
|
|
if (readLen+readPos > dataSize)
|
|
readLen=(size_t)(dataSize - readPos);
|
|
check(diffData->read(diffData,readPos,buf,buf+readLen),
|
|
HPATCH_FILEREAD_ERROR,"createSfx() read diffData");
|
|
check(out_sfxData->write(out_sfxData,writePos,buf,buf+readLen),
|
|
HPATCH_FILEWRITE_ERROR,"createSfx() write sfxData");
|
|
readPos+=readLen;
|
|
writePos+=readLen;
|
|
}
|
|
}
|
|
clear:
|
|
_isInClear=hpatch_TRUE;
|
|
_free_mem(pmem);
|
|
return result;
|
|
}
|
|
|
|
int createSfx_notCheckDiffFile(const char* selfExecuteFileName,const char* diffFileName,
|
|
const char* out_sfxFileName){
|
|
int result=HPATCH_SUCCESS;
|
|
int _isInClear=hpatch_FALSE;
|
|
hpatch_TFileStreamInput exeData;
|
|
hpatch_TFileStreamInput diffData;
|
|
hpatch_TFileStreamOutput out_sfxData;
|
|
hpatch_TFileStreamInput_init(&exeData);
|
|
hpatch_TFileStreamInput_init(&diffData);
|
|
hpatch_TFileStreamOutput_init(&out_sfxData);
|
|
printf( "selfExecute: \""); hpatch_printPath_utf8(selfExecuteFileName);
|
|
printf("\"\ndiffFile : \""); hpatch_printPath_utf8(diffFileName);
|
|
printf("\"\nout sfxFile: \""); hpatch_printPath_utf8(out_sfxFileName);
|
|
printf("\"\n\n");
|
|
{//open
|
|
hpatch_StreamPos_t sfxFileLength=0;
|
|
check(hpatch_TFileStreamInput_open(&exeData,selfExecuteFileName),
|
|
HPATCH_OPENREAD_ERROR,"createSfx() open selfExecuteFile read");
|
|
sfxFileLength+=exeData.base.streamSize;
|
|
check(hpatch_TFileStreamInput_open(&diffData,diffFileName),
|
|
HPATCH_OPENREAD_ERROR,"createSfx() open diffFileName read");
|
|
sfxFileLength+=diffData.base.streamSize;
|
|
check(hpatch_TFileStreamOutput_open(&out_sfxData,out_sfxFileName,sfxFileLength),
|
|
HPATCH_OPENWRITE_ERROR,"createSfx() open sfxFile write");
|
|
}
|
|
result=createSfx_notCheckDiffFile_byStream(&exeData.base,&diffData.base,&out_sfxData.base);
|
|
if (result!=HPATCH_SUCCESS) check_on_error(result);
|
|
assert(out_sfxData.base.streamSize==out_sfxData.out_length);
|
|
check(hpatch_TFileStreamOutput_close(&out_sfxData),HPATCH_FILECLOSE_ERROR,"createSfx() out sfxFile close");
|
|
printf("sfxFileSize: %" PRIu64 "\n",out_sfxData.base.streamSize);
|
|
if (hpatch_getIsExecuteFile(selfExecuteFileName)){
|
|
check(hpatch_setIsExecuteFile(out_sfxFileName),
|
|
HPATCH_CREATE_SFX_EXECUTETAG_ERROR,"createSfx() set sfxFile Execute tag");
|
|
}
|
|
printf("out sfxFile ok!\n");
|
|
clear:
|
|
_isInClear=hpatch_TRUE;
|
|
check(hpatch_TFileStreamOutput_close(&out_sfxData),HPATCH_FILECLOSE_ERROR,"createSfx() out sfxFile close");
|
|
check(hpatch_TFileStreamInput_close(&diffData),HPATCH_FILECLOSE_ERROR,"createSfx() diffFile close");
|
|
check(hpatch_TFileStreamInput_close(&exeData),HPATCH_FILECLOSE_ERROR,"createSfx() selfExecuteFile close");
|
|
return result;
|
|
}
|
|
|
|
static hpatch_BOOL _getIsCompressedDiffFile(const char* diffFileName){
|
|
hpatch_TFileStreamInput diffData;
|
|
hpatch_compressedDiffInfo diffInfo;
|
|
hpatch_BOOL result=hpatch_TRUE;
|
|
hpatch_TFileStreamInput_init(&diffData);
|
|
if (!hpatch_TFileStreamInput_open(&diffData,diffFileName)) return hpatch_FALSE;
|
|
result=getCompressedDiffInfo(&diffInfo,&diffData.base);
|
|
if (!hpatch_TFileStreamInput_close(&diffData)) return hpatch_FALSE;
|
|
return result;
|
|
}
|
|
|
|
int createSfx(const char* selfExecuteFileName,const char* diffFileName,const char* out_sfxFileName){
|
|
int result=HPATCH_SUCCESS;
|
|
int _isInClear=hpatch_FALSE;
|
|
{//check diffFile type
|
|
hpatch_BOOL isDiffFile=hpatch_FALSE;
|
|
#if (_IS_NEED_DIR_DIFF_PATCH)
|
|
if (!isDiffFile)
|
|
isDiffFile=getIsDirDiffFile(diffFileName);
|
|
#endif
|
|
if (!isDiffFile)
|
|
isDiffFile=_getIsCompressedDiffFile(diffFileName);
|
|
check(isDiffFile,HPATCH_CREATE_SFX_DIFFFILETYPE_ERROR,
|
|
"createSfx() input diffFile is unsupported type");
|
|
}
|
|
result=createSfx_notCheckDiffFile(selfExecuteFileName,diffFileName,out_sfxFileName);
|
|
clear:
|
|
_isInClear=hpatch_TRUE;
|
|
return result;
|
|
}
|
|
|
|
hpatch_BOOL getDiffDataOffertInSfx(hpatch_StreamPos_t* out_diffDataOffert,hpatch_StreamPos_t* out_diffDataSize){
|
|
hpatch_uint32_t diffOff=0;
|
|
hpatch_uint64_t diffSize=0;
|
|
size_t i;
|
|
for (i=0; i<sizeof(hpatch_uint32_t); ++i){
|
|
size_t si=_sfx_guid_size+i;
|
|
diffOff|=((hpatch_uint32_t)_sfx_guid_node[si])<<(8*i);
|
|
}
|
|
if (diffOff==(~(hpatch_uint32_t)0)) return hpatch_FALSE;
|
|
assert(diffOff>_sfx_guid_node_size);
|
|
|
|
for (i=0; i<sizeof(hpatch_uint64_t); ++i){
|
|
size_t si=_sfx_guid_size+sizeof(hpatch_uint32_t)+i;
|
|
diffSize|=((hpatch_uint64_t)_sfx_guid_node[si])<<(8*i);
|
|
}
|
|
if (diffSize==(~(hpatch_uint64_t)0)) return hpatch_FALSE;
|
|
|
|
if (out_diffDataOffert) *out_diffDataOffert=diffOff;
|
|
if (out_diffDataSize) *out_diffDataSize=diffSize;
|
|
return hpatch_TRUE;
|
|
}
|
|
|
|
#endif // _IS_NEED_SFX
|