2929#include <stdio.h>
3030
3131#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"
14033
14134size_t nghttp2_hd_huff_encode_count (const uint8_t * src , size_t len ) {
14235 size_t i ;
@@ -151,81 +44,101 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
15144
15245int nghttp2_hd_huff_encode (nghttp2_bufs * bufs , const uint8_t * src ,
15346 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 ;
15752 size_t avail ;
53+ int rv ;
15854
15955 avail = nghttp2_bufs_cur_avail (bufs );
16056
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 ;
17278 }
79+ code <<= 8 ;
80+ nbits -= 8 ;
17381 }
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 ;
17790 }
91+ code <<= 8 ;
92+ nbits -= 8 ;
17893 }
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+ }
188101 }
189102
190103 return 0 ;
191104}
192105
193106void 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 ;
196108}
197109
198110ssize_t nghttp2_hd_huff_decode (nghttp2_hd_huff_decode_context * ctx ,
199111 nghttp2_buf * buf , const uint8_t * src ,
200112 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 ;
202117
203118 /* We use the decoding algorithm described in
204119 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 ) {
213124 * buf -> last ++ = t -> sym ;
214125 }
215126
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 ) {
221129 * buf -> last ++ = t -> sym ;
222130 }
223-
224- ctx -> state = t -> state ;
225- ctx -> accept = (t -> flags & NGHTTP2_HUFF_ACCEPTED ) != 0 ;
226131 }
227- if (final && !ctx -> accept ) {
132+
133+ ctx -> fstate = t -> fstate ;
134+
135+ if (final && !(ctx -> fstate & NGHTTP2_HUFF_ACCEPTED )) {
228136 return NGHTTP2_ERR_HEADER_COMP ;
229137 }
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 ;
231144}
0 commit comments