/* Copyright 2016 Google Inc. All Rights Reserved. Distributed under MIT license. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT */ /* Brotli compressor API C++ wrapper and utilities. */ #include "./compressor.h" #include /* exit */ namespace brotli { static void ConvertParams(const BrotliParams* from, BrotliEncoderParams* to) { BrotliEncoderParamsSetDefault(to); if (from->mode == BrotliParams::MODE_TEXT) { to->mode = BROTLI_MODE_TEXT; } else if (from->mode == BrotliParams::MODE_FONT) { to->mode = BROTLI_MODE_FONT; } to->quality = from->quality; to->lgwin = from->lgwin; to->lgblock = from->lgblock; } BrotliCompressor::BrotliCompressor(BrotliParams params) { BrotliEncoderParams encoder_params; ConvertParams(¶ms, &encoder_params); state_ = BrotliEncoderCreateState(&encoder_params, 0, 0, 0); if (state_ == 0) std::exit(EXIT_FAILURE); /* OOM */ } BrotliCompressor::~BrotliCompressor(void) { BrotliEncoderDestroyState(state_); } bool BrotliCompressor::WriteMetaBlock(const size_t input_size, const uint8_t* input_buffer, const bool is_last, size_t* encoded_size, uint8_t* encoded_buffer) { return !!BrotliEncoderWriteMetaBlock(state_, input_size, input_buffer, is_last ? 1 : 0, encoded_size, encoded_buffer); } bool BrotliCompressor::WriteMetadata(const size_t input_size, const uint8_t* input_buffer, const bool is_last, size_t* encoded_size, uint8_t* encoded_buffer) { return !!BrotliEncoderWriteMetadata(state_, input_size, input_buffer, is_last ? 1 : 0, encoded_size, encoded_buffer); } bool BrotliCompressor::FinishStream(size_t* encoded_size, uint8_t* encoded_buffer) { return !!BrotliEncoderFinishStream(state_, encoded_size, encoded_buffer); } void BrotliCompressor::CopyInputToRingBuffer(const size_t input_size, const uint8_t* input_buffer) { BrotliEncoderCopyInputToRingBuffer(state_, input_size, input_buffer); } bool BrotliCompressor::WriteBrotliData(const bool is_last, const bool force_flush, size_t* out_size, uint8_t** output) { return !!BrotliEncoderWriteData( state_, is_last ? 1 : 0, force_flush ? 1 : 0, out_size, output); } void BrotliCompressor::BrotliSetCustomDictionary(size_t size, const uint8_t* dict) { BrotliEncoderSetCustomDictionary(state_, size, dict); } int BrotliCompressBuffer(BrotliParams params, size_t input_size, const uint8_t* input_buffer, size_t* encoded_size, uint8_t* encoded_buffer) { return BrotliEncoderCompress(params.quality, params.lgwin, (BrotliEncoderMode)params.mode, input_size, input_buffer, encoded_size, encoded_buffer); } int BrotliCompress(BrotliParams params, BrotliIn* in, BrotliOut* out) { return BrotliCompressWithCustomDictionary(0, 0, params, in, out); } int BrotliCompressWithCustomDictionary(size_t dictsize, const uint8_t* dict, BrotliParams params, BrotliIn* in, BrotliOut* out) { const size_t kOutputBufferSize = 65536; uint8_t* output_buffer; bool result = true; size_t available_in = 0; const uint8_t* next_in = NULL; size_t total_out = 0; bool end_of_input = false; BrotliEncoderParams encoder_params; BrotliEncoderState* s; ConvertParams(¶ms, &encoder_params); s = BrotliEncoderCreateState(&encoder_params, 0, 0, 0); if (!s) return 0; BrotliEncoderSetCustomDictionary(s, dictsize, dict); output_buffer = new uint8_t[kOutputBufferSize]; while (true) { if (available_in == 0 && !end_of_input) { next_in = reinterpret_cast( in->Read(BrotliEncoderInputBlockSize(s), &available_in)); if (!next_in) { end_of_input = true; available_in = 0; } else if (available_in == 0) { continue; } } size_t available_out = kOutputBufferSize; uint8_t* next_out = output_buffer; result = !!BrotliEncoderCompressStream( s, end_of_input ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS, &available_in, &next_in, &available_out, &next_out, &total_out); if (!result) break; size_t used_output = kOutputBufferSize - available_out; if (used_output != 0) { result = out->Write(output_buffer, used_output); if (!result) break; } if (BrotliEncoderIsFinished(s)) break; } delete[] output_buffer; BrotliEncoderDestroyState(s); return result ? 1 : 0; } } /* namespace brotli */