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