/******************************************************************************* * Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://robocode.sourceforge.net/license/epl-v10.html * * Contributors: * Mathew A. Nelson * - Initial API and implementation * Flemming N. Larsen * - Code cleanup * - Bugfix: Changed the if-statement of "if (readIndex == writeIndex)" in * the read() method to a while-statement in order to correct text-output * bug, where old text or odd characters were printed out * - The setReadIndexToNextLine() has been embedded into the write(int b) * method *******************************************************************************/ package net.sf.robocode.host.io; import java.io.IOException; import java.io.OutputStream; /** * @author Mathew A. Nelson (original) * @author Flemming N. Larsen (contributor) */ public class BufferedPipedOutputStream extends OutputStream { private final Object monitor = new Object(); private final byte[] buf; private volatile int readIndex; private volatile int writeIndex; private volatile boolean waiting; private volatile boolean closed; private BufferedPipedInputStream in; private final boolean skipLines; public BufferedPipedOutputStream(int bufferSize, boolean skipLines) { this.buf = new byte[bufferSize]; this.skipLines = skipLines; } /* * @see OutputStream#write(int) */ @Override public void write(int b) throws IOException { synchronized (monitor) { if (closed) { throw new IOException("Stream is closed."); } buf[writeIndex++] = (byte) (b & 0xff); if (writeIndex == buf.length) { writeIndex = 0; } if (writeIndex == readIndex) { // skipping a line! if (skipLines) { boolean writeIndexReached = false; while (buf[readIndex] != '\n') { readIndex++; if (readIndex == buf.length) { readIndex = 0; } if (readIndex == writeIndex) { writeIndexReached = true; } } if (!writeIndexReached) { readIndex++; if (readIndex == buf.length) { readIndex = 0; } } } else { throw new IOException("Buffer is full."); } } if (waiting) { monitor.notifyAll(); } } } protected int read() throws IOException { synchronized (monitor) { while (readIndex == writeIndex) { waiting = true; try { if (!closed) { monitor.wait(10000); } if (closed) { return -1; } } catch (InterruptedException e) { // Immediately reasserts the exception by interrupting the caller thread itself Thread.currentThread().interrupt(); IOException ioException = new IOException("read interrupted"); ioException.initCause(e); throw ioException; } } int result = buf[readIndex++]; if (readIndex == buf.length) { readIndex = 0; } return result; } } public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || off >= b.length || (off + len) > b.length) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int first = read(); if (first == -1) { return -1; } b[off] = (byte) (first & 0xff); int count = 1; synchronized (monitor) { for (int i = 1; readIndex != writeIndex && i < len; i++) { b[off + i] = buf[readIndex++]; count++; if (readIndex == buf.length) { readIndex = 0; } } } return count; } protected int available() { synchronized (monitor) { if (writeIndex == readIndex) { return 0; } else if (writeIndex > readIndex) { return writeIndex - readIndex; } else { return buf.length - readIndex + writeIndex; } } } public BufferedPipedInputStream getInputStream() { synchronized (monitor) { if (in == null) { in = new BufferedPipedInputStream(this); } return in; } } @Override public void close() { synchronized (monitor) { closed = true; if (waiting) { monitor.notifyAll(); } } } }