Home | History | Annotate | Download | only in metrics
      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