1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/other-licenses/snappy/src/snappy-test.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,594 @@ 1.4 +// Copyright 2011 Google Inc. All Rights Reserved. 1.5 +// 1.6 +// Redistribution and use in source and binary forms, with or without 1.7 +// modification, are permitted provided that the following conditions are 1.8 +// met: 1.9 +// 1.10 +// * Redistributions of source code must retain the above copyright 1.11 +// notice, this list of conditions and the following disclaimer. 1.12 +// * Redistributions in binary form must reproduce the above 1.13 +// copyright notice, this list of conditions and the following disclaimer 1.14 +// in the documentation and/or other materials provided with the 1.15 +// distribution. 1.16 +// * Neither the name of Google Inc. nor the names of its 1.17 +// contributors may be used to endorse or promote products derived from 1.18 +// this software without specific prior written permission. 1.19 +// 1.20 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.21 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.22 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.23 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.24 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.25 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.26 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.27 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.28 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.29 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.30 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.31 +// 1.32 +// Various stubs for the unit tests for the open-source version of Snappy. 1.33 + 1.34 +#include "snappy-test.h" 1.35 + 1.36 +#ifdef HAVE_WINDOWS_H 1.37 +#define WIN32_LEAN_AND_MEAN 1.38 +#include <windows.h> 1.39 +#endif 1.40 + 1.41 +#include <algorithm> 1.42 + 1.43 +DEFINE_bool(run_microbenchmarks, true, 1.44 + "Run microbenchmarks before doing anything else."); 1.45 + 1.46 +namespace snappy { 1.47 + 1.48 +string ReadTestDataFile(const string& base) { 1.49 + string contents; 1.50 + const char* srcdir = getenv("srcdir"); // This is set by Automake. 1.51 + if (srcdir) { 1.52 + File::ReadFileToStringOrDie( 1.53 + string(srcdir) + "/testdata/" + base, &contents); 1.54 + } else { 1.55 + File::ReadFileToStringOrDie("testdata/" + base, &contents); 1.56 + } 1.57 + return contents; 1.58 +} 1.59 + 1.60 +string StringPrintf(const char* format, ...) { 1.61 + char buf[4096]; 1.62 + va_list ap; 1.63 + va_start(ap, format); 1.64 + vsnprintf(buf, sizeof(buf), format, ap); 1.65 + va_end(ap); 1.66 + return buf; 1.67 +} 1.68 + 1.69 +bool benchmark_running = false; 1.70 +int64 benchmark_real_time_us = 0; 1.71 +int64 benchmark_cpu_time_us = 0; 1.72 +string *benchmark_label = NULL; 1.73 +int64 benchmark_bytes_processed = 0; 1.74 + 1.75 +void ResetBenchmarkTiming() { 1.76 + benchmark_real_time_us = 0; 1.77 + benchmark_cpu_time_us = 0; 1.78 +} 1.79 + 1.80 +#ifdef WIN32 1.81 +LARGE_INTEGER benchmark_start_real; 1.82 +FILETIME benchmark_start_cpu; 1.83 +#else // WIN32 1.84 +struct timeval benchmark_start_real; 1.85 +struct rusage benchmark_start_cpu; 1.86 +#endif // WIN32 1.87 + 1.88 +void StartBenchmarkTiming() { 1.89 +#ifdef WIN32 1.90 + QueryPerformanceCounter(&benchmark_start_real); 1.91 + FILETIME dummy; 1.92 + CHECK(GetProcessTimes( 1.93 + GetCurrentProcess(), &dummy, &dummy, &dummy, &benchmark_start_cpu)); 1.94 +#else 1.95 + gettimeofday(&benchmark_start_real, NULL); 1.96 + if (getrusage(RUSAGE_SELF, &benchmark_start_cpu) == -1) { 1.97 + perror("getrusage(RUSAGE_SELF)"); 1.98 + exit(1); 1.99 + } 1.100 +#endif 1.101 + benchmark_running = true; 1.102 +} 1.103 + 1.104 +void StopBenchmarkTiming() { 1.105 + if (!benchmark_running) { 1.106 + return; 1.107 + } 1.108 + 1.109 +#ifdef WIN32 1.110 + LARGE_INTEGER benchmark_stop_real; 1.111 + LARGE_INTEGER benchmark_frequency; 1.112 + QueryPerformanceCounter(&benchmark_stop_real); 1.113 + QueryPerformanceFrequency(&benchmark_frequency); 1.114 + 1.115 + double elapsed_real = static_cast<double>( 1.116 + benchmark_stop_real.QuadPart - benchmark_start_real.QuadPart) / 1.117 + benchmark_frequency.QuadPart; 1.118 + benchmark_real_time_us += elapsed_real * 1e6 + 0.5; 1.119 + 1.120 + FILETIME benchmark_stop_cpu, dummy; 1.121 + CHECK(GetProcessTimes( 1.122 + GetCurrentProcess(), &dummy, &dummy, &dummy, &benchmark_stop_cpu)); 1.123 + 1.124 + ULARGE_INTEGER start_ulargeint; 1.125 + start_ulargeint.LowPart = benchmark_start_cpu.dwLowDateTime; 1.126 + start_ulargeint.HighPart = benchmark_start_cpu.dwHighDateTime; 1.127 + 1.128 + ULARGE_INTEGER stop_ulargeint; 1.129 + stop_ulargeint.LowPart = benchmark_stop_cpu.dwLowDateTime; 1.130 + stop_ulargeint.HighPart = benchmark_stop_cpu.dwHighDateTime; 1.131 + 1.132 + benchmark_cpu_time_us += 1.133 + (stop_ulargeint.QuadPart - start_ulargeint.QuadPart + 5) / 10; 1.134 +#else // WIN32 1.135 + struct timeval benchmark_stop_real; 1.136 + gettimeofday(&benchmark_stop_real, NULL); 1.137 + benchmark_real_time_us += 1.138 + 1000000 * (benchmark_stop_real.tv_sec - benchmark_start_real.tv_sec); 1.139 + benchmark_real_time_us += 1.140 + (benchmark_stop_real.tv_usec - benchmark_start_real.tv_usec); 1.141 + 1.142 + struct rusage benchmark_stop_cpu; 1.143 + if (getrusage(RUSAGE_SELF, &benchmark_stop_cpu) == -1) { 1.144 + perror("getrusage(RUSAGE_SELF)"); 1.145 + exit(1); 1.146 + } 1.147 + benchmark_cpu_time_us += 1000000 * (benchmark_stop_cpu.ru_utime.tv_sec - 1.148 + benchmark_start_cpu.ru_utime.tv_sec); 1.149 + benchmark_cpu_time_us += (benchmark_stop_cpu.ru_utime.tv_usec - 1.150 + benchmark_start_cpu.ru_utime.tv_usec); 1.151 +#endif // WIN32 1.152 + 1.153 + benchmark_running = false; 1.154 +} 1.155 + 1.156 +void SetBenchmarkLabel(const string& str) { 1.157 + if (benchmark_label) { 1.158 + delete benchmark_label; 1.159 + } 1.160 + benchmark_label = new string(str); 1.161 +} 1.162 + 1.163 +void SetBenchmarkBytesProcessed(int64 bytes) { 1.164 + benchmark_bytes_processed = bytes; 1.165 +} 1.166 + 1.167 +struct BenchmarkRun { 1.168 + int64 real_time_us; 1.169 + int64 cpu_time_us; 1.170 +}; 1.171 + 1.172 +struct BenchmarkCompareCPUTime { 1.173 + bool operator() (const BenchmarkRun& a, const BenchmarkRun& b) const { 1.174 + return a.cpu_time_us < b.cpu_time_us; 1.175 + } 1.176 +}; 1.177 + 1.178 +void Benchmark::Run() { 1.179 + for (int test_case_num = start_; test_case_num <= stop_; ++test_case_num) { 1.180 + // Run a few iterations first to find out approximately how fast 1.181 + // the benchmark is. 1.182 + const int kCalibrateIterations = 100; 1.183 + ResetBenchmarkTiming(); 1.184 + StartBenchmarkTiming(); 1.185 + (*function_)(kCalibrateIterations, test_case_num); 1.186 + StopBenchmarkTiming(); 1.187 + 1.188 + // Let each test case run for about 200ms, but at least as many 1.189 + // as we used to calibrate. 1.190 + // Run five times and pick the median. 1.191 + const int kNumRuns = 5; 1.192 + const int kMedianPos = kNumRuns / 2; 1.193 + int num_iterations = 0; 1.194 + if (benchmark_real_time_us > 0) { 1.195 + num_iterations = 200000 * kCalibrateIterations / benchmark_real_time_us; 1.196 + } 1.197 + num_iterations = max(num_iterations, kCalibrateIterations); 1.198 + BenchmarkRun benchmark_runs[kNumRuns]; 1.199 + 1.200 + for (int run = 0; run < kNumRuns; ++run) { 1.201 + ResetBenchmarkTiming(); 1.202 + StartBenchmarkTiming(); 1.203 + (*function_)(num_iterations, test_case_num); 1.204 + StopBenchmarkTiming(); 1.205 + 1.206 + benchmark_runs[run].real_time_us = benchmark_real_time_us; 1.207 + benchmark_runs[run].cpu_time_us = benchmark_cpu_time_us; 1.208 + } 1.209 + 1.210 + nth_element(benchmark_runs, 1.211 + benchmark_runs + kMedianPos, 1.212 + benchmark_runs + kNumRuns, 1.213 + BenchmarkCompareCPUTime()); 1.214 + int64 real_time_us = benchmark_runs[kMedianPos].real_time_us; 1.215 + int64 cpu_time_us = benchmark_runs[kMedianPos].cpu_time_us; 1.216 + int64 bytes_per_second = benchmark_bytes_processed * 1000000 / cpu_time_us; 1.217 + 1.218 + string heading = StringPrintf("%s/%d", name_.c_str(), test_case_num); 1.219 + string human_readable_speed; 1.220 + if (bytes_per_second < 1024) { 1.221 + human_readable_speed = StringPrintf("%dB/s", bytes_per_second); 1.222 + } else if (bytes_per_second < 1024 * 1024) { 1.223 + human_readable_speed = StringPrintf( 1.224 + "%.1fkB/s", bytes_per_second / 1024.0f); 1.225 + } else if (bytes_per_second < 1024 * 1024 * 1024) { 1.226 + human_readable_speed = StringPrintf( 1.227 + "%.1fMB/s", bytes_per_second / (1024.0f * 1024.0f)); 1.228 + } else { 1.229 + human_readable_speed = StringPrintf( 1.230 + "%.1fGB/s", bytes_per_second / (1024.0f * 1024.0f * 1024.0f)); 1.231 + } 1.232 + 1.233 + fprintf(stderr, 1.234 +#ifdef WIN32 1.235 + "%-18s %10I64d %10I64d %10d %s %s\n", 1.236 +#else 1.237 + "%-18s %10lld %10lld %10d %s %s\n", 1.238 +#endif 1.239 + heading.c_str(), 1.240 + static_cast<long long>(real_time_us * 1000 / num_iterations), 1.241 + static_cast<long long>(cpu_time_us * 1000 / num_iterations), 1.242 + num_iterations, 1.243 + human_readable_speed.c_str(), 1.244 + benchmark_label->c_str()); 1.245 + } 1.246 +} 1.247 + 1.248 +#ifdef HAVE_LIBZ 1.249 + 1.250 +ZLib::ZLib() 1.251 + : comp_init_(false), 1.252 + uncomp_init_(false) { 1.253 + Reinit(); 1.254 +} 1.255 + 1.256 +ZLib::~ZLib() { 1.257 + if (comp_init_) { deflateEnd(&comp_stream_); } 1.258 + if (uncomp_init_) { inflateEnd(&uncomp_stream_); } 1.259 +} 1.260 + 1.261 +void ZLib::Reinit() { 1.262 + compression_level_ = Z_DEFAULT_COMPRESSION; 1.263 + window_bits_ = MAX_WBITS; 1.264 + mem_level_ = 8; // DEF_MEM_LEVEL 1.265 + if (comp_init_) { 1.266 + deflateEnd(&comp_stream_); 1.267 + comp_init_ = false; 1.268 + } 1.269 + if (uncomp_init_) { 1.270 + inflateEnd(&uncomp_stream_); 1.271 + uncomp_init_ = false; 1.272 + } 1.273 + first_chunk_ = true; 1.274 +} 1.275 + 1.276 +void ZLib::Reset() { 1.277 + first_chunk_ = true; 1.278 +} 1.279 + 1.280 +// --------- COMPRESS MODE 1.281 + 1.282 +// Initialization method to be called if we hit an error while 1.283 +// compressing. On hitting an error, call this method before returning 1.284 +// the error. 1.285 +void ZLib::CompressErrorInit() { 1.286 + deflateEnd(&comp_stream_); 1.287 + comp_init_ = false; 1.288 + Reset(); 1.289 +} 1.290 + 1.291 +int ZLib::DeflateInit() { 1.292 + return deflateInit2(&comp_stream_, 1.293 + compression_level_, 1.294 + Z_DEFLATED, 1.295 + window_bits_, 1.296 + mem_level_, 1.297 + Z_DEFAULT_STRATEGY); 1.298 +} 1.299 + 1.300 +int ZLib::CompressInit(Bytef *dest, uLongf *destLen, 1.301 + const Bytef *source, uLong *sourceLen) { 1.302 + int err; 1.303 + 1.304 + comp_stream_.next_in = (Bytef*)source; 1.305 + comp_stream_.avail_in = (uInt)*sourceLen; 1.306 + if ((uLong)comp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR; 1.307 + comp_stream_.next_out = dest; 1.308 + comp_stream_.avail_out = (uInt)*destLen; 1.309 + if ((uLong)comp_stream_.avail_out != *destLen) return Z_BUF_ERROR; 1.310 + 1.311 + if ( !first_chunk_ ) // only need to set up stream the first time through 1.312 + return Z_OK; 1.313 + 1.314 + if (comp_init_) { // we've already initted it 1.315 + err = deflateReset(&comp_stream_); 1.316 + if (err != Z_OK) { 1.317 + LOG(WARNING) << "ERROR: Can't reset compress object; creating a new one"; 1.318 + deflateEnd(&comp_stream_); 1.319 + comp_init_ = false; 1.320 + } 1.321 + } 1.322 + if (!comp_init_) { // first use 1.323 + comp_stream_.zalloc = (alloc_func)0; 1.324 + comp_stream_.zfree = (free_func)0; 1.325 + comp_stream_.opaque = (voidpf)0; 1.326 + err = DeflateInit(); 1.327 + if (err != Z_OK) return err; 1.328 + comp_init_ = true; 1.329 + } 1.330 + return Z_OK; 1.331 +} 1.332 + 1.333 +// In a perfect world we'd always have the full buffer to compress 1.334 +// when the time came, and we could just call Compress(). Alas, we 1.335 +// want to do chunked compression on our webserver. In this 1.336 +// application, we compress the header, send it off, then compress the 1.337 +// results, send them off, then compress the footer. Thus we need to 1.338 +// use the chunked compression features of zlib. 1.339 +int ZLib::CompressAtMostOrAll(Bytef *dest, uLongf *destLen, 1.340 + const Bytef *source, uLong *sourceLen, 1.341 + int flush_mode) { // Z_FULL_FLUSH or Z_FINISH 1.342 + int err; 1.343 + 1.344 + if ( (err=CompressInit(dest, destLen, source, sourceLen)) != Z_OK ) 1.345 + return err; 1.346 + 1.347 + // This is used to figure out how many bytes we wrote *this chunk* 1.348 + int compressed_size = comp_stream_.total_out; 1.349 + 1.350 + // Some setup happens only for the first chunk we compress in a run 1.351 + if ( first_chunk_ ) { 1.352 + first_chunk_ = false; 1.353 + } 1.354 + 1.355 + // flush_mode is Z_FINISH for all mode, Z_SYNC_FLUSH for incremental 1.356 + // compression. 1.357 + err = deflate(&comp_stream_, flush_mode); 1.358 + 1.359 + *sourceLen = comp_stream_.avail_in; 1.360 + 1.361 + if ((err == Z_STREAM_END || err == Z_OK) 1.362 + && comp_stream_.avail_in == 0 1.363 + && comp_stream_.avail_out != 0 ) { 1.364 + // we processed everything ok and the output buffer was large enough. 1.365 + ; 1.366 + } else if (err == Z_STREAM_END && comp_stream_.avail_in > 0) { 1.367 + return Z_BUF_ERROR; // should never happen 1.368 + } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) { 1.369 + // an error happened 1.370 + CompressErrorInit(); 1.371 + return err; 1.372 + } else if (comp_stream_.avail_out == 0) { // not enough space 1.373 + err = Z_BUF_ERROR; 1.374 + } 1.375 + 1.376 + assert(err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR); 1.377 + if (err == Z_STREAM_END) 1.378 + err = Z_OK; 1.379 + 1.380 + // update the crc and other metadata 1.381 + compressed_size = comp_stream_.total_out - compressed_size; // delta 1.382 + *destLen = compressed_size; 1.383 + 1.384 + return err; 1.385 +} 1.386 + 1.387 +int ZLib::CompressChunkOrAll(Bytef *dest, uLongf *destLen, 1.388 + const Bytef *source, uLong sourceLen, 1.389 + int flush_mode) { // Z_FULL_FLUSH or Z_FINISH 1.390 + const int ret = 1.391 + CompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode); 1.392 + if (ret == Z_BUF_ERROR) 1.393 + CompressErrorInit(); 1.394 + return ret; 1.395 +} 1.396 + 1.397 +// This routine only initializes the compression stream once. Thereafter, it 1.398 +// just does a deflateReset on the stream, which should be faster. 1.399 +int ZLib::Compress(Bytef *dest, uLongf *destLen, 1.400 + const Bytef *source, uLong sourceLen) { 1.401 + int err; 1.402 + if ( (err=CompressChunkOrAll(dest, destLen, source, sourceLen, 1.403 + Z_FINISH)) != Z_OK ) 1.404 + return err; 1.405 + Reset(); // reset for next call to Compress 1.406 + 1.407 + return Z_OK; 1.408 +} 1.409 + 1.410 + 1.411 +// --------- UNCOMPRESS MODE 1.412 + 1.413 +int ZLib::InflateInit() { 1.414 + return inflateInit2(&uncomp_stream_, MAX_WBITS); 1.415 +} 1.416 + 1.417 +// Initialization method to be called if we hit an error while 1.418 +// uncompressing. On hitting an error, call this method before 1.419 +// returning the error. 1.420 +void ZLib::UncompressErrorInit() { 1.421 + inflateEnd(&uncomp_stream_); 1.422 + uncomp_init_ = false; 1.423 + Reset(); 1.424 +} 1.425 + 1.426 +int ZLib::UncompressInit(Bytef *dest, uLongf *destLen, 1.427 + const Bytef *source, uLong *sourceLen) { 1.428 + int err; 1.429 + 1.430 + uncomp_stream_.next_in = (Bytef*)source; 1.431 + uncomp_stream_.avail_in = (uInt)*sourceLen; 1.432 + // Check for source > 64K on 16-bit machine: 1.433 + if ((uLong)uncomp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR; 1.434 + 1.435 + uncomp_stream_.next_out = dest; 1.436 + uncomp_stream_.avail_out = (uInt)*destLen; 1.437 + if ((uLong)uncomp_stream_.avail_out != *destLen) return Z_BUF_ERROR; 1.438 + 1.439 + if ( !first_chunk_ ) // only need to set up stream the first time through 1.440 + return Z_OK; 1.441 + 1.442 + if (uncomp_init_) { // we've already initted it 1.443 + err = inflateReset(&uncomp_stream_); 1.444 + if (err != Z_OK) { 1.445 + LOG(WARNING) 1.446 + << "ERROR: Can't reset uncompress object; creating a new one"; 1.447 + UncompressErrorInit(); 1.448 + } 1.449 + } 1.450 + if (!uncomp_init_) { 1.451 + uncomp_stream_.zalloc = (alloc_func)0; 1.452 + uncomp_stream_.zfree = (free_func)0; 1.453 + uncomp_stream_.opaque = (voidpf)0; 1.454 + err = InflateInit(); 1.455 + if (err != Z_OK) return err; 1.456 + uncomp_init_ = true; 1.457 + } 1.458 + return Z_OK; 1.459 +} 1.460 + 1.461 +// If you compressed your data a chunk at a time, with CompressChunk, 1.462 +// you can uncompress it a chunk at a time with UncompressChunk. 1.463 +// Only difference bewteen chunked and unchunked uncompression 1.464 +// is the flush mode we use: Z_SYNC_FLUSH (chunked) or Z_FINISH (unchunked). 1.465 +int ZLib::UncompressAtMostOrAll(Bytef *dest, uLongf *destLen, 1.466 + const Bytef *source, uLong *sourceLen, 1.467 + int flush_mode) { // Z_SYNC_FLUSH or Z_FINISH 1.468 + int err = Z_OK; 1.469 + 1.470 + if ( (err=UncompressInit(dest, destLen, source, sourceLen)) != Z_OK ) { 1.471 + LOG(WARNING) << "UncompressInit: Error: " << err << " SourceLen: " 1.472 + << *sourceLen; 1.473 + return err; 1.474 + } 1.475 + 1.476 + // This is used to figure out how many output bytes we wrote *this chunk*: 1.477 + const uLong old_total_out = uncomp_stream_.total_out; 1.478 + 1.479 + // This is used to figure out how many input bytes we read *this chunk*: 1.480 + const uLong old_total_in = uncomp_stream_.total_in; 1.481 + 1.482 + // Some setup happens only for the first chunk we compress in a run 1.483 + if ( first_chunk_ ) { 1.484 + first_chunk_ = false; // so we don't do this again 1.485 + 1.486 + // For the first chunk *only* (to avoid infinite troubles), we let 1.487 + // there be no actual data to uncompress. This sometimes triggers 1.488 + // when the input is only the gzip header, say. 1.489 + if ( *sourceLen == 0 ) { 1.490 + *destLen = 0; 1.491 + return Z_OK; 1.492 + } 1.493 + } 1.494 + 1.495 + // We'll uncompress as much as we can. If we end OK great, otherwise 1.496 + // if we get an error that seems to be the gzip footer, we store the 1.497 + // gzip footer and return OK, otherwise we return the error. 1.498 + 1.499 + // flush_mode is Z_SYNC_FLUSH for chunked mode, Z_FINISH for all mode. 1.500 + err = inflate(&uncomp_stream_, flush_mode); 1.501 + 1.502 + // Figure out how many bytes of the input zlib slurped up: 1.503 + const uLong bytes_read = uncomp_stream_.total_in - old_total_in; 1.504 + CHECK_LE(source + bytes_read, source + *sourceLen); 1.505 + *sourceLen = uncomp_stream_.avail_in; 1.506 + 1.507 + if ((err == Z_STREAM_END || err == Z_OK) // everything went ok 1.508 + && uncomp_stream_.avail_in == 0) { // and we read it all 1.509 + ; 1.510 + } else if (err == Z_STREAM_END && uncomp_stream_.avail_in > 0) { 1.511 + LOG(WARNING) 1.512 + << "UncompressChunkOrAll: Received some extra data, bytes total: " 1.513 + << uncomp_stream_.avail_in << " bytes: " 1.514 + << string(reinterpret_cast<const char *>(uncomp_stream_.next_in), 1.515 + min(int(uncomp_stream_.avail_in), 20)); 1.516 + UncompressErrorInit(); 1.517 + return Z_DATA_ERROR; // what's the extra data for? 1.518 + } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) { 1.519 + // an error happened 1.520 + LOG(WARNING) << "UncompressChunkOrAll: Error: " << err 1.521 + << " avail_out: " << uncomp_stream_.avail_out; 1.522 + UncompressErrorInit(); 1.523 + return err; 1.524 + } else if (uncomp_stream_.avail_out == 0) { 1.525 + err = Z_BUF_ERROR; 1.526 + } 1.527 + 1.528 + assert(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END); 1.529 + if (err == Z_STREAM_END) 1.530 + err = Z_OK; 1.531 + 1.532 + *destLen = uncomp_stream_.total_out - old_total_out; // size for this call 1.533 + 1.534 + return err; 1.535 +} 1.536 + 1.537 +int ZLib::UncompressChunkOrAll(Bytef *dest, uLongf *destLen, 1.538 + const Bytef *source, uLong sourceLen, 1.539 + int flush_mode) { // Z_SYNC_FLUSH or Z_FINISH 1.540 + const int ret = 1.541 + UncompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode); 1.542 + if (ret == Z_BUF_ERROR) 1.543 + UncompressErrorInit(); 1.544 + return ret; 1.545 +} 1.546 + 1.547 +int ZLib::UncompressAtMost(Bytef *dest, uLongf *destLen, 1.548 + const Bytef *source, uLong *sourceLen) { 1.549 + return UncompressAtMostOrAll(dest, destLen, source, sourceLen, Z_SYNC_FLUSH); 1.550 +} 1.551 + 1.552 +// We make sure we've uncompressed everything, that is, the current 1.553 +// uncompress stream is at a compressed-buffer-EOF boundary. In gzip 1.554 +// mode, we also check the gzip footer to make sure we pass the gzip 1.555 +// consistency checks. We RETURN true iff both types of checks pass. 1.556 +bool ZLib::UncompressChunkDone() { 1.557 + assert(!first_chunk_ && uncomp_init_); 1.558 + // Make sure we're at the end-of-compressed-data point. This means 1.559 + // if we call inflate with Z_FINISH we won't consume any input or 1.560 + // write any output 1.561 + Bytef dummyin, dummyout; 1.562 + uLongf dummylen = 0; 1.563 + if ( UncompressChunkOrAll(&dummyout, &dummylen, &dummyin, 0, Z_FINISH) 1.564 + != Z_OK ) { 1.565 + return false; 1.566 + } 1.567 + 1.568 + // Make sure that when we exit, we can start a new round of chunks later 1.569 + Reset(); 1.570 + 1.571 + return true; 1.572 +} 1.573 + 1.574 +// Uncompresses the source buffer into the destination buffer. 1.575 +// The destination buffer must be long enough to hold the entire 1.576 +// decompressed contents. 1.577 +// 1.578 +// We only initialize the uncomp_stream once. Thereafter, we use 1.579 +// inflateReset, which should be faster. 1.580 +// 1.581 +// Returns Z_OK on success, otherwise, it returns a zlib error code. 1.582 +int ZLib::Uncompress(Bytef *dest, uLongf *destLen, 1.583 + const Bytef *source, uLong sourceLen) { 1.584 + int err; 1.585 + if ( (err=UncompressChunkOrAll(dest, destLen, source, sourceLen, 1.586 + Z_FINISH)) != Z_OK ) { 1.587 + Reset(); // let us try to compress again 1.588 + return err; 1.589 + } 1.590 + if ( !UncompressChunkDone() ) // calls Reset() 1.591 + return Z_DATA_ERROR; 1.592 + return Z_OK; // stream_end is ok 1.593 +} 1.594 + 1.595 +#endif // HAVE_LIBZ 1.596 + 1.597 +} // namespace snappy