/* Copyright (c) 2007 Jython Developers */ package org.python.core.io; import java.nio.ByteBuffer; import org.python.core.util.StringUtil; /** * A Buffered text stream in binary mode. * * @author Philip Jenvey */ public class BinaryIOWrapper extends TextIOBase { /** * Contruct a TextIOBase in binary mode, wrapping the given * BufferedIOBase. * * @param bufferedIO {@inheritDoc} */ public BinaryIOWrapper(BufferedIOBase bufferedIO) { super(bufferedIO); } @Override public String read(int size) { if (size < 0) { return readall(); } if (!readahead.hasRemaining()) { return StringUtil.fromBytes(bufferedIO.read(size)); } ByteBuffer data = ByteBuffer.allocate(size); if (readahead.remaining() >= size) { // Fulfill the read entirely from the readahead int readaheadLimit = readahead.limit(); readahead.limit(readahead.position() + size); data.put(readahead); readahead.limit(readaheadLimit); data.flip(); return StringUtil.fromBytes(data); } // Drain the readahead then request more from the buffer data.put(readahead); clearReadahead(); bufferedIO.readinto(data); data.flip(); return StringUtil.fromBytes(data); } @Override public String readall() { if (!readahead.hasRemaining()) { return StringUtil.fromBytes(bufferedIO.readall()); } ByteBuffer remaining = bufferedIO.readall(); ByteBuffer all = ByteBuffer.allocate(readahead.remaining() + remaining.remaining()); all.put(readahead); clearReadahead(); all.put(remaining); all.flip(); return StringUtil.fromBytes(all); } @Override public String readline(int size) { // Avoid ByteBuffer (this.readahead) and StringBuilder // (this.builder) method calls in the inner loop by reading // directly from the readahead's backing array and writing to // an interim char array (this.interimBuilder) byte[] readaheadArray; int readaheadPos; int interimBuilderPos; do { readaheadArray = readahead.array(); readaheadPos = readahead.position(); interimBuilderPos = 0; while (readaheadPos < readahead.limit() && (size < 0 || builder.length() + interimBuilderPos < size)) { char next = (char)(readaheadArray[readaheadPos++] & 0xff); interimBuilder[interimBuilderPos++] = next; if (next == '\n') { builder.append(interimBuilder, 0, interimBuilderPos); // Reposition the readahead to where we ended readahead.position(readaheadPos); return drainBuilder(); } } builder.append(interimBuilder, 0, interimBuilderPos); } while ((size < 0 || builder.length() < size) && readChunk() > 0); // Reposition the readahead to where we ended. The position is // invalid if the readahead is empty (at EOF; readChunk() // returned 0) if (readahead.hasRemaining()) { readahead.position(readaheadPos); } return drainBuilder(); } @Override public int write(String buf) { if (readahead.hasRemaining()) { clearReadahead(); } return bufferedIO.write(ByteBuffer.wrap(StringUtil.toBytes(buf))); } }