/* Copyright (C) 1998, 1999 Cygnus Solutions This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.io; /** * @author Warren Levy * @date October 8, 1998. */ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. * Status: Believed complete and correct. */ public class BufferedInputStream extends FilterInputStream { /* Internal buffer array for data. */ protected byte[] buf; /* Index one greater than the last valid byte in the buffer. */ protected int count = 0; /* The current position in the buffer. */ protected int pos = 0; /* The value of pos the last time mark() was called. */ protected int markpos = -1; /* The maximum read-ahead allowed before calls to reset() fail. */ protected int marklimit = 0; public BufferedInputStream(InputStream in) { this(in, 2048); } public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) throw new IllegalArgumentException(); buf = new byte[size]; } public synchronized int available() throws IOException { return count - pos + super.available(); } public void close() throws IOException { // Free up the array memory. buf = null; super.close(); } public synchronized void mark(int readlimit) { marklimit = readlimit; markpos = pos; } public boolean markSupported() { return true; } public synchronized int read() throws IOException { if (pos >= count && !refill()) return -1; // EOF if (markpos >= 0 && pos - markpos > marklimit) markpos = -1; return ((int) buf[pos++]) & 0xFF; } public synchronized int read(byte[] b, int off, int len) throws IOException { if (off < 0 || len < 0 || off + len > b.length) throw new ArrayIndexOutOfBoundsException(); if (pos >= count && !refill()) return -1; // No bytes were read before EOF. int remain = Math.min(count - pos, len); System.arraycopy(buf, pos, b, off, remain); pos += remain; if (markpos >= 0 && pos - markpos > marklimit) markpos = -1; return remain; } public synchronized void reset() throws IOException { if (markpos < 0) throw new IOException(); pos = markpos; } public synchronized long skip(long n) throws IOException { final long origN = n; while (n > 0L) { if (pos >= count && !refill()) if (n < origN) break; else return -1; // No bytes were read before EOF. int numread = (int) Math.min((long) (count - pos), n); pos += numread; n -= numread; if (markpos >= 0 && pos - markpos > marklimit) markpos = -1; } return origN - n; } private boolean refill() throws IOException { if (markpos < 0) count = pos = 0; else if (markpos > 0) { // Shift the marked bytes (if any) to the beginning of the array // but don't grow it. This saves space in case a reset is done // before we reach the max capacity of this array. System.arraycopy(buf, markpos, buf, 0, count - markpos); count -= markpos; pos -= markpos; markpos = 0; } else if (marklimit >= buf.length) // BTW, markpos == 0 { // Need to grow the buffer now to have room for marklimit bytes. // Note that the new buffer is one greater than marklimit. // This is so that there will be one byte past marklimit to be read // before having to call refill again, thus allowing marklimit to be // invalidated. That way refill doesn't have to check marklimit. byte[] newbuf = new byte[marklimit + 1]; System.arraycopy(buf, 0, newbuf, 0, count); buf = newbuf; } int numread = super.read(buf, count, buf.length - count); if (numread < 0) // EOF return false; count += numread; return true; } }