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 if (newParser_->GetPkgBuffer(newBuffer) != 0 || oldParser_->GetPkgBuffer(oldBuffer) != 0) {
269 PATCH_LOGE("Failed to get pkgbuffer");
270 return -1;
271 }
272
273 if (limit_ != 0 && newBuffer.length >= limit_) {
274 PatchBuffer oldInfo = { oldBuffer.buffer, 0, oldBuffer.length };
275 PatchBuffer newInfo = { newBuffer.buffer, 0, newBuffer.length };
276 if (SplitImage(oldInfo, newInfo) != 0) {
277 PATCH_LOGE("Failed to split imgage");
278 return -1;
279 }
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 if (DiffFile(newParser_->GetFileIds()[i], oldOffset, newOffset) != 0) {
289 PATCH_LOGE("Failed to generate patch");
290 updateBlocks_.clear();
291 return ImageDiff::MakePatch(patchName);
292 }
293 }
294 PATCH_LOGI("MakePatch oldOffset:%zu newOffset:%zu newBuffer %zu oldBuffer: %zu",
295 oldOffset, newOffset, newBuffer.length, oldBuffer.length);
296 if (newOffset < newBuffer.length) {
297 ImageBlock block = {
298 BLOCK_RAW,
299 { newBuffer.buffer, newOffset, newBuffer.length - newOffset },
300 { oldBuffer.buffer, oldOffset, oldBuffer.length - oldOffset },
301 };
302 updateBlocks_.push_back(std::move(block));
303 }
304 return DiffImage(patchName);
305 }
306
DiffFile(const std::string & fileName,size_t & oldOffset,size_t & newOffset)307 int32_t CompressedImageDiff::DiffFile(const std::string &fileName, size_t &oldOffset, size_t &newOffset)
308 {
309 BlockBuffer orgNewBuffer;
310 BlockBuffer orgOldBuffer;
311 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
312 int32_t ret1 = oldParser_->GetPkgBuffer(orgOldBuffer);
313 if (ret != 0 || ret1 != 0) {
314 PATCH_LOGE("Failed to get pkgbuffer");
315 return -1;
316 }
317 std::vector<uint8_t> newBuffer;
318 std::vector<uint8_t> oldBuffer;
319 ret = newParser_->Extract(fileName, newBuffer);
320 const FileInfo *newFileInfo = newParser_->GetFileInfo(fileName);
321 if (ret != 0 || newFileInfo == nullptr) {
322 PATCH_LOGE("Failed to get new data");
323 return -1;
324 }
325 newOffset += GET_REAL_DATA_LEN(newFileInfo);
326 if (limit_ != 0 && newFileInfo->unpackedSize >= limit_) {
327 PATCH_LOGE("Exceed limit, so make patch by original file");
328 return PATCH_EXCEED_LIMIT;
329 }
330
331 ret = oldParser_->Extract(fileName, oldBuffer);
332 if (ret != 0) {
333 ImageBlock block = {
334 BLOCK_RAW,
335 { orgNewBuffer.buffer, newFileInfo->headerOffset, GET_REAL_DATA_LEN(newFileInfo) },
336 { orgOldBuffer.buffer, 0, orgOldBuffer.length },
337 };
338 updateBlocks_.push_back(std::move(block));
339 return 0;
340 }
341 const FileInfo *oldFileInfo = oldParser_->GetFileInfo(fileName);
342 if (oldFileInfo == nullptr) {
343 PATCH_LOGE("Failed to get file info");
344 return -1;
345 }
346 oldOffset += GET_REAL_DATA_LEN(oldFileInfo);
347
348 BlockBuffer newData = {newBuffer.data(), newFileInfo->unpackedSize};
349 ret = TestAndSetConfig(newData, fileName);
350 if (ret != 0) {
351 PATCH_LOGE("Failed to test zip config");
352 return -1;
353 }
354 std::pair<std::vector<uint8_t>, std::vector<uint8_t>> buffer(std::move(oldBuffer), std::move(newBuffer));
355 UpdateBlocks(orgNewBuffer, newFileInfo, orgOldBuffer, oldFileInfo, buffer);
356 return 0;
357 }
358
UpdateBlocks(const BlockBuffer & orgNewBuffer,const Hpackage::FileInfo * newFileInfo,const BlockBuffer & orgOldBuffer,const Hpackage::FileInfo * oldFileInfo,std::pair<std::vector<uint8_t>,std::vector<uint8_t>> & buffer)359 void CompressedImageDiff::UpdateBlocks(const BlockBuffer &orgNewBuffer, const Hpackage::FileInfo *newFileInfo,
360 const BlockBuffer &orgOldBuffer, const Hpackage::FileInfo *oldFileInfo,
361 std::pair<std::vector<uint8_t>, std::vector<uint8_t>> &buffer)
362 {
363 if (type_ != BLOCK_LZ4 && newFileInfo->dataOffset > newFileInfo->headerOffset) {
364 ImageBlock block = {
365 BLOCK_RAW,
366 { orgNewBuffer.buffer, newFileInfo->headerOffset, newFileInfo->dataOffset - newFileInfo->headerOffset },
367 { orgOldBuffer.buffer, oldFileInfo->headerOffset, oldFileInfo->dataOffset - oldFileInfo->headerOffset },
368 };
369 updateBlocks_.push_back(std::move(block));
370 }
371
372 ImageBlock block = {
373 type_,
374 { orgNewBuffer.buffer, newFileInfo->dataOffset, newFileInfo->packedSize },
375 { orgOldBuffer.buffer, oldFileInfo->dataOffset, oldFileInfo->packedSize },
376 };
377 block.srcOriginalData = std::move(buffer.first);
378 block.destOriginalData = std::move(buffer.second);
379 block.srcOriginalLength = oldFileInfo->unpackedSize;
380 block.destOriginalLength = newFileInfo->unpackedSize;
381 updateBlocks_.push_back(std::move(block));
382 }
383
WriteHeader(std::ofstream & patchFile,std::fstream & blockPatchFile,size_t & dataOffset,ImageBlock & block) const384 int32_t ZipImageDiff::WriteHeader(std::ofstream &patchFile,
385 std::fstream &blockPatchFile, size_t &dataOffset, ImageBlock &block) const
386 {
387 int32_t ret = 0;
388 if (block.type == BLOCK_DEFLATE) {
389 size_t patchSize = 0;
390 BlockBuffer oldInfo = { block.srcOriginalData.data(), block.srcOriginalLength };
391 BlockBuffer newInfo = { block.destOriginalData.data(), block.destOriginalLength };
392 ret = MakeBlockPatch(block, blockPatchFile, newInfo, oldInfo, patchSize);
393 if (ret != 0) {
394 PATCH_LOGE("Failed to make block patch");
395 return -1;
396 }
397
398 PATCH_LOGI("WriteHeader BLOCK_DEFLATE patchoffset %zu dataOffset:%zu patchData:%zu",
399 static_cast<size_t>(patchFile.tellp()), dataOffset, patchSize);
400 PATCH_LOGI("WriteHeader oldInfo start:%zu length:%zu", block.oldInfo.start, block.oldInfo.length);
401 PATCH_LOGI("WriteHeader uncompressedLength:%zu %zu", block.srcOriginalLength, block.destOriginalLength);
402 PATCH_LOGI("WriteHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
403 level_, method_, windowBits_, memLevel_, strategy_);
404
405 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.start), sizeof(int64_t));
406 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.length), sizeof(int64_t));
407 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(dataOffset), sizeof(int64_t));
408 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.srcOriginalLength), sizeof(int64_t));
409 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.destOriginalLength), sizeof(int64_t));
410
411 WriteToFile<int32_t>(patchFile, level_, sizeof(int32_t));
412 WriteToFile<int32_t>(patchFile, method_, sizeof(int32_t));
413 WriteToFile<int32_t>(patchFile, windowBits_, sizeof(int32_t));
414 WriteToFile<int32_t>(patchFile, memLevel_, sizeof(int32_t));
415 WriteToFile<int32_t>(patchFile, strategy_, sizeof(int32_t));
416 dataOffset += patchSize;
417 } else {
418 ret = ImageDiff::WriteHeader(patchFile, blockPatchFile, dataOffset, block);
419 }
420 return ret;
421 }
422
TestAndSetConfig(const BlockBuffer & buffer,const std::string & fileName)423 int32_t ZipImageDiff::TestAndSetConfig(const BlockBuffer &buffer, const std::string &fileName)
424 {
425 const FileInfo *fileInfo = newParser_->GetFileInfo(fileName);
426 if (fileInfo == nullptr) {
427 PATCH_LOGE("Failed to get file info");
428 return -1;
429 }
430 ZipFileInfo *info = (ZipFileInfo *)fileInfo;
431 method_ = info->method;
432 level_ = info->level;
433 windowBits_ = info->windowBits;
434 memLevel_ = info->memLevel;
435 strategy_ = info->strategy;
436
437 BlockBuffer orgNewBuffer;
438 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
439 if (ret != 0) {
440 PATCH_LOGE("Failed to get pkgbuffer");
441 return -1;
442 }
443 ZipFileInfo zipInfo {};
444 zipInfo.fileInfo.packMethod = info->fileInfo.packMethod;
445 zipInfo.method = info->method;
446 zipInfo.level = info->level;
447 zipInfo.windowBits = info->windowBits;
448 zipInfo.memLevel = info->memLevel;
449 zipInfo.strategy = info->strategy;
450
451 PATCH_LOGI("TestAndSetConfig new info %zu %zu %zu %zu",
452 fileInfo->unpackedSize, fileInfo->packedSize, fileInfo->dataOffset, fileInfo->headerOffset);
453 PATCH_LOGI("TestAndSetConfig level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
454 level_, method_, windowBits_, memLevel_, strategy_);
455 BlockBuffer orgData = {orgNewBuffer.buffer + fileInfo->dataOffset, fileInfo->packedSize};
456 PATCH_DEBUG("DiffFile new orignial hash %zu %s", fileInfo->packedSize, GeneraterBufferHash(orgData).c_str());
457 std::vector<uint8_t> data;
458 for (int32_t i = ZIP_MAX_LEVEL; i >= 0; i--) {
459 zipInfo.level = i;
460 size_t bufferSize = 0;
461 ret = CompressData(&zipInfo.fileInfo, buffer, data, bufferSize);
462 if (ret != 0) {
463 PATCH_LOGE("Can not Compress buff");
464 return -1;
465 }
466 if ((bufferSize == fileInfo->packedSize) &&
467 memcmp(data.data(), orgNewBuffer.buffer + fileInfo->dataOffset, bufferSize) == 0) {
468 level_ = i;
469 return 0;
470 }
471 }
472 return -1;
473 }
474
WriteHeader(std::ofstream & patchFile,std::fstream & blockPatchFile,size_t & dataOffset,ImageBlock & block) const475 int32_t Lz4ImageDiff::WriteHeader(std::ofstream &patchFile,
476 std::fstream &blockPatchFile, size_t &dataOffset, ImageBlock &block) const
477 {
478 int32_t ret = 0;
479 if (block.type == BLOCK_LZ4) {
480 size_t patchSize = 0;
481 BlockBuffer oldInfo = { block.srcOriginalData.data(), block.srcOriginalLength };
482 BlockBuffer newInfo = { block.destOriginalData.data(), block.destOriginalLength };
483 ret = MakeBlockPatch(block, blockPatchFile, newInfo, oldInfo, patchSize);
484 if (ret != 0) {
485 PATCH_LOGE("Failed to make block patch");
486 return -1;
487 }
488
489 PATCH_LOGI("WriteHeader BLOCK_LZ4 patchoffset %zu dataOffset:%zu %zu",
490 static_cast<size_t>(patchFile.tellp()), dataOffset, patchSize);
491 PATCH_LOGI("WriteHeader oldInfo start:%zu length:%zu", block.oldInfo.start, block.oldInfo.length);
492 PATCH_LOGI("WriteHeader uncompressedLength:%zu %zu", block.srcOriginalLength, block.destOriginalLength);
493 PATCH_LOGI("WriteHeader level_:%d method_:%d blockIndependence_:%d contentChecksumFlag_:%d blockSizeID_:%d %d",
494 compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
495 PATCH_LOGI("WriteHeader BLOCK_LZ4 decompressed hash %zu %s",
496 newInfo.length, GeneraterBufferHash(newInfo).c_str());
497 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.start), sizeof(int64_t));
498 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.oldInfo.length), sizeof(int64_t));
499 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(dataOffset), sizeof(int64_t));
500 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.srcOriginalLength), sizeof(int64_t));
501 WriteToFile<int64_t>(patchFile, static_cast<int64_t>(block.destOriginalLength), sizeof(int64_t));
502
503 int32_t magic = (method_ == PKG_COMPRESS_METHOD_LZ4_BLOCK) ? LZ4B_MAGIC : LZ4S_MAGIC;
504 WriteToFile<int32_t>(patchFile, compressionLevel_, sizeof(int32_t));
505 WriteToFile<int32_t>(patchFile, magic, sizeof(int32_t));
506 WriteToFile<int32_t>(patchFile, blockIndependence_, sizeof(int32_t));
507 WriteToFile<int32_t>(patchFile, contentChecksumFlag_, sizeof(int32_t));
508 WriteToFile<int32_t>(patchFile, blockSizeID_, sizeof(int32_t));
509 WriteToFile<int32_t>(patchFile, autoFlush_, sizeof(int32_t));
510 dataOffset += patchSize;
511 } else {
512 ret = ImageDiff::WriteHeader(patchFile, blockPatchFile, dataOffset, block);
513 }
514 return ret;
515 }
516
TestAndSetConfig(const BlockBuffer & buffer,const std::string & fileName)517 int32_t Lz4ImageDiff::TestAndSetConfig(const BlockBuffer &buffer, const std::string &fileName)
518 {
519 const FileInfo *fileInfo = newParser_->GetFileInfo(fileName);
520 if (fileInfo == nullptr) {
521 PATCH_LOGE("Failed to get file info");
522 return -1;
523 }
524 Lz4FileInfo *info = (Lz4FileInfo *)fileInfo;
525 method_ = static_cast<int32_t>(info->fileInfo.packMethod);
526 compressionLevel_ = info->compressionLevel;
527 blockIndependence_ = info->blockIndependence;
528 contentChecksumFlag_ = info->contentChecksumFlag;
529 blockSizeID_ = info->blockSizeID;
530 autoFlush_ = info->autoFlush;
531
532 BlockBuffer orgNewBuffer;
533 int32_t ret = newParser_->GetPkgBuffer(orgNewBuffer);
534 if (ret != 0) {
535 PATCH_LOGE("Failed to get pkgbuffer");
536 return -1;
537 }
538 Lz4FileInfo lz4Info {{}, info->compressionLevel, info->blockIndependence, info->contentChecksumFlag,
539 info->blockSizeID, info->autoFlush};
540 lz4Info.fileInfo.packMethod = info->fileInfo.packMethod;
541
542 PATCH_DEBUG("TestAndSetConfig level_:%d method_:%d blockIndependence_:%d contentChecksumFlag_:%d blockSizeID_:%d",
543 compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_);
544 PATCH_DEBUG("DiffFile new info %zu %zu %zu %zu",
545 fileInfo->unpackedSize, fileInfo->packedSize, fileInfo->dataOffset, fileInfo->headerOffset);
546 BlockBuffer orgData = { orgNewBuffer.buffer, fileInfo->packedSize + sizeof(uint32_t) };
547 PATCH_DEBUG("DiffFile new orignial hash %zu %s",
548 fileInfo->packedSize + sizeof(uint32_t), GeneraterBufferHash(orgData).c_str());
549
550 std::vector<uint8_t> data;
551 for (int32_t i = 0; i <= LZ4F_MAX_BLOCKID; i++) {
552 lz4Info.blockSizeID = i;
553 size_t bufferSize = 0;
554 ret = CompressData(&lz4Info.fileInfo, buffer, data, bufferSize);
555 if (ret != 0) {
556 PATCH_LOGE("Can not Compress buff");
557 return -1;
558 }
559 if ((bufferSize == fileInfo->packedSize + sizeof(uint32_t)) &&
560 memcmp(data.data(), orgNewBuffer.buffer + fileInfo->headerOffset, bufferSize) == 0) {
561 blockSizeID_ = i;
562 return 0;
563 }
564 }
565 return -1;
566 }
567
CompressData(Hpackage::PkgManager::FileInfoPtr info,const BlockBuffer & buffer,std::vector<uint8_t> & outData,size_t & outSize) const568 int32_t CompressedImageDiff::CompressData(Hpackage::PkgManager::FileInfoPtr info,
569 const BlockBuffer &buffer, std::vector<uint8_t> &outData, size_t &outSize) const
570 {
571 Hpackage::PkgManager *pkgManager = Hpackage::PkgManager::CreatePackageInstance();
572 if (pkgManager == nullptr) {
573 PATCH_LOGE("Can not get manager ");
574 return -1;
575 }
576 Hpackage::PkgManager::StreamPtr stream1 = nullptr;
577 pkgManager->CreatePkgStream(stream1, "gzip",
578 [&outData, &outSize](const PkgBuffer &data,
579 size_t size, size_t start, bool isFinish, const void *context) ->int {
580 if (isFinish) {
581 return 0;
582 }
583 outSize += size;
584 if ((start + outSize) > outData.size()) {
585 outData.resize(IGMDIFF_LIMIT_UNIT * ((start + outSize) / IGMDIFF_LIMIT_UNIT + 1));
586 }
587 return memcpy_s(outData.data() + start, outData.size(), data.buffer, size);
588 }, nullptr);
589 int32_t ret = pkgManager->CompressBuffer(info, {buffer.buffer, buffer.length}, stream1);
590 if (ret != 0) {
591 PATCH_LOGE("Can not Compress buff ");
592 Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
593 return -1;
594 }
595 PATCH_DEBUG("UpdateDiff::MakePatch totalSize: %zu", outSize);
596 Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
597 return 0;
598 }
599 } // namespace UpdatePatch
600