Rewritten to use ByteBuffer.

This commit is contained in:
Harald Kuhr 2013-11-20 20:05:39 +01:00
parent 39d3fc426e
commit c7ecd7afc8

View File

@ -5,6 +5,7 @@ import com.twelvemonkeys.lang.Validate;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageInputStreamImpl; import javax.imageio.stream.ImageInputStreamImpl;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
/** /**
* A buffered {@code ImageInputStream}. * A buffered {@code ImageInputStream}.
@ -20,15 +21,11 @@ import java.io.IOException;
// TODO: Create a provider for this (wrapping the FileIIS and FileCacheIIS classes), and disable the Sun built-in spis? // TODO: Create a provider for this (wrapping the FileIIS and FileCacheIIS classes), and disable the Sun built-in spis?
// TODO: Test on other platforms, might be just an OS X issue // TODO: Test on other platforms, might be just an OS X issue
public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream { public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream {
static final int DEFAULT_BUFFER_SIZE = 8192; static final int DEFAULT_BUFFER_SIZE = 8192;
private ImageInputStream stream; private ImageInputStream stream;
private byte[] buffer; private ByteBuffer buffer;
private long bufferStart = 0;
private int bufferPos = 0;
private int bufferLength = 0;
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException { public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
this(pStream, DEFAULT_BUFFER_SIZE); this(pStream, DEFAULT_BUFFER_SIZE);
@ -39,42 +36,54 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
stream = pStream; stream = pStream;
streamPos = pStream.getStreamPosition(); streamPos = pStream.getStreamPosition();
buffer = new byte[pBufferSize]; buffer = ByteBuffer.allocate(pBufferSize);
buffer.limit(0);
} }
private void fillBuffer() throws IOException { private void fillBuffer() throws IOException {
bufferStart = streamPos; buffer.clear();
bufferLength = stream.read(buffer, 0, buffer.length);
bufferPos = 0; int length = stream.read(buffer.array(), 0, buffer.capacity());
if (length >= 0) {
try {
buffer.position(length);
}
catch (IllegalArgumentException e) {
System.err.println("length: " + length);
throw e;
}
buffer.flip();
}
else {
buffer.limit(0);
}
} }
private boolean isBufferValid() throws IOException {
return bufferPos < bufferLength && bufferStart == stream.getStreamPosition() - bufferLength;
}
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if (!isBufferValid()) { if (!buffer.hasRemaining()) {
fillBuffer(); fillBuffer();
} }
if (bufferLength <= 0) { if (!buffer.hasRemaining()) {
return -1; return -1;
} }
bitOffset = 0; bitOffset = 0;
streamPos++; streamPos++;
return buffer[bufferPos++] & 0xff; return buffer.get() & 0xff;
} }
@Override @Override
public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException { public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
bitOffset = 0; bitOffset = 0;
if (!isBufferValid()) { if (!buffer.hasRemaining()) {
// Bypass cache if cache is empty for reads longer than buffer // Bypass cache if cache is empty for reads longer than buffer
if (pLength >= buffer.length) { if (pLength >= buffer.capacity()) {
return readDirect(pBuffer, pOffset, pLength); return readDirect(pBuffer, pOffset, pLength);
} }
else { else {
@ -87,30 +96,29 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
private int readDirect(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException { private int readDirect(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
// TODO: Figure out why reading more than the buffer length causes alignment issues... // TODO: Figure out why reading more than the buffer length causes alignment issues...
int read = stream.read(pBuffer, pOffset, Math.min(buffer.length, pLength)); int read = stream.read(pBuffer, pOffset, Math.min(buffer.capacity(), pLength));
if (read > 0) { if (read > 0) {
streamPos += read; streamPos += read;
} }
bufferStart = stream.getStreamPosition();
bufferLength = 0;
return read; return read;
} }
private int readBuffered(final byte[] pBuffer, final int pOffset, final int pLength) { private int readBuffered(final byte[] pBuffer, final int pOffset, final int pLength) {
if (bufferLength <= 0) { if (!buffer.hasRemaining()) {
return -1; return -1;
} }
// Read as much as possible from buffer // Read as much as possible from buffer
int length = Math.min(bufferLength - bufferPos, pLength); int length = Math.min(buffer.remaining(), pLength);
if (length > 0) { if (length > 0) {
System.arraycopy(buffer, bufferPos, pBuffer, pOffset, length); int position = buffer.position();
bufferPos += length; System.arraycopy(buffer.array(), position, pBuffer, pOffset, length);
buffer.position(position + length);
} }
streamPos += length; streamPos += length;
@ -122,7 +130,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
public void seek(long pPosition) throws IOException { public void seek(long pPosition) throws IOException {
// TODO: Could probably be optimized to not invalidate buffer if new position is within current buffer // TODO: Could probably be optimized to not invalidate buffer if new position is within current buffer
stream.seek(pPosition); stream.seek(pPosition);
bufferLength = 0; // Will invalidate buffer buffer.limit(0); // Will invalidate buffer
streamPos = stream.getStreamPosition(); streamPos = stream.getStreamPosition();
} }
@ -158,6 +166,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
stream = null; stream = null;
buffer = null; buffer = null;
} }
super.close(); super.close();
} }