blob: 50d4b2d0eaa2454409451479f226a15dea03d319 [file] [log] [blame]
Alex Deymoa28e0192017-09-08 14:21:05 +02001// 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
Alex Deymodcd423b2017-09-13 20:54:24 +02005#include "bsdiff/bz2_compressor.h"
Alex Deymoa28e0192017-09-08 14:21:05 +02006
7#include <string.h>
8
Alex Deymodcd423b2017-09-13 20:54:24 +02009#include "bsdiff/logging.h"
Alex Deymoa28e0192017-09-08 14:21:05 +020010
Alex Deymoa28e0192017-09-08 14:21:05 +020011namespace {
12
13// The BZ2 compression level used. Smaller compression levels are nowadays
14// pointless.
15const int kCompressionLevel = 9;
16
17} // namespace
18
19namespace bsdiff {
20
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070021BZ2Compressor::BZ2Compressor() : comp_buffer_(1024 * 1024) {
Alex Deymoa28e0192017-09-08 14:21:05 +020022 memset(&bz_strm_, 0, sizeof(bz_strm_));
23 int bz_err = BZ2_bzCompressInit(&bz_strm_, kCompressionLevel,
24 0 /* verbosity */, 0 /* workFactor */);
25 if (bz_err != BZ_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080026 LOG(ERROR) << "Initializing bz_strm, bz_error=" << bz_err;
Alex Deymoa28e0192017-09-08 14:21:05 +020027 } else {
28 bz_strm_initialized_ = true;
29 }
Alex Deymoa28e0192017-09-08 14:21:05 +020030}
31
32BZ2Compressor::~BZ2Compressor() {
33 if (!bz_strm_initialized_)
34 return;
35 int bz_err = BZ2_bzCompressEnd(&bz_strm_);
36 if (bz_err != BZ_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080037 LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err;
Alex Deymoa28e0192017-09-08 14:21:05 +020038 }
39}
40
41bool BZ2Compressor::Write(const uint8_t* buf, size_t size) {
42 if (!bz_strm_initialized_)
43 return false;
44
45 // The bz_stream struct defines the next_in as a non-const data pointer,
46 // although the documentation says it won't modify it.
47 bz_strm_.next_in = reinterpret_cast<char*>(const_cast<uint8_t*>(buf));
48 bz_strm_.avail_in = size;
49
50 while (bz_strm_.avail_in) {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070051 bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.buffer_data());
52 bz_strm_.avail_out = comp_buffer_.buffer_size();
Alex Deymoa28e0192017-09-08 14:21:05 +020053 int bz_err = BZ2_bzCompress(&bz_strm_, BZ_RUN);
54 if (bz_err != BZ_RUN_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080055 LOG(ERROR) << "Compressing data, bz_error=" << bz_err;
Alex Deymoa28e0192017-09-08 14:21:05 +020056 return false;
57 }
58
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070059 uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out;
Alex Deymoa28e0192017-09-08 14:21:05 +020060 if (output_bytes) {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070061 comp_buffer_.AddDataToChunks(output_bytes);
Alex Deymoa28e0192017-09-08 14:21:05 +020062 }
63 }
64 return true;
65}
66
67bool BZ2Compressor::Finish() {
68 if (!bz_strm_initialized_)
69 return false;
70 bz_strm_.next_in = nullptr;
71 bz_strm_.avail_in = 0;
72
73 int bz_err = BZ_FINISH_OK;
74 while (bz_err == BZ_FINISH_OK) {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070075 bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.buffer_data());
76 bz_strm_.avail_out = comp_buffer_.buffer_size();
Alex Deymoa28e0192017-09-08 14:21:05 +020077 bz_err = BZ2_bzCompress(&bz_strm_, BZ_FINISH);
78
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070079 uint64_t output_bytes = comp_buffer_.buffer_size() - bz_strm_.avail_out;
Alex Deymoa28e0192017-09-08 14:21:05 +020080 if (output_bytes) {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070081 comp_buffer_.AddDataToChunks(output_bytes);
Alex Deymoa28e0192017-09-08 14:21:05 +020082 }
83 }
84 if (bz_err != BZ_STREAM_END) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080085 LOG(ERROR) << "Finishing compressing data, bz_error=" << bz_err;
Alex Deymoa28e0192017-09-08 14:21:05 +020086 return false;
87 }
88 bz_err = BZ2_bzCompressEnd(&bz_strm_);
89 bz_strm_initialized_ = false;
90 if (bz_err != BZ_OK) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080091 LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err;
Alex Deymoa28e0192017-09-08 14:21:05 +020092 return false;
93 }
94 return true;
95}
96
97const std::vector<uint8_t>& BZ2Compressor::GetCompressedData() {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070098 return comp_buffer_.GetCompressedData();
Alex Deymoa28e0192017-09-08 14:21:05 +020099}
100
101} // namespace bsdiff