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