2016-08-16 06:34:23 +00:00
|
|
|
package com.bytezone.diskbrowser.wizardry;
|
|
|
|
|
2016-08-17 02:20:00 +00:00
|
|
|
import com.bytezone.diskbrowser.applefile.AbstractFile;
|
|
|
|
|
2016-08-16 22:55:51 +00:00
|
|
|
// Based on a pascal routine by Tom Ewers
|
|
|
|
|
2016-08-17 11:33:27 +00:00
|
|
|
// link for possible display algorithm:
|
|
|
|
// http://stackoverflow.com/questions/14184655/set-position-for-drawing-binary-tree
|
|
|
|
|
2016-08-17 02:20:00 +00:00
|
|
|
public class Huffman extends AbstractFile
|
2016-08-16 06:34:23 +00:00
|
|
|
{
|
2016-08-18 04:03:13 +00:00
|
|
|
private static final byte[] mask = { 2, 1 }; // bits: 10 or 01
|
|
|
|
private static final int[] offset = { 512, 256 }; // offset to left/right nodes
|
2016-08-17 11:33:27 +00:00
|
|
|
|
2016-08-17 12:06:52 +00:00
|
|
|
private byte depth;
|
2016-08-16 22:55:51 +00:00
|
|
|
private int msgPtr;
|
2016-08-17 12:06:52 +00:00
|
|
|
private byte currentByte;
|
2016-08-16 06:34:23 +00:00
|
|
|
private byte[] message;
|
|
|
|
|
2016-08-17 09:42:28 +00:00
|
|
|
private String bufferContents;
|
2016-08-17 02:20:00 +00:00
|
|
|
|
|
|
|
public Huffman (String name, byte[] buffer)
|
2016-08-16 06:34:23 +00:00
|
|
|
{
|
2016-08-17 02:20:00 +00:00
|
|
|
super (name, buffer);
|
2016-08-16 06:34:23 +00:00
|
|
|
}
|
|
|
|
|
2016-08-17 11:33:27 +00:00
|
|
|
public String decodeMessage (byte[] message)
|
2016-08-16 06:34:23 +00:00
|
|
|
{
|
|
|
|
this.message = message;
|
2016-08-17 12:06:52 +00:00
|
|
|
depth = 0;
|
2016-08-16 06:34:23 +00:00
|
|
|
msgPtr = 0;
|
2016-08-16 09:04:17 +00:00
|
|
|
currentByte = 0;
|
2016-08-16 06:34:23 +00:00
|
|
|
|
|
|
|
int len = getChar ();
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
text.append ((char) getChar ());
|
2016-08-16 22:55:51 +00:00
|
|
|
|
2016-08-16 06:34:23 +00:00
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
private byte getChar ()
|
|
|
|
{
|
2016-08-18 06:35:54 +00:00
|
|
|
int treePtr = 0; // start at the root
|
2016-08-16 06:34:23 +00:00
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
2016-08-18 06:35:54 +00:00
|
|
|
if ((depth++ & 0x07) == 0) // every 8th bit...
|
|
|
|
currentByte = message[msgPtr++]; // ...get a new byte
|
2016-08-17 12:06:52 +00:00
|
|
|
|
2016-08-18 06:35:54 +00:00
|
|
|
int currentBit = currentByte & 0x01; // extract the next bit to process
|
|
|
|
currentByte >>= 1; // and remove it from the current byte
|
2016-08-16 06:34:23 +00:00
|
|
|
|
2016-08-17 11:33:27 +00:00
|
|
|
// use currentBit to determine whether to use the left or right node
|
|
|
|
byte nodeValue = buffer[treePtr + offset[currentBit]];
|
|
|
|
|
|
|
|
// if the node is a leaf, return its contents
|
|
|
|
if ((buffer[treePtr] & mask[currentBit]) != 0)
|
|
|
|
return nodeValue;
|
|
|
|
|
|
|
|
// else continue traversal
|
|
|
|
treePtr = nodeValue & 0xFF;
|
2016-08-16 06:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-17 02:20:00 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getText ()
|
|
|
|
{
|
2016-08-17 09:42:28 +00:00
|
|
|
if (bufferContents == null)
|
2016-08-17 02:20:00 +00:00
|
|
|
{
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
walk (0, "", text);
|
2016-08-17 09:42:28 +00:00
|
|
|
bufferContents = text.toString ();
|
2016-08-17 02:20:00 +00:00
|
|
|
}
|
2016-08-17 09:42:28 +00:00
|
|
|
return bufferContents;
|
2016-08-17 02:20:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void walk (int treePtr, String path, StringBuilder text)
|
|
|
|
{
|
2016-08-18 04:03:13 +00:00
|
|
|
for (int currentBit = 1; currentBit >= 0; --currentBit)
|
|
|
|
if ((buffer[treePtr] & mask[currentBit]) == 0)
|
|
|
|
walk (buffer[treePtr + offset[currentBit]] & 0xFF, path + currentBit, text);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int val = buffer[treePtr + offset[currentBit]] & 0xFF;
|
|
|
|
char c = val < 32 || val >= 127 ? ' ' : (char) val;
|
|
|
|
text.append (String.format ("%3d %1.1s %s%n", val, c, path + currentBit));
|
|
|
|
}
|
2016-08-17 02:20:00 +00:00
|
|
|
}
|
2016-08-16 06:34:23 +00:00
|
|
|
}
|