001: /*
002: * Copyright 1994-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.io;
027:
028: import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
029:
030: /**
031: * A <code>BufferedInputStream</code> adds
032: * functionality to another input stream-namely,
033: * the ability to buffer the input and to
034: * support the <code>mark</code> and <code>reset</code>
035: * methods. When the <code>BufferedInputStream</code>
036: * is created, an internal buffer array is
037: * created. As bytes from the stream are read
038: * or skipped, the internal buffer is refilled
039: * as necessary from the contained input stream,
040: * many bytes at a time. The <code>mark</code>
041: * operation remembers a point in the input
042: * stream and the <code>reset</code> operation
043: * causes all the bytes read since the most
044: * recent <code>mark</code> operation to be
045: * reread before new bytes are taken from
046: * the contained input stream.
047: *
048: * @author Arthur van Hoff
049: * @version 1.63, 05/05/07
050: * @since JDK1.0
051: */
052: public class BufferedInputStream extends FilterInputStream {
053:
054: private static int defaultBufferSize = 8192;
055:
056: /**
057: * The internal buffer array where the data is stored. When necessary,
058: * it may be replaced by another array of
059: * a different size.
060: */
061: protected volatile byte buf[];
062:
063: /**
064: * Atomic updater to provide compareAndSet for buf. This is
065: * necessary because closes can be asynchronous. We use nullness
066: * of buf[] as primary indicator that this stream is closed. (The
067: * "in" field is also nulled out on close.)
068: */
069: private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater
070: .newUpdater(BufferedInputStream.class, byte[].class, "buf");
071:
072: /**
073: * The index one greater than the index of the last valid byte in
074: * the buffer.
075: * This value is always
076: * in the range <code>0</code> through <code>buf.length</code>;
077: * elements <code>buf[0]</code> through <code>buf[count-1]
078: * </code>contain buffered input data obtained
079: * from the underlying input stream.
080: */
081: protected int count;
082:
083: /**
084: * The current position in the buffer. This is the index of the next
085: * character to be read from the <code>buf</code> array.
086: * <p>
087: * This value is always in the range <code>0</code>
088: * through <code>count</code>. If it is less
089: * than <code>count</code>, then <code>buf[pos]</code>
090: * is the next byte to be supplied as input;
091: * if it is equal to <code>count</code>, then
092: * the next <code>read</code> or <code>skip</code>
093: * operation will require more bytes to be
094: * read from the contained input stream.
095: *
096: * @see java.io.BufferedInputStream#buf
097: */
098: protected int pos;
099:
100: /**
101: * The value of the <code>pos</code> field at the time the last
102: * <code>mark</code> method was called.
103: * <p>
104: * This value is always
105: * in the range <code>-1</code> through <code>pos</code>.
106: * If there is no marked position in the input
107: * stream, this field is <code>-1</code>. If
108: * there is a marked position in the input
109: * stream, then <code>buf[markpos]</code>
110: * is the first byte to be supplied as input
111: * after a <code>reset</code> operation. If
112: * <code>markpos</code> is not <code>-1</code>,
113: * then all bytes from positions <code>buf[markpos]</code>
114: * through <code>buf[pos-1]</code> must remain
115: * in the buffer array (though they may be
116: * moved to another place in the buffer array,
117: * with suitable adjustments to the values
118: * of <code>count</code>, <code>pos</code>,
119: * and <code>markpos</code>); they may not
120: * be discarded unless and until the difference
121: * between <code>pos</code> and <code>markpos</code>
122: * exceeds <code>marklimit</code>.
123: *
124: * @see java.io.BufferedInputStream#mark(int)
125: * @see java.io.BufferedInputStream#pos
126: */
127: protected int markpos = -1;
128:
129: /**
130: * The maximum read ahead allowed after a call to the
131: * <code>mark</code> method before subsequent calls to the
132: * <code>reset</code> method fail.
133: * Whenever the difference between <code>pos</code>
134: * and <code>markpos</code> exceeds <code>marklimit</code>,
135: * then the mark may be dropped by setting
136: * <code>markpos</code> to <code>-1</code>.
137: *
138: * @see java.io.BufferedInputStream#mark(int)
139: * @see java.io.BufferedInputStream#reset()
140: */
141: protected int marklimit;
142:
143: /**
144: * Check to make sure that underlying input stream has not been
145: * nulled out due to close; if not return it;
146: */
147: private InputStream getInIfOpen() throws IOException {
148: InputStream input = in;
149: if (input == null)
150: throw new IOException("Stream closed");
151: return input;
152: }
153:
154: /**
155: * Check to make sure that buffer has not been nulled out due to
156: * close; if not return it;
157: */
158: private byte[] getBufIfOpen() throws IOException {
159: byte[] buffer = buf;
160: if (buffer == null)
161: throw new IOException("Stream closed");
162: return buffer;
163: }
164:
165: /**
166: * Creates a <code>BufferedInputStream</code>
167: * and saves its argument, the input stream
168: * <code>in</code>, for later use. An internal
169: * buffer array is created and stored in <code>buf</code>.
170: *
171: * @param in the underlying input stream.
172: */
173: public BufferedInputStream(InputStream in) {
174: this (in, defaultBufferSize);
175: }
176:
177: /**
178: * Creates a <code>BufferedInputStream</code>
179: * with the specified buffer size,
180: * and saves its argument, the input stream
181: * <code>in</code>, for later use. An internal
182: * buffer array of length <code>size</code>
183: * is created and stored in <code>buf</code>.
184: *
185: * @param in the underlying input stream.
186: * @param size the buffer size.
187: * @exception IllegalArgumentException if size <= 0.
188: */
189: public BufferedInputStream(InputStream in, int size) {
190: super (in);
191: if (size <= 0) {
192: throw new IllegalArgumentException("Buffer size <= 0");
193: }
194: buf = new byte[size];
195: }
196:
197: /**
198: * Fills the buffer with more data, taking into account
199: * shuffling and other tricks for dealing with marks.
200: * Assumes that it is being called by a synchronized method.
201: * This method also assumes that all data has already been read in,
202: * hence pos > count.
203: */
204: private void fill() throws IOException {
205: byte[] buffer = getBufIfOpen();
206: if (markpos < 0)
207: pos = 0; /* no mark: throw away the buffer */
208: else if (pos >= buffer.length) /* no room left in buffer */
209: if (markpos > 0) { /* can throw away early part of the buffer */
210: int sz = pos - markpos;
211: System.arraycopy(buffer, markpos, buffer, 0, sz);
212: pos = sz;
213: markpos = 0;
214: } else if (buffer.length >= marklimit) {
215: markpos = -1; /* buffer got too big, invalidate mark */
216: pos = 0; /* drop buffer contents */
217: } else { /* grow buffer */
218: int nsz = pos * 2;
219: if (nsz > marklimit)
220: nsz = marklimit;
221: byte nbuf[] = new byte[nsz];
222: System.arraycopy(buffer, 0, nbuf, 0, pos);
223: if (!bufUpdater.compareAndSet(this , buffer, nbuf)) {
224: // Can't replace buf if there was an async close.
225: // Note: This would need to be changed if fill()
226: // is ever made accessible to multiple threads.
227: // But for now, the only way CAS can fail is via close.
228: // assert buf == null;
229: throw new IOException("Stream closed");
230: }
231: buffer = nbuf;
232: }
233: count = pos;
234: int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
235: if (n > 0)
236: count = n + pos;
237: }
238:
239: /**
240: * See
241: * the general contract of the <code>read</code>
242: * method of <code>InputStream</code>.
243: *
244: * @return the next byte of data, or <code>-1</code> if the end of the
245: * stream is reached.
246: * @exception IOException if this input stream has been closed by
247: * invoking its {@link #close()} method,
248: * or an I/O error occurs.
249: * @see java.io.FilterInputStream#in
250: */
251: public synchronized int read() throws IOException {
252: if (pos >= count) {
253: fill();
254: if (pos >= count)
255: return -1;
256: }
257: return getBufIfOpen()[pos++] & 0xff;
258: }
259:
260: /**
261: * Read characters into a portion of an array, reading from the underlying
262: * stream at most once if necessary.
263: */
264: private int read1(byte[] b, int off, int len) throws IOException {
265: int avail = count - pos;
266: if (avail <= 0) {
267: /* If the requested length is at least as large as the buffer, and
268: if there is no mark/reset activity, do not bother to copy the
269: bytes into the local buffer. In this way buffered streams will
270: cascade harmlessly. */
271: if (len >= getBufIfOpen().length && markpos < 0) {
272: return getInIfOpen().read(b, off, len);
273: }
274: fill();
275: avail = count - pos;
276: if (avail <= 0)
277: return -1;
278: }
279: int cnt = (avail < len) ? avail : len;
280: System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
281: pos += cnt;
282: return cnt;
283: }
284:
285: /**
286: * Reads bytes from this byte-input stream into the specified byte array,
287: * starting at the given offset.
288: *
289: * <p> This method implements the general contract of the corresponding
290: * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
291: * the <code>{@link InputStream}</code> class. As an additional
292: * convenience, it attempts to read as many bytes as possible by repeatedly
293: * invoking the <code>read</code> method of the underlying stream. This
294: * iterated <code>read</code> continues until one of the following
295: * conditions becomes true: <ul>
296: *
297: * <li> The specified number of bytes have been read,
298: *
299: * <li> The <code>read</code> method of the underlying stream returns
300: * <code>-1</code>, indicating end-of-file, or
301: *
302: * <li> The <code>available</code> method of the underlying stream
303: * returns zero, indicating that further input requests would block.
304: *
305: * </ul> If the first <code>read</code> on the underlying stream returns
306: * <code>-1</code> to indicate end-of-file then this method returns
307: * <code>-1</code>. Otherwise this method returns the number of bytes
308: * actually read.
309: *
310: * <p> Subclasses of this class are encouraged, but not required, to
311: * attempt to read as many bytes as possible in the same fashion.
312: *
313: * @param b destination buffer.
314: * @param off offset at which to start storing bytes.
315: * @param len maximum number of bytes to read.
316: * @return the number of bytes read, or <code>-1</code> if the end of
317: * the stream has been reached.
318: * @exception IOException if this input stream has been closed by
319: * invoking its {@link #close()} method,
320: * or an I/O error occurs.
321: */
322: public synchronized int read(byte b[], int off, int len)
323: throws IOException {
324: getBufIfOpen(); // Check for closed stream
325: if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
326: throw new IndexOutOfBoundsException();
327: } else if (len == 0) {
328: return 0;
329: }
330:
331: int n = 0;
332: for (;;) {
333: int nread = read1(b, off + n, len - n);
334: if (nread <= 0)
335: return (n == 0) ? nread : n;
336: n += nread;
337: if (n >= len)
338: return n;
339: // if not closed but no bytes available, return
340: InputStream input = in;
341: if (input != null && input.available() <= 0)
342: return n;
343: }
344: }
345:
346: /**
347: * See the general contract of the <code>skip</code>
348: * method of <code>InputStream</code>.
349: *
350: * @exception IOException if the stream does not support seek,
351: * or if this input stream has been closed by
352: * invoking its {@link #close()} method, or an
353: * I/O error occurs.
354: */
355: public synchronized long skip(long n) throws IOException {
356: getBufIfOpen(); // Check for closed stream
357: if (n <= 0) {
358: return 0;
359: }
360: long avail = count - pos;
361:
362: if (avail <= 0) {
363: // If no mark position set then don't keep in buffer
364: if (markpos < 0)
365: return getInIfOpen().skip(n);
366:
367: // Fill in buffer to save bytes for reset
368: fill();
369: avail = count - pos;
370: if (avail <= 0)
371: return 0;
372: }
373:
374: long skipped = (avail < n) ? avail : n;
375: pos += skipped;
376: return skipped;
377: }
378:
379: /**
380: * Returns an estimate of the number of bytes that can be read (or
381: * skipped over) from this input stream without blocking by the next
382: * invocation of a method for this input stream. The next invocation might be
383: * the same thread or another thread. A single read or skip of this
384: * many bytes will not block, but may read or skip fewer bytes.
385: * <p>
386: * This method returns the sum of the number of bytes remaining to be read in
387: * the buffer (<code>count - pos</code>) and the result of calling the
388: * {@link java.io.FilterInputStream#in in}.available().
389: *
390: * @return an estimate of the number of bytes that can be read (or skipped
391: * over) from this input stream without blocking.
392: * @exception IOException if this input stream has been closed by
393: * invoking its {@link #close()} method,
394: * or an I/O error occurs.
395: */
396: public synchronized int available() throws IOException {
397: return getInIfOpen().available() + (count - pos);
398: }
399:
400: /**
401: * See the general contract of the <code>mark</code>
402: * method of <code>InputStream</code>.
403: *
404: * @param readlimit the maximum limit of bytes that can be read before
405: * the mark position becomes invalid.
406: * @see java.io.BufferedInputStream#reset()
407: */
408: public synchronized void mark(int readlimit) {
409: marklimit = readlimit;
410: markpos = pos;
411: }
412:
413: /**
414: * See the general contract of the <code>reset</code>
415: * method of <code>InputStream</code>.
416: * <p>
417: * If <code>markpos</code> is <code>-1</code>
418: * (no mark has been set or the mark has been
419: * invalidated), an <code>IOException</code>
420: * is thrown. Otherwise, <code>pos</code> is
421: * set equal to <code>markpos</code>.
422: *
423: * @exception IOException if this stream has not been marked or,
424: * if the mark has been invalidated, or the stream
425: * has been closed by invoking its {@link #close()}
426: * method, or an I/O error occurs.
427: * @see java.io.BufferedInputStream#mark(int)
428: */
429: public synchronized void reset() throws IOException {
430: getBufIfOpen(); // Cause exception if closed
431: if (markpos < 0)
432: throw new IOException("Resetting to invalid mark");
433: pos = markpos;
434: }
435:
436: /**
437: * Tests if this input stream supports the <code>mark</code>
438: * and <code>reset</code> methods. The <code>markSupported</code>
439: * method of <code>BufferedInputStream</code> returns
440: * <code>true</code>.
441: *
442: * @return a <code>boolean</code> indicating if this stream type supports
443: * the <code>mark</code> and <code>reset</code> methods.
444: * @see java.io.InputStream#mark(int)
445: * @see java.io.InputStream#reset()
446: */
447: public boolean markSupported() {
448: return true;
449: }
450:
451: /**
452: * Closes this input stream and releases any system resources
453: * associated with the stream.
454: * Once the stream has been closed, further read(), available(), reset(),
455: * or skip() invocations will throw an IOException.
456: * Closing a previously closed stream has no effect.
457: *
458: * @exception IOException if an I/O error occurs.
459: */
460: public void close() throws IOException {
461: byte[] buffer;
462: while ((buffer = buf) != null) {
463: if (bufUpdater.compareAndSet(this , buffer, null)) {
464: InputStream input = in;
465: in = null;
466: if (input != null)
467: input.close();
468: return;
469: }
470: // Else retry in case a new buf was CASed in fill()
471: }
472: }
473: }
|