xref: /aosp_15_r20/external/bsdiff/bz2_compressor.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
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