mirror of
https://github.com/AppleCommander/ShrinkItArchive.git
synced 2024-12-21 11:29:45 +00:00
Adding BitOutputStream; moved bit mask constants into BitConstants interface for both the input and the output stream.
This commit is contained in:
parent
69debc0765
commit
af85d76306
19
src/com/webcodepro/shrinkit/io/BitConstants.java
Normal file
19
src/com/webcodepro/shrinkit/io/BitConstants.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.webcodepro.shrinkit.io;
|
||||
|
||||
/**
|
||||
* This interface allows bit-related constants to be shared among
|
||||
* classes.
|
||||
*
|
||||
* @author robgreene@users.sourceforge.net
|
||||
*/
|
||||
public interface BitConstants {
|
||||
/**
|
||||
* The low-tech way to compute a bit mask. Allowing up to 16 bits at this time.
|
||||
*/
|
||||
public static final int[] BIT_MASKS = new int[] {
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f,
|
||||
0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff,
|
||||
0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff,
|
||||
0x7fff, 0xffff
|
||||
};
|
||||
}
|
@ -14,15 +14,7 @@ import java.io.InputStream;
|
||||
*
|
||||
* @author robgreene@users.sourceforge.net
|
||||
*/
|
||||
public class BitInputStream extends InputStream {
|
||||
/** The low-tech way to compute a bit mask. Allowing up to 16 bits at this time. */
|
||||
private static int[] BIT_MASKS = new int[] {
|
||||
0x0000, 0x0001, 0x0003, 0x0007, 0x000f,
|
||||
0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff,
|
||||
0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff,
|
||||
0x7fff, 0xffff
|
||||
};
|
||||
|
||||
public class BitInputStream extends InputStream implements BitConstants {
|
||||
/** Our source of data. */
|
||||
private InputStream is;
|
||||
/** The number of bits to read for a request. This can be adjusted dynamically. */
|
||||
@ -75,7 +67,7 @@ public class BitInputStream extends InputStream {
|
||||
int b = is.read();
|
||||
if (b == -1) return b;
|
||||
if (bitsOfData > 0) {
|
||||
b <<= bitsOfData;
|
||||
b <<= bitsOfData; // We're placing b on the high-bit side
|
||||
}
|
||||
data|= b;
|
||||
bitsOfData+= 8;
|
||||
|
98
src/com/webcodepro/shrinkit/io/BitOutputStream.java
Normal file
98
src/com/webcodepro/shrinkit/io/BitOutputStream.java
Normal file
@ -0,0 +1,98 @@
|
||||
package com.webcodepro.shrinkit.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The BitOutputStream allows varying bit sizes to be written to the wrapped
|
||||
* OutputStream. This is useful for LZW type compression algorithms
|
||||
* where 9-12 bit codes are used instead of the 8-bit byte.
|
||||
* <p>
|
||||
* Warning: The <code>write(byte[])</code> and <code>write(byte[], int, int)</code>
|
||||
* methods of <code>OutputStream</code> will not work appropriately with any
|
||||
* bit size > 8 bits.
|
||||
*
|
||||
* @author robgreene@users.sourceforge.net
|
||||
*/
|
||||
public class BitOutputStream extends OutputStream implements BitConstants {
|
||||
/** Our data target. */
|
||||
private OutputStream os;
|
||||
/** The number of bits to write for a request. This can be adjusted dynamically. */
|
||||
private int requestedNumberOfBits;
|
||||
/** The current bit mask to use for a <code>write(int)</code> request. */
|
||||
private int bitMask;
|
||||
/** The buffer containing our bits. */
|
||||
private int data = 0;
|
||||
/** Number of bits remaining in our buffer */
|
||||
private int bitsOfData = 0;
|
||||
|
||||
/**
|
||||
* Create a BitOutpuStream wrapping the given <code>OutputStream</code>
|
||||
* and writing the number of bits specified.
|
||||
*/
|
||||
public BitOutputStream(OutputStream os, int startingNumberOfBits) {
|
||||
this.os = os;
|
||||
setRequestedNumberOfBits(startingNumberOfBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bits to be write with each call to <code>write(int)</code>.
|
||||
*/
|
||||
public void setRequestedNumberOfBits(int numberOfBits) {
|
||||
this.requestedNumberOfBits = numberOfBits;
|
||||
this.bitMask = BIT_MASKS[numberOfBits];
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the requested number of bits by one.
|
||||
* This is the general usage and prevents client from needing to track
|
||||
* the requested number of bits or from making various method calls.
|
||||
*/
|
||||
public void increaseRequestedNumberOfBits() {
|
||||
setRequestedNumberOfBits(requestedNumberOfBits + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer with the current bit mask for the current bit size.
|
||||
*/
|
||||
public int getBitMask() {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the number of bits to the wrapped OutputStream.
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
b &= bitMask; // Ensure we don't have extra baggage
|
||||
b <<= bitsOfData; // Move beyond existing bits of data
|
||||
data|= b; // Add in the additional data
|
||||
bitsOfData+= requestedNumberOfBits;
|
||||
while (bitsOfData >= 8) {
|
||||
os.write(data & 0xff);
|
||||
data >>= 8;
|
||||
bitsOfData-= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When shifting from buffer to buffer, this OutputStream also should be reset.
|
||||
* This allows the "left over" bits to be cleared.
|
||||
*/
|
||||
public void clearRemainingBitsOfData() {
|
||||
this.bitsOfData = 0;
|
||||
this.data = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the output stream and write any remaining byte to the output.
|
||||
* Note that we may very well end up with extra bits if there are < 8
|
||||
* bits remaining.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (bitsOfData > 0) {
|
||||
write(0x00); // forces a flush of the remaining bits in the proper order
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
33
test_src/com/webcodepro/shrinkit/io/BitOutputStreamTest.java
Normal file
33
test_src/com/webcodepro/shrinkit/io/BitOutputStreamTest.java
Normal file
@ -0,0 +1,33 @@
|
||||
package com.webcodepro.shrinkit.io;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exercise the BitOutputStream.
|
||||
*
|
||||
* @author robgreene@users.sourceforge.net
|
||||
*/
|
||||
public class BitOutputStreamTest extends TestCaseHelper {
|
||||
public void test1() throws IOException {
|
||||
byte[] expected = new byte[] {
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01,
|
||||
0x01
|
||||
};
|
||||
ByteArrayOutputStream actual = new ByteArrayOutputStream();
|
||||
BitOutputStream os = new BitOutputStream(actual, 9);
|
||||
// 9-bit groups: 100000001 010000000 001000000 000100000 000010000 000001000 000000100 000000010
|
||||
// 8-bit groups: 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
os.write(0x101);
|
||||
os.write(0x80);
|
||||
os.write(0x40);
|
||||
os.write(0x20);
|
||||
os.write(0x10);
|
||||
os.write(0x08);
|
||||
os.write(0x04);
|
||||
os.write(0x02);
|
||||
os.close(); // VERY IMPORTANT!
|
||||
assertEquals(expected, actual.toByteArray());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user