1*86ee64e7SAndroid Build Coastguard Worker /* compression_utils_portable.cc
2*86ee64e7SAndroid Build Coastguard Worker *
3*86ee64e7SAndroid Build Coastguard Worker * Copyright 2019 The Chromium Authors
4*86ee64e7SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*86ee64e7SAndroid Build Coastguard Worker * found in the Chromium source repository LICENSE file.
6*86ee64e7SAndroid Build Coastguard Worker */
7*86ee64e7SAndroid Build Coastguard Worker
8*86ee64e7SAndroid Build Coastguard Worker #include "compression_utils_portable.h"
9*86ee64e7SAndroid Build Coastguard Worker
10*86ee64e7SAndroid Build Coastguard Worker #include <stddef.h>
11*86ee64e7SAndroid Build Coastguard Worker #include <stdlib.h>
12*86ee64e7SAndroid Build Coastguard Worker #include <string.h>
13*86ee64e7SAndroid Build Coastguard Worker
14*86ee64e7SAndroid Build Coastguard Worker namespace zlib_internal {
15*86ee64e7SAndroid Build Coastguard Worker
16*86ee64e7SAndroid Build Coastguard Worker // The difference in bytes between a zlib header and a gzip header.
17*86ee64e7SAndroid Build Coastguard Worker const size_t kGzipZlibHeaderDifferenceBytes = 16;
18*86ee64e7SAndroid Build Coastguard Worker
19*86ee64e7SAndroid Build Coastguard Worker // Pass an integer greater than the following get a gzip header instead of a
20*86ee64e7SAndroid Build Coastguard Worker // zlib header when calling deflateInit2() and inflateInit2().
21*86ee64e7SAndroid Build Coastguard Worker const int kWindowBitsToGetGzipHeader = 16;
22*86ee64e7SAndroid Build Coastguard Worker
23*86ee64e7SAndroid Build Coastguard Worker // This describes the amount of memory zlib uses to compress data. It can go
24*86ee64e7SAndroid Build Coastguard Worker // from 1 to 9, with 8 being the default. For details, see:
25*86ee64e7SAndroid Build Coastguard Worker // http://www.zlib.net/manual.html (search for memLevel).
26*86ee64e7SAndroid Build Coastguard Worker const int kZlibMemoryLevel = 8;
27*86ee64e7SAndroid Build Coastguard Worker
28*86ee64e7SAndroid Build Coastguard Worker // The expected compressed size is based on the input size factored by
29*86ee64e7SAndroid Build Coastguard Worker // internal Zlib constants (e.g. window size, etc) plus the wrapper
30*86ee64e7SAndroid Build Coastguard Worker // header size.
GzipExpectedCompressedSize(uLongf input_size)31*86ee64e7SAndroid Build Coastguard Worker uLongf GzipExpectedCompressedSize(uLongf input_size) {
32*86ee64e7SAndroid Build Coastguard Worker return kGzipZlibHeaderDifferenceBytes + compressBound(input_size);
33*86ee64e7SAndroid Build Coastguard Worker }
34*86ee64e7SAndroid Build Coastguard Worker
35*86ee64e7SAndroid Build Coastguard Worker // The expected decompressed size is stored in the last
36*86ee64e7SAndroid Build Coastguard Worker // 4 bytes of |input| in LE. See https://tools.ietf.org/html/rfc1952#page-5
GetGzipUncompressedSize(const Bytef * compressed_data,size_t length)37*86ee64e7SAndroid Build Coastguard Worker uint32_t GetGzipUncompressedSize(const Bytef* compressed_data, size_t length) {
38*86ee64e7SAndroid Build Coastguard Worker uint32_t size;
39*86ee64e7SAndroid Build Coastguard Worker if (length < sizeof(size))
40*86ee64e7SAndroid Build Coastguard Worker return 0;
41*86ee64e7SAndroid Build Coastguard Worker
42*86ee64e7SAndroid Build Coastguard Worker memcpy(&size, &compressed_data[length - sizeof(size)], sizeof(size));
43*86ee64e7SAndroid Build Coastguard Worker #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
44*86ee64e7SAndroid Build Coastguard Worker return size;
45*86ee64e7SAndroid Build Coastguard Worker #else
46*86ee64e7SAndroid Build Coastguard Worker return __builtin_bswap32(size);
47*86ee64e7SAndroid Build Coastguard Worker #endif
48*86ee64e7SAndroid Build Coastguard Worker }
49*86ee64e7SAndroid Build Coastguard Worker
50*86ee64e7SAndroid Build Coastguard Worker // The number of window bits determines the type of wrapper to use - see
51*86ee64e7SAndroid Build Coastguard Worker // https://cs.chromium.org/chromium/src/third_party/zlib/zlib.h?l=566
ZlibStreamWrapperType(WrapperType type)52*86ee64e7SAndroid Build Coastguard Worker inline int ZlibStreamWrapperType(WrapperType type) {
53*86ee64e7SAndroid Build Coastguard Worker if (type == ZLIB) // zlib DEFLATE stream wrapper
54*86ee64e7SAndroid Build Coastguard Worker return MAX_WBITS;
55*86ee64e7SAndroid Build Coastguard Worker if (type == GZIP) // gzip DEFLATE stream wrapper
56*86ee64e7SAndroid Build Coastguard Worker return MAX_WBITS + kWindowBitsToGetGzipHeader;
57*86ee64e7SAndroid Build Coastguard Worker if (type == ZRAW) // no wrapper, use raw DEFLATE
58*86ee64e7SAndroid Build Coastguard Worker return -MAX_WBITS;
59*86ee64e7SAndroid Build Coastguard Worker return 0;
60*86ee64e7SAndroid Build Coastguard Worker }
61*86ee64e7SAndroid Build Coastguard Worker
GzipCompressHelper(Bytef * dest,uLongf * dest_length,const Bytef * source,uLong source_length,void * (* malloc_fn)(size_t),void (* free_fn)(void *))62*86ee64e7SAndroid Build Coastguard Worker int GzipCompressHelper(Bytef* dest,
63*86ee64e7SAndroid Build Coastguard Worker uLongf* dest_length,
64*86ee64e7SAndroid Build Coastguard Worker const Bytef* source,
65*86ee64e7SAndroid Build Coastguard Worker uLong source_length,
66*86ee64e7SAndroid Build Coastguard Worker void* (*malloc_fn)(size_t),
67*86ee64e7SAndroid Build Coastguard Worker void (*free_fn)(void*)) {
68*86ee64e7SAndroid Build Coastguard Worker return CompressHelper(GZIP, dest, dest_length, source, source_length,
69*86ee64e7SAndroid Build Coastguard Worker Z_DEFAULT_COMPRESSION, malloc_fn, free_fn);
70*86ee64e7SAndroid Build Coastguard Worker }
71*86ee64e7SAndroid Build Coastguard Worker
72*86ee64e7SAndroid Build Coastguard Worker // This code is taken almost verbatim from third_party/zlib/compress.c. The only
73*86ee64e7SAndroid Build Coastguard Worker // difference is deflateInit2() is called which allows different window bits to
74*86ee64e7SAndroid Build Coastguard Worker // be set. > 16 causes a gzip header to be emitted rather than a zlib header,
75*86ee64e7SAndroid Build Coastguard Worker // and negative causes no header to emitted.
76*86ee64e7SAndroid Build Coastguard Worker //
77*86ee64e7SAndroid Build Coastguard Worker // Compression level can be a number from 1-9, with 1 being the fastest, 9 being
78*86ee64e7SAndroid Build Coastguard Worker // the best compression. The default, which the GZIP helper uses, is 6.
CompressHelper(WrapperType wrapper_type,Bytef * dest,uLongf * dest_length,const Bytef * source,uLong source_length,int compression_level,void * (* malloc_fn)(size_t),void (* free_fn)(void *))79*86ee64e7SAndroid Build Coastguard Worker int CompressHelper(WrapperType wrapper_type,
80*86ee64e7SAndroid Build Coastguard Worker Bytef* dest,
81*86ee64e7SAndroid Build Coastguard Worker uLongf* dest_length,
82*86ee64e7SAndroid Build Coastguard Worker const Bytef* source,
83*86ee64e7SAndroid Build Coastguard Worker uLong source_length,
84*86ee64e7SAndroid Build Coastguard Worker int compression_level,
85*86ee64e7SAndroid Build Coastguard Worker void* (*malloc_fn)(size_t),
86*86ee64e7SAndroid Build Coastguard Worker void (*free_fn)(void*)) {
87*86ee64e7SAndroid Build Coastguard Worker if (compression_level < 0 || compression_level > 9) {
88*86ee64e7SAndroid Build Coastguard Worker compression_level = Z_DEFAULT_COMPRESSION;
89*86ee64e7SAndroid Build Coastguard Worker }
90*86ee64e7SAndroid Build Coastguard Worker
91*86ee64e7SAndroid Build Coastguard Worker z_stream stream;
92*86ee64e7SAndroid Build Coastguard Worker
93*86ee64e7SAndroid Build Coastguard Worker // FIXME(cavalcantii): z_const is not defined as 'const'.
94*86ee64e7SAndroid Build Coastguard Worker stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source));
95*86ee64e7SAndroid Build Coastguard Worker stream.avail_in = static_cast<uInt>(source_length);
96*86ee64e7SAndroid Build Coastguard Worker stream.next_out = dest;
97*86ee64e7SAndroid Build Coastguard Worker stream.avail_out = static_cast<uInt>(*dest_length);
98*86ee64e7SAndroid Build Coastguard Worker if (static_cast<uLong>(stream.avail_out) != *dest_length)
99*86ee64e7SAndroid Build Coastguard Worker return Z_BUF_ERROR;
100*86ee64e7SAndroid Build Coastguard Worker
101*86ee64e7SAndroid Build Coastguard Worker // Cannot convert capturing lambdas to function pointers directly, hence the
102*86ee64e7SAndroid Build Coastguard Worker // structure.
103*86ee64e7SAndroid Build Coastguard Worker struct MallocFreeFunctions {
104*86ee64e7SAndroid Build Coastguard Worker void* (*malloc_fn)(size_t);
105*86ee64e7SAndroid Build Coastguard Worker void (*free_fn)(void*);
106*86ee64e7SAndroid Build Coastguard Worker } malloc_free = {malloc_fn, free_fn};
107*86ee64e7SAndroid Build Coastguard Worker
108*86ee64e7SAndroid Build Coastguard Worker if (malloc_fn) {
109*86ee64e7SAndroid Build Coastguard Worker if (!free_fn)
110*86ee64e7SAndroid Build Coastguard Worker return Z_BUF_ERROR;
111*86ee64e7SAndroid Build Coastguard Worker
112*86ee64e7SAndroid Build Coastguard Worker auto zalloc = [](void* opaque, uInt items, uInt size) {
113*86ee64e7SAndroid Build Coastguard Worker return reinterpret_cast<MallocFreeFunctions*>(opaque)->malloc_fn(items *
114*86ee64e7SAndroid Build Coastguard Worker size);
115*86ee64e7SAndroid Build Coastguard Worker };
116*86ee64e7SAndroid Build Coastguard Worker auto zfree = [](void* opaque, void* address) {
117*86ee64e7SAndroid Build Coastguard Worker return reinterpret_cast<MallocFreeFunctions*>(opaque)->free_fn(address);
118*86ee64e7SAndroid Build Coastguard Worker };
119*86ee64e7SAndroid Build Coastguard Worker
120*86ee64e7SAndroid Build Coastguard Worker stream.zalloc = static_cast<alloc_func>(zalloc);
121*86ee64e7SAndroid Build Coastguard Worker stream.zfree = static_cast<free_func>(zfree);
122*86ee64e7SAndroid Build Coastguard Worker stream.opaque = static_cast<voidpf>(&malloc_free);
123*86ee64e7SAndroid Build Coastguard Worker } else {
124*86ee64e7SAndroid Build Coastguard Worker stream.zalloc = static_cast<alloc_func>(0);
125*86ee64e7SAndroid Build Coastguard Worker stream.zfree = static_cast<free_func>(0);
126*86ee64e7SAndroid Build Coastguard Worker stream.opaque = static_cast<voidpf>(0);
127*86ee64e7SAndroid Build Coastguard Worker }
128*86ee64e7SAndroid Build Coastguard Worker
129*86ee64e7SAndroid Build Coastguard Worker int err = deflateInit2(&stream, compression_level, Z_DEFLATED,
130*86ee64e7SAndroid Build Coastguard Worker ZlibStreamWrapperType(wrapper_type), kZlibMemoryLevel,
131*86ee64e7SAndroid Build Coastguard Worker Z_DEFAULT_STRATEGY);
132*86ee64e7SAndroid Build Coastguard Worker if (err != Z_OK)
133*86ee64e7SAndroid Build Coastguard Worker return err;
134*86ee64e7SAndroid Build Coastguard Worker
135*86ee64e7SAndroid Build Coastguard Worker // This has to exist outside of the if statement to prevent it going off the
136*86ee64e7SAndroid Build Coastguard Worker // stack before deflate(), which will use this object.
137*86ee64e7SAndroid Build Coastguard Worker gz_header gzip_header;
138*86ee64e7SAndroid Build Coastguard Worker if (wrapper_type == GZIP) {
139*86ee64e7SAndroid Build Coastguard Worker memset(&gzip_header, 0, sizeof(gzip_header));
140*86ee64e7SAndroid Build Coastguard Worker err = deflateSetHeader(&stream, &gzip_header);
141*86ee64e7SAndroid Build Coastguard Worker if (err != Z_OK)
142*86ee64e7SAndroid Build Coastguard Worker return err;
143*86ee64e7SAndroid Build Coastguard Worker }
144*86ee64e7SAndroid Build Coastguard Worker
145*86ee64e7SAndroid Build Coastguard Worker err = deflate(&stream, Z_FINISH);
146*86ee64e7SAndroid Build Coastguard Worker if (err != Z_STREAM_END) {
147*86ee64e7SAndroid Build Coastguard Worker deflateEnd(&stream);
148*86ee64e7SAndroid Build Coastguard Worker return err == Z_OK ? Z_BUF_ERROR : err;
149*86ee64e7SAndroid Build Coastguard Worker }
150*86ee64e7SAndroid Build Coastguard Worker *dest_length = stream.total_out;
151*86ee64e7SAndroid Build Coastguard Worker
152*86ee64e7SAndroid Build Coastguard Worker err = deflateEnd(&stream);
153*86ee64e7SAndroid Build Coastguard Worker return err;
154*86ee64e7SAndroid Build Coastguard Worker }
155*86ee64e7SAndroid Build Coastguard Worker
GzipUncompressHelper(Bytef * dest,uLongf * dest_length,const Bytef * source,uLong source_length)156*86ee64e7SAndroid Build Coastguard Worker int GzipUncompressHelper(Bytef* dest,
157*86ee64e7SAndroid Build Coastguard Worker uLongf* dest_length,
158*86ee64e7SAndroid Build Coastguard Worker const Bytef* source,
159*86ee64e7SAndroid Build Coastguard Worker uLong source_length) {
160*86ee64e7SAndroid Build Coastguard Worker return UncompressHelper(GZIP, dest, dest_length, source, source_length);
161*86ee64e7SAndroid Build Coastguard Worker }
162*86ee64e7SAndroid Build Coastguard Worker
163*86ee64e7SAndroid Build Coastguard Worker // This code is taken almost verbatim from third_party/zlib/uncompr.c. The only
164*86ee64e7SAndroid Build Coastguard Worker // difference is inflateInit2() is called which allows different window bits to
165*86ee64e7SAndroid Build Coastguard Worker // be set. > 16 causes a gzip header to be emitted rather than a zlib header,
166*86ee64e7SAndroid Build Coastguard Worker // and negative causes no header to emitted.
UncompressHelper(WrapperType wrapper_type,Bytef * dest,uLongf * dest_length,const Bytef * source,uLong source_length)167*86ee64e7SAndroid Build Coastguard Worker int UncompressHelper(WrapperType wrapper_type,
168*86ee64e7SAndroid Build Coastguard Worker Bytef* dest,
169*86ee64e7SAndroid Build Coastguard Worker uLongf* dest_length,
170*86ee64e7SAndroid Build Coastguard Worker const Bytef* source,
171*86ee64e7SAndroid Build Coastguard Worker uLong source_length) {
172*86ee64e7SAndroid Build Coastguard Worker z_stream stream;
173*86ee64e7SAndroid Build Coastguard Worker
174*86ee64e7SAndroid Build Coastguard Worker // FIXME(cavalcantii): z_const is not defined as 'const'.
175*86ee64e7SAndroid Build Coastguard Worker stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source));
176*86ee64e7SAndroid Build Coastguard Worker stream.avail_in = static_cast<uInt>(source_length);
177*86ee64e7SAndroid Build Coastguard Worker if (static_cast<uLong>(stream.avail_in) != source_length)
178*86ee64e7SAndroid Build Coastguard Worker return Z_BUF_ERROR;
179*86ee64e7SAndroid Build Coastguard Worker
180*86ee64e7SAndroid Build Coastguard Worker stream.next_out = dest;
181*86ee64e7SAndroid Build Coastguard Worker stream.avail_out = static_cast<uInt>(*dest_length);
182*86ee64e7SAndroid Build Coastguard Worker if (static_cast<uLong>(stream.avail_out) != *dest_length)
183*86ee64e7SAndroid Build Coastguard Worker return Z_BUF_ERROR;
184*86ee64e7SAndroid Build Coastguard Worker
185*86ee64e7SAndroid Build Coastguard Worker stream.zalloc = static_cast<alloc_func>(0);
186*86ee64e7SAndroid Build Coastguard Worker stream.zfree = static_cast<free_func>(0);
187*86ee64e7SAndroid Build Coastguard Worker
188*86ee64e7SAndroid Build Coastguard Worker int err = inflateInit2(&stream, ZlibStreamWrapperType(wrapper_type));
189*86ee64e7SAndroid Build Coastguard Worker if (err != Z_OK)
190*86ee64e7SAndroid Build Coastguard Worker return err;
191*86ee64e7SAndroid Build Coastguard Worker
192*86ee64e7SAndroid Build Coastguard Worker err = inflate(&stream, Z_FINISH);
193*86ee64e7SAndroid Build Coastguard Worker if (err != Z_STREAM_END) {
194*86ee64e7SAndroid Build Coastguard Worker inflateEnd(&stream);
195*86ee64e7SAndroid Build Coastguard Worker if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
196*86ee64e7SAndroid Build Coastguard Worker return Z_DATA_ERROR;
197*86ee64e7SAndroid Build Coastguard Worker return err;
198*86ee64e7SAndroid Build Coastguard Worker }
199*86ee64e7SAndroid Build Coastguard Worker *dest_length = stream.total_out;
200*86ee64e7SAndroid Build Coastguard Worker
201*86ee64e7SAndroid Build Coastguard Worker err = inflateEnd(&stream);
202*86ee64e7SAndroid Build Coastguard Worker return err;
203*86ee64e7SAndroid Build Coastguard Worker }
204*86ee64e7SAndroid Build Coastguard Worker
205*86ee64e7SAndroid Build Coastguard Worker } // namespace zlib_internal
206