/* * Copyright 2012 David Tinker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.qdb.buffer; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * Fast class to treat a FileChannel more or less like a stream with synchronization on the channel. Reading past * the end of the channel will produce an IOException. */ class ChannelInput { private final FileChannel channel; private final ByteBuffer buffer; private int nextBufferPosition; ChannelInput(FileChannel channel, int position, int bufferSize) throws IOException { this.channel = channel; this.nextBufferPosition = position; this.buffer = ByteBuffer.allocateDirect(bufferSize); buffer.limit(0); } private void fill() throws IOException { buffer.compact(); synchronized (channel) { channel.position(nextBufferPosition); int sz = channel.read(buffer); if (sz == 0) throw new EOFException(); nextBufferPosition += sz; } buffer.flip(); } public int position() { return nextBufferPosition - buffer.remaining(); } public void position(int newPosition) { if (newPosition == position()) return; if (newPosition >= nextBufferPosition) { nextBufferPosition = newPosition; buffer.limit(0); return; } int startOfBuffer = nextBufferPosition - buffer.limit(); if (newPosition < startOfBuffer) { nextBufferPosition = newPosition; buffer.limit(0); return; } // position to seek to is in buffer buffer.position(newPosition - startOfBuffer); } public byte readByte() throws IOException { if (!buffer.hasRemaining()) fill(); return buffer.get(); } public short readShort() throws IOException { if (buffer.remaining() < 2) fill(); return buffer.getShort(); } public int readInt() throws IOException { if (buffer.remaining() < 4) fill(); return buffer.getInt(); } public long readLong() throws IOException { if (buffer.remaining() < 8) fill(); return buffer.getLong(); } public void read(byte[] dst, int offset, int length) throws IOException { for (; length > 0; ) { int remaining = buffer.remaining(); if (length <= remaining) { buffer.get(dst, offset, length); break; } buffer.get(dst, offset, remaining); offset += remaining; length -= remaining; fill(); } } public void skip(int bytes) { int remaining = buffer.remaining(); if (bytes < remaining) { buffer.position(buffer.position() + bytes); } else { buffer.position(0); buffer.limit(0); nextBufferPosition += bytes - remaining; } } }