• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium OS Authors. All rights reserved.
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/src/logging.h"
10 #include "puffin/memory_stream.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,
31                             quality);
32   BrotliEncoderSetParameter(encoder.get(), BROTLI_PARAM_LGWIN,
33                             kDefaultParamLgwin);
34 
35   size_t available_in = input_size;
36   while (available_in != 0 || !BrotliEncoderIsFinished(encoder.get())) {
37     const uint8_t* next_in = input + input_size - available_in;
38     // Set up the output buffer
39     uint8_t buffer[kBufferSize];
40     uint8_t* next_out = buffer;
41     size_t available_out = kBufferSize;
42 
43     BrotliEncoderOperation op =
44         available_in == 0 ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
45 
46     if (!BrotliEncoderCompressStream(encoder.get(), op, &available_in, &next_in,
47                                      &available_out, &next_out, nullptr)) {
48       LOG(ERROR) << "Failed to compress " << input_size << " bytes with brotli";
49       return false;
50     }
51 
52     size_t bytes_consumed = kBufferSize - available_out;
53     output_stream->Write(buffer, bytes_consumed);
54   }
55 
56   return true;
57 }
58 
BrotliEncode(const uint8_t * input,size_t input_size,UniqueStreamPtr output_stream)59 bool BrotliEncode(const uint8_t* input,
60                   size_t input_size,
61                   UniqueStreamPtr output_stream) {
62   return BrotliEncode(input, input_size, std::move(output_stream),
63                       kDefaultParamQuality);
64 }
65 
BrotliEncode(const uint8_t * input,size_t input_size,std::vector<uint8_t> * output)66 bool BrotliEncode(const uint8_t* input,
67                   size_t input_size,
68                   std::vector<uint8_t>* output) {
69   TEST_AND_RETURN_FALSE(output != nullptr);
70   return BrotliEncode(input, input_size, MemoryStream::CreateForWrite(output));
71 }
72 
BrotliDecode(const uint8_t * input,size_t input_size,UniqueStreamPtr output_stream)73 bool BrotliDecode(const uint8_t* input,
74                   size_t input_size,
75                   UniqueStreamPtr output_stream) {
76   std::unique_ptr<BrotliDecoderState, decltype(&BrotliDecoderDestroyInstance)>
77       decoder(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
78               BrotliDecoderDestroyInstance);
79   TEST_AND_RETURN_FALSE(decoder != nullptr);
80 
81   size_t available_in = input_size;
82   while (available_in != 0 || !BrotliDecoderIsFinished(decoder.get())) {
83     const uint8_t* next_in = input + input_size - available_in;
84     // Set up the output buffer
85     uint8_t buffer[kBufferSize];
86     uint8_t* next_out = buffer;
87     size_t available_out = kBufferSize;
88 
89     BrotliDecoderResult result =
90         BrotliDecoderDecompressStream(decoder.get(), &available_in, &next_in,
91                                       &available_out, &next_out, nullptr);
92     if (result == BROTLI_DECODER_RESULT_ERROR ||
93         result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
94       LOG(ERROR) << "Failed to decompress " << input_size
95                  << " bytes with brotli, result " << result;
96       return false;
97     }
98 
99     size_t bytes_consumed = kBufferSize - available_out;
100     output_stream->Write(buffer, bytes_consumed);
101   }
102   return true;
103 }
104 
BrotliDecode(const uint8_t * input,size_t input_size,std::vector<uint8_t> * output)105 bool BrotliDecode(const uint8_t* input,
106                   size_t input_size,
107                   std::vector<uint8_t>* output) {
108   TEST_AND_RETURN_FALSE(output != nullptr);
109   return BrotliDecode(input, input_size, MemoryStream::CreateForWrite(output));
110 }
111 
112 }  // namespace puffin
113