haproxy/src/hpack-huff.c
Willy Tarreau 094ecf19f9 BUG/MEDIUM: hpack: fix incorrect huffman decoding of some control chars
Commit 9f4f6b038 ("OPTIM: hpack-huff: reduce the cache footprint of the
huffman decoder") replaced the large tables with more space efficient
byte arrays, but one table, rht_bit15_11_11_4, has a 64 bytes hole in it
that wasn't materialized by filling it with zeroes to make the offsets
match, nor by adjusting the offset from the caller. This resulted in
some control chars not properly being decoded and being seen as byte 0,
and the associated messages to be rejected, as can be seen in issue #1971.

This commit fixes it by adjusting the offset used for the higher part of
the table so that we don't need to store 64 zeroes that will never be
accessed.

This needs to be backported to 2.7.

Thanks to Christopher for spotting the bug, and to Juanga Covas for
providing precious traces showing the problem.
2023-01-26 11:36:39 +01:00

862 lines
28 KiB
C

/*
* Huffman decoding and encoding for HPACK (RFC7541)
*
* Copyright (C) 2014-2017 Willy Tarreau <willy@haproxy.org>
* Copyright (C) 2017 HAProxy Technologies
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <haproxy/api.h>
#include <haproxy/hpack-huff.h>
#include <haproxy/net_helper.h>
struct huff {
uint32_t c; /* code point */
int b; /* bits */
};
/* huffman table as per RFC7541 appendix B */
static const struct huff ht[257] = {
[ 0] = { .c = 0x00001ff8, .b = 13 },
[ 1] = { .c = 0x007fffd8, .b = 23 },
[ 2] = { .c = 0x0fffffe2, .b = 28 },
[ 3] = { .c = 0x0fffffe3, .b = 28 },
[ 4] = { .c = 0x0fffffe4, .b = 28 },
[ 5] = { .c = 0x0fffffe5, .b = 28 },
[ 6] = { .c = 0x0fffffe6, .b = 28 },
[ 7] = { .c = 0x0fffffe7, .b = 28 },
[ 8] = { .c = 0x0fffffe8, .b = 28 },
[ 9] = { .c = 0x00ffffea, .b = 24 },
[ 10] = { .c = 0x3ffffffc, .b = 30 },
[ 11] = { .c = 0x0fffffe9, .b = 28 },
[ 12] = { .c = 0x0fffffea, .b = 28 },
[ 13] = { .c = 0x3ffffffd, .b = 30 },
[ 14] = { .c = 0x0fffffeb, .b = 28 },
[ 15] = { .c = 0x0fffffec, .b = 28 },
[ 16] = { .c = 0x0fffffed, .b = 28 },
[ 17] = { .c = 0x0fffffee, .b = 28 },
[ 18] = { .c = 0x0fffffef, .b = 28 },
[ 19] = { .c = 0x0ffffff0, .b = 28 },
[ 20] = { .c = 0x0ffffff1, .b = 28 },
[ 21] = { .c = 0x0ffffff2, .b = 28 },
[ 22] = { .c = 0x3ffffffe, .b = 30 },
[ 23] = { .c = 0x0ffffff3, .b = 28 },
[ 24] = { .c = 0x0ffffff4, .b = 28 },
[ 25] = { .c = 0x0ffffff5, .b = 28 },
[ 26] = { .c = 0x0ffffff6, .b = 28 },
[ 27] = { .c = 0x0ffffff7, .b = 28 },
[ 28] = { .c = 0x0ffffff8, .b = 28 },
[ 29] = { .c = 0x0ffffff9, .b = 28 },
[ 30] = { .c = 0x0ffffffa, .b = 28 },
[ 31] = { .c = 0x0ffffffb, .b = 28 },
[ 32] = { .c = 0x00000014, .b = 6 },
[ 33] = { .c = 0x000003f8, .b = 10 },
[ 34] = { .c = 0x000003f9, .b = 10 },
[ 35] = { .c = 0x00000ffa, .b = 12 },
[ 36] = { .c = 0x00001ff9, .b = 13 },
[ 37] = { .c = 0x00000015, .b = 6 },
[ 38] = { .c = 0x000000f8, .b = 8 },
[ 39] = { .c = 0x000007fa, .b = 11 },
[ 40] = { .c = 0x000003fa, .b = 10 },
[ 41] = { .c = 0x000003fb, .b = 10 },
[ 42] = { .c = 0x000000f9, .b = 8 },
[ 43] = { .c = 0x000007fb, .b = 11 },
[ 44] = { .c = 0x000000fa, .b = 8 },
[ 45] = { .c = 0x00000016, .b = 6 },
[ 46] = { .c = 0x00000017, .b = 6 },
[ 47] = { .c = 0x00000018, .b = 6 },
[ 48] = { .c = 0x00000000, .b = 5 },
[ 49] = { .c = 0x00000001, .b = 5 },
[ 50] = { .c = 0x00000002, .b = 5 },
[ 51] = { .c = 0x00000019, .b = 6 },
[ 52] = { .c = 0x0000001a, .b = 6 },
[ 53] = { .c = 0x0000001b, .b = 6 },
[ 54] = { .c = 0x0000001c, .b = 6 },
[ 55] = { .c = 0x0000001d, .b = 6 },
[ 56] = { .c = 0x0000001e, .b = 6 },
[ 57] = { .c = 0x0000001f, .b = 6 },
[ 58] = { .c = 0x0000005c, .b = 7 },
[ 59] = { .c = 0x000000fb, .b = 8 },
[ 60] = { .c = 0x00007ffc, .b = 15 },
[ 61] = { .c = 0x00000020, .b = 6 },
[ 62] = { .c = 0x00000ffb, .b = 12 },
[ 63] = { .c = 0x000003fc, .b = 10 },
[ 64] = { .c = 0x00001ffa, .b = 13 },
[ 65] = { .c = 0x00000021, .b = 6 },
[ 66] = { .c = 0x0000005d, .b = 7 },
[ 67] = { .c = 0x0000005e, .b = 7 },
[ 68] = { .c = 0x0000005f, .b = 7 },
[ 69] = { .c = 0x00000060, .b = 7 },
[ 70] = { .c = 0x00000061, .b = 7 },
[ 71] = { .c = 0x00000062, .b = 7 },
[ 72] = { .c = 0x00000063, .b = 7 },
[ 73] = { .c = 0x00000064, .b = 7 },
[ 74] = { .c = 0x00000065, .b = 7 },
[ 75] = { .c = 0x00000066, .b = 7 },
[ 76] = { .c = 0x00000067, .b = 7 },
[ 77] = { .c = 0x00000068, .b = 7 },
[ 78] = { .c = 0x00000069, .b = 7 },
[ 79] = { .c = 0x0000006a, .b = 7 },
[ 80] = { .c = 0x0000006b, .b = 7 },
[ 81] = { .c = 0x0000006c, .b = 7 },
[ 82] = { .c = 0x0000006d, .b = 7 },
[ 83] = { .c = 0x0000006e, .b = 7 },
[ 84] = { .c = 0x0000006f, .b = 7 },
[ 85] = { .c = 0x00000070, .b = 7 },
[ 86] = { .c = 0x00000071, .b = 7 },
[ 87] = { .c = 0x00000072, .b = 7 },
[ 88] = { .c = 0x000000fc, .b = 8 },
[ 89] = { .c = 0x00000073, .b = 7 },
[ 90] = { .c = 0x000000fd, .b = 8 },
[ 91] = { .c = 0x00001ffb, .b = 13 },
[ 92] = { .c = 0x0007fff0, .b = 19 },
[ 93] = { .c = 0x00001ffc, .b = 13 },
[ 94] = { .c = 0x00003ffc, .b = 14 },
[ 95] = { .c = 0x00000022, .b = 6 },
[ 96] = { .c = 0x00007ffd, .b = 15 },
[ 97] = { .c = 0x00000003, .b = 5 },
[ 98] = { .c = 0x00000023, .b = 6 },
[ 99] = { .c = 0x00000004, .b = 5 },
[100] = { .c = 0x00000024, .b = 6 },
[101] = { .c = 0x00000005, .b = 5 },
[102] = { .c = 0x00000025, .b = 6 },
[103] = { .c = 0x00000026, .b = 6 },
[104] = { .c = 0x00000027, .b = 6 },
[105] = { .c = 0x00000006, .b = 5 },
[106] = { .c = 0x00000074, .b = 7 },
[107] = { .c = 0x00000075, .b = 7 },
[108] = { .c = 0x00000028, .b = 6 },
[109] = { .c = 0x00000029, .b = 6 },
[110] = { .c = 0x0000002a, .b = 6 },
[111] = { .c = 0x00000007, .b = 5 },
[112] = { .c = 0x0000002b, .b = 6 },
[113] = { .c = 0x00000076, .b = 7 },
[114] = { .c = 0x0000002c, .b = 6 },
[115] = { .c = 0x00000008, .b = 5 },
[116] = { .c = 0x00000009, .b = 5 },
[117] = { .c = 0x0000002d, .b = 6 },
[118] = { .c = 0x00000077, .b = 7 },
[119] = { .c = 0x00000078, .b = 7 },
[120] = { .c = 0x00000079, .b = 7 },
[121] = { .c = 0x0000007a, .b = 7 },
[122] = { .c = 0x0000007b, .b = 7 },
[123] = { .c = 0x00007ffe, .b = 15 },
[124] = { .c = 0x000007fc, .b = 11 },
[125] = { .c = 0x00003ffd, .b = 14 },
[126] = { .c = 0x00001ffd, .b = 13 },
[127] = { .c = 0x0ffffffc, .b = 28 },
[128] = { .c = 0x000fffe6, .b = 20 },
[129] = { .c = 0x003fffd2, .b = 22 },
[130] = { .c = 0x000fffe7, .b = 20 },
[131] = { .c = 0x000fffe8, .b = 20 },
[132] = { .c = 0x003fffd3, .b = 22 },
[133] = { .c = 0x003fffd4, .b = 22 },
[134] = { .c = 0x003fffd5, .b = 22 },
[135] = { .c = 0x007fffd9, .b = 23 },
[136] = { .c = 0x003fffd6, .b = 22 },
[137] = { .c = 0x007fffda, .b = 23 },
[138] = { .c = 0x007fffdb, .b = 23 },
[139] = { .c = 0x007fffdc, .b = 23 },
[140] = { .c = 0x007fffdd, .b = 23 },
[141] = { .c = 0x007fffde, .b = 23 },
[142] = { .c = 0x00ffffeb, .b = 24 },
[143] = { .c = 0x007fffdf, .b = 23 },
[144] = { .c = 0x00ffffec, .b = 24 },
[145] = { .c = 0x00ffffed, .b = 24 },
[146] = { .c = 0x003fffd7, .b = 22 },
[147] = { .c = 0x007fffe0, .b = 23 },
[148] = { .c = 0x00ffffee, .b = 24 },
[149] = { .c = 0x007fffe1, .b = 23 },
[150] = { .c = 0x007fffe2, .b = 23 },
[151] = { .c = 0x007fffe3, .b = 23 },
[152] = { .c = 0x007fffe4, .b = 23 },
[153] = { .c = 0x001fffdc, .b = 21 },
[154] = { .c = 0x003fffd8, .b = 22 },
[155] = { .c = 0x007fffe5, .b = 23 },
[156] = { .c = 0x003fffd9, .b = 22 },
[157] = { .c = 0x007fffe6, .b = 23 },
[158] = { .c = 0x007fffe7, .b = 23 },
[159] = { .c = 0x00ffffef, .b = 24 },
[160] = { .c = 0x003fffda, .b = 22 },
[161] = { .c = 0x001fffdd, .b = 21 },
[162] = { .c = 0x000fffe9, .b = 20 },
[163] = { .c = 0x003fffdb, .b = 22 },
[164] = { .c = 0x003fffdc, .b = 22 },
[165] = { .c = 0x007fffe8, .b = 23 },
[166] = { .c = 0x007fffe9, .b = 23 },
[167] = { .c = 0x001fffde, .b = 21 },
[168] = { .c = 0x007fffea, .b = 23 },
[169] = { .c = 0x003fffdd, .b = 22 },
[170] = { .c = 0x003fffde, .b = 22 },
[171] = { .c = 0x00fffff0, .b = 24 },
[172] = { .c = 0x001fffdf, .b = 21 },
[173] = { .c = 0x003fffdf, .b = 22 },
[174] = { .c = 0x007fffeb, .b = 23 },
[175] = { .c = 0x007fffec, .b = 23 },
[176] = { .c = 0x001fffe0, .b = 21 },
[177] = { .c = 0x001fffe1, .b = 21 },
[178] = { .c = 0x003fffe0, .b = 22 },
[179] = { .c = 0x001fffe2, .b = 21 },
[180] = { .c = 0x007fffed, .b = 23 },
[181] = { .c = 0x003fffe1, .b = 22 },
[182] = { .c = 0x007fffee, .b = 23 },
[183] = { .c = 0x007fffef, .b = 23 },
[184] = { .c = 0x000fffea, .b = 20 },
[185] = { .c = 0x003fffe2, .b = 22 },
[186] = { .c = 0x003fffe3, .b = 22 },
[187] = { .c = 0x003fffe4, .b = 22 },
[188] = { .c = 0x007ffff0, .b = 23 },
[189] = { .c = 0x003fffe5, .b = 22 },
[190] = { .c = 0x003fffe6, .b = 22 },
[191] = { .c = 0x007ffff1, .b = 23 },
[192] = { .c = 0x03ffffe0, .b = 26 },
[193] = { .c = 0x03ffffe1, .b = 26 },
[194] = { .c = 0x000fffeb, .b = 20 },
[195] = { .c = 0x0007fff1, .b = 19 },
[196] = { .c = 0x003fffe7, .b = 22 },
[197] = { .c = 0x007ffff2, .b = 23 },
[198] = { .c = 0x003fffe8, .b = 22 },
[199] = { .c = 0x01ffffec, .b = 25 },
[200] = { .c = 0x03ffffe2, .b = 26 },
[201] = { .c = 0x03ffffe3, .b = 26 },
[202] = { .c = 0x03ffffe4, .b = 26 },
[203] = { .c = 0x07ffffde, .b = 27 },
[204] = { .c = 0x07ffffdf, .b = 27 },
[205] = { .c = 0x03ffffe5, .b = 26 },
[206] = { .c = 0x00fffff1, .b = 24 },
[207] = { .c = 0x01ffffed, .b = 25 },
[208] = { .c = 0x0007fff2, .b = 19 },
[209] = { .c = 0x001fffe3, .b = 21 },
[210] = { .c = 0x03ffffe6, .b = 26 },
[211] = { .c = 0x07ffffe0, .b = 27 },
[212] = { .c = 0x07ffffe1, .b = 27 },
[213] = { .c = 0x03ffffe7, .b = 26 },
[214] = { .c = 0x07ffffe2, .b = 27 },
[215] = { .c = 0x00fffff2, .b = 24 },
[216] = { .c = 0x001fffe4, .b = 21 },
[217] = { .c = 0x001fffe5, .b = 21 },
[218] = { .c = 0x03ffffe8, .b = 26 },
[219] = { .c = 0x03ffffe9, .b = 26 },
[220] = { .c = 0x0ffffffd, .b = 28 },
[221] = { .c = 0x07ffffe3, .b = 27 },
[222] = { .c = 0x07ffffe4, .b = 27 },
[223] = { .c = 0x07ffffe5, .b = 27 },
[224] = { .c = 0x000fffec, .b = 20 },
[225] = { .c = 0x00fffff3, .b = 24 },
[226] = { .c = 0x000fffed, .b = 20 },
[227] = { .c = 0x001fffe6, .b = 21 },
[228] = { .c = 0x003fffe9, .b = 22 },
[229] = { .c = 0x001fffe7, .b = 21 },
[230] = { .c = 0x001fffe8, .b = 21 },
[231] = { .c = 0x007ffff3, .b = 23 },
[232] = { .c = 0x003fffea, .b = 22 },
[233] = { .c = 0x003fffeb, .b = 22 },
[234] = { .c = 0x01ffffee, .b = 25 },
[235] = { .c = 0x01ffffef, .b = 25 },
[236] = { .c = 0x00fffff4, .b = 24 },
[237] = { .c = 0x00fffff5, .b = 24 },
[238] = { .c = 0x03ffffea, .b = 26 },
[239] = { .c = 0x007ffff4, .b = 23 },
[240] = { .c = 0x03ffffeb, .b = 26 },
[241] = { .c = 0x07ffffe6, .b = 27 },
[242] = { .c = 0x03ffffec, .b = 26 },
[243] = { .c = 0x03ffffed, .b = 26 },
[244] = { .c = 0x07ffffe7, .b = 27 },
[245] = { .c = 0x07ffffe8, .b = 27 },
[246] = { .c = 0x07ffffe9, .b = 27 },
[247] = { .c = 0x07ffffea, .b = 27 },
[248] = { .c = 0x07ffffeb, .b = 27 },
[249] = { .c = 0x0ffffffe, .b = 28 },
[250] = { .c = 0x07ffffec, .b = 27 },
[251] = { .c = 0x07ffffed, .b = 27 },
[252] = { .c = 0x07ffffee, .b = 27 },
[253] = { .c = 0x07ffffef, .b = 27 },
[254] = { .c = 0x07fffff0, .b = 27 },
[255] = { .c = 0x03ffffee, .b = 26 },
[256] = { .c = 0x3fffffff, .b = 30 }, /* EOS */
};
/* Reversed huffman codes, generated by dev/hpack/gen-rht.c from the table
* above, then simplified by hand by extracting the few different length
* values and writing code to produce them instead.
*
* The codes are aligned on the MSB since that's how they appear in the stream.
*
* Quick summary below of the way the tables work. They're based on how the
* prefixes are organized, starting from the MSB.
*
* These codes fit in a single octet (5 to 8 bits) :
* 00/5 08/5 10/5 18/5 20/5 28/5 30/5 38/5
* 40/5 48/5
*
* 50/6 54/6 58/6 5c/6 60/6 64/6 68/6 6c/6
* 70/6 74/6 78/6 7c/6 80/6 84/6 88/6 8c/6
* 90/6 94/6 98/6 9c/6 a0/6 a4/6 a8/6 ac/6
* b0/6 b4/6
*
* b8/7 ba/7 bc/7 be/7 c0/7 c2/7 c4/7 c6/7
* c8/7 ca/7 cc/7 ce/7 d0/7 d2/7 d4/7 d6/7
* d8/7 da/7 dc/7 de/7 e0/7 e2/7 e4/7 e6/7
* e8/7 ea/7 ec/7 ee/7 f0/7 f2/7 f4/7 f6/7
*
* f8/8 f9/8 fa/8 fb/8 fc/8 fd/8
*
* ==> a single 256-symbol table based on the full byte provides a direct
* access and the bit count
*
* These codes fit in two octets (10 to 15 bits, neither 9 nor 16 bits code) :
*
* fe + 2 bits:
* 00/2 40/2 80/2 c0/2
*
* ff + 2..7 bits :
* 00/2
* 40/3 60/3 80/3
* a0/4 b0/4
* c0/5 c8/5 d0/5 d8/5 e0/5 e8/5
* f0/6 f4/6
* f8/7 fa/7 fc/7
*
* ==> a single 256-symbol table made of b0.0 and b1.7-1 provides a direct
* access and the bit count after a miss on the first one above.
*
* These ones fit in three octets :
* ff fe + 3..5 bits :
* 00/3 20/3 40/3 60/4 70/4 80/4 90/4 a0/4
* b0/4 c0/4 d0/4
* e0/5 e8/5 f0/5 f8/5
*
* ff ff + 5..8 bits :
* 00/5 08/5 10/5 18/5 20/5 28/5 30/5 38/5
* 40/5
* 48/6 4c/6 50/6 54/6 58/6 5c/6 60/6 64/6
* 68/6 6c/6 70/6 74/6 78/6 7c/6 80/6 84/6
* 88/6 8c/6 90/6 94/6 98/6 9c/6 a0/6 a4/6
* a8/6 ac/6
* b0/7 b2/7 b4/7 b6/7 b8/7 ba/7 bc/7 be/7
* c0/7 c2/7 c4/7 c6/7 c8/7 ca/7 cc/7 ce/7
* d0/7 d2/7 d4/7 d6/7 d8/7 da/7 dc/7 de/7
* e0/7 e2/7 e4/7 e6/7 e8/7
* ea/8 eb/8 ec/8 ed/8 ee/8 ef/8 f0/8 f1/8
* f2/8 f3/8 f4/8 f5/8
*
* ==> a 32-symbol table has to be applied to 0xfffe
* ==> a 256-symbol table has to be applied to 0xffff
*
* The other ones fit in four octets with 1 to 6 bits in the last one :
* ff ff f6 : 00/1 80/1
* ff ff f7 : 00/1 80/1
* ff ff f8 : 00/2 40/2 80/2 c0/2
* ff ff f9 : 00/2 40/2 80/2 c0/2
* ff ff fa : 00/2 40/2 80/2 c0/2
* ff ff fb : 00/2 40/2 80/2
* ff ff fb : c0/3 e0/3
* ff ff fc : 00/3 20/3 40/3 60/3 80/3 a0/3 c0/3 e0/3
* ff ff fd : 00/3 20/3 40/3 60/3 80/3 a0/3 c0/3 e0/3
* ff ff fe : 00/3
* ff ff fe : 20/4 30/4 40/4 50/4 60/4 70/4 80/4 90/4 a0/4 b0/4 c0/4 d0/4 e0/4 f0/4
* ff ff ff : 00/4 10/4 20/4 30/4 40/4 50/4 60/4 70/4 80/4 90/4 a0/4 b0/4 c0/4 d0/4 e0/4
* ff ff ff : f0/6 f4/6 f8/6 fc/6
*
* ==> a 256-symbol table with b2.0-3,b3.7-4 gives all of them except the
* distinction between ffffff{f0,f4,f8,fc} which is rare enough
* and can be done by hand when bit count == 30.
*
*
* Code lengths :
* 5..8 : 0x00..0xfe
* 10..15 : 0xfe
* 0xff 0x00..0xfe
* 19..20 : 0xff 0xfe 0x00..0xdf
* 21 : 0xff 0xfe 0xe0..0xff
* 21 : 0xff 0xff 0x00..0x40
* 22..24 : 0xff 0xff 0x00..0xf5
* 24..28 : 0xff 0xff 0xf5..0xff
* 30 : 0xff 0xff 0xff 0xf0..0xff
*
*
* if b0 < 0xfe ==> 5..8 bits (74 codes)
* if b0 == 0xfe or 0xff : 10..15
* => if b0 == 0xfe || b1 < 0xfe : lookup (b0:0|b1:7..1) (21 codes)
*
* -- b0 = 0xff --
* if b1 == 0xfe : 19..21 bits
* => lookup b2:7..3 (15 codes)
*
* -- b0 = 0xff, b1 = 0xff : 147 codes --
* if b2 < 0xf6 : 21..24 bits (76 codes)
* if b2 >= 0xf6 : 25..30 bits (71 codes)
*
* Algorithm:
* - if > 24 and < 32, read missing bits.
* - if less than 24 bits, read 1 byte. If past end, insert 0xff instead.
* - if b0 < 0xfe lookup b0 in table0[0..255]
* - else if b0 == 0xfe, manual lookup
* - else if b0 == 0xff, lookup b1 in table1[0..255]
* ...
*/
uint8_t rht_bit31_24[256] = {
/* 0x00 */ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
/* 0x08 */ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
/* 0x10 */ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
/* 0x18 */ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
/* 0x20 */ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
/* 0x28 */ 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
/* 0x30 */ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
/* 0x38 */ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
/* 0x40 */ 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73,
/* 0x48 */ 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
/* 0x50 */ 0x20, 0x20, 0x20, 0x20,
/* 0x54 */ 0x25, 0x25, 0x25, 0x25,
/* 0x58 */ 0x2d, 0x2d, 0x2d, 0x2d,
/* 0x5c */ 0x2e, 0x2e, 0x2e, 0x2e,
/* 0x60 */ 0x2f, 0x2f, 0x2f, 0x2f,
/* 0x64 */ 0x33, 0x33, 0x33, 0x33,
/* 0x68 */ 0x34, 0x34, 0x34, 0x34,
/* 0x6c */ 0x35, 0x35, 0x35, 0x35,
/* 0x70 */ 0x36, 0x36, 0x36, 0x36,
/* 0x74 */ 0x37, 0x37, 0x37, 0x37,
/* 0x78 */ 0x38, 0x38, 0x38, 0x38,
/* 0x7c */ 0x39, 0x39, 0x39, 0x39,
/* 0x80 */ 0x3d, 0x3d, 0x3d, 0x3d,
/* 0x84 */ 0x41, 0x41, 0x41, 0x41,
/* 0x88 */ 0x5f, 0x5f, 0x5f, 0x5f,
/* 0x8c */ 0x62, 0x62, 0x62, 0x62,
/* 0x90 */ 0x64, 0x64, 0x64, 0x64,
/* 0x94 */ 0x66, 0x66, 0x66, 0x66,
/* 0x98 */ 0x67, 0x67, 0x67, 0x67,
/* 0x9c */ 0x68, 0x68, 0x68, 0x68,
/* 0xa0 */ 0x6c, 0x6c, 0x6c, 0x6c,
/* 0xa4 */ 0x6d, 0x6d, 0x6d, 0x6d,
/* 0xa8 */ 0x6e, 0x6e, 0x6e, 0x6e,
/* 0xac */ 0x70, 0x70, 0x70, 0x70,
/* 0xb0 */ 0x72, 0x72, 0x72, 0x72,
/* 0xb4 */ 0x75, 0x75, 0x75, 0x75,
/* 0xb8 */ 0x3a, 0x3a,
/* 0xba */ 0x42, 0x42,
/* 0xbc */ 0x43, 0x43,
/* 0xbe */ 0x44, 0x44,
/* 0xc0 */ 0x45, 0x45,
/* 0xc2 */ 0x46, 0x46,
/* 0xc4 */ 0x47, 0x47,
/* 0xc6 */ 0x48, 0x48,
/* 0xc8 */ 0x49, 0x49,
/* 0xca */ 0x4a, 0x4a,
/* 0xcc */ 0x4b, 0x4b,
/* 0xce */ 0x4c, 0x4c,
/* 0xd0 */ 0x4d, 0x4d,
/* 0xd2 */ 0x4e, 0x4e,
/* 0xd4 */ 0x4f, 0x4f,
/* 0xd6 */ 0x50, 0x50,
/* 0xd8 */ 0x51, 0x51,
/* 0xda */ 0x52, 0x52,
/* 0xdc */ 0x53, 0x53,
/* 0xde */ 0x54, 0x54,
/* 0xe0 */ 0x55, 0x55,
/* 0xe2 */ 0x56, 0x56,
/* 0xe4 */ 0x57, 0x57,
/* 0xe6 */ 0x59, 0x59,
/* 0xe8 */ 0x6a, 0x6a,
/* 0xea */ 0x6b, 0x6b,
/* 0xec */ 0x71, 0x71,
/* 0xee */ 0x76, 0x76,
/* 0xf0 */ 0x77, 0x77,
/* 0xf2 */ 0x78, 0x78,
/* 0xf4 */ 0x79, 0x79,
/* 0xf6 */ 0x7a, 0x7a,
/* 0xf8 */ 0x26,
/* 0xf9 */ 0x2a,
/* 0xfa */ 0x2c,
/* 0xfb */ 0x3b,
/* 0xfc */ 0x58,
/* 0xfd */ 0x5a,
};
uint8_t rht_bit24_17[256] = {
/* 0x00 */ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
/* 0x10 */ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
/* 0x20 */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
/* 0x30 */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
/* 0x40 */ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
/* 0x50 */ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
/* 0x60 */ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
/* 0x70 */ 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
/* 0x80 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
/* 0x90 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
/* 0xa0 */ 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
/* 0xb0 */ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
/* 0xc0 */ 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
/* 0xd0 */ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
/* 0xd8 */ 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
/* 0xe0 */ 0x00, 0x00, 0x00, 0x00,
/* 0xe4 */ 0x24, 0x24, 0x24, 0x24,
/* 0xe8 */ 0x40, 0x40, 0x40, 0x40,
/* 0xec */ 0x5b, 0x5b, 0x5b, 0x5b,
/* 0xf0 */ 0x5d, 0x5d, 0x5d, 0x5d,
/* 0xf4 */ 0x7e, 0x7e, 0x7e, 0x7e,
/* 0xf8 */ 0x5e, 0x5e,
/* 0xfa */ 0x7d, 0x7d,
/* 0xfc */ 0x3c,
/* 0xfd */ 0x60,
/* 0xfe */ 0x7b,
};
uint8_t rht_bit15_8[256] = {
/* 0x00 */ 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
/* 0x08 */ 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
/* 0x10 */ 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
/* 0x18 */ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
/* 0x20 */ 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8,
/* 0x28 */ 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9,
/* 0x30 */ 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3,
/* 0x38 */ 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
/* 0x40 */ 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
/* 0x48 */ 0x81, 0x81, 0x81, 0x81,
/* 0x4c */ 0x84, 0x84, 0x84, 0x84,
/* 0x50 */ 0x85, 0x85, 0x85, 0x85,
/* 0x54 */ 0x86, 0x86, 0x86, 0x86,
/* 0x58 */ 0x88, 0x88, 0x88, 0x88,
/* 0x5c */ 0x92, 0x92, 0x92, 0x92,
/* 0x60 */ 0x9a, 0x9a, 0x9a, 0x9a,
/* 0x64 */ 0x9c, 0x9c, 0x9c, 0x9c,
/* 0x68 */ 0xa0, 0xa0, 0xa0, 0xa0,
/* 0x6c */ 0xa3, 0xa3, 0xa3, 0xa3,
/* 0x70 */ 0xa4, 0xa4, 0xa4, 0xa4,
/* 0x74 */ 0xa9, 0xa9, 0xa9, 0xa9,
/* 0x78 */ 0xaa, 0xaa, 0xaa, 0xaa,
/* 0x7c */ 0xad, 0xad, 0xad, 0xad,
/* 0x80 */ 0xb2, 0xb2, 0xb2, 0xb2,
/* 0x84 */ 0xb5, 0xb5, 0xb5, 0xb5,
/* 0x88 */ 0xb9, 0xb9, 0xb9, 0xb9,
/* 0x8c */ 0xba, 0xba, 0xba, 0xba,
/* 0x90 */ 0xbb, 0xbb, 0xbb, 0xbb,
/* 0x94 */ 0xbd, 0xbd, 0xbd, 0xbd,
/* 0x98 */ 0xbe, 0xbe, 0xbe, 0xbe,
/* 0x9c */ 0xc4, 0xc4, 0xc4, 0xc4,
/* 0xa0 */ 0xc6, 0xc6, 0xc6, 0xc6,
/* 0xa4 */ 0xe4, 0xe4, 0xe4, 0xe4,
/* 0xa8 */ 0xe8, 0xe8, 0xe8, 0xe8,
/* 0xac */ 0xe9, 0xe9, 0xe9, 0xe9,
/* 0xb0 */ 0x01, 0x01,
/* 0xb2 */ 0x87, 0x87,
/* 0xb4 */ 0x89, 0x89,
/* 0xb6 */ 0x8a, 0x8a,
/* 0xb8 */ 0x8b, 0x8b,
/* 0xba */ 0x8c, 0x8c,
/* 0xbc */ 0x8d, 0x8d,
/* 0xbe */ 0x8f, 0x8f,
/* 0xc0 */ 0x93, 0x93,
/* 0xc2 */ 0x95, 0x95,
/* 0xc4 */ 0x96, 0x96,
/* 0xc6 */ 0x97, 0x97,
/* 0xc8 */ 0x98, 0x98,
/* 0xca */ 0x9b, 0x9b,
/* 0xcc */ 0x9d, 0x9d,
/* 0xce */ 0x9e, 0x9e,
/* 0xd0 */ 0xa5, 0xa5,
/* 0xd2 */ 0xa6, 0xa6,
/* 0xd4 */ 0xa8, 0xa8,
/* 0xd6 */ 0xae, 0xae,
/* 0xd8 */ 0xaf, 0xaf,
/* 0xda */ 0xb4, 0xb4,
/* 0xdc */ 0xb6, 0xb6,
/* 0xde */ 0xb7, 0xb7,
/* 0xe0 */ 0xbc, 0xbc,
/* 0xe2 */ 0xbf, 0xbf,
/* 0xe4 */ 0xc5, 0xc5,
/* 0xe6 */ 0xe7, 0xe7,
/* 0xe8 */ 0xef, 0xef,
/* 0xea */ 0x09,
/* 0xeb */ 0x8e,
/* 0xec */ 0x90,
/* 0xed */ 0x91,
/* 0xee */ 0x94,
/* 0xef */ 0x9f,
/* 0xf0 */ 0xab,
/* 0xf1 */ 0xce,
/* 0xf2 */ 0xd7,
/* 0xf3 */ 0xe1,
/* 0xf4 */ 0xec,
/* 0xf5 */ 0xed,
};
/* below two non-overlapping tables are merged in order to save on L1D:
* - bits 15-11 for values 0x00-0x1f
* - bits 11-4 for values 0x60-0xff
* Note that there's no data between 0x20 and 0x5f, the caller must
* adjust its offsets by subtracting 0x40 for values 0x60 and above.
*/
uint8_t rht_bit15_11_11_4[192] = {
/* part used for bits 15-11 (0x00-0x1f) */
/* 0x00 */ 0x5c, 0x5c, 0x5c, 0x5c,
/* 0x04 */ 0xc3, 0xc3, 0xc3, 0xc3,
/* 0x08 */ 0xd0, 0xd0, 0xd0, 0xd0,
/* 0x0c */ 0x80, 0x80,
/* 0x0e */ 0x82, 0x82,
/* 0x10 */ 0x83, 0x83,
/* 0x12 */ 0xa2, 0xa2,
/* 0x14 */ 0xb8, 0xb8,
/* 0x16 */ 0xc2, 0xc2,
/* 0x18 */ 0xe0, 0xe0,
/* 0x1a */ 0xe2, 0xe2,
/* 0x1c */ 0x99,
/* 0x1d */ 0xa1,
/* 0x1e */ 0xa7,
/* 0x1f */ 0xac,
/* part used for bits 11-4 for 0xf600 (0x60-0xff), starting @0x20 */
/* 0x60 */ 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
/* 0x68 */ 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
/* 0x70 */ 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
/* 0x78 */ 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
/* 0x80 */ 0xc0, 0xc0, 0xc0, 0xc0,
/* 0x84 */ 0xc1, 0xc1, 0xc1, 0xc1,
/* 0x88 */ 0xc8, 0xc8, 0xc8, 0xc8,
/* 0x8c */ 0xc9, 0xc9, 0xc9, 0xc9,
/* 0x90 */ 0xca, 0xca, 0xca, 0xca,
/* 0x94 */ 0xcd, 0xcd, 0xcd, 0xcd,
/* 0x98 */ 0xd2, 0xd2, 0xd2, 0xd2,
/* 0x9c */ 0xd5, 0xd5, 0xd5, 0xd5,
/* 0xa0 */ 0xda, 0xda, 0xda, 0xda,
/* 0xa4 */ 0xdb, 0xdb, 0xdb, 0xdb,
/* 0xa8 */ 0xee, 0xee, 0xee, 0xee,
/* 0xac */ 0xf0, 0xf0, 0xf0, 0xf0,
/* 0xb0 */ 0xf2, 0xf2, 0xf2, 0xf2,
/* 0xb4 */ 0xf3, 0xf3, 0xf3, 0xf3,
/* 0xb8 */ 0xff, 0xff, 0xff, 0xff,
/* 0xbc */ 0xcb, 0xcb,
/* 0xbe */ 0xcc, 0xcc,
/* 0xc0 */ 0xd3, 0xd3,
/* 0xc2 */ 0xd4, 0xd4,
/* 0xc4 */ 0xd6, 0xd6,
/* 0xc6 */ 0xdd, 0xdd,
/* 0xc8 */ 0xde, 0xde,
/* 0xca */ 0xdf, 0xdf,
/* 0xcc */ 0xf1, 0xf1,
/* 0xce */ 0xf4, 0xf4,
/* 0xd0 */ 0xf5, 0xf5,
/* 0xd2 */ 0xf6, 0xf6,
/* 0xd4 */ 0xf7, 0xf7,
/* 0xd6 */ 0xf8, 0xf8,
/* 0xd8 */ 0xfa, 0xfa,
/* 0xda */ 0xfb, 0xfb,
/* 0xdc */ 0xfc, 0xfc,
/* 0xde */ 0xfd, 0xfd,
/* 0xe0 */ 0xfe, 0xfe,
/* 0xe2 */ 0x02,
/* 0xe3 */ 0x03,
/* 0xe4 */ 0x04,
/* 0xe5 */ 0x05,
/* 0xe6 */ 0x06,
/* 0xe7 */ 0x07,
/* 0xe8 */ 0x08,
/* 0xe9 */ 0x0b,
/* 0xea */ 0x0c,
/* 0xeb */ 0x0e,
/* 0xec */ 0x0f,
/* 0xed */ 0x10,
/* 0xee */ 0x11,
/* 0xef */ 0x12,
/* 0xf0 */ 0x13,
/* 0xf1 */ 0x14,
/* 0xf2 */ 0x15,
/* 0xf3 */ 0x17,
/* 0xf4 */ 0x18,
/* 0xf5 */ 0x19,
/* 0xf6 */ 0x1a,
/* 0xf7 */ 0x1b,
/* 0xf8 */ 0x1c,
/* 0xf9 */ 0x1d,
/* 0xfa */ 0x1e,
/* 0xfb */ 0x1f,
/* 0xfc */ 0x7f,
/* 0xfd */ 0xdc,
/* 0xfe */ 0xf9,
/* 0xff */ 0x0a,
/* Note, for [0xff], l==30 and bits 2..3 give 00:0x0a, 01:0x0d, 10:0x16, 11:EOS */
};
/* huffman-encode string <s> into the huff_tmp buffer and returns the amount
* of output bytes. The caller must ensure the output is large enough (ie at
* least 4 times as long as s).
*
* FIXME: bits are only counted for now, no code is emitted!
*/
int huff_enc(const char *s, char *out)
{
int bits = 0;
while (*s) {
bits += ht[(uint8_t)*s].b;
s++;
}
bits += 7;
/* FIXME: huffman code is not emitted yet. */
//memset(out, 'H', bits / 8);
return bits / 8;
}
/* pass a huffman string, it will decode it and return the new output size or
* -1 in case of error.
*
* The principle of the decoder is to lookup full bytes in reverse-huffman
* tables. Since we may need up to 30 bits and the word positions are not
* always multiples of 8, we build the code word by shifting the "current"
* 32-bit word and the "next" one of the appropriate amount of bits. Once
* the shift goes beyond 32, words are swapped and the "next" one is refilled
* with new bytes. Shift operations are cheap when done a single time like this.
* On 64-bit platforms it is possible to further improve this by storing both
* of them in a single word.
*/
int huff_dec(const uint8_t *huff, int hlen, char *out, int olen)
{
char *out_start = out;
char *out_end = out + olen;
const uint8_t *huff_end = huff + hlen;
uint32_t curr = 0;
uint32_t next = 0;
uint32_t shift;
uint32_t code; /* The 30-bit code being looked up, MSB-aligned */
uint8_t sym;
int bleft; /* bits left */
int l;
code = 0;
shift = 64; // start with an empty buffer
bleft = hlen << 3;
while (bleft > 0 && out != out_end) {
while (shift >= 32) {
curr = next;
/* read up to 4 bytes into next */
next = 0;
if (huff + 4 <= huff_end) {
next = read_n32(huff);
huff += 4;
}
else {
/* note: we append 0 and not 0xff so that we can
* distinguish shifted bits from a really inserted
* EOS.
*/
next = (((huff + 0 < huff_end) ? (uint32_t)huff[0] : 0x00) << 24) +
(((huff + 1 < huff_end) ? (uint32_t)huff[1] : 0x00) << 16) +
(((huff + 2 < huff_end) ? (uint32_t)huff[2] : 0x00) << 8) +
((huff + 3 < huff_end) ? (uint32_t)huff[3] : 0x00);
huff = huff_end;
}
shift -= 32;
}
/* curr:next contain 64 bit of huffman code */
code = curr;
if (shift)
code = (code << shift) + (next >> (32 - shift));
/* now we necessarily have 32 bits available */
if (code < 0xfe000000) {
/* single byte */
sym = code >> 24;
l = sym < 0xb8 ?
sym < 0x50 ? 5 : 6 :
sym < 0xf8 ? 7 : 8;
sym = rht_bit31_24[code >> 24];
}
else if (code < 0xfffe0000) {
/* two bytes, 0xfe + 2 bits or 0xff + 2..7 bits */
sym = code >> 17;
l = sym < 0xe0 ?
sym < 0xa0 ? 10 : sym < 0xd0 ? 11 : 12 :
sym < 0xf8 ? 13 : sym < 0xfc ? 14 : 15;
sym = rht_bit24_17[(code >> 17) & 0xff];
}
else if (code < 0xffff0000) { /* 3..5 bits */
/* 0xff + 0xfe + 3..5 bits or
* 0xff + 0xff + 5..8 bits for values till 0xf5
*/
sym = (code >> 11) & 0x1f;
l = sym < 0x0c ? 19 : sym < 0x1c ? 20 : 21;
sym = rht_bit15_11_11_4[(code >> 11) & 0x1f];
}
else if (code < 0xfffff600) { /* 5..8 bits */
/* that's 0xff + 0xff */
sym = code >> 8;
l = sym < 0xb0 ?
sym < 0x48 ? 21 : 22 :
sym < 0xea ? 23 : 24;
sym = rht_bit15_8[(code >> 8) & 0xff];
}
else {
/* 0xff 0xff 0xf6..0xff */
sym = code >> 4; /* sym = 0x60..0xff */
l = sym < 0xbc ?
sym < 0x80 ? 25 : 26 :
sym < 0xe2 ? 27 : sym < 0xff ? 28 : 30;
if (sym < 0xff)
sym = rht_bit15_11_11_4[((code >> 4) & 0xff) - 0x40L];
else if ((code & 0xff) == 0xf0)
sym = 10;
else if ((code & 0xff) == 0xf4)
sym = 13;
else if ((code & 0xff) == 0xf8)
sym = 22;
else { // 0xfc : EOS
break;
}
}
if (!l || bleft - l < 0)
break;
bleft -= l;
shift += l;
*out++ = sym;
}
if (bleft > 0) {
/* some bits were not consumed after the last code, they must
* match EOS (ie: all ones) and there must be 7 bits or less.
* (7541#5.2).
*/
if (bleft > 7)
return -1;
if ((code & -(1 << (32 - bleft))) != (uint32_t)-(1 << (32 - bleft)))
return -1;
}
if (out < out_end)
*out = 0; // end of string whenever possible
return out - out_start;
}