--- /home/tromey/gnu/Nightly/classpath/classpath/java/io/BufferedInputStream.java 2004-07-10 02:22:14.000000000 -0600 +++ java/io/BufferedInputStream.java 2004-11-23 02:16:21.000000000 -0700 @@ -1,5 +1,5 @@ /* BufferedInputStream.java -- An input stream that implements buffering - Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -60,12 +60,11 @@ * does. * * @author Aaron M. Renn (arenn@urbanophile.com) - * @author Warren Levy - * @author Jeroen Frijters + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeroen Frijters (jeroen@frijters.net) */ public class BufferedInputStream extends FilterInputStream { - /** * This is the default buffer size */ @@ -104,11 +103,17 @@ protected int marklimit; /** - * This is the initial buffer size. When the buffer is grown because - * of marking requirements, it will be grown by bufferSize increments. - * The underlying stream will be read in chunks of bufferSize. + * This is the maximum size we have to allocate for the mark buffer. + * This number may be huge (Integer.MAX_VALUE). The class will continue + * to allocate new chunks (specified by CHUNKSIZE) until the + * the size specified by this field is achieved. + */ + private int marktarget = 0; + + /** + * This is the number of bytes to allocate to reach marktarget. */ - private final int bufferSize; + static final private int CHUNKSIZE = 1024; /** * This method initializes a new BufferedInputStream that will @@ -138,9 +143,6 @@ if (size <= 0) throw new IllegalArgumentException(); buf = new byte[size]; - // initialize pos & count to bufferSize, to prevent refill from - // allocating a new buffer (if the caller starts out by calling mark()). - pos = count = bufferSize = size; } /** @@ -171,8 +173,6 @@ { // Free up the array memory. buf = null; - pos = count = 0; - markpos = -1; super.close(); } @@ -196,7 +196,9 @@ */ public synchronized void mark(int readlimit) { - marklimit = readlimit; + marktarget = marklimit = readlimit; + if (marklimit > CHUNKSIZE) + marklimit = CHUNKSIZE; markpos = pos; } @@ -229,6 +231,9 @@ if (pos >= count && !refill()) return -1; // EOF + if (markpos >= 0 && pos - markpos > marktarget) + markpos = -1; + return buf[pos++] & 0xFF; } @@ -236,10 +241,7 @@ * This method reads bytes from a stream and stores them into a caller * supplied buffer. It starts storing the data at index off * into the buffer and attempts to read len bytes. This method - * can return before reading the number of bytes requested, but it will try - * to read the requested number of bytes by repeatedly calling the underlying - * stream as long as available() for this stream continues to return a - * non-zero value (or until the requested number of bytes have been read). + * can return before reading the number of bytes requested. * The actual number of bytes read is returned as an int. A -1 is returned * to indicate the end of the stream. *

@@ -267,18 +269,9 @@ int totalBytesRead = Math.min(count - pos, len); System.arraycopy(buf, pos, b, off, totalBytesRead); pos += totalBytesRead; - off += totalBytesRead; - len -= totalBytesRead; - while (len > 0 && super.available() > 0 && refill()) - { - int remain = Math.min(count - pos, len); - System.arraycopy(buf, pos, b, off, remain); - pos += remain; - off += remain; - len -= remain; - totalBytesRead += remain; - } + if (markpos >= 0 && pos - markpos > marktarget) + markpos = -1; return totalBytesRead; } @@ -328,11 +321,14 @@ if (n < origN) break; else - return -1; // No bytes were read before EOF. + return 0; // No bytes were read before EOF. int numread = (int) Math.min((long) (count - pos), n); pos += numread; n -= numread; + + if (markpos >= 0 && pos - markpos > marktarget) + markpos = -1; } return origN - n; @@ -344,34 +340,42 @@ * @return true when at least one additional byte was read * into buf, false otherwise (at EOF). */ - private boolean refill() throws IOException + boolean refill() throws IOException { if (buf == null) throw new IOException("Stream closed."); - if (markpos == -1 || count - markpos >= marklimit) - { - markpos = -1; - pos = count = 0; - } - else + if (markpos < 0) + count = pos = 0; + else if (markpos > 0) { - byte[] newbuf = buf; - if (markpos < bufferSize) - { - newbuf = new byte[count - markpos + bufferSize]; - } - System.arraycopy(buf, markpos, newbuf, 0, count - markpos); - buf = newbuf; + // 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 (marktarget >= buf.length && marklimit < marktarget) // 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. + marklimit += CHUNKSIZE; + if (marklimit >= marktarget) + marklimit = marktarget; + byte[] newbuf = new byte[marklimit + 1]; + System.arraycopy(buf, 0, newbuf, 0, count); + buf = newbuf; + } - int numread = super.read(buf, count, bufferSize); + int numread = super.read(buf, count, buf.length - count); - if (numread <= 0) // EOF - return false; + if (numread < 0) // EOF + return false; count += numread; return true;