/******************************************************************************* * Copyright (c) 2005-2011, G. Weirich and Elexis * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * G. Weirich - initial implementation * *******************************************************************************/ package ch.rgw.compress; import java.io.IOException; import java.io.OutputStream; import ch.rgw.io.BitOutputStream; import ch.rgw.tools.IntTool; /** * A Stream that compresses its output on the fly with the Huffmann algorithm<br> * A Huffman tree can be provided by the caller. The tree can be declared dynamic to be recomputed * regularly (for not in advance analyzable Stream with very variable data). * * @author Gerry */ public class HuffmanOutputStream extends OutputStream { public static String Version(){ return "0.1.4"; } static final byte[] signature = new byte[] { 'H', 'O', 'S', '0', '4' }; BitOutputStream bos; HuffmanTree tree; int dyn; int counter; int[] tbl; /** * The only Constructor * * @param sup * a Stream to receive the output ultimately * @param tree * tree a precomputed Huffman tree or null. If null, a standard tree for textual * files will be used. * @param dynamic * if !=0: The tree will be recomputed every <dynamic> bytes */ public HuffmanOutputStream(OutputStream sup, HuffmanTree tr, int dynamic) throws IOException{ if (tr == null) { tree = new HuffmanTree(); tbl = HuffmanTree.useTable(HuffmanTree.TextDeutsch); } else { tree = tr; tbl = tree.getTable(); } tree.build(tbl); sup.write(signature); IntTool.writeInt(dynamic, sup); tree.saveTable(sup); bos = new BitOutputStream(sup); dyn = dynamic; if (dyn != 0) { tbl = new int[HuffmanTree.TABLESIZE]; } } public void write(int c) throws IOException{ if (Huff.writeByte(tree.getRootNode(), bos, c) == false) { // System.out.println("Escaped"); } if (dyn > 0) { tbl[c]++; if (++counter == dyn) { tree.build(tbl); tbl = new int[HuffmanTree.TABLESIZE]; counter = 0; } } } public void flush() throws IOException{ bos.flush(); } /** * terminate the stream: An EOF marker is written and he Stream is closed. If you don't store * Informations about the length of the original data, you should always end with close(), * because HuffmanInputStream can not determine the end of the compressed data. */ public void close() throws IOException{ // Huff.writeByte(tree.getRootNode(),bos,Huff.escape); // write(Huff.eof); Huff.writeEOF(tree.getRootNode(), bos); bos.close(); } }