1 module hunt.http.codec.http.hpack.Huffman;
2 
3 import hunt.Exceptions;
4 import hunt.text.Common;
5 import hunt.util.StringBuilder;
6 
7 import hunt.io.ByteBuffer;
8 import hunt.logging;
9 
10 /**
11 */
12 class Huffman
13 {
14 
15     // dfmt off
16     // Appendix C: Huffman Codes
17     // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C
18     enum int[][] CODES =
19     [ 
20         /*    (  0)  |11111111|11000                      */       [0x1ff8,13],
21         /*    (  1)  |11111111|11111111|1011000           */     [0x7fffd8,23],
22         /*    (  2)  |11111111|11111111|11111110|0010     */    [0xfffffe2,28],
23         /*    (  3)  |11111111|11111111|11111110|0011     */    [0xfffffe3,28],
24         /*    (  4)  |11111111|11111111|11111110|0100     */    [0xfffffe4,28],
25         /*    (  5)  |11111111|11111111|11111110|0101     */    [0xfffffe5,28],
26         /*    (  6)  |11111111|11111111|11111110|0110     */    [0xfffffe6,28],
27         /*    (  7)  |11111111|11111111|11111110|0111     */    [0xfffffe7,28],
28         /*    (  8)  |11111111|11111111|11111110|1000     */    [0xfffffe8,28],
29         /*    (  9)  |11111111|11111111|11101010          */     [0xffffea,24],
30         /*    ( 10)  |11111111|11111111|11111111|111100   */   [0x3ffffffc,30],
31         /*    ( 11)  |11111111|11111111|11111110|1001     */    [0xfffffe9,28],
32         /*    ( 12)  |11111111|11111111|11111110|1010     */    [0xfffffea,28],
33         /*    ( 13)  |11111111|11111111|11111111|111101   */   [0x3ffffffd,30],
34         /*    ( 14)  |11111111|11111111|11111110|1011     */    [0xfffffeb,28],
35         /*    ( 15)  |11111111|11111111|11111110|1100     */    [0xfffffec,28],
36         /*    ( 16)  |11111111|11111111|11111110|1101     */    [0xfffffed,28],
37         /*    ( 17)  |11111111|11111111|11111110|1110     */    [0xfffffee,28],
38         /*    ( 18)  |11111111|11111111|11111110|1111     */    [0xfffffef,28],
39         /*    ( 19)  |11111111|11111111|11111111|0000     */    [0xffffff0,28],
40         /*    ( 20)  |11111111|11111111|11111111|0001     */    [0xffffff1,28],
41         /*    ( 21)  |11111111|11111111|11111111|0010     */    [0xffffff2,28],
42         /*    ( 22)  |11111111|11111111|11111111|111110   */   [0x3ffffffe,30],
43         /*    ( 23)  |11111111|11111111|11111111|0011     */    [0xffffff3,28],
44         /*    ( 24)  |11111111|11111111|11111111|0100     */    [0xffffff4,28],
45         /*    ( 25)  |11111111|11111111|11111111|0101     */    [0xffffff5,28],
46         /*    ( 26)  |11111111|11111111|11111111|0110     */    [0xffffff6,28],
47         /*    ( 27)  |11111111|11111111|11111111|0111     */    [0xffffff7,28],
48         /*    ( 28)  |11111111|11111111|11111111|1000     */    [0xffffff8,28],
49         /*    ( 29)  |11111111|11111111|11111111|1001     */    [0xffffff9,28],
50         /*    ( 30)  |11111111|11111111|11111111|1010     */    [0xffffffa,28],
51         /*    ( 31)  |11111111|11111111|11111111|1011     */    [0xffffffb,28],
52         /*' ' ( 32)  |010100                              */         [0x14, 6],
53         /*'!' ( 33)  |11111110|00                         */        [0x3f8,10],
54         /*'"' ( 34)  |11111110|01                         */        [0x3f9,10],
55         /*'#' ( 35)  |11111111|1010                       */        [0xffa,12],
56         /*'$' ( 36)  |11111111|11001                      */       [0x1ff9,13],
57         /*'%' ( 37)  |010101                              */         [0x15, 6],
58         /*'&' ( 38)  |11111000                            */         [0xf8, 8],
59         /*''' ( 39)  |11111111|010                        */        [0x7fa,11],
60         /*'(' ( 40)  |11111110|10                         */        [0x3fa,10],
61         /*')' ( 41)  |11111110|11                         */        [0x3fb,10],
62         /*'*' ( 42)  |11111001                            */         [0xf9, 8],
63         /*'+' ( 43)  |11111111|011                        */        [0x7fb,11],
64         /*',' ( 44)  |11111010                            */         [0xfa, 8],
65         /*'-' ( 45)  |010110                              */         [0x16, 6],
66         /*'.' ( 46)  |010111                              */         [0x17, 6],
67         /*'/' ( 47)  |011000                              */         [0x18, 6],
68         /*'0' ( 48)  |00000                               */          [0x0, 5],
69         /*'1' ( 49)  |00001                               */          [0x1, 5],
70         /*'2' ( 50)  |00010                               */          [0x2, 5],
71         /*'3' ( 51)  |011001                              */         [0x19, 6],
72         /*'4' ( 52)  |011010                              */         [0x1a, 6],
73         /*'5' ( 53)  |011011                              */         [0x1b, 6],
74         /*'6' ( 54)  |011100                              */         [0x1c, 6],
75         /*'7' ( 55)  |011101                              */         [0x1d, 6],
76         /*'8' ( 56)  |011110                              */         [0x1e, 6],
77         /*'9' ( 57)  |011111                              */         [0x1f, 6],
78         /*':' ( 58)  |1011100                             */         [0x5c, 7],
79         /*';' ( 59)  |11111011                            */         [0xfb, 8],
80         /*'<' ( 60)  |11111111|1111100                    */       [0x7ffc,15],
81         /*'=' ( 61)  |100000                              */         [0x20, 6],
82         /*'>' ( 62)  |11111111|1011                       */        [0xffb,12],
83         /*'?' ( 63)  |11111111|00                         */        [0x3fc,10],
84         /*'@' ( 64)  |11111111|11010                      */       [0x1ffa,13],
85         /*'A' ( 65)  |100001                              */         [0x21, 6],
86         /*'B' ( 66)  |1011101                             */         [0x5d, 7],
87         /*'C' ( 67)  |1011110                             */         [0x5e, 7],
88         /*'D' ( 68)  |1011111                             */         [0x5f, 7],
89         /*'E' ( 69)  |1100000                             */         [0x60, 7],
90         /*'F' ( 70)  |1100001                             */         [0x61, 7],
91         /*'G' ( 71)  |1100010                             */         [0x62, 7],
92         /*'H' ( 72)  |1100011                             */         [0x63, 7],
93         /*'I' ( 73)  |1100100                             */         [0x64, 7],
94         /*'J' ( 74)  |1100101                             */         [0x65, 7],
95         /*'K' ( 75)  |1100110                             */         [0x66, 7],
96         /*'L' ( 76)  |1100111                             */         [0x67, 7],
97         /*'M' ( 77)  |1101000                             */         [0x68, 7],
98         /*'N' ( 78)  |1101001                             */         [0x69, 7],
99         /*'O' ( 79)  |1101010                             */         [0x6a, 7],
100         /*'P' ( 80)  |1101011                             */         [0x6b, 7],
101         /*'Q' ( 81)  |1101100                             */         [0x6c, 7],
102         /*'R' ( 82)  |1101101                             */         [0x6d, 7],
103         /*'S' ( 83)  |1101110                             */         [0x6e, 7],
104         /*'T' ( 84)  |1101111                             */         [0x6f, 7],
105         /*'U' ( 85)  |1110000                             */         [0x70, 7],
106         /*'V' ( 86)  |1110001                             */         [0x71, 7],
107         /*'W' ( 87)  |1110010                             */         [0x72, 7],
108         /*'X' ( 88)  |11111100                            */         [0xfc, 8],
109         /*'Y' ( 89)  |1110011                             */         [0x73, 7],
110         /*'Z' ( 90)  |11111101                            */         [0xfd, 8],
111         /*'[' ( 91)  |11111111|11011                      */       [0x1ffb,13],
112         /*'\' ( 92)  |11111111|11111110|000               */      [0x7fff0,19],
113         /*']' ( 93)  |11111111|11100                      */       [0x1ffc,13],
114         /*'^' ( 94)  |11111111|111100                     */       [0x3ffc,14],
115         /*'_' ( 95)  |100010                              */         [0x22, 6],
116         /*'`' ( 96)  |11111111|1111101                    */       [0x7ffd,15],
117         /*'a' ( 97)  |00011                               */          [0x3, 5],
118         /*'b' ( 98)  |100011                              */         [0x23, 6],
119         /*'c' ( 99)  |00100                               */          [0x4, 5],
120         /*'d' (100)  |100100                              */         [0x24, 6],
121         /*'e' (101)  |00101                               */          [0x5, 5],
122         /*'f' (102)  |100101                              */         [0x25, 6],
123         /*'g' (103)  |100110                              */         [0x26, 6],
124         /*'h' (104)  |100111                              */         [0x27, 6],
125         /*'i' (105)  |00110                               */          [0x6, 5],
126         /*'j' (106)  |1110100                             */         [0x74, 7],
127         /*'k' (107)  |1110101                             */         [0x75, 7],
128         /*'l' (108)  |101000                              */         [0x28, 6],
129         /*'m' (109)  |101001                              */         [0x29, 6],
130         /*'n' (110)  |101010                              */         [0x2a, 6],
131         /*'o' (111)  |00111                               */          [0x7, 5],
132         /*'p' (112)  |101011                              */         [0x2b, 6],
133         /*'q' (113)  |1110110                             */         [0x76, 7],
134         /*'r' (114)  |101100                              */         [0x2c, 6],
135         /*'s' (115)  |01000                               */          [0x8, 5],
136         /*'t' (116)  |01001                               */          [0x9, 5],
137         /*'u' (117)  |101101                              */         [0x2d, 6],
138         /*'v' (118)  |1110111                             */         [0x77, 7],
139         /*'w' (119)  |1111000                             */         [0x78, 7],
140         /*'x' (120)  |1111001                             */         [0x79, 7],
141         /*'y' (121)  |1111010                             */         [0x7a, 7],
142         /*'z' (122)  |1111011                             */         [0x7b, 7],
143         /*'[' (123)  |11111111|1111110                    */       [0x7ffe,15],
144         /*'|' (124)  |11111111|100                        */        [0x7fc,11],
145         /*']' (125)  |11111111|111101                     */       [0x3ffd,14],
146         /*'~' (126)  |11111111|11101                      */       [0x1ffd,13],
147         /*    (127)  |11111111|11111111|11111111|1100     */    [0xffffffc,28],
148         /*    (128)  |11111111|11111110|0110              */      [0xfffe6,20],
149         /*    (129)  |11111111|11111111|010010            */     [0x3fffd2,22],
150         /*    (130)  |11111111|11111110|0111              */      [0xfffe7,20],
151         /*    (131)  |11111111|11111110|1000              */      [0xfffe8,20],
152         /*    (132)  |11111111|11111111|010011            */     [0x3fffd3,22],
153         /*    (133)  |11111111|11111111|010100            */     [0x3fffd4,22],
154         /*    (134)  |11111111|11111111|010101            */     [0x3fffd5,22],
155         /*    (135)  |11111111|11111111|1011001           */     [0x7fffd9,23],
156         /*    (136)  |11111111|11111111|010110            */     [0x3fffd6,22],
157         /*    (137)  |11111111|11111111|1011010           */     [0x7fffda,23],
158         /*    (138)  |11111111|11111111|1011011           */     [0x7fffdb,23],
159         /*    (139)  |11111111|11111111|1011100           */     [0x7fffdc,23],
160         /*    (140)  |11111111|11111111|1011101           */     [0x7fffdd,23],
161         /*    (141)  |11111111|11111111|1011110           */     [0x7fffde,23],
162         /*    (142)  |11111111|11111111|11101011          */     [0xffffeb,24],
163         /*    (143)  |11111111|11111111|1011111           */     [0x7fffdf,23],
164         /*    (144)  |11111111|11111111|11101100          */     [0xffffec,24],
165         /*    (145)  |11111111|11111111|11101101          */     [0xffffed,24],
166         /*    (146)  |11111111|11111111|010111            */     [0x3fffd7,22],
167         /*    (147)  |11111111|11111111|1100000           */     [0x7fffe0,23],
168         /*    (148)  |11111111|11111111|11101110          */     [0xffffee,24],
169         /*    (149)  |11111111|11111111|1100001           */     [0x7fffe1,23],
170         /*    (150)  |11111111|11111111|1100010           */     [0x7fffe2,23],
171         /*    (151)  |11111111|11111111|1100011           */     [0x7fffe3,23],
172         /*    (152)  |11111111|11111111|1100100           */     [0x7fffe4,23],
173         /*    (153)  |11111111|11111110|11100             */     [0x1fffdc,21],
174         /*    (154)  |11111111|11111111|011000            */     [0x3fffd8,22],
175         /*    (155)  |11111111|11111111|1100101           */     [0x7fffe5,23],
176         /*    (156)  |11111111|11111111|011001            */     [0x3fffd9,22],
177         /*    (157)  |11111111|11111111|1100110           */     [0x7fffe6,23],
178         /*    (158)  |11111111|11111111|1100111           */     [0x7fffe7,23],
179         /*    (159)  |11111111|11111111|11101111          */     [0xffffef,24],
180         /*    (160)  |11111111|11111111|011010            */     [0x3fffda,22],
181         /*    (161)  |11111111|11111110|11101             */     [0x1fffdd,21],
182         /*    (162)  |11111111|11111110|1001              */      [0xfffe9,20],
183         /*    (163)  |11111111|11111111|011011            */     [0x3fffdb,22],
184         /*    (164)  |11111111|11111111|011100            */     [0x3fffdc,22],
185         /*    (165)  |11111111|11111111|1101000           */     [0x7fffe8,23],
186         /*    (166)  |11111111|11111111|1101001           */     [0x7fffe9,23],
187         /*    (167)  |11111111|11111110|11110             */     [0x1fffde,21],
188         /*    (168)  |11111111|11111111|1101010           */     [0x7fffea,23],
189         /*    (169)  |11111111|11111111|011101            */     [0x3fffdd,22],
190         /*    (170)  |11111111|11111111|011110            */     [0x3fffde,22],
191         /*    (171)  |11111111|11111111|11110000          */     [0xfffff0,24],
192         /*    (172)  |11111111|11111110|11111             */     [0x1fffdf,21],
193         /*    (173)  |11111111|11111111|011111            */     [0x3fffdf,22],
194         /*    (174)  |11111111|11111111|1101011           */     [0x7fffeb,23],
195         /*    (175)  |11111111|11111111|1101100           */     [0x7fffec,23],
196         /*    (176)  |11111111|11111111|00000             */     [0x1fffe0,21],
197         /*    (177)  |11111111|11111111|00001             */     [0x1fffe1,21],
198         /*    (178)  |11111111|11111111|100000            */     [0x3fffe0,22],
199         /*    (179)  |11111111|11111111|00010             */     [0x1fffe2,21],
200         /*    (180)  |11111111|11111111|1101101           */     [0x7fffed,23],
201         /*    (181)  |11111111|11111111|100001            */     [0x3fffe1,22],
202         /*    (182)  |11111111|11111111|1101110           */     [0x7fffee,23],
203         /*    (183)  |11111111|11111111|1101111           */     [0x7fffef,23],
204         /*    (184)  |11111111|11111110|1010              */      [0xfffea,20],
205         /*    (185)  |11111111|11111111|100010            */     [0x3fffe2,22],
206         /*    (186)  |11111111|11111111|100011            */     [0x3fffe3,22],
207         /*    (187)  |11111111|11111111|100100            */     [0x3fffe4,22],
208         /*    (188)  |11111111|11111111|1110000           */     [0x7ffff0,23],
209         /*    (189)  |11111111|11111111|100101            */     [0x3fffe5,22],
210         /*    (190)  |11111111|11111111|100110            */     [0x3fffe6,22],
211         /*    (191)  |11111111|11111111|1110001           */     [0x7ffff1,23],
212         /*    (192)  |11111111|11111111|11111000|00       */    [0x3ffffe0,26],
213         /*    (193)  |11111111|11111111|11111000|01       */    [0x3ffffe1,26],
214         /*    (194)  |11111111|11111110|1011              */      [0xfffeb,20],
215         /*    (195)  |11111111|11111110|001               */      [0x7fff1,19],
216         /*    (196)  |11111111|11111111|100111            */     [0x3fffe7,22],
217         /*    (197)  |11111111|11111111|1110010           */     [0x7ffff2,23],
218         /*    (198)  |11111111|11111111|101000            */     [0x3fffe8,22],
219         /*    (199)  |11111111|11111111|11110110|0        */    [0x1ffffec,25],
220         /*    (200)  |11111111|11111111|11111000|10       */    [0x3ffffe2,26],
221         /*    (201)  |11111111|11111111|11111000|11       */    [0x3ffffe3,26],
222         /*    (202)  |11111111|11111111|11111001|00       */    [0x3ffffe4,26],
223         /*    (203)  |11111111|11111111|11111011|110      */    [0x7ffffde,27],
224         /*    (204)  |11111111|11111111|11111011|111      */    [0x7ffffdf,27],
225         /*    (205)  |11111111|11111111|11111001|01       */    [0x3ffffe5,26],
226         /*    (206)  |11111111|11111111|11110001          */     [0xfffff1,24],
227         /*    (207)  |11111111|11111111|11110110|1        */    [0x1ffffed,25],
228         /*    (208)  |11111111|11111110|010               */      [0x7fff2,19],
229         /*    (209)  |11111111|11111111|00011             */     [0x1fffe3,21],
230         /*    (210)  |11111111|11111111|11111001|10       */    [0x3ffffe6,26],
231         /*    (211)  |11111111|11111111|11111100|000      */    [0x7ffffe0,27],
232         /*    (212)  |11111111|11111111|11111100|001      */    [0x7ffffe1,27],
233         /*    (213)  |11111111|11111111|11111001|11       */    [0x3ffffe7,26],
234         /*    (214)  |11111111|11111111|11111100|010      */    [0x7ffffe2,27],
235         /*    (215)  |11111111|11111111|11110010          */     [0xfffff2,24],
236         /*    (216)  |11111111|11111111|00100             */     [0x1fffe4,21],
237         /*    (217)  |11111111|11111111|00101             */     [0x1fffe5,21],
238         /*    (218)  |11111111|11111111|11111010|00       */    [0x3ffffe8,26],
239         /*    (219)  |11111111|11111111|11111010|01       */    [0x3ffffe9,26],
240         /*    (220)  |11111111|11111111|11111111|1101     */    [0xffffffd,28],
241         /*    (221)  |11111111|11111111|11111100|011      */    [0x7ffffe3,27],
242         /*    (222)  |11111111|11111111|11111100|100      */    [0x7ffffe4,27],
243         /*    (223)  |11111111|11111111|11111100|101      */    [0x7ffffe5,27],
244         /*    (224)  |11111111|11111110|1100              */      [0xfffec,20],
245         /*    (225)  |11111111|11111111|11110011          */     [0xfffff3,24],
246         /*    (226)  |11111111|11111110|1101              */      [0xfffed,20],
247         /*    (227)  |11111111|11111111|00110             */     [0x1fffe6,21],
248         /*    (228)  |11111111|11111111|101001            */     [0x3fffe9,22],
249         /*    (229)  |11111111|11111111|00111             */     [0x1fffe7,21],
250         /*    (230)  |11111111|11111111|01000             */     [0x1fffe8,21],
251         /*    (231)  |11111111|11111111|1110011           */     [0x7ffff3,23],
252         /*    (232)  |11111111|11111111|101010            */     [0x3fffea,22],
253         /*    (233)  |11111111|11111111|101011            */     [0x3fffeb,22],
254         /*    (234)  |11111111|11111111|11110111|0        */    [0x1ffffee,25],
255         /*    (235)  |11111111|11111111|11110111|1        */    [0x1ffffef,25],
256         /*    (236)  |11111111|11111111|11110100          */     [0xfffff4,24],
257         /*    (237)  |11111111|11111111|11110101          */     [0xfffff5,24],
258         /*    (238)  |11111111|11111111|11111010|10       */    [0x3ffffea,26],
259         /*    (239)  |11111111|11111111|1110100           */     [0x7ffff4,23],
260         /*    (240)  |11111111|11111111|11111010|11       */    [0x3ffffeb,26],
261         /*    (241)  |11111111|11111111|11111100|110      */    [0x7ffffe6,27],
262         /*    (242)  |11111111|11111111|11111011|00       */    [0x3ffffec,26],
263         /*    (243)  |11111111|11111111|11111011|01       */    [0x3ffffed,26],
264         /*    (244)  |11111111|11111111|11111100|111      */    [0x7ffffe7,27],
265         /*    (245)  |11111111|11111111|11111101|000      */    [0x7ffffe8,27],
266         /*    (246)  |11111111|11111111|11111101|001      */    [0x7ffffe9,27],
267         /*    (247)  |11111111|11111111|11111101|010      */    [0x7ffffea,27],
268         /*    (248)  |11111111|11111111|11111101|011      */    [0x7ffffeb,27],
269         /*    (249)  |11111111|11111111|11111111|1110     */    [0xffffffe,28],
270         /*    (250)  |11111111|11111111|11111101|100      */    [0x7ffffec,27],
271         /*    (251)  |11111111|11111111|11111101|101      */    [0x7ffffed,27],
272         /*    (252)  |11111111|11111111|11111101|110      */    [0x7ffffee,27],
273         /*    (253)  |11111111|11111111|11111101|111      */    [0x7ffffef,27],
274         /*    (254)  |11111111|11111111|11111110|000      */    [0x7fffff0,27],
275         /*    (255)  |11111111|11111111|11111011|10       */    [0x3ffffee,26],
276         /*EOS (256)  |11111111|11111111|11111111|111111   */   [0x3fffffff,30],
277     ];
278 
279     // dfmt on
280 
281     __gshared  int[][] LCCODES; // = new int[CODES.length][];
282     
283     // Huffman decode tree stored in a flattened char array for good 
284     // locality of reference.
285     __gshared  ubyte[] tree;
286     __gshared  ubyte[] rowsym;
287     __gshared  byte[] rowbits;
288 
289     // Build the Huffman lookup tree and LC TABLE
290     shared static this()
291     {
292         // System.arraycopy(CODES,0,LCCODES,0,CODES.length);
293         LCCODES = new int[][CODES.length];
294         for (size_t i=0; i<CODES.length; i++)
295         {
296             LCCODES[i] = CODES[i].dup;
297         }
298 
299         for (size_t i='A';i<='Z';i++)
300             LCCODES[i]=LCCODES['a'+i-'A'];
301         
302         int r=0;
303         for (size_t i=0;i<CODES.length;i++)
304             r+=(CODES[i][1]+7)/8;
305         tree=new ubyte[r*256];
306         rowsym=new ubyte[r];
307         rowbits=new byte[r];
308 
309         r=0;
310         for (int sym = 0; sym < CODES.length; sym++) 
311         {
312             int code = CODES[sym][0];
313             int len = CODES[sym][1];
314 
315             int current = 0;
316 
317             while (len > 8) 
318             {
319                 len -= 8;
320                 int i = ((code >>> len) & 0xFF);
321 
322                 int t=current*256+i;
323                 current = tree[t];
324                 if (current == 0)
325                 {
326                     tree[t] = cast(char)++r;
327                     current=r;
328                 }
329             }
330 
331             int terminal = ++r;
332             rowsym[r]=cast(char)sym;
333             int b = len & 0x07;
334             int terminalBits = b == 0?8:b;
335 
336             rowbits[r]=cast(byte)terminalBits;
337             int shift = 8 - len;
338             int start = current*256 + ((code << shift) & 0xFF);
339             int end = start + (1<<shift);
340             for (int i = start; i < end; i++)
341                 tree[i]=cast(char)terminal;
342         }
343     }
344 
345     static string decode(ByteBuffer buffer)
346     {  
347         return decode(buffer,buffer.remaining());
348     }
349 
350     static string decode(ByteBuffer buffer,int length)
351     {        
352         StringBuilder r = new StringBuilder(length*2);
353         int node = 0;
354         int current = 0;
355         int bits = 0;
356         
357         byte[] array = buffer.array();
358         int position=buffer.position();
359         int start=buffer.arrayOffset()+position;
360         int end=start+length;
361         buffer.position(position+length);
362         
363         for (int i=start; i<end; i++)
364         {
365             int b = array[i]&0xFF;
366             current = (current << 8) | b;
367             bits += 8;
368             while (bits >= 8) 
369             {
370                 int c = (current >>> (bits - 8)) & 0xFF;
371                 node = tree[node*256+c];
372                 if (rowbits[node]!=0) 
373                 {
374                     // terminal node
375                     // tracef("xx=>%s", rowsym[node]);
376                     r.append(rowsym[node]);
377                     bits -= rowbits[node];
378                     node = 0;
379                 } 
380                 else 
381                 {
382                     // non-terminal node
383                     bits -= 8;
384                 }
385             }
386         }
387 
388         // tracef("bits=>%d", bits);
389         while (bits > 0) 
390         {
391             int c = (current << (8 - bits)) & 0xFF;
392             // tracef("node=%d, c=%d", node, c);
393             node = tree[node*256+c];
394         // tracef("rowbits[%d]=>%d", node, rowbits[node]);
395             if (rowbits[node]==0 || rowbits[node] > bits) 
396                 break;
397             
398             // tracef("xx=>%s", rowsym[node]);
399             r.append(rowsym[node]);
400             bits -= rowbits[node];
401             node = 0;
402         }
403 
404         return r.toString();
405     }
406 
407     static int octetsNeeded(string s)
408     {   
409         return octetsNeeded(CODES,s);
410     }
411     
412     static void encode(ByteBuffer buffer,string s)
413     {
414         encode(CODES,buffer,s);
415     }
416     
417     static int octetsNeededLC(string s)
418     {
419         return octetsNeeded(LCCODES,s);
420     }
421 
422     static void encodeLC(ByteBuffer buffer, string s)
423     {
424         encode(LCCODES,buffer,s);
425     }
426     
427     private static int octetsNeeded( int[][] table,string s)
428     {   
429         int needed=0;
430         for (size_t i=0;i< s.length;i++)
431         {
432             char c=s[i];
433             if (c>=128 || c<' ')
434                 throw new IllegalArgumentException("");
435             needed += table[c][1];
436         }
437 
438         return (needed+7) / 8;
439     }
440 
441     private static void encode( int[][] table,ByteBuffer buffer,string s)
442     {
443         long current = 0;
444         int n = 0;
445 
446         byte[] array = buffer.array();
447         int p=buffer.arrayOffset()+buffer.position();
448 
449         for (size_t i=0;i<s.length;i++)
450         {
451             char c=s[i];
452             if (c>=128 || c<' ')
453                 throw new IllegalArgumentException("");
454             int code = table[c][0];
455             int bits = table[c][1];
456 
457             current <<= bits;
458             current |= code;
459             n += bits;
460 
461             while (n >= 8) 
462             {
463                 n -= 8;
464                 array[p++]=cast(byte)(current >> n);
465             }
466         }
467 
468         if (n > 0) 
469         {
470           current <<= (8 - n);
471           current |= (0xFF >>> n); 
472           array[p++]=cast(byte)current;
473         }
474         
475         buffer.position(p-buffer.arrayOffset());
476     }
477 
478 }