• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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