Home | History | Annotate | Download | only in bsdiff
      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 
     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 
     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 
     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 
     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 
     97 const std::vector<uint8_t>& BZ2Compressor::GetCompressedData() {
     98   return comp_buffer_.GetCompressedData();
     99 }
    100 
    101 }  // namespace bsdiff
    102