blob: 80a7242270253d46f77eb92fdf92f360480fd9bb [file] [log] [blame]
Tianjie Xu4d10c3e2017-10-26 14:02:06 -07001// 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
Tianjie Xu4d10c3e2017-10-26 14:02:06 -07009namespace bsdiff {
10
Alex Deymoc2ae7a52018-03-12 19:23:35 +010011BrotliDecompressor::~BrotliDecompressor() {
12 if (brotli_decoder_state_)
13 BrotliDecoderDestroyInstance(brotli_decoder_state_);
14}
15
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070016bool BrotliDecompressor::SetInputData(const uint8_t* input_data, size_t size) {
17 brotli_decoder_state_ =
18 BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
19 if (brotli_decoder_state_ == nullptr) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080020 LOG(ERROR) << "Failed to initialize brotli decoder.";
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070021 return false;
22 }
23 next_in_ = input_data;
24 available_in_ = size;
25 return true;
26}
27
28bool BrotliDecompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
Alex Deymoc2ae7a52018-03-12 19:23:35 +010029 if (!brotli_decoder_state_) {
30 LOG(ERROR) << "BrotliDecompressor not initialized";
31 return false;
32 }
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070033 auto next_out = output_data;
34 size_t available_out = bytes_to_output;
35
36 while (available_out > 0) {
37 // The brotli decoder will update |available_in_|, |available_in_|,
38 // |next_out| and |available_out|.
39 BrotliDecoderResult result = BrotliDecoderDecompressStream(
40 brotli_decoder_state_, &available_in_, &next_in_, &available_out,
41 &next_out, nullptr);
42
43 if (result == BROTLI_DECODER_RESULT_ERROR) {
44 LOG(ERROR) << "Decompression failed with "
45 << BrotliDecoderErrorString(
Tianjie Xu18480eb2017-11-29 16:21:43 -080046 BrotliDecoderGetErrorCode(brotli_decoder_state_));
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070047 return false;
48 } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080049 LOG(ERROR) << "Decompressor reached EOF while reading from input stream.";
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070050 return false;
Alex Deymo338f3402018-03-23 13:40:17 +010051 } else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
52 // This means that decoding is finished, no more input might be consumed
53 // and no more output will be produced. In the normal case, when there is
54 // more data available than what was requested in this Read() call it
55 // returns BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT.
56 if (available_out > 0) {
57 LOG(ERROR) << "Expected to read " << available_out
58 << " more bytes but reached the end of compressed brotli "
59 "stream";
60 return false;
61 }
62 return true;
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070063 }
64 }
65 return true;
66}
67
68bool BrotliDecompressor::Close() {
Alex Deymoc2ae7a52018-03-12 19:23:35 +010069 if (!brotli_decoder_state_) {
70 LOG(ERROR) << "BrotliDecompressor not initialized";
71 return false;
72 }
Tianjie Xud4875cd2017-11-17 16:06:30 -080073 // In some cases, the brotli compressed stream could be empty. As a result,
74 // the function BrotliDecoderIsFinished() will return false because we never
75 // start the decompression. When that happens, we just destroy the decoder
76 // and return true.
77 if (BrotliDecoderIsUsed(brotli_decoder_state_) &&
78 !BrotliDecoderIsFinished(brotli_decoder_state_)) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080079 LOG(ERROR) << "Unfinished brotli decoder.";
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070080 return false;
81 }
82
83 BrotliDecoderDestroyInstance(brotli_decoder_state_);
Alex Deymoc2ae7a52018-03-12 19:23:35 +010084 brotli_decoder_state_ = nullptr;
Tianjie Xu4d10c3e2017-10-26 14:02:06 -070085 return true;
86}
87
Alex Deymo9bb4ddb2018-02-14 16:30:54 +010088} // namespace bsdiff