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 #include "pkg_algo_lz4.h"
16 #include "lz4.h"
17 #include "lz4frame.h"
18 #include "lz4hc.h"
19 #include "pkg_stream.h"
20 #include "pkg_utils.h"
21 #include "securec.h"
22
23 namespace Hpackage {
PkgAlgorithmLz4(const Lz4FileInfo & config)24 PkgAlgorithmLz4::PkgAlgorithmLz4(const Lz4FileInfo &config) : PkgAlgorithm(),
25 compressionLevel_(config.compressionLevel),
26 blockIndependence_(config.blockIndependence),
27 contentChecksumFlag_(config.contentChecksumFlag),
28 blockSizeID_(config.blockSizeID),
29 autoFlush_(config.autoFlush)
30 {
31 // blockIndependence_ 0 LZ4F_blockLinked
32 // contentChecksumFlag_ 0 disable
33 // blockSizeID_ LZ4F_default=0
34 if (compressionLevel_ < 1) {
35 compressionLevel_ = 2; // 2 : set compressionLevel_ 2
36 }
37 if (compressionLevel_ >= LZ4HC_CLEVEL_MAX) {
38 compressionLevel_ = LZ4HC_CLEVEL_MAX;
39 }
40 }
41
AdpLz4Compress(const uint8_t * src,uint8_t * dest,uint32_t srcSize,uint32_t dstCapacity) const42 int32_t PkgAlgorithmLz4::AdpLz4Compress(const uint8_t *src, uint8_t *dest,
43 uint32_t srcSize, uint32_t dstCapacity) const
44 {
45 if (compressionLevel_ < LZ4HC_CLEVEL_MIN) { // hc 最小是3
46 return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dest),
47 static_cast<int32_t>(srcSize), static_cast<int32_t>(dstCapacity));
48 }
49 return LZ4_compress_HC(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dest), srcSize, dstCapacity,
50 compressionLevel_);
51 }
52
AdpLz4Decompress(const uint8_t * src,uint8_t * dest,uint32_t srcSize,uint32_t dstCapacity) const53 int32_t PkgAlgorithmLz4::AdpLz4Decompress(const uint8_t *src, uint8_t *dest, uint32_t srcSize,
54 uint32_t dstCapacity) const
55 {
56 return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dest), srcSize,
57 dstCapacity);
58 }
59
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)60 int32_t PkgAlgorithmBlockLz4::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
61 PkgAlgorithmContext &context)
62 {
63 PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
64 size_t blockSize = static_cast<size_t>(GetBlockSizeFromBlockId(blockSizeID_));
65 blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize;
66 PkgBuffer inBuffer = {blockSize};
67 PkgBuffer outBuffer = {LZ4_compressBound(blockSize)};
68 PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr,
69 return PKG_NONE_MEMORY, "Fail to alloc buffer ");
70
71 PKG_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d contentChecksumFlag_:%d %zu",
72 static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
73 static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_), blockSize);
74
75 size_t srcOffset = context.srcOffset;
76 size_t destOffset = context.destOffset;
77 size_t remainSize = context.unpackedSize;
78 size_t readLen = 0;
79 /* 写包头 */
80 WriteLE32(outBuffer.buffer, LZ4B_MAGIC_NUMBER);
81 int32_t ret = outStream->Write(outBuffer, sizeof(LZ4B_MAGIC_NUMBER), destOffset);
82 PKG_CHECK(ret == PKG_SUCCESS, return ret, "Fail write data ");
83 destOffset += sizeof(LZ4B_MAGIC_NUMBER);
84
85 while (remainSize > 0) {
86 ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
87 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
88
89 // Compress Block, reserve 4 bytes to store block size
90 int32_t outSize = AdpLz4Compress(inBuffer.buffer,
91 outBuffer.buffer + LZ4B_REVERSED_LEN, readLen, outBuffer.length - LZ4B_REVERSED_LEN);
92 PKG_CHECK(outSize > 0, break, "Fail to compress data outSize %d ", outSize);
93
94 // Write block to buffer.
95 // Buffer format: <block size> + <block contents>
96 WriteLE32(outBuffer.buffer, outSize);
97 ret = outStream->Write(outBuffer, outSize + LZ4B_REVERSED_LEN, destOffset);
98 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail write data ");
99
100 srcOffset += readLen;
101 destOffset += static_cast<size_t>(outSize) + LZ4B_REVERSED_LEN;
102 }
103 PKG_CHECK(srcOffset - context.srcOffset == context.unpackedSize,
104 return ret, "original size error %zu %zu", srcOffset, context.unpackedSize);
105 context.packedSize = destOffset - context.destOffset;
106
107 return PKG_SUCCESS;
108 }
109
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)110 int32_t PkgAlgorithmBlockLz4::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
111 PkgAlgorithmContext &context)
112 {
113 PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
114 int inBuffSize = LZ4_compressBound(LZ4B_BLOCK_SIZE);
115 PKG_CHECK(inBuffSize > 0, return PKG_NONE_MEMORY, "BufferSize must > 0");
116 PkgBuffer inBuffer(static_cast<size_t>(inBuffSize));
117 PkgBuffer outBuffer(LZ4B_BLOCK_SIZE);
118 PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr, return PKG_NONE_MEMORY,
119 "Fail to alloc buffer ");
120
121 size_t srcOffset = context.srcOffset;
122 size_t destOffset = context.destOffset;
123 size_t remainSize = context.packedSize;
124 size_t readLen = 0;
125
126 /* Main Loop */
127 while (1) {
128 /* Block Size */
129 inBuffer.length = sizeof(uint32_t);
130 int32_t ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
131 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
132 if (readLen == 0) {
133 break;
134 }
135 uint32_t blockSize = ReadLE32(inBuffer.buffer);
136 PKG_CHECK(!(blockSize > static_cast<uint32_t>(inBuffSize)), break,
137 "Fail to get block size %u %d", blockSize, inBuffSize);
138 srcOffset += sizeof(uint32_t);
139
140 /* Read Block */
141 inBuffer.length = blockSize;
142 ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
143 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
144
145 /* Decode Block */
146 int32_t decodeSize = AdpLz4Decompress(inBuffer.buffer,
147 outBuffer.buffer, readLen, LZ4B_BLOCK_SIZE);
148 PKG_CHECK(decodeSize > 0, break, "Fail to decompress");
149
150 /* Write Block */
151 ret = outStream->Write(outBuffer, decodeSize, destOffset);
152 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail write data ");
153 destOffset += static_cast<size_t>(decodeSize);
154 srcOffset += readLen;
155 }
156 context.packedSize = srcOffset - context.srcOffset;
157 context.unpackedSize = destOffset - context.destOffset;
158 return PKG_SUCCESS;
159 }
160
GetPackParam(LZ4F_compressionContext_t & ctx,LZ4F_preferences_t & preferences,size_t & inBuffSize,size_t & outBuffSize) const161 int32_t PkgAlgorithmLz4::GetPackParam(LZ4F_compressionContext_t &ctx, LZ4F_preferences_t &preferences,
162 size_t &inBuffSize, size_t &outBuffSize) const
163 {
164 LZ4F_errorCode_t errorCode = 0;
165 errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
166 if (LZ4F_isError(errorCode)) {
167 PKG_LOGE("Fail to create compress context %s", LZ4F_getErrorName(errorCode));
168 return PKG_NONE_MEMORY;
169 }
170 size_t blockSize = static_cast<size_t>(GetBlockSizeFromBlockId(blockSizeID_));
171 if (memset_s(&preferences, sizeof(preferences), 0, sizeof(preferences)) != EOK) {
172 PKG_LOGE("Memset failed");
173 return PKG_NONE_MEMORY;
174 }
175 preferences.autoFlush = autoFlush_;
176 preferences.compressionLevel = compressionLevel_;
177 preferences.frameInfo.blockMode = ((blockIndependence_ == 0) ? LZ4F_blockLinked : LZ4F_blockIndependent);
178 preferences.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID_;
179 preferences.frameInfo.contentChecksumFlag =
180 ((contentChecksumFlag_ == 0) ? LZ4F_noContentChecksum : LZ4F_contentChecksumEnabled);
181
182 outBuffSize = LZ4F_compressBound(blockSize, &preferences);
183 if (outBuffSize <= 0) {
184 PKG_LOGE("BufferSize must > 0");
185 return PKG_NONE_MEMORY;
186 }
187 inBuffSize = blockSize;
188
189 PKG_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d contentChecksumFlag_:%d",
190 static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
191 static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_));
192 PKG_LOGI("blockSize %zu %zu %zu", blockSize, GetBlockSizeFromBlockId(blockSizeID_), outBuffSize);
193 return PKG_SUCCESS;
194 }
195
196 /* 打包数据时,会自动生成magic字 */
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)197 int32_t PkgAlgorithmLz4::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
198 PkgAlgorithmContext &context)
199 {
200 PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
201 LZ4F_compressionContext_t ctx;
202 LZ4F_preferences_t preferences;
203 size_t inLength = 0;
204 size_t outLength = 0;
205 int32_t ret = GetPackParam(ctx, preferences, inLength, outLength);
206 PKG_CHECK(ret == PKG_SUCCESS, return PKG_NONE_MEMORY, "Fail to get param for pack");
207
208 PkgBuffer inBuffer(inLength);
209 PkgBuffer outBuffer(outLength);
210 PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr,
211 (void)LZ4F_freeCompressionContext(ctx); return PKG_NONE_MEMORY, "Fail to alloc buffer ");
212 size_t srcOffset = context.srcOffset;
213 size_t destOffset = context.destOffset;
214 size_t remainSize = context.unpackedSize;
215
216 /* 写包头 */
217 size_t dataLen = LZ4F_compressBegin(ctx, outBuffer.buffer, outBuffer.length, &preferences);
218 PKG_CHECK(!LZ4F_isError(dataLen), (void)LZ4F_freeCompressionContext(ctx);
219 return PKG_NONE_MEMORY, "Fail to generate header %s", LZ4F_getErrorName(dataLen));
220 ret = outStream->Write(outBuffer, dataLen, destOffset);
221 PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeCompressionContext(ctx); return ret, "Fail write data ");
222
223 destOffset += dataLen;
224 while (remainSize > 0) {
225 ret = ReadData(inStream, srcOffset, inBuffer, remainSize, dataLen);
226 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
227
228 size_t outSize = LZ4F_compressUpdate(ctx,
229 outBuffer.buffer, outBuffer.length, inBuffer.buffer, dataLen, nullptr);
230 PKG_CHECK(!LZ4F_isError(outSize), ret = PKG_NONE_MEMORY; break,
231 "Fail to compress update %s", LZ4F_getErrorName(outSize));
232 ret = outStream->Write(outBuffer, outSize, destOffset);
233 PKG_CHECK(ret == PKG_SUCCESS, ret = PKG_NONE_MEMORY; break, "Fail write data ");
234
235 srcOffset += dataLen;
236 destOffset += outSize;
237 }
238
239 if (ret == PKG_SUCCESS) {
240 size_t headerSize = LZ4F_compressEnd(ctx, outBuffer.buffer, outBuffer.length, nullptr);
241 PKG_CHECK(!LZ4F_isError(headerSize), (void)LZ4F_freeCompressionContext(ctx);
242 return PKG_NONE_MEMORY, "Fail to compress update end %s", LZ4F_getErrorName(headerSize));
243 ret = outStream->Write(outBuffer, headerSize, destOffset);
244 PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeCompressionContext(ctx); return ret, "Fail write data ");
245 destOffset += headerSize;
246 }
247
248 (void)LZ4F_freeCompressionContext(ctx);
249 PKG_CHECK(srcOffset - context.srcOffset == context.unpackedSize,
250 return ret, "original size error %zu %zu", srcOffset, context.unpackedSize);
251 context.packedSize = destOffset - context.destOffset;
252 return PKG_SUCCESS;
253 }
254
GetUnpackParam(LZ4F_decompressionContext_t & ctx,const PkgStreamPtr inStream,size_t & nextToRead,size_t & srcOffset)255 int32_t PkgAlgorithmLz4::GetUnpackParam(LZ4F_decompressionContext_t &ctx, const PkgStreamPtr inStream,
256 size_t &nextToRead, size_t &srcOffset)
257 {
258 LZ4F_errorCode_t errorCode = 0;
259 LZ4F_frameInfo_t frameInfo;
260
261 errorCode = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
262 PKG_CHECK(!LZ4F_isError(errorCode), return PKG_INVALID_LZ4,
263 "Fail to create compress context %s", LZ4F_getErrorName(errorCode));
264
265 PkgBuffer pkgHeader(LZ4S_HEADER_LEN);
266 WriteLE32(pkgHeader.buffer, LZ4S_MAGIC_NUMBER);
267
268 /* Decode stream descriptor */
269 size_t readLen = 0;
270 size_t outBuffSize = 0;
271 size_t inBuffSize = 0;
272 size_t sizeCheck = sizeof(LZ4B_MAGIC_NUMBER);
273 nextToRead = LZ4F_decompress(ctx, nullptr, &outBuffSize, pkgHeader.buffer, &sizeCheck, nullptr);
274 PKG_CHECK(!LZ4F_isError(nextToRead), (void)LZ4F_freeDecompressionContext(ctx);
275 return PKG_INVALID_LZ4, "Fail to decode frame info %s", LZ4F_getErrorName(nextToRead));
276 PKG_CHECK(nextToRead <= pkgHeader.length, (void)LZ4F_freeDecompressionContext(ctx);
277 return PKG_INVALID_LZ4, "Invalid pkgHeader.length %d", pkgHeader.length);
278
279 size_t remainSize = LZ4S_HEADER_LEN;
280 pkgHeader.length = nextToRead;
281 int32_t ret = ReadData(inStream, srcOffset, pkgHeader, remainSize, readLen);
282 PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4, "Fail read data ");
283 PKG_CHECK(readLen == pkgHeader.length, (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
284 "Invalid len %zu %zu", readLen, pkgHeader.length);
285 srcOffset += readLen;
286 sizeCheck = readLen;
287 nextToRead = LZ4F_decompress(ctx, nullptr, &outBuffSize, pkgHeader.buffer, &sizeCheck, nullptr);
288 errorCode = LZ4F_getFrameInfo(ctx, &frameInfo, nullptr, &inBuffSize);
289 PKG_CHECK(!LZ4F_isError(errorCode), (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
290 "Fail to decode frame info %s", LZ4F_getErrorName(errorCode));
291 PKG_CHECK(frameInfo.blockSizeID >= 3 && frameInfo.blockSizeID <= 7,
292 (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4, "Invalid block size ID %d",
293 frameInfo.blockSizeID);
294
295 blockIndependence_ = frameInfo.blockMode;
296 contentChecksumFlag_ = frameInfo.contentChecksumFlag;
297 blockSizeID_ = frameInfo.blockSizeID;
298 return PKG_SUCCESS;
299 }
300
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)301 int32_t PkgAlgorithmLz4::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
302 PkgAlgorithmContext &context)
303 {
304 PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
305 LZ4F_decompressionContext_t ctx;
306 LZ4F_errorCode_t errorCode = 0;
307 size_t srcOffset = context.srcOffset;
308 size_t destOffset = context.destOffset;
309 size_t remainSize = context.packedSize;
310 size_t nextToRead = 0;
311 int32_t ret = GetUnpackParam(ctx, inStream, nextToRead, srcOffset);
312 PKG_CHECK(ret == PKG_SUCCESS, return PKG_INVALID_LZ4, "Fail to get param ");
313
314 int32_t outBuffSize = GetBlockSizeFromBlockId(blockSizeID_);
315 PKG_LOGI("Block size ID %d outBuffSize:%d", blockSizeID_, outBuffSize);
316 int32_t inBuffSize = outBuffSize + static_cast<int32_t>(sizeof(uint32_t));
317 PKG_CHECK(inBuffSize > 0 && outBuffSize > 0, return PKG_NONE_MEMORY, "Buffer size must > 0");
318
319 PkgBuffer inBuffer(static_cast<size_t>(inBuffSize));
320 PkgBuffer outBuffer(static_cast<size_t>(outBuffSize));
321 PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr,
322 (void)LZ4F_freeDecompressionContext(ctx); return PKG_NONE_MEMORY, "Fail to alloc buffer ");
323
324 /* Main Loop */
325 while (nextToRead != 0) {
326 size_t readLen = 0;
327 size_t decodedBytes = static_cast<size_t>(outBuffSize);
328 PKG_CHECK(nextToRead <= static_cast<size_t>(inBuffSize), break,
329 "Error next read %zu %d ", nextToRead, inBuffSize);
330
331 /* Read Block */
332 inBuffer.length = nextToRead;
333 ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
334 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
335
336 /* Decode Block */
337 size_t sizeCheck = readLen;
338 errorCode = LZ4F_decompress(ctx, outBuffer.buffer,
339 &decodedBytes, inBuffer.buffer, &sizeCheck, nullptr);
340 PKG_CHECK(!LZ4F_isError(errorCode), (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
341 "Fail to decompress %s", LZ4F_getErrorName(errorCode));
342 if (decodedBytes == 0) {
343 srcOffset += readLen;
344 break;
345 }
346 PKG_CHECK(sizeCheck == nextToRead, break, "Error next read %zu %zu ", nextToRead, sizeCheck);
347
348 /* Write Block */
349 ret = outStream->Write(outBuffer, decodedBytes, destOffset);
350 PKG_CHECK(ret == PKG_SUCCESS, break, "Fail write data ");
351 destOffset += decodedBytes;
352 srcOffset += readLen;
353 nextToRead = errorCode;
354 }
355 errorCode = LZ4F_freeDecompressionContext(ctx);
356 PKG_CHECK(!LZ4F_isError(errorCode), return PKG_NONE_MEMORY,
357 "Fail to free compress context %s", LZ4F_getErrorName(errorCode));
358 context.packedSize = srcOffset - context.srcOffset;
359 context.unpackedSize = destOffset - context.destOffset;
360 return ret;
361 }
362
UpdateFileInfo(PkgManager::FileInfoPtr info) const363 void PkgAlgorithmLz4::UpdateFileInfo(PkgManager::FileInfoPtr info) const
364 {
365 Lz4FileInfo *lz4Info = (Lz4FileInfo *)info;
366 lz4Info->fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
367 lz4Info->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
368 lz4Info->compressionLevel = compressionLevel_;
369 lz4Info->blockIndependence = blockIndependence_;
370 lz4Info->contentChecksumFlag = contentChecksumFlag_;
371 lz4Info->blockSizeID = blockSizeID_;
372 lz4Info->autoFlush = autoFlush_;
373 }
374 } // namespace Hpackage
375