• 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;
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             (int32_t)srcSize, (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 = 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 += 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     size_t inBuffSize = LZ4_compressBound(LZ4B_BLOCK_SIZE);
115     PKG_CHECK(inBuffSize > 0, return PKG_NONE_MEMORY, "BufferSize must > 0");
116     PkgBuffer inBuffer(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 > LZ4_COMPRESSBOUND(LZ4B_BLOCK_SIZE) || blockSize > inBuffSize), break,
137             "Fail to get block size %u  %u", blockSize, LZ4_COMPRESSBOUND(LZ4B_BLOCK_SIZE));
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 += 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     PKG_CHECK(!LZ4F_isError(errorCode), return PKG_NONE_MEMORY,
167         "Fail to create compress context %s", LZ4F_getErrorName(errorCode));
168     size_t blockSize = GetBlockSizeFromBlockId(blockSizeID_);
169     PKG_CHECK(!memset_s(&preferences, sizeof(preferences), 0, sizeof(preferences)),
170         return PKG_NONE_MEMORY, "Memset failed");
171     preferences.autoFlush = autoFlush_;
172     preferences.compressionLevel = compressionLevel_;
173     preferences.frameInfo.blockMode = ((blockIndependence_ == 0) ? LZ4F_blockLinked : LZ4F_blockIndependent);
174     preferences.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID_;
175     preferences.frameInfo.contentChecksumFlag =
176         ((contentChecksumFlag_ == 0) ? LZ4F_noContentChecksum : LZ4F_contentChecksumEnabled);
177 
178     outBuffSize = LZ4F_compressBound(blockSize, &preferences);
179     PKG_CHECK(outBuffSize > 0, return PKG_NONE_MEMORY, "BufferSize must > 0");
180     inBuffSize = blockSize;
181 
182     PKG_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d contentChecksumFlag_:%d",
183         static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
184         static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_));
185     PKG_LOGI("blockSize %zu %zu %zu", blockSize, GetBlockSizeFromBlockId(blockSizeID_), outBuffSize);
186     return PKG_SUCCESS;
187 }
188 
189 /* 打包数据时,会自动生成magic字 */
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)190 int32_t PkgAlgorithmLz4::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
191     PkgAlgorithmContext &context)
192 {
193     PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
194     LZ4F_compressionContext_t ctx;
195     LZ4F_preferences_t preferences;
196     size_t inLength = 0;
197     size_t outLength = 0;
198     int32_t ret = GetPackParam(ctx, preferences, inLength, outLength);
199     PKG_CHECK(ret == PKG_SUCCESS, return PKG_NONE_MEMORY, "Fail to get param for pack");
200 
201     PkgBuffer inBuffer(inLength);
202     PkgBuffer outBuffer(outLength);
203     PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr,
204         (void)LZ4F_freeCompressionContext(ctx); return PKG_NONE_MEMORY, "Fail to alloc buffer ");
205     size_t srcOffset = context.srcOffset;
206     size_t destOffset = context.destOffset;
207     size_t remainSize = context.unpackedSize;
208 
209     /* 写包头 */
210     size_t dataLen = LZ4F_compressBegin(ctx, outBuffer.buffer, outBuffer.length, &preferences);
211     PKG_CHECK(!LZ4F_isError(dataLen), (void)LZ4F_freeCompressionContext(ctx);
212         return PKG_NONE_MEMORY, "Fail to generate header %s", LZ4F_getErrorName(dataLen));
213     ret = outStream->Write(outBuffer, dataLen, destOffset);
214     PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeCompressionContext(ctx); return ret, "Fail write data ");
215 
216     destOffset += dataLen;
217     while (remainSize > 0) {
218         ret = ReadData(inStream, srcOffset, inBuffer, remainSize, dataLen);
219         PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
220 
221         size_t outSize = LZ4F_compressUpdate(ctx,
222             outBuffer.buffer, outBuffer.length, inBuffer.buffer, dataLen, nullptr);
223         PKG_CHECK(!LZ4F_isError(outSize), ret = PKG_NONE_MEMORY; break,
224             "Fail to compress update %s", LZ4F_getErrorName(outSize));
225         ret = outStream->Write(outBuffer, outSize, destOffset);
226         PKG_CHECK(ret == PKG_SUCCESS, ret = PKG_NONE_MEMORY; break, "Fail write data ");
227 
228         srcOffset += dataLen;
229         destOffset += outSize;
230     }
231 
232     if (ret == PKG_SUCCESS) {
233         size_t headerSize = LZ4F_compressEnd(ctx, outBuffer.buffer, outBuffer.length, nullptr);
234         PKG_CHECK(!LZ4F_isError(headerSize), (void)LZ4F_freeCompressionContext(ctx);
235             return PKG_NONE_MEMORY, "Fail to compress update end %s", LZ4F_getErrorName(headerSize));
236         ret = outStream->Write(outBuffer, headerSize, destOffset);
237         PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeCompressionContext(ctx); return ret, "Fail write data ");
238         destOffset += headerSize;
239     }
240 
241     (void)LZ4F_freeCompressionContext(ctx);
242     PKG_CHECK(srcOffset - context.srcOffset == context.unpackedSize,
243         return ret, "original size error %zu %zu", srcOffset, context.unpackedSize);
244     context.packedSize = destOffset - context.destOffset;
245     return PKG_SUCCESS;
246 }
247 
GetUnpackParam(LZ4F_decompressionContext_t & ctx,const PkgStreamPtr inStream,size_t & nextToRead,size_t & srcOffset)248 int32_t PkgAlgorithmLz4::GetUnpackParam(LZ4F_decompressionContext_t &ctx, const PkgStreamPtr inStream,
249     size_t &nextToRead, size_t &srcOffset)
250 {
251     LZ4F_errorCode_t errorCode = 0;
252     LZ4F_frameInfo_t frameInfo;
253 
254     errorCode = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
255     PKG_CHECK(!LZ4F_isError(errorCode), return PKG_INVALID_LZ4,
256         "Fail to create compress context %s", LZ4F_getErrorName(errorCode));
257 
258     PkgBuffer pkgHeader(LZ4S_HEADER_LEN);
259     WriteLE32(pkgHeader.buffer, LZ4S_MAGIC_NUMBER);
260 
261     /* Decode stream descriptor */
262     size_t readLen = 0;
263     size_t outBuffSize = 0;
264     size_t inBuffSize = 0;
265     size_t sizeCheck = sizeof(LZ4B_MAGIC_NUMBER);
266     nextToRead = LZ4F_decompress(ctx, nullptr, &outBuffSize, pkgHeader.buffer, &sizeCheck, nullptr);
267     PKG_CHECK(!LZ4F_isError(nextToRead), (void)LZ4F_freeDecompressionContext(ctx);
268         return PKG_INVALID_LZ4, "Fail to decode frame info %s", LZ4F_getErrorName(nextToRead));
269     PKG_CHECK(nextToRead <= pkgHeader.length, (void)LZ4F_freeDecompressionContext(ctx);
270         return PKG_INVALID_LZ4, "Invalid pkgHeader.length %d", pkgHeader.length);
271 
272     size_t remainSize = LZ4S_HEADER_LEN;
273     pkgHeader.length = nextToRead;
274     int32_t ret = ReadData(inStream, srcOffset, pkgHeader, remainSize, readLen);
275     PKG_CHECK(ret == PKG_SUCCESS, (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4, "Fail read data ");
276     PKG_CHECK(readLen == pkgHeader.length, (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
277         "Invalid len %zu %zu", readLen, pkgHeader.length);
278     srcOffset += readLen;
279     sizeCheck = readLen;
280     nextToRead = LZ4F_decompress(ctx, nullptr, &outBuffSize, pkgHeader.buffer, &sizeCheck, nullptr);
281     errorCode = LZ4F_getFrameInfo(ctx, &frameInfo, nullptr, &inBuffSize);
282     PKG_CHECK(!LZ4F_isError(errorCode), (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
283         "Fail to decode frame info %s", LZ4F_getErrorName(errorCode));
284     PKG_CHECK(frameInfo.blockSizeID >= 3 && frameInfo.blockSizeID <= 7,
285         (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4, "Invalid block size ID %d",
286         frameInfo.blockSizeID);
287 
288     blockIndependence_ = frameInfo.blockMode;
289     contentChecksumFlag_ = frameInfo.contentChecksumFlag;
290     blockSizeID_ = frameInfo.blockSizeID;
291     return PKG_SUCCESS;
292 }
293 
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)294 int32_t PkgAlgorithmLz4::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
295     PkgAlgorithmContext &context)
296 {
297     PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
298     LZ4F_decompressionContext_t ctx;
299     LZ4F_errorCode_t errorCode = 0;
300     size_t srcOffset = context.srcOffset;
301     size_t destOffset = context.destOffset;
302     size_t remainSize = context.packedSize;
303     size_t nextToRead = 0;
304     int32_t ret = GetUnpackParam(ctx, inStream, nextToRead, srcOffset);
305     PKG_CHECK(ret == PKG_SUCCESS, return PKG_INVALID_LZ4, "Fail to get param ");
306 
307     size_t outBuffSize = GetBlockSizeFromBlockId(blockSizeID_);
308     PKG_LOGI("Block size ID %d outBuffSize:%zu", blockSizeID_, outBuffSize);
309     size_t inBuffSize = outBuffSize + sizeof(uint32_t);
310     PKG_CHECK(inBuffSize > 0 && outBuffSize > 0, return PKG_NONE_MEMORY, "Buffer size must > 0");
311 
312     PkgBuffer inBuffer(inBuffSize);
313     PkgBuffer outBuffer(outBuffSize);
314     PKG_CHECK(inBuffer.buffer != nullptr && outBuffer.buffer != nullptr,
315         (void)LZ4F_freeDecompressionContext(ctx); return PKG_NONE_MEMORY, "Fail to alloc buffer ");
316 
317     /* Main Loop */
318     while (nextToRead != 0) {
319         size_t readLen = 0;
320         size_t decodedBytes = outBuffSize;
321         PKG_CHECK(nextToRead <= inBuffSize, break, "Error next read %zu %zu ", nextToRead, inBuffSize);
322 
323         /* Read Block */
324         inBuffer.length = nextToRead;
325         ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
326         PKG_CHECK(ret == PKG_SUCCESS, break, "Fail read data ");
327 
328         /* Decode Block */
329         size_t sizeCheck = readLen;
330         errorCode = LZ4F_decompress(ctx, outBuffer.buffer,
331             &decodedBytes, inBuffer.buffer, &sizeCheck, nullptr);
332         PKG_CHECK(!LZ4F_isError(errorCode), (void)LZ4F_freeDecompressionContext(ctx); return PKG_INVALID_LZ4,
333             "Fail to decompress %s", LZ4F_getErrorName(errorCode));
334         if (decodedBytes == 0) {
335             srcOffset += readLen;
336             break;
337         }
338         PKG_CHECK(sizeCheck == nextToRead, break, "Error next read %zu %zu ", nextToRead, sizeCheck);
339 
340         /* Write Block */
341         ret = outStream->Write(outBuffer, decodedBytes, destOffset);
342         PKG_CHECK(ret == PKG_SUCCESS, break, "Fail write data ");
343         destOffset += decodedBytes;
344         srcOffset += readLen;
345         nextToRead = errorCode;
346     }
347     errorCode = LZ4F_freeDecompressionContext(ctx);
348     PKG_CHECK(!LZ4F_isError(errorCode), return PKG_NONE_MEMORY,
349         "Fail to free compress context %s", LZ4F_getErrorName(errorCode));
350     context.packedSize = srcOffset - context.srcOffset;
351     context.unpackedSize = destOffset - context.destOffset;
352     return ret;
353 }
354 
UpdateFileInfo(PkgManager::FileInfoPtr info) const355 void PkgAlgorithmLz4::UpdateFileInfo(PkgManager::FileInfoPtr info) const
356 {
357     Lz4FileInfo *lz4Info = (Lz4FileInfo *)info;
358     lz4Info->fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
359     lz4Info->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
360     lz4Info->compressionLevel = compressionLevel_;
361     lz4Info->blockIndependence = blockIndependence_;
362     lz4Info->contentChecksumFlag = contentChecksumFlag_;
363     lz4Info->blockSizeID = blockSizeID_;
364     lz4Info->autoFlush = autoFlush_;
365 }
366 } // namespace hpackage
367