1fb299fa2Sopenharmony_ci/* 2fb299fa2Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License. 5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at 6fb299fa2Sopenharmony_ci * 7fb299fa2Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fb299fa2Sopenharmony_ci * 9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and 13fb299fa2Sopenharmony_ci * limitations under the License. 14fb299fa2Sopenharmony_ci */ 15fb299fa2Sopenharmony_ci 16fb299fa2Sopenharmony_ci#include "lz4_adapter.h" 17fb299fa2Sopenharmony_ci#include <iostream> 18fb299fa2Sopenharmony_ci#include <vector> 19fb299fa2Sopenharmony_ci#include "lz4.h" 20fb299fa2Sopenharmony_ci#include "lz4frame.h" 21fb299fa2Sopenharmony_ci#include "lz4hc.h" 22fb299fa2Sopenharmony_ci#include "pkg_manager.h" 23fb299fa2Sopenharmony_ci 24fb299fa2Sopenharmony_ciusing namespace Hpackage; 25fb299fa2Sopenharmony_ci 26fb299fa2Sopenharmony_cinamespace UpdatePatch { 27fb299fa2Sopenharmony_ciLz4Adapter::Lz4Adapter(UpdatePatchWriterPtr outStream, size_t offset, const PkgManager::FileInfoPtr fileInfo) 28fb299fa2Sopenharmony_ci : DeflateAdapter(), outStream_(outStream), offset_(offset) 29fb299fa2Sopenharmony_ci{ 30fb299fa2Sopenharmony_ci const Hpackage::Lz4FileInfo *info = (const Hpackage::Lz4FileInfo *)fileInfo; 31fb299fa2Sopenharmony_ci compressionLevel_ = info->compressionLevel; 32fb299fa2Sopenharmony_ci blockIndependence_ = info->blockIndependence; 33fb299fa2Sopenharmony_ci contentChecksumFlag_ = info->contentChecksumFlag; 34fb299fa2Sopenharmony_ci blockSizeID_ = info->blockSizeID; 35fb299fa2Sopenharmony_ci autoFlush_ = info->autoFlush; 36fb299fa2Sopenharmony_ci if (compressionLevel_ < 1) { 37fb299fa2Sopenharmony_ci compressionLevel_ = LZ4HC_CLEVEL_MIN - 1; 38fb299fa2Sopenharmony_ci } 39fb299fa2Sopenharmony_ci if (compressionLevel_ >= LZ4HC_CLEVEL_MAX) { 40fb299fa2Sopenharmony_ci compressionLevel_ = LZ4HC_CLEVEL_MAX; 41fb299fa2Sopenharmony_ci } 42fb299fa2Sopenharmony_ci} 43fb299fa2Sopenharmony_ci 44fb299fa2Sopenharmony_ciint32_t Lz4FrameAdapter::Open() 45fb299fa2Sopenharmony_ci{ 46fb299fa2Sopenharmony_ci if (init_) { 47fb299fa2Sopenharmony_ci PATCH_LOGE("Has been open"); 48fb299fa2Sopenharmony_ci return 0; 49fb299fa2Sopenharmony_ci } 50fb299fa2Sopenharmony_ci LZ4F_preferences_t preferences; 51fb299fa2Sopenharmony_ci LZ4F_errorCode_t errorCode = LZ4F_createCompressionContext(&compressionContext_, LZ4F_VERSION); 52fb299fa2Sopenharmony_ci if (LZ4F_isError(errorCode)) { 53fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to create compress context %s", LZ4F_getErrorName(errorCode)); 54fb299fa2Sopenharmony_ci return -1; 55fb299fa2Sopenharmony_ci } 56fb299fa2Sopenharmony_ci if (memset_s(&preferences, sizeof(preferences), 0, sizeof(preferences)) != EOK) { 57fb299fa2Sopenharmony_ci PATCH_LOGE("Memset failed"); 58fb299fa2Sopenharmony_ci return -1; 59fb299fa2Sopenharmony_ci } 60fb299fa2Sopenharmony_ci preferences.autoFlush = static_cast<uint32_t>(autoFlush_); 61fb299fa2Sopenharmony_ci preferences.compressionLevel = compressionLevel_; 62fb299fa2Sopenharmony_ci preferences.frameInfo.blockMode = ((blockIndependence_ == 0) ? LZ4F_blockLinked : LZ4F_blockIndependent); 63fb299fa2Sopenharmony_ci preferences.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID_; 64fb299fa2Sopenharmony_ci preferences.frameInfo.contentChecksumFlag = 65fb299fa2Sopenharmony_ci ((contentChecksumFlag_ == 0) ? LZ4F_noContentChecksum : LZ4F_contentChecksumEnabled); 66fb299fa2Sopenharmony_ci size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_); 67fb299fa2Sopenharmony_ci blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize; 68fb299fa2Sopenharmony_ci inData_.resize(blockSize); 69fb299fa2Sopenharmony_ci size_t outBuffSize = LZ4F_compressBound(blockSize, &preferences); 70fb299fa2Sopenharmony_ci if (outBuffSize <= 0) { 71fb299fa2Sopenharmony_ci PATCH_LOGE("BufferSize must > 0"); 72fb299fa2Sopenharmony_ci return -1; 73fb299fa2Sopenharmony_ci } 74fb299fa2Sopenharmony_ci buffer_.resize(outBuffSize); 75fb299fa2Sopenharmony_ci PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d %d blockSize %zu %zu %zu", 76fb299fa2Sopenharmony_ci static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_), 77fb299fa2Sopenharmony_ci static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_), autoFlush_, 78fb299fa2Sopenharmony_ci blockSize, LZ4_BLOCK_SIZE(blockSizeID_), outBuffSize); 79fb299fa2Sopenharmony_ci 80fb299fa2Sopenharmony_ci /* write package header */ 81fb299fa2Sopenharmony_ci size_t dataSize = LZ4F_compressBegin(compressionContext_, buffer_.data(), buffer_.size(), &preferences); 82fb299fa2Sopenharmony_ci if (LZ4F_isError(dataSize)) { 83fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to generate header %s", LZ4F_getErrorName(dataSize)); 84fb299fa2Sopenharmony_ci return -1; 85fb299fa2Sopenharmony_ci } 86fb299fa2Sopenharmony_ci int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize); 87fb299fa2Sopenharmony_ci if (ret != 0) { 88fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to deflate data"); 89fb299fa2Sopenharmony_ci return -1; 90fb299fa2Sopenharmony_ci } 91fb299fa2Sopenharmony_ci offset_ += dataSize; 92fb299fa2Sopenharmony_ci init_ = true; 93fb299fa2Sopenharmony_ci return ret; 94fb299fa2Sopenharmony_ci} 95fb299fa2Sopenharmony_ci 96fb299fa2Sopenharmony_ciint32_t Lz4FrameAdapter::Close() 97fb299fa2Sopenharmony_ci{ 98fb299fa2Sopenharmony_ci if (!init_) { 99fb299fa2Sopenharmony_ci PATCH_LOGE("Has been close"); 100fb299fa2Sopenharmony_ci return 0; 101fb299fa2Sopenharmony_ci } 102fb299fa2Sopenharmony_ci LZ4F_errorCode_t errorCode = LZ4F_freeCompressionContext(compressionContext_); 103fb299fa2Sopenharmony_ci if (LZ4F_isError(errorCode)) { 104fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to free compress context %s", LZ4F_getErrorName(errorCode)); 105fb299fa2Sopenharmony_ci return -1; 106fb299fa2Sopenharmony_ci } 107fb299fa2Sopenharmony_ci init_ = false; 108fb299fa2Sopenharmony_ci return 0; 109fb299fa2Sopenharmony_ci} 110fb299fa2Sopenharmony_ci 111fb299fa2Sopenharmony_ciint32_t Lz4FrameAdapter::WriteData(const BlockBuffer &srcData) 112fb299fa2Sopenharmony_ci{ 113fb299fa2Sopenharmony_ci size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_); 114fb299fa2Sopenharmony_ci int32_t ret = 0; 115fb299fa2Sopenharmony_ci if ((currDataSize_ + srcData.length) < inData_.size()) { 116fb299fa2Sopenharmony_ci ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, srcData.length); 117fb299fa2Sopenharmony_ci if (ret != 0) { 118fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to copy data "); 119fb299fa2Sopenharmony_ci return -1; 120fb299fa2Sopenharmony_ci } 121fb299fa2Sopenharmony_ci currDataSize_ += srcData.length; 122fb299fa2Sopenharmony_ci } else { 123fb299fa2Sopenharmony_ci size_t hasCopyLen = inData_.size() - currDataSize_; 124fb299fa2Sopenharmony_ci ret = memcpy_s(inData_.data() + currDataSize_, inData_.size(), srcData.buffer, hasCopyLen); 125fb299fa2Sopenharmony_ci if (ret != 0) { 126fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to copy data "); 127fb299fa2Sopenharmony_ci return -1; 128fb299fa2Sopenharmony_ci } 129fb299fa2Sopenharmony_ci 130fb299fa2Sopenharmony_ci BlockBuffer data = {inData_.data(), inData_.size()}; 131fb299fa2Sopenharmony_ci ret = CompressData(data); 132fb299fa2Sopenharmony_ci if (ret != 0) { 133fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress data "); 134fb299fa2Sopenharmony_ci return -1; 135fb299fa2Sopenharmony_ci } 136fb299fa2Sopenharmony_ci 137fb299fa2Sopenharmony_ci size_t remainLen = srcData.length - hasCopyLen; 138fb299fa2Sopenharmony_ci currDataSize_ = 0; 139fb299fa2Sopenharmony_ci while (remainLen >= inData_.size()) { 140fb299fa2Sopenharmony_ci size_t length = (blockSize <= remainLen) ? blockSize : remainLen; 141fb299fa2Sopenharmony_ci BlockBuffer data = {srcData.buffer + srcData.length - remainLen, length}; 142fb299fa2Sopenharmony_ci ret = CompressData(data); 143fb299fa2Sopenharmony_ci if (ret != 0) { 144fb299fa2Sopenharmony_ci PATCH_LOGE("Failed compress data "); 145fb299fa2Sopenharmony_ci return -1; 146fb299fa2Sopenharmony_ci } 147fb299fa2Sopenharmony_ci remainLen -= length; 148fb299fa2Sopenharmony_ci } 149fb299fa2Sopenharmony_ci if (remainLen > 0) { 150fb299fa2Sopenharmony_ci ret = memcpy_s(inData_.data(), inData_.size(), srcData.buffer + srcData.length - remainLen, remainLen); 151fb299fa2Sopenharmony_ci if (ret != 0) { 152fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to copy data "); 153fb299fa2Sopenharmony_ci return -1; 154fb299fa2Sopenharmony_ci } 155fb299fa2Sopenharmony_ci currDataSize_ = remainLen; 156fb299fa2Sopenharmony_ci } 157fb299fa2Sopenharmony_ci } 158fb299fa2Sopenharmony_ci return ret; 159fb299fa2Sopenharmony_ci} 160fb299fa2Sopenharmony_ci 161fb299fa2Sopenharmony_ciint32_t Lz4FrameAdapter::CompressData(const BlockBuffer &srcData) 162fb299fa2Sopenharmony_ci{ 163fb299fa2Sopenharmony_ci int32_t ret = 0; 164fb299fa2Sopenharmony_ci size_t dataSize = LZ4F_compressUpdate(compressionContext_, 165fb299fa2Sopenharmony_ci buffer_.data(), buffer_.size(), srcData.buffer, srcData.length, nullptr); 166fb299fa2Sopenharmony_ci if (LZ4F_isError(dataSize)) { 167fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress update %s", LZ4F_getErrorName(dataSize)); 168fb299fa2Sopenharmony_ci return -1; 169fb299fa2Sopenharmony_ci } 170fb299fa2Sopenharmony_ci 171fb299fa2Sopenharmony_ci if (dataSize > 0) { 172fb299fa2Sopenharmony_ci ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize); 173fb299fa2Sopenharmony_ci if (ret != 0) { 174fb299fa2Sopenharmony_ci PATCH_LOGE("Failed write data "); 175fb299fa2Sopenharmony_ci return -1; 176fb299fa2Sopenharmony_ci } 177fb299fa2Sopenharmony_ci } 178fb299fa2Sopenharmony_ci offset_ += dataSize; 179fb299fa2Sopenharmony_ci return ret; 180fb299fa2Sopenharmony_ci} 181fb299fa2Sopenharmony_ci 182fb299fa2Sopenharmony_ciint32_t Lz4FrameAdapter::FlushData(size_t &offset) 183fb299fa2Sopenharmony_ci{ 184fb299fa2Sopenharmony_ci if (currDataSize_ > 0) { 185fb299fa2Sopenharmony_ci BlockBuffer data = {inData_.data(), currDataSize_}; 186fb299fa2Sopenharmony_ci int32_t ret = CompressData(data); 187fb299fa2Sopenharmony_ci if (ret != 0) { 188fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress data "); 189fb299fa2Sopenharmony_ci return -1; 190fb299fa2Sopenharmony_ci } 191fb299fa2Sopenharmony_ci } 192fb299fa2Sopenharmony_ci size_t dataSize = LZ4F_compressEnd(compressionContext_, buffer_.data(), buffer_.size(), nullptr); 193fb299fa2Sopenharmony_ci if (LZ4F_isError(dataSize)) { 194fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress update end %s", LZ4F_getErrorName(dataSize)); 195fb299fa2Sopenharmony_ci return -1; 196fb299fa2Sopenharmony_ci } 197fb299fa2Sopenharmony_ci int32_t ret = outStream_->Write(offset_, {buffer_.data(), dataSize}, dataSize); 198fb299fa2Sopenharmony_ci if (ret != 0) { 199fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to deflate data"); 200fb299fa2Sopenharmony_ci return -1; 201fb299fa2Sopenharmony_ci } 202fb299fa2Sopenharmony_ci offset_ += dataSize; 203fb299fa2Sopenharmony_ci offset = offset_; 204fb299fa2Sopenharmony_ci return ret; 205fb299fa2Sopenharmony_ci} 206fb299fa2Sopenharmony_ci 207fb299fa2Sopenharmony_ciint32_t Lz4BlockAdapter::Open() 208fb299fa2Sopenharmony_ci{ 209fb299fa2Sopenharmony_ci if (init_) { 210fb299fa2Sopenharmony_ci PATCH_LOGE("Has been open"); 211fb299fa2Sopenharmony_ci return 0; 212fb299fa2Sopenharmony_ci } 213fb299fa2Sopenharmony_ci size_t blockSize = LZ4_BLOCK_SIZE(blockSizeID_); 214fb299fa2Sopenharmony_ci blockSize = (blockSize > LZ4B_BLOCK_SIZE) ? LZ4B_BLOCK_SIZE : blockSize; 215fb299fa2Sopenharmony_ci inData_.resize(blockSize); 216fb299fa2Sopenharmony_ci PATCH_LOGI("frameInfo blockSizeID %d compressionLevel_: %d blockIndependence_:%d %d blockSize %zu %zu %zu", 217fb299fa2Sopenharmony_ci static_cast<int32_t>(blockSizeID_), static_cast<int32_t>(compressionLevel_), 218fb299fa2Sopenharmony_ci static_cast<int32_t>(blockIndependence_), static_cast<int32_t>(contentChecksumFlag_), 219fb299fa2Sopenharmony_ci blockSize, LZ4_BLOCK_SIZE(blockSizeID_), LZ4B_BLOCK_SIZE); 220fb299fa2Sopenharmony_ci 221fb299fa2Sopenharmony_ci /* write package */ 222fb299fa2Sopenharmony_ci int bufferSize = LZ4_compressBound(LZ4_BLOCK_SIZE(blockSizeID_)); 223fb299fa2Sopenharmony_ci if (bufferSize < 0) { 224fb299fa2Sopenharmony_ci PATCH_LOGE("Buffer size should >= 0"); 225fb299fa2Sopenharmony_ci return -1; 226fb299fa2Sopenharmony_ci } 227fb299fa2Sopenharmony_ci buffer_.resize(static_cast<size_t>(bufferSize)); 228fb299fa2Sopenharmony_ci int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &LZ4B_MAGIC_NUMBER, sizeof(int32_t)); 229fb299fa2Sopenharmony_ci if (ret != 0) { 230fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to memcpy "); 231fb299fa2Sopenharmony_ci return -1; 232fb299fa2Sopenharmony_ci } 233fb299fa2Sopenharmony_ci ret = outStream_->Write(offset_, {buffer_.data(), sizeof(int32_t)}, sizeof(int32_t)); 234fb299fa2Sopenharmony_ci if (ret != 0) { 235fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to deflate data "); 236fb299fa2Sopenharmony_ci return -1; 237fb299fa2Sopenharmony_ci } 238fb299fa2Sopenharmony_ci offset_ += sizeof(int32_t); 239fb299fa2Sopenharmony_ci init_ = true; 240fb299fa2Sopenharmony_ci return ret; 241fb299fa2Sopenharmony_ci} 242fb299fa2Sopenharmony_ci 243fb299fa2Sopenharmony_ciint32_t Lz4BlockAdapter::Close() 244fb299fa2Sopenharmony_ci{ 245fb299fa2Sopenharmony_ci if (!init_) { 246fb299fa2Sopenharmony_ci PATCH_LOGE("Has been close"); 247fb299fa2Sopenharmony_ci return 0; 248fb299fa2Sopenharmony_ci } 249fb299fa2Sopenharmony_ci init_ = false; 250fb299fa2Sopenharmony_ci return 0; 251fb299fa2Sopenharmony_ci} 252fb299fa2Sopenharmony_ci 253fb299fa2Sopenharmony_ciint32_t Lz4BlockAdapter::CompressData(const BlockBuffer &srcData) 254fb299fa2Sopenharmony_ci{ 255fb299fa2Sopenharmony_ci int32_t dataSize = 0; 256fb299fa2Sopenharmony_ci // Compress Block, reserve 4 bytes to store block size 257fb299fa2Sopenharmony_ci if (compressionLevel_ < LZ4HC_CLEVEL_MIN) { // hc 最小是3 258fb299fa2Sopenharmony_ci dataSize = LZ4_compress_default(reinterpret_cast<const char *>(srcData.buffer), 259fb299fa2Sopenharmony_ci reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN), 260fb299fa2Sopenharmony_ci (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN)); 261fb299fa2Sopenharmony_ci } else { 262fb299fa2Sopenharmony_ci dataSize = LZ4_compress_HC(reinterpret_cast<const char *>(srcData.buffer), 263fb299fa2Sopenharmony_ci reinterpret_cast<char *>(buffer_.data() + LZ4B_REVERSED_LEN), 264fb299fa2Sopenharmony_ci (int32_t)srcData.length, (int32_t)(buffer_.size() - LZ4B_REVERSED_LEN), 265fb299fa2Sopenharmony_ci compressionLevel_); 266fb299fa2Sopenharmony_ci } 267fb299fa2Sopenharmony_ci if (dataSize <= 0) { 268fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress data dataSize %d ", dataSize); 269fb299fa2Sopenharmony_ci return -1; 270fb299fa2Sopenharmony_ci } 271fb299fa2Sopenharmony_ci 272fb299fa2Sopenharmony_ci // Write block to buffer. 273fb299fa2Sopenharmony_ci // Buffer format: <block size> + <block contents> 274fb299fa2Sopenharmony_ci int32_t ret = memcpy_s(buffer_.data(), buffer_.size(), &dataSize, sizeof(int32_t)); 275fb299fa2Sopenharmony_ci if (ret != 0) { 276fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to memcpy "); 277fb299fa2Sopenharmony_ci return -1; 278fb299fa2Sopenharmony_ci } 279fb299fa2Sopenharmony_ci dataSize += LZ4B_REVERSED_LEN; 280fb299fa2Sopenharmony_ci 281fb299fa2Sopenharmony_ci ret = outStream_->Write(offset_, {buffer_.data(), static_cast<size_t>(dataSize)}, static_cast<size_t>(dataSize)); 282fb299fa2Sopenharmony_ci if (ret != 0) { 283fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to write data "); 284fb299fa2Sopenharmony_ci return -1; 285fb299fa2Sopenharmony_ci } 286fb299fa2Sopenharmony_ci offset_ += static_cast<size_t>(dataSize); 287fb299fa2Sopenharmony_ci return ret; 288fb299fa2Sopenharmony_ci} 289fb299fa2Sopenharmony_ci 290fb299fa2Sopenharmony_ciint32_t Lz4BlockAdapter::FlushData(size_t &offset) 291fb299fa2Sopenharmony_ci{ 292fb299fa2Sopenharmony_ci if (currDataSize_ > 0) { 293fb299fa2Sopenharmony_ci BlockBuffer data = {inData_.data(), currDataSize_}; 294fb299fa2Sopenharmony_ci int32_t ret = CompressData(data); 295fb299fa2Sopenharmony_ci if (ret != 0) { 296fb299fa2Sopenharmony_ci PATCH_LOGE("Failed to compress data "); 297fb299fa2Sopenharmony_ci return -1; 298fb299fa2Sopenharmony_ci } 299fb299fa2Sopenharmony_ci } 300fb299fa2Sopenharmony_ci offset = offset_; 301fb299fa2Sopenharmony_ci return 0; 302fb299fa2Sopenharmony_ci} 303fb299fa2Sopenharmony_ci} // namespace UpdatePatch 304