blob: e36e98d74fa898bc9ea8beb9572d621b97cfdce5 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "puffin/src/include/puffin/brotli_util.h"
#include "brotli/decode.h"
#include "brotli/encode.h"
#include "puffin/src/logging.h"
#include "puffin/src/memory_stream.h"
namespace puffin {
namespace {
constexpr auto kBufferSize = 32768;
constexpr auto kDefaultParamQuality = 9;
constexpr auto kDefaultParamLgwin = 20;
} // namespace
bool BrotliEncode(const uint8_t* input,
size_t input_size,
UniqueStreamPtr output_stream) {
std::unique_ptr<BrotliEncoderState, decltype(&BrotliEncoderDestroyInstance)>
encoder(BrotliEncoderCreateInstance(nullptr, nullptr, nullptr),
BrotliEncoderDestroyInstance);
TEST_AND_RETURN_FALSE(encoder != nullptr);
BrotliEncoderSetParameter(encoder.get(), BROTLI_PARAM_QUALITY,
kDefaultParamQuality);
BrotliEncoderSetParameter(encoder.get(), BROTLI_PARAM_LGWIN,
kDefaultParamLgwin);
size_t available_in = input_size;
while (available_in != 0 || !BrotliEncoderIsFinished(encoder.get())) {
const uint8_t* next_in = input + input_size - available_in;
// Set up the output buffer
uint8_t buffer[kBufferSize];
uint8_t* next_out = buffer;
size_t available_out = kBufferSize;
BrotliEncoderOperation op =
available_in == 0 ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
if (!BrotliEncoderCompressStream(encoder.get(), op, &available_in, &next_in,
&available_out, &next_out, nullptr)) {
LOG(ERROR) << "Failed to compress " << input_size << " bytes with brotli";
return false;
}
size_t bytes_consumed = kBufferSize - available_out;
output_stream->Write(buffer, bytes_consumed);
}
return true;
}
bool BrotliEncode(const uint8_t* input,
size_t input_size,
std::vector<uint8_t>* output) {
TEST_AND_RETURN_FALSE(output != nullptr);
return BrotliEncode(input, input_size, MemoryStream::CreateForWrite(output));
}
bool BrotliDecode(const uint8_t* input,
size_t input_size,
UniqueStreamPtr output_stream) {
std::unique_ptr<BrotliDecoderState, decltype(&BrotliDecoderDestroyInstance)>
decoder(BrotliDecoderCreateInstance(nullptr, nullptr, nullptr),
BrotliDecoderDestroyInstance);
TEST_AND_RETURN_FALSE(decoder != nullptr);
size_t available_in = input_size;
while (available_in != 0 || !BrotliDecoderIsFinished(decoder.get())) {
const uint8_t* next_in = input + input_size - available_in;
// Set up the output buffer
uint8_t buffer[kBufferSize];
uint8_t* next_out = buffer;
size_t available_out = kBufferSize;
BrotliDecoderResult result =
BrotliDecoderDecompressStream(decoder.get(), &available_in, &next_in,
&available_out, &next_out, nullptr);
if (result == BROTLI_DECODER_RESULT_ERROR ||
result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
LOG(ERROR) << "Failed to decompress " << input_size
<< " bytes with brotli, result " << result;
return false;
}
size_t bytes_consumed = kBufferSize - available_out;
output_stream->Write(buffer, bytes_consumed);
}
return true;
}
bool BrotliDecode(const uint8_t* input,
size_t input_size,
std::vector<uint8_t>* output) {
TEST_AND_RETURN_FALSE(output != nullptr);
return BrotliDecode(input, input_size, MemoryStream::CreateForWrite(output));
}
} // namespace puffin