1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/metrics/compression_utils.h" 6 7 #include <vector> 8 9 #include "base/basictypes.h" 10 #include "third_party/zlib/zlib.h" 11 12 namespace { 13 14 // The difference in bytes between a zlib header and a gzip header. 15 const size_t kGzipZlibHeaderDifferenceBytes = 16; 16 17 // Pass an integer greater than the following get a gzip header instead of a 18 // zlib header when calling deflateInit2_. 19 const int kWindowBitsToGetGzipHeader = 16; 20 21 // This describes the amount of memory zlib uses to compress data. It can go 22 // from 1 to 9, with 8 being the default. For details, see: 23 // http://www.zlib.net/manual.html (search for memLevel). 24 const int kZlibMemoryLevel = 8; 25 26 // This code is taken almost verbatim from third_party/zlib/compress.c. The only 27 // difference is deflateInit2_ is called which sets the window bits to be > 16. 28 // That causes a gzip header to be emitted rather than a zlib header. 29 int GzipCompressHelper(Bytef* dest, 30 uLongf* dest_length, 31 const Bytef* source, 32 uLong source_length) { 33 z_stream stream; 34 35 stream.next_in = bit_cast<Bytef*>(source); 36 stream.avail_in = static_cast<uInt>(source_length); 37 stream.next_out = dest; 38 stream.avail_out = static_cast<uInt>(*dest_length); 39 if (static_cast<uLong>(stream.avail_out) != *dest_length) 40 return Z_BUF_ERROR; 41 42 stream.zalloc = static_cast<alloc_func>(0); 43 stream.zfree = static_cast<free_func>(0); 44 stream.opaque = static_cast<voidpf>(0); 45 46 gz_header gzip_header; 47 memset(&gzip_header, 0, sizeof(gzip_header)); 48 int err = deflateInit2_(&stream, 49 Z_DEFAULT_COMPRESSION, 50 Z_DEFLATED, 51 MAX_WBITS + kWindowBitsToGetGzipHeader, 52 kZlibMemoryLevel, 53 Z_DEFAULT_STRATEGY, 54 ZLIB_VERSION, 55 sizeof(z_stream)); 56 if (err != Z_OK) 57 return err; 58 59 err = deflateSetHeader(&stream, &gzip_header); 60 if (err != Z_OK) 61 return err; 62 63 err = deflate(&stream, Z_FINISH); 64 if (err != Z_STREAM_END) { 65 deflateEnd(&stream); 66 return err == Z_OK ? Z_BUF_ERROR : err; 67 } 68 *dest_length = stream.total_out; 69 70 err = deflateEnd(&stream); 71 return err; 72 } 73 } // namespace 74 75 namespace chrome { 76 77 bool GzipCompress(const std::string& input, std::string* output) { 78 std::vector<Bytef> compressed_data(kGzipZlibHeaderDifferenceBytes + 79 compressBound(input.size())); 80 81 uLongf compressed_size = compressed_data.size(); 82 if (GzipCompressHelper(&compressed_data.front(), 83 &compressed_size, 84 bit_cast<const Bytef*>(input.data()), 85 input.size()) != Z_OK) 86 return false; 87 88 compressed_data.resize(compressed_size); 89 output->assign(compressed_data.begin(), compressed_data.end()); 90 return true; 91 } 92 } // namespace chrome 93