1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.incubator.http.internal.hpack;
  26 
  27 import java.io.IOException;
  28 import java.io.UncheckedIOException;
  29 import java.nio.ByteBuffer;
  30 
  31 import static java.lang.String.format;
  32 
  33 /**
  34  * Huffman coding table.
  35  *
  36  * <p> Instances of this class are safe for use by multiple threads.
  37  *
  38  * @since 9
  39  */
  40 public final class Huffman {
  41 
  42     // TODO: check if reset is done in both reader and writer
  43 
  44     static final class Reader {
  45 
  46         private Node curr; // position in the trie
  47         private int len;   // length of the path from the root to 'curr'
  48         private int p;     // byte probe
  49 
  50         {
  51             reset();
  52         }
  53 
  54         public void read(ByteBuffer source, Appendable destination,
  55                          boolean isLast) {
  56             read(source, destination, true, isLast);
  57         }
  58 
  59         // Takes 'isLast' rather than returns whether the reading is done or
  60         // not, for more informative exceptions.
  61         void read(ByteBuffer source, Appendable destination, boolean reportEOS,
  62                   boolean isLast) {
  63 
  64             Node c = curr;
  65             int l = len;
  66             /*
  67                Since ByteBuffer is itself stateful, its position is
  68                remembered here NOT as a part of Reader's state,
  69                but to set it back in the case of a failure
  70              */
  71             int pos = source.position();
  72 
  73             while (source.hasRemaining()) {
  74                 int d = source.get();
  75                 for (; p != 0; p >>= 1) {
  76                     c = c.getChild(p & d);
  77                     l++;
  78                     if (c.isLeaf()) {
  79                         if (reportEOS && c.isEOSPath) {
  80                             throw new IllegalArgumentException("Encountered EOS");
  81                         }
  82                         try {
  83                             destination.append(c.getChar());
  84                         } catch (RuntimeException | Error e) {
  85                             source.position(pos);
  86                             throw e;
  87                         } catch (IOException e) {
  88                             source.position(pos);
  89                             throw new UncheckedIOException(e);
  90                         }
  91                         c = INSTANCE.root;
  92                         l = 0;
  93                     }
  94                     curr = c;
  95                     len = l;
  96                 }
  97                 resetProbe();
  98                 pos++;
  99             }
 100             if (!isLast) {
 101                 return; // it's too early to jump to any conclusions, let's wait
 102             }
 103             if (c.isLeaf()) {
 104                 return; // it's perfectly ok, no extra padding bits
 105             }
 106             if (c.isEOSPath && len <= 7) {
 107                 return; // it's ok, some extra padding bits
 108             }
 109             if (c.isEOSPath) {
 110                 throw new IllegalArgumentException(
 111                         "Padding is too long (len=" + len + ") " +
 112                                 "or unexpected end of data");
 113             }
 114             throw new IllegalArgumentException(
 115                     "Not a EOS prefix padding or unexpected end of data");
 116         }
 117 
 118         public void reset() {
 119             curr = INSTANCE.root;
 120             len = 0;
 121             resetProbe();
 122         }
 123 
 124         private void resetProbe() {
 125             p = 0x80;
 126         }
 127     }
 128 
 129     static final class Writer {
 130 
 131         private int pos;       // position in 'source'
 132         private int avail = 8; // number of least significant bits available in 'curr'
 133         private int curr;      // next byte to put to the destination
 134         private int rem;       // number of least significant bits in 'code' yet to be processed
 135         private int code;      // current code being written
 136 
 137         private CharSequence source;
 138         private int end;
 139 
 140         public Writer from(CharSequence input, int start, int end) {
 141             if (start < 0 || end < 0 || end > input.length() || start > end) {
 142                 throw new IndexOutOfBoundsException(
 143                         String.format("input.length()=%s, start=%s, end=%s",
 144                                 input.length(), start, end));
 145             }
 146             pos = start;
 147             this.end = end;
 148             this.source = input;
 149             return this;
 150         }
 151 
 152         public boolean write(ByteBuffer destination) {
 153             for (; pos < end; pos++) {
 154                 if (rem == 0) {
 155                     Code desc = INSTANCE.codeOf(source.charAt(pos));
 156                     rem = desc.length;
 157                     code = desc.code;
 158                 }
 159                 while (rem > 0) {
 160                     if (rem < avail) {
 161                         curr |= (code << (avail - rem));
 162                         avail -= rem;
 163                         rem = 0;
 164                     } else {
 165                         int c = (curr | (code >>> (rem - avail)));
 166                         if (destination.hasRemaining()) {
 167                             destination.put((byte) c);
 168                         } else {
 169                             return false;
 170                         }
 171                         curr = c;
 172                         code <<= (32 - rem + avail);  // throw written bits off the cliff (is this Sparta?)
 173                         code >>>= (32 - rem + avail); // return to the position
 174                         rem -= avail;
 175                         curr = 0;
 176                         avail = 8;
 177                     }
 178                 }
 179             }
 180 
 181             if (avail < 8) { // have to pad
 182                 if (destination.hasRemaining()) {
 183                     destination.put((byte) (curr | (INSTANCE.EOS.code >>> (INSTANCE.EOS.length - avail))));
 184                     avail = 8;
 185                 } else {
 186                     return false;
 187                 }
 188             }
 189 
 190             return true;
 191         }
 192 
 193         public Writer reset() {
 194             source = null;
 195             end = -1;
 196             pos = -1;
 197             avail = 8;
 198             curr = 0;
 199             code = 0;
 200             return this;
 201         }
 202     }
 203 
 204     /**
 205      * Shared instance.
 206      */
 207     public static final Huffman INSTANCE = new Huffman();
 208 
 209     private final Code EOS = new Code(0x3fffffff, 30);
 210     private final Code[] codes = new Code[257];
 211     private final Node root = new Node() {
 212         @Override
 213         public String toString() { return "root"; }
 214     };
 215 
 216     // TODO: consider builder and immutable trie
 217     private Huffman() {
 218         // @formatter:off
 219         addChar(0,   0x1ff8,     13);
 220         addChar(1,   0x7fffd8,   23);
 221         addChar(2,   0xfffffe2,  28);
 222         addChar(3,   0xfffffe3,  28);
 223         addChar(4,   0xfffffe4,  28);
 224         addChar(5,   0xfffffe5,  28);
 225         addChar(6,   0xfffffe6,  28);
 226         addChar(7,   0xfffffe7,  28);
 227         addChar(8,   0xfffffe8,  28);
 228         addChar(9,   0xffffea,   24);
 229         addChar(10,  0x3ffffffc, 30);
 230         addChar(11,  0xfffffe9,  28);
 231         addChar(12,  0xfffffea,  28);
 232         addChar(13,  0x3ffffffd, 30);
 233         addChar(14,  0xfffffeb,  28);
 234         addChar(15,  0xfffffec,  28);
 235         addChar(16,  0xfffffed,  28);
 236         addChar(17,  0xfffffee,  28);
 237         addChar(18,  0xfffffef,  28);
 238         addChar(19,  0xffffff0,  28);
 239         addChar(20,  0xffffff1,  28);
 240         addChar(21,  0xffffff2,  28);
 241         addChar(22,  0x3ffffffe, 30);
 242         addChar(23,  0xffffff3,  28);
 243         addChar(24,  0xffffff4,  28);
 244         addChar(25,  0xffffff5,  28);
 245         addChar(26,  0xffffff6,  28);
 246         addChar(27,  0xffffff7,  28);
 247         addChar(28,  0xffffff8,  28);
 248         addChar(29,  0xffffff9,  28);
 249         addChar(30,  0xffffffa,  28);
 250         addChar(31,  0xffffffb,  28);
 251         addChar(32,  0x14,        6);
 252         addChar(33,  0x3f8,      10);
 253         addChar(34,  0x3f9,      10);
 254         addChar(35,  0xffa,      12);
 255         addChar(36,  0x1ff9,     13);
 256         addChar(37,  0x15,        6);
 257         addChar(38,  0xf8,        8);
 258         addChar(39,  0x7fa,      11);
 259         addChar(40,  0x3fa,      10);
 260         addChar(41,  0x3fb,      10);
 261         addChar(42,  0xf9,        8);
 262         addChar(43,  0x7fb,      11);
 263         addChar(44,  0xfa,        8);
 264         addChar(45,  0x16,        6);
 265         addChar(46,  0x17,        6);
 266         addChar(47,  0x18,        6);
 267         addChar(48,  0x0,         5);
 268         addChar(49,  0x1,         5);
 269         addChar(50,  0x2,         5);
 270         addChar(51,  0x19,        6);
 271         addChar(52,  0x1a,        6);
 272         addChar(53,  0x1b,        6);
 273         addChar(54,  0x1c,        6);
 274         addChar(55,  0x1d,        6);
 275         addChar(56,  0x1e,        6);
 276         addChar(57,  0x1f,        6);
 277         addChar(58,  0x5c,        7);
 278         addChar(59,  0xfb,        8);
 279         addChar(60,  0x7ffc,     15);
 280         addChar(61,  0x20,        6);
 281         addChar(62,  0xffb,      12);
 282         addChar(63,  0x3fc,      10);
 283         addChar(64,  0x1ffa,     13);
 284         addChar(65,  0x21,        6);
 285         addChar(66,  0x5d,        7);
 286         addChar(67,  0x5e,        7);
 287         addChar(68,  0x5f,        7);
 288         addChar(69,  0x60,        7);
 289         addChar(70,  0x61,        7);
 290         addChar(71,  0x62,        7);
 291         addChar(72,  0x63,        7);
 292         addChar(73,  0x64,        7);
 293         addChar(74,  0x65,        7);
 294         addChar(75,  0x66,        7);
 295         addChar(76,  0x67,        7);
 296         addChar(77,  0x68,        7);
 297         addChar(78,  0x69,        7);
 298         addChar(79,  0x6a,        7);
 299         addChar(80,  0x6b,        7);
 300         addChar(81,  0x6c,        7);
 301         addChar(82,  0x6d,        7);
 302         addChar(83,  0x6e,        7);
 303         addChar(84,  0x6f,        7);
 304         addChar(85,  0x70,        7);
 305         addChar(86,  0x71,        7);
 306         addChar(87,  0x72,        7);
 307         addChar(88,  0xfc,        8);
 308         addChar(89,  0x73,        7);
 309         addChar(90,  0xfd,        8);
 310         addChar(91,  0x1ffb,     13);
 311         addChar(92,  0x7fff0,    19);
 312         addChar(93,  0x1ffc,     13);
 313         addChar(94,  0x3ffc,     14);
 314         addChar(95,  0x22,        6);
 315         addChar(96,  0x7ffd,     15);
 316         addChar(97,  0x3,         5);
 317         addChar(98,  0x23,        6);
 318         addChar(99,  0x4,         5);
 319         addChar(100, 0x24,        6);
 320         addChar(101, 0x5,         5);
 321         addChar(102, 0x25,        6);
 322         addChar(103, 0x26,        6);
 323         addChar(104, 0x27,        6);
 324         addChar(105, 0x6,         5);
 325         addChar(106, 0x74,        7);
 326         addChar(107, 0x75,        7);
 327         addChar(108, 0x28,        6);
 328         addChar(109, 0x29,        6);
 329         addChar(110, 0x2a,        6);
 330         addChar(111, 0x7,         5);
 331         addChar(112, 0x2b,        6);
 332         addChar(113, 0x76,        7);
 333         addChar(114, 0x2c,        6);
 334         addChar(115, 0x8,         5);
 335         addChar(116, 0x9,         5);
 336         addChar(117, 0x2d,        6);
 337         addChar(118, 0x77,        7);
 338         addChar(119, 0x78,        7);
 339         addChar(120, 0x79,        7);
 340         addChar(121, 0x7a,        7);
 341         addChar(122, 0x7b,        7);
 342         addChar(123, 0x7ffe,     15);
 343         addChar(124, 0x7fc,      11);
 344         addChar(125, 0x3ffd,     14);
 345         addChar(126, 0x1ffd,     13);
 346         addChar(127, 0xffffffc,  28);
 347         addChar(128, 0xfffe6,    20);
 348         addChar(129, 0x3fffd2,   22);
 349         addChar(130, 0xfffe7,    20);
 350         addChar(131, 0xfffe8,    20);
 351         addChar(132, 0x3fffd3,   22);
 352         addChar(133, 0x3fffd4,   22);
 353         addChar(134, 0x3fffd5,   22);
 354         addChar(135, 0x7fffd9,   23);
 355         addChar(136, 0x3fffd6,   22);
 356         addChar(137, 0x7fffda,   23);
 357         addChar(138, 0x7fffdb,   23);
 358         addChar(139, 0x7fffdc,   23);
 359         addChar(140, 0x7fffdd,   23);
 360         addChar(141, 0x7fffde,   23);
 361         addChar(142, 0xffffeb,   24);
 362         addChar(143, 0x7fffdf,   23);
 363         addChar(144, 0xffffec,   24);
 364         addChar(145, 0xffffed,   24);
 365         addChar(146, 0x3fffd7,   22);
 366         addChar(147, 0x7fffe0,   23);
 367         addChar(148, 0xffffee,   24);
 368         addChar(149, 0x7fffe1,   23);
 369         addChar(150, 0x7fffe2,   23);
 370         addChar(151, 0x7fffe3,   23);
 371         addChar(152, 0x7fffe4,   23);
 372         addChar(153, 0x1fffdc,   21);
 373         addChar(154, 0x3fffd8,   22);
 374         addChar(155, 0x7fffe5,   23);
 375         addChar(156, 0x3fffd9,   22);
 376         addChar(157, 0x7fffe6,   23);
 377         addChar(158, 0x7fffe7,   23);
 378         addChar(159, 0xffffef,   24);
 379         addChar(160, 0x3fffda,   22);
 380         addChar(161, 0x1fffdd,   21);
 381         addChar(162, 0xfffe9,    20);
 382         addChar(163, 0x3fffdb,   22);
 383         addChar(164, 0x3fffdc,   22);
 384         addChar(165, 0x7fffe8,   23);
 385         addChar(166, 0x7fffe9,   23);
 386         addChar(167, 0x1fffde,   21);
 387         addChar(168, 0x7fffea,   23);
 388         addChar(169, 0x3fffdd,   22);
 389         addChar(170, 0x3fffde,   22);
 390         addChar(171, 0xfffff0,   24);
 391         addChar(172, 0x1fffdf,   21);
 392         addChar(173, 0x3fffdf,   22);
 393         addChar(174, 0x7fffeb,   23);
 394         addChar(175, 0x7fffec,   23);
 395         addChar(176, 0x1fffe0,   21);
 396         addChar(177, 0x1fffe1,   21);
 397         addChar(178, 0x3fffe0,   22);
 398         addChar(179, 0x1fffe2,   21);
 399         addChar(180, 0x7fffed,   23);
 400         addChar(181, 0x3fffe1,   22);
 401         addChar(182, 0x7fffee,   23);
 402         addChar(183, 0x7fffef,   23);
 403         addChar(184, 0xfffea,    20);
 404         addChar(185, 0x3fffe2,   22);
 405         addChar(186, 0x3fffe3,   22);
 406         addChar(187, 0x3fffe4,   22);
 407         addChar(188, 0x7ffff0,   23);
 408         addChar(189, 0x3fffe5,   22);
 409         addChar(190, 0x3fffe6,   22);
 410         addChar(191, 0x7ffff1,   23);
 411         addChar(192, 0x3ffffe0,  26);
 412         addChar(193, 0x3ffffe1,  26);
 413         addChar(194, 0xfffeb,    20);
 414         addChar(195, 0x7fff1,    19);
 415         addChar(196, 0x3fffe7,   22);
 416         addChar(197, 0x7ffff2,   23);
 417         addChar(198, 0x3fffe8,   22);
 418         addChar(199, 0x1ffffec,  25);
 419         addChar(200, 0x3ffffe2,  26);
 420         addChar(201, 0x3ffffe3,  26);
 421         addChar(202, 0x3ffffe4,  26);
 422         addChar(203, 0x7ffffde,  27);
 423         addChar(204, 0x7ffffdf,  27);
 424         addChar(205, 0x3ffffe5,  26);
 425         addChar(206, 0xfffff1,   24);
 426         addChar(207, 0x1ffffed,  25);
 427         addChar(208, 0x7fff2,    19);
 428         addChar(209, 0x1fffe3,   21);
 429         addChar(210, 0x3ffffe6,  26);
 430         addChar(211, 0x7ffffe0,  27);
 431         addChar(212, 0x7ffffe1,  27);
 432         addChar(213, 0x3ffffe7,  26);
 433         addChar(214, 0x7ffffe2,  27);
 434         addChar(215, 0xfffff2,   24);
 435         addChar(216, 0x1fffe4,   21);
 436         addChar(217, 0x1fffe5,   21);
 437         addChar(218, 0x3ffffe8,  26);
 438         addChar(219, 0x3ffffe9,  26);
 439         addChar(220, 0xffffffd,  28);
 440         addChar(221, 0x7ffffe3,  27);
 441         addChar(222, 0x7ffffe4,  27);
 442         addChar(223, 0x7ffffe5,  27);
 443         addChar(224, 0xfffec,    20);
 444         addChar(225, 0xfffff3,   24);
 445         addChar(226, 0xfffed,    20);
 446         addChar(227, 0x1fffe6,   21);
 447         addChar(228, 0x3fffe9,   22);
 448         addChar(229, 0x1fffe7,   21);
 449         addChar(230, 0x1fffe8,   21);
 450         addChar(231, 0x7ffff3,   23);
 451         addChar(232, 0x3fffea,   22);
 452         addChar(233, 0x3fffeb,   22);
 453         addChar(234, 0x1ffffee,  25);
 454         addChar(235, 0x1ffffef,  25);
 455         addChar(236, 0xfffff4,   24);
 456         addChar(237, 0xfffff5,   24);
 457         addChar(238, 0x3ffffea,  26);
 458         addChar(239, 0x7ffff4,   23);
 459         addChar(240, 0x3ffffeb,  26);
 460         addChar(241, 0x7ffffe6,  27);
 461         addChar(242, 0x3ffffec,  26);
 462         addChar(243, 0x3ffffed,  26);
 463         addChar(244, 0x7ffffe7,  27);
 464         addChar(245, 0x7ffffe8,  27);
 465         addChar(246, 0x7ffffe9,  27);
 466         addChar(247, 0x7ffffea,  27);
 467         addChar(248, 0x7ffffeb,  27);
 468         addChar(249, 0xffffffe,  28);
 469         addChar(250, 0x7ffffec,  27);
 470         addChar(251, 0x7ffffed,  27);
 471         addChar(252, 0x7ffffee,  27);
 472         addChar(253, 0x7ffffef,  27);
 473         addChar(254, 0x7fffff0,  27);
 474         addChar(255, 0x3ffffee,  26);
 475         addEOS (256, EOS.code,   EOS.length);
 476         // @formatter:on
 477     }
 478 
 479 
 480     /**
 481      * Calculates the number of bytes required to represent the given {@code
 482      * CharSequence} with the Huffman coding.
 483      *
 484      * @param value
 485      *         characters
 486      *
 487      * @return number of bytes
 488      *
 489      * @throws NullPointerException
 490      *         if the value is null
 491      */
 492     public int lengthOf(CharSequence value) {
 493         return lengthOf(value, 0, value.length());
 494     }
 495 
 496     /**
 497      * Calculates the number of bytes required to represent a subsequence of the
 498      * given {@code CharSequence} with the Huffman coding.
 499      *
 500      * @param value
 501      *         characters
 502      * @param start
 503      *         the start index, inclusive
 504      * @param end
 505      *         the end index, exclusive
 506      *
 507      * @return number of bytes
 508      *
 509      * @throws NullPointerException
 510      *         if the value is null
 511      * @throws IndexOutOfBoundsException
 512      *         if any invocation of {@code value.charAt(i)}, where {@code start
 513      *         <= i < end} would throw an IndexOutOfBoundsException
 514      */
 515     public int lengthOf(CharSequence value, int start, int end) {
 516         int len = 0;
 517         for (int i = start; i < end; i++) {
 518             char c = value.charAt(i);
 519             len += INSTANCE.codeOf(c).length;
 520         }
 521         // Integer division with ceiling, assumption:
 522         assert (len / 8 + (len % 8 != 0 ? 1 : 0)) == (len + 7) / 8 : len;
 523         return (len + 7) / 8;
 524     }
 525 
 526     private void addChar(int c, int code, int bitLength) {
 527         addLeaf(c, code, bitLength, false);
 528         codes[c] = new Code(code, bitLength);
 529     }
 530 
 531     private void addEOS(int c, int code, int bitLength) {
 532         addLeaf(c, code, bitLength, true);
 533         codes[c] = new Code(code, bitLength);
 534     }
 535 
 536     private void addLeaf(int c, int code, int bitLength, boolean isEOS) {
 537         if (bitLength < 1) {
 538             throw new IllegalArgumentException("bitLength < 1");
 539         }
 540         Node curr = root;
 541         for (int p = 1 << bitLength - 1; p != 0 && !curr.isLeaf(); p = p >> 1) {
 542             curr.isEOSPath |= isEOS; // If it's already true, it can't become false
 543             curr = curr.addChildIfAbsent(p & code);
 544         }
 545         curr.isEOSPath |= isEOS; // The last one needs to have this property as well
 546         if (curr.isLeaf()) {
 547             throw new IllegalStateException("Specified code is already taken");
 548         }
 549         curr.setChar((char) c);
 550     }
 551 
 552     private Code codeOf(char c) {
 553         if (c > 255) {
 554             throw new IllegalArgumentException("char=" + ((int) c));
 555         }
 556         return codes[c];
 557     }
 558 
 559     //
 560     // For debugging/testing purposes
 561     //
 562     Node getRoot() {
 563         return root;
 564     }
 565 
 566     //
 567     // Guarantees:
 568     //
 569     //  if (isLeaf() == true) => getChar() is a legal call
 570     //  if (isLeaf() == false) => getChild(i) is a legal call (though it can
 571     //                                                           return null)
 572     //
 573     static class Node {
 574 
 575         Node left;
 576         Node right;
 577         boolean isEOSPath;
 578 
 579         boolean charIsSet;
 580         char c;
 581 
 582         Node getChild(int selector) {
 583             if (isLeaf()) {
 584                 throw new IllegalStateException("This is a leaf node");
 585             }
 586             Node result = selector == 0 ? left : right;
 587             if (result == null) {
 588                 throw new IllegalStateException(format(
 589                         "Node doesn't have a child (selector=%s)", selector));
 590             }
 591             return result;
 592         }
 593 
 594         boolean isLeaf() {
 595             return charIsSet;
 596         }
 597 
 598         char getChar() {
 599             if (!isLeaf()) {
 600                 throw new IllegalStateException("This node is not a leaf node");
 601             }
 602             return c;
 603         }
 604 
 605         void setChar(char c) {
 606             if (charIsSet) {
 607                 throw new IllegalStateException(
 608                         "This node has been taken already");
 609             }
 610             if (left != null || right != null) {
 611                 throw new IllegalStateException("The node cannot be made "
 612                         + "a leaf as it's already has a child");
 613             }
 614             this.c = c;
 615             charIsSet = true;
 616         }
 617 
 618         Node addChildIfAbsent(int i) {
 619             if (charIsSet) {
 620                 throw new IllegalStateException("The node cannot have a child "
 621                         + "as it's already a leaf node");
 622             }
 623             Node child;
 624             if (i == 0) {
 625                 if ((child = left) == null) {
 626                     child = left = new Node();
 627                 }
 628             } else {
 629                 if ((child = right) == null) {
 630                     child = right = new Node();
 631                 }
 632             }
 633             return child;
 634         }
 635 
 636         @Override
 637         public String toString() {
 638             if (isLeaf()) {
 639                 if (isEOSPath) {
 640                     return "EOS";
 641                 } else {
 642                     return format("char: (%3s) '%s'", (int) c, c);
 643                 }
 644             }
 645             return "/\\";
 646         }
 647     }
 648 
 649     // TODO: value-based class?
 650     // FIXME: can we re-use Node instead of this class?
 651     private static final class Code {
 652 
 653         final int code;
 654         final int length;
 655 
 656         private Code(int code, int length) {
 657             this.code = code;
 658             this.length = length;
 659         }
 660 
 661         public int getCode() {
 662             return code;
 663         }
 664 
 665         public int getLength() {
 666             return length;
 667         }
 668 
 669         @Override
 670         public String toString() {
 671             long p = 1 << length;
 672             return Long.toBinaryString(code + p).substring(1)
 673                     + ", length=" + length;
 674         }
 675     }
 676 }