1 // Copyright 2017 The Wuffs Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // ----------------
16
17 // Uncomment this line to test and bench miniz instead of zlib-the-library.
18 // #define WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB 1
19
20 #ifdef WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB
21 #include "/path/to/your/copy/of/github.com/richgel999/miniz/miniz_tinfl.c"
22
mimic_bench_adler32(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)23 const char* mimic_bench_adler32(wuffs_base__io_buffer* dst,
24 wuffs_base__io_buffer* src,
25 uint32_t wuffs_initialize_flags,
26 uint64_t wlimit,
27 uint64_t rlimit) {
28 return "miniz does not independently compute Adler32";
29 }
30
mimic_bench_crc32_ieee(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)31 const char* mimic_bench_crc32_ieee(wuffs_base__io_buffer* dst,
32 wuffs_base__io_buffer* src,
33 uint32_t wuffs_initialize_flags,
34 uint64_t wlimit,
35 uint64_t rlimit) {
36 return "miniz does not implement CRC32/IEEE";
37 }
38
mimic_deflate_zlib_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit,bool deflate_instead_of_zlib)39 const char* mimic_deflate_zlib_decode(wuffs_base__io_buffer* dst,
40 wuffs_base__io_buffer* src,
41 uint32_t wuffs_initialize_flags,
42 uint64_t wlimit,
43 uint64_t rlimit,
44 bool deflate_instead_of_zlib) {
45 if ((wlimit < UINT64_MAX) || (rlimit < UINT64_MAX)) {
46 // Supporting this would probably mean using tinfl_decompress instead of
47 // the simpler tinfl_decompress_mem_to_mem function.
48 return "unsupported I/O limit";
49 }
50 int flags = 0;
51 if (!deflate_instead_of_zlib) {
52 flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
53 }
54 size_t n = tinfl_decompress_mem_to_mem(
55 dst->data.ptr + dst->meta.wi, dst->data.len - dst->meta.wi,
56 src->data.ptr + src->meta.ri, src->meta.wi - src->meta.ri, flags);
57 if (n == TINFL_DECOMPRESS_MEM_TO_MEM_FAILED) {
58 return "TINFL_DECOMPRESS_MEM_TO_MEM_FAILED";
59 }
60 dst->meta.wi += n;
61 src->meta.ri = src->meta.wi;
62 return NULL;
63 }
64
mimic_deflate_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint64_t wlimit,uint64_t rlimit)65 const char* mimic_deflate_decode(wuffs_base__io_buffer* dst,
66 wuffs_base__io_buffer* src,
67 uint64_t wlimit,
68 uint64_t rlimit) {
69 return mimic_deflate_zlib_decode(dst, src, wlimit, rlimit, true);
70 }
71
mimic_gzip_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint64_t wlimit,uint64_t rlimit)72 const char* mimic_gzip_decode(wuffs_base__io_buffer* dst,
73 wuffs_base__io_buffer* src,
74 uint64_t wlimit,
75 uint64_t rlimit) {
76 return "miniz does not implement gzip";
77 }
78
mimic_zlib_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint64_t wlimit,uint64_t rlimit)79 const char* mimic_zlib_decode(wuffs_base__io_buffer* dst,
80 wuffs_base__io_buffer* src,
81 uint64_t wlimit,
82 uint64_t rlimit) {
83 return mimic_deflate_zlib_decode(dst, src, wlimit, rlimit, false);
84 }
85
86 #else // WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB
87 #include "zlib.h"
88
89 uint32_t global_mimiclib_deflate_unused_u32;
90
mimic_bench_adler32(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)91 const char* mimic_bench_adler32(wuffs_base__io_buffer* dst,
92 wuffs_base__io_buffer* src,
93 uint32_t wuffs_initialize_flags,
94 uint64_t wlimit,
95 uint64_t rlimit) {
96 global_mimiclib_deflate_unused_u32 = 0;
97 while (src->meta.ri < src->meta.wi) {
98 uint8_t* ptr = src->data.ptr + src->meta.ri;
99 size_t len = src->meta.wi - src->meta.ri;
100 if (len > 0x7FFFFFFF) {
101 return "src length is too large";
102 } else if (len > rlimit) {
103 len = rlimit;
104 }
105 global_mimiclib_deflate_unused_u32 =
106 adler32(global_mimiclib_deflate_unused_u32, ptr, len);
107 src->meta.ri += len;
108 }
109 return NULL;
110 }
111
mimic_bench_crc32_ieee(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)112 const char* mimic_bench_crc32_ieee(wuffs_base__io_buffer* dst,
113 wuffs_base__io_buffer* src,
114 uint32_t wuffs_initialize_flags,
115 uint64_t wlimit,
116 uint64_t rlimit) {
117 global_mimiclib_deflate_unused_u32 = 0;
118 while (src->meta.ri < src->meta.wi) {
119 uint8_t* ptr = src->data.ptr + src->meta.ri;
120 size_t len = src->meta.wi - src->meta.ri;
121 if (len > 0x7FFFFFFF) {
122 return "src length is too large";
123 } else if (len > rlimit) {
124 len = rlimit;
125 }
126 global_mimiclib_deflate_unused_u32 =
127 crc32(global_mimiclib_deflate_unused_u32, ptr, len);
128 src->meta.ri += len;
129 }
130 return NULL;
131 }
132
133 typedef enum {
134 zlib_flavor_raw,
135 zlib_flavor_gzip,
136 zlib_flavor_zlib,
137 } zlib_flavor;
138
mimic_deflate_gzip_zlib_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint64_t wlimit,uint64_t rlimit,zlib_flavor flavor)139 const char* mimic_deflate_gzip_zlib_decode(wuffs_base__io_buffer* dst,
140 wuffs_base__io_buffer* src,
141 uint64_t wlimit,
142 uint64_t rlimit,
143 zlib_flavor flavor) {
144 const char* ret = NULL;
145 if (dst->data.len > UINT_MAX) {
146 ret = "dst length is too large";
147 goto cleanup0;
148 }
149 if (src->data.len > UINT_MAX) {
150 ret = "src length is too large";
151 goto cleanup0;
152 }
153
154 // See inflateInit2 in the zlib manual, or in zlib.h, for details about how
155 // the window_bits int also encodes the wire format wrapper.
156 int window_bits = 0;
157 switch (flavor) {
158 case zlib_flavor_raw:
159 window_bits = -15;
160 break;
161 case zlib_flavor_gzip:
162 window_bits = +15 | 16;
163 break;
164 case zlib_flavor_zlib:
165 window_bits = +15;
166 break;
167 default:
168 ret = "invalid zlib_flavor";
169 goto cleanup0;
170 }
171 z_stream z = {0};
172 int ii2_err = inflateInit2(&z, window_bits);
173 if (ii2_err != Z_OK) {
174 ret = "inflateInit2 failed";
175 goto cleanup0;
176 }
177
178 while (true) {
179 z.next_in = src->data.ptr + src->meta.ri;
180 z.avail_in = src->meta.wi - src->meta.ri;
181 if (z.avail_in > rlimit) {
182 z.avail_in = rlimit;
183 }
184 uInt initial_avail_in = z.avail_in;
185
186 z.next_out = dst->data.ptr + dst->meta.wi;
187 z.avail_out = dst->data.len - dst->meta.wi;
188 if (z.avail_out > wlimit) {
189 z.avail_out = wlimit;
190 }
191 uInt initial_avail_out = z.avail_out;
192
193 // TODO: s/Z_NO_FLUSH/Z_SYNC_FLUSH/ more closely matches Wuffs' behavior.
194 int i_err = inflate(&z, Z_NO_FLUSH);
195
196 if (initial_avail_in < z.avail_in) {
197 ret = "inconsistent avail_in";
198 goto cleanup1;
199 }
200 src->meta.ri += initial_avail_in - z.avail_in;
201
202 if (initial_avail_out < z.avail_out) {
203 ret = "inconsistent avail_out";
204 goto cleanup1;
205 }
206 dst->meta.wi += initial_avail_out - z.avail_out;
207
208 if (i_err == Z_STREAM_END) {
209 break;
210 } else if (i_err == Z_DATA_ERROR) {
211 ret = "inflate failed (data error)";
212 goto cleanup1;
213 } else if (i_err != Z_OK) {
214 ret = "inflate failed";
215 goto cleanup1;
216 }
217 }
218
219 cleanup1:;
220 int ie_err = inflateEnd(&z);
221 if ((ie_err != Z_OK) && !ret) {
222 ret = "inflateEnd failed";
223 }
224
225 cleanup0:;
226 return ret;
227 }
228
mimic_deflate_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)229 const char* mimic_deflate_decode(wuffs_base__io_buffer* dst,
230 wuffs_base__io_buffer* src,
231 uint32_t wuffs_initialize_flags,
232 uint64_t wlimit,
233 uint64_t rlimit) {
234 return mimic_deflate_gzip_zlib_decode(dst, src, wlimit, rlimit,
235 zlib_flavor_raw);
236 }
237
mimic_gzip_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)238 const char* mimic_gzip_decode(wuffs_base__io_buffer* dst,
239 wuffs_base__io_buffer* src,
240 uint32_t wuffs_initialize_flags,
241 uint64_t wlimit,
242 uint64_t rlimit) {
243 return mimic_deflate_gzip_zlib_decode(dst, src, wlimit, rlimit,
244 zlib_flavor_gzip);
245 }
246
mimic_zlib_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)247 const char* mimic_zlib_decode(wuffs_base__io_buffer* dst,
248 wuffs_base__io_buffer* src,
249 uint32_t wuffs_initialize_flags,
250 uint64_t wlimit,
251 uint64_t rlimit) {
252 return mimic_deflate_gzip_zlib_decode(dst, src, wlimit, rlimit,
253 zlib_flavor_zlib);
254 }
255
256 #endif // WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB
257