1*a3a45f30SXin Li // Copyright 2017 The Chromium OS Authors. All rights reserved.
2*a3a45f30SXin Li // Use of this source code is governed by a BSD-style license that can be
3*a3a45f30SXin Li // found in the LICENSE file.
4*a3a45f30SXin Li
5*a3a45f30SXin Li #include "bsdiff/brotli_decompressor.h"
6*a3a45f30SXin Li
7*a3a45f30SXin Li #include "bsdiff/logging.h"
8*a3a45f30SXin Li
9*a3a45f30SXin Li namespace bsdiff {
10*a3a45f30SXin Li
~BrotliDecompressor()11*a3a45f30SXin Li BrotliDecompressor::~BrotliDecompressor() {
12*a3a45f30SXin Li if (brotli_decoder_state_)
13*a3a45f30SXin Li BrotliDecoderDestroyInstance(brotli_decoder_state_);
14*a3a45f30SXin Li }
15*a3a45f30SXin Li
SetInputData(const uint8_t * input_data,size_t size)16*a3a45f30SXin Li bool BrotliDecompressor::SetInputData(const uint8_t* input_data, size_t size) {
17*a3a45f30SXin Li brotli_decoder_state_ =
18*a3a45f30SXin Li BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
19*a3a45f30SXin Li if (brotli_decoder_state_ == nullptr) {
20*a3a45f30SXin Li LOG(ERROR) << "Failed to initialize brotli decoder.";
21*a3a45f30SXin Li return false;
22*a3a45f30SXin Li }
23*a3a45f30SXin Li next_in_ = input_data;
24*a3a45f30SXin Li available_in_ = size;
25*a3a45f30SXin Li return true;
26*a3a45f30SXin Li }
27*a3a45f30SXin Li
Read(uint8_t * output_data,size_t bytes_to_output)28*a3a45f30SXin Li bool BrotliDecompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
29*a3a45f30SXin Li if (!brotli_decoder_state_) {
30*a3a45f30SXin Li LOG(ERROR) << "BrotliDecompressor not initialized";
31*a3a45f30SXin Li return false;
32*a3a45f30SXin Li }
33*a3a45f30SXin Li auto next_out = output_data;
34*a3a45f30SXin Li size_t available_out = bytes_to_output;
35*a3a45f30SXin Li
36*a3a45f30SXin Li while (available_out > 0) {
37*a3a45f30SXin Li // The brotli decoder will update |available_in_|, |available_in_|,
38*a3a45f30SXin Li // |next_out| and |available_out|.
39*a3a45f30SXin Li BrotliDecoderResult result = BrotliDecoderDecompressStream(
40*a3a45f30SXin Li brotli_decoder_state_, &available_in_, &next_in_, &available_out,
41*a3a45f30SXin Li &next_out, nullptr);
42*a3a45f30SXin Li
43*a3a45f30SXin Li if (result == BROTLI_DECODER_RESULT_ERROR) {
44*a3a45f30SXin Li LOG(ERROR) << "Decompression failed with "
45*a3a45f30SXin Li << BrotliDecoderErrorString(
46*a3a45f30SXin Li BrotliDecoderGetErrorCode(brotli_decoder_state_));
47*a3a45f30SXin Li return false;
48*a3a45f30SXin Li } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
49*a3a45f30SXin Li LOG(ERROR) << "Decompressor reached EOF while reading from input stream.";
50*a3a45f30SXin Li return false;
51*a3a45f30SXin Li } else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
52*a3a45f30SXin Li // This means that decoding is finished, no more input might be consumed
53*a3a45f30SXin Li // and no more output will be produced. In the normal case, when there is
54*a3a45f30SXin Li // more data available than what was requested in this Read() call it
55*a3a45f30SXin Li // returns BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT.
56*a3a45f30SXin Li if (available_out > 0) {
57*a3a45f30SXin Li LOG(ERROR) << "Expected to read " << available_out
58*a3a45f30SXin Li << " more bytes but reached the end of compressed brotli "
59*a3a45f30SXin Li "stream";
60*a3a45f30SXin Li return false;
61*a3a45f30SXin Li }
62*a3a45f30SXin Li return true;
63*a3a45f30SXin Li }
64*a3a45f30SXin Li }
65*a3a45f30SXin Li return true;
66*a3a45f30SXin Li }
67*a3a45f30SXin Li
Close()68*a3a45f30SXin Li bool BrotliDecompressor::Close() {
69*a3a45f30SXin Li if (!brotli_decoder_state_) {
70*a3a45f30SXin Li LOG(ERROR) << "BrotliDecompressor not initialized";
71*a3a45f30SXin Li return false;
72*a3a45f30SXin Li }
73*a3a45f30SXin Li // In some cases, the brotli compressed stream could be empty. As a result,
74*a3a45f30SXin Li // the function BrotliDecoderIsFinished() will return false because we never
75*a3a45f30SXin Li // start the decompression. When that happens, we just destroy the decoder
76*a3a45f30SXin Li // and return true.
77*a3a45f30SXin Li if (BrotliDecoderIsUsed(brotli_decoder_state_) &&
78*a3a45f30SXin Li !BrotliDecoderIsFinished(brotli_decoder_state_)) {
79*a3a45f30SXin Li LOG(ERROR) << "Unfinished brotli decoder.";
80*a3a45f30SXin Li return false;
81*a3a45f30SXin Li }
82*a3a45f30SXin Li
83*a3a45f30SXin Li BrotliDecoderDestroyInstance(brotli_decoder_state_);
84*a3a45f30SXin Li brotli_decoder_state_ = nullptr;
85*a3a45f30SXin Li return true;
86*a3a45f30SXin Li }
87*a3a45f30SXin Li
88*a3a45f30SXin Li } // namespace bsdiff
89