blob: cfd5651ac9839f8c5a346d6a01210d7ab45dcee9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.imaging.common.itu_t4;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.imaging.common.BitInputStreamFlexible;
/**
* A Huffman tree implemented as 1 array for high locality of reference.
*/
class HuffmanTree {
private final static class Node {
boolean isEmpty = true;
Object value = null;
}
private List<Node> nodes = new ArrayList<Node>();
public final void insert(String pattern, Object value) throws HuffmanTreeException {
int position = 0;
Node node = growAndGetNode(position);
if (node.value != null) {
throw new HuffmanTreeException("Can't add child to a leaf");
}
for(int patternPosition = 0; patternPosition < pattern.length(); patternPosition++) {
char nextChar = pattern.charAt(patternPosition);
if (nextChar == '0') {
position = (position << 1) + 1;
} else {
position = (position + 1) << 1;
}
node = growAndGetNode(position);
if (node.value != null) {
throw new HuffmanTreeException("Can't add child to a leaf");
}
}
node.value = value;
}
private Node growAndGetNode(int position) {
while (position >= nodes.size()) {
nodes.add(new Node());
}
Node node = nodes.get(position);
node.isEmpty = false;
return node;
}
public final Object decode(BitInputStreamFlexible bitStream) throws HuffmanTreeException {
int position = 0;
Node node = nodes.get(0);
while (node.value == null) {
int nextBit;
try {
nextBit = bitStream.readBits(1);
} catch (IOException ioEx) {
throw new HuffmanTreeException("Error reading stream for huffman tree", ioEx);
}
if (nextBit == 0) {
position = (position << 1) + 1;
} else {
position = (position + 1) << 1;
}
if (position >= nodes.size()) {
throw new HuffmanTreeException("Invalid bit pattern");
}
node = nodes.get(position);
if (node.isEmpty) {
throw new HuffmanTreeException("Invalid bit pattern");
}
}
return node.value;
}
}