1. BitInputStream.java
import java.io.*;
/**
* Reads bits-at-a-time where the number of bits is between 1 and 32.
* Updated for version 2.0 to extend java.io.InputStream. This class
* can be used together with <code>BitOutputStream</code> to facilitate
* reading and writing data several bits-at-a-time. BitInputStream objects
* that are constructed from a File support <code>reset()</code>. However,
* if constructed from an <code>InputStream</code> an object cannot be reset.
* <P>
* Any exceptions generated are rethrown as <code>RuntimeException</code> objects
* so client code does not have to catch or rethrow them. (Unless the extension
* of <code>InputStream</code> requires throwing as another type of exception, e.g.,
* as with method <code>read</code>.
* <P>
* @author Owen Astrachan
* @version 1.0, July 2000
* @version 2.0, October 2004
*/
public class BitInputStream extends InputStream
{
private InputStream myInput;
private int myBitCount;
private int myBuffer;
private File myFile;
private static final int bmask[] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
0x1ff,0x3ff,0x7ff,0xfff,0x1fff,0x3fff,0x7fff,0xffff,
0x1ffff,0x3ffff,0x7ffff,0xfffff,0x1fffff,0x3fffff,
0x7fffff,0xffffff,0x1ffffff,0x3ffffff,0x7ffffff,
0xfffffff,0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff
};
private static final int BITS_PER_BYTE = 8;
/**
* Construct a bit-at-a-time input stream from a file whose
* name is supplied.
* @param filename is the name of the file that will be read.
* @throws RuntimeException if filename cannot be opened.
*/
public BitInputStream(String filename)
{
this(new File(filename));
}
/**
* Construct a bit-at-a-time input stream from <code>file</code>.
* @param file is the File that is the source of the input
* @throws RuntimeExceptoin if file cannot be opened.
*/
public BitInputStream(File file)
{
myFile = file;
2. try {
reset();
} catch (IOException e) {
throw new RuntimeException("could not open file for reading bits "+e);
}
}
/**
* Open a bit-at-a-time stream that reads from supplied InputStream. If this
* constructor is used the BitInputStream is not reset-able.
* @param in is the stream from which bits are read.
*/
public BitInputStream(InputStream in){
myInput = in;
myFile = null;
}
/**
* Return true if the stream has been initialized from a File and
* is thus reset-able. If constructed from an InputStream it is not reset-able.
* @return true if stream can be reset (it has been constructed appropriately from a File).
*/
public boolean markSupported(){
return myFile != null;
}
/**
* Reset stream to beginning. The implementation creates a new
* stream.
* @throws IOException if not reset-able (e.g., constructed from InputStream).
*/
public void reset() throws IOException
{
if (! markSupported()){
throw new IOException("not resettable");
}
try{
close();
myInput = new BufferedInputStream(new FileInputStream(myFile));
}
catch (FileNotFoundException fnf){
System.err.println("error opening " + myFile.getName() + " " + fnf);
}
myBuffer = myBitCount = 0;
}
/**
* Closes the input stream.
* @throws RuntimeException if the close fails
*/
public void close()
{
try{
if (myInput != null) {
3. myInput.close();
}
}
catch (java.io.IOException ioe){
throw new RuntimeException("error closing bit stream " + ioe);
}
}
/**
* Returns the number of bits requested as rightmost bits in
* returned value, returns -1 if not enough bits available to
* satisfy the request.
*
* @param howManyBits is the number of bits to read and return
* @return the value read, only rightmost <code>howManyBits</code>
* are valid, returns -1 if not enough bits left
*/
public int readBits(int howManyBits) throws IOException
{
int retval = 0;
if (myInput == null){
return -1;
}
while (howManyBits > myBitCount){
retval |= ( myBuffer << (howManyBits - myBitCount) );
howManyBits -= myBitCount;
try{
if ( (myBuffer = myInput.read()) == -1) {
return -1;
}
}
catch (IOException ioe) {
throw new IOException("bitreading trouble "+ioe);
}
myBitCount = BITS_PER_BYTE;
}
if (howManyBits > 0){
retval |= myBuffer >> (myBitCount - howManyBits);
myBuffer &= bmask[myBitCount - howManyBits];
myBitCount -= howManyBits;
}
return retval;
}
/**
* Required by classes extending InputStream, returns
* the next byte from this stream as an int value.
* @return the next byte from this stream
*/
public int read() throws IOException {
return readBits(8);
}
}
4. BitOutputStream.java
/**
* Write bits-at-a-time where the number of bits is between 1 and 32
* Client programs must call <code>flush</code> or
* <code>close</code> when finished writing or not all bits will be written.
* This class is intended to be used with <code>BitInputStream</code> to
* facilitate reading and writing data in a bits-at-a-time manner.
* <P>
* Updated for version 2.0 to extend java.io.OutputStream
* <P>
* Any exceptions generated are rethrown as <code>RuntimeException</code> objects
* so client code does not have to catch or rethrow them.
* <P>
* @author Owen Astrachan
* @version 1.0, July 2000
* @version 2.0, October 2004
*/
import java.io.*;
public class BitOutputStream extends OutputStream
{
private OutputStream myOutput;
private int myBuffer;
private int myBitsToGo;
private static final int bmask[] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
0x1ff,0x3ff,0x7ff,0xfff,0x1fff,0x3fff,0x7fff,0xffff,
0x1ffff,0x3ffff,0x7ffff,0xfffff,0x1fffff,0x3fffff,
0x7fffff,0xffffff,0x1ffffff,0x3ffffff,0x7ffffff,
0xfffffff,0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff
};
private static final int BITS_PER_BYTE = 8;
/**
* Required by OutputStream subclasses, write the low
* 8-bits to the underlying outputstream
*/
public void write(int b) throws IOException {
myOutput.write(b);
}
/**
* Create a stream that writes-through to the <code>OutputStream</code> object
* passed as a parameter.
* @param out is the output stream to which bits are written
*/
public BitOutputStream(OutputStream out){
myOutput = out;
initialize();
}
5. private void initialize(){
myBuffer = 0;
myBitsToGo = BITS_PER_BYTE;
}
/**
* Construct a bit-at-a-time output stream with specified file
* name.
* @param filename is the name of the file being written
* @throws RuntimeException if opening file fails for either FileNotFound
* or for Security exceptoins
*/
public BitOutputStream(String filename)
{
try{
myOutput = new BufferedOutputStream(new FileOutputStream(filename));
}
catch (FileNotFoundException fnf){
throw new RuntimeException("could not create " + filename + " " + fnf);
}
catch(SecurityException se){
throw new RuntimeException("security exception on write " + se);
}
initialize();
}
/**
* Flushes bits not yet written, must be called by client
* programs if <code>close</code> isn't called.
* @throws RuntimeException if there's a problem writing bits
*/
public void flush()
{
if (myBitsToGo != BITS_PER_BYTE) {
try{
write( (myBuffer << myBitsToGo) );
}
catch (java.io.IOException ioe){
throw new RuntimeException("error writing bits on flush " + ioe);
}
myBuffer = 0;
myBitsToGo = BITS_PER_BYTE;
}
try{
myOutput.flush();
}
catch (java.io.IOException ioe){
throw new RuntimeException("error on flush " + ioe);
}
}
/**
* Releases system resources associated with file and
* flushes bits not yet written. Either this function
* or flush must be called or not all bits will be written
* @throws RuntimeException if close fails
6. */
public void close()
{
flush();
try{
myOutput.close();
}
catch (IOException ioe){
throw new RuntimeException("error closing BitOutputStream " + ioe);
}
}
/**
* Write specified number of bits from value to a file.
* @param howManyBits is number of bits to write (1-32)
* @param value is source of bits, rightmost bits are written
* @throws RuntimeException if there's an I/O problem writing bits
*/
public void writeBits(int howManyBits, int value)
{
value &= bmask[howManyBits]; // only right most bits valid
while (howManyBits >= myBitsToGo){
myBuffer = (myBuffer << myBitsToGo) |
(value >> (howManyBits - myBitsToGo));
try{
write(myBuffer);
}
catch (java.io.IOException ioe){
throw new RuntimeException("error writing bits " + ioe);
}
value &= bmask[howManyBits - myBitsToGo];
howManyBits -= myBitsToGo;
myBitsToGo = BITS_PER_BYTE;
myBuffer = 0;
}
if (howManyBits > 0) {
myBuffer = (myBuffer << howManyBits) | value;
myBitsToGo -= howManyBits;
}
}
}
7. Diff.java
import java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.ProgressMonitorInputStream;
public class Diff
{
protected static JFileChooser ourChooser = new JFileChooser(".");
public Diff(){
}
public static void showMessage(String message){
JOptionPane.showMessageDialog(null, message,"Diff Output",
JOptionPane.INFORMATION_MESSAGE);
}
public static boolean doDiffer(File[] files){
try {
ProgressMonitorInputStream stream1 =
new ProgressMonitorInputStream(
null,
"reading "+files[0].getName(),
new FileInputStream(files[0]));
ProgressMonitorInputStream stream2 =
new ProgressMonitorInputStream(
null,
"reading "+files[1].getName(),
new FileInputStream(files[1]));
BitInputStream b1 = new BitInputStream(stream1);
BitInputStream b2 = new BitInputStream(stream2);
while (true) {
int x = b1.readBits(8);
int y = b2.readBits(8);
if (x == -1) return y == -1;
if (y == -1) return false;
if (x != y) return false;
}
// never reached
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null,"trouble reading","Diff Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
}
public static void main(String[] args){
ourChooser.setMultiSelectionEnabled(true);
ourChooser.setDialogTitle("Diff: choose two files");
int retval = ourChooser.showOpenDialog(null);
if (retval == JFileChooser.APPROVE_OPTION){
File[] files = ourChooser.getSelectedFiles();
8. if (files.length != 2){
JOptionPane.showMessageDialog(null,"Choose Two Files",
"Diff Error",JOptionPane.ERROR_MESSAGE);
}
else {
if (doDiffer(files)){
showMessage("Files are the same");
}
else {
showMessage("Files DIFFER somewhere");
}
}
}
System.exit(0);
}
}
Huff.java
/**
* Main/launch program for Huff assignment. A better
* comment than this is warranted.
* @author YOU THE STUDENT
*
*/
public class Huff {
public static void main(String[] args){
HuffViewer sv = new HuffViewer("Duke Compsci Huffing");
IHuffProcessor proc = new SimpleHuffProcessor();
sv.setModel(proc);
}
}
9. HuffMark.java
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class HuffMark {
protected static JFileChooser ourOpenChooser = new JFileChooser(System
.getProperties().getProperty("user.dir"));
static {
ourOpenChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
}
private double myTotalCompressTime;
private long myTotalUncompressedBytes;
private long myTotalCompressedBytes;
private IHuffProcessor myHuffer;
private static String SUFFIX = ".hf";
private static boolean FAST_READER = true;
public void compress(File f) throws IOException{
if (f.getName().endsWith(SUFFIX)) return; // don't read .hf files!
if (f.isDirectory()) return; // don't read directories
double start = System.currentTimeMillis();
myHuffer.preprocessCompress(getFastByteReader(f));
File outFile = new File(getCompressedName(f));
FileOutputStream out = new FileOutputStream(outFile);
System.out.println("compressing to: "+outFile.getCanonicalPath());
myHuffer.compress(getFastByteReader(f), out,true);
double end = System.currentTimeMillis();
double time = (end-start)/1000.0;
myTotalUncompressedBytes += f.length();
myTotalCompressedBytes += outFile.length();
myTotalCompressTime += time;
System.out.printf("%s fromt %d tot %d int %.3fn",f.getName(),f.length(),outFile.length(),time);
}
public void doMark() throws IOException{
if (myHuffer == null){
myHuffer = new SimpleHuffProcessor();
}
int action = ourOpenChooser.showOpenDialog(null);
if (action == JFileChooser.APPROVE_OPTION){
File dir = ourOpenChooser.getSelectedFile();
File[] list = dir.listFiles();
for(File f : list){
11. HuffViewer.java
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* The GUI/View for Huffman coding assignment. Clients communicate
* with this view by attaching a model and then using the menu choices/options that
* are part of the GUI. Thus client code that fails to call <code>setModel</code> will
* almost certainly not work and generate null pointer problems because the view/GUI will
* not have an associated model.
* <P>
* @author Owen Astrachan
*
*/
public class HuffViewer extends JFrame {
private static String HUFF_SUFFIX = ".hf";
private static String UNHUFF_SUFFIX = ".unhf";
private static boolean FAST_READER = true;
protected JTextArea myOutput;
protected IHuffProcessor myModel;
protected String myTitle;
protected JTextField myMessage;
protected File myFile;
private boolean myForce;
protected static JFileChooser ourChooser =
new JFileChooser(System.getProperties().getProperty("user.dir"));
public HuffViewer(String title) {
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = (JPanel) getContentPane();
panel.setLayout(new BorderLayout());
setTitle(title);
myTitle = title;
myForce = false;
panel.add(makeOutput(), BorderLayout.CENTER);
panel.add(makeMessage(), BorderLayout.SOUTH);
makeMenus();
pack();
setSize(400, 400);
setVisible(true);
}
12. /**
* Associates this view with the given model. The GUI/View will
* attach itself to the model so that communication between the view
* and the model as well as <em>vice versa</em> is supported.
* @param model is the model for this view
*/
public void setModel(IHuffProcessor model) {
myModel = model;
myModel.setViewer(this);
}
protected JPanel makeMessage() {
JPanel p = new JPanel(new BorderLayout());
myMessage = new JTextField(30);
p.setBorder(BorderFactory.createTitledBorder("message"));
p.add(myMessage, BorderLayout.CENTER);
return p;
}
protected JPanel makeOutput() {
JPanel p = new JPanel(new BorderLayout());
myOutput = new JTextArea(10,40);
p.setBorder(BorderFactory.createTitledBorder("output"));
p.add(new JScrollPane(myOutput), BorderLayout.CENTER);
return p;
}
protected File doRead() {
int retval = ourChooser.showOpenDialog(null);
if (retval != JFileChooser.APPROVE_OPTION) {
return null;
}
showMessage("reading/initializing");
myFile = ourChooser.getSelectedFile();
ProgressMonitorInputStream temp = null;
if (FAST_READER){
temp = getMonitorableStream(getFastByteReader(myFile),"counting/reading bits ...");
}
else {
temp = getMonitorableStream(myFile,"counting/reading bits ...");
}
final ProgressMonitorInputStream pmis = temp;
final ProgressMonitor progress = pmis.getProgressMonitor();
try {
Thread fileReaderThread = new Thread() {
public void run() {
try {
int saved = myModel.preprocessCompress(pmis);
HuffViewer.this.showMessage("saved: "+saved+" bits");
} catch (IOException e) {
13. HuffViewer.this.showError("reading exception");
e.printStackTrace();
}
if (progress.isCanceled()) {
HuffViewer.this.showError("reading cancelled");
}
}
};
fileReaderThread.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File ret = myFile;
myFile = null;
return ret;
}
protected JMenu makeOptionsMenu() {
JMenu menu = new JMenu("Options");
JCheckBoxMenuItem force = new JCheckBoxMenuItem(new AbstractAction(
"Force Compression") {
public void actionPerformed(ActionEvent ev) {
myForce = !myForce;
}
});
menu.add(force);
return menu;
}
protected JMenu makeFileMenu() {
JMenu fileMenu = new JMenu("File");
fileMenu.add(new AbstractAction("Open/Count") {
public void actionPerformed(ActionEvent ev) {
doRead();
}
});
fileMenu.add(new AbstractAction("Compress") {
public void actionPerformed(ActionEvent ev) {
doSave();
}
});
fileMenu.add(new AbstractAction("Uncompress") {
public void actionPerformed(ActionEvent ev) {
doDecode();
}
});
fileMenu.add(new AbstractAction("Quit") {
public void actionPerformed(ActionEvent ev) {
System.exit(0);
}
14. });
return fileMenu;
}
protected void makeMenus() {
JMenuBar bar = new JMenuBar();
bar.add(makeFileMenu());
bar.add(makeOptionsMenu());
setJMenuBar(bar);
}
private void doDecode() {
File file = null;
showMessage("uncompressing");
try {
int retval = ourChooser.showOpenDialog(null);
if (retval != JFileChooser.APPROVE_OPTION) {
return;
}
file = ourChooser.getSelectedFile();
String name = file.getName();
String uname = name;
if (name.endsWith(HUFF_SUFFIX)) {
uname = name.substring(0,name.length() - HUFF_SUFFIX.length()) + UNHUFF_SUFFIX;
}
else {
uname = name + UNHUFF_SUFFIX;
}
String newName = JOptionPane.showInputDialog(this,
"Name of uncompressed file", uname);
if (newName == null) {
return;
}
String path = file.getCanonicalPath();
int pos = path.lastIndexOf(name);
newName = path.substring(0, pos) + newName;
final File newFile = new File(newName);
ProgressMonitorInputStream temp = null;
if (FAST_READER){
temp = getMonitorableStream(getFastByteReader(file),"uncompressing bits ...");
}
else {
temp = getMonitorableStream(file, "uncompressing bits...");
}
final ProgressMonitorInputStream stream = temp;
final ProgressMonitor progress = stream.getProgressMonitor();
final OutputStream out = new FileOutputStream(newFile);
Thread fileReaderThread = new Thread() {
public void run() {
try {
myModel.uncompress(stream, out);
} catch (IOException e) {
HuffViewer.this.showError("reading exception");
e.printStackTrace();
}
15. if (progress.isCanceled()) {
HuffViewer.this.showError("reading cancelled");
}
}
};
fileReaderThread.start();
} catch (FileNotFoundException e) {
showError("could not open " + file.getName());
e.printStackTrace();
} catch (IOException e) {
showError("IOException, uncompression halted from viewer");
e.printStackTrace();
}
}
private void doSave() {
myFile = doRead();
if (myFile == null){
return;
}
String name = myFile.getName();
showMessage("compressing "+name);
String newName = JOptionPane.showInputDialog(this,
"Name of compressed file", name + HUFF_SUFFIX);
if (newName == null) {
return;
}
String path = null;
try {
path = myFile.getCanonicalPath();
} catch (IOException e) {
showError("trouble with file canonicalizing");
return;
}
int pos = path.lastIndexOf(name);
newName = path.substring(0, pos) + newName;
final File file = new File(newName);
try {
final FileOutputStream out = new FileOutputStream(file);
ProgressMonitorInputStream temp = null;
if (FAST_READER){
temp = getMonitorableStream(getFastByteReader(myFile),"compressing bits...");
}
else {
temp = getMonitorableStream(myFile,"compressing bits ...");
}
final ProgressMonitorInputStream pmis = temp;
final ProgressMonitor progress = pmis.getProgressMonitor();
Thread fileWriterThread = new Thread() {
public void run() {
try {
myModel.compress(pmis, out,myForce);
} catch (IOException e) {
HuffViewer.this.showError("compression exception");
e.printStackTrace();
}
if (progress.isCanceled()) {
16. HuffViewer.this.showError("compression cancelled");
cleanUp(file);
}
}
};
fileWriterThread.start();
} catch (FileNotFoundException e) {
showError("could not open " + file.getName());
e.printStackTrace();
}
myFile = null;
}
private void cleanUp(File f) {
if (!f.delete()) {
showError("trouble deleting " + f.getName());
} else {
// do something here?
}
}
private ProgressMonitorInputStream getMonitorableStream(InputStream stream, String message) {
final ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
this, message, stream);
ProgressMonitor progress = pmis.getProgressMonitor();
progress.setMillisToDecideToPopup(1);
progress.setMillisToPopup(1);
return pmis;
}
private ProgressMonitorInputStream getMonitorableStream(File file,
String message) {
try {
FileInputStream stream = new FileInputStream(file);
if (stream == null){
System.out.println("null on "+file.getCanonicalPath());
}
final ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
this, message, stream);
ProgressMonitor progress = pmis.getProgressMonitor();
progress.setMillisToDecideToPopup(1);
progress.setMillisToPopup(1);
return pmis;
} catch (IOException e) {
showError("could not open " + file.getName());
e.printStackTrace();
return null;
}
}
17. /**
* To be called by model/client code to display strings in the GUI. Each object
* in parameter elements will be displayed as a string in this view.
* @param elements is source of objects that will be displayed, each object's
* <code>toString</code> method wil be called to display.
*/
public void update(Collection elements) {
showMessage("");
myOutput.setText("");
for(Object o : elements){
myOutput.append(o+"n");
}
}
/**
* Display a text message in the view (e.g., in the small text area
* at the bottom of the GUI), thus a modeless message the user can ignore.
* @param s is the message displayed
*/
public void showMessage(String s) {
myMessage.setText(s);
}
/**
* Show a modal-dialog indicating an error; the user must dismiss the
* displayed dialog.
* @param s is the error-message displayed
*/
public void showError(String s) {
JOptionPane.showMessageDialog(this, s, "Huff info",
JOptionPane.INFORMATION_MESSAGE);
}
private ByteArrayInputStream getFastByteReader(File f){
ByteBuffer buffer = null;
try {
FileChannel channel = new FileInputStream(f).getChannel();
buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
byte[] barray = new byte[buffer.limit()];
if (barray.length != channel.size()){
showError(String.format("Reading %s error: lengths differ %d
%ldn",f.getName(),barray.length,channel.size()));
}
buffer.get(barray);
return new ByteArrayInputStream(barray);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
18. IHuffConstants.java
/**
* Global constants used in Huff/Unhuff. Clients needing these
* values should implement this interface or access the
* values directly, e.g., as <code>IHuffConstants.BITS_PER_WORD</code>. However,
* implementing the interface is preferred in which case
* the values can be accessed simply as <code>BITS_PER_WORD</code>, for example.
* <P>
* @author Owen Astrachan
*/
public interface IHuffConstants {
/**
* The standard number of bits per chunk/word when huffing.
*/
public static final int BITS_PER_WORD = 8;
/**
* The size of the alphabet given the number of bits per chunk, this
* should be 2^BITS_PER_WORD.
*/
public static final int ALPH_SIZE = (1 << BITS_PER_WORD);
/**
* The standard number of bits needed to represent/store
* an int, this is 32 in Java and nearly all other languages.
*/
public static final int BITS_PER_INT = 32;
/**
* The value of the PSEUDO_EOF character. This is one-more
* than the maximum value of a legal BITS_PER_WORD-bit character.
*/
public static final int PSEUDO_EOF = ALPH_SIZE;
/**
* Isolate the magic number in one place.
*/
public static final int MAGIC_NUMBER = 1234567873;
}
19. IHuffProcessor.java
/**
* The interface for the model that can be attached
* to a HuffViewer. Most of the work done in huffing
* (and unhuffing) will be via a class that implements
* this interface. The interface may need to be extended
* depending on the design of the huffman program.
* <P>
* @author Owen Astrachan
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
public interface IHuffProcessor extends IHuffConstants {
/**
* Make sure this model communicates with some view.
* @param viewer is the view for communicating.
*/
public void setViewer(HuffViewer viewer);
/**
* Preprocess data so that compression is possible ---
* count characters/create tree/store state so that
* a subsequent call to compress will work. The InputStream
* is <em>not</em> a BitInputStream, so wrap it int one as needed.
* @param in is the stream which could be subsequently compressed
* @return number of bits saved by compression or some other measure
*/
public int preprocessCompress(InputStream in) throws IOException;
/**
* Compresses input to output, where the same InputStream has
* previously been pre-processed via <code>preprocessCompress</code>
* storing state used by this call.
* @param in is the stream being compressed (not a BitInputStream)
* @param out is bound to a file/stream to which bits are written
* for the compressed file (not a BitOutputStream)
* @return the number of bits written
*/
public int compress(InputStream in, OutputStream out, boolean force) throws IOException;
20. /**
* Uncompress a previously compressed stream in, writing the
* uncompressed bits/data to out.
* @param in is the previously compressed data (not a BitInputStream)
* @param out is the uncompressed file/stream
* @return the number of bits written to the uncompressed file/stream
*/
public int uncompress(InputStream in, OutputStream out) throws IOException;
}
SimpleHuffProcessor...>
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
public class SimpleHuffProcessor implements IHuffProcessor {
private HuffViewer myViewer;
public int compress(InputStream in, OutputStream out, boolean force) throws IOException {
myViewer.showError("compress is not implemented");
return 0;
}
public int preprocessCompress(InputStream in) throws IOException {
myViewer.showError("preprocessCompress is not implemented");
return 0;
}
public void setViewer(HuffViewer viewer) {
myViewer = viewer;
}
public int uncompress(InputStream in, OutputStream out) throws IOException {
myViewer.showError("uncompress is not implemented");
return 0;
}
private void showMessage(ArrayList<String> list){
myViewer.update(list);
}
}
21. TreeNode.java
/**
* Utility binary-tree (Huffman tree) node for Huffman coding.
* This is a simple, standard binary-tree node implementing
* the comparable interface based on weight.
*
* @author Owen Astrachan
* @version 1.0 July 2000
* @version 2.0 Jan 2006
*/
public class TreeNode implements Comparable<TreeNode> {
public int myValue;
public int myWeight;
public TreeNode myLeft;
public TreeNode myRight;
/**
* construct leaf node (null children)
*
* @param value
* is the value stored in the node (e.g., character)
* @param weight
* is used for comparison (e.g., count of # occurrences)
*/
public TreeNode(int value, int weight) {
myValue = value;
myWeight = weight;
}
/**
* construct internal node (with children)
*
* @param value
* is stored as value of node
* @param weight
* is weight of node
* @param ltree
* is left subtree
* @param rtree
* is right subtree
*/
22. public TreeNode(int value, int weight, TreeNode ltree, TreeNode rtree) {
this(value, weight);
myLeft = ltree;
myRight = rtree;
}
/**
* Return value based on comparing this TreeNode to another.
* @return -1 if this < o, +1 if this > o, and 0 if this == 0
*/
public int compareTo(TreeNode rhs) {
return myWeight - rhs.myWeight;
}
}