blob: bef8d1a67755d25e23ff991f049b0e55b83b9c6e [file] [edit]
// Copyright 2026 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxcodec/brotli/brotli_decoder.h"
#include <memory>
#include <utility>
#include "core/fxcrt/check.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/numerics/safe_conversions.h"
#include "third_party/brotli/include/brotli/decode.h"
namespace {
constexpr size_t kMaxDecodeBytes = 1024 * 1024 * 1024;
bool g_brotli_enabled = false;
struct BrotliDecoderStateDeleter {
void operator()(struct BrotliDecoderStateStruct* ptr) const {
BrotliDecoderDestroyInstance(ptr);
}
};
} // namespace
DataAndBytesConsumed BrotliDecoder::Decode(pdfium::span<const uint8_t> src_span,
uint32_t estimated_decode_size) {
CHECK(g_brotli_enabled);
if (src_span.empty()) {
return {DataVector<uint8_t>(), 0u};
}
if (estimated_decode_size == 0) {
estimated_decode_size = pdfium::checked_cast<uint32_t>(src_span.size());
}
if (estimated_decode_size > kMaxDecodeBytes) {
return {DataVector<uint8_t>(), 0u};
}
std::unique_ptr<BrotliDecoderState, BrotliDecoderStateDeleter> state(
BrotliDecoderCreateInstance(nullptr, nullptr, nullptr));
if (!state) {
return {DataVector<uint8_t>(), 0u};
}
DataVector<uint8_t> decoded_buffer(estimated_decode_size);
size_t available_in = src_span.size();
const uint8_t* next_in = src_span.data();
size_t total_out = 0;
while (true) {
auto output_span = pdfium::span(decoded_buffer).subspan(total_out);
size_t available_out = output_span.size();
uint8_t* next_out = output_span.data();
BrotliDecoderResult result =
BrotliDecoderDecompressStream(state.get(), &available_in, &next_in,
&available_out, &next_out, &total_out);
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT &&
decoded_buffer.size() <= kMaxDecodeBytes / 2) {
decoded_buffer.resize(decoded_buffer.size() * 2);
continue;
}
if (result == BROTLI_DECODER_RESULT_SUCCESS) {
decoded_buffer.resize(total_out);
return {std::move(decoded_buffer),
static_cast<uint32_t>(src_span.subspan(available_in).size())};
}
return {DataVector<uint8_t>(), 0u};
}
}
void BrotliDecoder::SetBrotliEnabled(bool enabled) {
g_brotli_enabled = enabled;
}
bool BrotliDecoder::GetBrotliEnabled() {
return g_brotli_enabled;
}