blob: 50890d73c6b242acbd2d737cc406df63dbcc2468 [file] [log] [blame]
Tianjie Xu1c26e2e2017-10-26 17:19:41 -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_compressor.h"
6
7#include "bsdiff/logging.h"
8
Tianjie Xu1c26e2e2017-10-26 17:19:41 -07009namespace {
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080010
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070011const size_t kBufferSize = 1024 * 1024;
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080012const uint32_t kBrotliDefaultLgwin = 20;
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070013
14} // namespace
15
16namespace bsdiff {
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080017BrotliCompressor::BrotliCompressor(int quality) : comp_buffer_(kBufferSize) {
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070018 brotli_encoder_state_ =
19 BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
20 if (!brotli_encoder_state_) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080021 LOG(ERROR) << "Failed to initialize brotli decoder state";
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070022 } else {
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080023 int compression_quality = quality;
24 if (compression_quality > BROTLI_MAX_QUALITY ||
25 compression_quality < BROTLI_MIN_QUALITY) {
26 LOG(ERROR) << "Invalid quality value: " << quality
27 << ", using default quality instead.";
28 compression_quality = BROTLI_MAX_QUALITY;
29 }
30
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070031 BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_QUALITY,
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080032 compression_quality);
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070033 BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_LGWIN,
Tianjie Xu1f1cdb22017-11-20 11:05:55 -080034 kBrotliDefaultLgwin);
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070035 }
36}
37
38BrotliCompressor::~BrotliCompressor() {
39 if (brotli_encoder_state_) {
40 BrotliEncoderDestroyInstance(brotli_encoder_state_);
41 }
42}
43
44bool BrotliCompressor::Write(const uint8_t* buf, size_t size) {
45 if (!brotli_encoder_state_)
46 return false;
47
48 const uint8_t* next_in = buf;
49 size_t avail_in = size;
50 while (avail_in > 0) {
51 size_t avail_out = kBufferSize;
52 uint8_t* next_out = comp_buffer_.buffer_data();
53 if (!BrotliEncoderCompressStream(
54 brotli_encoder_state_, BROTLI_OPERATION_PROCESS, &avail_in,
55 &next_in, &avail_out, &next_out, nullptr)) {
56 LOG(ERROR) << "BrotliCompressor failed to compress " << avail_in
Tianjie Xu18480eb2017-11-29 16:21:43 -080057 << " bytes of data.";
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070058 return false;
59 }
60
61 uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
62 if (output_bytes > 0) {
63 comp_buffer_.AddDataToChunks(output_bytes);
64 }
65 }
66 return true;
67}
68
69bool BrotliCompressor::Finish() {
70 if (!brotli_encoder_state_)
71 return false;
72
73 const uint8_t* next_in = nullptr;
74 size_t avail_in = 0;
75 while (!BrotliEncoderIsFinished(brotli_encoder_state_)) {
76 size_t avail_out = kBufferSize;
77 uint8_t* next_out = comp_buffer_.buffer_data();
78 if (!BrotliEncoderCompressStream(
79 brotli_encoder_state_, BROTLI_OPERATION_FINISH, &avail_in, &next_in,
80 &avail_out, &next_out, nullptr)) {
Tianjie Xu18480eb2017-11-29 16:21:43 -080081 LOG(ERROR) << "BrotliCompressor failed to finish compression";
Tianjie Xu1c26e2e2017-10-26 17:19:41 -070082 return false;
83 }
84
85 uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
86 if (output_bytes > 0) {
87 comp_buffer_.AddDataToChunks(output_bytes);
88 }
89 }
90 return true;
91}
92
93const std::vector<uint8_t>& BrotliCompressor::GetCompressedData() {
94 return comp_buffer_.GetCompressedData();
95}
96
97} // namespace bsdiff