/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.pim;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* InputStream that supports mark() with an infinite lookahead.
*
*/
public class MarkableInputStream extends InputStream {
/** Input stream. */
private final InputStream in;
/** Internal buffered stream. */
private ByteArrayOutputStream baos;
/** Current buffer. */
private byte[] buffer;
/** Current index in buffer. */
private int bufferIndex;
/**
* Constructs a markable input stream.
* @param in input data
*/
public MarkableInputStream(InputStream in) {
this.in = in;
}
/**
* Checks if mark is supported.
* @return <code>true</code> if mark is supported
*/
public boolean markSupported() {
return true;
}
/**
* This implementation of mark() supports infinite lookahead.
*
* @param lookahead The value of this parameter is ignored.
*/
public synchronized void mark(int lookahead) {
baos = new ByteArrayOutputStream();
}
/**
* Reset the line markers.
* @throws IOException if an error occurs accessing the
* input stream
*/
public synchronized void reset() throws IOException {
if (baos == null) {
throw new IOException("Cannot reset an unmarked stream");
}
if (baos.size() == 0) {
// no data was read since the call to mark()
baos = null;
} else {
buffer = baos.toByteArray();
baos = null;
bufferIndex = 0;
}
}
/**
* Closes the input stream.
* @throws IOException if any error occurs
*/
public void close() throws IOException {
in.close();
baos.close();
baos = null;
buffer = null;
}
/**
* Reads a byte from the stream.
* @return next byte from stream
* @throws IOException if an error occurs
*/
public int read() throws IOException {
if (buffer != null &&
bufferIndex < buffer.length) {
return readFromBuffer();
} else {
return readFromStream();
}
}
/**
* Reads a byte from the internal buffer.
* @return next byte from the buffer.
*/
private int readFromBuffer() {
int i = buffer[bufferIndex++];
if (baos != null) {
baos.write(i);
}
if (bufferIndex == buffer.length) {
buffer = null;
}
return i;
}
/**
* Reads next value from the input stream.
* @return next value from stream
* @throws IOException if an error occurs
*/
private int readFromStream() throws IOException {
int i = in.read();
if (i != -1 && baos != null) {
baos.write(i);
}
return i;
}
/**
* Reads next block of bytes from the stream.
* @param b buffer to hold data
* @param offset in buffer for data read
* @param length size of data to read
* @return number of bytes read
* @throws IOException if an error occurs
*/
public int read(byte[] b, int offset, int length) throws IOException {
if (buffer != null) {
return readFromBuffer(b, offset, length);
} else {
return readFromStream(b, offset, length);
}
}
/**
* Reads next block of bytes from the internal buffer.
* @param b buffer to hold data
* @param offset in buffer for data read
* @param length size of data to read
* @return number of bytes read
*/
private int readFromBuffer(byte[] b, int offset, int length) {
int bytesRead = -1;
if (length <= buffer.length - bufferIndex) {
System.arraycopy(buffer, bufferIndex, b, offset, length);
bufferIndex += length;
bytesRead = length;
} else {
int count = buffer.length - bufferIndex;
System.arraycopy(buffer, bufferIndex, b, offset, count);
buffer = null;
bytesRead = count;
}
if (baos != null) {
baos.write(b, offset, bytesRead);
}
return bytesRead;
}
/**
* Reads next block of bytes from the stream.
* @param b buffer to hold data
* @param offset in buffer for data read
* @param length size of data to read
* @return number of bytes read
* @throws IOException if an error occurs
*/
private int readFromStream(byte[] b, int offset, int length)
throws IOException {
int i = in.read(b, offset, length);
if (i != -1 && baos != null) {
baos.write(b, offset, i);
}
return i;
}
/**
* Reads next block of bytes from the stream.
* @param b buffer to hold data
* @return number of bytes read
* @throws IOException if an error occurs
*/
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
}