Skip to content

Commit b715db2

Browse files
authored
Merge pull request #389 from sisong/dev
support "hdiffz -BSD -SD" create diffFile new format: endsley/bsdiff …
2 parents 914c6db + f4302c5 commit b715db2

File tree

13 files changed

+278
-105
lines changed

13 files changed

+278
-105
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
full changelog at: https://github.com/sisong/HDiffPatch/commits
44

5+
## [v4.7.0](https://github.com/sisong/HDiffPatch/tree/v4.7.0) - 2024-07-12
6+
### Added
7+
* cmdline hdiffz support option "-BSD -SD", to create diffFile compatible with another BSDIFF format "ENDSLEY/BSDIFF43", https://github.com/mendsley/bsdiff ; patch support this format from v4.6.7
8+
* cmdline hdiffz support option "-neq"; if opened, hdiffz will refuse to created diffFile when oldData==newData.
9+
### Fixed
10+
* fixed SFX auto extract logic (SFX executable file is hpatchz file + diffFile)
11+
SFX extract with default option `$selfExtractArchive -f ".\" -X ".\"` when diffFile created by directories;
12+
if diffFile created by empty oldPath, then extract with default option `$selfExtractArchive -f "" -X ".\"`.
13+
514
## [v4.6.9](https://github.com/sisong/HDiffPatch/tree/v4.6.9) - 2023-12-01
615
### Added
716
* cmdline hdiffz & hpatchz support option "-info diffFile", print infos of diffFile;

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# [HDiffPatch]
2-
[![release](https://img.shields.io/badge/release-v4.6.10-blue.svg)](https://github.com/sisong/HDiffPatch/releases)
2+
[![release](https://img.shields.io/badge/release-v4.7.0-blue.svg)](https://github.com/sisong/HDiffPatch/releases)
33
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/sisong/HDiffPatch/blob/master/LICENSE)
44
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blue.svg)](https://github.com/sisong/HDiffPatch/pulls)
55
[![+issue Welcome](https://img.shields.io/github/issues-raw/sisong/HDiffPatch?color=green&label=%2Bissue%20welcome)](https://github.com/sisong/HDiffPatch/issues)
@@ -122,6 +122,8 @@ options:
122122
stepSize>=(1024*4), DEFAULT -SD-256k, recommended 64k,2m etc...
123123
-BSD
124124
create diffFile compatible with bsdiff4, unsupport input directory(folder).
125+
support run with -SD (not used stepSize), then create single compressed
126+
diffFile compatible with endsley/bsdiff (https://github.com/mendsley/bsdiff).
125127
-VCD[-compressLevel[-dictSize]]
126128
create diffFile compatible with VCDIFF, unsupport input directory(folder).
127129
DEFAULT no compress, out format same as $open-vcdiff ... or $xdelta3 -S -e -n ...
@@ -195,6 +197,9 @@ options:
195197
newManifestFile is created from newPath;
196198
-D force run Directory diff between two files; DEFAULT (no -D) run
197199
directory diff need oldPath or newPath is directory.
200+
-neq
201+
open check: if newPath & oldPath's all datas are equal, then return error;
202+
DEFAULT not check equal.
198203
-d Diff only, do't run patch check, DEFAULT run patch check.
199204
-t Test only, run patch check, patch(oldPath,testDiffFile)==newPath ?
200205
-f Force overwrite, ignore write path already exists;
@@ -215,7 +220,7 @@ uncompress usage: **hpatchz** [options] **"" diffFile outNewPath**
215220
print info: **hpatchz** -info **diffFile**
216221
create SFX: **hpatchz** [-X-exe#selfExecuteFile] **diffFile -X#outSelfExtractArchive**
217222
run SFX: **selfExtractArchive** [options] **oldPath -X outNewPath**
218-
extract SFX: **selfExtractArchive** (same as: selfExtractArchive -f "" -X "./")
223+
extract SFX: **selfExtractArchive** (same as: $selfExtractArchive -f {""|".\"} -X ".\")
219224
```
220225
if oldPath is empty input parameter ""
221226
options:
@@ -305,7 +310,7 @@ options:
305310
* **create_lite_diff()**
306311
* **hpatch_lite_open()**
307312
* **hpatch_lite_patch()**
308-
#### bsdiff wrapper API:
313+
#### bsdiff4 & endsley/bsdiff wrapper API:
309314
* **create_bsdiff()**
310315
* **create_bsdiff_stream()**
311316
* **bspatch_with_cache()**

README_cn.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# [HDiffPatch]
2-
[![release](https://img.shields.io/badge/release-v4.6.10-blue.svg)](https://github.com/sisong/HDiffPatch/releases)
2+
[![release](https://img.shields.io/badge/release-v4.7.0-blue.svg)](https://github.com/sisong/HDiffPatch/releases)
33
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/sisong/HDiffPatch/blob/master/LICENSE)
44
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blue.svg)](https://github.com/sisong/HDiffPatch/pulls)
55
[![+issue Welcome](https://img.shields.io/github/issues-raw/sisong/HDiffPatch?color=green&label=%2Bissue%20welcome)](https://github.com/sisong/HDiffPatch/issues)
@@ -122,6 +122,8 @@ $ git clone https://github.com/sisong/bzip2.git ../bzip2
122122
压缩步长stepSize>=(1024*4), 默认为256k, 推荐64k,2m等。
123123
-BSD
124124
创建一个和bsdiff4兼容的补丁, 不支持参数为文件夹。
125+
支持和-SD选项一起运行(不使用其stepSize), 创建单压缩流的补丁文件,
126+
兼容endsley/bsdiff格式 (https://github.com/mendsley/bsdiff)。
125127
-VCD[-compressLevel[-dictSize]]
126128
创建一个标准规范VCDIFF格式的补丁, 不支持参数为文件夹。
127129
默认输出补丁不带压缩, 格式和 $open-vcdiff ... 或 $xdelta3 -S -e -n ... 命令输出的补丁格式兼容;
@@ -191,6 +193,9 @@ $ git clone https://github.com/sisong/bzip2.git ../bzip2
191193
设置newPath的清单文件newManifestFile;
192194
-D 强制执行文件夹间的diff, 即使输入的是2个文件; 从而为文件间的补丁添加校验功能。
193195
默认情况下oldPath或newPath有一个是文件夹时才会执行文件夹间的diff。
196+
-neq
197+
打开检查: 如果newPath和oldPath的数据都相同,则返回错误;
198+
默认不执行该相等检查。
194199
-d 只执行diff, 不要执行patch检查, 默认会执行patch检查.
195200
-t 只执行patch检查, 检查是否 patch(oldPath,testDiffFile)==newPath ?
196201
-f 强制文件写覆盖, 忽略输出的路径是否已经存在;
@@ -213,7 +218,7 @@ $ git clone https://github.com/sisong/bzip2.git ../bzip2
213218
(将目标平台的hpatchz可执行文件和补丁包文件合并成一个可执行文件, 称作自释放包SFX)
214219
执行一个自释放包: **selfExtractArchive** [options] **oldPath -X outNewPath**
215220
(利用自释放包来打补丁,将包中自带的补丁数据应用到oldPath上, 合成outNewPath)
216-
执行一个自解压包: **selfExtractArchive** (等价于: selfExtractArchive -f "" -X "./")
221+
执行一个自解压包: **selfExtractArchive** (等价于:$selfExtractArchive -f {""|".\"} -X "./")
217222
```
218223
oldPath可以为空, 输入参数为 ""
219224
选项:
@@ -301,7 +306,7 @@ $ git clone https://github.com/sisong/bzip2.git ../bzip2
301306
* **create_lite_diff()**
302307
* **hpatch_lite_open()**
303308
* **hpatch_lite_patch()**
304-
#### bsdiff 兼容包装 API:
309+
#### bsdiff4 和 endsley/bsdiff 兼容包装 API:
305310
* **create_bsdiff()**
306311
* **create_bsdiff_stream()**
307312
* **bspatch_with_cache()**

bsdiff_wrapper/bsdiff_wrapper.cpp

Lines changed: 113 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#endif
3939
#define _check(value,info) { if (!(value)) { throw std::runtime_error(info); } }
4040
static const char* kBsDiffVersionType="BSDIFF40";
41+
static const char* kEsBsDiffVersionType = "ENDSLEY/BSDIFF43";
4142

4243
namespace hdiff_private{
4344
static inline void pushUInt64(std::vector<unsigned char>& buf,hpatch_uint64_t v){
@@ -103,23 +104,115 @@ namespace hdiff_private{
103104
}
104105
};
105106

107+
108+
struct TInterlaceStream:public hpatch_TStreamInput{
109+
explicit TInterlaceStream(const TCovers& _covers,TCtrlStream& _ctrlStream,
110+
TNewDataSubDiffStream& _subStream,TNewDataDiffStream& _diffStream)
111+
:curPos(0),curi(0),covers(_covers),
112+
curCtrlPos(0),curSubPos(0),curDiffPos(0),curCtrlLen(0),curSubLen(0),curDiffLen(0),
113+
ctrlStream(_ctrlStream),subStream(_subStream),diffStream(_diffStream){
114+
streamImport=this;
115+
read=_read;
116+
streamSize=ctrlStream.streamSize+subStream.streamSize+diffStream.streamSize;
117+
}
118+
private:
119+
hpatch_StreamPos_t curPos;
120+
size_t curi;
121+
const TCovers& covers;
122+
hpatch_StreamPos_t curCtrlPos;
123+
hpatch_StreamPos_t curSubPos;
124+
hpatch_StreamPos_t curDiffPos;
125+
size_t curCtrlLen;
126+
size_t curSubLen;
127+
size_t curDiffLen;
128+
TCtrlStream& ctrlStream;
129+
TNewDataSubDiffStream& subStream;
130+
TNewDataDiffStream& diffStream;
131+
void _update(){
132+
if (curi+1<covers.coverCount()){
133+
TCover c,cnext;
134+
covers.covers(curi++,&c);
135+
covers.covers(curi,&cnext);
136+
curCtrlLen=3*8;
137+
curDiffLen=cnext.newPos-(c.newPos+c.length);
138+
curSubLen=c.length;
139+
}
140+
}
141+
hpatch_BOOL readTo(hpatch_StreamPos_t readFromPos,unsigned char* out_data,unsigned char* out_data_end){
142+
if (readFromPos!=curPos)
143+
return hpatch_FALSE;
144+
size_t readLen=out_data_end-out_data;
145+
curPos+=readLen;
146+
while (readLen>0){
147+
if (curCtrlLen+curSubLen+curDiffLen==0){
148+
_update();
149+
_check(curCtrlLen+curSubLen+curDiffLen>0,"TInterlaceStream _update");
150+
}
151+
152+
hpatch_StreamPos_t* dataPos;
153+
size_t* dataLen;
154+
hpatch_TStreamInput* dataStream;
155+
if (curCtrlLen>0){
156+
dataPos=&curCtrlPos;
157+
dataLen=&curCtrlLen;
158+
dataStream=&ctrlStream;
159+
}else if (curSubLen>0){
160+
dataPos=&curSubPos;
161+
dataLen=&curSubLen;
162+
dataStream=&subStream;
163+
}else{
164+
assert(curDiffLen>0);
165+
dataPos=&curDiffPos;
166+
dataLen=&curDiffLen;
167+
dataStream=&diffStream;
168+
}
169+
170+
size_t cLen=(*dataLen);
171+
if (cLen>readLen) cLen=readLen;
172+
_check(dataStream->read(dataStream,*dataPos,out_data,out_data+cLen),"TInterlaceStream dataStream->read")
173+
out_data+=cLen;
174+
readLen-=cLen;
175+
(*dataPos)+=cLen;
176+
(*dataLen)-=cLen;
177+
}
178+
return hpatch_TRUE;
179+
}
180+
static hpatch_BOOL _read(const hpatch_TStreamInput* stream,hpatch_StreamPos_t readFromPos,
181+
unsigned char* out_data,unsigned char* out_data_end){
182+
TInterlaceStream* self=(TInterlaceStream*)stream->streamImport;
183+
return self->readTo(readFromPos,out_data,out_data_end);
184+
}
185+
};
186+
106187
static void serialize_bsdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
107188
const TCovers& covers,const hpatch_TStreamOutput* out_diff,
108-
const hdiff_TCompress* compressPlugin,bool isZeroSubDiff=false){
189+
const hdiff_TCompress* compressPlugin,bool isEndsleyBsdiff,bool isZeroSubDiff=false){
109190
std::vector<unsigned char> buf;
110191
TDiffStream outDiff(out_diff);
111192
size_t ctrlDataSize_pos;
112-
size_t subDataSize_pos;
113193
{//head
114194
buf.clear();
115-
pushCStr(buf,kBsDiffVersionType);
195+
pushCStr(buf,isEndsleyBsdiff?kEsBsDiffVersionType:kBsDiffVersionType);
116196
ctrlDataSize_pos=buf.size();
117-
pushUInt64(buf,0); //ctrlDataSize
118-
subDataSize_pos=buf.size();
119-
pushUInt64(buf,0); //subDataSize
197+
if (!isEndsleyBsdiff){
198+
pushUInt64(buf,0); //ctrlDataSize
199+
pushUInt64(buf,0); //subDataSize
200+
}
120201
pushUInt64(buf,newData->streamSize);
121202
outDiff.pushBack(buf.data(),buf.size());
122203
}
204+
205+
if (isEndsleyBsdiff){
206+
// endsley/bsdiff
207+
TCtrlStream ctrlStream(covers);
208+
TNewDataSubDiffStream subStream(newData,oldData,covers,true,isZeroSubDiff);
209+
TNewDataDiffStream diffStream(covers,newData);
210+
211+
TInterlaceStream interlaceStream(covers,ctrlStream,subStream,diffStream);
212+
outDiff.pushStream(&interlaceStream,compressPlugin,true);
213+
return;
214+
}
215+
//else bsdiff4
123216

124217
{//ctrl data
125218
TCtrlStream ctrlStream(covers);
@@ -135,6 +228,7 @@ static void serialize_bsdiff(const hpatch_TStreamInput* newData,const hpatch_TSt
135228
TNewDataSubDiffStream subStream(newData,oldData,covers,true,isZeroSubDiff);
136229
hpatch_StreamPos_t subDataSize=outDiff.pushStream(&subStream,compressPlugin,true);
137230

231+
size_t subDataSize_pos=ctrlDataSize_pos+8;
138232
buf.clear();
139233
pushUInt64(buf,subDataSize);//update subDataSize
140234
_check(out_diff->write(out_diff,subDataSize_pos,buf.data(),
@@ -173,7 +267,7 @@ static void _to_bsdiff_covers(std::vector<_TCover>& covers,_TSize newSize){
173267
void _create_bsdiff(const unsigned char* newData,const unsigned char* cur_newData_end,const unsigned char* newData_end,
174268
const unsigned char* oldData,const unsigned char* cur_oldData_end,const unsigned char* oldData_end,
175269
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
176-
int kMinSingleMatchScore,bool isUseBigCacheMatch,
270+
bool isEndsleyBsdiff,int kMinSingleMatchScore,bool isUseBigCacheMatch,
177271
ICoverLinesListener* coverLinesListener,size_t threadNum){
178272
std::vector<hpatch_TCover_sz> covers;
179273
get_match_covers_by_sstring(newData,cur_newData_end,oldData,cur_oldData_end,covers,
@@ -188,7 +282,7 @@ void _create_bsdiff(const unsigned char* newData,const unsigned char* cur_newDat
188282
mem_as_hStreamInput(&newStream,newData,newData_end);
189283
mem_as_hStreamInput(&oldStream,oldData,oldData_end);
190284

191-
serialize_bsdiff(&newStream,&oldStream,_covers,out_diff,compressPlugin);
285+
serialize_bsdiff(&newStream,&oldStream,_covers,out_diff,compressPlugin,isEndsleyBsdiff);
192286
}
193287

194288
}//end namespace hdiff_private
@@ -198,15 +292,15 @@ using namespace hdiff_private;
198292
void create_bsdiff(const unsigned char* newData,const unsigned char* newData_end,
199293
const unsigned char* oldData,const unsigned char* oldData_end,
200294
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
201-
int kMinSingleMatchScore,bool isUseBigCacheMatch,
295+
bool isEndsleyBsdiff,int kMinSingleMatchScore,bool isUseBigCacheMatch,
202296
ICoverLinesListener* coverLinesListener,size_t threadNum){
203297
_create_bsdiff(newData,newData_end,newData_end,oldData,oldData_end,oldData_end,
204-
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
298+
out_diff,compressPlugin,isEndsleyBsdiff,kMinSingleMatchScore,isUseBigCacheMatch,
205299
coverLinesListener,threadNum);
206300
}
207301
void create_bsdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
208302
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
209-
int kMinSingleMatchScore,bool isUseBigCacheMatch,
303+
bool isEndsleyBsdiff,int kMinSingleMatchScore,bool isUseBigCacheMatch,
210304
ICoverLinesListener* coverLinesListener,size_t threadNum){
211305
TAutoMem oldAndNewData;
212306
loadOldAndNewStream(oldAndNewData,oldData,newData);
@@ -215,50 +309,50 @@ void create_bsdiff(const hpatch_TStreamInput* newData,const hpatch_TStreamInput*
215309
unsigned char* pNewData=pOldData+old_size;
216310
unsigned char* pNewDataEnd=pNewData+(size_t)newData->streamSize;
217311
_create_bsdiff(pNewData,pNewDataEnd,pNewDataEnd,pOldData,pOldData+old_size,pOldData+old_size,
218-
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
312+
out_diff,compressPlugin,isEndsleyBsdiff,kMinSingleMatchScore,isUseBigCacheMatch,
219313
coverLinesListener,threadNum);
220314
}
221315

222316
void create_bsdiff_stream(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
223317
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
224-
size_t kMatchBlockSize,const hdiff_TMTSets_s* mtsets){
318+
bool isEndsleyBsdiff,size_t kMatchBlockSize,const hdiff_TMTSets_s* mtsets){
225319
TCoversBuf covers(newData->streamSize,oldData->streamSize);
226320
get_match_covers_by_block(newData,oldData,&covers,kMatchBlockSize,mtsets);
227321
if (covers._isCover32)
228322
_to_bsdiff_covers(covers.m_covers_limit,(hpatch_uint32_t)newData->streamSize);
229323
else
230324
_to_bsdiff_covers(covers.m_covers_larger,newData->streamSize);
231325
covers.update();
232-
serialize_bsdiff(newData,oldData,covers,out_diff,compressPlugin,true);
326+
serialize_bsdiff(newData,oldData,covers,out_diff,compressPlugin,isEndsleyBsdiff,true);
233327
}
234328

235329

236330
void create_bsdiff_block(unsigned char* newData,unsigned char* newData_end,
237331
unsigned char* oldData,unsigned char* oldData_end,
238332
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
239-
int kMinSingleMatchScore,bool isUseBigCacheMatch,
333+
bool isEndsleyBsdiff,int kMinSingleMatchScore,bool isUseBigCacheMatch,
240334
size_t matchBlockSize,size_t threadNum){
241335
if (matchBlockSize==0){
242336
_create_bsdiff(newData,newData_end,newData_end,oldData,oldData_end,oldData_end,
243-
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,0,threadNum);
337+
out_diff,compressPlugin,isEndsleyBsdiff,kMinSingleMatchScore,isUseBigCacheMatch,0,threadNum);
244338
return;
245339
}
246340
TCoversOptimMB<TMatchBlock> coversOp(newData,newData_end,oldData,oldData_end,matchBlockSize,threadNum);
247341
_create_bsdiff(newData,coversOp.matchBlock->newData_end_cur,newData_end,
248342
oldData,coversOp.matchBlock->oldData_end_cur,oldData_end,
249-
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,&coversOp,threadNum);
343+
out_diff,compressPlugin,isEndsleyBsdiff,kMinSingleMatchScore,isUseBigCacheMatch,&coversOp,threadNum);
250344
}
251345
void create_bsdiff_block(const hpatch_TStreamInput* newData,const hpatch_TStreamInput* oldData,
252346
const hpatch_TStreamOutput* out_diff,const hdiff_TCompress* compressPlugin,
253-
int kMinSingleMatchScore,bool isUseBigCacheMatch,
347+
bool isEndsleyBsdiff,int kMinSingleMatchScore,bool isUseBigCacheMatch,
254348
size_t matchBlockSize,size_t threadNum){
255349
TAutoMem oldAndNewData;
256350
loadOldAndNewStream(oldAndNewData,oldData,newData);
257351
size_t old_size=oldData?(size_t)oldData->streamSize:0;
258352
unsigned char* pOldData=oldAndNewData.data();
259353
unsigned char* pNewData=pOldData+old_size;
260354
create_bsdiff_block(pNewData,pNewData+(size_t)newData->streamSize,pOldData,pOldData+old_size,
261-
out_diff,compressPlugin,kMinSingleMatchScore,isUseBigCacheMatch,
355+
out_diff,compressPlugin,isEndsleyBsdiff,kMinSingleMatchScore,isUseBigCacheMatch,
262356
matchBlockSize,threadNum);
263357
}
264358

0 commit comments

Comments
 (0)