* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bzip2_adapter.h"
#include <iostream>
#include "bzlib.h"
using namespace Hpackage;
namespace UpdatePatch {
int32_t BZip2Adapter::Open()
{
(void)memset_s(&stream_, sizeof(bz_stream), 0, sizeof(bz_stream));
int32_t ret = BZ2_bzCompressInit(&stream_, BLOCK_SIZE_BEST, 0, 0);
if (ret != BZ_OK) {
PATCH_LOGE("Failed to bzcompressinit %d", ret);
return ret;
}
init_ = true;
return ret;
}
int32_t BZip2Adapter::Close()
{
if (!init_) {
return PATCH_SUCCESS;
}
int32_t ret = BZ2_bzCompressEnd(&stream_);
if (ret != BZ_OK) {
PATCH_LOGE("Failed to bz_compressEnd %d", ret);
return ret;
}
init_ = false;
return ret;
}
int32_t BZipBuffer2Adapter::WriteData(const BlockBuffer &srcData)
{
stream_.next_in = reinterpret_cast<char*>(srcData.buffer);
stream_.avail_in = srcData.length;
char *next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
stream_.avail_out = buffer_.size() - offset_ - dataSize_;
stream_.next_out = next;
int32_t ret = BZ_RUN_OK;
do {
ret = BZ2_bzCompress(&stream_, BZ_RUN);
if (stream_.avail_out == 0) {
dataSize_ += stream_.next_out - next;
size_t bufferSize = buffer_.size();
buffer_.resize(bufferSize + IGMDIFF_LIMIT_UNIT);
stream_.avail_out = IGMDIFF_LIMIT_UNIT;
next = reinterpret_cast<char*>(buffer_.data() + bufferSize);
stream_.next_out = next;
}
if (stream_.avail_in == 0) {
break;
}
} while (ret == BZ_RUN_OK);
if (ret != BZ_RUN_OK) {
PATCH_LOGE("BZipBuffer2Adapter::WriteData : Failed to write data ret %d", ret);
return ret;
}
if (stream_.avail_in != 0) {
PATCH_LOGE("BZipBuffer2Adapter::WriteData : Failed to write data");
return ret;
}
dataSize_ += stream_.next_out - next;
return PATCH_SUCCESS;
}
int32_t BZipBuffer2Adapter::FlushData(size_t &dataSize)
{
dataSize = 0;
PATCH_DEBUG("FlushData dataSize_ %d ", dataSize_);
stream_.next_in = nullptr;
stream_.avail_in = 0;
stream_.avail_out = buffer_.size() - offset_ - dataSize_;
char *next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
stream_.next_out = next;
int ret = BZ_FINISH_OK;
while (ret == BZ_FINISH_OK) {
ret = BZ2_bzCompress(&stream_, BZ_FINISH);
if (stream_.avail_out == 0) {
dataSize_ += stream_.next_out - next;
buffer_.resize(buffer_.size() + IGMDIFF_LIMIT_UNIT);
stream_.avail_out = buffer_.size() - offset_ - dataSize_;
next = reinterpret_cast<char*>(buffer_.data() + offset_ + dataSize_);
stream_.next_out = next;
}
}
if (ret != BZ_RUN_OK && ret != BZ_STREAM_END) {
PATCH_LOGE("Failed to write data %d", ret);
return ret;
}
dataSize_ += stream_.next_out - next;
PATCH_DEBUG("FlushData offset_ %zu dataSize_ %zu ", offset_, dataSize_);
dataSize = dataSize_;
return 0;
}
int32_t BZip2StreamAdapter::Open()
{
buffer_.resize(IGMDIFF_LIMIT_UNIT);
return BZip2Adapter::Open();
}
int32_t BZip2StreamAdapter::WriteData(const BlockBuffer &srcData)
{
stream_.next_in = reinterpret_cast<char*>(srcData.buffer);
stream_.avail_in = srcData.length;
stream_.avail_out = buffer_.size();
stream_.next_out = reinterpret_cast<char*>(buffer_.data());
int32_t ret = BZ_RUN_OK;
do {
ret = BZ2_bzCompress(&stream_, BZ_RUN);
if (stream_.avail_out == 0) {
outStream_.write(buffer_.data(), buffer_.size());
dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
stream_.avail_out = buffer_.size();
stream_.next_out = reinterpret_cast<char*>(buffer_.data());
}
if (stream_.avail_in == 0) {
break;
}
} while (ret == BZ_RUN_OK);
if (ret != BZ_RUN_OK) {
PATCH_LOGE("BZip2StreamAdapter::WriteData : Failed to write data ret %d", ret);
return ret;
}
if (stream_.avail_in != 0) {
PATCH_LOGE("BZip2StreamAdapter::WriteData : Failed to write data");
return ret;
}
if (stream_.avail_out != buffer_.size()) {
outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
}
dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
return PATCH_SUCCESS;
}
int32_t BZip2StreamAdapter::FlushData(size_t &dataSize)
{
dataSize = 0;
PATCH_DEBUG("FlushData dataSize_ %d ", dataSize_);
stream_.next_in = nullptr;
stream_.avail_in = 0;
stream_.avail_out = buffer_.size();
stream_.next_out = reinterpret_cast<char*>(buffer_.data());
int ret = BZ_FINISH_OK;
while (ret == BZ_FINISH_OK) {
ret = BZ2_bzCompress(&stream_, BZ_FINISH);
if (stream_.avail_out == 0) {
outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
stream_.avail_out = buffer_.size();
stream_.next_out = reinterpret_cast<char*>(buffer_.data());
}
}
if (ret != BZ_RUN_OK && ret != BZ_STREAM_END) {
PATCH_LOGE("Failed to write data %d", ret);
return ret;
}
if (stream_.avail_out != buffer_.size()) {
outStream_.write(buffer_.data(), stream_.next_out - reinterpret_cast<char*>(buffer_.data()));
}
dataSize_ += stream_.next_out - reinterpret_cast<char*>(buffer_.data());
PATCH_DEBUG("FlushData dataSize %zu %zu", dataSize_, static_cast<size_t>(outStream_.tellp()));
dataSize = dataSize_;
return 0;
}
int32_t BZip2BufferReadAdapter::Open()
{
if (init_) {
PATCH_LOGE("State error %d", init_);
return -1;
}
if (buffer_.length < offset_ || dataLength_ > buffer_.length - offset_) {
PATCH_LOGE("Invalid buffer length. dataLength:%zu, buffer_.length:%zu, offset_:%zu",
dataLength_, buffer_.length, offset_);
return -1;
}
PATCH_DEBUG("BZip2BufferReadAdapter::Open %zu dataLength_ %zu", offset_, dataLength_);
(void)memset_s(&stream_, sizeof(bz_stream), 0, sizeof(bz_stream));
int32_t ret = BZ2_bzDecompressInit(&stream_, 0, 0);
if (ret != BZ_OK) {
PATCH_LOGE("Failed to open read mem ret %d", ret);
return -1;
}
stream_.avail_in = static_cast<unsigned int>(dataLength_);
stream_.next_in = reinterpret_cast<char*>(buffer_.buffer + offset_);
init_ = true;
return PATCH_SUCCESS;
}
int32_t BZip2BufferReadAdapter::Close()
{
if (!init_) {
return PATCH_SUCCESS;
}
int32_t ret = 0;
ret = BZ2_bzDecompressEnd(&stream_);
if (ret != BZ_OK) {
PATCH_LOGE("Failed to close read mem ret %d", ret);
return -1;
}
init_ = false;
return PATCH_SUCCESS;
}
int32_t BZip2BufferReadAdapter::ReadData(BlockBuffer &info)
{
if (!init_) {
PATCH_LOGE("State error %d", init_);
return -1;
}
int32_t ret = 0;
size_t readLen = 0;
stream_.next_out = reinterpret_cast<char*>(info.buffer);
stream_.avail_out = info.length;
while (1) {
ret = BZ2_bzDecompress(&stream_);
if (ret == BZ_STREAM_END) {
readLen = info.length - stream_.avail_out;
break;
}
if (ret != BZ_OK) {
PATCH_LOGE("Failed to decompress ret %d", ret);
return -1;
}
if (stream_.avail_out == 0) {
readLen = info.length;
break;
}
if (stream_.avail_in == 0) {
PATCH_LOGE("Not enough buffer to decompress");
return -1;
}
}
if (readLen < info.length) {
PATCH_LOGE("Failed to read mem ret %zu length %zu", readLen, info.length);
return -1;
}
return 0;
}
}