// Copyright 2013 The Chromium 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 "chrome/browser/metrics/compression_utils.h" #include #include "base/basictypes.h" #include "third_party/zlib/zlib.h" #include "third_party/zlib/zutil.h" namespace { // The difference in bytes between a zlib header and a gzip header. const size_t kGzipZlibHeaderDifferenceBytes = 16; // Pass an integer greater than the following get a gzip header instead of a // zlib header when calling deflateInit2_. const int kWindowBitsToGetGzipHeader = 16; // This code is taken almost verbatim from third_party/zlib/compress.c. The only // difference is deflateInit2_ is called which sets the window bits to be > 16. // That causes a gzip header to be emitted rather than a zlib header. int GzipCompressHelper(Bytef* dest, uLongf* dest_length, const Bytef* source, uLong source_length) { z_stream stream; stream.next_in = bit_cast(source); stream.avail_in = static_cast(source_length); stream.next_out = dest; stream.avail_out = static_cast(*dest_length); if (static_cast(stream.avail_out) != *dest_length) return Z_BUF_ERROR; stream.zalloc = static_cast(0); stream.zfree = static_cast(0); stream.opaque = static_cast(0); gz_header gzip_header; memset(&gzip_header, 0, sizeof(gzip_header)); int err = deflateInit2_(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + kWindowBitsToGetGzipHeader, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(z_stream)); if (err != Z_OK) return err; err = deflateSetHeader(&stream, &gzip_header); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *dest_length = stream.total_out; err = deflateEnd(&stream); return err; } } // namespace namespace chrome { bool GzipCompress(const std::string& input, std::string* output) { std::vector compressed_data(kGzipZlibHeaderDifferenceBytes + compressBound(input.size())); uLongf compressed_size = compressed_data.size(); if (GzipCompressHelper(&compressed_data.front(), &compressed_size, bit_cast(input.data()), input.size()) != Z_OK) return false; compressed_data.resize(compressed_size); output->assign(compressed_data.begin(), compressed_data.end()); return true; } } // namespace chrome