blob: 82386500122a377e699f0e7bdfa7e4ddcb055348 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bsdiff/brotli_compressor.h"
#include "bsdiff/logging.h"
using std::endl;
namespace {
// TODO(xunchang) set brotli compression parameters based on input options.
const size_t kBufferSize = 1024 * 1024;
const uint32_t kBrotliQuality = 11;
const uint32_t kBrotliLgwin = 24;
} // namespace
namespace bsdiff {
BrotliCompressor::BrotliCompressor() : comp_buffer_(kBufferSize) {
brotli_encoder_state_ =
BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
if (!brotli_encoder_state_) {
LOG(ERROR) << "Failed to initialize brotli decoder state" << endl;
} else {
BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_QUALITY,
kBrotliQuality);
BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_LGWIN,
kBrotliLgwin);
}
}
BrotliCompressor::~BrotliCompressor() {
if (brotli_encoder_state_) {
BrotliEncoderDestroyInstance(brotli_encoder_state_);
}
}
bool BrotliCompressor::Write(const uint8_t* buf, size_t size) {
if (!brotli_encoder_state_)
return false;
const uint8_t* next_in = buf;
size_t avail_in = size;
while (avail_in > 0) {
size_t avail_out = kBufferSize;
uint8_t* next_out = comp_buffer_.buffer_data();
if (!BrotliEncoderCompressStream(
brotli_encoder_state_, BROTLI_OPERATION_PROCESS, &avail_in,
&next_in, &avail_out, &next_out, nullptr)) {
LOG(ERROR) << "BrotliCompressor failed to compress " << avail_in
<< " bytes of data." << endl;
return false;
}
uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
if (output_bytes > 0) {
comp_buffer_.AddDataToChunks(output_bytes);
}
}
return true;
}
bool BrotliCompressor::Finish() {
if (!brotli_encoder_state_)
return false;
const uint8_t* next_in = nullptr;
size_t avail_in = 0;
while (!BrotliEncoderIsFinished(brotli_encoder_state_)) {
size_t avail_out = kBufferSize;
uint8_t* next_out = comp_buffer_.buffer_data();
if (!BrotliEncoderCompressStream(
brotli_encoder_state_, BROTLI_OPERATION_FINISH, &avail_in, &next_in,
&avail_out, &next_out, nullptr)) {
LOG(ERROR) << "BrotliCompressor failed to finish compression" << endl;
return false;
}
uint64_t output_bytes = comp_buffer_.buffer_size() - avail_out;
if (output_bytes > 0) {
comp_buffer_.AddDataToChunks(output_bytes);
}
}
return true;
}
const std::vector<uint8_t>& BrotliCompressor::GetCompressedData() {
return comp_buffer_.GetCompressedData();
}
} // namespace bsdiff