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 /*
18 This test program is typically run indirectly, by the "wuffs test" or "wuffs
19 bench" commands. These commands take an optional "-mimic" flag to check that
20 Wuffs' output mimics (i.e. exactly matches) other libraries' output, such as
21 giflib for GIF, libpng for PNG, etc.
22
23 To manually run this test:
24
25 for CC in clang gcc; do
26 $CC -std=c99 -Wall -Werror deflate.c && ./a.out
27 rm -f a.out
28 done
29
30 Each edition should print "PASS", amongst other information, and exit(0).
31
32 Add the "wuffs mimic cflags" (everything after the colon below) to the C
33 compiler flags (after the .c file) to run the mimic tests.
34
35 To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace
36 the first "./a.out" with "./a.out -bench". Combine these changes with the
37 "wuffs mimic cflags" to run the mimic benchmarks.
38 */
39
40 // !! wuffs mimic cflags: -DWUFFS_MIMIC -lz
41
42 // Wuffs ships as a "single file C library" or "header file library" as per
43 // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
44 //
45 // To use that single file as a "foo.c"-like implementation, instead of a
46 // "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or
47 // compiling it.
48 #define WUFFS_IMPLEMENTATION
49
50 // Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of
51 // release/c/etc.c whitelist which parts of Wuffs to build. That file contains
52 // the entire Wuffs standard library, implementing a variety of codecs and file
53 // formats. Without this macro definition, an optimizing compiler or linker may
54 // very well discard Wuffs code for unused codecs, but listing the Wuffs
55 // modules we use makes that process explicit. Preprocessing means that such
56 // code simply isn't compiled.
57 #define WUFFS_CONFIG__MODULES
58 #define WUFFS_CONFIG__MODULE__BASE
59 #define WUFFS_CONFIG__MODULE__DEFLATE
60
61 // If building this program in an environment that doesn't easily accommodate
62 // relative includes, you can use the script/inline-c-relative-includes.go
63 // program to generate a stand-alone C file.
64 #include "../../../release/c/wuffs-unsupported-snapshot.c"
65 #include "../testlib/testlib.c"
66 #ifdef WUFFS_MIMIC
67 #include "../mimiclib/deflate-gzip-zlib.c"
68 #endif
69
70 // ---------------- Golden Tests
71
72 // The src_offset0 and src_offset1 magic numbers come from:
73 //
74 // go run script/extract-flate-offsets.go test/data/*.gz
75 //
76 // The empty comments forces clang-format to place one element per line.
77
78 golden_test deflate_256_bytes_gt = {
79 .want_filename = "test/data/artificial/256.bytes", //
80 .src_filename = "test/data/artificial/256.bytes.gz", //
81 .src_offset0 = 20, //
82 .src_offset1 = 281, //
83 };
84
85 golden_test deflate_deflate_backref_crosses_blocks_gt = {
86 .want_filename =
87 "test/data/artificial/"
88 "deflate-backref-crosses-blocks.deflate.decompressed",
89 .src_filename =
90 "test/data/artificial/"
91 "deflate-backref-crosses-blocks.deflate",
92 };
93
94 golden_test deflate_deflate_distance_32768_gt = {
95 .want_filename =
96 "test/data/artificial/"
97 "deflate-distance-32768.deflate.decompressed",
98 .src_filename =
99 "test/data/artificial/"
100 "deflate-distance-32768.deflate",
101 };
102
103 golden_test deflate_deflate_distance_code_31_gt = {
104 .want_filename = "test/data/artificial/0.bytes",
105 .src_filename =
106 "test/data/artificial/"
107 "deflate-distance-code-31.deflate",
108 };
109
110 golden_test deflate_midsummer_gt = {
111 .want_filename = "test/data/midsummer.txt", //
112 .src_filename = "test/data/midsummer.txt.gz", //
113 .src_offset0 = 24, //
114 .src_offset1 = 5166, //
115 };
116
117 golden_test deflate_pi_gt = {
118 .want_filename = "test/data/pi.txt", //
119 .src_filename = "test/data/pi.txt.gz", //
120 .src_offset0 = 17, //
121 .src_offset1 = 48335, //
122 };
123
124 golden_test deflate_romeo_gt = {
125 .want_filename = "test/data/romeo.txt", //
126 .src_filename = "test/data/romeo.txt.gz", //
127 .src_offset0 = 20, //
128 .src_offset1 = 550, //
129 };
130
131 golden_test deflate_romeo_fixed_gt = {
132 .want_filename = "test/data/romeo.txt", //
133 .src_filename = "test/data/romeo.txt.fixed-huff.deflate", //
134 };
135
136 // ---------------- Deflate Tests
137
wuffs_deflate_decode(wuffs_base__io_buffer * dst,wuffs_base__io_buffer * src,uint32_t wuffs_initialize_flags,uint64_t wlimit,uint64_t rlimit)138 const char* wuffs_deflate_decode(wuffs_base__io_buffer* dst,
139 wuffs_base__io_buffer* src,
140 uint32_t wuffs_initialize_flags,
141 uint64_t wlimit,
142 uint64_t rlimit) {
143 wuffs_deflate__decoder dec;
144 const char* status = wuffs_deflate__decoder__initialize(
145 &dec, sizeof dec, WUFFS_VERSION, wuffs_initialize_flags);
146 if (status) {
147 RETURN_FAIL("initialize: \"%s\"", status);
148 }
149
150 while (true) {
151 wuffs_base__io_buffer limited_dst = make_limited_writer(*dst, wlimit);
152 wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
153
154 status = wuffs_deflate__decoder__decode_io_writer(
155 &dec, &limited_dst, &limited_src, global_work_slice);
156
157 dst->meta.wi += limited_dst.meta.wi;
158 src->meta.ri += limited_src.meta.ri;
159
160 if (((wlimit < UINT64_MAX) &&
161 (status == wuffs_base__suspension__short_write)) ||
162 ((rlimit < UINT64_MAX) &&
163 (status == wuffs_base__suspension__short_read))) {
164 continue;
165 }
166 return status;
167 }
168 }
169
test_wuffs_deflate_decode_256_bytes()170 const char* test_wuffs_deflate_decode_256_bytes() {
171 CHECK_FOCUS(__func__);
172 return do_test_io_buffers(wuffs_deflate_decode, &deflate_256_bytes_gt,
173 UINT64_MAX, UINT64_MAX);
174 }
175
test_wuffs_deflate_decode_deflate_backref_crosses_blocks()176 const char* test_wuffs_deflate_decode_deflate_backref_crosses_blocks() {
177 CHECK_FOCUS(__func__);
178 return do_test_io_buffers(wuffs_deflate_decode,
179 &deflate_deflate_backref_crosses_blocks_gt,
180 UINT64_MAX, UINT64_MAX);
181 }
182
test_wuffs_deflate_decode_deflate_distance_32768()183 const char* test_wuffs_deflate_decode_deflate_distance_32768() {
184 CHECK_FOCUS(__func__);
185 return do_test_io_buffers(wuffs_deflate_decode,
186 &deflate_deflate_distance_32768_gt, UINT64_MAX,
187 UINT64_MAX);
188 }
189
test_wuffs_deflate_decode_deflate_distance_code_31()190 const char* test_wuffs_deflate_decode_deflate_distance_code_31() {
191 CHECK_FOCUS(__func__);
192 const char* got = do_test_io_buffers(wuffs_deflate_decode,
193 &deflate_deflate_distance_code_31_gt,
194 UINT64_MAX, UINT64_MAX);
195 if (got != wuffs_deflate__error__bad_huffman_code) {
196 RETURN_FAIL("got \"%s\", want \"%s\"", got,
197 wuffs_deflate__error__bad_huffman_code);
198 }
199 return NULL;
200 }
201
test_wuffs_deflate_decode_midsummer()202 const char* test_wuffs_deflate_decode_midsummer() {
203 CHECK_FOCUS(__func__);
204 return do_test_io_buffers(wuffs_deflate_decode, &deflate_midsummer_gt,
205 UINT64_MAX, UINT64_MAX);
206 }
207
test_wuffs_deflate_decode_pi_just_one_read()208 const char* test_wuffs_deflate_decode_pi_just_one_read() {
209 CHECK_FOCUS(__func__);
210 return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
211 UINT64_MAX);
212 }
213
test_wuffs_deflate_decode_pi_many_big_reads()214 const char* test_wuffs_deflate_decode_pi_many_big_reads() {
215 CHECK_FOCUS(__func__);
216 return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
217 4096);
218 }
219
test_wuffs_deflate_decode_pi_many_medium_reads()220 const char* test_wuffs_deflate_decode_pi_many_medium_reads() {
221 CHECK_FOCUS(__func__);
222 return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
223 599);
224 }
225
test_wuffs_deflate_decode_pi_many_small_writes_reads()226 const char* test_wuffs_deflate_decode_pi_many_small_writes_reads() {
227 CHECK_FOCUS(__func__);
228 return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, 59, 61);
229 }
230
test_wuffs_deflate_decode_romeo()231 const char* test_wuffs_deflate_decode_romeo() {
232 CHECK_FOCUS(__func__);
233 return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_gt, UINT64_MAX,
234 UINT64_MAX);
235 }
236
test_wuffs_deflate_decode_romeo_fixed()237 const char* test_wuffs_deflate_decode_romeo_fixed() {
238 CHECK_FOCUS(__func__);
239 return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_fixed_gt,
240 UINT64_MAX, UINT64_MAX);
241 }
242
test_wuffs_deflate_decode_split_src()243 const char* test_wuffs_deflate_decode_split_src() {
244 CHECK_FOCUS(__func__);
245
246 wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
247 .data = global_src_slice,
248 });
249 wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
250 .data = global_got_slice,
251 });
252 wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
253 .data = global_want_slice,
254 });
255
256 const char* status;
257 golden_test* gt = &deflate_256_bytes_gt;
258 status = read_file(&src, gt->src_filename);
259 if (status) {
260 return status;
261 }
262 status = read_file(&want, gt->want_filename);
263 if (status) {
264 return status;
265 }
266
267 int i;
268 for (i = 1; i < 32; i++) {
269 size_t split = gt->src_offset0 + i;
270 if (split >= gt->src_offset1) {
271 RETURN_FAIL("i=%d: split was not an interior split", i);
272 }
273 got.meta.wi = 0;
274
275 wuffs_deflate__decoder dec;
276 status = wuffs_deflate__decoder__initialize(
277 &dec, sizeof dec, WUFFS_VERSION,
278 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
279 if (status) {
280 RETURN_FAIL("initialize: \"%s\"", status);
281 }
282
283 src.meta.closed = false;
284 src.meta.ri = gt->src_offset0;
285 src.meta.wi = split;
286 const char* z0 = wuffs_deflate__decoder__decode_io_writer(
287 &dec, &got, &src, global_work_slice);
288
289 src.meta.closed = true;
290 src.meta.ri = split;
291 src.meta.wi = gt->src_offset1;
292 const char* z1 = wuffs_deflate__decoder__decode_io_writer(
293 &dec, &got, &src, global_work_slice);
294
295 if (z0 != wuffs_base__suspension__short_read) {
296 RETURN_FAIL("i=%d: z0: got \"%s\", want \"%s\"", i, z0,
297 wuffs_base__suspension__short_read);
298 }
299
300 if (z1) {
301 RETURN_FAIL("i=%d: z1: got \"%s\"", i, z1);
302 }
303
304 char prefix[64];
305 snprintf(prefix, 64, "i=%d: ", i);
306 status = check_io_buffers_equal(prefix, &got, &want);
307 if (status) {
308 return status;
309 }
310 }
311 return NULL;
312 }
313
do_test_wuffs_deflate_history(int i,golden_test * gt,wuffs_base__io_buffer * src,wuffs_base__io_buffer * got,wuffs_deflate__decoder * dec,uint32_t starting_history_index,uint64_t wlimit,const char * want_z)314 const char* do_test_wuffs_deflate_history(int i,
315 golden_test* gt,
316 wuffs_base__io_buffer* src,
317 wuffs_base__io_buffer* got,
318 wuffs_deflate__decoder* dec,
319 uint32_t starting_history_index,
320 uint64_t wlimit,
321 const char* want_z) {
322 src->meta.ri = gt->src_offset0;
323 src->meta.wi = gt->src_offset1;
324 got->meta.ri = 0;
325 got->meta.wi = 0;
326
327 wuffs_base__io_buffer limited_got = make_limited_writer(*got, wlimit);
328
329 dec->private_impl.f_history_index = starting_history_index;
330
331 const char* got_z = wuffs_deflate__decoder__decode_io_writer(
332 dec, &limited_got, src, global_work_slice);
333 got->meta.wi += limited_got.meta.wi;
334 if (got_z != want_z) {
335 RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
336 ": decode status: got \"%s\", want \"%s\"",
337 i, starting_history_index, got_z, want_z);
338 }
339 return NULL;
340 }
341
test_wuffs_deflate_history_full()342 const char* test_wuffs_deflate_history_full() {
343 CHECK_FOCUS(__func__);
344
345 wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
346 .data = global_src_slice,
347 });
348 wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
349 .data = global_got_slice,
350 });
351 wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
352 .data = global_want_slice,
353 });
354
355 const char* status;
356 golden_test* gt = &deflate_pi_gt;
357 status = read_file(&src, gt->src_filename);
358 if (status) {
359 return status;
360 }
361 status = read_file(&want, gt->want_filename);
362 if (status) {
363 return status;
364 }
365
366 const int full_history_size = 0x8000;
367 int i;
368 for (i = -2; i <= +2; i++) {
369 wuffs_deflate__decoder dec;
370 status = wuffs_deflate__decoder__initialize(
371 &dec, sizeof dec, WUFFS_VERSION,
372 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
373 if (status) {
374 RETURN_FAIL("initialize: \"%s\"", status);
375 }
376
377 status = do_test_wuffs_deflate_history(
378 i, gt, &src, &got, &dec, 0, want.meta.wi + i,
379 i >= 0 ? NULL : wuffs_base__suspension__short_write);
380 if (status) {
381 return status;
382 }
383
384 uint32_t want_history_index = i >= 0 ? 0 : full_history_size;
385 if (dec.private_impl.f_history_index != want_history_index) {
386 RETURN_FAIL("i=%d: history_index: got %" PRIu32 ", want %" PRIu32, i,
387 dec.private_impl.f_history_index, want_history_index);
388 }
389 if (i >= 0) {
390 continue;
391 }
392
393 wuffs_base__io_buffer history_got = ((wuffs_base__io_buffer){
394 .data = ((wuffs_base__slice_u8){
395 .ptr = dec.private_data.f_history,
396 .len = full_history_size,
397 }),
398 });
399 history_got.meta.wi = full_history_size;
400 if (want.meta.wi < full_history_size - i) {
401 RETURN_FAIL("i=%d: want file is too short", i);
402 }
403 wuffs_base__io_buffer history_want = ((wuffs_base__io_buffer){
404 .data = ((wuffs_base__slice_u8){
405 .ptr = global_want_array + want.meta.wi - (full_history_size - i),
406 .len = full_history_size,
407 }),
408 });
409 history_want.meta.wi = full_history_size;
410
411 status = check_io_buffers_equal("", &history_got, &history_want);
412 if (status) {
413 return status;
414 }
415 }
416 return NULL;
417 }
418
test_wuffs_deflate_history_partial()419 const char* test_wuffs_deflate_history_partial() {
420 CHECK_FOCUS(__func__);
421
422 wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
423 .data = global_src_slice,
424 });
425 wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
426 .data = global_got_slice,
427 });
428
429 golden_test* gt = &deflate_pi_gt;
430 const char* status = read_file(&src, gt->src_filename);
431 if (status) {
432 return status;
433 }
434
435 uint32_t starting_history_indexes[] = {
436 0x0000, 0x0001, 0x1234, 0x7FFB, 0x7FFC, 0x7FFD, 0x7FFE, 0x7FFF,
437 0x8000, 0x8001, 0x9234, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
438 };
439
440 int i;
441 for (i = 0; i < WUFFS_TESTLIB_ARRAY_SIZE(starting_history_indexes); i++) {
442 uint32_t starting_history_index = starting_history_indexes[i];
443
444 // The flate_pi_gt golden test file decodes to the digits of pi.
445 const char* fragment = "3.14";
446 const uint32_t fragment_length = 4;
447
448 wuffs_deflate__decoder dec;
449 memset(&(dec.private_data.f_history), 0,
450 sizeof(dec.private_data.f_history));
451 status = wuffs_deflate__decoder__initialize(
452 &dec, sizeof dec, WUFFS_VERSION,
453 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
454 if (status) {
455 RETURN_FAIL("initialize: \"%s\"", status);
456 }
457
458 status = do_test_wuffs_deflate_history(
459 i, gt, &src, &got, &dec, starting_history_index, fragment_length,
460 wuffs_base__suspension__short_write);
461 if (status) {
462 return status;
463 }
464
465 bool got_full = dec.private_impl.f_history_index >= 0x8000;
466 uint32_t got_history_index = dec.private_impl.f_history_index & 0x7FFF;
467 bool want_full = (starting_history_index + fragment_length) >= 0x8000;
468 uint32_t want_history_index =
469 (starting_history_index + fragment_length) & 0x7FFF;
470 if ((got_full != want_full) || (got_history_index != want_history_index)) {
471 RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
472 ": history_index: got %d;%04" PRIX32 ", want %d;%04" PRIX32,
473 i, starting_history_index, (int)(got_full), got_history_index,
474 (int)(want_full), want_history_index);
475 }
476
477 int j;
478 for (j = -2; j < (int)(fragment_length) + 2; j++) {
479 uint32_t index = (starting_history_index + j) & 0x7FFF;
480 uint8_t got = dec.private_data.f_history[index];
481 uint8_t want = (0 <= j && j < fragment_length) ? fragment[j] : 0;
482 if (got != want) {
483 RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
484 ": j=%d: got 0x%02" PRIX8 ", want 0x%02" PRIX8,
485 i, starting_history_index, j, got, want);
486 }
487 }
488 }
489 return NULL;
490 }
491
test_wuffs_deflate_table_redirect()492 const char* test_wuffs_deflate_table_redirect() {
493 CHECK_FOCUS(__func__);
494
495 // Call init_huff with a Huffman code that looks like:
496 //
497 // code_bits cl c r s 1st 2nd
498 // 0b_______________0 1 1 1 0 0b........0
499 // 0b______________10 2 1 1 1 0b.......01
500 // 0b_____________110 3 1 1 2 0b......011
501 // 0b____________1110 4 1 1 3 0b.....0111
502 // 0b__________1_1110 5 1 1 4 0b....01111
503 // 0b_________11_1110 6 1 1 5 0b...011111
504 // 0b________111_1110 7 1 1 6 0b..0111111
505 // 8 0 2
506 // 0b_____1_1111_1100 9 1 3 7 0b001111111
507 // 0b____11_1111_1010 10 1 5 8 0b101111111 0b..0 (3 bits)
508 // 11 0 10
509 // 0b__1111_1110_1100 12 19 19 9 0b101111111 0b001
510 // 0b__1111_1110_1101 12 18 10 0b101111111 0b101
511 // 0b__1111_1110_1110 12 17 11 0b101111111 0b011
512 // 0b__1111_1110_1111 12 16 12 0b101111111 0b111
513 // 0b__1111_1111_0000 12 15 13 0b011111111 0b000 (3 bits)
514 // 0b__1111_1111_0001 12 14 14 0b011111111 0b100
515 // 0b__1111_1111_0010 12 13 15 0b011111111 0b010
516 // 0b__1111_1111_0011 12 12 16 0b011111111 0b110
517 // 0b__1111_1111_0100 12 11 17 0b011111111 0b001
518 // 0b__1111_1111_0101 12 10 18 0b011111111 0b101
519 // 0b__1111_1111_0110 12 9 19 0b011111111 0b011
520 // 0b__1111_1111_0111 12 8 20 0b011111111 0b111
521 // 0b__1111_1111_1000 12 7 21 0b111111111 0b.000 (4 bits)
522 // 0b__1111_1111_1001 12 6 22 0b111111111 0b.100
523 // 0b__1111_1111_1010 12 5 23 0b111111111 0b.010
524 // 0b__1111_1111_1011 12 4 24 0b111111111 0b.110
525 // 0b__1111_1111_1100 12 3 25 0b111111111 0b.001
526 // 0b__1111_1111_1101 12 2 26 0b111111111 0b.101
527 // 0b__1111_1111_1110 12 1 27 0b111111111 0b.011
528 // 0b1_1111_1111_1110 13 2 1 28 0b111111111 0b0111
529 // 0b1_1111_1111_1111 13 0 29 0b111111111 0b1111
530 //
531 // cl is the code_length.
532 // c is counts[code_length]
533 // r is the number of codes (of that code_length) remaining.
534 // s is the symbol
535 // 1st is the key in the first level table (9 bits).
536 // 2nd is the key in the second level table (variable bits).
537
538 wuffs_deflate__decoder dec;
539 const char* status = wuffs_deflate__decoder__initialize(
540 &dec, sizeof dec, WUFFS_VERSION,
541 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
542 if (status) {
543 RETURN_FAIL("initialize: \"%s\"", status);
544 }
545 memset(&(dec.private_data.f_huffs), 0, sizeof(dec.private_data.f_huffs));
546
547 int i;
548 int n = 0;
549 dec.private_data.f_code_lengths[n++] = 1;
550 dec.private_data.f_code_lengths[n++] = 2;
551 dec.private_data.f_code_lengths[n++] = 3;
552 dec.private_data.f_code_lengths[n++] = 4;
553 dec.private_data.f_code_lengths[n++] = 5;
554 dec.private_data.f_code_lengths[n++] = 6;
555 dec.private_data.f_code_lengths[n++] = 7;
556 dec.private_data.f_code_lengths[n++] = 9;
557 dec.private_data.f_code_lengths[n++] = 10;
558 for (i = 0; i < 19; i++) {
559 dec.private_data.f_code_lengths[n++] = 12;
560 }
561 dec.private_data.f_code_lengths[n++] = 13;
562 dec.private_data.f_code_lengths[n++] = 13;
563
564 status = wuffs_deflate__decoder__init_huff(&dec, 0, 0, n, 257);
565 if (status) {
566 RETURN_FAIL("init_huff: \"%s\"", status);
567 }
568
569 // There is one 1st-level table (9 bits), and three 2nd-level tables (3, 3
570 // and 4 bits). f_huffs[0]'s elements should be non-zero for those tables and
571 // should be zero outside of those tables.
572 const int n_f_huffs = sizeof(dec.private_data.f_huffs[0]) /
573 sizeof(dec.private_data.f_huffs[0][0]);
574 for (i = 0; i < n_f_huffs; i++) {
575 bool got = dec.private_data.f_huffs[0][i] == 0;
576 bool want = i >= (1 << 9) + (1 << 3) + (1 << 3) + (1 << 4);
577 if (got != want) {
578 RETURN_FAIL("huffs[0][%d] == 0: got %d, want %d", i, got, want);
579 }
580 }
581
582 // The redirects in the 1st-level table should be at:
583 // - 0b101111111 (0x017F) to the table offset 512 (0x0200), a 3-bit table.
584 // - 0b011111111 (0x00FF) to the table offset 520 (0x0208), a 3-bit table.
585 // - 0b111111111 (0x01FF) to the table offset 528 (0x0210), a 4-bit table.
586 uint32_t got;
587 uint32_t want;
588 got = dec.private_data.f_huffs[0][0x017F];
589 want = 0x10020039;
590 if (got != want) {
591 RETURN_FAIL("huffs[0][0x017F]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got,
592 want);
593 }
594 got = dec.private_data.f_huffs[0][0x00FF];
595 want = 0x10020839;
596 if (got != want) {
597 RETURN_FAIL("huffs[0][0x00FF]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got,
598 want);
599 }
600 got = dec.private_data.f_huffs[0][0x01FF];
601 want = 0x10021049;
602 if (got != want) {
603 RETURN_FAIL("huffs[0][0x01FF]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got,
604 want);
605 }
606
607 // The first 2nd-level table should look like wants.
608 const uint32_t wants[8] = {
609 0x80000801, 0x80000903, 0x80000801, 0x80000B03,
610 0x80000801, 0x80000A03, 0x80000801, 0x80000C03,
611 };
612 for (i = 0; i < 8; i++) {
613 got = dec.private_data.f_huffs[0][0x0200 + i];
614 want = wants[i];
615 if (got != want) {
616 RETURN_FAIL("huffs[0][0x%04" PRIX32 "]: got 0x%08" PRIX32
617 ", want 0x%08" PRIX32,
618 (uint32_t)(0x0200 + i), got, want);
619 }
620 }
621 return NULL;
622 }
623
624 // ---------------- Mimic Tests
625
626 #ifdef WUFFS_MIMIC
627
test_mimic_deflate_decode_256_bytes()628 const char* test_mimic_deflate_decode_256_bytes() {
629 CHECK_FOCUS(__func__);
630 return do_test_io_buffers(mimic_deflate_decode, &deflate_256_bytes_gt,
631 UINT64_MAX, UINT64_MAX);
632 }
633
test_mimic_deflate_decode_deflate_backref_crosses_blocks()634 const char* test_mimic_deflate_decode_deflate_backref_crosses_blocks() {
635 CHECK_FOCUS(__func__);
636 return do_test_io_buffers(mimic_deflate_decode,
637 &deflate_deflate_backref_crosses_blocks_gt,
638 UINT64_MAX, UINT64_MAX);
639 }
640
test_mimic_deflate_decode_deflate_distance_32768()641 const char* test_mimic_deflate_decode_deflate_distance_32768() {
642 CHECK_FOCUS(__func__);
643 return do_test_io_buffers(mimic_deflate_decode,
644 &deflate_deflate_distance_32768_gt, UINT64_MAX,
645 UINT64_MAX);
646 }
647
test_mimic_deflate_decode_deflate_distance_code_31()648 const char* test_mimic_deflate_decode_deflate_distance_code_31() {
649 CHECK_FOCUS(__func__);
650 const char* got = do_test_io_buffers(mimic_deflate_decode,
651 &deflate_deflate_distance_code_31_gt,
652 UINT64_MAX, UINT64_MAX);
653 const char* want = "inflate failed (data error)";
654 if ((got != want) && ((got == NULL) || (want == NULL) || strcmp(got, want))) {
655 RETURN_FAIL("got \"%s\", want \"%s\"", got, want);
656 }
657 return NULL;
658 }
659
test_mimic_deflate_decode_midsummer()660 const char* test_mimic_deflate_decode_midsummer() {
661 CHECK_FOCUS(__func__);
662 return do_test_io_buffers(mimic_deflate_decode, &deflate_midsummer_gt,
663 UINT64_MAX, UINT64_MAX);
664 }
665
test_mimic_deflate_decode_pi_just_one_read()666 const char* test_mimic_deflate_decode_pi_just_one_read() {
667 CHECK_FOCUS(__func__);
668 return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, UINT64_MAX,
669 UINT64_MAX);
670 }
671
test_mimic_deflate_decode_pi_many_big_reads()672 const char* test_mimic_deflate_decode_pi_many_big_reads() {
673 CHECK_FOCUS(__func__);
674 return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, UINT64_MAX,
675 4096);
676 }
677
test_mimic_deflate_decode_romeo()678 const char* test_mimic_deflate_decode_romeo() {
679 CHECK_FOCUS(__func__);
680 return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_gt, UINT64_MAX,
681 UINT64_MAX);
682 }
683
test_mimic_deflate_decode_romeo_fixed()684 const char* test_mimic_deflate_decode_romeo_fixed() {
685 CHECK_FOCUS(__func__);
686 return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_fixed_gt,
687 UINT64_MAX, UINT64_MAX);
688 }
689
690 #endif // WUFFS_MIMIC
691
692 // ---------------- Deflate Benches
693
bench_wuffs_deflate_decode_1k_full_init()694 const char* bench_wuffs_deflate_decode_1k_full_init() {
695 CHECK_FOCUS(__func__);
696 return do_bench_io_buffers(wuffs_deflate_decode,
697 WUFFS_INITIALIZE__DEFAULT_OPTIONS, tc_dst,
698 &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
699 }
700
bench_wuffs_deflate_decode_1k_part_init()701 const char* bench_wuffs_deflate_decode_1k_part_init() {
702 CHECK_FOCUS(__func__);
703 return do_bench_io_buffers(
704 wuffs_deflate_decode,
705 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
706 &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
707 }
708
bench_wuffs_deflate_decode_10k_full_init()709 const char* bench_wuffs_deflate_decode_10k_full_init() {
710 CHECK_FOCUS(__func__);
711 return do_bench_io_buffers(
712 wuffs_deflate_decode, WUFFS_INITIALIZE__DEFAULT_OPTIONS, tc_dst,
713 &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
714 }
715
bench_wuffs_deflate_decode_10k_part_init()716 const char* bench_wuffs_deflate_decode_10k_part_init() {
717 CHECK_FOCUS(__func__);
718 return do_bench_io_buffers(
719 wuffs_deflate_decode,
720 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
721 &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
722 }
723
bench_wuffs_deflate_decode_100k_just_one_read()724 const char* bench_wuffs_deflate_decode_100k_just_one_read() {
725 CHECK_FOCUS(__func__);
726 return do_bench_io_buffers(
727 wuffs_deflate_decode,
728 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
729 &deflate_pi_gt, UINT64_MAX, UINT64_MAX, 30);
730 }
731
bench_wuffs_deflate_decode_100k_many_big_reads()732 const char* bench_wuffs_deflate_decode_100k_many_big_reads() {
733 CHECK_FOCUS(__func__);
734 return do_bench_io_buffers(
735 wuffs_deflate_decode,
736 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
737 &deflate_pi_gt, UINT64_MAX, 4096, 30);
738 }
739
740 // ---------------- Mimic Benches
741
742 #ifdef WUFFS_MIMIC
743
bench_mimic_deflate_decode_1k()744 const char* bench_mimic_deflate_decode_1k() {
745 CHECK_FOCUS(__func__);
746 return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_romeo_gt,
747 UINT64_MAX, UINT64_MAX, 2000);
748 }
749
bench_mimic_deflate_decode_10k()750 const char* bench_mimic_deflate_decode_10k() {
751 CHECK_FOCUS(__func__);
752 return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst,
753 &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX,
754 300);
755 }
756
bench_mimic_deflate_decode_100k_just_one_read()757 const char* bench_mimic_deflate_decode_100k_just_one_read() {
758 CHECK_FOCUS(__func__);
759 return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt,
760 UINT64_MAX, UINT64_MAX, 30);
761 }
762
bench_mimic_deflate_decode_100k_many_big_reads()763 const char* bench_mimic_deflate_decode_100k_many_big_reads() {
764 CHECK_FOCUS(__func__);
765 return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt,
766 UINT64_MAX, 4096, 30);
767 }
768
769 #endif // WUFFS_MIMIC
770
771 // ---------------- Manifest
772
773 // The empty comments forces clang-format to place one element per line.
774 proc tests[] = {
775
776 test_wuffs_deflate_decode_256_bytes, //
777 test_wuffs_deflate_decode_deflate_backref_crosses_blocks, //
778 test_wuffs_deflate_decode_deflate_distance_32768, //
779 test_wuffs_deflate_decode_deflate_distance_code_31, //
780 test_wuffs_deflate_decode_midsummer, //
781 test_wuffs_deflate_decode_pi_just_one_read, //
782 test_wuffs_deflate_decode_pi_many_big_reads, //
783 test_wuffs_deflate_decode_pi_many_medium_reads, //
784 test_wuffs_deflate_decode_pi_many_small_writes_reads, //
785 test_wuffs_deflate_decode_romeo, //
786 test_wuffs_deflate_decode_romeo_fixed, //
787 test_wuffs_deflate_decode_split_src, //
788 test_wuffs_deflate_history_full, //
789 test_wuffs_deflate_history_partial, //
790 test_wuffs_deflate_table_redirect, //
791
792 #ifdef WUFFS_MIMIC
793
794 test_mimic_deflate_decode_256_bytes, //
795 test_mimic_deflate_decode_deflate_backref_crosses_blocks, //
796 test_mimic_deflate_decode_deflate_distance_32768, //
797 test_mimic_deflate_decode_deflate_distance_code_31, //
798 test_mimic_deflate_decode_midsummer, //
799 test_mimic_deflate_decode_pi_just_one_read, //
800 test_mimic_deflate_decode_pi_many_big_reads, //
801 test_mimic_deflate_decode_romeo, //
802 test_mimic_deflate_decode_romeo_fixed, //
803
804 #endif // WUFFS_MIMIC
805
806 NULL,
807 };
808
809 // The empty comments forces clang-format to place one element per line.
810 proc benches[] = {
811
812 bench_wuffs_deflate_decode_1k_full_init, //
813 bench_wuffs_deflate_decode_1k_part_init, //
814 bench_wuffs_deflate_decode_10k_full_init, //
815 bench_wuffs_deflate_decode_10k_part_init, //
816 bench_wuffs_deflate_decode_100k_just_one_read, //
817 bench_wuffs_deflate_decode_100k_many_big_reads, //
818
819 #ifdef WUFFS_MIMIC
820
821 bench_mimic_deflate_decode_1k, //
822 bench_mimic_deflate_decode_10k, //
823 bench_mimic_deflate_decode_100k_just_one_read, //
824 bench_mimic_deflate_decode_100k_many_big_reads, //
825
826 #endif // WUFFS_MIMIC
827
828 NULL,
829 };
830
main(int argc,char ** argv)831 int main(int argc, char** argv) {
832 proc_package_name = "std/deflate";
833 return test_main(argc, argv, tests, benches);
834 }
835