Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit

Permalink
Translation back to english. Full comments in code, including javadoc…
Browse files Browse the repository at this point in the history
… annotations
  • Loading branch information
Anssi Kinnunen committed Mar 8, 2013
1 parent a795369 commit 9c344d8
Show file tree
Hide file tree
Showing 12 changed files with 749 additions and 808 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
target/

# ignore all .txt's
*.txt
*.txt

# ignore javadoc
doc/
196 changes: 196 additions & 0 deletions src/main/java/bluemoon/Huffman/Decoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package bluemoon.Huffman;

import java.io.*;
import java.text.*;
import java.util.*;

/**
* Class for decoding a Huffman-encoded message. Relies heavily on TreeBuilder-class for rebuilding
* the Huffman-tree, and also on Encoder-class to create a lookUp-table for decoding purposes.
*
* @author Anssi Kinnunen
*/
public class Decoder {

public Decoder() {

}

/**
* Decodes the contents of given (binary encoded) file. Utilizes a lookUp-table provided by
* Encoder-class.
*
* @param lookUpFile
*/
public void decode(File lookUpFile, boolean debug) {
String rawLookUpMsg = readFromLookupFile();
String parsedLookUpMsg = parseLookupMsg(rawLookUpMsg, "BRL", "BRP");
ArrayList<Node> huffmanTree = rebuildHuffmanTree(parsedLookUpMsg);
String decodedMsg = decodeMessage(huffmanTree);
if (debug) {
System.out.println("Decoded message: " + decodedMsg);
}
Date dateNow = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd_MM_yyyy");
File tiedosto = new File(dateFormat.format(dateNow) + "_decoded.txt");
writeToFile(tiedosto, decodedMsg);
}

/**
* Reads data from a pre-determined lookUp-table and returns it as a String.
*
* @param lookupFile File, where the lookUp-table for decodable message resides.
* @return Raw data from the lookUp-table as a String.
*/
public String readFromLookupFile() {
File lookUpFile = new File("testiLookUp.txt");
if (!lookUpFile.exists()) {
System.err.println("Error: testiLookUp.txt doesn't exist");
System.exit(0);
}
BufferedReader bufReader;
StringBuilder sbBuilder = new StringBuilder();
String auxLine = "";
try {
bufReader = new BufferedReader(new FileReader(lookUpFile));
while ((auxLine = bufReader.readLine()) != null) {
sbBuilder.append(auxLine);
}
bufReader.close();
} catch (IOException ie) {
ie.printStackTrace();
}
return sbBuilder.toString();
}

/**
* Iterates through the lookUp-table and creates new string, which contains the original message
* in random order (the string has same amount of symbols, but they aren't in order).
*
* @param lookUpMsg Parseable message from the lookUp-table as String.
* @param msgRegex Regex string for splitting lookUp-message into symbol[pairRegex]number -strings.
* @param pairRegex Regex string for splitting symbol[pairRegex]number-strings into symbols and numbers.
* @return Parsed lookUp-message, which contains the original message unordered as String.
*/
public String parseLookupMsg(String lookUpMsg, String msgRegex,
String pairRegex) {
StringBuilder unsortedMsg = new StringBuilder();
String[] pairs = lookUpMsg.split(msgRegex);
int amountOfSymbols = 0;
for (String weightedPair : pairs) {
amountOfSymbols = Integer
.parseInt(weightedPair.split(pairRegex)[1]);
String symbol = weightedPair.split(pairRegex)[0];
for (int i = 0; i < amountOfSymbols; i++) {
unsortedMsg.append(symbol);
}
}
return unsortedMsg.toString();
}

/**
* Rebuilds the Huffman-tree from the given message.
*
* @param message Message as a String.
* @return Huffman-tree as ArrayList< Node >.
*/
public ArrayList<Node> rebuildHuffmanTree(String message) {
SortedMap<String, Integer> weightedList = TreeBuilder
.createWeightedList(message);
ArrayList<Node> nodes = TreeBuilder.createNodeList(weightedList);
ArrayList<Node> huffmanTree = TreeBuilder.createHuffmanTree(nodes);

return huffmanTree;
}

/**
* Decodes the encoded message. Reads the binary data written by encoder and decodes it into String
* by traversing the Huffman-tree as the original algorithm suggests. This type of decoding, however, is
* painfully slow and is practically unusable for any text files over 30KB in size.
*
* @param huffmanTree Huffman-tree as ArrayList< Node >.
* @return Decoded message as a String.
*/
public String decodeMessage(ArrayList<Node> huffmanTree) {
Date dateNow = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd_MM_yyyy");
File file = new File(dateFormat.format(dateNow) + "_encoded.txt");
byte[] binaryEncodedMsg = readBinaryFromFile(file);
StringBuilder stringEncodedMsg = new StringBuilder();

// Reads binary input and creates string encoded message accordingly, adding
// "1" or "0" to the string
for (int i = 0; i < binaryEncodedMsg.length; i++) {
for (int j = 7; j >= 0; j--) {
if (((binaryEncodedMsg[i] >> j) & 1) == 1) {
stringEncodedMsg.append("1");
} else {
stringEncodedMsg.append("0");
}
}
}
// Bit-by-bit-decoding method, "by the book". Painfully slow method for anything useful.
StringBuilder decodedMsg = new StringBuilder();
Node currentNode = huffmanTree.get(0);
for (int i = 0; i < stringEncodedMsg.toString().length(); i++) {
if (stringEncodedMsg.charAt(i) == '1') {
currentNode = currentNode.getRightChild();
} else {
currentNode = currentNode.getLeftChild();
}
if (currentNode.getSymbol() != null) {
decodedMsg.append(currentNode.getSymbol());
currentNode = huffmanTree.get(0);
}
}
return decodedMsg.toString();
}

/**
* Reads binary data from the given file.
*
* @param file File to read from.
* @return Binary data as Byte[].
*/
public byte[] readBinaryFromFile(File file) {
FileInputStream inStream;
byte[] binaryMsg = null;
try {
inStream = new FileInputStream(file);
int numberOfBytes = inStream.available();
binaryMsg = new byte[numberOfBytes];
inStream.read(binaryMsg);
inStream.close();
} catch (IOException ie) {
ie.printStackTrace();
}
return binaryMsg;
}

/**
* Writes given content as String to given file.
*
* @param file File to write to.
* @param message Content of type String which to write.
*/
public static void writeToFile(File file, String message) {
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
System.err.println("Error creating the file");
}
}
FileWriter flWriter;
BufferedWriter bufWriter;
try {
flWriter = new FileWriter(file);
bufWriter = new BufferedWriter(flWriter);
bufWriter.write(message);
bufWriter.close();
flWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Loading

0 comments on commit 9c344d8

Please sign in to comment.