TMC-IOENC-11: Fixed problem introduced when migrating byte[] -> ByteBuffer

This commit is contained in:
Harald Kuhr 2013-09-27 14:21:31 +02:00
parent cd197afc04
commit 1acc04eeaf
5 changed files with 33 additions and 22 deletions

View File

@ -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}.
* <p/>
* 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

View File

@ -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);

View File

@ -73,16 +73,20 @@ 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
@ -95,31 +99,31 @@ public final class PackBitsEncoder implements Encoder {
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++]);
}
}
}

View File

@ -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.
}

View File

@ -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
* <p/>