All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.v5.http.protocol2.HeaderCommon Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.v5.http.protocol2;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * Header compression/decompression common methods and structures.
 */
class HeaderCommon
{
  private static final HashMap _tableKeyStatic;
  private static final HashMap _tableEntryStatic;
  private static final TableEntry []_staticEntryArray;

  private static final HuffmanCode []_huffmanEncoding;
  private static final char [][]_huffmanDecodeTable;

  private static HuffmanProgram _huffmanDecodeProgram;

  protected Map getTableKeyStatic()
  {
    return _tableKeyStatic;
  }

  protected Map getTableEntryStatic()
  {
    return _tableEntryStatic;
  }

  protected TableEntry []getEntryArrayStatic()
  {
    return _staticEntryArray;
  }

  protected static HuffmanCode []getHuffmanTable()
  {
    return _huffmanEncoding;
  }

  protected int read()
    throws IOException
  {
    return -1;
  }

  protected static int huffmanEncode(byte []buffer, int head, String value,
                                     HuffmanCode []table)
  {
    int strlen = value.length();

    long data = 0;
    int bits = 0;

    int offset = head;

    for (int i = 0; i < strlen; i++) {
      int ch = value.charAt(i);

      HuffmanCode entry = table[ch];

      int length = entry.getLength();
      int code = entry.getCode();

      data = (data << length) | code;
      bits += length;

      while (bits >= 8) {
        buffer[++offset] = (byte) (data >> (bits - 8));
        bits -= 8;
      }
    }

    if (bits > 0) {
      buffer[++offset] = (byte) ((data << (8 - bits))
                                | (0xff >> bits));
    }

    int len = offset - head;

    buffer[head] = (byte) (0x80 + len);

    return offset + 1;
  }

  private static void addTableStatic(ArrayList list,
                                     String key,
                                     String value)
  {
    int id = list.size();

    TableEntryStatic entry = new TableEntryStatic(id, key, value);

    _tableKeyStatic.put(key, entry);
    _tableEntryStatic.put(entry, entry);

    list.add(entry);
  }

