diff options
Diffstat (limited to 'src/hpack-huff.c')
-rw-r--r-- | src/hpack-huff.c | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/src/hpack-huff.c b/src/hpack-huff.c new file mode 100644 index 0000000..77743be --- /dev/null +++ b/src/hpack-huff.c @@ -0,0 +1,861 @@ +/* + * 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; +} |