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