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.
5 #include "chrome/browser/metrics/compression_utils.h"
9 #include "base/basictypes.h"
10 #include "third_party/zlib/zlib.h"
14 // The difference in bytes between a zlib header and a gzip header.
15 const size_t kGzipZlibHeaderDifferenceBytes
= 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;
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;
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
,
32 uLong source_length
) {
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
)
42 stream
.zalloc
= static_cast<alloc_func
>(0);
43 stream
.zfree
= static_cast<free_func
>(0);
44 stream
.opaque
= static_cast<voidpf
>(0);
46 gz_header gzip_header
;
47 memset(&gzip_header
, 0, sizeof(gzip_header
));
48 int err
= deflateInit2_(&stream
,
49 Z_DEFAULT_COMPRESSION
,
51 MAX_WBITS
+ kWindowBitsToGetGzipHeader
,
59 err
= deflateSetHeader(&stream
, &gzip_header
);
63 err
= deflate(&stream
, Z_FINISH
);
64 if (err
!= Z_STREAM_END
) {
66 return err
== Z_OK
? Z_BUF_ERROR
: err
;
68 *dest_length
= stream
.total_out
;
70 err
= deflateEnd(&stream
);
77 bool GzipCompress(const std::string
& input
, std::string
* output
) {
78 std::vector
<Bytef
> compressed_data(kGzipZlibHeaderDifferenceBytes
+
79 compressBound(input
.size()));
81 uLongf compressed_size
= compressed_data
.size();
82 if (GzipCompressHelper(&compressed_data
.front(),
84 bit_cast
<const Bytef
*>(input
.data()),
85 input
.size()) != Z_OK
)
88 compressed_data
.resize(compressed_size
);
89 output
->assign(compressed_data
.begin(), compressed_data
.end());