You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
3.0 KiB
89 lines
3.0 KiB
4 months ago
|
// Copyright 2017 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 "bsdiff/brotli_decompressor.h"
|
||
|
|
||
|
#include "bsdiff/logging.h"
|
||
|
|
||
|
namespace bsdiff {
|
||
|
|
||
|
BrotliDecompressor::~BrotliDecompressor() {
|
||
|
if (brotli_decoder_state_)
|
||
|
BrotliDecoderDestroyInstance(brotli_decoder_state_);
|
||
|
}
|
||
|
|
||
|
bool BrotliDecompressor::SetInputData(const uint8_t* input_data, size_t size) {
|
||
|
brotli_decoder_state_ =
|
||
|
BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
|
||
|
if (brotli_decoder_state_ == nullptr) {
|
||
|
LOG(ERROR) << "Failed to initialize brotli decoder.";
|
||
|
return false;
|
||
|
}
|
||
|
next_in_ = input_data;
|
||
|
available_in_ = size;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool BrotliDecompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
|
||
|
if (!brotli_decoder_state_) {
|
||
|
LOG(ERROR) << "BrotliDecompressor not initialized";
|
||
|
return false;
|
||
|
}
|
||
|
auto next_out = output_data;
|
||
|
size_t available_out = bytes_to_output;
|
||
|
|
||
|
while (available_out > 0) {
|
||
|
// The brotli decoder will update |available_in_|, |available_in_|,
|
||
|
// |next_out| and |available_out|.
|
||
|
BrotliDecoderResult result = BrotliDecoderDecompressStream(
|
||
|
brotli_decoder_state_, &available_in_, &next_in_, &available_out,
|
||
|
&next_out, nullptr);
|
||
|
|
||
|
if (result == BROTLI_DECODER_RESULT_ERROR) {
|
||
|
LOG(ERROR) << "Decompression failed with "
|
||
|
<< BrotliDecoderErrorString(
|
||
|
BrotliDecoderGetErrorCode(brotli_decoder_state_));
|
||
|
return false;
|
||
|
} else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||
|
LOG(ERROR) << "Decompressor reached EOF while reading from input stream.";
|
||
|
return false;
|
||
|
} else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
|
||
|
// This means that decoding is finished, no more input might be consumed
|
||
|
// and no more output will be produced. In the normal case, when there is
|
||
|
// more data available than what was requested in this Read() call it
|
||
|
// returns BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT.
|
||
|
if (available_out > 0) {
|
||
|
LOG(ERROR) << "Expected to read " << available_out
|
||
|
<< " more bytes but reached the end of compressed brotli "
|
||
|
"stream";
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool BrotliDecompressor::Close() {
|
||
|
if (!brotli_decoder_state_) {
|
||
|
LOG(ERROR) << "BrotliDecompressor not initialized";
|
||
|
return false;
|
||
|
}
|
||
|
// In some cases, the brotli compressed stream could be empty. As a result,
|
||
|
// the function BrotliDecoderIsFinished() will return false because we never
|
||
|
// start the decompression. When that happens, we just destroy the decoder
|
||
|
// and return true.
|
||
|
if (BrotliDecoderIsUsed(brotli_decoder_state_) &&
|
||
|
!BrotliDecoderIsFinished(brotli_decoder_state_)) {
|
||
|
LOG(ERROR) << "Unfinished brotli decoder.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
BrotliDecoderDestroyInstance(brotli_decoder_state_);
|
||
|
brotli_decoder_state_ = nullptr;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace bsdiff
|