1// Copyright 2017 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 "bsdiff/brotli_decompressor.h"
6
7#include "bsdiff/logging.h"
8
9namespace bsdiff {
10
11bool BrotliDecompressor::SetInputData(const uint8_t* input_data, size_t size) {
12  brotli_decoder_state_ =
13      BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
14  if (brotli_decoder_state_ == nullptr) {
15    LOG(ERROR) << "Failed to initialize brotli decoder.";
16    return false;
17  }
18  next_in_ = input_data;
19  available_in_ = size;
20  return true;
21}
22
23bool BrotliDecompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
24  auto next_out = output_data;
25  size_t available_out = bytes_to_output;
26
27  while (available_out > 0) {
28    // The brotli decoder will update |available_in_|, |available_in_|,
29    // |next_out| and |available_out|.
30    BrotliDecoderResult result = BrotliDecoderDecompressStream(
31        brotli_decoder_state_, &available_in_, &next_in_, &available_out,
32        &next_out, nullptr);
33
34    if (result == BROTLI_DECODER_RESULT_ERROR) {
35      LOG(ERROR) << "Decompression failed with "
36                 << BrotliDecoderErrorString(
37                        BrotliDecoderGetErrorCode(brotli_decoder_state_));
38      return false;
39    } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
40      LOG(ERROR) << "Decompressor reached EOF while reading from input stream.";
41      return false;
42    }
43  }
44  return true;
45}
46
47bool BrotliDecompressor::Close() {
48  // In some cases, the brotli compressed stream could be empty. As a result,
49  // the function BrotliDecoderIsFinished() will return false because we never
50  // start the decompression. When that happens, we just destroy the decoder
51  // and return true.
52  if (BrotliDecoderIsUsed(brotli_decoder_state_) &&
53      !BrotliDecoderIsFinished(brotli_decoder_state_)) {
54    LOG(ERROR) << "Unfinished brotli decoder.";
55    return false;
56  }
57
58  BrotliDecoderDestroyInstance(brotli_decoder_state_);
59  return true;
60}
61
62}  // namespace bsdiff
63