#include "snappy-test.h"
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
namespace file {
OptionsStub::OptionsStub() = default;
OptionsStub::~OptionsStub() = default;
const OptionsStub &Defaults() {
static OptionsStub defaults;
return defaults;
}
StatusStub::StatusStub() = default;
StatusStub::StatusStub(const StatusStub &) = default;
StatusStub &StatusStub::operator=(const StatusStub &) = default;
StatusStub::~StatusStub() = default;
bool StatusStub::ok() { return true; }
StatusStub GetContents(const std::string &filename, std::string *output,
const OptionsStub & ) {
std::FILE *fp = std::fopen(filename.c_str(), "rb");
if (fp == nullptr) {
std::perror(filename.c_str());
std::exit(1);
}
output->clear();
while (!std::feof(fp)) {
char buffer[4096];
size_t bytes_read = std::fread(buffer, 1, sizeof(buffer), fp);
if (bytes_read == 0 && std::ferror(fp)) {
std::perror("fread");
std::exit(1);
}
output->append(buffer, bytes_read);
}
std::fclose(fp);
return StatusStub();
}
StatusStub SetContents(const std::string &file_name, const std::string &content,
const OptionsStub & ) {
std::FILE *fp = std::fopen(file_name.c_str(), "wb");
if (fp == nullptr) {
std::perror(file_name.c_str());
std::exit(1);
}
size_t bytes_written = std::fwrite(content.data(), 1, content.size(), fp);
if (bytes_written != content.size()) {
std::perror("fwrite");
std::exit(1);
}
std::fclose(fp);
return StatusStub();
}
}
namespace snappy {
std::string ReadTestDataFile(const std::string& base, size_t size_limit) {
std::string contents;
const char* srcdir = getenv("srcdir"); std::string prefix;
if (srcdir) {
prefix = std::string(srcdir) + "/";
}
file::GetContents(prefix + "testdata/" + base, &contents, file::Defaults()
).ok();
if (size_limit > 0) {
contents = contents.substr(0, size_limit);
}
return contents;
}
std::string StrFormat(const char* format, ...) {
char buffer[4096];
std::va_list ap;
va_start(ap, format);
std::vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
return buffer;
}
LogMessage::~LogMessage() { std::cerr << std::endl; }
LogMessage &LogMessage::operator<<(const std::string &message) {
std::cerr << message;
return *this;
}
LogMessage &LogMessage::operator<<(int number) {
std::cerr << number;
return *this;
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4722)
#endif
LogMessageCrash::~LogMessageCrash() {
std::cerr << std::endl;
std::abort();
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#if HAVE_LIBZ
ZLib::ZLib()
: comp_init_(false),
uncomp_init_(false) {
Reinit();
}
ZLib::~ZLib() {
if (comp_init_) { deflateEnd(&comp_stream_); }
if (uncomp_init_) { inflateEnd(&uncomp_stream_); }
}
void ZLib::Reinit() {
compression_level_ = Z_DEFAULT_COMPRESSION;
window_bits_ = MAX_WBITS;
mem_level_ = 8; if (comp_init_) {
deflateEnd(&comp_stream_);
comp_init_ = false;
}
if (uncomp_init_) {
inflateEnd(&uncomp_stream_);
uncomp_init_ = false;
}
first_chunk_ = true;
}
void ZLib::Reset() {
first_chunk_ = true;
}
void ZLib::CompressErrorInit() {
deflateEnd(&comp_stream_);
comp_init_ = false;
Reset();
}
int ZLib::DeflateInit() {
return deflateInit2(&comp_stream_,
compression_level_,
Z_DEFLATED,
window_bits_,
mem_level_,
Z_DEFAULT_STRATEGY);
}
int ZLib::CompressInit(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen) {
int err;
comp_stream_.next_in = (Bytef*)source;
comp_stream_.avail_in = (uInt)*sourceLen;
if ((uLong)comp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR;
comp_stream_.next_out = dest;
comp_stream_.avail_out = (uInt)*destLen;
if ((uLong)comp_stream_.avail_out != *destLen) return Z_BUF_ERROR;
if ( !first_chunk_ ) return Z_OK;
if (comp_init_) { err = deflateReset(&comp_stream_);
if (err != Z_OK) {
LOG(WARNING) << "ERROR: Can't reset compress object; creating a new one";
deflateEnd(&comp_stream_);
comp_init_ = false;
}
}
if (!comp_init_) { comp_stream_.zalloc = (alloc_func)0;
comp_stream_.zfree = (free_func)0;
comp_stream_.opaque = (voidpf)0;
err = DeflateInit();
if (err != Z_OK) return err;
comp_init_ = true;
}
return Z_OK;
}
int ZLib::CompressAtMostOrAll(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen,
int flush_mode) { int err;
if ( (err=CompressInit(dest, destLen, source, sourceLen)) != Z_OK )
return err;
int compressed_size = comp_stream_.total_out;
if ( first_chunk_ ) {
first_chunk_ = false;
}
err = deflate(&comp_stream_, flush_mode);
*sourceLen = comp_stream_.avail_in;
if ((err == Z_STREAM_END || err == Z_OK)
&& comp_stream_.avail_in == 0
&& comp_stream_.avail_out != 0 ) {
;
} else if (err == Z_STREAM_END && comp_stream_.avail_in > 0) {
return Z_BUF_ERROR; } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
CompressErrorInit();
return err;
} else if (comp_stream_.avail_out == 0) { err = Z_BUF_ERROR;
}
assert(err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR);
if (err == Z_STREAM_END)
err = Z_OK;
compressed_size = comp_stream_.total_out - compressed_size; *destLen = compressed_size;
return err;
}
int ZLib::CompressChunkOrAll(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int flush_mode) { const int ret =
CompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode);
if (ret == Z_BUF_ERROR)
CompressErrorInit();
return ret;
}
int ZLib::Compress(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen) {
int err;
if ( (err=CompressChunkOrAll(dest, destLen, source, sourceLen,
Z_FINISH)) != Z_OK )
return err;
Reset();
return Z_OK;
}
int ZLib::InflateInit() {
return inflateInit2(&uncomp_stream_, MAX_WBITS);
}
void ZLib::UncompressErrorInit() {
inflateEnd(&uncomp_stream_);
uncomp_init_ = false;
Reset();
}
int ZLib::UncompressInit(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen) {
int err;
uncomp_stream_.next_in = (Bytef*)source;
uncomp_stream_.avail_in = (uInt)*sourceLen;
if ((uLong)uncomp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR;
uncomp_stream_.next_out = dest;
uncomp_stream_.avail_out = (uInt)*destLen;
if ((uLong)uncomp_stream_.avail_out != *destLen) return Z_BUF_ERROR;
if ( !first_chunk_ ) return Z_OK;
if (uncomp_init_) { err = inflateReset(&uncomp_stream_);
if (err != Z_OK) {
LOG(WARNING)
<< "ERROR: Can't reset uncompress object; creating a new one";
UncompressErrorInit();
}
}
if (!uncomp_init_) {
uncomp_stream_.zalloc = (alloc_func)0;
uncomp_stream_.zfree = (free_func)0;
uncomp_stream_.opaque = (voidpf)0;
err = InflateInit();
if (err != Z_OK) return err;
uncomp_init_ = true;
}
return Z_OK;
}
int ZLib::UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen,
int flush_mode) { int err = Z_OK;
if ( (err=UncompressInit(dest, destLen, source, sourceLen)) != Z_OK ) {
LOG(WARNING) << "UncompressInit: Error: " << err << " SourceLen: "
<< *sourceLen;
return err;
}
const uLong old_total_out = uncomp_stream_.total_out;
const uLong old_total_in = uncomp_stream_.total_in;
if ( first_chunk_ ) {
first_chunk_ = false;
if ( *sourceLen == 0 ) {
*destLen = 0;
return Z_OK;
}
}
err = inflate(&uncomp_stream_, flush_mode);
const uLong bytes_read = uncomp_stream_.total_in - old_total_in;
CHECK_LE(source + bytes_read, source + *sourceLen);
*sourceLen = uncomp_stream_.avail_in;
if ((err == Z_STREAM_END || err == Z_OK) && uncomp_stream_.avail_in == 0) { ;
} else if (err == Z_STREAM_END && uncomp_stream_.avail_in > 0) {
LOG(WARNING)
<< "UncompressChunkOrAll: Received some extra data, bytes total: "
<< uncomp_stream_.avail_in << " bytes: "
<< std::string(reinterpret_cast<const char *>(uncomp_stream_.next_in),
std::min(int(uncomp_stream_.avail_in), 20));
UncompressErrorInit();
return Z_DATA_ERROR; } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
LOG(WARNING) << "UncompressChunkOrAll: Error: " << err
<< " avail_out: " << uncomp_stream_.avail_out;
UncompressErrorInit();
return err;
} else if (uncomp_stream_.avail_out == 0) {
err = Z_BUF_ERROR;
}
assert(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END);
if (err == Z_STREAM_END)
err = Z_OK;
*destLen = uncomp_stream_.total_out - old_total_out;
return err;
}
int ZLib::UncompressChunkOrAll(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int flush_mode) { const int ret =
UncompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode);
if (ret == Z_BUF_ERROR)
UncompressErrorInit();
return ret;
}
int ZLib::UncompressAtMost(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen) {
return UncompressAtMostOrAll(dest, destLen, source, sourceLen, Z_SYNC_FLUSH);
}
bool ZLib::UncompressChunkDone() {
assert(!first_chunk_ && uncomp_init_);
Bytef dummyin, dummyout;
uLongf dummylen = 0;
if ( UncompressChunkOrAll(&dummyout, &dummylen, &dummyin, 0, Z_FINISH)
!= Z_OK ) {
return false;
}
Reset();
return true;
}
int ZLib::Uncompress(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen) {
int err;
if ( (err=UncompressChunkOrAll(dest, destLen, source, sourceLen,
Z_FINISH)) != Z_OK ) {
Reset(); return err;
}
if ( !UncompressChunkDone() ) return Z_DATA_ERROR;
return Z_OK; }
#endif
}