/* Copyright (c) 2007 Jython Developers */ package org.python.core.io; import java.nio.ByteBuffer; /** * Buffer for a readable sequential RawIO object. * * @author Philip Jenvey */ public class BufferedReader extends BufferedIOMixin { /** The underlying buffer */ protected ByteBuffer buffer; /** * Construct a BufferedReader of bufferSize, wrapping the given * RawIOBase. * * @param rawIO {@inheritDoc} * @param bufferSize {@inheritDoc} */ public BufferedReader(RawIOBase rawIO, int bufferSize) { super(rawIO, bufferSize); rawIO.checkReadable(); buffer = ByteBuffer.allocate(this.bufferSize); clear(); } @Override public int readinto(ByteBuffer bytes) { int size = bytes.remaining(); if (size == 0) { return 0; } if (buffer.remaining() >= size) { // Fulfill the read entirely from the buffer int bufferLimit = buffer.limit(); buffer.limit(buffer.position() + size); bytes.put(buffer); buffer.limit(bufferLimit); return size; } // Drain the buffer then request more from the RawIO bytes.put(buffer); buffer.clear(); // Only attempt one read. The buffering layer should not wait // for more data (block) to fulfill the entire read long read = rawIO.readinto(new ByteBuffer[] {bytes, buffer}); read -= buffer.flip().limit(); // This is an int after subtracting the buffer size anyway return (int)read; } @Override public ByteBuffer readall() { ByteBuffer remaining = rawIO.readall(); if (!buffer.hasRemaining()) { return remaining; } ByteBuffer all = ByteBuffer.allocate(buffer.remaining() + remaining.remaining()); all.put(buffer); clear(); all.put(remaining); all.flip(); return all; } @Override public ByteBuffer peek(int size) { if (buffer.remaining() < Math.min(size, bufferSize)) { // Prepare to fill the buffer if (buffer.position() == 0) { buffer.limit(buffer.capacity()); } else { buffer.compact(); } rawIO.readinto(buffer); buffer.flip(); } return buffer; } @Override public int read1(ByteBuffer bytes) { int size = bytes.remaining(); if (size == 0) { return 0; } if (bufferSize > 0) { peek(1); int bufferedSize = buffer.remaining(); if (bufferedSize < size) { bytes.limit(bytes.position() + bufferedSize); } } return readinto(bytes); } @Override public long tell() { return rawIO.tell() - buffer.remaining(); } @Override public long seek(long pos, int whence) { if (whence == 1) { pos -= buffer.remaining(); } pos = rawIO.seek(pos, whence); clear(); return pos; } @Override public boolean buffered() { return buffer.hasRemaining(); } @Override public void clear() { buffer.clear().limit(0); } @Override public int write(ByteBuffer bytes) { // Never writable; just raise the appropriate exception checkClosed(); checkWritable(); return -1; } @Override public boolean writable() { return false; } }