diff --git a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/Encoder.java b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/Encoder.java index c1a126b0..1864e4dc 100644 --- a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/Encoder.java +++ b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/Encoder.java @@ -33,9 +33,9 @@ import java.io.OutputStream; import java.nio.ByteBuffer; /** - * Interface for endcoders. + * Interface for encoders. * An {@code Encoder} may be used with an {@code EncoderStream}, to perform - * on-the-fly enoding to an {@code OutputStream}. + * on-the-fly encoding to an {@code OutputStream}. *

* Important note: Encoder implementations are typically not synchronized. * @@ -48,7 +48,7 @@ import java.nio.ByteBuffer; public interface Encoder { /** - * Encodes up to {@code pBuffer.length} bytes into the given input stream, + * Encodes up to {@code buffer.remaining()} bytes into the given input stream, * from the given buffer. * * @param stream the output stream to encode data to diff --git a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java index 6cf9ee31..f1ba67ef 100644 --- a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java +++ b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java @@ -44,6 +44,7 @@ import java.nio.ByteBuffer; * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java#2 $ */ public final class EncoderStream extends FilterOutputStream { + // TODO: This class need a test case ASAP!!! protected final Encoder encoder; private final boolean flushOnWrite; @@ -91,7 +92,9 @@ public final class EncoderStream extends FilterOutputStream { } private void encodeBuffer() throws IOException { - if (buffer.hasRemaining()) { + if (buffer.position() != 0) { + buffer.flip(); + // Make sure all remaining data in buffer is written to the stream encoder.encode(out, buffer); diff --git a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/PackBitsEncoder.java b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/PackBitsEncoder.java index 61edf7bb..c11ccd97 100755 --- a/common/common-io/src/main/java/com/twelvemonkeys/io/enc/PackBitsEncoder.java +++ b/common/common-io/src/main/java/com/twelvemonkeys/io/enc/PackBitsEncoder.java @@ -73,53 +73,57 @@ public final class PackBitsEncoder implements Encoder { } public void encode(final OutputStream stream, final ByteBuffer buffer) throws IOException { + encode(stream, buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); + buffer.position(buffer.remaining()); + } + + private void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException { // NOTE: It's best to encode a 2 byte repeat // run as a replicate run except when preceded and followed by a // literal run, in which case it's best to merge the three into one // literal run. Always encode 3 byte repeats as replicate runs. // NOTE: Worst case: output = input + (input + 127) / 128 - int offset = buffer.position(); - final int max = buffer.remaining() - 1; + int offset = pOffset; + final int max = pOffset + pLength - 1; final int maxMinus1 = max - 1; - final byte[] pBuffer = buffer.array(); while (offset <= max) { // Compressed run int run = 1; byte replicate = pBuffer[offset]; - while (run < 127 && offset < max && pBuffer[offset] == pBuffer[offset + 1]) { + while(run < 127 && offset < max && pBuffer[offset] == pBuffer[offset + 1]) { offset++; run++; } if (run > 1) { offset++; - stream.write(-(run - 1)); - stream.write(replicate); + pStream.write(-(run - 1)); + pStream.write(replicate); } // Literal run run = 0; while ((run < 128 && ((offset < max && pBuffer[offset] != pBuffer[offset + 1]) || (offset < maxMinus1 && pBuffer[offset] != pBuffer[offset + 2])))) { - this.buffer[run++] = pBuffer[offset++]; + buffer[run++] = pBuffer[offset++]; } // If last byte, include it in literal run, if space if (offset == max && run > 0 && run < 128) { - this.buffer[run++] = pBuffer[offset++]; + buffer[run++] = pBuffer[offset++]; } if (run > 0) { - stream.write(run - 1); - stream.write(this.buffer, 0, run); + pStream.write(run - 1); + pStream.write(buffer, 0, run); } // If last byte, and not space, start new literal run if (offset == max && (run <= 0 || run >= 128)) { - stream.write(0); - stream.write(pBuffer[offset++]); + pStream.write(0); + pStream.write(pBuffer[offset++]); } } } diff --git a/common/common-io/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java b/common/common-io/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java index 0977a654..6376a73d 100644 --- a/common/common-io/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java +++ b/common/common-io/src/test/java/com/twelvemonkeys/io/enc/EncoderAbstractTestCase.java @@ -54,7 +54,12 @@ public abstract class EncoderAbstractTestCase extends ObjectAbstractTestCase { OutputStream out = new EncoderStream(outBytes, createEncoder(), true); try { - out.write(data); + // Provoke failure for encoders that doesn't take array offset properly into account + int off = (data.length + 1) / 2; + out.write(data, 0, off); + if (data.length > off) { + out.write(data, off, data.length - off); + } } finally { out.close(); @@ -127,4 +132,8 @@ public abstract class EncoderAbstractTestCase extends ObjectAbstractTestCase { } } } + + // TODO: Test that the transition from byte[] to ByteBuffer didn't introduce bugs when writing to a wrapped array with offset. + + } diff --git a/common/common-io/src/test/java/com/twelvemonkeys/io/enc/PackBitsEncoderTestCase.java b/common/common-io/src/test/java/com/twelvemonkeys/io/enc/PackBitsEncoderTestCase.java index 023e99e1..d214fd3f 100755 --- a/common/common-io/src/test/java/com/twelvemonkeys/io/enc/PackBitsEncoderTestCase.java +++ b/common/common-io/src/test/java/com/twelvemonkeys/io/enc/PackBitsEncoderTestCase.java @@ -1,10 +1,5 @@ package com.twelvemonkeys.io.enc; -import com.twelvemonkeys.io.enc.Decoder; -import com.twelvemonkeys.io.enc.Encoder; -import com.twelvemonkeys.io.enc.PackBitsDecoder; -import com.twelvemonkeys.io.enc.PackBitsEncoder; - /** * PackBitsEncoderTest *