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     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
67     blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize;
68     inData_.resize(blockSize);
69     size_t outBuffSize = LZ4F_compressBound(blockSize, &preferences);
70     if (outBuffSize <= 0) {
71         PATCH_LOGE("BufferSize must > 0");
72         return -1;
73     }
74     buffer_.resize(outBuffSize);
75     PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d %d blockSize %zu %zu %zu",
76         static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
77         static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_), autoFlush_,
78         blockSize, LZ4_BLOCK_SIZE(blockSizeID_), outBuffSize);
79 
80     /* write package header */
81     size_t dataSize = LZ4F_compressBegin(compressionContext_, buffer_.data(), buffer_.size(), &preferences);
82     if (LZ4F_isError(dataSize)) {
83         PATCH_LOGE("Failed to generate header %s", LZ4F_getErrorName(dataSize));
84         return -1;
85     }
86     int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
87     if (ret != 0) {
88         PATCH_LOGE("Failed to deflate data");
89         return -1;
90     }
91     offset_ += dataSize;
92     init_ = true;
93     return ret;
94 }
95 
Close()96 int32_t Lz4FrameAdapter::Close()
97 {
98     if (!init_) {
99         PATCH_LOGE("Has been close");
100         return 0;
101     }
102     LZ4F_errorCode_t errorCode = LZ4F_freeCompressionContext(compressionContext_);
103     if (LZ4F_isError(errorCode)) {
104         PATCH_LOGE("Failed to free compress context %s", LZ4F_getErrorName(errorCode));
105         return -1;
106     }
107     init_ = false;
108     return 0;
109 }
110 
WriteData(const BlockBuffer & srcData)111 int32_t Lz4FrameAdapter::WriteData(const BlockBuffer &srcData)
112 {
113     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
114     int32_t ret = 0;
115     if ((currDataSize_ + srcData.length) < inData_.size()) {
116         ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, srcData.length);
117         if (ret != 0) {
118             PATCH_LOGE("Failed to copy data ");
119             return -1;
120         }
121         currDataSize_ += srcData.length;
122     } else {
123         size_t hasCopyLen = inData_.size() - currDataSize_;
124         ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, hasCopyLen);
125         if (ret != 0) {
126             PATCH_LOGE("Failed to copy data ");
127             return -1;
128         }
129 
130         BlockBuffer data = {inData_.data(), inData_.size()};
131         ret = CompressData(data);
132         if (ret != 0) {
133             PATCH_LOGE("Failed to compress data ");
134             return -1;
135         }
136 
137         size_t remainLen = srcData.length - hasCopyLen;
138         currDataSize_ = 0;
139         while (remainLen >= inData_.size()) {
140             size_t length = (blockSize <= remainLen) ? blockSize : remainLen;
141             BlockBuffer data = {srcData.buffer + srcData.length - remainLen, length};
142             ret = CompressData(data);
143             if (ret != 0) {
144                 PATCH_LOGE("Failed compress data ");
145                 return -1;
146             }
147             remainLen -= length;
148         }
149         if (remainLen > 0) {
150             ret = memcpy_s(inData_.data(), inData_.size(), srcData.buffer + srcData.length - remainLen, remainLen);
151             if (ret != 0) {
152                 PATCH_LOGE("Failed to copy data ");
153                 return -1;
154             }
155             currDataSize_ = remainLen;
156         }
157     }
158     return ret;
159 }
160 
CompressData(const BlockBuffer & srcData)161 int32_t Lz4FrameAdapter::CompressData(const BlockBuffer &srcData)
162 {
163     int32_t ret = 0;
164     size_t dataSize = LZ4F_compressUpdate(compressionContext_,
165         buffer_.data(), buffer_.size(), srcData.buffer, srcData.length, nullptr);
166     if (LZ4F_isError(dataSize)) {
167         PATCH_LOGE("Failed to compress update %s", LZ4F_getErrorName(dataSize));
168         return -1;
169     }
170 
171     if (dataSize > 0) {
172         ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
173         if (ret != 0) {
174             PATCH_LOGE("Failed write data ");
175             return -1;
176         }
177     }
178     offset_ += dataSize;
179     return ret;
180 }
181 
FlushData(size_t & offset)182 int32_t Lz4FrameAdapter::FlushData(size_t &offset)
183 {
184     if (currDataSize_ > 0) {
185         BlockBuffer data = {inData_.data(), currDataSize_};
186         int32_t ret = CompressData(data);
187         if (ret != 0) {
188             PATCH_LOGE("Failed to compress data ");
189             return -1;
190         }
191     }
192     size_t dataSize = LZ4F_compressEnd(compressionContext_, buffer_.data(), buffer_.size(), nullptr);
193     if (LZ4F_isError(dataSize)) {
194         PATCH_LOGE("Failed to compress update end %s", LZ4F_getErrorName(dataSize));
195         return -1;
196     }
197     int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize);
198     if (ret != 0) {
199         PATCH_LOGE("Failed to deflate data");
200         return -1;
201     }
202     offset_ += dataSize;
203     offset = offset_;
204     return ret;
205 }
206 
Open()207 int32_t Lz4BlockAdapter::Open()
208 {
209     if (init_) {
210         PATCH_LOGE("Has been open");
211         return 0;
212     }
213     size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_);
214     blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize;
215     inData_.resize(blockSize);
216     PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d blockSize %zu %zu %zu",
217         static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_),
218         static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_),
219         blockSize, LZ4_BLOCK_SIZE(blockSizeID_), LZ4B_BLOCK_SIZE);
220 
221     /* write package */
222     int bufferSize = LZ4_compressBound(LZ4_BLOCK_SIZE(blockSizeID_));
223     if (bufferSize < 0) {
224         PATCH_LOGE("Buffer size should >= 0");
225         return -1;
226     }
227     buffer_.resize(static_cast<size_t>(bufferSize));
228     int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &LZ4B_MAGIC_NUMBER, sizeof(int32_t));
229     if (ret != 0) {
230         PATCH_LOGE("Failed to memcpy ");
231         return -1;
232     }
233     ret = outStream_->Write(offset_, {buffer_.data(), sizeof(int32_t)}, sizeof(int32_t));
234     if (ret != 0) {
235         PATCH_LOGE("Failed to deflate data ");
236         return -1;
237     }
238     offset_ += sizeof(int32_t);
239     init_ = true;
240     return ret;
241 }
242 
Close()243 int32_t Lz4BlockAdapter::Close()
244 {
245     if (!init_) {
246         PATCH_LOGE("Has been close");
247         return 0;
248     }
249     init_ = false;
250     return 0;
251 }
252 
CompressData(const BlockBuffer & srcData)253 int32_t Lz4BlockAdapter::CompressData(const BlockBuffer &srcData)
254 {
255     int32_t dataSize = 0;
256     // Compress Block, reserve 4 bytes to store block size
257     if (compressionLevel_ < LZ4HC_CLEVEL_MIN) { // hc 最小是3
258         dataSize = LZ4_compress_default(reinterpret_cast<const char *>(srcData.buffer),
259             reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN),
260             (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN));
261     } else {
262         dataSize = LZ4_compress_HC(reinterpret_cast<const char *>(srcData.buffer),
263             reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN),
264             (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN),
265             compressionLevel_);
266     }
267     if (dataSize <= 0) {
268         PATCH_LOGE("Failed to compress data dataSize %d ", dataSize);
269         return -1;
270     }
271 
272     // Write block to buffer.
273     // Buffer format: <block size> + <block contents>
274     int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &dataSize, sizeof(int32_t));
275     if (ret != 0) {
276         PATCH_LOGE("Failed to memcpy ");
277         return -1;
278     }
279     dataSize += LZ4B_REVERSED_LEN;
280 
281     ret = outStream_->Write(offset_, {buffer_.data(), static_cast<size_t>(dataSize)}, static_cast<size_t>(dataSize));
282     if (ret != 0) {
283         PATCH_LOGE("Failed to write data ");
284         return -1;
285     }
286     offset_ += static_cast<size_t>(dataSize);
287     return ret;
288 }
289 
FlushData(size_t & offset)290 int32_t Lz4BlockAdapter::FlushData(size_t &offset)
291 {
292     if (currDataSize_ > 0) {
293         BlockBuffer data = {inData_.data(), currDataSize_};
294         int32_t ret = CompressData(data);
295         if (ret != 0) {
296             PATCH_LOGE("Failed to compress data ");
297             return -1;
298         }
299     }
300     offset = offset_;
301     return 0;
302 }
303 } // namespace UpdatePatch
304