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