blob: 4504ac5af2f16f738140cb704deeba53a5c26f83 [file] [log] [blame]
Tianjie Xu65288122017-10-13 15:10:58 -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/bz2_decompressor.h"
6
7#include <algorithm>
8#include <limits>
9
10#include <bzlib.h>
11
12#include "bsdiff/logging.h"
13
Tianjie Xu65288122017-10-13 15:10:58 -070014namespace bsdiff {
15
Alex Deymo942194f2018-03-12 19:15:43 +010016BZ2Decompressor::~BZ2Decompressor() {
17 // Release the memory on destruction if needed.
18 if (stream_initialized_)
19 BZ2_bzDecompressEnd(&stream_);
20}
21
Tianjie Xu65288122017-10-13 15:10:58 -070022bool BZ2Decompressor::SetInputData(const uint8_t* input_data, size_t size) {
23 // TODO(xunchang) update the avail_in for size > 2GB.
24 if (size > std::numeric_limits<unsigned int>::max()) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080025 LOG(ERROR) << "Oversized input data" << size;
Tianjie Xu65288122017-10-13 15:10:58 -070026 return false;
27 }
28
29 stream_.next_in = reinterpret_cast<char*>(const_cast<uint8_t*>(input_data));
30 stream_.avail_in = size;
31 stream_.bzalloc = nullptr;
32 stream_.bzfree = nullptr;
33 stream_.opaque = nullptr;
34 int bz2err = BZ2_bzDecompressInit(&stream_, 0, 0);
35 if (bz2err != BZ_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080036 LOG(ERROR) << "Failed to bzinit control stream: " << bz2err;
Tianjie Xu65288122017-10-13 15:10:58 -070037 return false;
38 }
Alex Deymo942194f2018-03-12 19:15:43 +010039 stream_initialized_ = true;
Tianjie Xu65288122017-10-13 15:10:58 -070040 return true;
41}
42
43bool BZ2Decompressor::Read(uint8_t* output_data, size_t bytes_to_output) {
Alex Deymo942194f2018-03-12 19:15:43 +010044 if (!stream_initialized_) {
45 LOG(ERROR) << "BZ2Decompressor not initialized";
46 return false;
47 }
Tianjie Xu65288122017-10-13 15:10:58 -070048 stream_.next_out = reinterpret_cast<char*>(output_data);
49 while (bytes_to_output > 0) {
50 size_t output_size = std::min<size_t>(
51 std::numeric_limits<unsigned int>::max(), bytes_to_output);
52 stream_.avail_out = output_size;
53
Alex Deymo64d5cd82018-03-12 20:00:04 +010054 size_t prev_avail_in = stream_.avail_in;
Tianjie Xu65288122017-10-13 15:10:58 -070055 int bz2err = BZ2_bzDecompress(&stream_);
56 if (bz2err != BZ_OK && bz2err != BZ_STREAM_END) {
57 LOG(ERROR) << "Failed to decompress " << output_size
Tianjie Xu18480eb2017-11-29 16:21:43 -080058 << " bytes of data, error: " << bz2err;
Tianjie Xu65288122017-10-13 15:10:58 -070059 return false;
60 }
61 bytes_to_output -= (output_size - stream_.avail_out);
Alex Deymo64d5cd82018-03-12 20:00:04 +010062 if (bytes_to_output && prev_avail_in == stream_.avail_in &&
63 output_size == stream_.avail_out) {
64 LOG(ERROR) << "BZ2Decompressor made no progress, pending "
65 << bytes_to_output << " bytes to decompress";
66 return false;
67 }
Tianjie Xu65288122017-10-13 15:10:58 -070068 }
69 return true;
70}
71
72bool BZ2Decompressor::Close() {
Alex Deymo942194f2018-03-12 19:15:43 +010073 if (!stream_initialized_) {
74 LOG(ERROR) << "BZ2Decompressor not initialized";
75 return false;
76 }
Tianjie Xu65288122017-10-13 15:10:58 -070077 int bz2err = BZ2_bzDecompressEnd(&stream_);
78 if (bz2err != BZ_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080079 LOG(ERROR) << "BZ2_bzDecompressEnd returns with " << bz2err;
Tianjie Xu65288122017-10-13 15:10:58 -070080 return false;
81 }
Alex Deymo942194f2018-03-12 19:15:43 +010082 stream_initialized_ = false;
Tianjie Xu65288122017-10-13 15:10:58 -070083 return true;
84}
85
Alex Deymo9bb4ddb2018-02-14 16:30:54 +010086} // namespace bsdiff