  protected int huffmanDecode(int length, char []chars)
    throws IOException
  {
    long chunk = 0;
    int bits = 0;
    int offset = 0;
    char [][]charTable = _huffmanDecodeTable;
    HuffmanProgram topProgram = _huffmanDecodeProgram;
    int tailBits = 0;

    while (true) {
      while (bits <= 56) {
        if (length > 0) {
          int d = read();

          chunk = (chunk << 8) | d;
          length--;

          bits += 8;
        }
        else if (bits <= 0) {
          return offset;
        } 
        else {
          //int rest = (64 - bits) & ~0x7;
          int rest = 8;

          //chunk = (chunk << rest) | ((1L << rest) - 1);
          chunk = (chunk << rest) | 0xff;
          bits += rest;
          tailBits += rest;
          
          break;
        }
      }

      int top = (int) ((chunk >> (bits - 8)) & 0xff);
      int index;

      if (true) {
        HuffmanProgram ptr = topProgram.getChild(top);

        int bitOff = 16;

        while (ptr != null && ! ptr.isFinal()) {
          int t1 = (int) ((chunk >> (bits - bitOff)) & 0xff);

          ptr = ptr.getChild(t1);
          bitOff += 8;
        }

        if (ptr == null || bits - tailBits < ptr.getLength()) {
          return offset;
        }

        chars[offset++] = (char) ptr.getChar();
        bits -= ptr.getLength();
        continue;
      }

      switch (top) {
      case 0x00: case 0x01: case 0x02: case 0x03:
      case 0x04: case 0x05: case 0x06: case 0x07:
      case 0x08: case 0x09: case 0x0a: case 0x0b:
      case 0x0c: case 0x0d: case 0x0e: case 0x0f:

      case 0x10: case 0x11: case 0x12: case 0x13:
      case 0x14: case 0x15: case 0x16: case 0x17:
      case 0x18: case 0x19: case 0x1a: case 0x1b:
      case 0x1c: case 0x1d: case 0x1e: case 0x1f:
        // [4] '/', 'e'
        index = (int) (top >> 4);
        bits -= 4;

        chars[offset++] = charTable[4][index];
        break;

      case 0x20: case 0x21: case 0x22: case 0x23:
      case 0x24: case 0x25: case 0x26: case 0x27:
      case 0x28: case 0x29: case 0x2a: case 0x2b:
      case 0x2c: case 0x2d: case 0x2e: case 0x2f:

      case 0x30: case 0x31: case 0x32: case 0x33:
      case 0x34: case 0x35: case 0x36: case 0x37:
      case 0x38: case 0x39: case 0x3a: case 0x3b:
      case 0x3c: case 0x3d: case 0x3e: case 0x3f:

      case 0x40: case 0x41: case 0x42: case 0x43:
      case 0x44: case 0x45: case 0x46: case 0x47:
      case 0x48: case 0x49: case 0x4a: case 0x4b:
      case 0x4c: case 0x4d: case 0x4e: case 0x4f:

      case 0x50: case 0x51: case 0x52: case 0x53:
      case 0x54: case 0x55: case 0x56: case 0x57:
      case 0x58: case 0x59: case 0x5a: case 0x5b:
      case 0x5c: case 0x5d: case 0x5e: case 0x5f:

      case 0x60: case 0x61: case 0x62: case 0x63:
      case 0x64: case 0x65: case 0x66: case 0x67:
      case 0x68: case 0x69: case 0x6a: case 0x6b:
      case 0x6c: case 0x6d: case 0x6e: case 0x6f:

      case 0x70: case 0x71: case 0x72: case 0x73:
      case 0x74: case 0x75: case 0x76: case 0x77:
      case 0x78: case 0x79: case 0x7a: case 0x7b:
      case 0x7c: case 0x7d: case 0x7e: case 0x7f:

      case 0x80: case 0x81: case 0x82: case 0x83:
      case 0x84: case 0x85: case 0x86: case 0x87:
      case 0x88: case 0x89: case 0x8a: case 0x8b:
      case 0x8c: case 0x8d: case 0x8e: case 0x8f:
        // [5] '.', '0', '1', '2',
        index = (int) ((top - 0x20) >> 3);
        bits -= 5;

        chars[offset++] = charTable[5][index];
        break;

      case 0x90: case 0x91: case 0x92: case 0x93:
      case 0x94: case 0x95: case 0x96: case 0x97:
      case 0x98: case 0x99: case 0x9a: case 0x9b:
      case 0x9c: case 0x9d: case 0x9e: case 0x9f:

      case 0xa0: case 0xa1: case 0xa2: case 0xa3:
      case 0xa4: case 0xa5: case 0xa6: case 0xa7:
      case 0xa8: case 0xa9: case 0xaa: case 0xab:
      case 0xac: case 0xad: case 0xae: case 0xaf:

      case 0xb0: case 0xb1: case 0xb2: case 0xb3:
      case 0xb4: case 0xb5: case 0xb6: case 0xb7:
      case 0xb8: case 0xb9: case 0xba: case 0xbb:
      case 0xbc: case 0xbd: case 0xbe: case 0xbf:

      case 0xc0: case 0xc1: case 0xc2: case 0xc3:
      case 0xc4: case 0xc5: case 0xc6: case 0xc7:
      case 0xc8: case 0xc9: case 0xca: case 0xcb:
      case 0xcc: case 0xcd: case 0xce: case 0xcf:

      case 0xd0: case 0xd1: case 0xd2: case 0xd3:
      case 0xd4: case 0xd5: case 0xd6: case 0xd7:
      case 0xd8: case 0xd9: case 0xda: case 0xdb:
        // [6] '%' ... 'w'
        index = (int) ((top - 0x90) >> 2);
        bits -= 6;

        chars[offset++] = charTable[6][index];
        break;

      case 0xdc: case 0xdd: case 0xde: case 0xdf:

      case 0xe0: case 0xe1: case 0xe2: case 0xe3:
      case 0xe4: case 0xe5: case 0xe6: case 0xe7:
        // [7]
        index = (int) ((top - 0xdc) >> 1);
        bits -= 7;

        chars[offset++] = charTable[7][index];
        break;

      case 0xe8: case 0xe9: case 0xea: case 0xeb:
      case 0xec: case 0xed: case 0xee: case 0xef:

      case 0xf0: case 0xf1: case 0xf2: case 0xf3:
      case 0xf4: case 0xf5:
        // [8]
        index = (int) (top - 0xe8);
        bits -= 8;

        chars[offset++] = charTable[8][index];
        break;

      case 0xf6: case 0xf7: case 0xf8: case 0xf9:
      case 0xfa: case 0xfb: case 0xfc: case 0xfd:
        // [9]

      case 0xfe:
        // [9-10]

      case 0xff:
        // [10 - 27]

      {
        HuffmanProgram ptr = topProgram.getChild(top);

        int bitOff = 16;

        while (ptr != null && ! ptr.isFinal()) {
          int t1 = (int) ((chunk >> (bits - bitOff)) & 0xff);

          ptr = ptr.getChild(t1);
          bitOff += 8;
        }

        if (ptr == null || bits - tailBits < ptr.getLength()) {
          return offset;
        }

        chars[offset++] = (char) ptr.getChar();
        bits -= ptr.getLength();
        break;
      }
      }
    }
  }

