xref: /aosp_15_r20/external/bsdiff/brotli_decompressor.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
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