• 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 #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