  static class TableEntry {
    private long _sequence;
    private String _key;
    private String _value;

    private int _hashCode;
    
    private long _reference;
    
    // used for static
    private TableEntry _next;

    public TableEntry()
    {
    }

    public TableEntry(TableEntry next)
    {
      update(0, next.getKey(), next.getValue());
      
      _next = next;
    }

    public TableEntry(long sequence, String key, String value)
    {
      update(sequence, key, value);
    }

    public final long getSequence()
    {
      return _sequence;
    }

    public final void setSequence(long sequence)
    {
      _sequence = sequence;
    }

    public final void setReference(long reference)
    {
      _reference = reference;
    }

    public final long getReference()
    {
      return _reference;
    }

    public boolean isStatic()
    {
      return false;
    }
    
    public TableEntry getNext()
    {
      return _next;
    }

    public void update(long sequence, String key, String value)
    {
      _sequence = sequence;
      _key = key;
      _value = value;

      _hashCode = key.hashCode() * 65521 + value.hashCode();
    }

    public final String getKey()
    {
      return _key;
    }

    public final String getValue()
    {
      return _value;
    }

    public int getSize()
    {
      return 32 + getKey().length() + getValue().length();
    }

    @Override
    public final int hashCode()
    {
      return _hashCode;
    }

    @Override
    public final boolean equals(Object o)
    {
      TableEntry entry = (TableEntry) o;

      return _key.equals(entry._key) && _value.equals(entry._value);
    }

    @Override
    public String toString()
    {
      return (getClass().getSimpleName()
              + "[" + _sequence + "," + _key + "," + _value + "]");
    }
  }

  private static class TableEntryStatic extends TableEntry
  {
    public TableEntryStatic(long sequence, String key, String value)
    {
      super(sequence, key, value);
    }

    @Override
    public boolean isStatic()
    {
      return true;
    }
  }

  abstract private static class HuffmanProgram {
    private final int _ch;
    private final int _code;
    private final int _length;

    HuffmanProgram(int ch, int code, int length)
    {
      _ch = ch;
      _code = code;
      _length = length;
    }

    public boolean isFinal()
    {
      return false;
    }

    final int getChar()
    {
      return _ch;
    }

    final int getCode()
    {
      return _code;
    }

    final int getLength()
    {
      return _length;
    }

    HuffmanProgram getChild(int i)
    {
      throw new UnsupportedOperationException(getClass().getName());
    }

    HuffmanProgram addPartial(int code)
    {
      throw new UnsupportedOperationException(getClass().getName());
    }

    void addFinal(int code, HuffmanCode entry)
    {
      throw new UnsupportedOperationException(getClass().getName());
    }
  }

  private static final class HuffmanPartial extends HuffmanProgram {
    private HuffmanProgram []_children = new HuffmanProgram[256];

    HuffmanPartial()
    {
      super(0, 0, 1);
    }

    @Override
    HuffmanProgram getChild(int i)
    {
      return _children[i];
    }

    @Override
    HuffmanProgram addPartial(int code)
    {
      code = code & 0xff;

      HuffmanProgram child = _children[code];

      if (child == null) {
        child = new HuffmanPartial();
        _children[code] = child;
      }
      else if (child.isFinal()) {
        throw new IllegalStateException("0x" + Integer.toHexString(code) + " " + String.valueOf(child));
      }

      return child;
    }

