/* Copyright (c) 2007 Jython Developers */
package org.python.core.io;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import org.python.core.Py;
/**
* Base class for raw binary I/O.
*
* RawIOBases wrap raw Java I/O objects (typically nio Channels). They
* provide a convenient means of handling raw Java I/O objects in the
* context of Python files.
*
* RawIOBases maintain state about their underlying I/O objects (such
* as their mode) and translate Java exceptions into PyExceptions.
*
* The read() method is implemented by calling readinto(); derived
* classes that want to support read() only need to implement
* readinto() as a primitive operation. In general, readinto() can be
* more efficient than read().
*
* @author Philip Jenvey
*/
public abstract class RawIOBase extends IOBase {
/**
* Read and return up to size bytes, contained in a ByteBuffer.
*
* ByteBuffers returned from read are already flip()'d.
*
* Returns an empty ByteBuffer on EOF
*
* @param size the number of bytes to read
* @return a ByteBuffer containing the bytes read
*/
public ByteBuffer read(int size) {
if (size < 0) {
return readall();
}
ByteBuffer buf = ByteBuffer.allocate(size);
readinto(buf);
// flip()ing here is more convenient as there's no real use
// case for appending to buffers returned from read. readinto
// doesn't/shouldn't flip()
buf.flip();
return buf;
}
/**
* Read until EOF, using multiple read() calls.
*
* @return a ByteBuffer containing the bytes read
*/
public ByteBuffer readall() {
ByteBuffer all = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
ByteBuffer readBuffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
for (int readCount = 0; (readCount = readinto(readBuffer)) > 0;) {
if (all.remaining() < readCount) {
long newSize = (long) all.position() + readCount;
if (newSize > Integer.MAX_VALUE) {
throw Py.OverflowError("requested number of bytes is more than a Python "
+ "string can hold");
}
ByteBuffer old = all;
all = ByteBuffer.allocate(Math.max(old.capacity() * 2, (int) newSize));
old.flip();
all.put(old);
}
readBuffer.flip();
all.put(readBuffer);
readBuffer.clear();
}
all.flip();
return all;
}
/**
* Read up to buf.remaining() bytes into buf.
*
* Returns number of bytes read (0 for EOF).
*
* @param buf a ByteBuffer to read bytes into
* @return the amount of data read as an int
*/
public int readinto(ByteBuffer buf) {
unsupported("readinto");
return -1;
}
/**
* Read bytes into each of the specified ByteBuffers.
*
* Returns number of bytes read (0 for EOF).
*
* @param bufs an array of ByteBuffers to read bytes into
* @return the amount of data read as a long
*/
public long readinto(ByteBuffer[] bufs) {
long count = 0;
int bufCount;
for (ByteBuffer buf : bufs) {
if (!buf.hasRemaining()) {
continue;
}
if ((bufCount = readinto(buf)) == 0) {
break;
}
count += bufCount;
}
return count;
}
/**
* Write the given ByteBuffer to the IO stream.
*
* Returns the number of bytes written, which may be less than
* buf.remaining().
*
* @param buf a ByteBuffer value
* @return the number of bytes written as an int
*/
public int write(ByteBuffer buf) {
unsupported("write");
return -1;
}
/**
* Write the given ByteBuffers to the IO stream.
*
* Returns the number of bytes written, which may be less than the
* combined value of all the buf.remaining()'s.
*
* @param bufs an array of ByteBuffers
* @return the number of bytes written as a long
*/
public long write(ByteBuffer[] bufs) {
long count = 0;
int bufCount;
for (ByteBuffer buf : bufs) {
if (!buf.hasRemaining()) {
continue;
}
if ((bufCount = write(buf)) == 0) {
break;
}
count += bufCount;
}
return count;
}
@Override
public RawIOBase fileno() {
checkClosed();
return this;
}
/**
* Return the underlying Java nio Channel.
*
* @return the underlying Java nio Channel
*/
public abstract Channel getChannel();
}