1*a3a45f30SXin Li // Copyright 2017 The Chromium OS Authors. All rights reserved.
2*a3a45f30SXin Li // Use of this source code is governed by a BSD-style license that can be
3*a3a45f30SXin Li // found in the LICENSE file.
4*a3a45f30SXin Li
5*a3a45f30SXin Li #include "bsdiff/bz2_compressor.h"
6*a3a45f30SXin Li
7*a3a45f30SXin Li #include <string.h>
8*a3a45f30SXin Li
9*a3a45f30SXin Li #include "bsdiff/logging.h"
10*a3a45f30SXin Li
11*a3a45f30SXin Li namespace {
12*a3a45f30SXin Li
13*a3a45f30SXin Li // The BZ2 compression level used. Smaller compression levels are nowadays
14*a3a45f30SXin Li // pointless.
15*a3a45f30SXin Li const int kCompressionLevel = 9;
16*a3a45f30SXin Li
17*a3a45f30SXin Li } // namespace
18*a3a45f30SXin Li
19*a3a45f30SXin Li namespace bsdiff {
20*a3a45f30SXin Li
BZ2Compressor()21*a3a45f30SXin Li BZ2Compressor::BZ2Compressor() : comp_buffer_(1024 * 1024) {
22*a3a45f30SXin Li memset(&bz_strm_, 0, sizeof(bz_strm_));
23*a3a45f30SXin Li int bz_err = BZ2_bzCompressInit(&bz_strm_, kCompressionLevel,
24*a3a45f30SXin Li 0 /* verbosity */, 0 /* workFactor */);
25*a3a45f30SXin Li if (bz_err != BZ_OK) {
26*a3a45f30SXin Li LOG(ERROR) << "Initializing bz_strm, bz_error=" << bz_err;
27*a3a45f30SXin Li } else {
28*a3a45f30SXin Li bz_strm_initialized_ = true;
29*a3a45f30SXin Li }
30*a3a45f30SXin Li }
31*a3a45f30SXin Li
~BZ2Compressor()32*a3a45f30SXin Li BZ2Compressor::~BZ2Compressor() {
33*a3a45f30SXin Li if (!bz_strm_initialized_)
34*a3a45f30SXin Li return;
35*a3a45f30SXin Li int bz_err = BZ2_bzCompressEnd(&bz_strm_);
36*a3a45f30SXin Li if (bz_err != BZ_OK) {
37*a3a45f30SXin Li LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err;
38*a3a45f30SXin Li }
39*a3a45f30SXin Li }
40*a3a45f30SXin Li
Write(const uint8_t * buf,size_t size)41*a3a45f30SXin Li bool BZ2Compressor::Write(const uint8_t* buf, size_t size) {
42*a3a45f30SXin Li if (!bz_strm_initialized_)
43*a3a45f30SXin Li return false;
44*a3a45f30SXin Li
45*a3a45f30SXin Li // The bz_stream struct defines the next_in as a non-const data pointer,
46*a3a45f30SXin Li // although the documentation says it won't modify it.
47*a3a45f30SXin Li bz_strm_.next_in = reinterpret_cast<char*>(const_cast<uint8_t*>(buf));
48*a3a45f30SXin Li bz_strm_.avail_in = size;
49*a3a45f30SXin Li
50*a3a45f30SXin Li while (bz_strm_.avail_in) {
51*a3a45f30SXin Li bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.buffer_data());
52*a3a45f30SXin Li bz_strm_.avail_out = comp_buffer_.buffer_size();
53*a3a45f30SXin Li int bz_err = BZ2_bzCompress(&bz_strm_, BZ_RUN);
54*a3a45f30SXin Li if (bz_err != BZ_RUN_OK) {
55*a3a45f30SXin Li LOG(ERROR) << "Compressing data, bz_error=" << bz_err;
56*a3a45f30SXin Li return false;
57*a3a45f30SXin Li }
58*a3a45f30SXin Li
59*a3a45f30SXin Li uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out;
60*a3a45f30SXin Li if (output_bytes) {
61*a3a45f30SXin Li comp_buffer_.AddDataToChunks(output_bytes);
62*a3a45f30SXin Li }
63*a3a45f30SXin Li }
64*a3a45f30SXin Li return true;
65*a3a45f30SXin Li }
66*a3a45f30SXin Li
Finish()67*a3a45f30SXin Li bool BZ2Compressor::Finish() {
68*a3a45f30SXin Li if (!bz_strm_initialized_)
69*a3a45f30SXin Li return false;
70*a3a45f30SXin Li bz_strm_.next_in = nullptr;
71*a3a45f30SXin Li bz_strm_.avail_in = 0;
72*a3a45f30SXin Li
73*a3a45f30SXin Li int bz_err = BZ_FINISH_OK;
74*a3a45f30SXin Li while (bz_err == BZ_FINISH_OK) {
75*a3a45f30SXin Li bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.buffer_data());
76*a3a45f30SXin Li bz_strm_.avail_out = comp_buffer_.buffer_size();
77*a3a45f30SXin Li bz_err = BZ2_bzCompress(&bz_strm_, BZ_FINISH);
78*a3a45f30SXin Li
79*a3a45f30SXin Li uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out;
80*a3a45f30SXin Li if (output_bytes) {
81*a3a45f30SXin Li comp_buffer_.AddDataToChunks(output_bytes);
82*a3a45f30SXin Li }
83*a3a45f30SXin Li }
84*a3a45f30SXin Li if (bz_err != BZ_STREAM_END) {
85*a3a45f30SXin Li LOG(ERROR) << "Finishing compressing data, bz_error=" << bz_err;
86*a3a45f30SXin Li return false;
87*a3a45f30SXin Li }
88*a3a45f30SXin Li bz_err = BZ2_bzCompressEnd(&bz_strm_);
89*a3a45f30SXin Li bz_strm_initialized_ = false;
90*a3a45f30SXin Li if (bz_err != BZ_OK) {
91*a3a45f30SXin Li LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err;
92*a3a45f30SXin Li return false;
93*a3a45f30SXin Li }
94*a3a45f30SXin Li return true;
95*a3a45f30SXin Li }
96*a3a45f30SXin Li
GetCompressedData()97*a3a45f30SXin Li const std::vector<uint8_t>& BZ2Compressor::GetCompressedData() {
98*a3a45f30SXin Li return comp_buffer_.GetCompressedData();
99*a3a45f30SXin Li }
100*a3a45f30SXin Li
101*a3a45f30SXin Li } // namespace bsdiff
102