mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-02 02:55:28 -04:00
TMC-IOENC-11: Fixed problem introduced when migrating byte[] -> ByteBuffer
This commit is contained in:
parent
cd197afc04
commit
1acc04eeaf
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
|
||||
}
|
||||
|
@ -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/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user