Coverage Report

Created: 2026-08-17 07:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/network/access/http2/huffman.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:critical reason:network-protocol
4
5
#include "bitstreams_p.h"
6
#include "huffman_p.h"
7
8
#include <QtCore/qbytearray.h>
9
10
#include <algorithm>
11
#include <limits>
12
13
QT_BEGIN_NAMESPACE
14
15
namespace HPack
16
{
17
18
/*
19
    The static Huffman code used here was extracted from:
20
    https://http2.github.io/http2-spec/compression.html#huffman.code
21
22
    This code was generated from statistics obtained on a large
23
    sample of HTTP headers. It is a canonical Huffman code
24
    with some tweaking to ensure that no symbol has a unique
25
    code length. All codes were left-aligned - for implementation
26
    convenience.
27
28
    Using binary trees to implement decoding would be prohibitively
29
    expensive (both memory and time-wise). Instead we use a table-based
30
    approach and any given code itself works as an index into such table(s).
31
    We have 256 possible byte values and code lengths in
32
    a range [5, 26]. This would require a huge table (and most of entries
33
    would be 'wasted', since we only have to encode 256 elements).
34
    Instead we use multi-level tables. The first level table
35
    is using 9-bit length index; some entries in this table are 'terminal',
36
    some reference the next level table(s).
37
38
    For example, bytes with values 48 and 49 (ASCII codes for '0' and '1')
39
    both have code length 5, Huffman codes are: 00000 and 00001. They
40
    both are placed in the 'root' table,
41
    the 'root' table has index length == 9:
42
    [00000 | 4 remaining bits]
43
     ...
44
    [00001 | 4 remaining bits]
45
46
    All entries with indices between these two will 'point' to value 48
47
    with bitLength == 5 so that bit stream (for example) 000001010 will be
48
    decoded as: 48 + "put 1010 back into bitstream".
49
50
    A good description can be found here:
51
    http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art007
52
    or just google "Efficient Huffman Decoding".
53
    Also see comments below about 'filling holes'.
54
*/
55
56
namespace
57
{
58
59
const CodeEntry staticHuffmanCodeTable[]
60
{
61
    {  0, 0xffc00000ul, 13},  //     11111111|11000
62
    {  1, 0xffffb000ul, 23},  //     11111111|11111111|1011000
63
    {  2, 0xfffffe20ul, 28},  //     11111111|11111111|11111110|0010
64
    {  3, 0xfffffe30ul, 28},  //     11111111|11111111|11111110|0011
65
    {  4, 0xfffffe40ul, 28},  //     11111111|11111111|11111110|0100
66
    {  5, 0xfffffe50ul, 28},  //     11111111|11111111|11111110|0101
67
    {  6, 0xfffffe60ul, 28},  //     11111111|11111111|11111110|0110
68
    {  7, 0xfffffe70ul, 28},  //     11111111|11111111|11111110|0111
69
    {  8, 0xfffffe80ul, 28},  //     11111111|11111111|11111110|1000
70
    {  9, 0xffffea00ul, 24},  //     11111111|11111111|11101010
71
    { 10, 0xfffffff0ul, 30},  //     11111111|11111111|11111111|111100
72
    { 11, 0xfffffe90ul, 28},  //     11111111|11111111|11111110|1001
73
    { 12, 0xfffffea0ul, 28},  //     11111111|11111111|11111110|1010
74
    { 13, 0xfffffff4ul, 30},  //     11111111|11111111|11111111|111101
75
    { 14, 0xfffffeb0ul, 28},  //     11111111|11111111|11111110|1011
76
    { 15, 0xfffffec0ul, 28},  //     11111111|11111111|11111110|1100
77
    { 16, 0xfffffed0ul, 28},  //     11111111|11111111|11111110|1101
78
    { 17, 0xfffffee0ul, 28},  //     11111111|11111111|11111110|1110
79
    { 18, 0xfffffef0ul, 28},  //     11111111|11111111|11111110|1111
80
    { 19, 0xffffff00ul, 28},  //     11111111|11111111|11111111|0000
81
    { 20, 0xffffff10ul, 28},  //     11111111|11111111|11111111|0001
82
    { 21, 0xffffff20ul, 28},  //     11111111|11111111|11111111|0010
83
    { 22, 0xfffffff8ul, 30},  //     11111111|11111111|11111111|111110
84
    { 23, 0xffffff30ul, 28},  //     11111111|11111111|11111111|0011
85
    { 24, 0xffffff40ul, 28},  //     11111111|11111111|11111111|0100
86
    { 25, 0xffffff50ul, 28},  //     11111111|11111111|11111111|0101
87
    { 26, 0xffffff60ul, 28},  //     11111111|11111111|11111111|0110
88
    { 27, 0xffffff70ul, 28},  //     11111111|11111111|11111111|0111
89
    { 28, 0xffffff80ul, 28},  //     11111111|11111111|11111111|1000
90
    { 29, 0xffffff90ul, 28},  //     11111111|11111111|11111111|1001
91
    { 30, 0xffffffa0ul, 28},  //     11111111|11111111|11111111|1010
92
    { 31, 0xffffffb0ul, 28},  //     11111111|11111111|11111111|1011
93
    { 32, 0x50000000ul,  6},  // ' ' 010100
94
    { 33, 0xfe000000ul, 10},  // '!' 11111110|00
95
    { 34, 0xfe400000ul, 10},  // '"' 11111110|01
96
    { 35, 0xffa00000ul, 12},  // '#' 11111111|1010
97
    { 36, 0xffc80000ul, 13},  // '$' 11111111|11001
98
    { 37, 0x54000000ul,  6},  // '%' 010101
99
    { 38, 0xf8000000ul,  8},  // '&' 11111000
100
    { 39, 0xff400000ul, 11},  // ''' 11111111|010
101
    { 40, 0xfe800000ul, 10},  // '(' 11111110|10
102
    { 41, 0xfec00000ul, 10},  // ')' 11111110|11
103
    { 42, 0xf9000000ul,  8},  // '*' 11111001
104
    { 43, 0xff600000ul, 11},  // '+' 11111111|011
105
    { 44, 0xfa000000ul,  8},  // ',' 11111010
106
    { 45, 0x58000000ul,  6},  // '-' 010110
107
    { 46, 0x5c000000ul,  6},  // '.' 010111
108
    { 47, 0x60000000ul,  6},  // '/' 011000
109
    { 48, 0x00000000ul,  5},  // '0' 00000
110
    { 49, 0x08000000ul,  5},  // '1' 00001
111
    { 50, 0x10000000ul,  5},  // '2' 00010
112
    { 51, 0x64000000ul,  6},  // '3' 011001
113
    { 52, 0x68000000ul,  6},  // '4' 011010
114
    { 53, 0x6c000000ul,  6},  // '5' 011011
115
    { 54, 0x70000000ul,  6},  // '6' 011100
116
    { 55, 0x74000000ul,  6},  // '7' 011101
117
    { 56, 0x78000000ul,  6},  // '8' 011110
118
    { 57, 0x7c000000ul,  6},  // '9' 011111
119
    { 58, 0xb8000000ul,  7},  // ':' 1011100
120
    { 59, 0xfb000000ul,  8},  // ';' 11111011
121
    { 60, 0xfff80000ul, 15},  // '<' 11111111|1111100
122
    { 61, 0x80000000ul,  6},  // '=' 100000
123
    { 62, 0xffb00000ul, 12},  // '>' 11111111|1011
124
    { 63, 0xff000000ul, 10},  // '?' 11111111|00
125
    { 64, 0xffd00000ul, 13},  // '@' 11111111|11010
126
    { 65, 0x84000000ul,  6},  // 'A' 100001
127
    { 66, 0xba000000ul,  7},  // 'B' 1011101
128
    { 67, 0xbc000000ul,  7},  // 'C' 1011110
129
    { 68, 0xbe000000ul,  7},  // 'D' 1011111
130
    { 69, 0xc0000000ul,  7},  // 'E' 1100000
131
    { 70, 0xc2000000ul,  7},  // 'F' 1100001
132
    { 71, 0xc4000000ul,  7},  // 'G' 1100010
133
    { 72, 0xc6000000ul,  7},  // 'H' 1100011
134
    { 73, 0xc8000000ul,  7},  // 'I' 1100100
135
    { 74, 0xca000000ul,  7},  // 'J' 1100101
136
    { 75, 0xcc000000ul,  7},  // 'K' 1100110
137
    { 76, 0xce000000ul,  7},  // 'L' 1100111
138
    { 77, 0xd0000000ul,  7},  // 'M' 1101000
139
    { 78, 0xd2000000ul,  7},  // 'N' 1101001
140
    { 79, 0xd4000000ul,  7},  // 'O' 1101010
141
    { 80, 0xd6000000ul,  7},  // 'P' 1101011
142
    { 81, 0xd8000000ul,  7},  // 'Q' 1101100
143
    { 82, 0xda000000ul,  7},  // 'R' 1101101
144
    { 83, 0xdc000000ul,  7},  // 'S' 1101110
145
    { 84, 0xde000000ul,  7},  // 'T' 1101111
146
    { 85, 0xe0000000ul,  7},  // 'U' 1110000
147
    { 86, 0xe2000000ul,  7},  // 'V' 1110001
148
    { 87, 0xe4000000ul,  7},  // 'W' 1110010
149
    { 88, 0xfc000000ul,  8},  // 'X' 11111100
150
    { 89, 0xe6000000ul,  7},  // 'Y' 1110011
151
    { 90, 0xfd000000ul,  8},  // 'Z' 11111101
152
    { 91, 0xffd80000ul, 13},  // '[' 11111111|11011
153
    { 92, 0xfffe0000ul, 19},  // '\' 11111111|11111110|000
154
    { 93, 0xffe00000ul, 13},  // ']' 11111111|11100
155
    { 94, 0xfff00000ul, 14},  // '^' 11111111|111100
156
    { 95, 0x88000000ul,  6},  // '_' 100010
157
    { 96, 0xfffa0000ul, 15},  // '`' 11111111|1111101
158
    { 97, 0x18000000ul,  5},  // 'a' 00011
159
    { 98, 0x8c000000ul,  6},  // 'b' 100011
160
    { 99, 0x20000000ul,  5},  // 'c' 00100
161
    {100, 0x90000000ul,  6},  // 'd' 100100
162
    {101, 0x28000000ul,  5},  // 'e' 00101
163
    {102, 0x94000000ul,  6},  // 'f' 100101
164
    {103, 0x98000000ul,  6},  // 'g' 100110
165
    {104, 0x9c000000ul,  6},  // 'h' 100111
166
    {105, 0x30000000ul,  5},  // 'i' 00110
167
    {106, 0xe8000000ul,  7},  // 'j' 1110100
168
    {107, 0xea000000ul,  7},  // 'k' 1110101
169
    {108, 0xa0000000ul,  6},  // 'l' 101000
170
    {109, 0xa4000000ul,  6},  // 'm' 101001
171
    {110, 0xa8000000ul,  6},  // 'n' 101010
172
    {111, 0x38000000ul,  5},  // 'o' 00111
173
    {112, 0xac000000ul,  6},  // 'p' 101011
174
    {113, 0xec000000ul,  7},  // 'q' 1110110
175
    {114, 0xb0000000ul,  6},  // 'r' 101100
176
    {115, 0x40000000ul,  5},  // 's' 01000
177
    {116, 0x48000000ul,  5},  // 't' 01001
178
    {117, 0xb4000000ul,  6},  // 'u' 101101
179
    {118, 0xee000000ul,  7},  // 'v' 1110111
180
    {119, 0xf0000000ul,  7},  // 'w' 1111000
181
    {120, 0xf2000000ul,  7},  // 'x' 1111001
182
    {121, 0xf4000000ul,  7},  // 'y' 1111010
183
    {122, 0xf6000000ul,  7},  // 'z' 1111011
184
    {123, 0xfffc0000ul, 15},  // '{' 11111111|1111110
185
    {124, 0xff800000ul, 11},  // '|' 11111111|100
186
    {125, 0xfff40000ul, 14},  // '}' 11111111|111101
187
    {126, 0xffe80000ul, 13},  // '~' 11111111|11101
188
    {127, 0xffffffc0ul, 28},  //     11111111|11111111|11111111|1100
189
    {128, 0xfffe6000ul, 20},  //     11111111|11111110|0110
190
    {129, 0xffff4800ul, 22},  //     11111111|11111111|010010
191
    {130, 0xfffe7000ul, 20},  //     11111111|11111110|0111
192
    {131, 0xfffe8000ul, 20},  //     11111111|11111110|1000
193
    {132, 0xffff4c00ul, 22},  //     11111111|11111111|010011
194
    {133, 0xffff5000ul, 22},  //     11111111|11111111|010100
195
    {134, 0xffff5400ul, 22},  //     11111111|11111111|010101
196
    {135, 0xffffb200ul, 23},  //     11111111|11111111|1011001
197
    {136, 0xffff5800ul, 22},  //     11111111|11111111|010110
198
    {137, 0xffffb400ul, 23},  //     11111111|11111111|1011010
199
    {138, 0xffffb600ul, 23},  //     11111111|11111111|1011011
200
    {139, 0xffffb800ul, 23},  //     11111111|11111111|1011100
201
    {140, 0xffffba00ul, 23},  //     11111111|11111111|1011101
202
    {141, 0xffffbc00ul, 23},  //     11111111|11111111|1011110
203
    {142, 0xffffeb00ul, 24},  //     11111111|11111111|11101011
204
    {143, 0xffffbe00ul, 23},  //     11111111|11111111|1011111
205
    {144, 0xffffec00ul, 24},  //     11111111|11111111|11101100
206
    {145, 0xffffed00ul, 24},  //     11111111|11111111|11101101
207
    {146, 0xffff5c00ul, 22},  //     11111111|11111111|010111
208
    {147, 0xffffc000ul, 23},  //     11111111|11111111|1100000
209
    {148, 0xffffee00ul, 24},  //     11111111|11111111|11101110
210
    {149, 0xffffc200ul, 23},  //     11111111|11111111|1100001
211
    {150, 0xffffc400ul, 23},  //     11111111|11111111|1100010
212
    {151, 0xffffc600ul, 23},  //     11111111|11111111|1100011
213
    {152, 0xffffc800ul, 23},  //     11111111|11111111|1100100
214
    {153, 0xfffee000ul, 21},  //     11111111|11111110|11100
215
    {154, 0xffff6000ul, 22},  //     11111111|11111111|011000
216
    {155, 0xffffca00ul, 23},  //     11111111|11111111|1100101
217
    {156, 0xffff6400ul, 22},  //     11111111|11111111|011001
218
    {157, 0xffffcc00ul, 23},  //     11111111|11111111|1100110
219
    {158, 0xffffce00ul, 23},  //     11111111|11111111|1100111
220
    {159, 0xffffef00ul, 24},  //     11111111|11111111|11101111
221
    {160, 0xffff6800ul, 22},  //     11111111|11111111|011010
222
    {161, 0xfffee800ul, 21},  //     11111111|11111110|11101
223
    {162, 0xfffe9000ul, 20},  //     11111111|11111110|1001
224
    {163, 0xffff6c00ul, 22},  //     11111111|11111111|011011
225
    {164, 0xffff7000ul, 22},  //     11111111|11111111|011100
226
    {165, 0xffffd000ul, 23},  //     11111111|11111111|1101000
227
    {166, 0xffffd200ul, 23},  //     11111111|11111111|1101001
228
    {167, 0xfffef000ul, 21},  //     11111111|11111110|11110
229
    {168, 0xffffd400ul, 23},  //     11111111|11111111|1101010
230
    {169, 0xffff7400ul, 22},  //     11111111|11111111|011101
231
    {170, 0xffff7800ul, 22},  //     11111111|11111111|011110
232
    {171, 0xfffff000ul, 24},  //     11111111|11111111|11110000
233
    {172, 0xfffef800ul, 21},  //     11111111|11111110|11111
234
    {173, 0xffff7c00ul, 22},  //     11111111|11111111|011111
235
    {174, 0xffffd600ul, 23},  //     11111111|11111111|1101011
236
    {175, 0xffffd800ul, 23},  //     11111111|11111111|1101100
237
    {176, 0xffff0000ul, 21},  //     11111111|11111111|00000
238
    {177, 0xffff0800ul, 21},  //     11111111|11111111|00001
239
    {178, 0xffff8000ul, 22},  //     11111111|11111111|100000
240
    {179, 0xffff1000ul, 21},  //     11111111|11111111|00010
241
    {180, 0xffffda00ul, 23},  //     11111111|11111111|1101101
242
    {181, 0xffff8400ul, 22},  //     11111111|11111111|100001
243
    {182, 0xffffdc00ul, 23},  //     11111111|11111111|1101110
244
    {183, 0xffffde00ul, 23},  //     11111111|11111111|1101111
245
    {184, 0xfffea000ul, 20},  //     11111111|11111110|1010
246
    {185, 0xffff8800ul, 22},  //     11111111|11111111|100010
247
    {186, 0xffff8c00ul, 22},  //     11111111|11111111|100011
248
    {187, 0xffff9000ul, 22},  //     11111111|11111111|100100
249
    {188, 0xffffe000ul, 23},  //     11111111|11111111|1110000
250
    {189, 0xffff9400ul, 22},  //     11111111|11111111|100101
251
    {190, 0xffff9800ul, 22},  //     11111111|11111111|100110
252
    {191, 0xffffe200ul, 23},  //     11111111|11111111|1110001
253
    {192, 0xfffff800ul, 26},  //     11111111|11111111|11111000|00
254
    {193, 0xfffff840ul, 26},  //     11111111|11111111|11111000|01
255
    {194, 0xfffeb000ul, 20},  //     11111111|11111110|1011
256
    {195, 0xfffe2000ul, 19},  //     11111111|11111110|001
257
    {196, 0xffff9c00ul, 22},  //     11111111|11111111|100111
258
    {197, 0xffffe400ul, 23},  //     11111111|11111111|1110010
259
    {198, 0xffffa000ul, 22},  //     11111111|11111111|101000
260
    {199, 0xfffff600ul, 25},  //     11111111|11111111|11110110|0
261
    {200, 0xfffff880ul, 26},  //     11111111|11111111|11111000|10
262
    {201, 0xfffff8c0ul, 26},  //     11111111|11111111|11111000|11
263
    {202, 0xfffff900ul, 26},  //     11111111|11111111|11111001|00
264
    {203, 0xfffffbc0ul, 27},  //     11111111|11111111|11111011|110
265
    {204, 0xfffffbe0ul, 27},  //     11111111|11111111|11111011|111
266
    {205, 0xfffff940ul, 26},  //     11111111|11111111|11111001|01
267
    {206, 0xfffff100ul, 24},  //     11111111|11111111|11110001
268
    {207, 0xfffff680ul, 25},  //     11111111|11111111|11110110|1
269
    {208, 0xfffe4000ul, 19},  //     11111111|11111110|010
270
    {209, 0xffff1800ul, 21},  //     11111111|11111111|00011
271
    {210, 0xfffff980ul, 26},  //     11111111|11111111|11111001|10
272
    {211, 0xfffffc00ul, 27},  //     11111111|11111111|11111100|000
273
    {212, 0xfffffc20ul, 27},  //     11111111|11111111|11111100|001
274
    {213, 0xfffff9c0ul, 26},  //     11111111|11111111|11111001|11
275
    {214, 0xfffffc40ul, 27},  //     11111111|11111111|11111100|010
276
    {215, 0xfffff200ul, 24},  //     11111111|11111111|11110010
277
    {216, 0xffff2000ul, 21},  //     11111111|11111111|00100
278
    {217, 0xffff2800ul, 21},  //     11111111|11111111|00101
279
    {218, 0xfffffa00ul, 26},  //     11111111|11111111|11111010|00
280
    {219, 0xfffffa40ul, 26},  //     11111111|11111111|11111010|01
281
    {220, 0xffffffd0ul, 28},  //     11111111|11111111|11111111|1101
282
    {221, 0xfffffc60ul, 27},  //     11111111|11111111|11111100|011
283
    {222, 0xfffffc80ul, 27},  //     11111111|11111111|11111100|100
284
    {223, 0xfffffca0ul, 27},  //     11111111|11111111|11111100|101
285
    {224, 0xfffec000ul, 20},  //     11111111|11111110|1100
286
    {225, 0xfffff300ul, 24},  //     11111111|11111111|11110011
287
    {226, 0xfffed000ul, 20},  //     11111111|11111110|1101
288
    {227, 0xffff3000ul, 21},  //     11111111|11111111|00110
289
    {228, 0xffffa400ul, 22},  //     11111111|11111111|101001
290
    {229, 0xffff3800ul, 21},  //     11111111|11111111|00111
291
    {230, 0xffff4000ul, 21},  //     11111111|11111111|01000
292
    {231, 0xffffe600ul, 23},  //     11111111|11111111|1110011
293
    {232, 0xffffa800ul, 22},  //     11111111|11111111|101010
294
    {233, 0xffffac00ul, 22},  //     11111111|11111111|101011
295
    {234, 0xfffff700ul, 25},  //     11111111|11111111|11110111|0
296
    {235, 0xfffff780ul, 25},  //     11111111|11111111|11110111|1
297
    {236, 0xfffff400ul, 24},  //     11111111|11111111|11110100
298
    {237, 0xfffff500ul, 24},  //     11111111|11111111|11110101
299
    {238, 0xfffffa80ul, 26},  //     11111111|11111111|11111010|10
300
    {239, 0xffffe800ul, 23},  //     11111111|11111111|1110100
301
    {240, 0xfffffac0ul, 26},  //     11111111|11111111|11111010|11
302
    {241, 0xfffffcc0ul, 27},  //     11111111|11111111|11111100|110
303
    {242, 0xfffffb00ul, 26},  //     11111111|11111111|11111011|00
304
    {243, 0xfffffb40ul, 26},  //     11111111|11111111|11111011|01
305
    {244, 0xfffffce0ul, 27},  //     11111111|11111111|11111100|111
306
    {245, 0xfffffd00ul, 27},  //     11111111|11111111|11111101|000
307
    {246, 0xfffffd20ul, 27},  //     11111111|11111111|11111101|001
308
    {247, 0xfffffd40ul, 27},  //     11111111|11111111|11111101|010
309
    {248, 0xfffffd60ul, 27},  //     11111111|11111111|11111101|011
310
    {249, 0xffffffe0ul, 28},  //     11111111|11111111|11111111|1110
311
    {250, 0xfffffd80ul, 27},  //     11111111|11111111|11111101|100
312
    {251, 0xfffffda0ul, 27},  //     11111111|11111111|11111101|101
313
    {252, 0xfffffdc0ul, 27},  //     11111111|11111111|11111101|110
314
    {253, 0xfffffde0ul, 27},  //     11111111|11111111|11111101|111
315
    {254, 0xfffffe00ul, 27},  //     11111111|11111111|11111110|000
316
    {255, 0xfffffb80ul, 26},  //     11111111|11111111|11111011|10
317
    {256, 0xfffffffcul, 30}   // EOS 11111111|11111111|11111111|111111
318
};
319
320
void write_huffman_code(BitOStream &outputStream, CodeEntry code)
321
0
{
322
    // Append octet by octet.
323
0
    auto bitLength = code.bitLength;
324
0
    const auto hc = code.huffmanCode >> (32 - bitLength);
325
326
0
    if (bitLength > 24) {
327
0
        outputStream.writeBits(uchar(hc >> 24), bitLength - 24);
328
0
        bitLength = 24;
329
0
    }
330
331
0
    if (bitLength > 16) {
332
0
        outputStream.writeBits(uchar(hc >> 16), bitLength - 16);
333
0
        bitLength = 16;
334
0
    }
335
336
0
    if (bitLength > 8) {
337
0
        outputStream.writeBits(uchar(hc >> 8), bitLength - 8);
338
0
        bitLength = 8;
339
0
    }
340
341
0
    outputStream.writeBits(uchar(hc), bitLength);
342
0
}
343
344
}
345
346
// That's from HPACK's specs - we deal with octets.
347
static_assert(std::numeric_limits<uchar>::digits == 8, "octets expected");
348
349
quint64 huffman_encoded_bit_length(QByteArrayView inputData)
350
0
{
351
0
    quint64 bitLength = 0;
352
0
    for (int i = 0, e = inputData.size(); i < e; ++i)
353
0
        bitLength += staticHuffmanCodeTable[int(inputData[i])].bitLength;
354
355
0
    return bitLength;
356
0
}
357
358
void huffman_encode_string(QByteArrayView inputData, BitOStream &outputStream)
359
0
{
360
0
    for (int i = 0, e = inputData.size(); i < e; ++i) {
361
0
        const auto value = uchar(inputData[i]);
362
0
        write_huffman_code(outputStream, staticHuffmanCodeTable[value]);
363
0
    }
364
365
    // Pad bits ...
366
0
    if (outputStream.bitLength() % 8)
367
0
        outputStream.writeBits(0xff, 8 - outputStream.bitLength() % 8);
368
0
}
369
370
static constexpr
371
bool padding_is_valid(quint32 chunk, quint32 nBits)
372
0
{
373
0
    Q_ASSERT(nBits);
374
375
    // HPACK, 5.2: "A padding strictly longer than 7 bits MUST be
376
    // treated as a decoding error."
377
0
    if (nBits > 7)
378
0
        return false;
379
    // HPACK, 5.2:
380
    // "A padding not corresponding to the most significant bits
381
    // of the code for the EOS symbol MUST be treated as a decoding error."
382
0
    return (chunk >> (32 - nBits)) == quint32((1 << nBits) - 1);
383
0
}
384
385
HuffmanDecoder::HuffmanDecoder()
386
    : minCodeLength()
387
0
{
388
0
    const auto nCodes = sizeof staticHuffmanCodeTable / sizeof staticHuffmanCodeTable[0];
389
390
0
    std::vector<CodeEntry> symbols(staticHuffmanCodeTable, staticHuffmanCodeTable + nCodes);
391
    // Now we sort: by bit length first (in the descending order) and by the symbol
392
    // value (descending). Descending order: to make sure we do not create prefix tables with
393
    // short 'indexLength' first and having longer codes that do not fit into such tables later.
394
0
    std::sort(symbols.begin(), symbols.end(), [](CodeEntry code1, CodeEntry code2) {
395
0
        if (code1.bitLength == code2.bitLength)
396
0
            return code1.byteValue > code2.byteValue;
397
0
        return code1.bitLength > code2.bitLength;
398
0
    });
399
400
0
    minCodeLength = symbols.back().bitLength; // The shortest one, currently it's 5.
401
402
    // TODO: add a verification - Huffman codes
403
    // within a given bit length range also
404
    // should be in descending order.
405
406
    // Initialize 'prefixTables' and 'tableData'.
407
0
    addTable(0, quint32(BitConstants::rootPrefix)); // 'root' table.
408
409
0
    for (const auto &s : symbols) {
410
0
        quint32 tableIndex = 0;
411
0
        while (true) {
412
0
            Q_ASSERT(tableIndex < prefixTables.size());
413
            // Note, by value - since prefixTables will be updated in between.
414
0
            const auto table = prefixTables[tableIndex];
415
            // We skip prefixed bits (if any) and use indexed bits only:
416
0
            const auto entryIndex = s.huffmanCode << table.prefixLength >> (32 - table.indexLength);
417
            // Again, by value.
418
0
            PrefixTableEntry entry = tableEntry(table, entryIndex);
419
            // How many bits were coded by previous tables and this table:
420
0
            const auto codedLength = table.prefixLength + table.indexLength;
421
0
            if (codedLength < s.bitLength) {
422
                // We have to add a new prefix table ... (if it's not done yet).
423
0
                if (!entry.bitLength) {
424
0
                    entry.nextTable = addTable(codedLength, std::min<quint32>(quint32(BitConstants::childPrefix),
425
0
                                                                              s.bitLength - codedLength));
426
0
                    entry.bitLength = s.bitLength;
427
0
                    entry.byteValue = s.byteValue;
428
0
                    setTableEntry(table, entryIndex, entry);
429
0
                }
430
0
                tableIndex = entry.nextTable;
431
0
            } else {
432
                // We found the slot for our code (terminal entry):
433
0
                entry.byteValue = s.byteValue;
434
0
                entry.bitLength = s.bitLength;
435
                // Refer to our own table as 'nextTable':
436
0
                entry.nextTable = tableIndex;
437
0
                setTableEntry(table, entryIndex, entry);
438
0
                break;
439
0
            }
440
0
        }
441
0
    }
442
443
    // Now, we have a table(s) and have to fill 'holes' to
444
    // 'fix' terminal entries.
445
0
    for (const auto &table : prefixTables) {
446
0
        const quint32 codedLength = table.prefixLength + table.indexLength;
447
0
        for (quint32 j = 0; j < table.size();) {
448
0
            const PrefixTableEntry &entry = tableEntry(table, j);
449
0
            if (entry.bitLength && entry.bitLength < codedLength) {
450
0
                const quint32 range = 1 << (codedLength - entry.bitLength);
451
0
                for (quint32 k = 1; k < range; ++k)
452
0
                    setTableEntry(table, j + k, entry);
453
0
                j += range;
454
0
            } else {
455
0
                ++j;
456
0
            }
457
0
        }
458
0
    }
459
0
}
460
461
bool HuffmanDecoder::decodeStream(BitIStream &inputStream, QByteArray &outputBuffer)
462
0
{
463
0
    while (true) {
464
0
        quint32 chunk = 0;
465
0
        const quint32 readBits = inputStream.peekBits(inputStream.streamOffset(), 32, &chunk);
466
0
        if (!readBits)
467
0
            return !inputStream.hasMoreBits();
468
469
0
        if (readBits < minCodeLength) {
470
0
            inputStream.skipBits(readBits);
471
0
            return padding_is_valid(chunk, readBits);
472
0
        }
473
474
0
        quint32 tableIndex = 0;
475
0
        const PrefixTable *table = &prefixTables[tableIndex];
476
0
        quint32 entryIndex = chunk >> (32 - table->indexLength);
477
0
        PrefixTableEntry entry = tableEntry(*table, entryIndex);
478
479
0
        while (true) {
480
0
            if (entry.nextTable == tableIndex)
481
0
                break;
482
483
0
            tableIndex = entry.nextTable;
484
0
            table = &prefixTables[tableIndex];
485
0
            entryIndex = chunk << table->prefixLength >> (32 - table->indexLength);
486
0
            entry = tableEntry(*table, entryIndex);
487
0
        }
488
489
0
        if (entry.bitLength > readBits) {
490
0
            inputStream.skipBits(readBits);
491
0
            return padding_is_valid(chunk, readBits);
492
0
        }
493
494
0
        if (!entry.bitLength || entry.byteValue == 256) {
495
            //EOS (256) == compression error (HPACK).
496
0
            inputStream.skipBits(readBits);
497
0
            return false;
498
0
        }
499
500
0
        outputBuffer.append(entry.byteValue);
501
0
        inputStream.skipBits(entry.bitLength);
502
0
    }
503
504
0
    return false;
505
0
}
506
507
quint32 HuffmanDecoder::addTable(quint32 prefix, quint32 index)
508
0
{
509
0
    PrefixTable newTable{prefix, index};
510
0
    newTable.offset = quint32(tableData.size());
511
0
    prefixTables.push_back(newTable);
512
    // Add entries for this table:
513
0
    tableData.resize(tableData.size() + newTable.size());
514
515
0
    return quint32(prefixTables.size() - 1);
516
0
}
517
518
PrefixTableEntry HuffmanDecoder::tableEntry(PrefixTable table, quint32 index)
519
0
{
520
0
    Q_ASSERT(index < table.size());
521
0
    return tableData[table.offset + index];
522
0
}
523
524
void HuffmanDecoder::setTableEntry(PrefixTable table, quint32 index,
525
                                   PrefixTableEntry entry)
526
0
{
527
0
    Q_ASSERT(index < table.size());
528
0
    tableData[table.offset + index] = entry;
529
0
}
530
531
bool huffman_decode_string(BitIStream &inputStream, QByteArray *outputBuffer)
532
0
{
533
0
    Q_ASSERT(outputBuffer);
534
535
0
    static HuffmanDecoder decoder;
536
0
    return decoder.decodeStream(inputStream, *outputBuffer);
537
0
}
538
539
}
540
541
QT_END_NAMESPACE