29
29
#include <stdio.h>
30
30
31
31
#include "nghttp2_hd.h"
32
-
33
- /*
34
- * Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits|
35
- * bits are not filled yet. The |rembits| must be in range [1, 8],
36
- * inclusive. At the end of the process, the |*dest_ptr| is updated
37
- * and points where next output should be placed. The number of
38
- * unfilled bits in the pointed location is returned.
39
- */
40
- static ssize_t huff_encode_sym (nghttp2_bufs * bufs , size_t * avail_ptr ,
41
- size_t rembits , const nghttp2_huff_sym * sym ) {
42
- int rv ;
43
- size_t nbits = sym -> nbits ;
44
- uint32_t code = sym -> code ;
45
-
46
- /* We assume that sym->nbits <= 32 */
47
- if (rembits > nbits ) {
48
- nghttp2_bufs_fast_orb_hold (bufs , (uint8_t )(code << (rembits - nbits )));
49
- return (ssize_t )(rembits - nbits );
50
- }
51
-
52
- if (rembits == nbits ) {
53
- nghttp2_bufs_fast_orb (bufs , (uint8_t )code );
54
- -- * avail_ptr ;
55
- return 8 ;
56
- }
57
-
58
- nghttp2_bufs_fast_orb (bufs , (uint8_t )(code >> (nbits - rembits )));
59
- -- * avail_ptr ;
60
-
61
- nbits -= rembits ;
62
- if (nbits & 0x7 ) {
63
- /* align code to MSB byte boundary */
64
- code <<= 8 - (nbits & 0x7 );
65
- }
66
-
67
- if (* avail_ptr < (nbits + 7 ) / 8 ) {
68
- /* slow path */
69
- if (nbits > 24 ) {
70
- rv = nghttp2_bufs_addb (bufs , (uint8_t )(code >> 24 ));
71
- if (rv != 0 ) {
72
- return rv ;
73
- }
74
- nbits -= 8 ;
75
- }
76
- if (nbits > 16 ) {
77
- rv = nghttp2_bufs_addb (bufs , (uint8_t )(code >> 16 ));
78
- if (rv != 0 ) {
79
- return rv ;
80
- }
81
- nbits -= 8 ;
82
- }
83
- if (nbits > 8 ) {
84
- rv = nghttp2_bufs_addb (bufs , (uint8_t )(code >> 8 ));
85
- if (rv != 0 ) {
86
- return rv ;
87
- }
88
- nbits -= 8 ;
89
- }
90
- if (nbits == 8 ) {
91
- rv = nghttp2_bufs_addb (bufs , (uint8_t )code );
92
- if (rv != 0 ) {
93
- return rv ;
94
- }
95
- * avail_ptr = nghttp2_bufs_cur_avail (bufs );
96
- return 8 ;
97
- }
98
-
99
- rv = nghttp2_bufs_addb_hold (bufs , (uint8_t )code );
100
- if (rv != 0 ) {
101
- return rv ;
102
- }
103
- * avail_ptr = nghttp2_bufs_cur_avail (bufs );
104
- return (ssize_t )(8 - nbits );
105
- }
106
-
107
- /* fast path, since most code is less than 8 */
108
- if (nbits < 8 ) {
109
- nghttp2_bufs_fast_addb_hold (bufs , (uint8_t )code );
110
- * avail_ptr = nghttp2_bufs_cur_avail (bufs );
111
- return (ssize_t )(8 - nbits );
112
- }
113
-
114
- /* handle longer code path */
115
- if (nbits > 24 ) {
116
- nghttp2_bufs_fast_addb (bufs , (uint8_t )(code >> 24 ));
117
- nbits -= 8 ;
118
- }
119
-
120
- if (nbits > 16 ) {
121
- nghttp2_bufs_fast_addb (bufs , (uint8_t )(code >> 16 ));
122
- nbits -= 8 ;
123
- }
124
-
125
- if (nbits > 8 ) {
126
- nghttp2_bufs_fast_addb (bufs , (uint8_t )(code >> 8 ));
127
- nbits -= 8 ;
128
- }
129
-
130
- if (nbits == 8 ) {
131
- nghttp2_bufs_fast_addb (bufs , (uint8_t )code );
132
- * avail_ptr = nghttp2_bufs_cur_avail (bufs );
133
- return 8 ;
134
- }
135
-
136
- nghttp2_bufs_fast_addb_hold (bufs , (uint8_t )code );
137
- * avail_ptr = nghttp2_bufs_cur_avail (bufs );
138
- return (ssize_t )(8 - nbits );
139
- }
32
+ #include "nghttp2_net.h"
140
33
141
34
size_t nghttp2_hd_huff_encode_count (const uint8_t * src , size_t len ) {
142
35
size_t i ;
@@ -151,81 +44,101 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
151
44
152
45
int nghttp2_hd_huff_encode (nghttp2_bufs * bufs , const uint8_t * src ,
153
46
size_t srclen ) {
154
- int rv ;
155
- ssize_t rembits = 8 ;
156
- size_t i ;
47
+ const nghttp2_huff_sym * sym ;
48
+ const uint8_t * end = src + srclen ;
49
+ uint64_t code = 0 ;
50
+ uint32_t x ;
51
+ size_t nbits = 0 ;
157
52
size_t avail ;
53
+ int rv ;
158
54
159
55
avail = nghttp2_bufs_cur_avail (bufs );
160
56
161
- for (i = 0 ; i < srclen ; ++ i ) {
162
- const nghttp2_huff_sym * sym = & huff_sym_table [src [i ]];
163
- if (rembits == 8 ) {
164
- if (avail ) {
165
- nghttp2_bufs_fast_addb_hold (bufs , 0 );
166
- } else {
167
- rv = nghttp2_bufs_addb_hold (bufs , 0 );
168
- if (rv != 0 ) {
169
- return rv ;
170
- }
171
- avail = nghttp2_bufs_cur_avail (bufs );
57
+ for (; src != end ;) {
58
+ sym = & huff_sym_table [* src ++ ];
59
+ code |= (uint64_t )sym -> code << (32 - nbits );
60
+ nbits += sym -> nbits ;
61
+ if (nbits < 32 ) {
62
+ continue ;
63
+ }
64
+ if (avail >= 4 ) {
65
+ x = htonl ((uint32_t )(code >> 32 ));
66
+ memcpy (bufs -> cur -> buf .last , & x , 4 );
67
+ bufs -> cur -> buf .last += 4 ;
68
+ avail -= 4 ;
69
+ code <<= 32 ;
70
+ nbits -= 32 ;
71
+ continue ;
72
+ }
73
+
74
+ for (; nbits >= 8 ;) {
75
+ rv = nghttp2_bufs_addb (bufs , (uint8_t )(code >> 56 ));
76
+ if (rv != 0 ) {
77
+ return rv ;
172
78
}
79
+ code <<= 8 ;
80
+ nbits -= 8 ;
173
81
}
174
- rembits = huff_encode_sym (bufs , & avail , (size_t )rembits , sym );
175
- if (rembits < 0 ) {
176
- return (int )rembits ;
82
+
83
+ avail = nghttp2_bufs_cur_avail (bufs );
84
+ }
85
+
86
+ for (; nbits >= 8 ;) {
87
+ rv = nghttp2_bufs_addb (bufs , (uint8_t )(code >> 56 ));
88
+ if (rv != 0 ) {
89
+ return rv ;
177
90
}
91
+ code <<= 8 ;
92
+ nbits -= 8 ;
178
93
}
179
- /* 256 is special terminal symbol, pad with its prefix */
180
- if (rembits < 8 ) {
181
- /* if rembits < 8, we should have at least 1 buffer space
182
- available */
183
- const nghttp2_huff_sym * sym = & huff_sym_table [256 ];
184
- assert (avail );
185
- /* Caution we no longer adjust avail here */
186
- nghttp2_bufs_fast_orb (
187
- bufs , (uint8_t )(sym -> code >> (sym -> nbits - (size_t )rembits )));
94
+
95
+ if (nbits ) {
96
+ rv = nghttp2_bufs_addb (
97
+ bufs , (uint8_t )((uint8_t )(code >> 56 ) | ((1 << (8 - nbits )) - 1 )));
98
+ if (rv != 0 ) {
99
+ return rv ;
100
+ }
188
101
}
189
102
190
103
return 0 ;
191
104
}
192
105
193
106
void nghttp2_hd_huff_decode_context_init (nghttp2_hd_huff_decode_context * ctx ) {
194
- ctx -> state = 0 ;
195
- ctx -> accept = 1 ;
107
+ ctx -> fstate = NGHTTP2_HUFF_ACCEPTED ;
196
108
}
197
109
198
110
ssize_t nghttp2_hd_huff_decode (nghttp2_hd_huff_decode_context * ctx ,
199
111
nghttp2_buf * buf , const uint8_t * src ,
200
112
size_t srclen , int final ) {
201
- size_t i ;
113
+ const uint8_t * end = src + srclen ;
114
+ nghttp2_huff_decode node = {ctx -> fstate , 0 };
115
+ const nghttp2_huff_decode * t = & node ;
116
+ uint8_t c ;
202
117
203
118
/* We use the decoding algorithm described in
204
119
http://graphics.ics.uci.edu/pub/Prefix.pdf */
205
- for (i = 0 ; i < srclen ; ++ i ) {
206
- const nghttp2_huff_decode * t ;
207
-
208
- t = & huff_decode_table [ctx -> state ][src [i ] >> 4 ];
209
- if (t -> flags & NGHTTP2_HUFF_FAIL ) {
210
- return NGHTTP2_ERR_HEADER_COMP ;
211
- }
212
- if (t -> flags & NGHTTP2_HUFF_SYM ) {
120
+ for (; src != end ;) {
121
+ c = * src ++ ;
122
+ t = & huff_decode_table [t -> fstate & 0x1ff ][c >> 4 ];
123
+ if (t -> fstate & NGHTTP2_HUFF_SYM ) {
213
124
* buf -> last ++ = t -> sym ;
214
125
}
215
126
216
- t = & huff_decode_table [t -> state ][src [i ] & 0xf ];
217
- if (t -> flags & NGHTTP2_HUFF_FAIL ) {
218
- return NGHTTP2_ERR_HEADER_COMP ;
219
- }
220
- if (t -> flags & NGHTTP2_HUFF_SYM ) {
127
+ t = & huff_decode_table [t -> fstate & 0x1ff ][c & 0xf ];
128
+ if (t -> fstate & NGHTTP2_HUFF_SYM ) {
221
129
* buf -> last ++ = t -> sym ;
222
130
}
223
-
224
- ctx -> state = t -> state ;
225
- ctx -> accept = (t -> flags & NGHTTP2_HUFF_ACCEPTED ) != 0 ;
226
131
}
227
- if (final && !ctx -> accept ) {
132
+
133
+ ctx -> fstate = t -> fstate ;
134
+
135
+ if (final && !(ctx -> fstate & NGHTTP2_HUFF_ACCEPTED )) {
228
136
return NGHTTP2_ERR_HEADER_COMP ;
229
137
}
230
- return (ssize_t )i ;
138
+
139
+ return (ssize_t )srclen ;
140
+ }
141
+
142
+ int nghttp2_hd_huff_decode_failure_state (nghttp2_hd_huff_decode_context * ctx ) {
143
+ return ctx -> fstate == 0x100 ;
231
144
}
0 commit comments