// Copyright 2017 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "bsdiff/bz2_compressor.h" #include #include "bsdiff/logging.h" namespace { // The BZ2 compression level used. Smaller compression levels are nowadays // pointless. const int kCompressionLevel = 9; } // namespace namespace bsdiff { BZ2Compressor::BZ2Compressor() : comp_buffer_(1024 * 1024) { memset(&bz_strm_, 0, sizeof(bz_strm_)); int bz_err = BZ2_bzCompressInit(&bz_strm_, kCompressionLevel, 0 /* verbosity */, 0 /* workFactor */); if (bz_err != BZ_OK) { LOG(ERROR) << "Initializing bz_strm, bz_error=" << bz_err; } else { bz_strm_initialized_ = true; } } BZ2Compressor::~BZ2Compressor() { if (!bz_strm_initialized_) return; int bz_err = BZ2_bzCompressEnd(&bz_strm_); if (bz_err != BZ_OK) { LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err; } } bool BZ2Compressor::Write(const uint8_t* buf, size_t size) { if (!bz_strm_initialized_) return false; // The bz_stream struct defines the next_in as a non-const data pointer, // although the documentation says it won't modify it. bz_strm_.next_in = reinterpret_cast(const_cast(buf)); bz_strm_.avail_in = size; while (bz_strm_.avail_in) { bz_strm_.next_out = reinterpret_cast(comp_buffer_.buffer_data()); bz_strm_.avail_out = comp_buffer_.buffer_size(); int bz_err = BZ2_bzCompress(&bz_strm_, BZ_RUN); if (bz_err != BZ_RUN_OK) { LOG(ERROR) << "Compressing data, bz_error=" << bz_err; return false; } uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out; if (output_bytes) { comp_buffer_.AddDataToChunks(output_bytes); } } return true; } bool BZ2Compressor::Finish() { if (!bz_strm_initialized_) return false; bz_strm_.next_in = nullptr; bz_strm_.avail_in = 0; int bz_err = BZ_FINISH_OK; while (bz_err == BZ_FINISH_OK) { bz_strm_.next_out = reinterpret_cast(comp_buffer_.buffer_data()); bz_strm_.avail_out = comp_buffer_.buffer_size(); bz_err = BZ2_bzCompress(&bz_strm_, BZ_FINISH); uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out; if (output_bytes) { comp_buffer_.AddDataToChunks(output_bytes); } } if (bz_err != BZ_STREAM_END) { LOG(ERROR) << "Finishing compressing data, bz_error=" << bz_err; return false; } bz_err = BZ2_bzCompressEnd(&bz_strm_); bz_strm_initialized_ = false; if (bz_err != BZ_OK) { LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err; return false; } return true; } const std::vector& BZ2Compressor::GetCompressedData() { return comp_buffer_.GetCompressedData(); } } // namespace bsdiff