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