• 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/brotli_compressor.h"
6 
7 #include "bsdiff/logging.h"
8 
9 namespace {
10 
11 const size_t kBufferSize = 1024 * 1024;
12 const uint32_t kBrotliDefaultLgwin = 20;
13 
14 }  // namespace
15 
16 namespace bsdiff {
BrotliCompressor(int quality)17 BrotliCompressor::BrotliCompressor(int quality) : comp_buffer_(kBufferSize) {
18   brotli_encoder_state_ =
19       BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
20   if (!brotli_encoder_state_) {
21     LOG(ERROR) << "Failed to initialize brotli decoder state";
22   } else {
23     int compression_quality = quality;
24     if (compression_quality > BROTLI_MAX_QUALITY ||
25         compression_quality < BROTLI_MIN_QUALITY) {
26       LOG(ERROR) << "Invalid quality value: " << quality
27                  << ", using default quality instead.";
28       compression_quality = BROTLI_MAX_QUALITY;
29     }
30 
31     BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_QUALITY,
32                               compression_quality);
33     BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_LGWIN,
34                               kBrotliDefaultLgwin);
35   }
36 }
37 
~BrotliCompressor()38 BrotliCompressor::~BrotliCompressor() {
39   if (brotli_encoder_state_) {
40     BrotliEncoderDestroyInstance(brotli_encoder_state_);
41   }
42 }
43 
Write(const uint8_t * buf,size_t size)44 bool BrotliCompressor::Write(const uint8_t* buf, size_t size) {
45   if (!brotli_encoder_state_)
46     return false;
47 
48   const uint8_t* next_in = buf;
49   size_t avail_in = size;
50   while (avail_in > 0) {
51     size_t avail_out = kBufferSize;
52     uint8_t* next_out = comp_buffer_.buffer_data();
53     if (!BrotliEncoderCompressStream(
54             brotli_encoder_state_, BROTLI_OPERATION_PROCESS, &avail_in,
55             &next_in, &avail_out, &next_out, nullptr)) {
56       LOG(ERROR) << "BrotliCompressor failed to compress " << avail_in
57                  << " bytes of data.";
58       return false;
59     }
60 
61     uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
62     if (output_bytes > 0) {
63       comp_buffer_.AddDataToChunks(output_bytes);
64     }
65   }
66   return true;
67 }
68 
Finish()69 bool BrotliCompressor::Finish() {
70   if (!brotli_encoder_state_)
71     return false;
72 
73   const uint8_t* next_in = nullptr;
74   size_t avail_in = 0;
75   while (!BrotliEncoderIsFinished(brotli_encoder_state_)) {
76     size_t avail_out = kBufferSize;
77     uint8_t* next_out = comp_buffer_.buffer_data();
78     if (!BrotliEncoderCompressStream(
79             brotli_encoder_state_, BROTLI_OPERATION_FINISH, &avail_in, &next_in,
80             &avail_out, &next_out, nullptr)) {
81       LOG(ERROR) << "BrotliCompressor failed to finish compression";
82       return false;
83     }
84 
85     uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
86     if (output_bytes > 0) {
87       comp_buffer_.AddDataToChunks(output_bytes);
88     }
89   }
90   return true;
91 }
92 
GetCompressedData()93 const std::vector<uint8_t>& BrotliCompressor::GetCompressedData() {
94   return comp_buffer_.GetCompressedData();
95 }
96 
97 }  // namespace bsdiff
98