You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.9 KiB
98 lines
2.9 KiB
4 months ago
|
// 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"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
const size_t kBufferSize = 1024 * 1024;
|
||
|
const uint32_t kBrotliDefaultLgwin = 20;
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
namespace bsdiff {
|
||
|
BrotliCompressor::BrotliCompressor(int quality) : comp_buffer_(kBufferSize) {
|
||
|
brotli_encoder_state_ =
|
||
|
BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
|
||
|
if (!brotli_encoder_state_) {
|
||
|
LOG(ERROR) << "Failed to initialize brotli decoder state";
|
||
|
} else {
|
||
|
int compression_quality = quality;
|
||
|
if (compression_quality > BROTLI_MAX_QUALITY ||
|
||
|
compression_quality < BROTLI_MIN_QUALITY) {
|
||
|
LOG(ERROR) << "Invalid quality value: " << quality
|
||
|
<< ", using default quality instead.";
|
||
|
compression_quality = BROTLI_MAX_QUALITY;
|
||
|
}
|
||
|
|
||
|
BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_QUALITY,
|
||
|
compression_quality);
|
||
|
BrotliEncoderSetParameter(brotli_encoder_state_, BROTLI_PARAM_LGWIN,
|
||
|
kBrotliDefaultLgwin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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.";
|
||
|
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";
|
||
|
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
|