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