11#include " hdiff.h"
22#include " ../HDiffPatch/libHDiffPatch/HDiff/diff.h"
3+ #include " ../HDiffPatch/libHDiffPatch/HPatch/patch.h"
34#include " ../HDiffPatch/file_for_patch.h"
5+ #include < cstring>
46#include < stdexcept>
57
68#define _CompressPlugin_lzma2
@@ -28,6 +30,8 @@ namespace {
2830 // 显式固定为旧值,保证与既有版本产出行为连续。
2931 const int kSingleMatchScore = 3 ;
3032 const size_t kPatchStepMemSize = 1024 * 256 ;
33+ const char kSingleDiffPrefix [] = " HDIFFSF20&" ;
34+ const size_t kSingleDiffPrefixSize = sizeof (kSingleDiffPrefix ) - 1 ;
3135
3236 struct FileStreamGuard {
3337 hpatch_TFileStreamInput oldStream{};
@@ -99,6 +103,155 @@ namespace {
99103 }
100104 }
101105 };
106+
107+ struct FileRewriteGuard {
108+ hpatch_TFileStreamOutput stream{};
109+ bool opened = false ;
110+
111+ FileRewriteGuard () {
112+ hpatch_TFileStreamOutput_init (&stream);
113+ }
114+ ~FileRewriteGuard () {
115+ if (opened) hpatch_TFileStreamOutput_close (&stream);
116+ }
117+ void open (const char * path) {
118+ if (!hpatch_TFileStreamOutput_reopen (&stream, path, ~(hpatch_StreamPos_t)0 )) {
119+ throw std::runtime_error (" open diff file for rewrite failed." );
120+ }
121+ opened = true ;
122+ hpatch_TFileStreamOutput_setRandomOut (&stream, hpatch_TRUE);
123+ }
124+ void close () {
125+ opened = false ;
126+ if (!hpatch_TFileStreamOutput_close (&stream)) {
127+ throw std::runtime_error (" close diff file failed." );
128+ }
129+ }
130+ };
131+
132+ bool should_clear_single_raw_compress_type (const hpatch_singleCompressedDiffInfo& diffInfo,
133+ size_t * outTypeLen) {
134+ if ((diffInfo.compressedSize != 0 ) || (diffInfo.compressType [0 ] == ' \0 ' )) {
135+ return false ;
136+ }
137+ *outTypeLen = std::strlen (diffInfo.compressType );
138+ if (*outTypeLen == 0 ) {
139+ return false ;
140+ }
141+ return true ;
142+ }
143+
144+ struct SingleRawCompressTypeSplice {
145+ bool shouldSplice = false ;
146+ hpatch_StreamPos_t readPos = 0 ;
147+ hpatch_StreamPos_t writePos = 0 ;
148+ hpatch_StreamPos_t newSize = 0 ;
149+ };
150+
151+ SingleRawCompressTypeSplice get_single_raw_compress_type_splice (
152+ const hpatch_singleCompressedDiffInfo& diffInfo,
153+ hpatch_StreamPos_t diffSize,
154+ const uint8_t * prefixBytes) {
155+ size_t typeLen = 0 ;
156+ if (!should_clear_single_raw_compress_type (diffInfo, &typeLen)) {
157+ return {};
158+ }
159+ if ((diffSize < kSingleDiffPrefixSize + typeLen + 1 ) ||
160+ (0 != std::memcmp (prefixBytes, kSingleDiffPrefix , kSingleDiffPrefixSize ))) {
161+ throw std::runtime_error (" single diff header layout error." );
162+ }
163+
164+ SingleRawCompressTypeSplice splice;
165+ splice.shouldSplice = true ;
166+ splice.readPos = kSingleDiffPrefixSize + typeLen;
167+ splice.writePos = kSingleDiffPrefixSize ;
168+ splice.newSize = diffSize - typeLen;
169+ return splice;
170+ }
171+
172+ void normalize_single_raw_compress_type (std::vector<uint8_t >& diff) {
173+ hpatch_singleCompressedDiffInfo diffInfo;
174+ if (!getSingleCompressedDiffInfo_mem (&diffInfo, diff.data (), diff.data () + diff.size ())) {
175+ throw std::runtime_error (" getSingleCompressedDiffInfo_mem() failed, invalid diff data!" );
176+ }
177+
178+ SingleRawCompressTypeSplice splice = get_single_raw_compress_type_splice (
179+ diffInfo, diff.size (), diff.data ());
180+ if (!splice.shouldSplice ) {
181+ return ;
182+ }
183+ diff.erase (diff.begin () + (size_t )splice.writePos ,
184+ diff.begin () + (size_t )splice.readPos );
185+ }
186+
187+ void normalize_single_raw_compress_type (const char * diffPath) {
188+ hpatch_TFileStreamInput diffIn;
189+ hpatch_TFileStreamInput_init (&diffIn);
190+ bool diffInOpened = false ;
191+
192+ hpatch_singleCompressedDiffInfo diffInfo;
193+ hpatch_StreamPos_t oldDiffSize = 0 ;
194+ uint8_t prefixBytes[kSingleDiffPrefixSize ];
195+ try {
196+ if (!hpatch_TFileStreamInput_open (&diffIn, diffPath)) {
197+ throw std::runtime_error (" open diff file for read failed." );
198+ }
199+ diffInOpened = true ;
200+ oldDiffSize = diffIn.base .streamSize ;
201+ if ((oldDiffSize < kSingleDiffPrefixSize ) ||
202+ !diffIn.base .read (&diffIn.base , 0 , prefixBytes,
203+ prefixBytes + kSingleDiffPrefixSize )) {
204+ throw std::runtime_error (" single diff header layout error." );
205+ }
206+ if (!getSingleCompressedDiffInfo (&diffInfo, &diffIn.base , 0 )) {
207+ throw std::runtime_error (" getSingleCompressedDiffInfo() failed, invalid diff data!" );
208+ }
209+ } catch (...) {
210+ if (diffInOpened) hpatch_TFileStreamInput_close (&diffIn);
211+ throw ;
212+ }
213+ diffInOpened = false ;
214+ if (!hpatch_TFileStreamInput_close (&diffIn)) {
215+ throw std::runtime_error (" close diff file failed." );
216+ }
217+
218+ SingleRawCompressTypeSplice splice = get_single_raw_compress_type_splice (
219+ diffInfo, oldDiffSize, prefixBytes);
220+ if (!splice.shouldSplice ) {
221+ return ;
222+ }
223+
224+ FileRewriteGuard diffOut;
225+ diffOut.open (diffPath);
226+
227+ const size_t kBufSize = hpatch_kFileIOBufBetterSize;
228+ std::vector<uint8_t > buf (kBufSize );
229+ hpatch_StreamPos_t readPos = splice.readPos ;
230+ hpatch_StreamPos_t writePos = splice.writePos ;
231+ while (readPos < oldDiffSize) {
232+ hpatch_StreamPos_t readLen = oldDiffSize - readPos;
233+ if (readLen > (hpatch_StreamPos_t)buf.size ()) {
234+ readLen = (hpatch_StreamPos_t)buf.size ();
235+ }
236+ if (!diffOut.stream .base .read_writed (&diffOut.stream .base , readPos,
237+ buf.data (), buf.data () + (size_t )readLen)) {
238+ throw std::runtime_error (" read diff file for rewrite failed." );
239+ }
240+ if (!diffOut.stream .base .write (&diffOut.stream .base , writePos,
241+ buf.data (), buf.data () + (size_t )readLen)) {
242+ throw std::runtime_error (" rewrite diff file failed." );
243+ }
244+ readPos += readLen;
245+ writePos += readLen;
246+ }
247+ if (!hpatch_TFileStreamOutput_flush (&diffOut.stream )) {
248+ throw std::runtime_error (" flush diff file failed." );
249+ }
250+ if (!hpatch_TFileStreamOutput_truncate (&diffOut.stream , splice.newSize )) {
251+ throw std::runtime_error (" truncate diff file failed." );
252+ }
253+ diffOut.close ();
254+ }
102255}
103256
104257void hdiff (const uint8_t * old, size_t oldsize, const uint8_t * _new, size_t newsize,
@@ -110,6 +263,7 @@ void hdiff(const uint8_t* old, size_t oldsize, const uint8_t* _new, size_t newsi
110263 create_single_compressed_diff (_new, _new + newsize, old, old + oldsize, out_codeBuf,
111264 &compressPlugin.base , kPatchStepMemSize ,
112265 kSingleMatchScore );
266+ normalize_single_raw_compress_type (out_codeBuf);
113267
114268 if (!check_single_compressed_diff (_new, _new + newsize, old, old + oldsize,
115269 out_codeBuf.data (),
@@ -173,6 +327,7 @@ void hdiff_window(const char* oldPath,const char* newPath,const char* outDiffPat
173327 kSingleMatchScore );
174328
175329 streams.closeDiffOut ();
330+ normalize_single_raw_compress_type (outDiffPath);
176331 streams.openDiffIn (outDiffPath);
177332 if (!check_single_compressed_diff (&streams.newStream .base , &streams.oldStream .base ,
178333 &streams.diffInStream .base , decompressPlugin)) {
@@ -200,6 +355,7 @@ void hdiff_single_stream(const char* oldPath,const char* newPath,const char* out
200355 kMatchBlockSize_default );
201356
202357 streams.closeDiffOut ();
358+ normalize_single_raw_compress_type (outDiffPath);
203359 streams.openDiffIn (outDiffPath);
204360 if (!check_single_compressed_diff (&streams.newStream .base , &streams.oldStream .base ,
205361 &streams.diffInStream .base , decompressPlugin)) {
0 commit comments