xref: /isa-l/igzip/huff_codes.c (revision 55fbfabfc60f1002bc8133b730a59f6abd22cfce)
1660f49b0SGreg Tucker /**********************************************************************
2660f49b0SGreg Tucker   Copyright(c) 2011-2016 Intel Corporation All rights reserved.
3660f49b0SGreg Tucker 
4660f49b0SGreg Tucker   Redistribution and use in source and binary forms, with or without
5660f49b0SGreg Tucker   modification, are permitted provided that the following conditions
6660f49b0SGreg Tucker   are met:
7660f49b0SGreg Tucker     * Redistributions of source code must retain the above copyright
8660f49b0SGreg Tucker       notice, this list of conditions and the following disclaimer.
9660f49b0SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
10660f49b0SGreg Tucker       notice, this list of conditions and the following disclaimer in
11660f49b0SGreg Tucker       the documentation and/or other materials provided with the
12660f49b0SGreg Tucker       distribution.
13660f49b0SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
14660f49b0SGreg Tucker       contributors may be used to endorse or promote products derived
15660f49b0SGreg Tucker       from this software without specific prior written permission.
16660f49b0SGreg Tucker 
17660f49b0SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18660f49b0SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19660f49b0SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20660f49b0SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21660f49b0SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22660f49b0SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23660f49b0SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24660f49b0SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25660f49b0SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26660f49b0SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27660f49b0SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28660f49b0SGreg Tucker **********************************************************************/
29660f49b0SGreg Tucker 
30660f49b0SGreg Tucker #include "huff_codes.h"
31660f49b0SGreg Tucker #include "huffman.h"
3201dfbcc4SRoy Oursler #include "flatten_ll.h"
33660f49b0SGreg Tucker 
34660f49b0SGreg Tucker /* The order code length codes are written in the dynamic code header. This is
35660f49b0SGreg Tucker  * defined in RFC 1951 page 13 */
36*55fbfabfSMarcel Cornu static const uint8_t code_length_code_order[] = { 16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
37*55fbfabfSMarcel Cornu                                                   11, 4,  12, 3, 13, 2, 14, 1, 15 };
38660f49b0SGreg Tucker 
39*55fbfabfSMarcel Cornu static const uint32_t len_code_extra_bits[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1,
40*55fbfabfSMarcel Cornu                                                 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3,
41*55fbfabfSMarcel Cornu                                                 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x0 };
429992cc19SRoy Oursler 
43*55fbfabfSMarcel Cornu static const uint32_t dist_code_extra_bits[] = { 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3,
44*55fbfabfSMarcel Cornu                                                  0x4, 0x4, 0x5, 0x5, 0x6, 0x6, 0x7, 0x7, 0x8, 0x8,
45*55fbfabfSMarcel Cornu                                                  0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd };
469992cc19SRoy Oursler 
4707eac8fcSDaniel Verkamp static struct hufftables_icf static_hufftables = {
48*55fbfabfSMarcel Cornu         .lit_len_table = { { { { .code_and_extra = 0x00c, .length2 = 0x8 } } },
499099918dSPeng Xiao                            { { { .code_and_extra = 0x08c, .length2 = 0x8 } } },
509099918dSPeng Xiao                            { { { .code_and_extra = 0x04c, .length2 = 0x8 } } },
519099918dSPeng Xiao                            { { { .code_and_extra = 0x0cc, .length2 = 0x8 } } },
529099918dSPeng Xiao                            { { { .code_and_extra = 0x02c, .length2 = 0x8 } } },
539099918dSPeng Xiao                            { { { .code_and_extra = 0x0ac, .length2 = 0x8 } } },
549099918dSPeng Xiao                            { { { .code_and_extra = 0x06c, .length2 = 0x8 } } },
559099918dSPeng Xiao                            { { { .code_and_extra = 0x0ec, .length2 = 0x8 } } },
569099918dSPeng Xiao                            { { { .code_and_extra = 0x01c, .length2 = 0x8 } } },
579099918dSPeng Xiao                            { { { .code_and_extra = 0x09c, .length2 = 0x8 } } },
589099918dSPeng Xiao                            { { { .code_and_extra = 0x05c, .length2 = 0x8 } } },
599099918dSPeng Xiao                            { { { .code_and_extra = 0x0dc, .length2 = 0x8 } } },
609099918dSPeng Xiao                            { { { .code_and_extra = 0x03c, .length2 = 0x8 } } },
619099918dSPeng Xiao                            { { { .code_and_extra = 0x0bc, .length2 = 0x8 } } },
629099918dSPeng Xiao                            { { { .code_and_extra = 0x07c, .length2 = 0x8 } } },
639099918dSPeng Xiao                            { { { .code_and_extra = 0x0fc, .length2 = 0x8 } } },
649099918dSPeng Xiao                            { { { .code_and_extra = 0x002, .length2 = 0x8 } } },
659099918dSPeng Xiao                            { { { .code_and_extra = 0x082, .length2 = 0x8 } } },
669099918dSPeng Xiao                            { { { .code_and_extra = 0x042, .length2 = 0x8 } } },
679099918dSPeng Xiao                            { { { .code_and_extra = 0x0c2, .length2 = 0x8 } } },
689099918dSPeng Xiao                            { { { .code_and_extra = 0x022, .length2 = 0x8 } } },
699099918dSPeng Xiao                            { { { .code_and_extra = 0x0a2, .length2 = 0x8 } } },
709099918dSPeng Xiao                            { { { .code_and_extra = 0x062, .length2 = 0x8 } } },
719099918dSPeng Xiao                            { { { .code_and_extra = 0x0e2, .length2 = 0x8 } } },
729099918dSPeng Xiao                            { { { .code_and_extra = 0x012, .length2 = 0x8 } } },
739099918dSPeng Xiao                            { { { .code_and_extra = 0x092, .length2 = 0x8 } } },
749099918dSPeng Xiao                            { { { .code_and_extra = 0x052, .length2 = 0x8 } } },
759099918dSPeng Xiao                            { { { .code_and_extra = 0x0d2, .length2 = 0x8 } } },
769099918dSPeng Xiao                            { { { .code_and_extra = 0x032, .length2 = 0x8 } } },
779099918dSPeng Xiao                            { { { .code_and_extra = 0x0b2, .length2 = 0x8 } } },
789099918dSPeng Xiao                            { { { .code_and_extra = 0x072, .length2 = 0x8 } } },
799099918dSPeng Xiao                            { { { .code_and_extra = 0x0f2, .length2 = 0x8 } } },
809099918dSPeng Xiao                            { { { .code_and_extra = 0x00a, .length2 = 0x8 } } },
819099918dSPeng Xiao                            { { { .code_and_extra = 0x08a, .length2 = 0x8 } } },
829099918dSPeng Xiao                            { { { .code_and_extra = 0x04a, .length2 = 0x8 } } },
839099918dSPeng Xiao                            { { { .code_and_extra = 0x0ca, .length2 = 0x8 } } },
849099918dSPeng Xiao                            { { { .code_and_extra = 0x02a, .length2 = 0x8 } } },
859099918dSPeng Xiao                            { { { .code_and_extra = 0x0aa, .length2 = 0x8 } } },
869099918dSPeng Xiao                            { { { .code_and_extra = 0x06a, .length2 = 0x8 } } },
879099918dSPeng Xiao                            { { { .code_and_extra = 0x0ea, .length2 = 0x8 } } },
889099918dSPeng Xiao                            { { { .code_and_extra = 0x01a, .length2 = 0x8 } } },
899099918dSPeng Xiao                            { { { .code_and_extra = 0x09a, .length2 = 0x8 } } },
909099918dSPeng Xiao                            { { { .code_and_extra = 0x05a, .length2 = 0x8 } } },
919099918dSPeng Xiao                            { { { .code_and_extra = 0x0da, .length2 = 0x8 } } },
929099918dSPeng Xiao                            { { { .code_and_extra = 0x03a, .length2 = 0x8 } } },
939099918dSPeng Xiao                            { { { .code_and_extra = 0x0ba, .length2 = 0x8 } } },
949099918dSPeng Xiao                            { { { .code_and_extra = 0x07a, .length2 = 0x8 } } },
959099918dSPeng Xiao                            { { { .code_and_extra = 0x0fa, .length2 = 0x8 } } },
969099918dSPeng Xiao                            { { { .code_and_extra = 0x006, .length2 = 0x8 } } },
979099918dSPeng Xiao                            { { { .code_and_extra = 0x086, .length2 = 0x8 } } },
989099918dSPeng Xiao                            { { { .code_and_extra = 0x046, .length2 = 0x8 } } },
999099918dSPeng Xiao                            { { { .code_and_extra = 0x0c6, .length2 = 0x8 } } },
1009099918dSPeng Xiao                            { { { .code_and_extra = 0x026, .length2 = 0x8 } } },
1019099918dSPeng Xiao                            { { { .code_and_extra = 0x0a6, .length2 = 0x8 } } },
1029099918dSPeng Xiao                            { { { .code_and_extra = 0x066, .length2 = 0x8 } } },
1039099918dSPeng Xiao                            { { { .code_and_extra = 0x0e6, .length2 = 0x8 } } },
1049099918dSPeng Xiao                            { { { .code_and_extra = 0x016, .length2 = 0x8 } } },
1059099918dSPeng Xiao                            { { { .code_and_extra = 0x096, .length2 = 0x8 } } },
1069099918dSPeng Xiao                            { { { .code_and_extra = 0x056, .length2 = 0x8 } } },
1079099918dSPeng Xiao                            { { { .code_and_extra = 0x0d6, .length2 = 0x8 } } },
1089099918dSPeng Xiao                            { { { .code_and_extra = 0x036, .length2 = 0x8 } } },
1099099918dSPeng Xiao                            { { { .code_and_extra = 0x0b6, .length2 = 0x8 } } },
1109099918dSPeng Xiao                            { { { .code_and_extra = 0x076, .length2 = 0x8 } } },
1119099918dSPeng Xiao                            { { { .code_and_extra = 0x0f6, .length2 = 0x8 } } },
1129099918dSPeng Xiao                            { { { .code_and_extra = 0x00e, .length2 = 0x8 } } },
1139099918dSPeng Xiao                            { { { .code_and_extra = 0x08e, .length2 = 0x8 } } },
1149099918dSPeng Xiao                            { { { .code_and_extra = 0x04e, .length2 = 0x8 } } },
1159099918dSPeng Xiao                            { { { .code_and_extra = 0x0ce, .length2 = 0x8 } } },
1169099918dSPeng Xiao                            { { { .code_and_extra = 0x02e, .length2 = 0x8 } } },
1179099918dSPeng Xiao                            { { { .code_and_extra = 0x0ae, .length2 = 0x8 } } },
1189099918dSPeng Xiao                            { { { .code_and_extra = 0x06e, .length2 = 0x8 } } },
1199099918dSPeng Xiao                            { { { .code_and_extra = 0x0ee, .length2 = 0x8 } } },
1209099918dSPeng Xiao                            { { { .code_and_extra = 0x01e, .length2 = 0x8 } } },
1219099918dSPeng Xiao                            { { { .code_and_extra = 0x09e, .length2 = 0x8 } } },
1229099918dSPeng Xiao                            { { { .code_and_extra = 0x05e, .length2 = 0x8 } } },
1239099918dSPeng Xiao                            { { { .code_and_extra = 0x0de, .length2 = 0x8 } } },
1249099918dSPeng Xiao                            { { { .code_and_extra = 0x03e, .length2 = 0x8 } } },
1259099918dSPeng Xiao                            { { { .code_and_extra = 0x0be, .length2 = 0x8 } } },
1269099918dSPeng Xiao                            { { { .code_and_extra = 0x07e, .length2 = 0x8 } } },
1279099918dSPeng Xiao                            { { { .code_and_extra = 0x0fe, .length2 = 0x8 } } },
1289099918dSPeng Xiao                            { { { .code_and_extra = 0x001, .length2 = 0x8 } } },
1299099918dSPeng Xiao                            { { { .code_and_extra = 0x081, .length2 = 0x8 } } },
1309099918dSPeng Xiao                            { { { .code_and_extra = 0x041, .length2 = 0x8 } } },
1319099918dSPeng Xiao                            { { { .code_and_extra = 0x0c1, .length2 = 0x8 } } },
1329099918dSPeng Xiao                            { { { .code_and_extra = 0x021, .length2 = 0x8 } } },
1339099918dSPeng Xiao                            { { { .code_and_extra = 0x0a1, .length2 = 0x8 } } },
1349099918dSPeng Xiao                            { { { .code_and_extra = 0x061, .length2 = 0x8 } } },
1359099918dSPeng Xiao                            { { { .code_and_extra = 0x0e1, .length2 = 0x8 } } },
1369099918dSPeng Xiao                            { { { .code_and_extra = 0x011, .length2 = 0x8 } } },
1379099918dSPeng Xiao                            { { { .code_and_extra = 0x091, .length2 = 0x8 } } },
1389099918dSPeng Xiao                            { { { .code_and_extra = 0x051, .length2 = 0x8 } } },
1399099918dSPeng Xiao                            { { { .code_and_extra = 0x0d1, .length2 = 0x8 } } },
1409099918dSPeng Xiao                            { { { .code_and_extra = 0x031, .length2 = 0x8 } } },
1419099918dSPeng Xiao                            { { { .code_and_extra = 0x0b1, .length2 = 0x8 } } },
1429099918dSPeng Xiao                            { { { .code_and_extra = 0x071, .length2 = 0x8 } } },
1439099918dSPeng Xiao                            { { { .code_and_extra = 0x0f1, .length2 = 0x8 } } },
1449099918dSPeng Xiao                            { { { .code_and_extra = 0x009, .length2 = 0x8 } } },
1459099918dSPeng Xiao                            { { { .code_and_extra = 0x089, .length2 = 0x8 } } },
1469099918dSPeng Xiao                            { { { .code_and_extra = 0x049, .length2 = 0x8 } } },
1479099918dSPeng Xiao                            { { { .code_and_extra = 0x0c9, .length2 = 0x8 } } },
1489099918dSPeng Xiao                            { { { .code_and_extra = 0x029, .length2 = 0x8 } } },
1499099918dSPeng Xiao                            { { { .code_and_extra = 0x0a9, .length2 = 0x8 } } },
1509099918dSPeng Xiao                            { { { .code_and_extra = 0x069, .length2 = 0x8 } } },
1519099918dSPeng Xiao                            { { { .code_and_extra = 0x0e9, .length2 = 0x8 } } },
1529099918dSPeng Xiao                            { { { .code_and_extra = 0x019, .length2 = 0x8 } } },
1539099918dSPeng Xiao                            { { { .code_and_extra = 0x099, .length2 = 0x8 } } },
1549099918dSPeng Xiao                            { { { .code_and_extra = 0x059, .length2 = 0x8 } } },
1559099918dSPeng Xiao                            { { { .code_and_extra = 0x0d9, .length2 = 0x8 } } },
1569099918dSPeng Xiao                            { { { .code_and_extra = 0x039, .length2 = 0x8 } } },
1579099918dSPeng Xiao                            { { { .code_and_extra = 0x0b9, .length2 = 0x8 } } },
1589099918dSPeng Xiao                            { { { .code_and_extra = 0x079, .length2 = 0x8 } } },
1599099918dSPeng Xiao                            { { { .code_and_extra = 0x0f9, .length2 = 0x8 } } },
1609099918dSPeng Xiao                            { { { .code_and_extra = 0x005, .length2 = 0x8 } } },
1619099918dSPeng Xiao                            { { { .code_and_extra = 0x085, .length2 = 0x8 } } },
1629099918dSPeng Xiao                            { { { .code_and_extra = 0x045, .length2 = 0x8 } } },
1639099918dSPeng Xiao                            { { { .code_and_extra = 0x0c5, .length2 = 0x8 } } },
1649099918dSPeng Xiao                            { { { .code_and_extra = 0x025, .length2 = 0x8 } } },
1659099918dSPeng Xiao                            { { { .code_and_extra = 0x0a5, .length2 = 0x8 } } },
1669099918dSPeng Xiao                            { { { .code_and_extra = 0x065, .length2 = 0x8 } } },
1679099918dSPeng Xiao                            { { { .code_and_extra = 0x0e5, .length2 = 0x8 } } },
1689099918dSPeng Xiao                            { { { .code_and_extra = 0x015, .length2 = 0x8 } } },
1699099918dSPeng Xiao                            { { { .code_and_extra = 0x095, .length2 = 0x8 } } },
1709099918dSPeng Xiao                            { { { .code_and_extra = 0x055, .length2 = 0x8 } } },
1719099918dSPeng Xiao                            { { { .code_and_extra = 0x0d5, .length2 = 0x8 } } },
1729099918dSPeng Xiao                            { { { .code_and_extra = 0x035, .length2 = 0x8 } } },
1739099918dSPeng Xiao                            { { { .code_and_extra = 0x0b5, .length2 = 0x8 } } },
1749099918dSPeng Xiao                            { { { .code_and_extra = 0x075, .length2 = 0x8 } } },
1759099918dSPeng Xiao                            { { { .code_and_extra = 0x0f5, .length2 = 0x8 } } },
1769099918dSPeng Xiao                            { { { .code_and_extra = 0x00d, .length2 = 0x8 } } },
1779099918dSPeng Xiao                            { { { .code_and_extra = 0x08d, .length2 = 0x8 } } },
1789099918dSPeng Xiao                            { { { .code_and_extra = 0x04d, .length2 = 0x8 } } },
1799099918dSPeng Xiao                            { { { .code_and_extra = 0x0cd, .length2 = 0x8 } } },
1809099918dSPeng Xiao                            { { { .code_and_extra = 0x02d, .length2 = 0x8 } } },
1819099918dSPeng Xiao                            { { { .code_and_extra = 0x0ad, .length2 = 0x8 } } },
1829099918dSPeng Xiao                            { { { .code_and_extra = 0x06d, .length2 = 0x8 } } },
1839099918dSPeng Xiao                            { { { .code_and_extra = 0x0ed, .length2 = 0x8 } } },
1849099918dSPeng Xiao                            { { { .code_and_extra = 0x01d, .length2 = 0x8 } } },
1859099918dSPeng Xiao                            { { { .code_and_extra = 0x09d, .length2 = 0x8 } } },
1869099918dSPeng Xiao                            { { { .code_and_extra = 0x05d, .length2 = 0x8 } } },
1879099918dSPeng Xiao                            { { { .code_and_extra = 0x0dd, .length2 = 0x8 } } },
1889099918dSPeng Xiao                            { { { .code_and_extra = 0x03d, .length2 = 0x8 } } },
1899099918dSPeng Xiao                            { { { .code_and_extra = 0x0bd, .length2 = 0x8 } } },
1909099918dSPeng Xiao                            { { { .code_and_extra = 0x07d, .length2 = 0x8 } } },
1919099918dSPeng Xiao                            { { { .code_and_extra = 0x0fd, .length2 = 0x8 } } },
1929099918dSPeng Xiao                            { { { .code_and_extra = 0x013, .length2 = 0x9 } } },
1939099918dSPeng Xiao                            { { { .code_and_extra = 0x113, .length2 = 0x9 } } },
1949099918dSPeng Xiao                            { { { .code_and_extra = 0x093, .length2 = 0x9 } } },
1959099918dSPeng Xiao                            { { { .code_and_extra = 0x193, .length2 = 0x9 } } },
1969099918dSPeng Xiao                            { { { .code_and_extra = 0x053, .length2 = 0x9 } } },
1979099918dSPeng Xiao                            { { { .code_and_extra = 0x153, .length2 = 0x9 } } },
1989099918dSPeng Xiao                            { { { .code_and_extra = 0x0d3, .length2 = 0x9 } } },
1999099918dSPeng Xiao                            { { { .code_and_extra = 0x1d3, .length2 = 0x9 } } },
2009099918dSPeng Xiao                            { { { .code_and_extra = 0x033, .length2 = 0x9 } } },
2019099918dSPeng Xiao                            { { { .code_and_extra = 0x133, .length2 = 0x9 } } },
2029099918dSPeng Xiao                            { { { .code_and_extra = 0x0b3, .length2 = 0x9 } } },
2039099918dSPeng Xiao                            { { { .code_and_extra = 0x1b3, .length2 = 0x9 } } },
2049099918dSPeng Xiao                            { { { .code_and_extra = 0x073, .length2 = 0x9 } } },
2059099918dSPeng Xiao                            { { { .code_and_extra = 0x173, .length2 = 0x9 } } },
2069099918dSPeng Xiao                            { { { .code_and_extra = 0x0f3, .length2 = 0x9 } } },
2079099918dSPeng Xiao                            { { { .code_and_extra = 0x1f3, .length2 = 0x9 } } },
2089099918dSPeng Xiao                            { { { .code_and_extra = 0x00b, .length2 = 0x9 } } },
2099099918dSPeng Xiao                            { { { .code_and_extra = 0x10b, .length2 = 0x9 } } },
2109099918dSPeng Xiao                            { { { .code_and_extra = 0x08b, .length2 = 0x9 } } },
2119099918dSPeng Xiao                            { { { .code_and_extra = 0x18b, .length2 = 0x9 } } },
2129099918dSPeng Xiao                            { { { .code_and_extra = 0x04b, .length2 = 0x9 } } },
2139099918dSPeng Xiao                            { { { .code_and_extra = 0x14b, .length2 = 0x9 } } },
2149099918dSPeng Xiao                            { { { .code_and_extra = 0x0cb, .length2 = 0x9 } } },
2159099918dSPeng Xiao                            { { { .code_and_extra = 0x1cb, .length2 = 0x9 } } },
2169099918dSPeng Xiao                            { { { .code_and_extra = 0x02b, .length2 = 0x9 } } },
2179099918dSPeng Xiao                            { { { .code_and_extra = 0x12b, .length2 = 0x9 } } },
2189099918dSPeng Xiao                            { { { .code_and_extra = 0x0ab, .length2 = 0x9 } } },
2199099918dSPeng Xiao                            { { { .code_and_extra = 0x1ab, .length2 = 0x9 } } },
2209099918dSPeng Xiao                            { { { .code_and_extra = 0x06b, .length2 = 0x9 } } },
2219099918dSPeng Xiao                            { { { .code_and_extra = 0x16b, .length2 = 0x9 } } },
2229099918dSPeng Xiao                            { { { .code_and_extra = 0x0eb, .length2 = 0x9 } } },
2239099918dSPeng Xiao                            { { { .code_and_extra = 0x1eb, .length2 = 0x9 } } },
2249099918dSPeng Xiao                            { { { .code_and_extra = 0x01b, .length2 = 0x9 } } },
2259099918dSPeng Xiao                            { { { .code_and_extra = 0x11b, .length2 = 0x9 } } },
2269099918dSPeng Xiao                            { { { .code_and_extra = 0x09b, .length2 = 0x9 } } },
2279099918dSPeng Xiao                            { { { .code_and_extra = 0x19b, .length2 = 0x9 } } },
2289099918dSPeng Xiao                            { { { .code_and_extra = 0x05b, .length2 = 0x9 } } },
2299099918dSPeng Xiao                            { { { .code_and_extra = 0x15b, .length2 = 0x9 } } },
2309099918dSPeng Xiao                            { { { .code_and_extra = 0x0db, .length2 = 0x9 } } },
2319099918dSPeng Xiao                            { { { .code_and_extra = 0x1db, .length2 = 0x9 } } },
2329099918dSPeng Xiao                            { { { .code_and_extra = 0x03b, .length2 = 0x9 } } },
2339099918dSPeng Xiao                            { { { .code_and_extra = 0x13b, .length2 = 0x9 } } },
2349099918dSPeng Xiao                            { { { .code_and_extra = 0x0bb, .length2 = 0x9 } } },
2359099918dSPeng Xiao                            { { { .code_and_extra = 0x1bb, .length2 = 0x9 } } },
2369099918dSPeng Xiao                            { { { .code_and_extra = 0x07b, .length2 = 0x9 } } },
2379099918dSPeng Xiao                            { { { .code_and_extra = 0x17b, .length2 = 0x9 } } },
2389099918dSPeng Xiao                            { { { .code_and_extra = 0x0fb, .length2 = 0x9 } } },
2399099918dSPeng Xiao                            { { { .code_and_extra = 0x1fb, .length2 = 0x9 } } },
2409099918dSPeng Xiao                            { { { .code_and_extra = 0x007, .length2 = 0x9 } } },
2419099918dSPeng Xiao                            { { { .code_and_extra = 0x107, .length2 = 0x9 } } },
2429099918dSPeng Xiao                            { { { .code_and_extra = 0x087, .length2 = 0x9 } } },
2439099918dSPeng Xiao                            { { { .code_and_extra = 0x187, .length2 = 0x9 } } },
2449099918dSPeng Xiao                            { { { .code_and_extra = 0x047, .length2 = 0x9 } } },
2459099918dSPeng Xiao                            { { { .code_and_extra = 0x147, .length2 = 0x9 } } },
2469099918dSPeng Xiao                            { { { .code_and_extra = 0x0c7, .length2 = 0x9 } } },
2479099918dSPeng Xiao                            { { { .code_and_extra = 0x1c7, .length2 = 0x9 } } },
2489099918dSPeng Xiao                            { { { .code_and_extra = 0x027, .length2 = 0x9 } } },
2499099918dSPeng Xiao                            { { { .code_and_extra = 0x127, .length2 = 0x9 } } },
2509099918dSPeng Xiao                            { { { .code_and_extra = 0x0a7, .length2 = 0x9 } } },
2519099918dSPeng Xiao                            { { { .code_and_extra = 0x1a7, .length2 = 0x9 } } },
2529099918dSPeng Xiao                            { { { .code_and_extra = 0x067, .length2 = 0x9 } } },
2539099918dSPeng Xiao                            { { { .code_and_extra = 0x167, .length2 = 0x9 } } },
2549099918dSPeng Xiao                            { { { .code_and_extra = 0x0e7, .length2 = 0x9 } } },
2559099918dSPeng Xiao                            { { { .code_and_extra = 0x1e7, .length2 = 0x9 } } },
2569099918dSPeng Xiao                            { { { .code_and_extra = 0x017, .length2 = 0x9 } } },
2579099918dSPeng Xiao                            { { { .code_and_extra = 0x117, .length2 = 0x9 } } },
2589099918dSPeng Xiao                            { { { .code_and_extra = 0x097, .length2 = 0x9 } } },
2599099918dSPeng Xiao                            { { { .code_and_extra = 0x197, .length2 = 0x9 } } },
2609099918dSPeng Xiao                            { { { .code_and_extra = 0x057, .length2 = 0x9 } } },
2619099918dSPeng Xiao                            { { { .code_and_extra = 0x157, .length2 = 0x9 } } },
2629099918dSPeng Xiao                            { { { .code_and_extra = 0x0d7, .length2 = 0x9 } } },
2639099918dSPeng Xiao                            { { { .code_and_extra = 0x1d7, .length2 = 0x9 } } },
2649099918dSPeng Xiao                            { { { .code_and_extra = 0x037, .length2 = 0x9 } } },
2659099918dSPeng Xiao                            { { { .code_and_extra = 0x137, .length2 = 0x9 } } },
2669099918dSPeng Xiao                            { { { .code_and_extra = 0x0b7, .length2 = 0x9 } } },
2679099918dSPeng Xiao                            { { { .code_and_extra = 0x1b7, .length2 = 0x9 } } },
2689099918dSPeng Xiao                            { { { .code_and_extra = 0x077, .length2 = 0x9 } } },
2699099918dSPeng Xiao                            { { { .code_and_extra = 0x177, .length2 = 0x9 } } },
2709099918dSPeng Xiao                            { { { .code_and_extra = 0x0f7, .length2 = 0x9 } } },
2719099918dSPeng Xiao                            { { { .code_and_extra = 0x1f7, .length2 = 0x9 } } },
2729099918dSPeng Xiao                            { { { .code_and_extra = 0x00f, .length2 = 0x9 } } },
2739099918dSPeng Xiao                            { { { .code_and_extra = 0x10f, .length2 = 0x9 } } },
2749099918dSPeng Xiao                            { { { .code_and_extra = 0x08f, .length2 = 0x9 } } },
2759099918dSPeng Xiao                            { { { .code_and_extra = 0x18f, .length2 = 0x9 } } },
2769099918dSPeng Xiao                            { { { .code_and_extra = 0x04f, .length2 = 0x9 } } },
2779099918dSPeng Xiao                            { { { .code_and_extra = 0x14f, .length2 = 0x9 } } },
2789099918dSPeng Xiao                            { { { .code_and_extra = 0x0cf, .length2 = 0x9 } } },
2799099918dSPeng Xiao                            { { { .code_and_extra = 0x1cf, .length2 = 0x9 } } },
2809099918dSPeng Xiao                            { { { .code_and_extra = 0x02f, .length2 = 0x9 } } },
2819099918dSPeng Xiao                            { { { .code_and_extra = 0x12f, .length2 = 0x9 } } },
2829099918dSPeng Xiao                            { { { .code_and_extra = 0x0af, .length2 = 0x9 } } },
2839099918dSPeng Xiao                            { { { .code_and_extra = 0x1af, .length2 = 0x9 } } },
2849099918dSPeng Xiao                            { { { .code_and_extra = 0x06f, .length2 = 0x9 } } },
2859099918dSPeng Xiao                            { { { .code_and_extra = 0x16f, .length2 = 0x9 } } },
2869099918dSPeng Xiao                            { { { .code_and_extra = 0x0ef, .length2 = 0x9 } } },
2879099918dSPeng Xiao                            { { { .code_and_extra = 0x1ef, .length2 = 0x9 } } },
2889099918dSPeng Xiao                            { { { .code_and_extra = 0x01f, .length2 = 0x9 } } },
2899099918dSPeng Xiao                            { { { .code_and_extra = 0x11f, .length2 = 0x9 } } },
2909099918dSPeng Xiao                            { { { .code_and_extra = 0x09f, .length2 = 0x9 } } },
2919099918dSPeng Xiao                            { { { .code_and_extra = 0x19f, .length2 = 0x9 } } },
2929099918dSPeng Xiao                            { { { .code_and_extra = 0x05f, .length2 = 0x9 } } },
2939099918dSPeng Xiao                            { { { .code_and_extra = 0x15f, .length2 = 0x9 } } },
2949099918dSPeng Xiao                            { { { .code_and_extra = 0x0df, .length2 = 0x9 } } },
2959099918dSPeng Xiao                            { { { .code_and_extra = 0x1df, .length2 = 0x9 } } },
2969099918dSPeng Xiao                            { { { .code_and_extra = 0x03f, .length2 = 0x9 } } },
2979099918dSPeng Xiao                            { { { .code_and_extra = 0x13f, .length2 = 0x9 } } },
2989099918dSPeng Xiao                            { { { .code_and_extra = 0x0bf, .length2 = 0x9 } } },
2999099918dSPeng Xiao                            { { { .code_and_extra = 0x1bf, .length2 = 0x9 } } },
3009099918dSPeng Xiao                            { { { .code_and_extra = 0x07f, .length2 = 0x9 } } },
3019099918dSPeng Xiao                            { { { .code_and_extra = 0x17f, .length2 = 0x9 } } },
3029099918dSPeng Xiao                            { { { .code_and_extra = 0x0ff, .length2 = 0x9 } } },
3039099918dSPeng Xiao                            { { { .code_and_extra = 0x1ff, .length2 = 0x9 } } },
3049099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x7 } } },
3059099918dSPeng Xiao                            { { { .code_and_extra = 0x040, .length2 = 0x7 } } },
3069099918dSPeng Xiao                            { { { .code_and_extra = 0x020, .length2 = 0x7 } } },
3079099918dSPeng Xiao                            { { { .code_and_extra = 0x060, .length2 = 0x7 } } },
3089099918dSPeng Xiao                            { { { .code_and_extra = 0x010, .length2 = 0x7 } } },
3099099918dSPeng Xiao                            { { { .code_and_extra = 0x050, .length2 = 0x7 } } },
3109099918dSPeng Xiao                            { { { .code_and_extra = 0x030, .length2 = 0x7 } } },
3119099918dSPeng Xiao                            { { { .code_and_extra = 0x070, .length2 = 0x7 } } },
3129099918dSPeng Xiao                            { { { .code_and_extra = 0x008, .length2 = 0x7 } } },
3139099918dSPeng Xiao                            { { { .code_and_extra = 0x048, .length2 = 0x7 } } },
3149099918dSPeng Xiao                            { { { .code_and_extra = 0x028, .length2 = 0x7 } } },
3159099918dSPeng Xiao                            { { { .code_and_extra = 0x068, .length2 = 0x7 } } },
3169099918dSPeng Xiao                            { { { .code_and_extra = 0x018, .length2 = 0x7 } } },
3179099918dSPeng Xiao                            { { { .code_and_extra = 0x058, .length2 = 0x7 } } },
3189099918dSPeng Xiao                            { { { .code_and_extra = 0x038, .length2 = 0x7 } } },
3199099918dSPeng Xiao                            { { { .code_and_extra = 0x078, .length2 = 0x7 } } },
3209099918dSPeng Xiao                            { { { .code_and_extra = 0x004, .length2 = 0x7 } } },
3219099918dSPeng Xiao                            { { { .code_and_extra = 0x044, .length2 = 0x7 } } },
3229099918dSPeng Xiao                            { { { .code_and_extra = 0x024, .length2 = 0x7 } } },
3239099918dSPeng Xiao                            { { { .code_and_extra = 0x064, .length2 = 0x7 } } },
3249099918dSPeng Xiao                            { { { .code_and_extra = 0x014, .length2 = 0x7 } } },
3259099918dSPeng Xiao                            { { { .code_and_extra = 0x054, .length2 = 0x7 } } },
3269099918dSPeng Xiao                            { { { .code_and_extra = 0x034, .length2 = 0x7 } } },
3279099918dSPeng Xiao                            { { { .code_and_extra = 0x074, .length2 = 0x7 } } },
3289099918dSPeng Xiao                            { { { .code_and_extra = 0x003, .length2 = 0x8 } } },
3299099918dSPeng Xiao                            { { { .code_and_extra = 0x083, .length2 = 0x8 } } },
3309099918dSPeng Xiao                            { { { .code_and_extra = 0x043, .length2 = 0x8 } } },
3319099918dSPeng Xiao                            { { { .code_and_extra = 0x0c3, .length2 = 0x8 } } },
3329099918dSPeng Xiao                            { { { .code_and_extra = 0x023, .length2 = 0x8 } } },
3339099918dSPeng Xiao                            { { { .code_and_extra = 0x0a3, .length2 = 0x8 } } },
3349099918dSPeng Xiao                            { { { .code_and_extra = 0x063, .length2 = 0x8 } } },
3359099918dSPeng Xiao                            { { { .code_and_extra = 0x0e3, .length2 = 0x8 } } },
3369099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3379099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3389099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3399099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3409099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3419099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3429099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3439099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3449099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3459099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3469099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3479099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3489099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3499099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3509099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3519099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3529099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3539099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3549099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3559099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3569099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3579099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3589099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3599099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3609099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3619099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3629099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3639099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3649099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3659099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3669099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3679099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3689099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3699099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3709099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3719099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3729099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3739099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3749099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3759099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3769099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3779099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3789099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3799099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3809099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3819099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3829099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3839099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3849099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3859099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3869099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3879099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3889099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3899099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3909099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3919099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3929099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3939099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3949099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3959099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3969099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3979099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3989099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
3999099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4009099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4019099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4029099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4039099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4049099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4059099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4069099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4079099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4089099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4099099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4109099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4119099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4129099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4139099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4149099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4159099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4169099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4179099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4189099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4199099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4209099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4219099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4229099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4239099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4249099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4259099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4269099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4279099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4289099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4299099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4309099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4319099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4329099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4339099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4349099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4359099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4369099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4379099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4389099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4399099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4409099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4419099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4429099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4439099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4449099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4459099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4469099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4479099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4489099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4499099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4509099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4519099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4529099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4539099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4549099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4559099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4569099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4579099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4589099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4599099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4609099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4619099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4629099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4639099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4649099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4659099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4669099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4679099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4689099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4699099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4709099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4719099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4729099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4739099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4749099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4759099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4769099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4779099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4789099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4799099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4809099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4819099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4829099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4839099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4849099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4859099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4869099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4879099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4889099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4899099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4909099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4919099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4929099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4939099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4949099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4959099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4969099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4979099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4989099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
4999099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5009099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5019099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5029099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5039099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5049099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5059099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5069099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5079099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5089099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5099099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5109099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5119099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5129099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5139099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5149099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5159099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5169099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5179099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5189099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5199099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5209099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5219099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5229099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5239099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5249099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5259099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5269099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5279099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5289099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5299099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5309099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5319099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5329099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5339099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5349099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5359099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5369099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5379099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5389099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5399099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5409099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5419099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5429099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5439099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5449099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5459099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5469099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5479099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5489099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5499099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5509099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5519099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5529099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5539099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5549099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5559099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5569099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5579099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5589099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5599099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } },
5609099918dSPeng Xiao                            { { { .code_and_extra = 0x000, .length2 = 0x0 } } } },
561*55fbfabfSMarcel Cornu         .dist_table = { { { { .code_and_extra = 0x000, .length2 = 0x5 } } },
5629099918dSPeng Xiao                         { { { .code_and_extra = 0x010, .length2 = 0x5 } } },
5639099918dSPeng Xiao                         { { { .code_and_extra = 0x008, .length2 = 0x5 } } },
5649099918dSPeng Xiao                         { { { .code_and_extra = 0x018, .length2 = 0x5 } } },
5659099918dSPeng Xiao                         { { { .code_and_extra = 0x10004, .length2 = 0x5 } } },
5669099918dSPeng Xiao                         { { { .code_and_extra = 0x10014, .length2 = 0x5 } } },
5679099918dSPeng Xiao                         { { { .code_and_extra = 0x2000c, .length2 = 0x5 } } },
5689099918dSPeng Xiao                         { { { .code_and_extra = 0x2001c, .length2 = 0x5 } } },
5699099918dSPeng Xiao                         { { { .code_and_extra = 0x30002, .length2 = 0x5 } } },
5709099918dSPeng Xiao                         { { { .code_and_extra = 0x30012, .length2 = 0x5 } } },
5719099918dSPeng Xiao                         { { { .code_and_extra = 0x4000a, .length2 = 0x5 } } },
5729099918dSPeng Xiao                         { { { .code_and_extra = 0x4001a, .length2 = 0x5 } } },
5739099918dSPeng Xiao                         { { { .code_and_extra = 0x50006, .length2 = 0x5 } } },
5749099918dSPeng Xiao                         { { { .code_and_extra = 0x50016, .length2 = 0x5 } } },
5759099918dSPeng Xiao                         { { { .code_and_extra = 0x6000e, .length2 = 0x5 } } },
5769099918dSPeng Xiao                         { { { .code_and_extra = 0x6001e, .length2 = 0x5 } } },
5779099918dSPeng Xiao                         { { { .code_and_extra = 0x70001, .length2 = 0x5 } } },
5789099918dSPeng Xiao                         { { { .code_and_extra = 0x70011, .length2 = 0x5 } } },
5799099918dSPeng Xiao                         { { { .code_and_extra = 0x80009, .length2 = 0x5 } } },
5809099918dSPeng Xiao                         { { { .code_and_extra = 0x80019, .length2 = 0x5 } } },
5819099918dSPeng Xiao                         { { { .code_and_extra = 0x90005, .length2 = 0x5 } } },
5829099918dSPeng Xiao                         { { { .code_and_extra = 0x90015, .length2 = 0x5 } } },
5839099918dSPeng Xiao                         { { { .code_and_extra = 0xa000d, .length2 = 0x5 } } },
5849099918dSPeng Xiao                         { { { .code_and_extra = 0xa001d, .length2 = 0x5 } } },
5859099918dSPeng Xiao                         { { { .code_and_extra = 0xb0003, .length2 = 0x5 } } },
5869099918dSPeng Xiao                         { { { .code_and_extra = 0xb0013, .length2 = 0x5 } } },
5879099918dSPeng Xiao                         { { { .code_and_extra = 0xc000b, .length2 = 0x5 } } },
5889099918dSPeng Xiao                         { { { .code_and_extra = 0xc001b, .length2 = 0x5 } } },
5899099918dSPeng Xiao                         { { { .code_and_extra = 0xd0007, .length2 = 0x5 } } },
5909099918dSPeng Xiao                         { { { .code_and_extra = 0xd0017, .length2 = 0x5 } } },
5919099918dSPeng Xiao                         { { { .code_and_extra = 0x000, .length2 = 0x0 } } } }
5929992cc19SRoy Oursler };
5939992cc19SRoy Oursler 
594*55fbfabfSMarcel Cornu extern uint32_t
595*55fbfabfSMarcel Cornu build_huff_tree(struct heap_tree *heap, uint64_t heap_size, uint64_t node_ptr);
596*55fbfabfSMarcel Cornu extern void
597*55fbfabfSMarcel Cornu build_heap(uint64_t *heap, uint64_t heap_size);
59801dfbcc4SRoy Oursler 
599*55fbfabfSMarcel Cornu static uint32_t
600*55fbfabfSMarcel Cornu convert_dist_to_dist_sym(uint32_t dist);
601*55fbfabfSMarcel Cornu static uint32_t
602*55fbfabfSMarcel Cornu convert_length_to_len_sym(uint32_t length);
603bcde6e41SDaniel Verkamp 
60401dfbcc4SRoy Oursler static const uint8_t bitrev8[0x100] = {
605*55fbfabfSMarcel Cornu         0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70,
606*55fbfabfSMarcel Cornu         0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8,
607*55fbfabfSMarcel Cornu         0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34,
608*55fbfabfSMarcel Cornu         0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
609*55fbfabfSMarcel Cornu         0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52,
610*55fbfabfSMarcel Cornu         0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A,
611*55fbfabfSMarcel Cornu         0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16,
612*55fbfabfSMarcel Cornu         0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
613*55fbfabfSMarcel Cornu         0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61,
614*55fbfabfSMarcel Cornu         0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9,
615*55fbfabfSMarcel Cornu         0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25,
616*55fbfabfSMarcel Cornu         0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
617*55fbfabfSMarcel Cornu         0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43,
618*55fbfabfSMarcel Cornu         0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B,
619*55fbfabfSMarcel Cornu         0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07,
620*55fbfabfSMarcel Cornu         0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
621*55fbfabfSMarcel Cornu         0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F,
622*55fbfabfSMarcel Cornu         0xFF
62301dfbcc4SRoy Oursler };
62401dfbcc4SRoy Oursler 
62501dfbcc4SRoy Oursler // bit reverse low order LENGTH bits in code, and return result in low order bits
626*55fbfabfSMarcel Cornu static inline uint16_t
bit_reverse(uint16_t code,uint32_t length)627*55fbfabfSMarcel Cornu bit_reverse(uint16_t code, uint32_t length)
628660f49b0SGreg Tucker {
62901dfbcc4SRoy Oursler         code = (bitrev8[code & 0x00FF] << 8) | (bitrev8[code >> 8]);
63001dfbcc4SRoy Oursler         return (code >> (16 - length));
631660f49b0SGreg Tucker }
632660f49b0SGreg Tucker 
633*55fbfabfSMarcel Cornu void
isal_update_histogram_base(uint8_t * start_stream,int length,struct isal_huff_histogram * histogram)634*55fbfabfSMarcel Cornu isal_update_histogram_base(uint8_t *start_stream, int length, struct isal_huff_histogram *histogram)
635660f49b0SGreg Tucker {
636660f49b0SGreg Tucker         uint32_t literal = 0, hash;
6378fe5cbeeSRoy Oursler         uint16_t seen, *last_seen = histogram->hash_table;
6388fe5cbeeSRoy Oursler         uint8_t *current, *end_stream, *next_hash, *end;
639660f49b0SGreg Tucker         uint32_t match_length;
640660f49b0SGreg Tucker         uint32_t dist;
641660f49b0SGreg Tucker         uint64_t *lit_len_histogram = histogram->lit_len_histogram;
642660f49b0SGreg Tucker         uint64_t *dist_histogram = histogram->dist_histogram;
643660f49b0SGreg Tucker 
644660f49b0SGreg Tucker         if (length <= 0)
645660f49b0SGreg Tucker                 return;
646660f49b0SGreg Tucker 
647660f49b0SGreg Tucker         end_stream = start_stream + length;
6488fe5cbeeSRoy Oursler         memset(last_seen, 0, sizeof(histogram->hash_table)); /* Initialize last_seen to be 0. */
649660f49b0SGreg Tucker         for (current = start_stream; current < end_stream - 3; current++) {
650d3cfb2fbSIlya Leoshkevich                 literal = load_le_u32(current);
6514ae2d1beSRoy Oursler                 hash = compute_hash(literal) & LVL0_HASH_MASK;
652660f49b0SGreg Tucker                 seen = last_seen[hash];
653c28be0d3SGreg Tucker                 last_seen[hash] = (current - start_stream) & 0xFFFF;
654c28be0d3SGreg Tucker                 dist = (current - start_stream - seen) & 0xFFFF;
6558fe5cbeeSRoy Oursler                 if (dist - 1 < D - 1) {
656d4c6067dSRoy Oursler                         assert(start_stream <= current - dist);
657*55fbfabfSMarcel Cornu                         match_length = compare258(current - dist, current, end_stream - current);
658660f49b0SGreg Tucker                         if (match_length >= SHORTEST_MATCH) {
659660f49b0SGreg Tucker                                 next_hash = current;
66088f95d85SRoy Oursler #ifdef ISAL_LIMIT_HASH_UPDATE
661660f49b0SGreg Tucker                                 end = next_hash + 3;
662660f49b0SGreg Tucker #else
663660f49b0SGreg Tucker                                 end = next_hash + match_length;
664660f49b0SGreg Tucker #endif
665660f49b0SGreg Tucker                                 if (end > end_stream - 3)
666660f49b0SGreg Tucker                                         end = end_stream - 3;
667660f49b0SGreg Tucker                                 next_hash++;
668660f49b0SGreg Tucker                                 for (; next_hash < end; next_hash++) {
669d3cfb2fbSIlya Leoshkevich                                         literal = load_le_u32(next_hash);
6704ae2d1beSRoy Oursler                                         hash = compute_hash(literal) & LVL0_HASH_MASK;
671c28be0d3SGreg Tucker                                         last_seen[hash] = (next_hash - start_stream) & 0xFFFF;
672660f49b0SGreg Tucker                                 }
673660f49b0SGreg Tucker 
674660f49b0SGreg Tucker                                 dist_histogram[convert_dist_to_dist_sym(dist)] += 1;
675*55fbfabfSMarcel Cornu                                 lit_len_histogram[convert_length_to_len_sym(match_length)] += 1;
676660f49b0SGreg Tucker                                 current += match_length - 1;
677660f49b0SGreg Tucker                                 continue;
678660f49b0SGreg Tucker                         }
679660f49b0SGreg Tucker                 }
680660f49b0SGreg Tucker                 lit_len_histogram[literal & 0xFF] += 1;
681660f49b0SGreg Tucker         }
682e8ca21baSRoy Oursler 
683e8ca21baSRoy Oursler         for (; current < end_stream; current++)
684e8ca21baSRoy Oursler                 lit_len_histogram[*current] += 1;
685e8ca21baSRoy Oursler 
686660f49b0SGreg Tucker         lit_len_histogram[256] += 1;
687660f49b0SGreg Tucker         return;
688660f49b0SGreg Tucker }
689660f49b0SGreg Tucker 
690bcde6e41SDaniel Verkamp /**
691bcde6e41SDaniel Verkamp  * @brief  Returns the deflate symbol value for a look back distance.
692bcde6e41SDaniel Verkamp  */
693*55fbfabfSMarcel Cornu static uint32_t
convert_dist_to_dist_sym(uint32_t dist)694*55fbfabfSMarcel Cornu convert_dist_to_dist_sym(uint32_t dist)
695660f49b0SGreg Tucker {
696660f49b0SGreg Tucker         assert(dist <= 32768 && dist > 0);
697b721db98SJun He         if (dist <= 32768) {
698b721db98SJun He                 uint32_t msb = dist > 4 ? bsr(dist - 1) - 2 : 0;
699b721db98SJun He                 return (msb * 2) + ((dist - 1) >> msb);
700b721db98SJun He         } else {
701b721db98SJun He                 return ~0;
702b721db98SJun He         }
703660f49b0SGreg Tucker }
704660f49b0SGreg Tucker 
705bcde6e41SDaniel Verkamp /**
706bcde6e41SDaniel Verkamp  * @brief  Returns the deflate symbol value for a repeat length.
707bcde6e41SDaniel Verkamp  */
708*55fbfabfSMarcel Cornu static uint32_t
convert_length_to_len_sym(uint32_t length)709*55fbfabfSMarcel Cornu convert_length_to_len_sym(uint32_t length)
710660f49b0SGreg Tucker {
711660f49b0SGreg Tucker         assert(length > 2 && length < 259);
712660f49b0SGreg Tucker 
713660f49b0SGreg Tucker         /* Based on tables on page 11 in RFC 1951 */
714660f49b0SGreg Tucker         if (length < 11)
715660f49b0SGreg Tucker                 return 257 + length - 3;
716660f49b0SGreg Tucker         else if (length < 19)
717660f49b0SGreg Tucker                 return 261 + (length - 3) / 2;
718660f49b0SGreg Tucker         else if (length < 35)
719660f49b0SGreg Tucker                 return 265 + (length - 3) / 4;
720660f49b0SGreg Tucker         else if (length < 67)
721660f49b0SGreg Tucker                 return 269 + (length - 3) / 8;
722660f49b0SGreg Tucker         else if (length < 131)
723660f49b0SGreg Tucker                 return 273 + (length - 3) / 16;
724660f49b0SGreg Tucker         else if (length < 258)
725660f49b0SGreg Tucker                 return 277 + (length - 3) / 32;
726660f49b0SGreg Tucker         else
727660f49b0SGreg Tucker                 return 285;
728660f49b0SGreg Tucker }
729660f49b0SGreg Tucker 
73001dfbcc4SRoy Oursler // Upon return, codes[] contains the code lengths,
73101dfbcc4SRoy Oursler // and bl_count is the count of the lengths
73201dfbcc4SRoy Oursler 
73301dfbcc4SRoy Oursler /* Init heap with the histogram, and return the histogram size */
734*55fbfabfSMarcel Cornu static inline uint32_t
init_heap32(struct heap_tree * heap_space,uint32_t * histogram,uint32_t hist_size)735*55fbfabfSMarcel Cornu init_heap32(struct heap_tree *heap_space, uint32_t *histogram, uint32_t hist_size)
736660f49b0SGreg Tucker {
73701dfbcc4SRoy Oursler         uint32_t heap_size, i;
738660f49b0SGreg Tucker 
73901dfbcc4SRoy Oursler         memset(heap_space, 0, sizeof(struct heap_tree));
740660f49b0SGreg Tucker 
74101dfbcc4SRoy Oursler         heap_size = 0;
74201dfbcc4SRoy Oursler         for (i = 0; i < hist_size; i++) {
74301dfbcc4SRoy Oursler                 if (histogram[i] != 0)
74401dfbcc4SRoy Oursler                         heap_space->heap[++heap_size] =
74501dfbcc4SRoy Oursler                                 (((uint64_t) histogram[i]) << FREQ_SHIFT) | i;
746660f49b0SGreg Tucker         }
747660f49b0SGreg Tucker 
74801dfbcc4SRoy Oursler         // make sure heap has at least two elements in it
74901dfbcc4SRoy Oursler         if (heap_size < 2) {
75001dfbcc4SRoy Oursler                 if (heap_size == 0) {
75101dfbcc4SRoy Oursler                         heap_space->heap[1] = 1ULL << FREQ_SHIFT;
75201dfbcc4SRoy Oursler                         heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
75301dfbcc4SRoy Oursler                         heap_size = 2;
754660f49b0SGreg Tucker                 } else {
75501dfbcc4SRoy Oursler                         // heap size == 1
75601dfbcc4SRoy Oursler                         if (histogram[0] == 0)
75701dfbcc4SRoy Oursler                                 heap_space->heap[2] = 1ULL << FREQ_SHIFT;
758660f49b0SGreg Tucker                         else
75901dfbcc4SRoy Oursler                                 heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
76001dfbcc4SRoy Oursler                         heap_size = 2;
76101dfbcc4SRoy Oursler                 }
762660f49b0SGreg Tucker         }
763660f49b0SGreg Tucker 
764f80a1ed6SRoy Oursler         build_heap(heap_space->heap, heap_size);
76501dfbcc4SRoy Oursler 
76601dfbcc4SRoy Oursler         return heap_size;
767660f49b0SGreg Tucker }
768660f49b0SGreg Tucker 
769*55fbfabfSMarcel Cornu static inline uint32_t
init_heap64(struct heap_tree * heap_space,uint64_t * histogram,uint64_t hist_size)770*55fbfabfSMarcel Cornu init_heap64(struct heap_tree *heap_space, uint64_t *histogram, uint64_t hist_size)
771660f49b0SGreg Tucker {
77201dfbcc4SRoy Oursler         uint32_t heap_size, i;
77301dfbcc4SRoy Oursler 
77401dfbcc4SRoy Oursler         memset(heap_space, 0, sizeof(struct heap_tree));
77501dfbcc4SRoy Oursler 
77601dfbcc4SRoy Oursler         heap_size = 0;
77701dfbcc4SRoy Oursler         for (i = 0; i < hist_size; i++) {
77801dfbcc4SRoy Oursler                 if (histogram[i] != 0)
77901dfbcc4SRoy Oursler                         heap_space->heap[++heap_size] = ((histogram[i]) << FREQ_SHIFT) | i;
780660f49b0SGreg Tucker         }
781660f49b0SGreg Tucker 
78201dfbcc4SRoy Oursler         // make sure heap has at least two elements in it
78301dfbcc4SRoy Oursler         if (heap_size < 2) {
78401dfbcc4SRoy Oursler                 if (heap_size == 0) {
78501dfbcc4SRoy Oursler                         heap_space->heap[1] = 1ULL << FREQ_SHIFT;
78601dfbcc4SRoy Oursler                         heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
78701dfbcc4SRoy Oursler                         heap_size = 2;
78801dfbcc4SRoy Oursler                 } else {
78901dfbcc4SRoy Oursler                         // heap size == 1
79001dfbcc4SRoy Oursler                         if (histogram[0] == 0)
79101dfbcc4SRoy Oursler                                 heap_space->heap[2] = 1ULL << FREQ_SHIFT;
79201dfbcc4SRoy Oursler                         else
79301dfbcc4SRoy Oursler                                 heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
79401dfbcc4SRoy Oursler                         heap_size = 2;
79501dfbcc4SRoy Oursler                 }
79601dfbcc4SRoy Oursler         }
79701dfbcc4SRoy Oursler 
798f80a1ed6SRoy Oursler         build_heap(heap_space->heap, heap_size);
79901dfbcc4SRoy Oursler 
80001dfbcc4SRoy Oursler         return heap_size;
80101dfbcc4SRoy Oursler }
80201dfbcc4SRoy Oursler 
803*55fbfabfSMarcel Cornu static inline uint32_t
init_heap64_semi_complete(struct heap_tree * heap_space,uint64_t * histogram,uint64_t hist_size,uint64_t complete_start)804*55fbfabfSMarcel Cornu init_heap64_semi_complete(struct heap_tree *heap_space, uint64_t *histogram, uint64_t hist_size,
805e79c57c7SRoy Oursler                           uint64_t complete_start)
806e79c57c7SRoy Oursler {
807e79c57c7SRoy Oursler         uint32_t heap_size, i;
808e79c57c7SRoy Oursler 
809e79c57c7SRoy Oursler         memset(heap_space, 0, sizeof(struct heap_tree));
810e79c57c7SRoy Oursler 
811e79c57c7SRoy Oursler         heap_size = 0;
812e79c57c7SRoy Oursler         for (i = 0; i < complete_start; i++) {
813e79c57c7SRoy Oursler                 if (histogram[i] != 0)
814e79c57c7SRoy Oursler                         heap_space->heap[++heap_size] = ((histogram[i]) << FREQ_SHIFT) | i;
815e79c57c7SRoy Oursler         }
816e79c57c7SRoy Oursler 
817e79c57c7SRoy Oursler         for (; i < hist_size; i++)
818e79c57c7SRoy Oursler                 heap_space->heap[++heap_size] = ((histogram[i]) << FREQ_SHIFT) | i;
819e79c57c7SRoy Oursler 
820e79c57c7SRoy Oursler         // make sure heap has at least two elements in it
821e79c57c7SRoy Oursler         if (heap_size < 2) {
822e79c57c7SRoy Oursler                 if (heap_size == 0) {
823e79c57c7SRoy Oursler                         heap_space->heap[1] = 1ULL << FREQ_SHIFT;
824e79c57c7SRoy Oursler                         heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
825e79c57c7SRoy Oursler                         heap_size = 2;
826e79c57c7SRoy Oursler                 } else {
827e79c57c7SRoy Oursler                         // heap size == 1
828e79c57c7SRoy Oursler                         if (histogram[0] == 0)
829e79c57c7SRoy Oursler                                 heap_space->heap[2] = 1ULL << FREQ_SHIFT;
830e79c57c7SRoy Oursler                         else
831e79c57c7SRoy Oursler                                 heap_space->heap[2] = (1ULL << FREQ_SHIFT) | 1;
832e79c57c7SRoy Oursler                         heap_size = 2;
833e79c57c7SRoy Oursler                 }
834e79c57c7SRoy Oursler         }
835e79c57c7SRoy Oursler 
836e79c57c7SRoy Oursler         build_heap(heap_space->heap, heap_size);
837e79c57c7SRoy Oursler 
838e79c57c7SRoy Oursler         return heap_size;
839e79c57c7SRoy Oursler }
840e79c57c7SRoy Oursler 
841*55fbfabfSMarcel Cornu static inline uint32_t
init_heap64_complete(struct heap_tree * heap_space,uint64_t * histogram,uint64_t hist_size)842*55fbfabfSMarcel Cornu init_heap64_complete(struct heap_tree *heap_space, uint64_t *histogram, uint64_t hist_size)
84301dfbcc4SRoy Oursler {
84401dfbcc4SRoy Oursler         uint32_t heap_size, i;
84501dfbcc4SRoy Oursler 
84601dfbcc4SRoy Oursler         memset(heap_space, 0, sizeof(struct heap_tree));
84701dfbcc4SRoy Oursler 
84801dfbcc4SRoy Oursler         heap_size = 0;
84901dfbcc4SRoy Oursler         for (i = 0; i < hist_size; i++)
85001dfbcc4SRoy Oursler                 heap_space->heap[++heap_size] = ((histogram[i]) << FREQ_SHIFT) | i;
85101dfbcc4SRoy Oursler 
852f80a1ed6SRoy Oursler         build_heap(heap_space->heap, heap_size);
85301dfbcc4SRoy Oursler 
85401dfbcc4SRoy Oursler         return heap_size;
85501dfbcc4SRoy Oursler }
85601dfbcc4SRoy Oursler 
857*55fbfabfSMarcel Cornu static inline uint32_t
fix_code_lens(struct heap_tree * heap_space,uint32_t root_node,uint32_t * bl_count,uint32_t max_code_len)858*55fbfabfSMarcel Cornu fix_code_lens(struct heap_tree *heap_space, uint32_t root_node, uint32_t *bl_count,
859*55fbfabfSMarcel Cornu               uint32_t max_code_len)
86001dfbcc4SRoy Oursler {
86101dfbcc4SRoy Oursler         struct tree_node *tree = heap_space->tree;
86201dfbcc4SRoy Oursler         uint64_t *code_len_count = heap_space->code_len_count;
86301dfbcc4SRoy Oursler         uint32_t i, j, k, child, depth, code_len;
86401dfbcc4SRoy Oursler 
86501dfbcc4SRoy Oursler         // compute code lengths and code length counts
86601dfbcc4SRoy Oursler         code_len = 0;
86701dfbcc4SRoy Oursler         j = root_node;
86801dfbcc4SRoy Oursler         for (i = root_node; i <= HEAP_TREE_NODE_START; i++) {
86901dfbcc4SRoy Oursler                 child = tree[i].child;
87001dfbcc4SRoy Oursler                 if (child > MAX_HISTHEAP_SIZE) {
87101dfbcc4SRoy Oursler                         depth = 1 + tree[i].depth;
87201dfbcc4SRoy Oursler 
87301dfbcc4SRoy Oursler                         tree[child].depth = depth;
87401dfbcc4SRoy Oursler                         tree[child - 1].depth = depth;
87501dfbcc4SRoy Oursler                 } else {
87601dfbcc4SRoy Oursler                         tree[j++] = tree[i];
87701dfbcc4SRoy Oursler                         depth = tree[i].depth;
87801dfbcc4SRoy Oursler                         while (code_len < depth) {
87901dfbcc4SRoy Oursler                                 code_len++;
88001dfbcc4SRoy Oursler                                 code_len_count[code_len] = 0;
88101dfbcc4SRoy Oursler                         }
88201dfbcc4SRoy Oursler                         code_len_count[depth]++;
88301dfbcc4SRoy Oursler                 }
88401dfbcc4SRoy Oursler         }
88501dfbcc4SRoy Oursler 
88601dfbcc4SRoy Oursler         if (code_len > max_code_len) {
88701dfbcc4SRoy Oursler                 while (code_len > max_code_len) {
88801dfbcc4SRoy Oursler                         assert(code_len_count[code_len] > 1);
88901dfbcc4SRoy Oursler                         for (i = max_code_len - 1; i != 0; i--)
89001dfbcc4SRoy Oursler                                 if (code_len_count[i] != 0)
89101dfbcc4SRoy Oursler                                         break;
89201dfbcc4SRoy Oursler                         assert(i != 0);
89301dfbcc4SRoy Oursler                         code_len_count[i]--;
89401dfbcc4SRoy Oursler                         code_len_count[i + 1] += 2;
89501dfbcc4SRoy Oursler                         code_len_count[code_len - 1]++;
89601dfbcc4SRoy Oursler                         code_len_count[code_len] -= 2;
89701dfbcc4SRoy Oursler                         if (code_len_count[code_len] == 0)
89801dfbcc4SRoy Oursler                                 code_len--;
89901dfbcc4SRoy Oursler                 }
90001dfbcc4SRoy Oursler 
90147348345SRoy Oursler                 bl_count[0] = 0;
90201dfbcc4SRoy Oursler                 for (i = 1; i <= code_len; i++)
90301dfbcc4SRoy Oursler                         bl_count[i] = code_len_count[i];
90401dfbcc4SRoy Oursler                 for (; i <= max_code_len; i++)
90501dfbcc4SRoy Oursler                         bl_count[i] = 0;
90601dfbcc4SRoy Oursler 
907*55fbfabfSMarcel Cornu                 for (k = 1; code_len_count[k] == 0; k++)
908*55fbfabfSMarcel Cornu                         ;
90901dfbcc4SRoy Oursler                 for (i = root_node; i < j; i++) {
91001dfbcc4SRoy Oursler                         tree[i].depth = k;
91101dfbcc4SRoy Oursler                         code_len_count[k]--;
912*55fbfabfSMarcel Cornu                         for (; code_len_count[k] == 0; k++)
913*55fbfabfSMarcel Cornu                                 ;
91401dfbcc4SRoy Oursler                 }
91501dfbcc4SRoy Oursler         } else {
91647348345SRoy Oursler                 bl_count[0] = 0;
91701dfbcc4SRoy Oursler                 for (i = 1; i <= code_len; i++)
91801dfbcc4SRoy Oursler                         bl_count[i] = code_len_count[i];
91901dfbcc4SRoy Oursler                 for (; i <= max_code_len; i++)
92001dfbcc4SRoy Oursler                         bl_count[i] = 0;
92101dfbcc4SRoy Oursler         }
92201dfbcc4SRoy Oursler 
92301dfbcc4SRoy Oursler         return j;
92401dfbcc4SRoy Oursler }
92501dfbcc4SRoy Oursler 
92601dfbcc4SRoy Oursler static inline void
gen_huff_code_lens(struct heap_tree * heap_space,uint32_t heap_size,uint32_t * bl_count,struct huff_code * codes,uint32_t codes_count,uint32_t max_code_len)92701dfbcc4SRoy Oursler gen_huff_code_lens(struct heap_tree *heap_space, uint32_t heap_size, uint32_t *bl_count,
92801dfbcc4SRoy Oursler                    struct huff_code *codes, uint32_t codes_count, uint32_t max_code_len)
92901dfbcc4SRoy Oursler {
93001dfbcc4SRoy Oursler         struct tree_node *tree = heap_space->tree;
93101dfbcc4SRoy Oursler         uint32_t root_node = HEAP_TREE_NODE_START, node_ptr;
93201dfbcc4SRoy Oursler         uint32_t end_node;
93301dfbcc4SRoy Oursler 
93401dfbcc4SRoy Oursler         root_node = build_huff_tree(heap_space, heap_size, root_node);
93501dfbcc4SRoy Oursler 
93601dfbcc4SRoy Oursler         end_node = fix_code_lens(heap_space, root_node, bl_count, max_code_len);
93701dfbcc4SRoy Oursler 
93801dfbcc4SRoy Oursler         memset(codes, 0, codes_count * sizeof(*codes));
93901dfbcc4SRoy Oursler         for (node_ptr = root_node; node_ptr < end_node; node_ptr++)
94001dfbcc4SRoy Oursler                 codes[tree[node_ptr].child].length = tree[node_ptr].depth;
94101dfbcc4SRoy Oursler }
94201dfbcc4SRoy Oursler 
943bcde6e41SDaniel Verkamp /**
944bcde6e41SDaniel Verkamp  * @brief Determines the code each element of a deflate compliant huffman tree and stores
945bcde6e41SDaniel Verkamp  * it in a lookup table
946bcde6e41SDaniel Verkamp  * @requires table has been initialized to already contain the code length for each element.
947bcde6e41SDaniel Verkamp  * @param table: A lookup table used to store the codes.
948bcde6e41SDaniel Verkamp  * @param table_length: The length of table.
9491500db75SColin Ian King  * @param count: a histogram representing the number of occurrences of codes of a given length
950bcde6e41SDaniel Verkamp  */
951*55fbfabfSMarcel Cornu static inline uint32_t
set_huff_codes(struct huff_code * huff_code_table,int table_length,uint32_t * count)952*55fbfabfSMarcel Cornu set_huff_codes(struct huff_code *huff_code_table, int table_length, uint32_t *count)
953660f49b0SGreg Tucker {
954660f49b0SGreg Tucker         /* Uses the algorithm mentioned in the deflate standard, Rfc 1951. */
955660f49b0SGreg Tucker         int i;
956660f49b0SGreg Tucker         uint16_t code = 0;
957660f49b0SGreg Tucker         uint16_t next_code[MAX_HUFF_TREE_DEPTH + 1];
95801dfbcc4SRoy Oursler         uint32_t max_code = 0;
959660f49b0SGreg Tucker 
960660f49b0SGreg Tucker         next_code[0] = code;
961660f49b0SGreg Tucker 
962660f49b0SGreg Tucker         for (i = 1; i < MAX_HUFF_TREE_DEPTH + 1; i++)
963660f49b0SGreg Tucker                 next_code[i] = (next_code[i - 1] + count[i - 1]) << 1;
964660f49b0SGreg Tucker 
965660f49b0SGreg Tucker         for (i = 0; i < table_length; i++) {
966660f49b0SGreg Tucker                 if (huff_code_table[i].length != 0) {
967*55fbfabfSMarcel Cornu                         huff_code_table[i].code = bit_reverse(next_code[huff_code_table[i].length],
968660f49b0SGreg Tucker                                                               huff_code_table[i].length);
969660f49b0SGreg Tucker                         next_code[huff_code_table[i].length] += 1;
97001dfbcc4SRoy Oursler                         max_code = i;
971660f49b0SGreg Tucker                 }
972660f49b0SGreg Tucker         }
973660f49b0SGreg Tucker 
97401dfbcc4SRoy Oursler         return max_code;
975660f49b0SGreg Tucker }
976660f49b0SGreg Tucker 
97701dfbcc4SRoy Oursler // on input, codes contain the code lengths
97801dfbcc4SRoy Oursler // on output, code contains:
97901dfbcc4SRoy Oursler // 23:16 code length
98001dfbcc4SRoy Oursler // 15:0  code value in low order bits
98101dfbcc4SRoy Oursler // returns max code value
982*55fbfabfSMarcel Cornu static inline uint32_t
set_dist_huff_codes(struct huff_code * codes,uint32_t * bl_count)983*55fbfabfSMarcel Cornu set_dist_huff_codes(struct huff_code *codes, uint32_t *bl_count)
98401dfbcc4SRoy Oursler {
98501dfbcc4SRoy Oursler         uint32_t code, code_len, bits, i;
98601dfbcc4SRoy Oursler         uint32_t next_code[MAX_DEFLATE_CODE_LEN + 1];
98701dfbcc4SRoy Oursler         uint32_t max_code = 0;
98801dfbcc4SRoy Oursler         const uint32_t num_codes = DIST_LEN;
98901dfbcc4SRoy Oursler 
99001dfbcc4SRoy Oursler         code = bl_count[0] = 0;
99101dfbcc4SRoy Oursler         for (bits = 1; bits <= MAX_HUFF_TREE_DEPTH; bits++) {
99201dfbcc4SRoy Oursler                 code = (code + bl_count[bits - 1]) << 1;
99301dfbcc4SRoy Oursler                 next_code[bits] = code;
99401dfbcc4SRoy Oursler         }
99501dfbcc4SRoy Oursler         for (i = 0; i < num_codes; i++) {
99601dfbcc4SRoy Oursler                 code_len = codes[i].length;
99701dfbcc4SRoy Oursler                 if (code_len != 0) {
99801dfbcc4SRoy Oursler                         codes[i].code = bit_reverse(next_code[code_len], code_len);
9999992cc19SRoy Oursler                         codes[i].extra_bit_count = dist_code_extra_bits[i];
100001dfbcc4SRoy Oursler                         next_code[code_len] += 1;
100101dfbcc4SRoy Oursler                         max_code = i;
100201dfbcc4SRoy Oursler                 }
100301dfbcc4SRoy Oursler         }
100401dfbcc4SRoy Oursler         return max_code;
100501dfbcc4SRoy Oursler }
100601dfbcc4SRoy Oursler 
1007bcde6e41SDaniel Verkamp /**
1008bcde6e41SDaniel Verkamp  * @brief Creates the header for run length encoded huffman trees.
1009bcde6e41SDaniel Verkamp  * @param header: the output header.
1010bcde6e41SDaniel Verkamp  * @param lookup_table: a huffman lookup table.
1011bcde6e41SDaniel Verkamp  * @param huffman_rep: a run length encoded huffman tree.
1012bcde6e41SDaniel Verkamp  * @extra_bits: extra bits associated with the corresponding spot in huffman_rep
1013bcde6e41SDaniel Verkamp  * @param huffman_rep_length: the length of huffman_rep.
1014bcde6e41SDaniel Verkamp  * @param end_of_block: Value determining whether end of block header is produced or not;
1015bcde6e41SDaniel Verkamp  * 0 corresponds to not end of block and all other inputs correspond to end of block.
1016bcde6e41SDaniel Verkamp  * @param hclen: Length of huffman code for huffman codes minus 4.
1017bcde6e41SDaniel Verkamp  * @param hlit: Length of literal/length table minus 257.
10181500db75SColin Ian King  * @param hdist: Length of distance table minus 1.
1019bcde6e41SDaniel Verkamp  */
1020*55fbfabfSMarcel Cornu static int
create_huffman_header(struct BitBuf2 * header_bitbuf,struct huff_code * lookup_table,struct rl_code * huffman_rep,uint16_t huffman_rep_length,uint32_t end_of_block,uint32_t hclen,uint32_t hlit,uint32_t hdist)1021*55fbfabfSMarcel Cornu create_huffman_header(struct BitBuf2 *header_bitbuf, struct huff_code *lookup_table,
1022*55fbfabfSMarcel Cornu                       struct rl_code *huffman_rep, uint16_t huffman_rep_length,
1023*55fbfabfSMarcel Cornu                       uint32_t end_of_block, uint32_t hclen, uint32_t hlit, uint32_t hdist)
102401dfbcc4SRoy Oursler {
102501dfbcc4SRoy Oursler         /* hlit, hdist, hclen are as defined in the deflate standard, head is the
102601dfbcc4SRoy Oursler          * first three deflate header bits.*/
102701dfbcc4SRoy Oursler         int i;
102801dfbcc4SRoy Oursler         uint64_t bit_count;
102901dfbcc4SRoy Oursler         uint64_t data;
103001dfbcc4SRoy Oursler         struct huff_code huffman_value;
103101dfbcc4SRoy Oursler         const uint32_t extra_bits[3] = { 2, 3, 7 };
103201dfbcc4SRoy Oursler 
103301dfbcc4SRoy Oursler         bit_count = buffer_bits_used(header_bitbuf);
103401dfbcc4SRoy Oursler 
103501dfbcc4SRoy Oursler         data = (end_of_block ? 5 : 4) | (hlit << 3) | (hdist << 8) | (hclen << 13);
103601dfbcc4SRoy Oursler         data |= ((lookup_table[code_length_code_order[0]].length) << DYN_HDR_START_LEN);
103701dfbcc4SRoy Oursler         write_bits(header_bitbuf, data, DYN_HDR_START_LEN + 3);
103801dfbcc4SRoy Oursler         data = 0;
103901dfbcc4SRoy Oursler         for (i = hclen + 3; i >= 1; i--)
104001dfbcc4SRoy Oursler                 data = (data << 3) | lookup_table[code_length_code_order[i]].length;
104101dfbcc4SRoy Oursler 
104201dfbcc4SRoy Oursler         write_bits(header_bitbuf, data, (hclen + 3) * 3);
104301dfbcc4SRoy Oursler 
104401dfbcc4SRoy Oursler         for (i = 0; i < huffman_rep_length; i++) {
104501dfbcc4SRoy Oursler                 huffman_value = lookup_table[huffman_rep[i].code];
104601dfbcc4SRoy Oursler 
104701dfbcc4SRoy Oursler                 write_bits(header_bitbuf, (uint64_t) huffman_value.code,
104801dfbcc4SRoy Oursler                            (uint32_t) huffman_value.length);
104901dfbcc4SRoy Oursler 
105001dfbcc4SRoy Oursler                 if (huffman_rep[i].code > 15) {
105101dfbcc4SRoy Oursler                         write_bits(header_bitbuf, (uint64_t) huffman_rep[i].extra_bits,
105201dfbcc4SRoy Oursler                                    (uint32_t) extra_bits[huffman_rep[i].code - 16]);
105301dfbcc4SRoy Oursler                 }
105401dfbcc4SRoy Oursler         }
105501dfbcc4SRoy Oursler         bit_count = buffer_bits_used(header_bitbuf) - bit_count;
105601dfbcc4SRoy Oursler 
105701dfbcc4SRoy Oursler         return bit_count;
105801dfbcc4SRoy Oursler }
105901dfbcc4SRoy Oursler 
1060bcde6e41SDaniel Verkamp /**
1061bcde6e41SDaniel Verkamp  * @brief Creates the dynamic huffman deflate header.
1062bcde6e41SDaniel Verkamp  * @returns Returns the  length of header in bits.
1063bcde6e41SDaniel Verkamp  * @requires This function requires header is large enough to store the whole header.
1064bcde6e41SDaniel Verkamp  * @param header: The output header.
1065bcde6e41SDaniel Verkamp  * @param lit_huff_table: A literal/length code huffman lookup table.\
1066bcde6e41SDaniel Verkamp  * @param dist_huff_table: A distance huffman code lookup table.
1067bcde6e41SDaniel Verkamp  * @param end_of_block: Value determining whether end of block header is produced or not;
1068bcde6e41SDaniel Verkamp  * 0 corresponds to not end of block and all other inputs correspond to end of block.
1069bcde6e41SDaniel Verkamp  */
1070*55fbfabfSMarcel Cornu static inline int
create_header(struct BitBuf2 * header_bitbuf,struct rl_code * huffman_rep,uint32_t length,uint64_t * histogram,uint32_t hlit,uint32_t hdist,uint32_t end_of_block)1071*55fbfabfSMarcel Cornu create_header(struct BitBuf2 *header_bitbuf, struct rl_code *huffman_rep, uint32_t length,
1072*55fbfabfSMarcel Cornu               uint64_t *histogram, uint32_t hlit, uint32_t hdist, uint32_t end_of_block)
1073660f49b0SGreg Tucker {
1074660f49b0SGreg Tucker         int i;
107501dfbcc4SRoy Oursler 
107601dfbcc4SRoy Oursler         uint32_t heap_size;
107701dfbcc4SRoy Oursler         struct heap_tree heap_space;
107801dfbcc4SRoy Oursler         uint32_t code_len_count[MAX_HUFF_TREE_DEPTH + 1];
1079660f49b0SGreg Tucker         struct huff_code lookup_table[HUFF_LEN];
1080660f49b0SGreg Tucker 
1081660f49b0SGreg Tucker         /* hlit, hdist, and hclen are defined in RFC 1951 page 13 */
108201dfbcc4SRoy Oursler         uint32_t hclen;
1083660f49b0SGreg Tucker         uint64_t bit_count;
1084660f49b0SGreg Tucker 
1085660f49b0SGreg Tucker         /* Create a huffman tree to encode run length encoded representation. */
108601dfbcc4SRoy Oursler         heap_size = init_heap64(&heap_space, histogram, HUFF_LEN);
108701dfbcc4SRoy Oursler         gen_huff_code_lens(&heap_space, heap_size, code_len_count,
108801dfbcc4SRoy Oursler                            (struct huff_code *) lookup_table, HUFF_LEN, 7);
108901dfbcc4SRoy Oursler         set_huff_codes(lookup_table, HUFF_LEN, code_len_count);
1090660f49b0SGreg Tucker 
1091660f49b0SGreg Tucker         /* Calculate hclen */
1092660f49b0SGreg Tucker         for (i = CODE_LEN_CODES - 1; i > 3; i--) /* i must be at least 4 */
1093660f49b0SGreg Tucker                 if (lookup_table[code_length_code_order[i]].length != 0)
1094660f49b0SGreg Tucker                         break;
1095660f49b0SGreg Tucker 
1096660f49b0SGreg Tucker         hclen = i - 3;
1097660f49b0SGreg Tucker 
1098660f49b0SGreg Tucker         /* Generate actual header. */
1099*55fbfabfSMarcel Cornu         bit_count = create_huffman_header(header_bitbuf, lookup_table, huffman_rep, length,
1100*55fbfabfSMarcel Cornu                                           end_of_block, hclen, hlit, hdist);
1101660f49b0SGreg Tucker 
1102660f49b0SGreg Tucker         return bit_count;
1103660f49b0SGreg Tucker }
1104660f49b0SGreg Tucker 
1105*55fbfabfSMarcel Cornu static inline struct rl_code *
write_rl(struct rl_code * pout,uint16_t last_len,uint32_t run_len,uint64_t * counts)1106*55fbfabfSMarcel Cornu write_rl(struct rl_code *pout, uint16_t last_len, uint32_t run_len, uint64_t *counts)
1107660f49b0SGreg Tucker {
110801dfbcc4SRoy Oursler         if (last_len == 0) {
110901dfbcc4SRoy Oursler                 while (run_len > 138) {
111001dfbcc4SRoy Oursler                         pout->code = 18;
111101dfbcc4SRoy Oursler                         pout->extra_bits = 138 - 11;
111201dfbcc4SRoy Oursler                         pout++;
111301dfbcc4SRoy Oursler                         run_len -= 138;
111401dfbcc4SRoy Oursler                         counts[18]++;
111501dfbcc4SRoy Oursler                 }
111601dfbcc4SRoy Oursler                 // 1 <= run_len <= 138
111701dfbcc4SRoy Oursler                 if (run_len > 10) {
111801dfbcc4SRoy Oursler                         pout->code = 18;
111901dfbcc4SRoy Oursler                         pout->extra_bits = run_len - 11;
112001dfbcc4SRoy Oursler                         pout++;
112101dfbcc4SRoy Oursler                         counts[18]++;
112201dfbcc4SRoy Oursler                 } else if (run_len > 2) {
112301dfbcc4SRoy Oursler                         pout->code = 17;
112401dfbcc4SRoy Oursler                         pout->extra_bits = run_len - 3;
112501dfbcc4SRoy Oursler                         pout++;
112601dfbcc4SRoy Oursler                         counts[17]++;
112701dfbcc4SRoy Oursler                 } else if (run_len == 1) {
112801dfbcc4SRoy Oursler                         pout->code = 0;
112901dfbcc4SRoy Oursler                         pout->extra_bits = 0;
113001dfbcc4SRoy Oursler                         pout++;
113101dfbcc4SRoy Oursler                         counts[0]++;
113201dfbcc4SRoy Oursler                 } else {
113301dfbcc4SRoy Oursler                         assert(run_len == 2);
113401dfbcc4SRoy Oursler                         pout[0].code = 0;
113501dfbcc4SRoy Oursler                         pout[0].extra_bits = 0;
113601dfbcc4SRoy Oursler                         pout[1].code = 0;
113701dfbcc4SRoy Oursler                         pout[1].extra_bits = 0;
113801dfbcc4SRoy Oursler                         pout += 2;
113901dfbcc4SRoy Oursler                         counts[0] += 2;
114001dfbcc4SRoy Oursler                 }
114101dfbcc4SRoy Oursler         } else {
114201dfbcc4SRoy Oursler                 // last_len != 0
114301dfbcc4SRoy Oursler                 pout->code = last_len;
114401dfbcc4SRoy Oursler                 pout->extra_bits = 0;
114501dfbcc4SRoy Oursler                 pout++;
114601dfbcc4SRoy Oursler                 counts[last_len]++;
114701dfbcc4SRoy Oursler                 run_len--;
114801dfbcc4SRoy Oursler                 if (run_len != 0) {
114901dfbcc4SRoy Oursler                         while (run_len > 6) {
115001dfbcc4SRoy Oursler                                 pout->code = 16;
115101dfbcc4SRoy Oursler                                 pout->extra_bits = 6 - 3;
115201dfbcc4SRoy Oursler                                 pout++;
115301dfbcc4SRoy Oursler                                 run_len -= 6;
115401dfbcc4SRoy Oursler                                 counts[16]++;
115501dfbcc4SRoy Oursler                         }
115601dfbcc4SRoy Oursler                         // 1 <= run_len <= 6
115701dfbcc4SRoy Oursler                         switch (run_len) {
115801dfbcc4SRoy Oursler                         case 1:
115901dfbcc4SRoy Oursler                                 pout->code = last_len;
116001dfbcc4SRoy Oursler                                 pout->extra_bits = 0;
116101dfbcc4SRoy Oursler                                 pout++;
116201dfbcc4SRoy Oursler                                 counts[last_len]++;
116301dfbcc4SRoy Oursler                                 break;
116401dfbcc4SRoy Oursler                         case 2:
116501dfbcc4SRoy Oursler                                 pout[0].code = last_len;
116601dfbcc4SRoy Oursler                                 pout[0].extra_bits = 0;
116701dfbcc4SRoy Oursler                                 pout[1].code = last_len;
116801dfbcc4SRoy Oursler                                 pout[1].extra_bits = 0;
116901dfbcc4SRoy Oursler                                 pout += 2;
117001dfbcc4SRoy Oursler                                 counts[last_len] += 2;
117101dfbcc4SRoy Oursler                                 break;
117201dfbcc4SRoy Oursler                         default: // 3...6
117301dfbcc4SRoy Oursler                                 pout->code = 16;
117401dfbcc4SRoy Oursler                                 pout->extra_bits = run_len - 3;
117501dfbcc4SRoy Oursler                                 pout++;
117601dfbcc4SRoy Oursler                                 counts[16]++;
117701dfbcc4SRoy Oursler                         }
117801dfbcc4SRoy Oursler                 }
117901dfbcc4SRoy Oursler         }
118001dfbcc4SRoy Oursler         return pout;
1181660f49b0SGreg Tucker }
1182660f49b0SGreg Tucker 
118301dfbcc4SRoy Oursler // convert codes into run-length symbols, write symbols into OUT
118401dfbcc4SRoy Oursler // generate histogram into COUNTS (assumed to be initialized to 0)
118501dfbcc4SRoy Oursler // Format of OUT:
118601dfbcc4SRoy Oursler // 4:0  code (0...18)
118701dfbcc4SRoy Oursler // 15:8 Extra bits (0...127)
118801dfbcc4SRoy Oursler // returns number of symbols in out
1189*55fbfabfSMarcel Cornu static inline uint32_t
rl_encode(uint16_t * codes,uint32_t num_codes,uint64_t * counts,struct rl_code * out)1190*55fbfabfSMarcel Cornu rl_encode(uint16_t *codes, uint32_t num_codes, uint64_t *counts, struct rl_code *out)
1191660f49b0SGreg Tucker {
119201dfbcc4SRoy Oursler         uint32_t i, run_len;
119301dfbcc4SRoy Oursler         uint16_t last_len, len;
119401dfbcc4SRoy Oursler         struct rl_code *pout;
1195660f49b0SGreg Tucker 
119601dfbcc4SRoy Oursler         pout = out;
119701dfbcc4SRoy Oursler         last_len = codes[0];
119801dfbcc4SRoy Oursler         run_len = 1;
119901dfbcc4SRoy Oursler         for (i = 1; i < num_codes; i++) {
120001dfbcc4SRoy Oursler                 len = codes[i];
120101dfbcc4SRoy Oursler                 if (len == last_len) {
120201dfbcc4SRoy Oursler                         run_len++;
120301dfbcc4SRoy Oursler                         continue;
1204660f49b0SGreg Tucker                 }
120501dfbcc4SRoy Oursler                 pout = write_rl(pout, last_len, run_len, counts);
120601dfbcc4SRoy Oursler                 last_len = len;
120701dfbcc4SRoy Oursler                 run_len = 1;
1208660f49b0SGreg Tucker         }
120901dfbcc4SRoy Oursler         pout = write_rl(pout, last_len, run_len, counts);
1210660f49b0SGreg Tucker 
121101dfbcc4SRoy Oursler         return (uint32_t) (pout - out);
1212660f49b0SGreg Tucker }
1213660f49b0SGreg Tucker 
1214bcde6e41SDaniel Verkamp /**
1215bcde6e41SDaniel Verkamp  * @brief Creates a two table representation of huffman codes.
1216bcde6e41SDaniel Verkamp  * @param code_table: output table containing the code
1217bcde6e41SDaniel Verkamp  * @param code_size_table: output table containing the code length
12181500db75SColin Ian King  * @param length: the length of hufftable
1219bcde6e41SDaniel Verkamp  * @param hufftable: a huffman lookup table
1220bcde6e41SDaniel Verkamp  */
1221*55fbfabfSMarcel Cornu static void
create_code_tables(uint16_t * code_table,uint8_t * code_length_table,uint32_t length,struct huff_code * hufftable)1222*55fbfabfSMarcel Cornu create_code_tables(uint16_t *code_table, uint8_t *code_length_table, uint32_t length,
1223*55fbfabfSMarcel Cornu                    struct huff_code *hufftable)
1224660f49b0SGreg Tucker {
1225660f49b0SGreg Tucker         int i;
1226660f49b0SGreg Tucker         for (i = 0; i < length; i++) {
1227660f49b0SGreg Tucker                 code_table[i] = hufftable[i].code;
1228660f49b0SGreg Tucker                 code_length_table[i] = hufftable[i].length;
1229660f49b0SGreg Tucker         }
1230660f49b0SGreg Tucker }
1231660f49b0SGreg Tucker 
1232bcde6e41SDaniel Verkamp /**
1233bcde6e41SDaniel Verkamp  * @brief Creates a packed representation of length huffman codes.
1234bcde6e41SDaniel Verkamp  * @details In packed_table, bits 32:8 contain the extra bits appended to the huffman
1235bcde6e41SDaniel Verkamp  * code and bits 8:0 contain the code length.
1236bcde6e41SDaniel Verkamp  * @param packed_table: the output table
1237bcde6e41SDaniel Verkamp  * @param length: the length of lit_len_hufftable
1238bcde6e41SDaniel Verkamp  * @param lit_len_hufftable: a literal/length huffman lookup table
1239bcde6e41SDaniel Verkamp  */
1240*55fbfabfSMarcel Cornu static void
create_packed_len_table(uint32_t * packed_table,struct huff_code * lit_len_hufftable)1241*55fbfabfSMarcel Cornu create_packed_len_table(uint32_t *packed_table, struct huff_code *lit_len_hufftable)
1242660f49b0SGreg Tucker {
1243660f49b0SGreg Tucker         int i, count = 0;
1244660f49b0SGreg Tucker         uint16_t extra_bits;
1245660f49b0SGreg Tucker         uint16_t extra_bits_count = 0;
1246660f49b0SGreg Tucker 
1247660f49b0SGreg Tucker         /* Gain extra bits is the next place where the number of extra bits in
12481500db75SColin Ian King          * length codes increases. */
1249660f49b0SGreg Tucker         uint16_t gain_extra_bits = LEN_EXTRA_BITS_START;
1250660f49b0SGreg Tucker 
1251660f49b0SGreg Tucker         for (i = 257; i < LIT_LEN - 1; i++) {
1252660f49b0SGreg Tucker                 for (extra_bits = 0; extra_bits < (1 << extra_bits_count); extra_bits++) {
1253660f49b0SGreg Tucker                         if (count > 254)
1254660f49b0SGreg Tucker                                 break;
1255660f49b0SGreg Tucker                         packed_table[count++] =
1256660f49b0SGreg Tucker                                 (extra_bits << (lit_len_hufftable[i].length + LENGTH_BITS)) |
1257660f49b0SGreg Tucker                                 (lit_len_hufftable[i].code << LENGTH_BITS) |
1258660f49b0SGreg Tucker                                 (lit_len_hufftable[i].length + extra_bits_count);
1259660f49b0SGreg Tucker                 }
1260660f49b0SGreg Tucker 
1261660f49b0SGreg Tucker                 if (i == gain_extra_bits) {
1262660f49b0SGreg Tucker                         gain_extra_bits += LEN_EXTRA_BITS_INTERVAL;
1263660f49b0SGreg Tucker                         extra_bits_count += 1;
1264660f49b0SGreg Tucker                 }
1265660f49b0SGreg Tucker         }
1266660f49b0SGreg Tucker 
1267660f49b0SGreg Tucker         packed_table[count] = (lit_len_hufftable[LIT_LEN - 1].code << LENGTH_BITS) |
1268660f49b0SGreg Tucker                               (lit_len_hufftable[LIT_LEN - 1].length);
1269660f49b0SGreg Tucker }
1270660f49b0SGreg Tucker 
1271bcde6e41SDaniel Verkamp /**
1272bcde6e41SDaniel Verkamp  * @brief Creates a packed representation of distance  huffman codes.
1273bcde6e41SDaniel Verkamp  * @details In packed_table, bits 32:8 contain the extra bits appended to the huffman
1274bcde6e41SDaniel Verkamp  * code and bits 8:0 contain the code length.
1275bcde6e41SDaniel Verkamp  * @param packed_table: the output table
1276bcde6e41SDaniel Verkamp  * @param length: the length of lit_len_hufftable
1277bcde6e41SDaniel Verkamp  * @param dist_hufftable: a distance huffman lookup table
1278bcde6e41SDaniel Verkamp  */
1279*55fbfabfSMarcel Cornu static void
create_packed_dist_table(uint32_t * packed_table,uint32_t length,struct huff_code * dist_hufftable)1280*55fbfabfSMarcel Cornu create_packed_dist_table(uint32_t *packed_table, uint32_t length, struct huff_code *dist_hufftable)
1281660f49b0SGreg Tucker {
1282660f49b0SGreg Tucker         int i, count = 0;
1283660f49b0SGreg Tucker         uint16_t extra_bits;
1284660f49b0SGreg Tucker         uint16_t extra_bits_count = 0;
1285660f49b0SGreg Tucker 
1286660f49b0SGreg Tucker         /* Gain extra bits is the next place where the number of extra bits in
1287660f49b0SGreg Tucker          * distance codes increases. */
1288660f49b0SGreg Tucker         uint16_t gain_extra_bits = DIST_EXTRA_BITS_START;
1289660f49b0SGreg Tucker 
1290660f49b0SGreg Tucker         for (i = 0; i < DIST_LEN; i++) {
1291660f49b0SGreg Tucker                 for (extra_bits = 0; extra_bits < (1 << extra_bits_count); extra_bits++) {
1292660f49b0SGreg Tucker                         if (count >= length)
1293660f49b0SGreg Tucker                                 return;
1294660f49b0SGreg Tucker 
1295660f49b0SGreg Tucker                         packed_table[count++] =
1296660f49b0SGreg Tucker                                 (extra_bits << (dist_hufftable[i].length + LENGTH_BITS)) |
1297660f49b0SGreg Tucker                                 (dist_hufftable[i].code << LENGTH_BITS) |
1298660f49b0SGreg Tucker                                 (dist_hufftable[i].length + extra_bits_count);
1299660f49b0SGreg Tucker                 }
1300660f49b0SGreg Tucker 
1301660f49b0SGreg Tucker                 if (i == gain_extra_bits) {
1302660f49b0SGreg Tucker                         gain_extra_bits += DIST_EXTRA_BITS_INTERVAL;
1303660f49b0SGreg Tucker                         extra_bits_count += 1;
1304660f49b0SGreg Tucker                 }
1305660f49b0SGreg Tucker         }
1306660f49b0SGreg Tucker }
1307660f49b0SGreg Tucker 
1308bcde6e41SDaniel Verkamp /**
1309bcde6e41SDaniel Verkamp  * @brief Checks to see if the hufftable is usable by igzip
1310bcde6e41SDaniel Verkamp  *
1311bcde6e41SDaniel Verkamp  * @param lit_len_hufftable: literal/length huffman code
1312bcde6e41SDaniel Verkamp  * @param dist_hufftable: distance huffman code
1313bcde6e41SDaniel Verkamp  * @returns Returns 0 if the table is usable
1314bcde6e41SDaniel Verkamp  */
1315*55fbfabfSMarcel Cornu static int
are_hufftables_useable(struct huff_code * lit_len_hufftable,struct huff_code * dist_hufftable)1316*55fbfabfSMarcel Cornu are_hufftables_useable(struct huff_code *lit_len_hufftable, struct huff_code *dist_hufftable)
1317660f49b0SGreg Tucker {
1318660f49b0SGreg Tucker         int max_lit_code_len = 0, max_len_code_len = 0, max_dist_code_len = 0;
1319660f49b0SGreg Tucker         int dist_extra_bits = 0, len_extra_bits = 0;
1320660f49b0SGreg Tucker         int gain_dist_extra_bits = DIST_EXTRA_BITS_START;
1321660f49b0SGreg Tucker         int gain_len_extra_bits = LEN_EXTRA_BITS_START;
1322660f49b0SGreg Tucker         int max_code_len;
1323660f49b0SGreg Tucker         int i;
1324660f49b0SGreg Tucker 
1325660f49b0SGreg Tucker         for (i = 0; i < LIT_LEN; i++)
1326660f49b0SGreg Tucker                 if (lit_len_hufftable[i].length > max_lit_code_len)
1327660f49b0SGreg Tucker                         max_lit_code_len = lit_len_hufftable[i].length;
1328660f49b0SGreg Tucker 
1329660f49b0SGreg Tucker         for (i = 257; i < LIT_LEN - 1; i++) {
1330660f49b0SGreg Tucker                 if (lit_len_hufftable[i].length + len_extra_bits > max_len_code_len)
1331660f49b0SGreg Tucker                         max_len_code_len = lit_len_hufftable[i].length + len_extra_bits;
1332660f49b0SGreg Tucker 
1333660f49b0SGreg Tucker                 if (i == gain_len_extra_bits) {
1334660f49b0SGreg Tucker                         gain_len_extra_bits += LEN_EXTRA_BITS_INTERVAL;
1335660f49b0SGreg Tucker                         len_extra_bits += 1;
1336660f49b0SGreg Tucker                 }
1337660f49b0SGreg Tucker         }
1338660f49b0SGreg Tucker 
1339660f49b0SGreg Tucker         for (i = 0; i < DIST_LEN; i++) {
1340660f49b0SGreg Tucker                 if (dist_hufftable[i].length + dist_extra_bits > max_dist_code_len)
1341660f49b0SGreg Tucker                         max_dist_code_len = dist_hufftable[i].length + dist_extra_bits;
1342660f49b0SGreg Tucker 
1343660f49b0SGreg Tucker                 if (i == gain_dist_extra_bits) {
1344660f49b0SGreg Tucker                         gain_dist_extra_bits += DIST_EXTRA_BITS_INTERVAL;
1345660f49b0SGreg Tucker                         dist_extra_bits += 1;
1346660f49b0SGreg Tucker                 }
1347660f49b0SGreg Tucker         }
1348660f49b0SGreg Tucker 
1349660f49b0SGreg Tucker         max_code_len = max_lit_code_len + max_len_code_len + max_dist_code_len;
1350660f49b0SGreg Tucker 
1351660f49b0SGreg Tucker         /* Some versions of igzip can write up to one literal, one length and one
1352660f49b0SGreg Tucker          * distance code at the same time. This checks to make sure that is
1353660f49b0SGreg Tucker          * always writeable in bitbuf*/
1354660f49b0SGreg Tucker         return (max_code_len > MAX_BITBUF_BIT_WRITE);
1355660f49b0SGreg Tucker }
1356660f49b0SGreg Tucker 
1357*55fbfabfSMarcel Cornu int
isal_create_hufftables(struct isal_hufftables * hufftables,struct isal_huff_histogram * histogram)1358*55fbfabfSMarcel Cornu isal_create_hufftables(struct isal_hufftables *hufftables, struct isal_huff_histogram *histogram)
1359660f49b0SGreg Tucker {
1360660f49b0SGreg Tucker         struct huff_code lit_huff_table[LIT_LEN], dist_huff_table[DIST_LEN];
1361660f49b0SGreg Tucker         uint64_t bit_count;
136288f95d85SRoy Oursler         int max_dist = convert_dist_to_dist_sym(IGZIP_HIST_SIZE);
136301dfbcc4SRoy Oursler         struct heap_tree heap_space;
136401dfbcc4SRoy Oursler         uint32_t heap_size;
136501dfbcc4SRoy Oursler         uint32_t code_len_count[MAX_HUFF_TREE_DEPTH + 1];
136601dfbcc4SRoy Oursler         struct BitBuf2 header_bitbuf;
136701dfbcc4SRoy Oursler         uint32_t max_lit_len_sym;
136801dfbcc4SRoy Oursler         uint32_t max_dist_sym;
136901dfbcc4SRoy Oursler         uint32_t hlit, hdist, i;
137001dfbcc4SRoy Oursler         uint16_t combined_table[LIT_LEN + DIST_LEN];
137101dfbcc4SRoy Oursler         uint64_t count_histogram[HUFF_LEN];
137201dfbcc4SRoy Oursler         struct rl_code rl_huff[LIT_LEN + DIST_LEN];
137301dfbcc4SRoy Oursler         uint32_t rl_huff_len;
1374660f49b0SGreg Tucker 
1375660f49b0SGreg Tucker         uint32_t *dist_table = hufftables->dist_table;
1376660f49b0SGreg Tucker         uint32_t *len_table = hufftables->len_table;
1377660f49b0SGreg Tucker         uint16_t *lit_table = hufftables->lit_table;
1378660f49b0SGreg Tucker         uint16_t *dcodes = hufftables->dcodes;
1379660f49b0SGreg Tucker         uint8_t *lit_table_sizes = hufftables->lit_table_sizes;
1380660f49b0SGreg Tucker         uint8_t *dcodes_sizes = hufftables->dcodes_sizes;
1381660f49b0SGreg Tucker         uint64_t *lit_len_histogram = histogram->lit_len_histogram;
1382660f49b0SGreg Tucker         uint64_t *dist_histogram = histogram->dist_histogram;
1383660f49b0SGreg Tucker 
1384660f49b0SGreg Tucker         memset(hufftables, 0, sizeof(struct isal_hufftables));
1385660f49b0SGreg Tucker 
138601dfbcc4SRoy Oursler         heap_size = init_heap64_complete(&heap_space, lit_len_histogram, LIT_LEN);
138701dfbcc4SRoy Oursler         gen_huff_code_lens(&heap_space, heap_size, code_len_count,
138801dfbcc4SRoy Oursler                            (struct huff_code *) lit_huff_table, LIT_LEN, MAX_DEFLATE_CODE_LEN);
138901dfbcc4SRoy Oursler         max_lit_len_sym = set_huff_codes(lit_huff_table, LIT_LEN, code_len_count);
1390660f49b0SGreg Tucker 
139101dfbcc4SRoy Oursler         heap_size = init_heap64_complete(&heap_space, dist_histogram, DIST_LEN);
139201dfbcc4SRoy Oursler         gen_huff_code_lens(&heap_space, heap_size, code_len_count,
1393*55fbfabfSMarcel Cornu                            (struct huff_code *) dist_huff_table, max_dist, MAX_DEFLATE_CODE_LEN);
139401dfbcc4SRoy Oursler         max_dist_sym = set_huff_codes(dist_huff_table, DIST_LEN, code_len_count);
1395660f49b0SGreg Tucker 
1396660f49b0SGreg Tucker         if (are_hufftables_useable(lit_huff_table, dist_huff_table)) {
139701dfbcc4SRoy Oursler                 heap_size = init_heap64_complete(&heap_space, lit_len_histogram, LIT_LEN);
139801dfbcc4SRoy Oursler                 gen_huff_code_lens(&heap_space, heap_size, code_len_count,
139901dfbcc4SRoy Oursler                                    (struct huff_code *) lit_huff_table, LIT_LEN,
140001dfbcc4SRoy Oursler                                    MAX_SAFE_LIT_CODE_LEN);
140101dfbcc4SRoy Oursler                 max_lit_len_sym = set_huff_codes(lit_huff_table, LIT_LEN, code_len_count);
1402660f49b0SGreg Tucker 
140301dfbcc4SRoy Oursler                 heap_size = init_heap64_complete(&heap_space, dist_histogram, DIST_LEN);
140401dfbcc4SRoy Oursler                 gen_huff_code_lens(&heap_space, heap_size, code_len_count,
140501dfbcc4SRoy Oursler                                    (struct huff_code *) dist_huff_table, max_dist,
140601dfbcc4SRoy Oursler                                    MAX_SAFE_DIST_CODE_LEN);
140701dfbcc4SRoy Oursler                 max_dist_sym = set_huff_codes(dist_huff_table, DIST_LEN, code_len_count);
1408660f49b0SGreg Tucker         }
1409660f49b0SGreg Tucker 
1410660f49b0SGreg Tucker         create_code_tables(dcodes, dcodes_sizes, DIST_LEN - DCODE_OFFSET,
1411660f49b0SGreg Tucker                            dist_huff_table + DCODE_OFFSET);
1412660f49b0SGreg Tucker 
141388f95d85SRoy Oursler         create_code_tables(lit_table, lit_table_sizes, IGZIP_LIT_TABLE_SIZE, lit_huff_table);
1414660f49b0SGreg Tucker 
1415660f49b0SGreg Tucker         create_packed_len_table(len_table, lit_huff_table);
141688f95d85SRoy Oursler         create_packed_dist_table(dist_table, IGZIP_DIST_TABLE_SIZE, dist_huff_table);
1417660f49b0SGreg Tucker 
1418bb05f0fcSRoy Oursler         set_buf(&header_bitbuf, hufftables->deflate_hdr, sizeof(hufftables->deflate_hdr));
141901dfbcc4SRoy Oursler         init(&header_bitbuf);
142001dfbcc4SRoy Oursler 
142101dfbcc4SRoy Oursler         hlit = max_lit_len_sym - 256;
142201dfbcc4SRoy Oursler         hdist = max_dist_sym;
142301dfbcc4SRoy Oursler 
142401dfbcc4SRoy Oursler         /* Run length encode the length and distance huffman codes */
142501dfbcc4SRoy Oursler         memset(count_histogram, 0, sizeof(count_histogram));
142601dfbcc4SRoy Oursler         for (i = 0; i < 257 + hlit; i++)
142701dfbcc4SRoy Oursler                 combined_table[i] = lit_huff_table[i].length;
142801dfbcc4SRoy Oursler         for (i = 0; i < 1 + hdist; i++)
142901dfbcc4SRoy Oursler                 combined_table[i + hlit + 257] = dist_huff_table[i].length;
1430*55fbfabfSMarcel Cornu         rl_huff_len = rl_encode(combined_table, hlit + 257 + hdist + 1, count_histogram, rl_huff);
143101dfbcc4SRoy Oursler 
143201dfbcc4SRoy Oursler         /* Create header */
1433*55fbfabfSMarcel Cornu         bit_count = create_header(&header_bitbuf, rl_huff, rl_huff_len, count_histogram, hlit,
1434*55fbfabfSMarcel Cornu                                   hdist, LAST_BLOCK);
143501dfbcc4SRoy Oursler         flush(&header_bitbuf);
1436660f49b0SGreg Tucker 
1437660f49b0SGreg Tucker         hufftables->deflate_hdr_count = bit_count / 8;
1438660f49b0SGreg Tucker         hufftables->deflate_hdr_extra_bits = bit_count % 8;
1439660f49b0SGreg Tucker 
1440660f49b0SGreg Tucker         return 0;
1441660f49b0SGreg Tucker }
1442660f49b0SGreg Tucker 
1443*55fbfabfSMarcel Cornu int
isal_create_hufftables_subset(struct isal_hufftables * hufftables,struct isal_huff_histogram * histogram)1444*55fbfabfSMarcel Cornu isal_create_hufftables_subset(struct isal_hufftables *hufftables,
1445660f49b0SGreg Tucker                               struct isal_huff_histogram *histogram)
1446660f49b0SGreg Tucker {
1447660f49b0SGreg Tucker         struct huff_code lit_huff_table[LIT_LEN], dist_huff_table[DIST_LEN];
1448660f49b0SGreg Tucker         uint64_t bit_count;
144901dfbcc4SRoy Oursler         int max_dist = convert_dist_to_dist_sym(IGZIP_HIST_SIZE);
145001dfbcc4SRoy Oursler         struct heap_tree heap_space;
145101dfbcc4SRoy Oursler         uint32_t heap_size;
145201dfbcc4SRoy Oursler         uint32_t code_len_count[MAX_HUFF_TREE_DEPTH + 1];
145301dfbcc4SRoy Oursler         struct BitBuf2 header_bitbuf;
145401dfbcc4SRoy Oursler         uint32_t max_lit_len_sym;
145501dfbcc4SRoy Oursler         uint32_t max_dist_sym;
145601dfbcc4SRoy Oursler         uint32_t hlit, hdist, i;
145701dfbcc4SRoy Oursler         uint16_t combined_table[LIT_LEN + DIST_LEN];
145801dfbcc4SRoy Oursler         uint64_t count_histogram[HUFF_LEN];
145901dfbcc4SRoy Oursler         struct rl_code rl_huff[LIT_LEN + DIST_LEN];
146001dfbcc4SRoy Oursler         uint32_t rl_huff_len;
1461660f49b0SGreg Tucker 
1462660f49b0SGreg Tucker         uint32_t *dist_table = hufftables->dist_table;
1463660f49b0SGreg Tucker         uint32_t *len_table = hufftables->len_table;
1464660f49b0SGreg Tucker         uint16_t *lit_table = hufftables->lit_table;
1465660f49b0SGreg Tucker         uint16_t *dcodes = hufftables->dcodes;
1466660f49b0SGreg Tucker         uint8_t *lit_table_sizes = hufftables->lit_table_sizes;
1467660f49b0SGreg Tucker         uint8_t *dcodes_sizes = hufftables->dcodes_sizes;
1468660f49b0SGreg Tucker         uint64_t *lit_len_histogram = histogram->lit_len_histogram;
1469660f49b0SGreg Tucker         uint64_t *dist_histogram = histogram->dist_histogram;
1470660f49b0SGreg Tucker 
1471660f49b0SGreg Tucker         memset(hufftables, 0, sizeof(struct isal_hufftables));
1472660f49b0SGreg Tucker 
1473*55fbfabfSMarcel Cornu         heap_size = init_heap64_semi_complete(&heap_space, lit_len_histogram, LIT_LEN,
1474e79c57c7SRoy Oursler                                               ISAL_DEF_LIT_SYMBOLS);
147501dfbcc4SRoy Oursler         gen_huff_code_lens(&heap_space, heap_size, code_len_count,
147601dfbcc4SRoy Oursler                            (struct huff_code *) lit_huff_table, LIT_LEN, MAX_DEFLATE_CODE_LEN);
147701dfbcc4SRoy Oursler         max_lit_len_sym = set_huff_codes(lit_huff_table, LIT_LEN, code_len_count);
1478660f49b0SGreg Tucker 
147901dfbcc4SRoy Oursler         heap_size = init_heap64_complete(&heap_space, dist_histogram, DIST_LEN);
148001dfbcc4SRoy Oursler         gen_huff_code_lens(&heap_space, heap_size, code_len_count,
1481*55fbfabfSMarcel Cornu                            (struct huff_code *) dist_huff_table, max_dist, MAX_DEFLATE_CODE_LEN);
148201dfbcc4SRoy Oursler         max_dist_sym = set_huff_codes(dist_huff_table, DIST_LEN, code_len_count);
1483660f49b0SGreg Tucker 
1484660f49b0SGreg Tucker         if (are_hufftables_useable(lit_huff_table, dist_huff_table)) {
148501dfbcc4SRoy Oursler                 heap_size = init_heap64_complete(&heap_space, lit_len_histogram, LIT_LEN);
148601dfbcc4SRoy Oursler                 gen_huff_code_lens(&heap_space, heap_size, code_len_count,
148701dfbcc4SRoy Oursler                                    (struct huff_code *) lit_huff_table, LIT_LEN,
148801dfbcc4SRoy Oursler                                    MAX_SAFE_LIT_CODE_LEN);
148901dfbcc4SRoy Oursler                 max_lit_len_sym = set_huff_codes(lit_huff_table, LIT_LEN, code_len_count);
1490660f49b0SGreg Tucker 
149101dfbcc4SRoy Oursler                 heap_size = init_heap64_complete(&heap_space, dist_histogram, DIST_LEN);
149201dfbcc4SRoy Oursler                 gen_huff_code_lens(&heap_space, heap_size, code_len_count,
149301dfbcc4SRoy Oursler                                    (struct huff_code *) dist_huff_table, max_dist,
149401dfbcc4SRoy Oursler                                    MAX_SAFE_DIST_CODE_LEN);
149501dfbcc4SRoy Oursler                 max_dist_sym = set_huff_codes(dist_huff_table, DIST_LEN, code_len_count);
1496660f49b0SGreg Tucker         }
1497660f49b0SGreg Tucker 
1498660f49b0SGreg Tucker         create_code_tables(dcodes, dcodes_sizes, DIST_LEN - DCODE_OFFSET,
1499660f49b0SGreg Tucker                            dist_huff_table + DCODE_OFFSET);
1500660f49b0SGreg Tucker 
150188f95d85SRoy Oursler         create_code_tables(lit_table, lit_table_sizes, IGZIP_LIT_TABLE_SIZE, lit_huff_table);
1502660f49b0SGreg Tucker 
1503660f49b0SGreg Tucker         create_packed_len_table(len_table, lit_huff_table);
150488f95d85SRoy Oursler         create_packed_dist_table(dist_table, IGZIP_DIST_TABLE_SIZE, dist_huff_table);
1505660f49b0SGreg Tucker 
1506bb05f0fcSRoy Oursler         set_buf(&header_bitbuf, hufftables->deflate_hdr, sizeof(hufftables->deflate_hdr));
150701dfbcc4SRoy Oursler         init(&header_bitbuf);
150801dfbcc4SRoy Oursler 
150901dfbcc4SRoy Oursler         hlit = max_lit_len_sym - 256;
151001dfbcc4SRoy Oursler         hdist = max_dist_sym;
151101dfbcc4SRoy Oursler 
151201dfbcc4SRoy Oursler         /* Run length encode the length and distance huffman codes */
151301dfbcc4SRoy Oursler         memset(count_histogram, 0, sizeof(count_histogram));
151401dfbcc4SRoy Oursler         for (i = 0; i < 257 + hlit; i++)
151501dfbcc4SRoy Oursler                 combined_table[i] = lit_huff_table[i].length;
151601dfbcc4SRoy Oursler         for (i = 0; i < 1 + hdist; i++)
151701dfbcc4SRoy Oursler                 combined_table[i + hlit + 257] = dist_huff_table[i].length;
1518*55fbfabfSMarcel Cornu         rl_huff_len = rl_encode(combined_table, hlit + 257 + hdist + 1, count_histogram, rl_huff);
151901dfbcc4SRoy Oursler 
152001dfbcc4SRoy Oursler         /* Create header */
1521*55fbfabfSMarcel Cornu         bit_count = create_header(&header_bitbuf, rl_huff, rl_huff_len, count_histogram, hlit,
1522*55fbfabfSMarcel Cornu                                   hdist, LAST_BLOCK);
152301dfbcc4SRoy Oursler         flush(&header_bitbuf);
1524660f49b0SGreg Tucker 
1525660f49b0SGreg Tucker         hufftables->deflate_hdr_count = bit_count / 8;
1526660f49b0SGreg Tucker         hufftables->deflate_hdr_extra_bits = bit_count % 8;
1527660f49b0SGreg Tucker 
1528660f49b0SGreg Tucker         return 0;
1529660f49b0SGreg Tucker }
153001dfbcc4SRoy Oursler 
1531*55fbfabfSMarcel Cornu static void
expand_hufftables_icf(struct hufftables_icf * hufftables)1532*55fbfabfSMarcel Cornu expand_hufftables_icf(struct hufftables_icf *hufftables)
153301dfbcc4SRoy Oursler {
153401dfbcc4SRoy Oursler         uint32_t i, eb, j, k, len, code;
153501dfbcc4SRoy Oursler         struct huff_code orig[21], *p_code;
153601dfbcc4SRoy Oursler         struct huff_code *lit_len_codes = hufftables->lit_len_table;
153701dfbcc4SRoy Oursler         struct huff_code *dist_codes = hufftables->dist_table;
153801dfbcc4SRoy Oursler 
153901dfbcc4SRoy Oursler         for (i = 0; i < 21; i++)
154001dfbcc4SRoy Oursler                 orig[i] = lit_len_codes[i + 265];
154101dfbcc4SRoy Oursler 
154201dfbcc4SRoy Oursler         p_code = &lit_len_codes[265];
154301dfbcc4SRoy Oursler 
154401dfbcc4SRoy Oursler         i = 0;
154501dfbcc4SRoy Oursler         for (eb = 1; eb < 6; eb++) {
154601dfbcc4SRoy Oursler                 for (k = 0; k < 4; k++) {
154701dfbcc4SRoy Oursler                         len = orig[i].length;
154801dfbcc4SRoy Oursler                         code = orig[i++].code;
154901dfbcc4SRoy Oursler                         for (j = 0; j < (1u << eb); j++) {
155001dfbcc4SRoy Oursler                                 p_code->code_and_extra = code | (j << len);
155101dfbcc4SRoy Oursler                                 p_code->length = len + eb;
155201dfbcc4SRoy Oursler                                 p_code++;
155301dfbcc4SRoy Oursler                         }
155401dfbcc4SRoy Oursler                 } // end for k
155501dfbcc4SRoy Oursler         } // end for eb
155601dfbcc4SRoy Oursler         // fix up last record
155701dfbcc4SRoy Oursler         p_code[-1] = orig[i];
155801dfbcc4SRoy Oursler 
155901dfbcc4SRoy Oursler         dist_codes[DIST_LEN].code_and_extra = 0;
156001dfbcc4SRoy Oursler         dist_codes[DIST_LEN].length = 0;
156101dfbcc4SRoy Oursler }
156201dfbcc4SRoy Oursler 
156364143a74SRoy Oursler uint64_t
create_hufftables_icf(struct BitBuf2 * bb,struct hufftables_icf * hufftables,struct isal_mod_hist * hist,uint32_t end_of_block)156401dfbcc4SRoy Oursler create_hufftables_icf(struct BitBuf2 *bb, struct hufftables_icf *hufftables,
156501dfbcc4SRoy Oursler                       struct isal_mod_hist *hist, uint32_t end_of_block)
156601dfbcc4SRoy Oursler {
156701dfbcc4SRoy Oursler         uint32_t bl_count[MAX_DEFLATE_CODE_LEN + 1];
156801dfbcc4SRoy Oursler         uint32_t max_ll_code, max_d_code;
156901dfbcc4SRoy Oursler         struct heap_tree heap_space;
157001dfbcc4SRoy Oursler         uint32_t heap_size;
157101dfbcc4SRoy Oursler         struct rl_code cl_tokens[LIT_LEN + DIST_LEN];
157201dfbcc4SRoy Oursler         uint32_t num_cl_tokens;
157301dfbcc4SRoy Oursler         uint64_t cl_counts[CODE_LEN_CODES];
157401dfbcc4SRoy Oursler         uint16_t combined_table[LIT_LEN + DIST_LEN];
157501dfbcc4SRoy Oursler         int i;
15769992cc19SRoy Oursler         uint64_t compressed_len = 0;
15779992cc19SRoy Oursler         uint64_t static_compressed_len = 3; /* The static header size */
15789992cc19SRoy Oursler         struct BitBuf2 bb_tmp;
157901dfbcc4SRoy Oursler 
158001dfbcc4SRoy Oursler         struct huff_code *ll_codes = hufftables->lit_len_table;
158101dfbcc4SRoy Oursler         struct huff_code *d_codes = hufftables->dist_table;
1582e38ed4b5SRoy Oursler         uint32_t *ll_hist = hist->ll_hist;
1583e38ed4b5SRoy Oursler         uint32_t *d_hist = hist->d_hist;
15849992cc19SRoy Oursler         struct huff_code *static_ll_codes = static_hufftables.lit_len_table;
15859992cc19SRoy Oursler         struct huff_code *static_d_codes = static_hufftables.dist_table;
15869992cc19SRoy Oursler 
15879992cc19SRoy Oursler         memcpy(&bb_tmp, bb, sizeof(struct BitBuf2));
158801dfbcc4SRoy Oursler 
158901dfbcc4SRoy Oursler         flatten_ll(hist->ll_hist);
159001dfbcc4SRoy Oursler 
159101dfbcc4SRoy Oursler         // make sure EOB is present
159201dfbcc4SRoy Oursler         if (ll_hist[256] == 0)
159301dfbcc4SRoy Oursler                 ll_hist[256] = 1;
159401dfbcc4SRoy Oursler 
1595e38ed4b5SRoy Oursler         heap_size = init_heap32(&heap_space, ll_hist, LIT_LEN);
1596*55fbfabfSMarcel Cornu         gen_huff_code_lens(&heap_space, heap_size, bl_count, ll_codes, LIT_LEN,
1597*55fbfabfSMarcel Cornu                            MAX_DEFLATE_CODE_LEN);
159801dfbcc4SRoy Oursler         max_ll_code = set_huff_codes(ll_codes, LIT_LEN, bl_count);
159901dfbcc4SRoy Oursler 
1600e38ed4b5SRoy Oursler         heap_size = init_heap32(&heap_space, d_hist, DIST_LEN);
1601*55fbfabfSMarcel Cornu         gen_huff_code_lens(&heap_space, heap_size, bl_count, d_codes, DIST_LEN,
1602*55fbfabfSMarcel Cornu                            MAX_DEFLATE_CODE_LEN);
160301dfbcc4SRoy Oursler         max_d_code = set_dist_huff_codes(d_codes, bl_count);
160401dfbcc4SRoy Oursler 
160501dfbcc4SRoy Oursler         assert(max_ll_code >= 256); // must be EOB code
160601dfbcc4SRoy Oursler         assert(max_d_code != 0);
160701dfbcc4SRoy Oursler 
160801dfbcc4SRoy Oursler         /* Run length encode the length and distance huffman codes */
160901dfbcc4SRoy Oursler         memset(cl_counts, 0, sizeof(cl_counts));
16109992cc19SRoy Oursler 
16119992cc19SRoy Oursler         for (i = 0; i <= 256; i++) {
161201dfbcc4SRoy Oursler                 combined_table[i] = ll_codes[i].length;
16139992cc19SRoy Oursler                 compressed_len += ll_codes[i].length * ll_hist[i];
16149992cc19SRoy Oursler                 static_compressed_len += static_ll_codes[i].length * ll_hist[i];
16159992cc19SRoy Oursler         }
16169992cc19SRoy Oursler 
16179992cc19SRoy Oursler         for (; i < max_ll_code + 1; i++) {
16189992cc19SRoy Oursler                 combined_table[i] = ll_codes[i].length;
1619*55fbfabfSMarcel Cornu                 compressed_len += (ll_codes[i].length + len_code_extra_bits[i - 257]) * ll_hist[i];
16209992cc19SRoy Oursler                 static_compressed_len +=
16219992cc19SRoy Oursler                         (static_ll_codes[i].length + len_code_extra_bits[i - 257]) * ll_hist[i];
16229992cc19SRoy Oursler         }
16239992cc19SRoy Oursler 
16249992cc19SRoy Oursler         for (i = 0; i < max_d_code + 1; i++) {
162501dfbcc4SRoy Oursler                 combined_table[i + max_ll_code + 1] = d_codes[i].length;
16269992cc19SRoy Oursler                 compressed_len += (d_codes[i].length + dist_code_extra_bits[i]) * d_hist[i];
16279992cc19SRoy Oursler                 static_compressed_len +=
16289992cc19SRoy Oursler                         (static_d_codes[i].length + dist_code_extra_bits[i]) * d_hist[i];
16299992cc19SRoy Oursler         }
163001dfbcc4SRoy Oursler 
163164143a74SRoy Oursler         if (static_compressed_len > compressed_len) {
1632*55fbfabfSMarcel Cornu                 num_cl_tokens = rl_encode(combined_table, max_ll_code + max_d_code + 2, cl_counts,
1633*55fbfabfSMarcel Cornu                                           cl_tokens);
163401dfbcc4SRoy Oursler 
163501dfbcc4SRoy Oursler                 /* Create header */
163664143a74SRoy Oursler                 create_header(bb, cl_tokens, num_cl_tokens, cl_counts, max_ll_code - 256,
163764143a74SRoy Oursler                               max_d_code, end_of_block);
16389992cc19SRoy Oursler                 compressed_len += 8 * buffer_used(bb) + bb->m_bit_count;
163964143a74SRoy Oursler         }
164001dfbcc4SRoy Oursler 
164164143a74SRoy Oursler         /* Substitute in static block since it creates smaller block */
164264143a74SRoy Oursler         if (static_compressed_len <= compressed_len) {
16439992cc19SRoy Oursler                 memcpy(hufftables, &static_hufftables, sizeof(struct hufftables_icf));
16449992cc19SRoy Oursler                 memcpy(bb, &bb_tmp, sizeof(struct BitBuf2));
16459992cc19SRoy Oursler                 end_of_block = end_of_block ? 1 : 0;
16469992cc19SRoy Oursler                 write_bits(bb, 0x2 | end_of_block, 3);
164764143a74SRoy Oursler                 compressed_len = static_compressed_len;
16489992cc19SRoy Oursler         }
164964143a74SRoy Oursler 
165064143a74SRoy Oursler         expand_hufftables_icf(hufftables);
165164143a74SRoy Oursler         return compressed_len;
165201dfbcc4SRoy Oursler }
1653