package ioio.lib.impl;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Similar to a {@link BufferedInputStream}, but guarantees that all reads from the source stream
* are exactly the specified size of the buffer.
* It turns out, {@link BufferedInputStream} does not actually have such a guarantee.
*/
public class FixedReadBufferedInputStream extends InputStream {
private int bufferIndex_ = 0;
private int validData_ = 0;
private final byte[] buffer_;
private final InputStream source_;
public FixedReadBufferedInputStream(InputStream source, int size) {
buffer_ = new byte[size];
source_ = source;
}
@Override
public int available() throws IOException {
return validData_ - bufferIndex_;
}
@Override
public void close() throws IOException {
source_.close();
}
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
fillIfEmpty();
if (validData_ == -1) {
return -1;
}
length = Math.min(length, validData_ - bufferIndex_);
System.arraycopy(buffer_, bufferIndex_, buffer, offset, length);
bufferIndex_ += length;
return length;
}
@Override
public int read(byte[] buffer) throws IOException {
return read(buffer, 0, buffer.length);
}
@Override
public int read() throws IOException {
fillIfEmpty();
if (validData_ == -1) {
return -1;
}
return buffer_[bufferIndex_++] & 0xFF;
}
@Override
public long skip(long byteCount) throws IOException {
long skipped = 0;
while (byteCount > 0) {
fillIfEmpty();
if (validData_ == -1) {
return skipped;
}
int count = (int) Math.min(available(), byteCount);
byteCount -= count;
bufferIndex_ += count;
skipped += count;
}
return skipped;
}
private void fillIfEmpty() throws IOException {
while (available() == 0 && validData_ != -1) {
fill();
}
}
private void fill() throws IOException {
bufferIndex_ = 0;
validData_ = source_.read(buffer_);
}
}