mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-02 11:05:29 -04:00
- Moved unused encoders/decoders to sandbox
- Fixed Base64 encoder/decoder to pass test cases - Minor clean-up in other decoders
This commit is contained in:
parent
40a5960a9f
commit
c45882846a
5
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java
Executable file → Normal file
5
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java
Executable file → Normal file
@ -33,7 +33,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Abstract base class for RLE decoding as specifed by in the Windows BMP (aka DIB) file format.
|
||||
* Abstract base class for RLE decoding as specified by in the Windows BMP (aka DIB) file format.
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
@ -59,9 +59,11 @@ abstract class AbstractRLEDecoder implements Decoder {
|
||||
mWidth = pWidth;
|
||||
int bytesPerRow = mWidth;
|
||||
int mod = bytesPerRow % 4;
|
||||
|
||||
if (mod != 0) {
|
||||
bytesPerRow += 4 - mod;
|
||||
}
|
||||
|
||||
mRow = new byte[bytesPerRow];
|
||||
|
||||
mSrcX = 0;
|
||||
@ -133,6 +135,7 @@ abstract class AbstractRLEDecoder implements Decoder {
|
||||
if (pByte < 0) {
|
||||
throw new EOFException("Premature end of file");
|
||||
}
|
||||
|
||||
return pByte;
|
||||
}
|
||||
}
|
||||
|
58
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java
Executable file → Normal file
58
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java
Executable file → Normal file
@ -43,7 +43,7 @@ import java.io.*;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java#2 $
|
||||
*/
|
||||
public class Base64Decoder implements Decoder {
|
||||
public final class Base64Decoder implements Decoder {
|
||||
/**
|
||||
* This array maps the characters to their 6 bit values
|
||||
*/
|
||||
@ -60,12 +60,14 @@ public class Base64Decoder implements Decoder {
|
||||
};
|
||||
|
||||
final static byte[] PEM_CONVERT_ARRAY;
|
||||
private byte[] decode_buffer = new byte[4];
|
||||
|
||||
private byte[] mDecodeBuffer = new byte[4];
|
||||
private ByteArrayOutputStream mWrapped;
|
||||
private Object mWrappedObject;
|
||||
|
||||
static {
|
||||
PEM_CONVERT_ARRAY = new byte[256];
|
||||
|
||||
for (int i = 0; i < 255; i++) {
|
||||
PEM_CONVERT_ARRAY[i] = -1;
|
||||
}
|
||||
@ -75,20 +77,23 @@ public class Base64Decoder implements Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
protected static int readFully(InputStream pStream, byte pBytes[],
|
||||
int pOffset, int pLength) throws IOException {
|
||||
protected static int readFully(final InputStream pStream, final byte pBytes[], final int pOffset, final int pLength)
|
||||
throws IOException
|
||||
{
|
||||
for (int i = 0; i < pLength; i++) {
|
||||
int read = pStream.read();
|
||||
|
||||
if (read == -1) {
|
||||
return i != 0 ? i : -1;
|
||||
}
|
||||
|
||||
pBytes[i + pOffset] = (byte) read;
|
||||
}
|
||||
|
||||
return pLength;
|
||||
}
|
||||
|
||||
protected boolean decodeAtom(InputStream pInput, OutputStream pOutput, int pLength)
|
||||
protected boolean decodeAtom(final InputStream pInput, final OutputStream pOutput, final int pLength)
|
||||
throws IOException {
|
||||
|
||||
byte byte0 = -1;
|
||||
@ -102,40 +107,45 @@ public class Base64Decoder implements Decoder {
|
||||
|
||||
int read;
|
||||
|
||||
// Skip linefeeds
|
||||
// Skip line feeds
|
||||
do {
|
||||
read = pInput.read();
|
||||
|
||||
if (read == -1) {
|
||||
return false;
|
||||
}
|
||||
} while (read == 10 || read == 13);
|
||||
|
||||
decode_buffer[0] = (byte) read;
|
||||
read = readFully(pInput, decode_buffer, 1, pLength - 1);
|
||||
mDecodeBuffer[0] = (byte) read;
|
||||
read = readFully(pInput, mDecodeBuffer, 1, pLength - 1);
|
||||
|
||||
if (read == -1) {
|
||||
return false;
|
||||
}
|
||||
if (pLength > 3 && decode_buffer[3] == 61) {
|
||||
pLength = 3;
|
||||
}
|
||||
if (pLength > 2 && decode_buffer[2] == 61) {
|
||||
pLength = 2;
|
||||
|
||||
int length = pLength;
|
||||
|
||||
if (length > 3 && mDecodeBuffer[3] == 61) {
|
||||
length = 3;
|
||||
}
|
||||
|
||||
switch (pLength) {
|
||||
if (length > 2 && mDecodeBuffer[2] == 61) {
|
||||
length = 2;
|
||||
}
|
||||
|
||||
switch (length) {
|
||||
case 4:
|
||||
byte3 = PEM_CONVERT_ARRAY[decode_buffer[3] & 255];
|
||||
byte3 = PEM_CONVERT_ARRAY[mDecodeBuffer[3] & 255];
|
||||
// fall through
|
||||
case 3:
|
||||
byte2 = PEM_CONVERT_ARRAY[decode_buffer[2] & 255];
|
||||
byte2 = PEM_CONVERT_ARRAY[mDecodeBuffer[2] & 255];
|
||||
// fall through
|
||||
case 2:
|
||||
byte1 = PEM_CONVERT_ARRAY[decode_buffer[1] & 255];
|
||||
byte0 = PEM_CONVERT_ARRAY[decode_buffer[0] & 255];
|
||||
byte1 = PEM_CONVERT_ARRAY[mDecodeBuffer[1] & 255];
|
||||
byte0 = PEM_CONVERT_ARRAY[mDecodeBuffer[0] & 255];
|
||||
// fall through
|
||||
default:
|
||||
switch (pLength) {
|
||||
switch (length) {
|
||||
case 2:
|
||||
pOutput.write((byte) (byte0 << 2 & 252 | byte1 >>> 4 & 3));
|
||||
break;
|
||||
@ -149,16 +159,18 @@ public class Base64Decoder implements Decoder {
|
||||
pOutput.write((byte) (byte2 << 6 & 192 | byte3 & 63));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void decodeBuffer(InputStream pInput, ByteArrayOutputStream pOutput, int pLength) throws IOException {
|
||||
void decodeBuffer(final InputStream pInput, final ByteArrayOutputStream pOutput, final int pLength) throws IOException {
|
||||
do {
|
||||
int k = 72;
|
||||
int i;
|
||||
|
||||
for (i = 0; i + 4 < k; i += 4) {
|
||||
if(!decodeAtom(pInput, pOutput, 4)) {
|
||||
break;
|
||||
@ -169,17 +181,17 @@ public class Base64Decoder implements Decoder {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
while (pOutput.size() + 54 < pLength); // 72 char lines should produce no more than 54 bytes
|
||||
}
|
||||
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
if (mWrappedObject != pBuffer) {
|
||||
// NOTE: Array not cloned in FastByteArrayOutputStream
|
||||
mWrapped = new FastByteArrayOutputStream(pBuffer);
|
||||
mWrappedObject = pBuffer;
|
||||
}
|
||||
mWrapped.reset(); // NOTE: This only resets count to 0
|
||||
|
||||
mWrapped.reset(); // NOTE: This only resets count to 0
|
||||
decodeBuffer(pStream, mWrapped, pBuffer.length);
|
||||
|
||||
return mWrapped.size();
|
||||
|
19
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java
Executable file → Normal file
19
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java
Executable file → Normal file
@ -44,26 +44,37 @@ import java.io.IOException;
|
||||
*/
|
||||
public class Base64Encoder implements Encoder {
|
||||
|
||||
public void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
public void encode(final OutputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength)
|
||||
throws IOException
|
||||
{
|
||||
if (pOffset < 0 || pOffset > pLength || pOffset > pBuffer.length) {
|
||||
throw new IndexOutOfBoundsException("offset outside [0...length]");
|
||||
}
|
||||
else if (pLength > pBuffer.length) {
|
||||
throw new IndexOutOfBoundsException("length > buffer length");
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
// NOTE: This is impossible, given the current spec, as we need to either:
|
||||
// - buffer all data in the EncoderStream
|
||||
// - or have flush/end method(s) in the Encoder
|
||||
// to ensure proper end of stream handling
|
||||
|
||||
int length = pLength;
|
||||
int offset = pOffset;
|
||||
|
||||
// TODO: Temp impl, will only work for single writes
|
||||
while ((pBuffer.length - offset) > 0) {
|
||||
byte a, b, c;
|
||||
|
||||
if ((pBuffer.length - offset) > 2) {
|
||||
pLength = 3;
|
||||
length = 3;
|
||||
}
|
||||
else {
|
||||
pLength = pBuffer.length - offset;
|
||||
length = pBuffer.length - offset;
|
||||
}
|
||||
|
||||
switch (pLength) {
|
||||
switch (length) {
|
||||
case 1:
|
||||
a = pBuffer[offset];
|
||||
b = 0;
|
||||
|
24
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java
Executable file → Normal file
24
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java
Executable file → Normal file
@ -33,7 +33,7 @@ import java.io.IOException;
|
||||
import java.io.FilterInputStream;
|
||||
|
||||
/**
|
||||
* An {@code InputStream} that provides on-the-fly deoding from an underlying
|
||||
* An {@code InputStream} that provides on-the-fly decoding from an underlying
|
||||
* stream.
|
||||
* <p/>
|
||||
* @see EncoderStream
|
||||
@ -54,11 +54,11 @@ public final class DecoderStream extends FilterInputStream {
|
||||
* input stream specified by the {@code pStream} argument.
|
||||
*
|
||||
* @param pStream the underlying input stream.
|
||||
* @param pDecoder
|
||||
* @param pDecoder the decoder that will be used to decode the underlying stream
|
||||
*
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public DecoderStream(InputStream pStream, Decoder pDecoder) {
|
||||
public DecoderStream(final InputStream pStream, final Decoder pDecoder) {
|
||||
super(pStream);
|
||||
mDecoder = pDecoder;
|
||||
mBuffer = new byte[1024];
|
||||
@ -92,7 +92,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
}
|
||||
else if ((pOffset < 0) || (pOffset > pBytes.length) || (pLength < 0) ||
|
||||
((pOffset + pLength) > pBytes.length) || ((pOffset + pLength) < 0)) {
|
||||
throw new IndexOutOfBoundsException("bytes.length=" + pBytes.length + " offset=" + pOffset + " lenght=" + pLength);
|
||||
throw new IndexOutOfBoundsException("bytes.length=" + pBytes.length + " offset=" + pOffset + " length=" + pLength);
|
||||
}
|
||||
else if (pLength == 0) {
|
||||
return 0;
|
||||
@ -106,6 +106,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
// Read until we have read pLength bytes, or have reached EOF
|
||||
int count = 0;
|
||||
int off = pOffset;
|
||||
|
||||
while (pLength > count) {
|
||||
int avail = mBufferLimit - mBufferPos;
|
||||
|
||||
@ -120,6 +121,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
// Copy as many bytes as possible
|
||||
int dstLen = Math.min(pLength - count, avail);
|
||||
System.arraycopy(mBuffer, mBufferPos, pBytes, off, dstLen);
|
||||
|
||||
mBufferPos += dstLen;
|
||||
|
||||
// Update offset (rest)
|
||||
@ -129,13 +131,6 @@ public final class DecoderStream extends FilterInputStream {
|
||||
count += dstLen;
|
||||
}
|
||||
|
||||
/*
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte b = pBytes[pOffset + i];
|
||||
System.out.print("0x" + Integer.toHexString(b & 0xff));
|
||||
}
|
||||
*/
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -179,11 +174,18 @@ public final class DecoderStream extends FilterInputStream {
|
||||
*/
|
||||
protected int fill() throws IOException {
|
||||
int read = mDecoder.decode(in, mBuffer);
|
||||
|
||||
// TODO: Enforce this in test case, leave here to aid debugging
|
||||
if (read > mBuffer.length) {
|
||||
throw new AssertionError(String.format("Decode beyond buffer (%d): %d", mBuffer.length, read));
|
||||
}
|
||||
|
||||
mBufferPos = 0;
|
||||
|
||||
if (read == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
2
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java
Executable file → Normal file
2
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java
Executable file → Normal file
@ -47,7 +47,7 @@ import java.io.OutputStream;
|
||||
public interface Encoder {
|
||||
|
||||
/**
|
||||
* Encodes up to {@code pBuffer.length} bytes into the given inputstream,
|
||||
* Encodes up to {@code pBuffer.length} bytes into the given input stream,
|
||||
* from the given buffer.
|
||||
*
|
||||
* @param pStream the outputstream to encode data to
|
||||
|
18
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java
Executable file → Normal file
18
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java
Executable file → Normal file
@ -55,9 +55,9 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
* underlying output stream.
|
||||
*
|
||||
* @param pStream the underlying output stream
|
||||
* @param pEncoder
|
||||
* @param pEncoder the encoder to use
|
||||
*/
|
||||
public EncoderStream(OutputStream pStream, Encoder pEncoder) {
|
||||
public EncoderStream(final OutputStream pStream, final Encoder pEncoder) {
|
||||
this(pStream, pEncoder, false);
|
||||
}
|
||||
|
||||
@ -66,11 +66,11 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
* underlying output stream.
|
||||
*
|
||||
* @param pStream the underlying output stream
|
||||
* @param pEncoder
|
||||
* @param pEncoder the encoder to use
|
||||
* @param pFlushOnWrite if {@code true}, calls to the byte-array
|
||||
* {@code write} methods will automatically flush the buffer.
|
||||
*/
|
||||
public EncoderStream(OutputStream pStream, Encoder pEncoder, boolean pFlushOnWrite) {
|
||||
public EncoderStream(final OutputStream pStream, final Encoder pEncoder, final boolean pFlushOnWrite) {
|
||||
super(pStream);
|
||||
|
||||
mEncoder = pEncoder;
|
||||
@ -94,12 +94,13 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
if (mBufferPos != 0) {
|
||||
// Make sure all remaining data in buffer is written to the stream
|
||||
mEncoder.encode(out, mBuffer, 0, mBufferPos);
|
||||
|
||||
// Reset buffer
|
||||
mBufferPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public final void write(byte[] pBytes) throws IOException {
|
||||
public final void write(final byte[] pBytes) throws IOException {
|
||||
write(pBytes, 0, pBytes.length);
|
||||
}
|
||||
|
||||
@ -107,14 +108,14 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
// TODO: We might need a way to explicitly flush the encoder, or specify
|
||||
// that the encoder can't buffer. In that case, the encoder should probably
|
||||
// tell the EncoderStream how large buffer it prefers...
|
||||
public void write(byte[] pBytes, int pOffset, int pLength) throws IOException {
|
||||
public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
|
||||
if (!mFlushOnWrite && mBufferPos + pLength < mBuffer.length) {
|
||||
// Buffer data
|
||||
System.arraycopy(pBytes, pOffset, mBuffer, mBufferPos, pLength);
|
||||
mBufferPos += pLength;
|
||||
}
|
||||
else {
|
||||
// Encode data allready in the buffer
|
||||
// Encode data already in the buffer
|
||||
if (mBufferPos != 0) {
|
||||
encodeBuffer();
|
||||
}
|
||||
@ -124,10 +125,11 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int pByte) throws IOException {
|
||||
public void write(final int pByte) throws IOException {
|
||||
if (mBufferPos >= mBuffer.length - 1) {
|
||||
encodeBuffer(); // Resets mBufferPos to 0
|
||||
}
|
||||
|
||||
mBuffer[mBufferPos++] = (byte) pByte;
|
||||
}
|
||||
}
|
||||
|
23
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java
Executable file → Normal file
23
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java
Executable file → Normal file
@ -62,31 +62,31 @@ public final class PackBits16Decoder implements Decoder {
|
||||
/**
|
||||
* Creates a {@code PackBitsDecoder}.
|
||||
* <p/>
|
||||
* As some implementations of PackBits-like encoders treat -128 as lenght of
|
||||
* As some implementations of PackBits-like encoders treat {@code -128} as length of
|
||||
* a compressed run, instead of a no-op, it's possible to disable no-ops
|
||||
* for compatibility.
|
||||
* Should be used with caution, even though, most known encoders never write
|
||||
* no-ops in the compressed streams.
|
||||
*
|
||||
* @param pDisableNoop
|
||||
* @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op
|
||||
*/
|
||||
public PackBits16Decoder(boolean pDisableNoop) {
|
||||
public PackBits16Decoder(final boolean pDisableNoop) {
|
||||
mDisableNoop = pDisableNoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes bytes from the given input stream, to the given buffer.
|
||||
*
|
||||
* @param pStream
|
||||
* @param pStream the stream to decode from
|
||||
* @param pBuffer a byte array, minimum 128 (or 129 if no-op is disabled)
|
||||
* bytes long
|
||||
* @return The number of bytes decoded
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
if (mEOF) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read = 0;
|
||||
@ -94,6 +94,7 @@ public final class PackBits16Decoder implements Decoder {
|
||||
|
||||
while (read < max) {
|
||||
int n;
|
||||
|
||||
if (mSplitRun) {
|
||||
// Continue run
|
||||
n = mLeftOfRun;
|
||||
@ -149,24 +150,30 @@ public final class PackBits16Decoder implements Decoder {
|
||||
return read;
|
||||
}
|
||||
|
||||
private static byte readByte(InputStream pStream) throws IOException {
|
||||
private static byte readByte(final InputStream pStream) throws IOException {
|
||||
int read = pStream.read();
|
||||
|
||||
if (read < 0) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
}
|
||||
|
||||
return (byte) read;
|
||||
}
|
||||
|
||||
private static void readFully(InputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
private static void readFully(final InputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
||||
if (pLength < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int read = 0;
|
||||
|
||||
while (read < pLength) {
|
||||
int count = pStream.read(pBuffer, pOffset + read, pLength - read);
|
||||
|
||||
if (count < 0) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
}
|
||||
|
||||
read += count;
|
||||
}
|
||||
}
|
||||
|
27
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java
Executable file → Normal file
27
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java
Executable file → Normal file
@ -69,9 +69,7 @@ public final class PackBitsDecoder implements Decoder {
|
||||
private boolean mSplitRun;
|
||||
private boolean mEOF;
|
||||
|
||||
/**
|
||||
* Creates a {@code PackBitsDecoder}.
|
||||
*/
|
||||
/** Creates a {@code PackBitsDecoder}. */
|
||||
public PackBitsDecoder() {
|
||||
this(false);
|
||||
}
|
||||
@ -79,31 +77,31 @@ public final class PackBitsDecoder implements Decoder {
|
||||
/**
|
||||
* Creates a {@code PackBitsDecoder}.
|
||||
* <p/>
|
||||
* As some implementations of PackBits-like encoders treat -128 as lenght of
|
||||
* As some implementations of PackBits-like encoders treat {@code -128} as length of
|
||||
* a compressed run, instead of a no-op, it's possible to disable no-ops
|
||||
* for compatibility.
|
||||
* Should be used with caution, even though, most known encoders never write
|
||||
* no-ops in the compressed streams.
|
||||
*
|
||||
* @param pDisableNoop
|
||||
* @param pDisableNoop {@code true} if {@code -128} should be treated as a compressed run, and not a no-op
|
||||
*/
|
||||
public PackBitsDecoder(boolean pDisableNoop) {
|
||||
public PackBitsDecoder(final boolean pDisableNoop) {
|
||||
mDisableNoop = pDisableNoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes bytes from the given input stream, to the given buffer.
|
||||
*
|
||||
* @param pStream
|
||||
* @param pStream the stream to decode from
|
||||
* @param pBuffer a byte array, minimum 128 (or 129 if no-op is disabled)
|
||||
* bytes long
|
||||
* @return The number of bytes decoded
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
if (mEOF) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read = 0;
|
||||
@ -111,6 +109,7 @@ public final class PackBitsDecoder implements Decoder {
|
||||
|
||||
while (read < max) {
|
||||
int n;
|
||||
|
||||
if (mSplitRun) {
|
||||
// Continue run
|
||||
n = mLeftOfRun;
|
||||
@ -164,24 +163,30 @@ public final class PackBitsDecoder implements Decoder {
|
||||
return read;
|
||||
}
|
||||
|
||||
private static byte readByte(InputStream pStream) throws IOException {
|
||||
private static byte readByte(final InputStream pStream) throws IOException {
|
||||
int read = pStream.read();
|
||||
|
||||
if (read < 0) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
}
|
||||
|
||||
return (byte) read;
|
||||
}
|
||||
|
||||
private static void readFully(InputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
private static void readFully(final InputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
||||
if (pLength < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
int read = 0;
|
||||
|
||||
while (read < pLength) {
|
||||
int count = pStream.read(pBuffer, pOffset + read, pLength - read);
|
||||
|
||||
if (count < 0) {
|
||||
throw new EOFException("Unexpected end of PackBits stream");
|
||||
}
|
||||
|
||||
read += count;
|
||||
}
|
||||
}
|
||||
|
5
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java
Executable file → Normal file
5
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java
Executable file → Normal file
@ -52,6 +52,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
|
||||
while (mSrcY >= 0) {
|
||||
int byte1 = pInput.read();
|
||||
int byte2 = checkEOF(pInput.read());
|
||||
|
||||
if (byte1 == 0x00) {
|
||||
switch (byte2) {
|
||||
case 0x00:
|
||||
@ -102,6 +103,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
|
||||
mRow[mSrcX++] = (byte) byte2;
|
||||
byte1 -= 2;
|
||||
}
|
||||
|
||||
if (byte1 == 1) {
|
||||
// TODO: Half byte alignment? Seems to be ok...
|
||||
mRow[mSrcX++] = (byte) (byte2 & 0xf0);
|
||||
@ -110,14 +112,15 @@ final class RLE4Decoder extends AbstractRLEDecoder {
|
||||
|
||||
// If we're done with a complete row, copy the data
|
||||
if (mSrcX == mRow.length) {
|
||||
|
||||
// Move to new position, either absolute (delta) or next line
|
||||
if (deltaX != 0 || deltaY != 0) {
|
||||
mSrcX = (deltaX + 1) / 2;
|
||||
|
||||
if (deltaY > mSrcY) {
|
||||
mSrcY = deltaY;
|
||||
break;
|
||||
}
|
||||
|
||||
deltaX = 0;
|
||||
deltaY = 0;
|
||||
}
|
||||
|
1
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java
Executable file → Normal file
1
twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java
Executable file → Normal file
@ -52,6 +52,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
|
||||
while (mSrcY >= 0) {
|
||||
int byte1 = pInput.read();
|
||||
int byte2 = checkEOF(pInput.read());
|
||||
|
||||
if (byte1 == 0x00) {
|
||||
switch (byte2) {
|
||||
case 0x00:
|
||||
|
6
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java
Executable file → Normal file
6
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java
Executable file → Normal file
@ -20,14 +20,14 @@ public class Base64EncoderTestCase extends EncoderAbstractTestCase {
|
||||
}
|
||||
|
||||
public void testNegativeEncode() throws IOException {
|
||||
Encoder base64 = createEncoder();
|
||||
Encoder encoder = createEncoder();
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
base64.encode(bytes, new byte[1], 2, 1);
|
||||
encoder.encode(bytes, new byte[1], 2, 1);
|
||||
fail("wrong index should throw IndexOutOfBoundsException");
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
catch (IndexOutOfBoundsException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
34
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java
Executable file → Normal file
34
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java
Executable file → Normal file
@ -1,11 +1,7 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.io.enc.Encoder;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
@ -86,14 +82,34 @@ public abstract class DecoderAbstractTestCase extends ObjectAbstractTestCase {
|
||||
}
|
||||
|
||||
public final void testStreams() throws Exception {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
runStreamTest(i);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 100; i < 2000; i += 250) {
|
||||
runStreamTest(i);
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 2000; i < 80000; i += 1000) {
|
||||
runStreamTest(i);
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
97
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java
Executable file → Normal file
97
twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java
Executable file → Normal file
@ -1,11 +1,7 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.io.enc.Encoder;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
@ -31,58 +27,99 @@ public abstract class EncoderAbstractTestCase extends ObjectAbstractTestCase {
|
||||
}
|
||||
|
||||
public final void testNullEncode() throws IOException {
|
||||
Encoder base64 = createEncoder();
|
||||
Encoder encoder = createEncoder();
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
base64.encode(bytes, null, 0, 1);
|
||||
encoder.encode(bytes, null, 0, 1);
|
||||
fail("null should throw NullPointerException");
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] createData(int pLength) throws Exception {
|
||||
private byte[] createData(final int pLength) throws Exception {
|
||||
byte[] bytes = new byte[pLength];
|
||||
RANDOM.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void runStreamTest(int pLength) throws Exception {
|
||||
private void runStreamTest(final int pLength) throws Exception {
|
||||
byte[] data = createData(pLength);
|
||||
ByteArrayOutputStream out_bytes = new ByteArrayOutputStream();
|
||||
OutputStream out = new EncoderStream(out_bytes, createEncoder(), true);
|
||||
out.write(data);
|
||||
out.close();
|
||||
byte[] encoded = out_bytes.toByteArray();
|
||||
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
||||
OutputStream out = new EncoderStream(outBytes, createEncoder(), true);
|
||||
|
||||
try {
|
||||
out.write(data);
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
byte[] encoded = outBytes.toByteArray();
|
||||
|
||||
// System.err.println("encoded.length: " + encoded.length);
|
||||
// System.err.println("encoded: " + Arrays.toString(encoded));
|
||||
|
||||
byte[] decoded = FileUtil.read(new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder()));
|
||||
assertTrue(Arrays.equals(data, decoded));
|
||||
|
||||
InputStream in = new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder());
|
||||
out_bytes = new ByteArrayOutputStream();
|
||||
/**
|
||||
byte[] buffer = new byte[3];
|
||||
for (int n = in.read(buffer); n > 0; n = in.read(buffer)) {
|
||||
out_bytes.write(buffer, 0, n);
|
||||
}
|
||||
//*/
|
||||
FileUtil.copy(in, out_bytes);
|
||||
outBytes = new ByteArrayOutputStream();
|
||||
|
||||
out_bytes.close();
|
||||
in.close();
|
||||
decoded = out_bytes.toByteArray();
|
||||
try {
|
||||
FileUtil.copy(in, outBytes);
|
||||
}
|
||||
finally {
|
||||
outBytes.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
decoded = outBytes.toByteArray();
|
||||
assertTrue(Arrays.equals(data, decoded));
|
||||
}
|
||||
|
||||
public final void testStreams() throws Exception {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
runStreamTest(i);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 100; i < 2000; i += 250) {
|
||||
runStreamTest(i);
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 2000; i < 80000; i += 1000) {
|
||||
runStreamTest(i);
|
||||
try {
|
||||
runStreamTest(i);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage() + ": " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
5
twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java
Executable file → Normal file
5
twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java
Executable file → Normal file
@ -30,12 +30,12 @@ package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.io.enc.InflateDecoder;
|
||||
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* PSDUtil
|
||||
@ -81,7 +81,8 @@ final class PSDUtil {
|
||||
}
|
||||
|
||||
static DataInputStream createZipStream(final ImageInputStream pInput, int pLength) {
|
||||
return new DataInputStream(new DecoderStream(IIOUtil.createStreamAdapter(pInput, pLength), new InflateDecoder()));
|
||||
//return new DataInputStream(new DecoderStream(IIOUtil.createStreamAdapter(pInput, pLength), new InflateDecoder()));
|
||||
return new DataInputStream(new ZipInputStream(IIOUtil.createStreamAdapter(pInput, pLength)));
|
||||
}
|
||||
|
||||
static DataInputStream createZipPredictorStream(final ImageInputStream pInput, int pLength) {
|
||||
|
@ -36,31 +36,55 @@ import java.util.zip.Deflater;
|
||||
* {@code Encoder} implementation for standard DEFLATE encoding.
|
||||
* <p/>
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java#2 $
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
||||
* @see Deflater
|
||||
* @see InflateDecoder
|
||||
* @see java.util.zip.DeflaterOutputStream
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java#2 $
|
||||
*/
|
||||
public final class DeflateEncoder implements Encoder {
|
||||
final class DeflateEncoder implements Encoder {
|
||||
|
||||
private final Deflater mDeflater;
|
||||
private final byte[] mBuffer = new byte[1024];
|
||||
|
||||
public DeflateEncoder() {
|
||||
this(new Deflater());
|
||||
// this(new Deflater());
|
||||
this(new Deflater(Deflater.DEFAULT_COMPRESSION, true)); // TODO: Should we use "no wrap"?
|
||||
}
|
||||
|
||||
public DeflateEncoder(Deflater pDeflater) {
|
||||
public DeflateEncoder(final Deflater pDeflater) {
|
||||
if (pDeflater == null) {
|
||||
throw new IllegalArgumentException("deflater == null");
|
||||
}
|
||||
|
||||
mDeflater = pDeflater;
|
||||
}
|
||||
|
||||
public void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
throw new InternalError("not implemented: encode()"); // TODO: Implement
|
||||
public void encode(final OutputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength)
|
||||
throws IOException
|
||||
{
|
||||
System.out.println("DeflateEncoder.encode");
|
||||
mDeflater.setInput(pBuffer, pOffset, pLength);
|
||||
flushInputToStream(pStream);
|
||||
}
|
||||
|
||||
private void flushInputToStream(final OutputStream pStream) throws IOException {
|
||||
System.out.println("DeflateEncoder.flushInputToStream");
|
||||
|
||||
if (mDeflater.needsInput()) {
|
||||
System.out.println("Foo");
|
||||
}
|
||||
|
||||
while (!mDeflater.needsInput()) {
|
||||
int deflated = mDeflater.deflate(mBuffer, 0, mBuffer.length);
|
||||
pStream.write(mBuffer, 0, deflated);
|
||||
System.out.println("flushed " + deflated);
|
||||
}
|
||||
}
|
||||
|
||||
// public void flush() {
|
||||
// mDeflater.finish();
|
||||
// }
|
||||
}
|
@ -47,7 +47,7 @@ import java.util.zip.Inflater;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java#2 $
|
||||
*/
|
||||
public final class InflateDecoder implements Decoder {
|
||||
final class InflateDecoder implements Decoder {
|
||||
|
||||
private final Inflater mInflater;
|
||||
|
||||
@ -66,25 +66,29 @@ public final class InflateDecoder implements Decoder {
|
||||
*
|
||||
* @param pInflater the inflater instance to use
|
||||
*/
|
||||
public InflateDecoder(Inflater pInflater) {
|
||||
public InflateDecoder(final Inflater pInflater) {
|
||||
if (pInflater == null) {
|
||||
throw new IllegalArgumentException("inflater == null");
|
||||
}
|
||||
|
||||
mInflater = pInflater;
|
||||
mBuffer = new byte[1024];
|
||||
}
|
||||
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
try {
|
||||
int decoded;
|
||||
|
||||
while ((decoded = mInflater.inflate(pBuffer, 0, pBuffer.length)) == 0) {
|
||||
if (mInflater.finished() || mInflater.needsDictionary()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mInflater.needsInput()) {
|
||||
fill(pStream);
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
catch (DataFormatException e) {
|
||||
@ -93,11 +97,13 @@ public final class InflateDecoder implements Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
private void fill(InputStream pStream) throws IOException {
|
||||
private void fill(final InputStream pStream) throws IOException {
|
||||
int available = pStream.read(mBuffer, 0, mBuffer.length);
|
||||
|
||||
if (available == -1) {
|
||||
throw new EOFException("Unexpected end of ZLIB stream");
|
||||
}
|
||||
|
||||
mInflater.setInput(mBuffer, 0, available);
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ import java.io.IOException;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java#2 $
|
||||
*/
|
||||
public class LZWDecoder implements Decoder {
|
||||
final class LZWDecoder implements Decoder {
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
return 0; // TODO: Implement
|
||||
// TODO: We probably need a GIF specific subclass
|
@ -38,7 +38,7 @@ import java.io.IOException;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java#2 $
|
||||
*/
|
||||
public class LZWEncoder implements Encoder {
|
||||
final class LZWEncoder implements Encoder {
|
||||
public void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
// TODO: Implement
|
||||
// TODO: We probably need a GIF specific subclass
|
@ -1,18 +1,13 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
import com.twelvemonkeys.io.enc.DeflateEncoder;
|
||||
import com.twelvemonkeys.io.enc.Encoder;
|
||||
import com.twelvemonkeys.io.enc.InflateDecoder;
|
||||
|
||||
/**
|
||||
* DeflateDecoderTest
|
||||
* DeflateEncoderTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java#1 $
|
||||
*/
|
||||
public class DeflateDecoderTestCase extends EncoderAbstractTestCase {
|
||||
public class DeflateEncoderTestCase extends EncoderAbstractTestCase {
|
||||
protected Encoder createEncoder() {
|
||||
return new DeflateEncoder();
|
||||
}
|
@ -1,10 +1,5 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
import com.twelvemonkeys.io.enc.DeflateEncoder;
|
||||
import com.twelvemonkeys.io.enc.Encoder;
|
||||
import com.twelvemonkeys.io.enc.InflateDecoder;
|
||||
|
||||
/**
|
||||
* InflateEncoderTest
|
||||
* <p/>
|
Loading…
x
Reference in New Issue
Block a user