1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "image_diff.h"
17 #include <iostream>
18 #include <vector>
19 #include "diffpatch.h"
20
21 using namespace Hpackage;
22
23 namespace UpdatePatch {
24 #define GET_REAL_DATA_LEN(info) (info) ->packedSize + (info)->dataOffset - (info)->headerOffset
25 constexpr int32_t LZ4F_MAX_BLOCKID = 7;
26 constexpr int32_t ZIP_MAX_LEVEL = 9;
27 constexpr int32_t MAX_NEW_LENGTH = 1 << 20;
28
29 template<class DataType>
WriteToFile(std::ofstream & patchFile,DataType data,size_t dataSize)30 static void WriteToFile(std::ofstream &patchFile, DataType data, size_t dataSize)
31 {
32 patchFile.write(reinterpret_cast<const char*>(&data), dataSize);
33 }
34
GetHeaderSize(const ImageBlock & block)35 static size_t GetHeaderSize(const ImageBlock &block)
36 {
37 switch (block.type) {
38 case BLOCK_NORMAL:
39 return sizeof(uint32_t) + PATCH_NORMAL_MIN_HEADER_LEN;
40 case BLOCK_DEFLATE:
41 return sizeof(uint32_t) + PATCH_DEFLATE_MIN_HEADER_LEN;
42 case BLOCK_RAW:
43 return sizeof(uint32_t) + sizeof(uint32_t) + block.newInfo.length;
44 case BLOCK_LZ4:
45 return sizeof(uint32_t) + PATCH_LZ4_MIN_HEADER_LEN;
46 default:
47 return 0;
48 }
49 }
50
MakePatch(const std::string & patchName)51 int32_t ImageDiff::MakePatch(const std::string &patchName)
52 {
53 PATCH_LOGI("ImageDiff::MakePatch %s limit_:%d", patchName.c_str(), limit_);
54 if (newParser_ == nullptr || oldParser_ == nullptr) {
55 PATCH_LOGE("Invalid parser");
56 return -1;
57 }
58 BlockBuffer newBuffer;
59 BlockBuffer olduffer;
60 int32_t ret = newParser_->GetPkgBuffer(newBuffer);
61 int32_t ret1 = oldParser_->GetPkgBuffer(olduffer);
62 if (ret != 0 || ret1 != 0) {
63 PATCH_LOGE("Failed to get pkgbuffer");
64 return -1;
65 }
66
67 PATCH_LOGI("ImageDiff::MakePatch newBuffer %zu %zu ", newBuffer.length, olduffer.length);
68
69 if (limit_ == 0 || newBuffer.length <= limit_) {
70 ImageBlock block = {
71 BLOCK_NORMAL,
72 { newBuffer.buffer, 0, newBuffer.length },
73 { olduffer.buffer, 0, olduffer.length },
74 };
75 updateBlocks_.push_back(std::move(block));
76 } else {
77 PatchBuffer oldInfo = { olduffer.buffer, 0, olduffer.length };
78 PatchBuffer newInfo = { newBuffer.buffer, 0, newBuffer.length };
79 ret = SplitImage(oldInfo, newInfo);
80 if (ret != 0) {
81 PATCH_LOGE("Failed to split imgage");
82 return ret;
83 }
84 }
85 return DiffImage(patchName);
86 }
87
SplitImage(const PatchBuffer & oldInfo,const PatchBuffer & newInfo)88 int32_t ImageDiff::SplitImage(const PatchBuffer &oldInfo, const PatchBuffer &newInfo)
89 {
90 size_t blockCount = newInfo.length / limit_ + 1;
91 size_t oldBlockSize = oldInfo.length / blockCount;
92 size_t newBlockSize = newInfo.length / blockCount;
93 int32_t type = (oldInfo.length == 0) ? BLOCK_RAW : BLOCK_NORMAL;
94 size_t i = 0;
95 while (i < blockCount - 1) {
96 ImageBlock block = {
97 type,
98 { newInfo.buffer, newInfo.start + newBlockSize * i, newBlockSize },
99 { oldInfo.buffer, oldInfo.start + oldBlockSize * i, oldBlockSize },
100 };
101 updateBlocks_.push_back(std::move(block));
102 i++;
103 }
104 ImageBlock block = {
105 type,
106 { newInfo.buffer, newInfo.start + newBlockSize * i, newInfo.length - (newInfo.start + newBlockSize * i) },
107 { oldInfo.buffer, oldInfo.start + oldBlockSize * i, oldInfo.length - (oldInfo.start + oldBlockSize * i) },
108 };
109 updateBlocks_.push_back(std::move(block));
110 return 0;
111 }
112
WriteHeader(std::ofstream & patchFile,std::fstream & blockPatchFile,size_t & dataOffset,ImageBlock & block) const113 int32_t ImageDiff::WriteHeader(std::ofstream &patchFile,
114 std::fstream &blockPatchFile, size_t &dataOffset, ImageBlock &block) const
115 {
116 int32_t ret = 0;
117 switch (block.type) {
118 case BLOCK_NORMAL: {
119 size_t patchSize = 0;
120 BlockBuffer newInfo = { block.newInfo.buffer + block.newInfo.start, block.newInfo.length };
121 BlockBuffer oldInfo = { block.oldInfo.buffer + block.oldInfo.start, block.oldInfo.length };
122 ret = MakeBlockPatch(block, blockPatchFile, newInfo, oldInfo, patchSize);
123 if (ret != 0) {
124 PATCH_LOGE("Failed to make block patch");
125 return -1;
126 }
127 PATCH_LOGI("WriteHeader BLOCK_NORMAL patchOffset %zu oldInfo %ld %ld newInfo:%zu %zu patch %zu %zu",
128 static_cast<size_t>(patchFile.tellp()),
129 block.oldInfo.start, block.oldInfo.length, block.newInfo.start, block.newInfo.length,
130 dataOffset, patchSize);
131 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.start), sizeof(int64_t));
132 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.length), sizeof(int64_t));
133 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(dataOffset), sizeof(int64_t));
134 dataOffset += patchSize;
135 break;
136 }
137 case BLOCK_RAW: {
138 PATCH_LOGI("WriteHeader BLOCK_ROW patchOffset %zu dataOffset:%zu newInfo:%zu",
139 static_cast<size_t>(patchFile.tellp()), dataOffset, block.newInfo.length);
140 WriteToFile<int32_t>(patchFile, static_cast<int32_t>(block.newInfo.length), sizeof(int32_t));
141 patchFile.write(reinterpret_cast<const char*>(block.newInfo.buffer + block.newInfo.start),
142 block.newInfo.length);
143 BlockBuffer rawData = { block.newInfo.buffer + block.newInfo.start, block.newInfo.length };
144 PATCH_LOGI("WriteHeader BLOCK_ROW hash %zu %s",
145 block.newInfo.length, GeneraterBufferHash(rawData).c_str());
146 break;
147 }
148 default:
149 break;
150 }
151 return ret;
152 }
153
MakeBlockPatch(ImageBlock & block,std::fstream & blockPatchFile,const BlockBuffer & newInfo,const BlockBuffer & oldInfo,size_t & patchSize) const154 int32_t ImageDiff::MakeBlockPatch(ImageBlock &block, std::fstream &blockPatchFile,
155 const BlockBuffer &newInfo, const BlockBuffer &oldInfo, size_t &patchSize) const
156 {
157 if (!usePatchFile_) {
158 std::vector<uint8_t> patchData;
159 int32_t ret = BlocksDiff::MakePatch(newInfo, oldInfo, patchData, 0, patchSize);
160 if (ret != 0) {
161 PATCH_LOGE("Failed to make block patch");
162 return -1;
163 }
164 BlockBuffer patchBuffer = {patchData.data(), patchSize};
165 PATCH_DEBUG("MakeBlockPatch hash %zu %s", patchSize, GeneraterBufferHash(patchBuffer).c_str());
166 block.patchData = std::move(patchData);
167 } else {
168 int32_t ret = BlocksDiff::MakePatch(newInfo, oldInfo, blockPatchFile, patchSize);
169 if (ret != 0) {
170 PATCH_LOGE("Failed to make block patch");
171 return -1;
172 }
173 PATCH_LOGI("MakeBlockPatch patch %zu patch %zu",
174 patchSize, static_cast<size_t>(blockPatchFile.tellp()));
175 }
176 return 0;
177 }
178
WritePatch(std::ofstream & patchFile,std::fstream & blockPatchFile)179 int32_t ImageDiff::WritePatch(std::ofstream &patchFile, std::fstream &blockPatchFile)
180 {
181 if (usePatchFile_) { // copy to patch
182 size_t bsPatchSize = static_cast<size_t>(blockPatchFile.tellp());
183 PATCH_LOGI("WritePatch patch block patch %zu img patch offset %zu",
184 bsPatchSize, static_cast<size_t>(patchFile.tellp()));
185 blockPatchFile.seekg(0, std::ios::beg);
186 std::vector<char> buffer(IGMDIFF_LIMIT_UNIT);
187 while (bsPatchSize > 0) {
188 size_t readLen = (bsPatchSize > IGMDIFF_LIMIT_UNIT) ? IGMDIFF_LIMIT_UNIT : bsPatchSize;
189 blockPatchFile.read(buffer.data(), readLen);
190 patchFile.write(buffer.data(), readLen);
191 bsPatchSize -= readLen;
192 }
193 PATCH_LOGI("WritePatch patch %zu", static_cast<size_t>(patchFile.tellp()));
194 } else {
195 for (size_t index = 0; index < updateBlocks_.size(); index++) {
196 if (updateBlocks_[index].type == BLOCK_RAW) {
197 continue;
198 }
199 PATCH_LOGI("WritePatch [%zu] write patch patchOffset %zu length %zu",
200 index, static_cast<size_t>(patchFile.tellp()), updateBlocks_[index].patchData.size());
201 patchFile.write(reinterpret_cast<const char*>(updateBlocks_[index].patchData.data()),
202 updateBlocks_[index].patchData.size());
203 }
204 }
205 return 0;
206 }
207
DiffImage(const std::string & patchName)208 int32_t ImageDiff::DiffImage(const std::string &patchName)
209 {
210 std::fstream blockPatchFile;
211 std::ofstream patchFile(patchName, std::ios::out | std::ios::trunc | std::ios::binary);
212 if (patchFile.fail()) {
213 PATCH_LOGE("Failed to open %s", patchName.c_str());
214 return -1;
215 }
216 patchFile.write(PKGDIFF_MAGIC, std::char_traits<char>::length(PKGDIFF_MAGIC));
217 size_t dataOffset = std::char_traits<char>::length(PKGDIFF_MAGIC);
218 uint32_t size = static_cast<uint32_t>(updateBlocks_.size());
219 patchFile.write(reinterpret_cast<const char*>(&size), sizeof(uint32_t));
220 dataOffset += sizeof(uint32_t);
221
222 for (size_t index = 0; index < updateBlocks_.size(); index++) {
223 dataOffset += GetHeaderSize(updateBlocks_[index]);
224 if (updateBlocks_[index].destOriginalLength >= MAX_NEW_LENGTH ||
225 updateBlocks_[index].newInfo.length >= MAX_NEW_LENGTH) {
226 usePatchFile_ = true;
227 }
228 }
229
230 if (usePatchFile_) {
231 blockPatchFile.open(patchName + ".bspatch", std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
232 if (blockPatchFile.fail()) {
233 PATCH_LOGE("Failed to open bspatch %s", patchName.c_str());
234 return -1;
235 }
236 }
237
238 for (size_t index = 0; index < updateBlocks_.size(); index++) {
239 PATCH_LOGI("DiffImage [%zu] write header patchOffset %zu dataOffset %zu",
240 index, static_cast<size_t>(patchFile.tellp()), dataOffset);
241 patchFile.write(reinterpret_cast<const char*>(&updateBlocks_[index].type), sizeof(uint32_t));
242 int32_t ret = WriteHeader(patchFile, blockPatchFile, dataOffset, updateBlocks_[index]);
243 if (ret != 0) {
244 PATCH_LOGE("Failed to write header");
245 return -1;
246 }
247 }
248
249 int32_t ret = WritePatch(patchFile, blockPatchFile);
250 if (ret != 0) {
251 PATCH_LOGE("Failed to write patch");
252 return -1;
253 }
254 PATCH_LOGI("DiffImage success patchOffset %zu %s", static_cast<size_t>(patchFile.tellp()), patchName.c_str());
255 patchFile.close();
256 return 0;
257 }
258
MakePatch(const std::string & patchName)259 int32_t CompressedImageDiff::MakePatch(const std::string &patchName)
260 {
261 PATCH_DEBUG("CompressedImageDiff::MakePatch %s limit_:%d", patchName.c_str(), limit_);
262 if (newParser_ == nullptr || oldParser_ == nullptr) {
263 PATCH_LOGE("Invalid parser");
264 return -1;
265 }
266 BlockBuffer newBuffer;
267 BlockBuffer oldBuffer;
268 int32_t ret = newParser_->GetPkgBuffer(newBuffer);
269 int32_t ret1 = oldParser_->GetPkgBuffer(oldBuffer);
270 if (ret != 0 || ret1 != 0) {
271 PATCH_LOGE("Failed to get pkgbuffer");
272 return -1;
273 }
274
275 if (limit_ != 0 && newBuffer.length >= limit_) {
276 PatchBuffer oldInfo = { oldBuffer.buffer, 0, oldBuffer.length };
277 PatchBuffer newInfo = { newBuffer.buffer, 0, newBuffer.length };
278 ret = SplitImage(oldInfo, newInfo);
279 PATCH_CHECK(ret == 0, return -1, "Failed to split imgage");
280 return DiffImage(patchName);
281 }
282
283 size_t oldOffset = 0;
284 size_t newOffset = 0;
285 for (size_t i = 0; i < newParser_->GetFileIds().size(); i++) {
286 PATCH_LOGI("CompressedImageDiff::DiffFile %s oldOffset:%zu newOffset:%zu",
287 newParser_->GetFileIds()[i].c_str(), oldOffset, newOffset);
288 ret = DiffFile(newParser_->GetFileIds()[i], oldOffset, newOffset);
289 PATCH_CHECK(ret == 0, break, "Failed to generate patch");
290 }
291 if (ret != 0) {
292 updateBlocks_.clear();
293 return ImageDiff::MakePatch(patchName);
294 }
295 PATCH_LOGI("MakePatch oldOffset:%zu newOffset:%zu newBuffer %zu oldBuffer: %zu",
296 oldOffset, newOffset, newBuffer.length, oldBuffer.length);
297 if (newOffset < newBuffer.length) {
298 ImageBlock block = {
299 BLOCK_RAW,
300 { newBuffer.buffer, newOffset, newBuffer.length - newOffset },
301 { oldBuffer.buffer, oldOffset, oldBuffer.length - oldOffset },
302 };
303 updateBlocks_.push_back(std::move(block));
304 }
305 return DiffImage(patchName);
306 }
307
DiffFile(const std::string & fileName,size_t & oldOffset,size_t & newOffset)308 int32_t CompressedImageDiff::DiffFile(const std::string &fileName, size_t &oldOffset, size_t &newOffset)
309 {
310 BlockBuffer orgNewBuffer;
311 BlockBuffer orgOldBuffer;
312 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
313 int32_t ret1 = oldParser_->GetPkgBuffer(orgOldBuffer);
314 PATCH_CHECK((ret == 0 && ret1 == 0), return -1, "Failed to get pkgbuffer");
315
316 std::vector<uint8_t> newBuffer;
317 std::vector<uint8_t> oldBuffer;
318 ret = newParser_->Extract(fileName, newBuffer);
319 const FileInfo *newFileInfo = newParser_->GetFileInfo(fileName);
320 PATCH_CHECK(ret == 0 && newFileInfo != nullptr, return -1, "Failed to get new data");
321 newOffset += GET_REAL_DATA_LEN(newFileInfo);
322 PATCH_CHECK(limit_ == 0 || newFileInfo->unpackedSize < limit_, return PATCH_EXCEED_LIMIT,
323 "Exceed limit, so make patch by original file");
324
325 ret = oldParser_->Extract(fileName, oldBuffer);
326 if (ret != 0) {
327 ImageBlock block = {
328 BLOCK_RAW,
329 { orgNewBuffer.buffer, newFileInfo->headerOffset, GET_REAL_DATA_LEN(newFileInfo) },
330 { orgOldBuffer.buffer, 0, orgOldBuffer.length },
331 };
332 updateBlocks_.push_back(std::move(block));
333 return 0;
334 }
335 const FileInfo *oldFileInfo = oldParser_->GetFileInfo(fileName);
336 PATCH_CHECK(oldFileInfo != nullptr, return -1, "Failed to get file info");
337 oldOffset += GET_REAL_DATA_LEN(oldFileInfo);
338
339 BlockBuffer newData = {newBuffer.data(), newFileInfo->unpackedSize};
340 ret = TestAndSetConfig(newData, fileName);
341 PATCH_CHECK(ret == 0, return -1, "Failed to test zip config");
342
343 if (type_ != BLOCK_LZ4 && newFileInfo->dataOffset > newFileInfo->headerOffset) {
344 ImageBlock block = {
345 BLOCK_RAW,
346 { orgNewBuffer.buffer, newFileInfo->headerOffset, newFileInfo->dataOffset - newFileInfo->headerOffset },
347 { orgOldBuffer.buffer, oldFileInfo->headerOffset, oldFileInfo->dataOffset - oldFileInfo->headerOffset },
348 };
349 updateBlocks_.push_back(std::move(block));
350 }
351
352 ImageBlock block = {
353 type_,
354 { orgNewBuffer.buffer, newFileInfo->dataOffset, newFileInfo->packedSize },
355 { orgOldBuffer.buffer, oldFileInfo->dataOffset, oldFileInfo->packedSize },
356 };
357 block.srcOriginalData = std::move(oldBuffer);
358 block.destOriginalData = std::move(newBuffer);
359 block.srcOriginalLength = oldFileInfo->unpackedSize;
360 block.destOriginalLength = newFileInfo->unpackedSize;
361 updateBlocks_.push_back(std::move(block));
362 return 0;
363 }
364
WriteHeader(std::ofstream & patchFile,std::fstream & blockPatchFile,size_t & dataOffset,ImageBlock & block) const365 int32_t ZipImageDiff::WriteHeader(std::ofstream &patchFile,
366 std::fstream &blockPatchFile, size_t &dataOffset, ImageBlock &block) const
367 {
368 int32_t ret = 0;
369 if (block.type == BLOCK_DEFLATE) {
370 size_t patchSize = 0;
371 BlockBuffer oldInfo = { block.srcOriginalData.data(), block.srcOriginalLength };
372 BlockBuffer newInfo = { block.destOriginalData.data(), block.destOriginalLength };
373 ret = MakeBlockPatch(block, blockPatchFile, newInfo, oldInfo, patchSize);
374 if (ret != 0) {
375 PATCH_LOGE("Failed to make block patch");
376 return -1;
377 }
378
379 PATCH_LOGI("WriteHeader BLOCK_DEFLATE patchoffset %zu dataOffset:%zu patchData:%zu",
380 static_cast<size_t>(patchFile.tellp()), dataOffset, patchSize);
381 PATCH_LOGI("WriteHeader oldInfo start:%zu length:%zu", block.oldInfo.start, block.oldInfo.length);
382 PATCH_LOGI("WriteHeader uncompressedLength:%zu %zu", block.srcOriginalLength, block.destOriginalLength);
383 PATCH_LOGI("WriteHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
384 level_, method_, windowBits_, memLevel_, strategy_);
385
386 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.start), sizeof(int64_t));
387 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.length), sizeof(int64_t));
388 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(dataOffset), sizeof(int64_t));
389 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.srcOriginalLength), sizeof(int64_t));
390 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.destOriginalLength), sizeof(int64_t));
391
392 WriteToFile<int32_t>(patchFile, level_, sizeof(int32_t));
393 WriteToFile<int32_t>(patchFile, method_, sizeof(int32_t));
394 WriteToFile<int32_t>(patchFile, windowBits_, sizeof(int32_t));
395 WriteToFile<int32_t>(patchFile, memLevel_, sizeof(int32_t));
396 WriteToFile<int32_t>(patchFile, strategy_, sizeof(int32_t));
397 dataOffset += patchSize;
398 } else {
399 ret = ImageDiff::WriteHeader(patchFile, blockPatchFile, dataOffset, block);
400 }
401 return ret;
402 }
403
TestAndSetConfig(const BlockBuffer & buffer,const std::string & fileName)404 int32_t ZipImageDiff::TestAndSetConfig(const BlockBuffer &buffer, const std::string &fileName)
405 {
406 const FileInfo *fileInfo = newParser_->GetFileInfo(fileName);
407 if (fileInfo == nullptr) {
408 PATCH_LOGE("Failed to get file info");
409 return -1;
410 }
411 ZipFileInfo *info = reinterpret_cast<ZipFileInfo *>(const_cast<FileInfo *>(fileInfo));
412 method_ = info->method;
413 level_ = info->level;
414 windowBits_ = info->windowBits;
415 memLevel_ = info->memLevel;
416 strategy_ = info->strategy;
417
418 BlockBuffer orgNewBuffer;
419 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
420 if (ret != 0) {
421 PATCH_LOGE("Failed to get pkgbuffer");
422 return -1;
423 }
424 ZipFileInfo zipInfo {};
425 zipInfo.fileInfo.packMethod = info->fileInfo.packMethod;
426 zipInfo.method = info->method;
427 zipInfo.level = info->level;
428 zipInfo.windowBits = info->windowBits;
429 zipInfo.memLevel = info->memLevel;
430 zipInfo.strategy = info->strategy;
431
432 PATCH_LOGI("TestAndSetConfig new info %zu %zu %zu %zu",
433 fileInfo->unpackedSize, fileInfo->packedSize, fileInfo->dataOffset, fileInfo->headerOffset);
434 PATCH_LOGI("TestAndSetConfig level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
435 level_, method_, windowBits_, memLevel_, strategy_);
436 BlockBuffer orgData = {orgNewBuffer.buffer + fileInfo->dataOffset, fileInfo->packedSize};
437 PATCH_DEBUG("DiffFile new orignial hash %zu %s", fileInfo->packedSize, GeneraterBufferHash(orgData).c_str());
438
439 std::vector<uint8_t> data;
440 for (int32_t i = ZIP_MAX_LEVEL; i >= 0; i--) {
441 zipInfo.level = i;
442 size_t bufferSize = 0;
443 ret = CompressData(&zipInfo.fileInfo, buffer, data, bufferSize);
444 PATCH_CHECK(ret == 0, return -1, "Can not Compress buff ");
445
446 if ((bufferSize == fileInfo->packedSize) &&
447 memcmp(data.data(), orgNewBuffer.buffer + fileInfo->dataOffset, bufferSize) == 0) {
448 level_ = i;
449 return 0;
450 }
451 }
452 return -1;
453 }
454
WriteHeader(std::ofstream & patchFile,std::fstream & blockPatchFile,size_t & dataOffset,ImageBlock & block) const455 int32_t Lz4ImageDiff::WriteHeader(std::ofstream &patchFile,
456 std::fstream &blockPatchFile, size_t &dataOffset, ImageBlock &block) const
457 {
458 int32_t ret = 0;
459 if (block.type == BLOCK_LZ4) {
460 size_t patchSize = 0;
461 BlockBuffer oldInfo = { block.srcOriginalData.data(), block.srcOriginalLength };
462 BlockBuffer newInfo = { block.destOriginalData.data(), block.destOriginalLength };
463 ret = MakeBlockPatch(block, blockPatchFile, newInfo, oldInfo, patchSize);
464 if (ret != 0) {
465 PATCH_LOGE("Failed to make block patch");
466 return -1;
467 }
468
469 PATCH_LOGI("WriteHeader BLOCK_LZ4 patchoffset %zu dataOffset:%zu %zu",
470 static_cast<size_t>(patchFile.tellp()), dataOffset, patchSize);
471 PATCH_LOGI("WriteHeader oldInfo start:%zu length:%zu", block.oldInfo.start, block.oldInfo.length);
472 PATCH_LOGI("WriteHeader uncompressedLength:%zu %zu", block.srcOriginalLength, block.destOriginalLength);
473 PATCH_LOGI("WriteHeader level_:%d method_:%d blockIndependence_:%d contentChecksumFlag_:%d blockSizeID_:%d %d",
474 compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
475 PATCH_LOGI("WriteHeader BLOCK_LZ4 decompressed hash %zu %s",
476 newInfo.length, GeneraterBufferHash(newInfo).c_str());
477 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.start), sizeof(int64_t));
478 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.length), sizeof(int64_t));
479 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(dataOffset), sizeof(int64_t));
480 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.srcOriginalLength), sizeof(int64_t));
481 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.destOriginalLength), sizeof(int64_t));
482
483 int32_t magic = (method_ == PKG_COMPRESS_METHOD_LZ4_BLOCK) ? LZ4B_MAGIC : LZ4S_MAGIC;
484 WriteToFile<int32_t>(patchFile, compressionLevel_, sizeof(int32_t));
485 WriteToFile<int32_t>(patchFile, magic, sizeof(int32_t));
486 WriteToFile<int32_t>(patchFile, blockIndependence_, sizeof(int32_t));
487 WriteToFile<int32_t>(patchFile, contentChecksumFlag_, sizeof(int32_t));
488 WriteToFile<int32_t>(patchFile, blockSizeID_, sizeof(int32_t));
489 WriteToFile<int32_t>(patchFile, autoFlush_, sizeof(int32_t));
490 dataOffset += patchSize;
491 } else {
492 ret = ImageDiff::WriteHeader(patchFile, blockPatchFile, dataOffset, block);
493 }
494 return ret;
495 }
496
TestAndSetConfig(const BlockBuffer & buffer,const std::string & fileName)497 int32_t Lz4ImageDiff::TestAndSetConfig(const BlockBuffer &buffer, const std::string &fileName)
498 {
499 const FileInfo *fileInfo = newParser_->GetFileInfo(fileName);
500 PATCH_CHECK(fileInfo != nullptr, return -1, "Failed to get file info");
501 Lz4FileInfo *info = reinterpret_cast<Lz4FileInfo *>(const_cast<FileInfo *>(fileInfo));
502 method_ = static_cast<int32_t>(info->fileInfo.packMethod);
503 compressionLevel_ = info->compressionLevel;
504 blockIndependence_ = info->blockIndependence;
505 contentChecksumFlag_ = info->contentChecksumFlag;
506 blockSizeID_ = info->blockSizeID;
507 autoFlush_ = info->autoFlush;
508
509 BlockBuffer orgNewBuffer;
510 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
511 PATCH_CHECK(ret == 0, return -1, "Failed to get pkgbuffer");
512 Lz4FileInfo lz4Info {};
513 lz4Info.fileInfo.packMethod = info->fileInfo.packMethod;
514 lz4Info.compressionLevel = info->compressionLevel;
515 lz4Info.blockIndependence = info->blockIndependence;
516 lz4Info.contentChecksumFlag = info->contentChecksumFlag;
517 lz4Info.blockSizeID = info->blockSizeID;
518 lz4Info.autoFlush = info->autoFlush;
519
520 PATCH_DEBUG("TestAndSetConfig level_:%d method_:%d blockIndependence_:%d contentChecksumFlag_:%d blockSizeID_:%d",
521 compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_);
522 PATCH_DEBUG("DiffFile new info %zu %zu %zu %zu",
523 fileInfo->unpackedSize, fileInfo->packedSize, fileInfo->dataOffset, fileInfo->headerOffset);
524 BlockBuffer orgData = { orgNewBuffer.buffer, fileInfo->packedSize + sizeof(uint32_t) };
525 PATCH_DEBUG("DiffFile new orignial hash %zu %s",
526 fileInfo->packedSize + sizeof(uint32_t), GeneraterBufferHash(orgData).c_str());
527
528 std::vector<uint8_t> data;
529 for (int32_t i = 0; i <= LZ4F_MAX_BLOCKID; i++) {
530 lz4Info.blockSizeID = i;
531 size_t bufferSize = 0;
532 ret = CompressData(&lz4Info.fileInfo, buffer, data, bufferSize);
533 PATCH_CHECK(ret == 0, return -1, "Can not Compress buff ");
534
535 if ((bufferSize == fileInfo->packedSize + sizeof(uint32_t)) &&
536 memcmp(data.data(), orgNewBuffer.buffer + fileInfo->headerOffset, bufferSize) == 0) {
537 blockSizeID_ = i;
538 return 0;
539 }
540 }
541 return -1;
542 }
543
CompressData(Hpackage::PkgManager::FileInfoPtr info,const BlockBuffer & buffer,std::vector<uint8_t> & outData,size_t & outSize) const544 int32_t CompressedImageDiff::CompressData(Hpackage::PkgManager::FileInfoPtr info,
545 const BlockBuffer &buffer, std::vector<uint8_t> &outData, size_t &outSize) const
546 {
547 Hpackage::PkgManager *pkgManager = Hpackage::PkgManager::GetPackageInstance();
548 if (pkgManager == nullptr) {
549 PATCH_LOGE("Can not get manager ");
550 return -1;
551 }
552 Hpackage::PkgManager::StreamPtr stream1 = nullptr;
553 pkgManager->CreatePkgStream(stream1, "gzip",
554 [&outData, &outSize](const PkgBuffer &data,
555 size_t size, size_t start, bool isFinish, const void *context) ->int {
556 if (isFinish) {
557 return 0;
558 }
559 outSize += size;
560 if ((start + outSize) > outData.size()) {
561 outData.resize(IGMDIFF_LIMIT_UNIT * ((start + outSize) / IGMDIFF_LIMIT_UNIT + 1));
562 }
563 return memcpy_s(outData.data() + start, outData.size(), data.buffer, size);
564 }, nullptr);
565 int32_t ret = pkgManager->CompressBuffer(info, {buffer.buffer, buffer.length}, stream1);
566 if (ret != 0) {
567 PATCH_LOGE("Can not Compress buff ");
568 return -1;
569 }
570 PATCH_DEBUG("UpdateDiff::MakePatch totalSize: %zu", outSize);
571 return 0;
572 }
573 } // namespace UpdatePatch
574