blob: 40b21fad46d23c4eb1572c30d811aac39078af09 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "zst_compressor.h"
#include <iostream>
#include "third_party/zstd/src/lib/zstd.h"
ZstCompressor::ZstCompressor(std::ostream& output_stream, int compression_level)
: output_stream_(output_stream) {
input_buffer_recommended_size_ = ZSTD_CStreamInSize();
input_struct_ = new ZSTD_inBuffer{/* src = */ nullptr,
/* size = */ 0,
/* pos = */ 0};
output_buffer_size_ = ZSTD_CStreamOutSize();
output_buffer_ = new char[output_buffer_size_];
output_struct_ = new ZSTD_outBuffer{/* dst = */ output_buffer_,
/* size = */ output_buffer_size_,
/* pos = */ 0};
ctx_ = ZSTD_createCCtx();
if (ctx_ == nullptr) {
std::cerr << "ZSTD_createCCtx failed!" << std::endl;
exit(1);
}
size_t ret =
ZSTD_CCtx_setParameter(ctx_, ZSTD_c_compressionLevel, compression_level);
if (ZSTD_isError(ret)) {
std::cerr << "ZSTD_CCtx_setParameter returned an error: "
<< ZSTD_getErrorName(ret) << std::endl;
exit(1);
}
}
ZstCompressor::~ZstCompressor() {
delete input_struct_;
delete[] output_buffer_;
delete output_struct_;
ZSTD_freeCCtx(ctx_);
}
size_t ZstCompressor::GetRecommendedInputBufferSize() {
return input_buffer_recommended_size_;
}
void ZstCompressor::CompressStreaming(UncompressedContent input,
bool last_chunk) {
input_struct_->src = input.buffer;
input_struct_->size = input.size;
input_struct_->pos = 0;
ZSTD_EndDirective mode = last_chunk ? ZSTD_e_end : ZSTD_e_continue;
// Repeatedly call ZSTD_compressStream2() until it has consumed all the input.
bool finished = false;
while (!finished) {
output_struct_->pos = 0;
size_t ret =
ZSTD_compressStream2(ctx_, output_struct_, input_struct_, mode);
if (ZSTD_isError(ret)) {
std::cerr << "ZSTD_compressStream returned an error: "
<< ZSTD_getErrorName(ret) << std::endl;
exit(1);
}
output_stream_.write(output_buffer_, output_struct_->pos);
if (output_stream_.fail()) {
std::cerr << "ZST compressor failed to write to output_stream."
<< std::endl;
exit(1);
}
// If we are processing the last chunk, we are finished when zstd returns 0,
// which means it has consumed all the input AND flushed all the output.
// Otherwise, we are finished when it has consumed all the input.
if (last_chunk) {
finished = (ret == 0);
} else {
finished = (input_struct_->pos == input.size);
}
}
}