    @Override
    void addFinal(int code, HuffmanCode entry)
    {
      code = code & 0xff;

      HuffmanProgram child = _children[code];

      if (child == null) {
        _children[code] = entry;
      }
      else {
        throw new IllegalStateException("0x" + Integer.toHexString(code) + " " + String.valueOf(child));
      }
    }
  }

  static final class HuffmanCode extends HuffmanProgram {
    HuffmanCode(int ch, int code, int length)
    {
      super(ch, code, length);
    }

    @Override
    public final boolean isFinal()
    {
      return true;
    }

    @Override
    public String toString()
    {
      return (getClass().getSimpleName()
          + "[0x" + Integer.toHexString(getChar()) + "(" + (int) getChar() + ")"
          + ",0x" + Integer.toHexString(getCode())
          + "," + getLength() + "]");
    }
  }

  static class HuffmanBuilder {
    private ArrayList> _decoder = new ArrayList<>();
    private HuffmanPartial _top = new HuffmanPartial();
    private HuffmanCode []_encode = new HuffmanCode[256];

    void add(int ch, int code, int length)
    {
      try {
        HuffmanCode entry = new HuffmanCode(ch, code, length);
        _encode[ch] = entry;

        while (_decoder.size() <= length) {
          _decoder.add(new ArrayList());
        }

        ArrayList charList = _decoder.get(length);
        charList.add((char) ch);

        HuffmanProgram ptr = _top;
        int codePtr = code;

        while (length > 8) {
          int op = codePtr >> (length - 8);

          ptr = ptr.addPartial(op);
          length -= 8;
        }

        codePtr = (codePtr << (8 - length)) & 0xff;

        int sublen = (1 << (8 - length));

        for (int i = 0; i < sublen; i++) {
          ptr.addFinal(codePtr + i, entry);
        }
      } catch (Exception e) {
        throw new IllegalStateException("ch=" + ch + " (0x" + Integer.toHexString(ch) + ")"
                                        + ",code=0x" + Integer.toHexString(code)
                                        + ",len=" + length + ": " + e.getMessage(),
                                        e);
      }
    }

    public HuffmanCode[] getEncoder()
    {
      return _encode;
    }

    public HuffmanProgram getDecodeProgram()
    {
      return _top;
    }

    public char[][] getDecodeTable()
    {
      char [][] table = new char[_decoder.size()][];

      for (int i = 0; i < _decoder.size(); i++) {
        ArrayList charList = _decoder.get(i);

        table[i] = new char[charList.size()];

        for (int j = 0; j < charList.size(); j++) {
          table[i][j] = charList.get(j);
        }
      }

      return table;
    }
  }

