blob: 3c30364ffc204f0a317b346fc4d43d9f4a38ba59 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "lzma2_compressor.h"
#include <limits>
#include "common/allocator/alloc_base.h"
#include "common/allocator/byte_stream.h"
using namespace common;
namespace storage {
namespace {
const uint32_t LZMA2_BUFFER_SIZE = 4096;
}
int LZMA2Compressor::reset(bool /* for_compress */) { return E_OK; }
void LZMA2Compressor::destroy() {
if (compressed_buf_ != nullptr) {
mem_free(compressed_buf_);
compressed_buf_ = nullptr;
}
if (uncompressed_buf_ != nullptr) {
mem_free(uncompressed_buf_);
uncompressed_buf_ = nullptr;
}
}
int LZMA2Compressor::compress(char* uncompressed_buf,
uint32_t uncompressed_buf_len,
char*& compressed_buf,
uint32_t& compressed_buf_len) {
const size_t max_dst_size = lzma_stream_buffer_bound(uncompressed_buf_len);
if (max_dst_size == 0 ||
max_dst_size > std::numeric_limits<uint32_t>::max()) {
return E_COMPRESS_ERR;
}
compressed_buf_ =
static_cast<char*>(mem_alloc(max_dst_size, MOD_COMPRESSOR_OBJ));
if (compressed_buf_ == nullptr) {
return E_OOM;
}
size_t out_pos = 0;
const lzma_ret ret = lzma_easy_buffer_encode(
LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64, nullptr,
reinterpret_cast<const uint8_t*>(uncompressed_buf),
uncompressed_buf_len, reinterpret_cast<uint8_t*>(compressed_buf_),
&out_pos, max_dst_size);
if (ret != LZMA_OK) {
mem_free(compressed_buf_);
compressed_buf_ = nullptr;
return E_COMPRESS_ERR;
}
char* compressed_data =
static_cast<char*>(mem_realloc(compressed_buf_, out_pos));
if (compressed_data == nullptr) {
mem_free(compressed_buf_);
compressed_buf_ = nullptr;
return E_OOM;
}
compressed_buf_ = compressed_data;
compressed_buf = compressed_data;
compressed_buf_len = static_cast<uint32_t>(out_pos);
return E_OK;
}
void LZMA2Compressor::after_compress(char* compressed_buf) {
if (compressed_buf != nullptr) {
mem_free(compressed_buf);
if (compressed_buf_ == compressed_buf) {
compressed_buf_ = nullptr;
}
}
}
int LZMA2Compressor::uncompress(char* compressed_buf,
uint32_t compressed_buf_len,
char*& uncompressed_buf,
uint32_t& uncompressed_buf_len) {
lzma_stream stream = LZMA_STREAM_INIT;
lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, 0);
if (ret != LZMA_OK) {
return E_COMPRESS_ERR;
}
ByteStream out(LZMA2_BUFFER_SIZE, MOD_COMPRESSOR_OBJ);
uint8_t out_buf[LZMA2_BUFFER_SIZE];
stream.next_in = reinterpret_cast<const uint8_t*>(compressed_buf);
stream.avail_in = compressed_buf_len;
do {
stream.next_out = out_buf;
stream.avail_out = LZMA2_BUFFER_SIZE;
ret = lzma_code(&stream, LZMA_FINISH);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
lzma_end(&stream);
out.destroy();
return E_COMPRESS_ERR;
}
const uint32_t produced =
static_cast<uint32_t>(LZMA2_BUFFER_SIZE - stream.avail_out);
if (produced > 0 && out.write_buf(out_buf, produced) != E_OK) {
lzma_end(&stream);
out.destroy();
return E_COMPRESS_ERR;
}
} while (ret != LZMA_STREAM_END);
const size_t remaining_input = stream.avail_in;
lzma_end(&stream);
if (remaining_input != 0 ||
out.total_size() > std::numeric_limits<uint32_t>::max()) {
out.destroy();
return E_COMPRESS_ERR;
}
uncompressed_buf_ = get_bytes_from_bytestream(out);
uncompressed_buf_len = static_cast<uint32_t>(out.total_size());
out.destroy();
if (uncompressed_buf_len != 0 && uncompressed_buf_ == nullptr) {
return E_OOM;
}
uncompressed_buf = uncompressed_buf_;
return E_OK;
}
void LZMA2Compressor::after_uncompress(char* uncompressed_buf) {
if (uncompressed_buf != nullptr) {
mem_free(uncompressed_buf);
if (uncompressed_buf_ == uncompressed_buf) {
uncompressed_buf_ = nullptr;
}
}
}
} // namespace storage