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