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