From c45882846a9a52625fc46187c2e871ed4221f76e Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Fri, 18 Sep 2009 22:46:31 +0200 Subject: [PATCH] - Moved unused encoders/decoders to sandbox - Fixed Base64 encoder/decoder to pass test cases - Minor clean-up in other decoders --- .../io/enc/AbstractRLEDecoder.java | 5 +- .../twelvemonkeys/io/enc/Base64Decoder.java | 58 ++++++----- .../twelvemonkeys/io/enc/Base64Encoder.java | 19 +++- .../twelvemonkeys/io/enc/DecoderStream.java | 24 ++--- .../com/twelvemonkeys/io/enc/Encoder.java | 2 +- .../twelvemonkeys/io/enc/EncoderStream.java | 18 ++-- .../io/enc/PackBits16Decoder.java | 23 +++-- .../twelvemonkeys/io/enc/PackBitsDecoder.java | 27 +++--- .../com/twelvemonkeys/io/enc/RLE4Decoder.java | 5 +- .../com/twelvemonkeys/io/enc/RLE8Decoder.java | 1 + .../io/enc/Base64EncoderTestCase.java | 6 +- .../io/enc/DecoderAbstractTestCase.java | 34 +++++-- .../io/enc/EncoderAbstractTestCase.java | 97 +++++++++++++------ .../imageio/plugins/psd/PSDUtil.java | 5 +- .../twelvemonkeys/io/enc/DeflateEncoder.java | 42 ++++++-- .../twelvemonkeys/io/enc/InflateDecoder.java | 14 ++- .../com/twelvemonkeys/io/enc/LZWDecoder.java | 2 +- .../com/twelvemonkeys/io/enc/LZWEncoder.java | 2 +- .../io/enc/DeflateEncoderTestCase.java | 9 +- .../io/enc/InflateDecoderTestCase.java | 5 - 20 files changed, 259 insertions(+), 139 deletions(-) mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java mode change 100755 => 100644 twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java mode change 100755 => 100644 twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java mode change 100755 => 100644 twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java mode change 100755 => 100644 twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java mode change 100755 => 100644 twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java rename {twelvemonkeys-core => twelvemonkeys-sandbox}/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java (66%) mode change 100755 => 100644 rename {twelvemonkeys-core => twelvemonkeys-sandbox}/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java (90%) mode change 100755 => 100644 rename {twelvemonkeys-core => twelvemonkeys-sandbox}/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java (95%) mode change 100755 => 100644 rename {twelvemonkeys-core => twelvemonkeys-sandbox}/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java (95%) mode change 100755 => 100644 rename twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java => twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/DeflateEncoderTestCase.java (62%) mode change 100755 => 100644 rename {twelvemonkeys-core => twelvemonkeys-sandbox}/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java (73%) mode change 100755 => 100644 diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java old mode 100755 new mode 100644 index 105339a6..e02fba8a --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/AbstractRLEDecoder.java @@ -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. *

* * @author Harald Kuhr @@ -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; } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java old mode 100755 new mode 100644 index 3e736445..d6799af2 --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Decoder.java @@ -43,7 +43,7 @@ import java.io.*; * @author Harald Kuhr * @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(); diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java old mode 100755 new mode 100644 index e03a1f55..6c916fee --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Base64Encoder.java @@ -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; diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java old mode 100755 new mode 100644 index 2c13a433..f371a9be --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java @@ -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. *

* @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; } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java old mode 100755 new mode 100644 index b5d67adf..d142bfc5 --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/Encoder.java @@ -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 diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java old mode 100755 new mode 100644 index 5377b1ad..de8a7b5b --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java @@ -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; } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java old mode 100755 new mode 100644 index bfef3691..ef4efe1b --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBits16Decoder.java @@ -62,31 +62,31 @@ public final class PackBits16Decoder implements Decoder { /** * Creates a {@code PackBitsDecoder}. *

- * 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; } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java old mode 100755 new mode 100644 index 7a27b0ef..d6f7262b --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/PackBitsDecoder.java @@ -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}. *

- * 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; } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java old mode 100755 new mode 100644 index 9ff89f0c..8a07b99d --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE4Decoder.java @@ -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; } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java old mode 100755 new mode 100644 index 55e58886..f2bf78cd --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java +++ b/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/RLE8Decoder.java @@ -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: diff --git a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java old mode 100755 new mode 100644 index f9b3731d..c8331751 --- a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java +++ b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/Base64EncoderTestCase.java @@ -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) { } } diff --git a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java old mode 100755 new mode 100644 index 1f4e8e27..6522363e --- a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java +++ b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DecoderAbstractTestCase.java @@ -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); + } } } } diff --git a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java old mode 100755 new mode 100644 index d0317ae8..32266fe6 --- a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java +++ b/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java @@ -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); + } } } } diff --git a/twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java b/twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java old mode 100755 new mode 100644 index 3865e2e3..d9338fa6 --- a/twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java +++ b/twelvemonkeys-imageio/psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDUtil.java @@ -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) { diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java old mode 100755 new mode 100644 similarity index 66% rename from twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java rename to twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java index ff30241c..194669fe --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java +++ b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java @@ -36,31 +36,55 @@ import java.util.zip.Deflater; * {@code Encoder} implementation for standard DEFLATE encoding. *

* - * @see RFC 1951 + * @author Harald Kuhr + * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java#2 $ * + * @see RFC 1951 * @see Deflater * @see InflateDecoder * @see java.util.zip.DeflaterOutputStream - * - * @author Harald Kuhr - * @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(); +// } } diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java old mode 100755 new mode 100644 similarity index 90% rename from twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java rename to twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java index 9315ec42..04ebf7b5 --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java +++ b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java @@ -47,7 +47,7 @@ import java.util.zip.Inflater; * @author Harald Kuhr * @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); } } \ No newline at end of file diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java old mode 100755 new mode 100644 similarity index 95% rename from twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java rename to twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java index f2230829..b2d56869 --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java +++ b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWDecoder.java @@ -38,7 +38,7 @@ import java.io.IOException; * @author Harald Kuhr * @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 diff --git a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java old mode 100755 new mode 100644 similarity index 95% rename from twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java rename to twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java index 4962b383..a18faaa0 --- a/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java +++ b/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/io/enc/LZWEncoder.java @@ -38,7 +38,7 @@ import java.io.IOException; * @author Harald Kuhr * @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 diff --git a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java b/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/DeflateEncoderTestCase.java old mode 100755 new mode 100644 similarity index 62% rename from twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java rename to twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/DeflateEncoderTestCase.java index 3c079a17..d2e501ff --- a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java +++ b/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/DeflateEncoderTestCase.java @@ -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 *

* * @author Harald Kuhr * @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(); } diff --git a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java b/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java old mode 100755 new mode 100644 similarity index 73% rename from twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java rename to twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java index 388d01aa..70a6ad08 --- a/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java +++ b/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java @@ -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 *