package org.jcodec.common.io;
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* This class is analogous to DataInputStream, it's backed by the Channel and
* buffers the IO
*
* @author The JCodec project
*
*/
public class DataReader implements Closeable {
private static final int DEFAULT_BUFFER_SIZE = 1 << 20; // 1 megabyte
private SeekableByteChannel channel;
private ByteBuffer buffer;
public static DataReader createDataReader(SeekableByteChannel channel, ByteOrder order) {
return new DataReader(channel, order, DEFAULT_BUFFER_SIZE);
}
public DataReader(SeekableByteChannel channel, ByteOrder order, int bufferSize) {
this.channel = channel;
this.buffer = ByteBuffer.allocate(bufferSize);
this.buffer.limit(0);
this.buffer.order(order);
}
public int readFully3(byte[] b, int off, int len) throws IOException {
int initOff = off;
while (len > 0) {
fetchIfNeeded(len);
if (buffer.remaining() == 0)
break;
int toRead = Math.min(buffer.remaining(), len);
buffer.get(b, off, toRead);
off += toRead;
len -= toRead;
}
return off - initOff;
}
public int skipBytes(int n) throws IOException {
long oldPosition = position();
if (n < buffer.remaining()) {
buffer.position(buffer.position() + n);
} else {
setPosition(oldPosition + n);
}
return (int) (position() - oldPosition);
}
public byte readByte() throws IOException {
fetchIfNeeded(1);
return buffer.get();
}
public short readShort() throws IOException {
fetchIfNeeded(2);
return buffer.getShort();
}
public char readChar() throws IOException {
fetchIfNeeded(2);
return buffer.getChar();
}
public int readInt() throws IOException {
fetchIfNeeded(4);
return buffer.getInt();
}
public long readLong() throws IOException {
fetchIfNeeded(8);
return buffer.getLong();
}
public float readFloat() throws IOException {
fetchIfNeeded(4);
return buffer.getFloat();
}
public double readDouble() throws IOException {
fetchIfNeeded(8);
return buffer.getDouble();
}
public long position() throws IOException {
return channel.position() - buffer.limit() + buffer.position();
}
public long setPosition(long newPos) throws IOException {
int relative = (int) (newPos - (channel.position() - buffer.limit()));
if (relative >= 0 && relative < buffer.limit()) {
buffer.position(relative);
} else {
buffer.limit(0);
channel.setPosition(newPos);
}
return position();
}
@Override
public void close() throws IOException {
channel.close();
}
private void fetchIfNeeded(int length) throws IOException {
if (buffer.remaining() < length) {
moveRemainderToTheStart(buffer);
channel.read(buffer);
buffer.flip();
}
}
private static void moveRemainderToTheStart(ByteBuffer readBuf) {
int rem = readBuf.remaining();
for (int i = 0; i < rem; i++) {
readBuf.put(i, readBuf.get());
}
readBuf.clear();
readBuf.position(rem);
}
public long size() throws IOException {
return channel.size();
}
public int readFully(byte[] b) throws IOException {
return readFully3(b, 0, b.length);
}
}