• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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