xref: /aosp_15_r20/external/zlib/google/compression_utils_portable.cc (revision 86ee64e75fa5f8bce2c8c356138035642429cd05)
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