xref: /aosp_15_r20/external/puffin/src/brotli_util.cc (revision 07fb1d065b7cfb4729786fadd42a612532d2f466)
1*07fb1d06SElliott Hughes // Copyright 2021 The ChromiumOS Authors
2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be
3*07fb1d06SElliott Hughes // found in the LICENSE file.
4*07fb1d06SElliott Hughes 
5*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/brotli_util.h"
6*07fb1d06SElliott Hughes 
7*07fb1d06SElliott Hughes #include "brotli/decode.h"
8*07fb1d06SElliott Hughes #include "brotli/encode.h"
9*07fb1d06SElliott Hughes #include "puffin/memory_stream.h"
10*07fb1d06SElliott Hughes #include "puffin/src/logging.h"
11*07fb1d06SElliott Hughes 
12*07fb1d06SElliott Hughes namespace puffin {
13*07fb1d06SElliott Hughes 
14*07fb1d06SElliott Hughes namespace {
15*07fb1d06SElliott Hughes 
16*07fb1d06SElliott Hughes constexpr auto kBufferSize = 32768;
17*07fb1d06SElliott Hughes constexpr auto kDefaultParamQuality = 9;
18*07fb1d06SElliott Hughes constexpr auto kDefaultParamLgwin = 20;
19*07fb1d06SElliott Hughes }  // namespace
20*07fb1d06SElliott Hughes 
BrotliEncode(const uint8_t * input,size_t input_size,UniqueStreamPtr output_stream,int quality)21*07fb1d06SElliott Hughes bool BrotliEncode(const uint8_t* input,
22*07fb1d06SElliott Hughes                   size_t input_size,
23*07fb1d06SElliott Hughes                   UniqueStreamPtr output_stream,
24*07fb1d06SElliott Hughes                   int quality) {
25*07fb1d06SElliott Hughes   std::unique_ptr<BrotliEncoderState, decltype(&BrotliEncoderDestroyInstance)>
26*07fb1d06SElliott Hughes       encoder(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr),
27*07fb1d06SElliott Hughes               BrotliEncoderDestroyInstance);
28*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(encoder != nullptr);
29*07fb1d06SElliott Hughes 
30*07fb1d06SElliott Hughes   BrotliEncoderSetParameter(encoder.get(), BROTLI_PARAM_QUALITY, quality);
31*07fb1d06SElliott Hughes   BrotliEncoderSetParameter(encoder.get(), BROTLI_PARAM_LGWIN,
32*07fb1d06SElliott Hughes                             kDefaultParamLgwin);
33*07fb1d06SElliott Hughes 
34*07fb1d06SElliott Hughes   size_t available_in = input_size;
35*07fb1d06SElliott Hughes   while (available_in != 0 || !BrotliEncoderIsFinished(encoder.get())) {
36*07fb1d06SElliott Hughes     const uint8_t* next_in = input + input_size - available_in;
37*07fb1d06SElliott Hughes     // Set up the output buffer
38*07fb1d06SElliott Hughes     uint8_t buffer[kBufferSize];
39*07fb1d06SElliott Hughes     uint8_t* next_out = buffer;
40*07fb1d06SElliott Hughes     size_t available_out = kBufferSize;
41*07fb1d06SElliott Hughes 
42*07fb1d06SElliott Hughes     BrotliEncoderOperation op =
43*07fb1d06SElliott Hughes         available_in == 0 ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
44*07fb1d06SElliott Hughes 
45*07fb1d06SElliott Hughes     if (!BrotliEncoderCompressStream(encoder.get(), op, &available_in, &next_in,
46*07fb1d06SElliott Hughes                                      &available_out, &next_out, nullptr)) {
47*07fb1d06SElliott Hughes       LOG(ERROR) << "Failed to compress " << input_size << " bytes with brotli";
48*07fb1d06SElliott Hughes       return false;
49*07fb1d06SElliott Hughes     }
50*07fb1d06SElliott Hughes 
51*07fb1d06SElliott Hughes     size_t bytes_consumed = kBufferSize - available_out;
52*07fb1d06SElliott Hughes     output_stream->Write(buffer, bytes_consumed);
53*07fb1d06SElliott Hughes   }
54*07fb1d06SElliott Hughes 
55*07fb1d06SElliott Hughes   return true;
56*07fb1d06SElliott Hughes }
57*07fb1d06SElliott Hughes 
BrotliEncode(const uint8_t * input,size_t input_size,UniqueStreamPtr output_stream)58*07fb1d06SElliott Hughes bool BrotliEncode(const uint8_t* input,
59*07fb1d06SElliott Hughes                   size_t input_size,
60*07fb1d06SElliott Hughes                   UniqueStreamPtr output_stream) {
61*07fb1d06SElliott Hughes   return BrotliEncode(input, input_size, std::move(output_stream),
62*07fb1d06SElliott Hughes                       kDefaultParamQuality);
63*07fb1d06SElliott Hughes }
64*07fb1d06SElliott Hughes 
BrotliEncode(const uint8_t * input,size_t input_size,std::vector<uint8_t> * output)65*07fb1d06SElliott Hughes bool BrotliEncode(const uint8_t* input,
66*07fb1d06SElliott Hughes                   size_t input_size,
67*07fb1d06SElliott Hughes                   std::vector<uint8_t>* output) {
68*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(output != nullptr);
69*07fb1d06SElliott Hughes   return BrotliEncode(input, input_size, MemoryStream::CreateForWrite(output));
70*07fb1d06SElliott Hughes }
71*07fb1d06SElliott Hughes 
BrotliDecode(const uint8_t * input,size_t input_size,UniqueStreamPtr output_stream)72*07fb1d06SElliott Hughes bool BrotliDecode(const uint8_t* input,
73*07fb1d06SElliott Hughes                   size_t input_size,
74*07fb1d06SElliott Hughes                   UniqueStreamPtr output_stream) {
75*07fb1d06SElliott Hughes   std::unique_ptr<BrotliDecoderState, decltype(&BrotliDecoderDestroyInstance)>
76*07fb1d06SElliott Hughes       decoder(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
77*07fb1d06SElliott Hughes               BrotliDecoderDestroyInstance);
78*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(decoder != nullptr);
79*07fb1d06SElliott Hughes 
80*07fb1d06SElliott Hughes   size_t available_in = input_size;
81*07fb1d06SElliott Hughes   while (available_in != 0 || !BrotliDecoderIsFinished(decoder.get())) {
82*07fb1d06SElliott Hughes     const uint8_t* next_in = input + input_size - available_in;
83*07fb1d06SElliott Hughes     // Set up the output buffer
84*07fb1d06SElliott Hughes     uint8_t buffer[kBufferSize];
85*07fb1d06SElliott Hughes     uint8_t* next_out = buffer;
86*07fb1d06SElliott Hughes     size_t available_out = kBufferSize;
87*07fb1d06SElliott Hughes 
88*07fb1d06SElliott Hughes     BrotliDecoderResult result =
89*07fb1d06SElliott Hughes         BrotliDecoderDecompressStream(decoder.get(), &available_in, &next_in,
90*07fb1d06SElliott Hughes                                       &available_out, &next_out, nullptr);
91*07fb1d06SElliott Hughes     if (result == BROTLI_DECODER_RESULT_ERROR ||
92*07fb1d06SElliott Hughes         result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
93*07fb1d06SElliott Hughes       LOG(ERROR) << "Failed to decompress " << input_size
94*07fb1d06SElliott Hughes                  << " bytes with brotli, result " << result;
95*07fb1d06SElliott Hughes       return false;
96*07fb1d06SElliott Hughes     }
97*07fb1d06SElliott Hughes 
98*07fb1d06SElliott Hughes     size_t bytes_consumed = kBufferSize - available_out;
99*07fb1d06SElliott Hughes     output_stream->Write(buffer, bytes_consumed);
100*07fb1d06SElliott Hughes   }
101*07fb1d06SElliott Hughes   return true;
102*07fb1d06SElliott Hughes }
103*07fb1d06SElliott Hughes 
BrotliDecode(const uint8_t * input,size_t input_size,std::vector<uint8_t> * output)104*07fb1d06SElliott Hughes bool BrotliDecode(const uint8_t* input,
105*07fb1d06SElliott Hughes                   size_t input_size,
106*07fb1d06SElliott Hughes                   std::vector<uint8_t>* output) {
107*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(output != nullptr);
108*07fb1d06SElliott Hughes   return BrotliDecode(input, input_size, MemoryStream::CreateForWrite(output));
109*07fb1d06SElliott Hughes }
110*07fb1d06SElliott Hughes 
111*07fb1d06SElliott Hughes }  // namespace puffin
112