//
package net.sf.zipme;
class InflaterHuffmanTree {
private static final int MAX_BITLEN=15;
private short[] tree;
static InflaterHuffmanTree defLitLenTree, defDistTree;
static {
try {
byte[] codeLengths=new byte[288];
int i=0;
while (i < 144) codeLengths[i++]=8;
while (i < 256) codeLengths[i++]=9;
while (i < 280) codeLengths[i++]=7;
while (i < 288) codeLengths[i++]=8;
defLitLenTree=new InflaterHuffmanTree(codeLengths);
codeLengths=new byte[32];
i=0;
while (i < 32) codeLengths[i++]=5;
defDistTree=new InflaterHuffmanTree(codeLengths);
}
catch ( DataFormatException ex) {
throw new Error("InflaterHuffmanTree: static tree length illegal");
}
}
/**
* Constructs a Huffman tree from the array of code lengths.
* @param codeLengths the array of code lengths
*/
InflaterHuffmanTree( byte[] codeLengths) throws DataFormatException {
buildTree(codeLengths);
}
private void buildTree( byte[] codeLengths) throws DataFormatException {
int[] blCount=new int[MAX_BITLEN + 1];
int[] nextCode=new int[MAX_BITLEN + 1];
for (int i=0; i < codeLengths.length; i++) {
int bits=codeLengths[i];
if (bits > 0) blCount[bits]++;
}
int code=0;
int treeSize=512;
for (int bits=1; bits <= MAX_BITLEN; bits++) {
nextCode[bits]=code;
code+=blCount[bits] << (16 - bits);
if (bits >= 10) {
int start=nextCode[bits] & 0x1ff80;
int end=code & 0x1ff80;
treeSize+=(end - start) >> (16 - bits);
}
}
if (code != 65536) throw new DataFormatException("Code lengths don't add up properly.");
tree=new short[treeSize];
int treePtr=512;
for (int bits=MAX_BITLEN; bits >= 10; bits--) {
int end=code & 0x1ff80;
code-=blCount[bits] << (16 - bits);
int start=code & 0x1ff80;
for (int i=start; i < end; i+=1 << 7) {
tree[DeflaterHuffman.bitReverse(i)]=(short)((-treePtr << 4) | bits);
treePtr+=1 << (bits - 9);
}
}
for (int i=0; i < codeLengths.length; i++) {
int bits=codeLengths[i];
if (bits == 0) continue;
code=nextCode[bits];
int revcode=DeflaterHuffman.bitReverse(code);
if (bits <= 9) {
do {
tree[revcode]=(short)((i << 4) | bits);
revcode+=1 << bits;
}
while (revcode < 512);
}
else {
int subTree=tree[revcode & 511];
int treeLen=1 << (subTree & 15);
subTree=-(subTree >> 4);
do {
tree[subTree | (revcode >> 9)]=(short)((i << 4) | bits);
revcode+=1 << bits;
}
while (revcode < treeLen);
}
nextCode[bits]=code + (1 << (16 - bits));
}
}
/**
* Reads the next symbol from input. The symbol is encoded using the
* huffman tree.
* @param input the input source.
* @return the next symbol, or -1 if not enough input is available.
*/
int getSymbol( StreamManipulator input) throws DataFormatException {
int lookahead, symbol;
if ((lookahead=input.peekBits(9)) >= 0) {
if ((symbol=tree[lookahead]) >= 0) {
input.dropBits(symbol & 15);
return symbol >> 4;
}
int subtree=-(symbol >> 4);
int bitlen=symbol & 15;
if ((lookahead=input.peekBits(bitlen)) >= 0) {
symbol=tree[subtree | (lookahead >> 9)];
input.dropBits(symbol & 15);
return symbol >> 4;
}
else {
int bits=input.getAvailableBits();
lookahead=input.peekBits(bits);
symbol=tree[subtree | (lookahead >> 9)];
if ((symbol & 15) <= bits) {
input.dropBits(symbol & 15);
return symbol >> 4;
}
else return -1;
}
}
else {
int bits=input.getAvailableBits();
lookahead=input.peekBits(bits);
symbol=tree[lookahead];
if (symbol >= 0 && (symbol & 15) <= bits) {
input.dropBits(symbol & 15);
return symbol >> 4;
}
else return -1;
}
}
}