Basically this is a form of compression that I decided to recode... I did this awhile ago so... I forget some of the details...
Code not by me:
Bit input stream: (This reads the bits of a file one at a time)
Code:
import java.io.*;
/**
* reads bits-at-a-time where the number of bits is between 1 and 32
* @author Owen Astrachan
* @version 1.0, July 2000
*/
public class BitInputStream
{
/**
* Construct a bit-at-a-time input stream from a file
*/
public BitInputStream(String filename)
{
myFilename = filename;
rewind();
}
/**
* reset stream to beginning. The implementation creates a new
* stream.
*/
public void rewind()
{
try{
close();
myInput = new BufferedInputStream(new FileInputStream(myFilename));
}
catch (FileNotFoundException fnf){
System.err.println("error opening " + myFilename + " " + fnf);
}
reset();
}
/**
* Construct a bit-at-a-time input stream from <code>file</code>
* @param file is the File that is the source of the input
*/
public BitInputStream(File file)
{
try{
myFilename = file.getCanonicalPath();
}
catch (IOException ioe){
System.err.println("error in opening " + file + " " + ioe);
}
rewind();
}
/**
* closes the input stream
*/
public void close()
{
try{
if (myInput != null)
{
myInput.close();
}
}
catch (java.io.IOException ioe){
System.err.println("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 read(int howManyBits)
{
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) {
System.err.println("error reading input file " + ioe);
}
myBitCount = BITS_PER_BYTE;
}
if (howManyBits > 0)
{
retval |= myBuffer >> (myBitCount - howManyBits);
myBuffer &= bmask[myBitCount - howManyBits];
myBitCount -= howManyBits;
}
return retval;
}
private void reset()
{
myBuffer = myBitCount = 0;
}
private InputStream myInput;
private int myBitCount;
private int myBuffer;
private String myFilename;
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;
/**
* simple test harnass, reads a file whose name is specified
* on the command line, creates a file with same name and ".bos"
* suffix that is identical (hopefully) to file read
* this tests both <code>BitInputStream</code>
* and <code>BitOutputStream</code>
*/
}
Bit Writer: (This outputs bits 1 at a time)
Code:
import java.io.*;
/**
* 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.
*
* @author Owen Astrachan
* @version 1.0, July 2000
*/
public class BitOutputStream
{
/**
* Construct a bit-at-a-time output stream with specified file
* name
* @param filename is the name of the file bein written
*/
public BitOutputStream(String filename)
{
try{
myOutput = new BufferedOutputStream(new FileOutputStream(filename));
}
catch (FileNotFoundException fnf){
System.err.println("could not create " + filename + " " + fnf);
}
catch(SecurityException se){
System.err.println("security exception on write " + se);
}
myBuffer = 0;
myBitsToGo = BITS_PER_BYTE;
}
/**
* Flushes bits not yet written, must be called by client
* programs if <code>close</code> isn't called.
*
*/
public void flush()
{
if (myBitsToGo != BITS_PER_BYTE)
{
try{
myOutput.write( (myBuffer << myBitsToGo) );
}
catch (java.io.IOException ioe){
System.err.println("error writing bits on flush " + ioe);
}
myBuffer = 0;
myBitsToGo = BITS_PER_BYTE;
}
try{
((BufferedOutputStream) myOutput).flush();
}
catch (java.io.IOException ioe){
System.err.println("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
*
*/
public void close()
{
flush();
try{
myOutput.close();
}
catch (IOException ioe){
System.err.println("error closing BitOutputStream " + ioe);
}
}
/**
* write bits to file
* @param howManyBits is number of bits to write (1-32)
* @param value is source of bits, rightmost bits are written
*/
public void write(int howManyBits, int value)
{
value &= bmask[howManyBits]; // only right most bits valid
while (howManyBits >= myBitsToGo)
{
myBuffer = (myBuffer << myBitsToGo) |
(value >> (howManyBits - myBitsToGo));
try{
myOutput.write(myBuffer);
}
catch (java.io.IOException ioe){
System.err.println("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;
}
}
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;
}
Code by me:
A Generic TreeNode...
Code:
public class TreeNode<E extends Comparable<E>> implements Comparable<TreeNode<E>>{
private TreeNode<E> left;
private TreeNode<E> right;
private E value;
public TreeNode(){
left = right = null;
value = null;
}
public TreeNode(TreeNode<E> lf, TreeNode<E> rgt, E v){
left = lf;
right = rgt;
value = v;
}
public TreeNode<E> getLeft(){
return left;
}
public TreeNode<E> getRight(){
return right;
}
public E getValue(){
return value;
}
public void setRight(TreeNode<E> x){
right = x;
}
public void setLeft(TreeNode<E> x){
left = x;
}
public void setValue(E x){
value = x;
}
public int compareTo(TreeNode<E> x){
return value.compareTo(x.value);
}
}
A Wrapper Class:
Code:
public class Wrapper implements Comparable<Wrapper>
{
public int a, b;
public Wrapper(int a2, int b2)
{
a = a2;
b = b2;
}
public int compareTo(Wrapper x)//b1 < b2 (-) b1 > b2 (+)
{
return b - x.b;
}
}
The Compression: (This process basically assigns individual values to each letter that is less bits that the current 8-bit value assigned to them. It then creates a table of representative values and prints it along with the file.
So a file containing
Text:
Binary:
Code:
01100001011000010110000101100001011000010110000101100001011000010110000101100001
Would output
Code:
0000000000011000010
A very useful algorithm for text based files...
Compress.java:
Code:
import java.util.*;
public class compress
{
private static int[] meow = new int[257];
private static TreeNode<Wrapper> getTree(String args)
{
BitInputStream a = new BitInputStream(args);
int p = 0;
meow[256] = 1;
while((p = a.read(8)) != -1)
meow[p]++;
PriorityQueue<TreeNode<Wrapper>> q = new PriorityQueue<TreeNode<Wrapper>>();
for(int i = 0; i < 257; i++)
if(meow[i] != 0)
q.add(new TreeNode<Wrapper>(null, null, new Wrapper(i, meow[i])));
while(!q.isEmpty())
{
TreeNode<Wrapper> b1 = q.remove();
TreeNode<Wrapper> b2;
if(!q.isEmpty())
b2 = q.remove();
else
{
q.add(b1);
break;
}
TreeNode<Wrapper> crux = new TreeNode<Wrapper>(b1, b2, new Wrapper(258, b1.getValue().b + b2.getValue().b));
q.add(crux);
}
TreeNode<Wrapper> temp = q.remove();
return (temp);
}
private static void omgHelper(TreeNode<Wrapper> x, BitOutputStream e)
{
if(x.getLeft() == null && x.getRight() == null)
{
e.write(1, 1);
e.write(9, x.getValue().a);
} else {
e.write(1, 0);
omgHelper(x.getLeft(), e);
omgHelper(x.getRight(), e);
}
}
private static void fillTable(TreeNode<Wrapper> x, String c[], String g, int me)
{
if(x.getLeft() == null && null == x.getRight())
{
if(x.getValue().a != 258)
c[x.getValue().a] = g + "" + me;
return ;
}
if(me != 254)
g += me;
fillTable(x.getLeft(), c, g, 0);
fillTable(x.getRight(), c, g, 1);
}
public static void mains(String args[])
{
TreeNode<Wrapper> x = getTree(args[0]);
BitOutputStream m = new BitOutputStream(args[1]);
omgHelper(x, m);
String f[] = new String[257];
fillTable(x, f, "", 254);
/*for(int i = 0; i < f.length; i++)
if(meow[i] != 0)
System.out.println(i + " : " + f[i]);*/
BitInputStream v = new BitInputStream(args[0]);
int val = 0;
while((val = v.read(8)) != -1)
for(int i = 0; i < f[val].length(); i++)
{
String a = "";
a += f[val].charAt(i);
m.write(1, Integer.parseInt(a));
}
for(int i = 0; i < f[256].length(); i++)
{
String a = "";
a += f[256].charAt(i);
m.write(1, Integer.parseInt(a));
}
m.close();
}
}
Decompress.java: (Basically takes the encoded and puts it back into legible format through reverse engineering)
Code:
public class decompress
{
private static void getTree(TreeNode<Integer> x, BitInputStream e)
{
int val = e.read(1);
System.out.print(val);
if(val == 1)
{
x.setValue(e.read(9));
return;
} else if(val == 0) {
x.setValue(-1);
x.setLeft(new TreeNode<Integer>(null, null, -1));
getTree(x.getLeft(), e);
x.setRight(new TreeNode<Integer>(null, null, -1));
getTree(x.getRight(), e);
}
}
private static void decomp(TreeNode<Integer> x, BitInputStream e, BitOutputStream m)
{
int val = 0;
TreeNode<Integer> temp = x;
while(true)
{
while(true)
{
if(temp.getLeft() == null && temp.getRight() == null)
break;
val = e.read(1);
if(val == 0)
temp = temp.getLeft();
else if(val == 1)
temp = temp.getRight();
}
int a = temp.getValue();
if(a == 256)
break;
m.write(8, a);
temp = x;
}
}
public static void mains(String args[])
{
BitInputStream v = new BitInputStream(args[0]);
TreeNode<Integer> x = new TreeNode<Integer>(null, null, -1);
getTree(x, v);
BitOutputStream m = new BitOutputStream(args[1]);
decomp(x, v, m);
m.close();
}
}
The GUI: (Hey, what's a program without a GUI?)
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
public class GUI extends JFrame implements ActionListener
{
private JTextField inFile;
private JTextField outFile;
private JProgressBar load;
private Container c;
private JMenuBar x;
private JMenu file, help;
private JMenuItem file1, file2, file3, help1;
private JLabel compF, decompF, gener, BS;
private JButton compressButton, decompressButton, inBut, outBut;
private JPanel c2, c3, c4, c5;
private JFileChooser choose;
private ImageIcon helpI, browsah, helpIs, compressI, compressIs, decompressI, decompressIs, exits, error;
public GUI()
{
super("Compressor");
choose = new JFileChooser();
Toolkit toolkit = Toolkit.getDefaultToolkit();
setResizable(false);
setSize(300, 175);
setDefaultLookAndFeelDecorated(false);
c = getContentPane();
c.setLayout(new GridLayout(3, 1));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String codebase = "http://i198.photobucket.com/albums/aa232/javatm/";
/*PROGRESS BAR*/
load = new JProgressBar(0);
load.setIndeterminate(true);
load.setString("Working");
load.setStringPainted(true);
load.setBorderPainted(true);
c2 = new JPanel();
c2.add(load);
/*END PBAR*/
try
{
helpI = new ImageIcon(toolkit.getImage(new URL(codebase + "help.gif")));
compressI = new ImageIcon(toolkit.getImage(new URL(codebase + "compress.gif")));
decompressI = new ImageIcon(toolkit.getImage(new URL(codebase + "Decompress.gif")));
helpIs = new ImageIcon(toolkit.getImage(new URL(codebase + "helpS.gif")));
compressIs = new ImageIcon(toolkit.getImage(new URL(codebase + "compressS.gif")));
decompressIs = new ImageIcon(toolkit.getImage(new URL(codebase + "DecompressS.gif")));
exits = new ImageIcon(toolkit.getImage(new URL(codebase + "exit.gif")));
error = new ImageIcon(toolkit.getImage(new URL(codebase + "erroricon.png")));
browsah = new ImageIcon(toolkit.getImage(new URL(codebase + "compressSbrowse.png")));
} catch(Exception e) {
helpI = new ImageIcon("help.gif");
compressI = new ImageIcon("compress.gif");
decompressI = new ImageIcon("Decompress.gif");
helpIs = new ImageIcon("helpS.gif");
compressIs = new ImageIcon("compressS.gif");
decompressIs = new ImageIcon("DecompressS.gif");
exits = new ImageIcon("exit.gif");
error = new ImageIcon("erroricon.png");
browsah = new ImageIcon("compressSbrowse.png");
}
setIconImage(compressI.getImage());
/*BEGIN Container*/
c3 = new JPanel();
c3.setLayout(new GridLayout(2, 3));
c4 = new JPanel(new GridLayout(1, 2));
inBut = new JButton("Browse...", browsah);
inBut.addActionListener(this);
outBut = new JButton("Browse...", browsah);
outBut.addActionListener(this);
inFile = new JTextField("File to Compress");
outFile = new JTextField("Output File");
compressButton = new JButton("Compress", compressI);
decompressButton = new JButton("Decompress", decompressI);
decompressButton.setSize(30, 50);
compressButton.setSize(30, 50);
inFile.setSize(30, 50);
outFile.setSize(30, 50);
compF = new JLabel(" In File:");
decompF = new JLabel(" Out File:");
decompressButton.addActionListener(this);
compressButton.addActionListener(this);
c5 = new JPanel();
BS = new JLabel("Enjoy This Amazing \n Compressor!");
c5.add(BS);
c3.add(compF);
c3.add(inFile);
c3.add(inBut);
c3.add(decompF);
c3.add(outFile);
c3.add(outBut);
c.add(c3);
c.add(c5);
c4.add(compressButton);
c4.add(decompressButton);
c.add(c4);
/*END Container*/
/*BEGIN MENUBARS*/
x = new JMenuBar();
file = new JMenu("File");
file1 = new JMenuItem("Compress", compressIs);
file2 = new JMenuItem("Decompress", decompressIs);
file3 = new JMenuItem("Exit", exits);
file3.addActionListener(this);
file2.addActionListener(this);
file1.addActionListener(this);
file.add(file1);
file.add(file2);
file.add(file3);
help = new JMenu("Help");
help1 = new JMenuItem("About", helpIs);
help1.addActionListener(this);
help.add(help1);
x.add(file);
x.add(help);
setJMenuBar(x);
/*END MENUBARS*/
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
Object f = e.getSource();
if(f == file1 || f == compressButton || f == decompressButton || f == file2)
{
c.remove(c3);
c.remove(c4);
c.remove(c5);
c.add(c3);
c.add(c2);
c.add(c4);
setVisible(true);
String errorMsg = "Done.";
File a, b;
boolean failed = false;
try
{
a = new File(inFile.getText());
BufferedReader junk = new BufferedReader(new FileReader(a));
} catch(FileNotFoundException err) {
JOptionPane.showMessageDialog(this, "Invalid input file", "ERROR", 2, error);
errorMsg = "Invalid input file";
failed = true;
}
try
{
b = new File(outFile.getText());
BufferedWriter junk = new BufferedWriter(new FileWriter(b));
} catch(FileNotFoundException err) {
JOptionPane.showMessageDialog(this, "Invalid file destination", "ERROR", 2, error);
failed = true;
errorMsg = "Invalid file destination";
} catch(IOException err) {
JOptionPane.showMessageDialog(this, "Invalid file destination", "ERROR", 2, error);
failed = true;
errorMsg = "Invalid file destination";
}
String[] arg = {inFile.getText(), outFile.getText()};
if((f == file1 || f == compressButton) && !failed)
compress.mains(arg);
else if((f == file2 || f == decompressButton) && !failed)
decompress.mains(arg);
c.remove(c2);
setVisible(true);
c.remove(c3);
c.remove(c4);
c.add(c3);
BS.setText(errorMsg);
c.add(c5);
c.add(c4);
setVisible(true);
} else if(f == help1) {
JOptionPane.showMessageDialog(this, "Title: Compressor \n Verision: v1.0 \n Author: Ben \n Copyright 2008", "About", 1, compressI);
} else if(f == file3){
dispose();
System.exit(0);
} else if(f == inBut || f == outBut) {
choose.showOpenDialog(this);
if(f == inBut)
inFile.setText(choose.getSelectedFile().getPath());
else
outFile.setText(choose.getSelectedFile().getPath());
}
}
public static void main(String args[])
{
GUI a = new GUI();
}
}
Overall look and feel of GUI:
If you wanna download my compressor feel free...
http://**********/IVTBRI
~Oblak