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#include "bzip2_adapter.h"
16#include <iostream>
17#include "bzlib.h"
18
19using namespace Hpackage;
20
21namespace UpdatePatch {
22int32_t BZip2Adapter::Open()
23{
24    (void)memset_s(&stream_, sizeof(bz_stream), 0, sizeof(bz_stream));
25    int32_t ret = BZ2_bzCompressInit(&stream_, BLOCK_SIZE_BEST, 0, 0);
26    if (ret != BZ_OK) {
27        PATCH_LOGE("Failed to bzcompressinit %d", ret);
28        return ret;
29    }
30    init_ = true;
31    return ret;
32}
33
34int32_t BZip2Adapter::Close()
35{
36    if (!init_) {
37        return PATCH_SUCCESS;
38    }
39    int32_t ret = BZ2_bzCompressEnd(&stream_);
40    if (ret != BZ_OK) {
41        PATCH_LOGE("Failed to bz_compressEnd %d", ret);
42        return ret;
43    }
44    init_ = false;
45    return ret;
46}
47
48int32_t BZipBuffer2Adapter::WriteData(const BlockBuffer &srcData)
49{
50    stream_.next_in = reinterpret_cast<char*>(srcData.buffer);
51    stream_.avail_in = srcData.length;
52
53    char *next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
54    stream_.avail_out = buffer_.size() - offset_ - dataSize_;
55    stream_.next_out = next;
56    int32_t ret = BZ_RUN_OK;
57    do {
58        ret = BZ2_bzCompress(&stream_, BZ_RUN);
59        if (stream_.avail_out == 0) {
60            dataSize_ += stream_.next_out - next;
61            size_t bufferSize =  buffer_.size();
62            buffer_.resize(bufferSize + IGMDIFF_LIMIT_UNIT);
63            stream_.avail_out = IGMDIFF_LIMIT_UNIT;
64            next = reinterpret_cast<char*>(buffer_.data() + bufferSize);
65            stream_.next_out = next;
66        }
67        if (stream_.avail_in == 0) {
68            break;
69        }
70    } while (ret == BZ_RUN_OK);
71    if (ret != BZ_RUN_OK) {
72        PATCH_LOGE("BZipBuffer2Adapter::WriteData : Failed to write data ret %d", ret);
73        return ret;
74    }
75    if (stream_.avail_in != 0) {
76        PATCH_LOGE("BZipBuffer2Adapter::WriteData : Failed to write data");
77        return ret;
78    }
79    dataSize_ += stream_.next_out - next;
80    return PATCH_SUCCESS;
81}
82
83int32_t BZipBuffer2Adapter::FlushData(size_t &dataSize)
84{
85    dataSize = 0;
86    PATCH_DEBUG("FlushData dataSize_ %d ", dataSize_);
87    stream_.next_in = nullptr;
88    stream_.avail_in = 0;
89    stream_.avail_out = buffer_.size() - offset_ - dataSize_;
90    char *next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
91    stream_.next_out = next;
92    int ret = BZ_FINISH_OK;
93    while (ret == BZ_FINISH_OK) {
94        ret = BZ2_bzCompress(&stream_, BZ_FINISH);
95        if (stream_.avail_out == 0) {
96            dataSize_ += stream_.next_out - next;
97            buffer_.resize(buffer_.size() + IGMDIFF_LIMIT_UNIT);
98            stream_.avail_out = buffer_.size() - offset_ - dataSize_;
99            next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
100            stream_.next_out = next;
101        }
102    }
103    if (ret != BZ_RUN_OK && ret != BZ_STREAM_END) {
104        PATCH_LOGE("Failed to write data %d", ret);
105        return ret;
106    }
107    dataSize_ += stream_.next_out - next;
108    PATCH_DEBUG("FlushData offset_ %zu dataSize_ %zu ", offset_, dataSize_);
109    dataSize = dataSize_;
110    return 0;
111}
112
113int32_t BZip2StreamAdapter::Open()
114{
115    buffer_.resize(IGMDIFF_LIMIT_UNIT);
116    return BZip2Adapter::Open();
117}
118
119int32_t BZip2StreamAdapter::WriteData(const BlockBuffer &srcData)
120{
121    stream_.next_in = reinterpret_cast<char*>(srcData.buffer);
122    stream_.avail_in = srcData.length;
123
124    stream_.avail_out = buffer_.size();
125    stream_.next_out = reinterpret_cast<char*>(buffer_.data());
126    int32_t ret = BZ_RUN_OK;
127    do {
128        ret = BZ2_bzCompress(&stream_, BZ_RUN);
129        if (stream_.avail_out == 0) {
130            outStream_.write(buffer_.data(), buffer_.size());
131            dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
132            stream_.avail_out = buffer_.size();
133            stream_.next_out = reinterpret_cast<char*>(buffer_.data());
134        }
135        if (stream_.avail_in == 0) {
136            break;
137        }
138    } while (ret == BZ_RUN_OK);
139    if (ret != BZ_RUN_OK) {
140        PATCH_LOGE("BZip2StreamAdapter::WriteData : Failed to write data ret %d", ret);
141        return ret;
142    }
143    if (stream_.avail_in != 0) {
144        PATCH_LOGE("BZip2StreamAdapter::WriteData : Failed to write data");
145        return ret;
146    }
147    if (stream_.avail_out != buffer_.size()) {
148        outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
149    }
150    dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
151    return PATCH_SUCCESS;
152}
153int32_t BZip2StreamAdapter::FlushData(size_t &dataSize)
154{
155    dataSize = 0;
156    PATCH_DEBUG("FlushData dataSize_ %d ", dataSize_);
157    stream_.next_in = nullptr;
158    stream_.avail_in = 0;
159    stream_.avail_out = buffer_.size();
160    stream_.next_out = reinterpret_cast<char*>(buffer_.data());
161    int ret = BZ_FINISH_OK;
162    while (ret == BZ_FINISH_OK) {
163        ret = BZ2_bzCompress(&stream_, BZ_FINISH);
164        if (stream_.avail_out == 0) {
165            outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
166            dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
167            stream_.avail_out = buffer_.size();
168            stream_.next_out = reinterpret_cast<char*>(buffer_.data());
169        }
170    }
171    if (ret != BZ_RUN_OK && ret != BZ_STREAM_END) {
172        PATCH_LOGE("Failed to write data %d", ret);
173        return ret;
174    }
175    if (stream_.avail_out != buffer_.size()) {
176        outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
177    }
178    dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
179    PATCH_DEBUG("FlushData dataSize %zu %zu", dataSize_, static_cast<size_t>(outStream_.tellp()));
180    dataSize = dataSize_;
181    return 0;
182}
183
184int32_t BZip2BufferReadAdapter::Open()
185{
186    if (init_) {
187        PATCH_LOGE("State error %d", init_);
188        return -1;
189    }
190    if (dataLength_ > buffer_.length - offset_) {
191        PATCH_LOGE("Invalid buffer length");
192        return -1;
193    }
194
195    PATCH_DEBUG("BZip2BufferReadAdapter::Open %zu dataLength_ %zu", offset_, dataLength_);
196    (void)memset_s(&stream_, sizeof(bz_stream), 0, sizeof(bz_stream));
197    int32_t ret = BZ2_bzDecompressInit(&stream_, 0, 0);
198    if (ret != BZ_OK) {
199        PATCH_LOGE("Failed to open read mem ret %d", ret);
200        return -1;
201    }
202    stream_.avail_in = static_cast<unsigned int>(dataLength_);
203    stream_.next_in  = reinterpret_cast<char*>(buffer_.buffer + offset_);
204
205    init_ = true;
206    return PATCH_SUCCESS;
207}
208
209int32_t BZip2BufferReadAdapter::Close()
210{
211    if (!init_) {
212        return PATCH_SUCCESS;
213    }
214    int32_t ret = 0;
215    ret = BZ2_bzDecompressEnd(&stream_);
216    if (ret != BZ_OK) {
217        PATCH_LOGE("Failed to close read mem ret %d", ret);
218        return -1;
219    }
220    init_ = false;
221    return PATCH_SUCCESS;
222}
223
224int32_t BZip2BufferReadAdapter::ReadData(BlockBuffer &info)
225{
226    if (!init_) {
227        PATCH_LOGE("State error %d", init_);
228        return -1;
229    }
230    int32_t ret = 0;
231    size_t readLen = 0;
232    stream_.next_out = reinterpret_cast<char*>(info.buffer);
233    stream_.avail_out = info.length;
234    while (1) {
235        ret = BZ2_bzDecompress(&stream_);
236        if (ret == BZ_STREAM_END) {
237            readLen = info.length - stream_.avail_out;
238            break;
239        }
240        if (ret != BZ_OK) {
241            PATCH_LOGE("Failed to decompress ret %d", ret);
242            return -1;
243        }
244        if (stream_.avail_out == 0) {
245            readLen = info.length;
246            break;
247        }
248        if (stream_.avail_in == 0) {
249            PATCH_LOGE("Not enough buffer to decompress");
250            return -1;
251        }
252    }
253    if (readLen < info.length) {
254        PATCH_LOGE("Failed to read mem ret %zu length %zu", readLen, info.length);
255        return -1;
256    }
257    return 0;
258}
259} // namespace UpdatePatch
260