  static {
    _tableKeyStatic = new HashMap<>();
    _tableEntryStatic = new HashMap<>();

    ArrayList list = new ArrayList<>();

    // 00
    list.add(null);
    addTableStatic(list, ":authority", "");
    addTableStatic(list, ":method", "GET");
    addTableStatic(list, ":method", "POST");
    addTableStatic(list, ":path", "/");
    
    addTableStatic(list, ":path", "/index.html");
    addTableStatic(list, ":scheme", "http");
    addTableStatic(list, ":scheme", "https");
    addTableStatic(list, ":status", "200");
    addTableStatic(list, ":status", "204");
    
    // 10
    addTableStatic(list, ":status", "206");
    addTableStatic(list, ":status", "304");
    addTableStatic(list, ":status", "400");
    addTableStatic(list, ":status", "404");
    addTableStatic(list, ":status", "500");
    
    addTableStatic(list, "accept-charset", "");
    addTableStatic(list, "accept-encoding", "gzip, deflate");
    addTableStatic(list, "accept-language", "");
    addTableStatic(list, "accept-ranges", "");
    addTableStatic(list, "accept", "");
    
    // 20
    addTableStatic(list, "access-control-allow-origin", "");
    addTableStatic(list, "age", "");
    addTableStatic(list, "allow", "");
    addTableStatic(list, "authorization", "");
    addTableStatic(list, "cache-control", "");
    
    addTableStatic(list, "content-disposition", "");
    addTableStatic(list, "content-encoding", "");
    addTableStatic(list, "content-language", "");
    addTableStatic(list, "content-length", "");
    addTableStatic(list, "content-location", "");
    
    // 30
    addTableStatic(list, "content-range", "");
    addTableStatic(list, "content-type", "");
    addTableStatic(list, "cookie", "");
    addTableStatic(list, "date", "");
    addTableStatic(list, "etag", "");

    addTableStatic(list, "expect", "");
    addTableStatic(list, "expires", "");
    addTableStatic(list, "from", "");
    addTableStatic(list, "host", "");
    addTableStatic(list, "if-match", "");

    // 40
    addTableStatic(list, "if-modified-since", "");
    addTableStatic(list, "if-none-match", "");
    addTableStatic(list, "if-range", "");
    addTableStatic(list, "if-unmodified-since", "");
    addTableStatic(list, "last-modified", "");
    
    addTableStatic(list, "link", "");
    addTableStatic(list, "location", "");
    addTableStatic(list, "max-forwards", "");
    addTableStatic(list, "proxy-authenticate", "");
    addTableStatic(list, "proxy-authorization", "");

    // 50
    addTableStatic(list, "range", "");
    addTableStatic(list, "referer", "");
    addTableStatic(list, "refresh", "");
    addTableStatic(list, "retry-after", "");
    addTableStatic(list, "server", "");
    
    addTableStatic(list, "set-cookie", "");
    addTableStatic(list, "strict-transport-security", "");
    addTableStatic(list, "transfer-encoding", "");
    addTableStatic(list, "user-agent", "");
    addTableStatic(list, "vary", "");
    
    // 60
    addTableStatic(list, "via", "");
    addTableStatic(list, "www-authenticate", "");

    _staticEntryArray = new TableEntry[list.size()];
    list.toArray(_staticEntryArray);

    HuffmanBuilder builder = new HuffmanBuilder();

    for (int i = 0; i <= 31; i++) {
      builder.add(i, 0x3ffffba + i, 26);
    }

    builder.add(0x20, 0x0006, 5); // ' '
    builder.add(0x21, 0x1ffc, 13); // '!'
    builder.add(0x22, 0x01f0, 9); // '"'
    builder.add(0x23, 0x3ffc, 14); // '#'
    builder.add(0x24, 0x7ffc, 15); // '$'
    builder.add(0x25, 0x001e, 6); // '%'
    builder.add(0x26, 0x0064, 7); // '&'
    builder.add(0x27, 0x1ffd, 13); // '''
    builder.add(0x28, 0x03fa, 10); // '('
    builder.add(0x29, 0x01f1, 9); // ')'
    builder.add(0x2a, 0x03fb, 10); // '*'
    builder.add(0x2b, 0x03fc, 10); // '+'
    builder.add(0x2c, 0x0065, 7); // ','
    builder.add(0x2d, 0x0066, 7); // '-'
    builder.add(0x2e, 0x001f, 6); // '.'
    builder.add(0x2f, 0x0007, 5); // '/'

    builder.add(0x30, 0x0000, 4); // '0'
    builder.add(0x31, 0x0001, 4); // '1'
    builder.add(0x32, 0x0002, 4); // '2'
    builder.add(0x33, 0x0008, 5); // '3'
    builder.add(0x34, 0x0020, 6); // '4'
    builder.add(0x35, 0x0021, 6); // '5'
    builder.add(0x36, 0x0022, 6); // '6'
    builder.add(0x37, 0x0023, 6); // '7'
    builder.add(0x38, 0x0024, 6); // '8'
    builder.add(0x39, 0x0025, 6); // '9'
    builder.add(0x3a, 0x0026, 6); // ':'
    builder.add(0x3b, 0x00ec, 8); // ';'
    builder.add(0x3c, 0x1fffc, 17); // '<'
    builder.add(0x3d, 0x0027, 6); // '='
    builder.add(0x3e, 0x7ffd, 15); // '>'
    builder.add(0x3f, 0x03fd, 10); // '?'

    builder.add(0x40, 0x7ffe, 15); // '@'
    builder.add(0x41, 0x0067, 7); // 'A'
    builder.add(0x42, 0x00ed, 8); // 'B'
    builder.add(0x43, 0x00ee, 8); // 'C'
    builder.add(0x44, 0x0068, 7); // 'D'
    builder.add(0x45, 0x00ef, 8); // 'E'
    builder.add(0x46, 0x0069, 7); // 'F'
    builder.add(0x47, 0x006a, 7); // 'G'
    builder.add(0x48, 0x01f2, 9); // 'H'
    builder.add(0x49, 0x00f0, 8); // 'I'
    builder.add(0x4a, 0x01f3, 9); // 'J'
    builder.add(0x4b, 0x01f4, 9); // 'K'
    builder.add(0x4c, 0x01f5, 9); // 'L'
    builder.add(0x4d, 0x006b, 7); // 'M'
    builder.add(0x4e, 0x006c, 7); // 'N'
    builder.add(0x4f, 0x00f1, 8); // 'O'

    builder.add(0x50, 0x00f2, 8); // 'P'
    builder.add(0x51, 0x01f6, 9); // 'Q'
    builder.add(0x52, 0x01f7, 9); // 'R'
    builder.add(0x53, 0x006d, 7); // 'S'
    builder.add(0x54, 0x0028, 6); // 'T'
    builder.add(0x55, 0x00f3, 8); // 'U'
    builder.add(0x56, 0x01f8, 9); // 'V'
    builder.add(0x57, 0x01f9, 9); // 'W'
    builder.add(0x58, 0x00f4, 8); // 'X'
    builder.add(0x59, 0x01fa, 9); // 'Y'
    builder.add(0x5a, 0x01fb, 9); // 'Z'
    builder.add(0x5b, 0x07fc, 11); // '['
    builder.add(0x5c, 0x3ffffda, 26); // '\'
    builder.add(0x5d, 0x07fd, 11); // ']'
    builder.add(0x5e, 0x3ffd, 14); // '^'
    builder.add(0x5f, 0x006e, 7); // '_'

    builder.add(0x60, 0x3fffe, 18); // '`'
    builder.add(0x61, 0x0009, 5); // 'a'
    builder.add(0x62, 0x006f, 7); // 'b'
    builder.add(0x63, 0x000a, 5); // 'c'
    builder.add(0x64, 0x0029, 6); // 'd'
    builder.add(0x65, 0x000b, 5); // 'e'
    builder.add(0x66, 0x0070, 7); // 'f'
    builder.add(0x67, 0x002a, 6); // 'g'
    builder.add(0x68, 0x002b, 6); // 'h'
    builder.add(0x69, 0x000c, 5); // 'i'
    builder.add(0x6a, 0x00f5, 8); // 'j'
    builder.add(0x6b, 0x00f6, 8); // 'k'
    builder.add(0x6c, 0x002c, 6); // 'l'
    builder.add(0x6d, 0x002d, 6); // 'm'
    builder.add(0x6e, 0x002e, 6); // ''
    builder.add(0x6f, 0x000d, 5); // 'o'

    builder.add(0x70, 0x002f, 6); // 'p'
    builder.add(0x71, 0x01fc, 9); // 'q'
    builder.add(0x72, 0x0030, 6); // 'r'
    builder.add(0x73, 0x0031, 6); // 's'
    builder.add(0x74, 0x000e, 5); // 't'
    builder.add(0x75, 0x0071, 7); // 'u'
    builder.add(0x76, 0x0072, 7); // 'v'
    builder.add(0x77, 0x0073, 7); // 'w'
    builder.add(0x78, 0x0074, 7); // 'x'
    builder.add(0x79, 0x0075, 7); // 'y'
    builder.add(0x7a, 0x00f7, 8); // 'z'
    builder.add(0x7b, 0x1fffd, 17); // '{'
    builder.add(0x7c, 0x0ffc, 12); // '|'
    builder.add(0x7d, 0x1fffe, 17); // '}'
    builder.add(0x7e, 0x0ffd, 12); // '~'

    for (int i = 127; i <= 163; i++) {
      builder.add(i, 0x3ffffdb + i - 127, 26);
    }

    for (int i = 164; i < 256; i++) {
      builder.add(i, 0x1ffff80 + i - 164, 25);
    }

    _huffmanEncoding = builder.getEncoder();
    _huffmanDecodeTable = builder.getDecodeTable();
    _huffmanDecodeProgram = builder.getDecodeProgram();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy