xref: /aosp_15_r20/external/bsdiff/brotli_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/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