• 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 /*
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