Created
February 15, 2016 10:58
-
-
Save AndyBowes/9a7bb672aedb797c562f to your computer and use it in GitHub Desktop.
Read LZW Compressed Stream to get 12-bit numbers as Code Points.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.nhs.mesh.util.lzw; | |
import java.io.IOException; | |
import java.io.InputStream; | |
/** | |
* Wrapper around an Input Stream which allows the Code Points to be read sequentially from | |
* an LZW compressed file. | |
* | |
* @author Andy Bowes | |
*/ | |
public class LZWCodePointStream { | |
private final int CODE_POINT_SIZE = 12; | |
private final InputStream wrappedStream; | |
private int readBitCount = 0; | |
private int bitBuffer = 0; | |
public LZWCodePointStream(InputStream wrappedStream) { | |
super(); | |
this.wrappedStream = wrappedStream; | |
} | |
public void close() throws IOException { | |
if (wrappedStream != null){ | |
wrappedStream.close(); | |
} | |
} | |
public int nextCodePoint() throws IOException{ | |
while (readBitCount < CODE_POINT_SIZE){ | |
int nextByte = wrappedStream.read(); | |
if (nextByte < 0){ | |
return -1; | |
} | |
readBitCount += 8; | |
bitBuffer <<= 8; | |
bitBuffer += nextByte; | |
} | |
int returnValue = (bitBuffer >> (readBitCount-CODE_POINT_SIZE)) & 0xFFF; | |
readBitCount -= CODE_POINT_SIZE; | |
bitBuffer = (readBitCount == 0) ? 0 : bitBuffer & 0xF; | |
return returnValue; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.nhs.mesh.util.lzw; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Implementation of Input Stream that performs LZW Decompression | |
* | |
* | |
* @author Andy Bowes | |
*/ | |
public class LZWInputStream extends InputStream { | |
private final int INITIAL_DICT_SIZE = 256; | |
private final int LAST_CODE_POINT = 4095; | |
private final LZWCodePointStream codePointStream; | |
private final Map<Integer, String> dictionary = new HashMap<Integer, String>(); | |
private int dictSize = INITIAL_DICT_SIZE; | |
private final StringBuffer outputBuffer = new StringBuffer(); | |
private String w; | |
public LZWInputStream(InputStream inputStream) throws IOException{ | |
codePointStream = new LZWCodePointStream(inputStream); | |
for (int i=0; i < INITIAL_DICT_SIZE; i++){ | |
dictionary.put(i, "" + (char)i); | |
} | |
dictSize = INITIAL_DICT_SIZE; | |
w = "" + dictionary.get(codePointStream.nextCodePoint()); | |
outputBuffer.append(w); | |
} | |
@Override | |
/** | |
* Return the next byte in the decompressed output stream. | |
* | |
*/ | |
public int read() throws IOException { | |
if (outputBuffer.length() == 0){ | |
String entry; | |
int nextCodePoint = codePointStream.nextCodePoint(); | |
if (nextCodePoint <= 0){ | |
return -1; | |
} | |
if (nextCodePoint == LAST_CODE_POINT){ | |
entry = w; | |
w = ""; | |
} else if (dictionary.containsKey(nextCodePoint)){ | |
entry = dictionary.get(nextCodePoint); | |
} else if (nextCodePoint == dictSize ){ | |
entry = w + w.charAt(0); | |
} else { | |
throw new IllegalArgumentException("Bad compressed CodePoint: " + nextCodePoint); | |
} | |
outputBuffer.append(entry); | |
dictionary.put(dictSize++, w + entry.charAt(0)); | |
w = entry; | |
} | |
char firstByte = outputBuffer.charAt(0); | |
outputBuffer.deleteCharAt(0); // TBD - Is this the best method to truncate the buffer; | |
return firstByte; | |
} | |
@Override | |
public synchronized void reset() throws IOException { | |
throw new java.lang.UnsupportedOperationException("LZWInputStream: reset() is not supported"); | |
} | |
@Override | |
public long skip(long arg0) throws IOException { | |
throw new java.lang.UnsupportedOperationException("LZWInputStream: skip() is not supported"); | |
} | |
@Override | |
public void close() throws IOException { | |
this.codePointStream.close(); | |
super.close(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment