• 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 "lz4_adapter.h"
17 #include <iostream>
18 #include <vector>
19 #include "lz4.h"
20 #include "lz4frame.h"
21 #include "lz4hc.h"
22 #include "pkg_manager.h"
23 
24 using namespace Hpackage;
25 
26 namespace UpdatePatch {
Lz4Adapter(UpdatePatchWriterPtr outStream,size_t offset,const PkgManager::FileInfoPtr fileInfo)27 Lz4Adapter::Lz4Adapter(UpdatePatchWriterPtr outStream, size_t offset, const PkgManager::FileInfoPtr fileInfo)
28     : DeflateAdapter(), outStream_(outStream), offset_(offset)
29 {
30     const Hpackage::Lz4FileInfo *info = (const Hpackage::Lz4FileInfo *)fileInfo;
31     compressionLevel_ = info->compressionLevel;
32     blockIndependence_ = info->blockIndependence;
33     contentChecksumFlag_ = info->contentChecksumFlag;
34     blockSizeID_ = info->blockSizeID;
35     autoFlush_ = info->autoFlush;
36     if (compressionLevel_ < 1) {
37         compressionLevel_ = LZ4HC_CLEVEL_MIN - 1;
38     }
39     if (compressionLevel_ >= LZ4HC_CLEVEL_MAX) {
40         compressionLevel_ = LZ4HC_CLEVEL_MAX;
41     }
42 }
43 
Open()44 int32_t Lz4FrameAdapter::Open()
45 {
46     if (init_) {
47         PATCH_LOGE("Has been open");
48         return 0;
49     }
50     LZ4F_preferences_t preferences;
51     LZ4F_errorCode_t errorCode = LZ4F_createCompressionContext(&compressionContext_, LZ4F_VERSION);
52     if (LZ4F_isError(errorCode)) {
53         PATCH_LOGE("Failed to create compress context %s", LZ4F_getErrorName(errorCode));
54         return -1;
55     }
56     if (memset_s(&preferences, sizeof(preferences), 0, sizeof(preferences)) != EOK) {
57         PATCH_LOGE("Memset failed");
58         return -1;
59     }
60     preferences.autoFlush = static_cast<uint32_t>(autoFlush_);
61     preferences.compressionLevel = compressionLevel_;
62     preferences.frameInfo.blockMode = ((blockIndependence_ == 0) ? LZ4F_blockLinked : LZ4F_blockIndependent);
63     preferences.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID_;
64     preferences.frameInfo.contentChecksumFlag =
65         ((contentChecksumFlag_ == 0) ? LZ4F_noContentChecksum : LZ4F_contentChecksumEnabled);
66 
67     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
68     blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize;
69     inData_.resize(blockSize);
70     size_t outBuffSize = LZ4F_compressBound(blockSize, &preferences);
71     if (outBuffSize <= 0) {
72         PATCH_LOGE("BufferSize must > 0");
73         return -1;
74     }
75     buffer_.resize(outBuffSize);
76 
77     PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d %d blockSize %zu %zu %zu",
78         static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
79         static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_), autoFlush_,
80         blockSize, LZ4_BLOCK_SIZE(blockSizeID_), outBuffSize);
81 
82     /* write package header */
83     size_t dataSize = LZ4F_compressBegin(compressionContext_, buffer_.data(), buffer_.size(), &preferences);
84     if (LZ4F_isError(dataSize)) {
85         PATCH_LOGE("Failed to generate header %s", LZ4F_getErrorName(dataSize));
86         return -1;
87     }
88     int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
89     PATCH_CHECK(ret == 0, return -1, "Failed to deflate data");
90     offset_ += dataSize;
91     init_ = true;
92     return ret;
93 }
94 
Close()95 int32_t Lz4FrameAdapter::Close()
96 {
97     if (!init_) {
98         PATCH_LOGE("Has been close");
99         return 0;
100     }
101     LZ4F_errorCode_t errorCode = LZ4F_freeCompressionContext(compressionContext_);
102     if (LZ4F_isError(errorCode)) {
103         PATCH_LOGE("Failed to free compress context %s", LZ4F_getErrorName(errorCode));
104         return -1;
105     }
106     init_ = false;
107     return 0;
108 }
109 
WriteData(const BlockBuffer & srcData)110 int32_t Lz4FrameAdapter::WriteData(const BlockBuffer &srcData)
111 {
112     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
113     int32_t ret = 0;
114     if ((currDataSize_ + srcData.length) < inData_.size()) {
115         ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, srcData.length);
116         if (ret != 0) {
117             PATCH_LOGE("Failed to copy data ");
118             return -1;
119         }
120         currDataSize_ += srcData.length;
121     } else {
122         size_t hasCopyLen = inData_.size() - currDataSize_;
123         ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, hasCopyLen);
124         if (ret != 0) {
125             PATCH_LOGE("Failed to copy data ");
126             return -1;
127         }
128 
129         BlockBuffer data = {inData_.data(), inData_.size()};
130         ret = CompressData(data);
131         if (ret != 0) {
132             PATCH_LOGE("Failed to compress data ");
133             return -1;
134         }
135 
136         size_t remainLen = srcData.length - hasCopyLen;
137         currDataSize_ = 0;
138         while (remainLen >= inData_.size()) {
139             size_t length = (blockSize <= remainLen) ? blockSize : remainLen;
140             BlockBuffer blockBuffer = {srcData.buffer + srcData.length - remainLen, length};
141             ret = CompressData(blockBuffer);
142             if (ret != 0) {
143                 PATCH_LOGE("Failed compress data ");
144                 return -1;
145             }
146             remainLen -= length;
147         }
148         if (remainLen > 0) {
149             ret = memcpy_s(inData_.data(), inData_.size(), srcData.buffer + srcData.length - remainLen, remainLen);
150             if (ret != 0) {
151                 PATCH_LOGE("Failed to copy data ");
152                 return -1;
153             }
154             currDataSize_ = remainLen;
155         }
156     }
157     return ret;
158 }
159 
CompressData(const BlockBuffer & srcData)160 int32_t Lz4FrameAdapter::CompressData(const BlockBuffer &srcData)
161 {
162     int32_t ret = 0;
163     size_t dataSize = LZ4F_compressUpdate(compressionContext_,
164         buffer_.data(), buffer_.size(), srcData.buffer, srcData.length, nullptr);
165     if (LZ4F_isError(dataSize)) {
166         PATCH_LOGE("Failed to compress update %s", LZ4F_getErrorName(dataSize));
167         return -1;
168     }
169 
170     if (dataSize > 0) {
171         ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
172         if (ret != 0) {
173             PATCH_LOGE("Failed write data ");
174             return -1;
175         }
176     }
177     offset_ += dataSize;
178     return ret;
179 }
180 
FlushData(size_t & offset)181 int32_t Lz4FrameAdapter::FlushData(size_t &offset)
182 {
183     if (currDataSize_ > 0) {
184         BlockBuffer data = {inData_.data(), currDataSize_};
185         int32_t ret = CompressData(data);
186         if (ret != 0) {
187             PATCH_LOGE("Failed to compress data ");
188             return -1;
189         }
190     }
191     size_t dataSize = LZ4F_compressEnd(compressionContext_, buffer_.data(), buffer_.size(), nullptr);
192     if (LZ4F_isError(dataSize)) {
193         PATCH_LOGE("Failed to compress update end %s", LZ4F_getErrorName(dataSize));
194         return -1;
195     }
196     int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
197     if (ret != 0) {
198         PATCH_LOGE("Failed to deflate data");
199         return -1;
200     }
201     offset_ += dataSize;
202     offset = offset_;
203     return ret;
204 }
205 
Open()206 int32_t Lz4BlockAdapter::Open()
207 {
208     if (init_) {
209         PATCH_LOGE("Has been open");
210         return 0;
211     }
212     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
213     blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize;
214     inData_.resize(blockSize);
215     PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d blockSize %zu %zu %zu",
216         static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
217         static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_),
218         blockSize, LZ4_BLOCK_SIZE(blockSizeID_), LZ4B_BLOCK_SIZE);
219 
220     /* write package */
221     int bufferSize = LZ4_compressBound(LZ4_BLOCK_SIZE(blockSizeID_));
222     if (bufferSize < 0) {
223         PATCH_LOGE("Buffer size should >= 0");
224         return -1;
225     }
226     buffer_.resize(static_cast<size_t>(bufferSize));
227     int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &LZ4B_MAGIC_NUMBER, sizeof(int32_t));
228     if (ret != 0) {
229         PATCH_LOGE("Failed to memcpy ");
230         return -1;
231     }
232     ret = outStream_->Write(offset_, {buffer_.data(), sizeof(int32_t)}, sizeof(int32_t));
233     if (ret != 0) {
234         PATCH_LOGE("Failed to deflate data ");
235         return -1;
236     }
237     offset_ += sizeof(int32_t);
238     init_ = true;
239     return ret;
240 }
241 
Close()242 int32_t Lz4BlockAdapter::Close()
243 {
244     if (!init_) {
245         PATCH_LOGE("Has been close");
246         return 0;
247     }
248     init_ = false;
249     return 0;
250 }
251 
CompressData(const BlockBuffer & srcData)252 int32_t Lz4BlockAdapter::CompressData(const BlockBuffer &srcData)
253 {
254     int32_t dataSize = 0;
255     // Compress Block, reserve 4 bytes to store block size
256     if (compressionLevel_ < LZ4HC_CLEVEL_MIN) { // hc 最小是3
257         dataSize = LZ4_compress_default(reinterpret_cast<const char *>(srcData.buffer),
258             reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN),
259             (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN));
260     } else {
261         dataSize = LZ4_compress_HC(reinterpret_cast<const char *>(srcData.buffer),
262             reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN),
263             (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN),
264             compressionLevel_);
265     }
266     if (dataSize <= 0) {
267         PATCH_LOGE("Failed to compress data dataSize %d ", dataSize);
268         return -1;
269     }
270 
271     // Write block to buffer.
272     // Buffer format: <block size> + <block contents>
273     int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &dataSize, sizeof(int32_t));
274     if (ret != 0) {
275         PATCH_LOGE("Failed to memcpy ");
276         return -1;
277     }
278     dataSize += LZ4B_REVERSED_LEN;
279 
280     ret = outStream_->Write(offset_, {buffer_.data(), static_cast<size_t>(dataSize)}, static_cast<size_t>(dataSize));
281     if (ret != 0) {
282         PATCH_LOGE("Failed to write data ");
283         return -1;
284     }
285     offset_ += static_cast<size_t>(dataSize);
286     return ret;
287 }
288 
FlushData(size_t & offset)289 int32_t Lz4BlockAdapter::FlushData(size_t &offset)
290 {
291     if (currDataSize_ > 0) {
292         BlockBuffer data = {inData_.data(), currDataSize_};
293         int32_t ret = CompressData(data);
294         if (ret != 0) {
295             PATCH_LOGE("Failed to compress data ");
296             return -1;
297         }
298     }
299     offset = offset_;
300     return 0;
301 }
302 } // namespace UpdatePatch
303