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 24using namespace Hpackage; 25 26namespace UpdatePatch { 27Lz4Adapter::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 44int32_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 96int32_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 111int32_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 161int32_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 182int32_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 207int32_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 243int32_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 253int32_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 290int32_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