1 /*
  2  * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.io;
 27 
 28 import jdk.internal.misc.Unsafe;
 29 import jdk.internal.util.ArraysSupport;
 30 
 31 /**
 32  * A {@code BufferedInputStream} adds
 33  * functionality to another input stream-namely,
 34  * the ability to buffer the input and to
 35  * support the {@code mark} and {@code reset}
 36  * methods. When  the {@code BufferedInputStream}
 37  * is created, an internal buffer array is
 38  * created. As bytes  from the stream are read
 39  * or skipped, the internal buffer is refilled
 40  * as necessary  from the contained input stream,
 41  * many bytes at a time. The {@code mark}
 42  * operation  remembers a point in the input
 43  * stream and the {@code reset} operation
 44  * causes all the  bytes read since the most
 45  * recent {@code mark} operation to be
 46  * reread before new bytes are  taken from
 47  * the contained input stream.
 48  *
 49  * @author  Arthur van Hoff
 50  * @since   1.0
 51  */
 52 public class BufferedInputStream extends FilterInputStream {
 53 
 54     private static int DEFAULT_BUFFER_SIZE = 8192;
 55 
 56     /**
 57      * As this class is used early during bootstrap, it's motivated to use
 58      * Unsafe.compareAndSetObject instead of AtomicReferenceFieldUpdater
 59      * (or VarHandles) to reduce dependencies and improve startup time.
 60      */
 61     private static final Unsafe U = Unsafe.getUnsafe();
 62 
 63     private static final long BUF_OFFSET
 64             = U.objectFieldOffset(BufferedInputStream.class, "buf");
 65 
 66     /**
 67      * The internal buffer array where the data is stored. When necessary,
 68      * it may be replaced by another array of
 69      * a different size.
 70      */
 71     /*
 72      * We null this out with a CAS on close(), which is necessary since
 73      * closes can be asynchronous. We use nullness of buf[] as primary
 74      * indicator that this stream is closed. (The "in" field is also
 75      * nulled out on close.)
 76      */
 77     protected volatile byte[] buf;
 78 
 79     /**
 80      * The index one greater than the index of the last valid byte in
 81      * the buffer.
 82      * This value is always
 83      * in the range {@code 0} through {@code buf.length};
 84      * elements {@code buf[0]} through {@code buf[count-1]}
 85      * contain buffered input data obtained
 86      * from the underlying  input stream.
 87      */
 88     protected int count;
 89 
 90     /**
 91      * The current position in the buffer. This is the index of the next
 92      * character to be read from the {@code buf} array.
 93      * <p>
 94      * This value is always in the range {@code 0}
 95      * through {@code count}. If it is less
 96      * than {@code count}, then  {@code buf[pos]}
 97      * is the next byte to be supplied as input;
 98      * if it is equal to {@code count}, then
 99      * the  next {@code read} or {@code skip}
100      * operation will require more bytes to be
101      * read from the contained  input stream.
102      *
103      * @see     java.io.BufferedInputStream#buf
104      */
105     protected int pos;
106 
107     /**
108      * The value of the {@code pos} field at the time the last
109      * {@code mark} method was called.
110      * <p>
111      * This value is always
112      * in the range {@code -1} through {@code pos}.
113      * If there is no marked position in  the input
114      * stream, this field is {@code -1}. If
115      * there is a marked position in the input
116      * stream,  then {@code buf[markpos]}
117      * is the first byte to be supplied as input
118      * after a {@code reset} operation. If
119      * {@code markpos} is not {@code -1},
120      * then all bytes from positions {@code buf[markpos]}
121      * through  {@code buf[pos-1]} must remain
122      * in the buffer array (though they may be
123      * moved to  another place in the buffer array,
124      * with suitable adjustments to the values
125      * of {@code count},  {@code pos},
126      * and {@code markpos}); they may not
127      * be discarded unless and until the difference
128      * between {@code pos} and {@code markpos}
129      * exceeds {@code marklimit}.
130      *
131      * @see     java.io.BufferedInputStream#mark(int)
132      * @see     java.io.BufferedInputStream#pos
133      */
134     protected int markpos = -1;
135 
136     /**
137      * The maximum read ahead allowed after a call to the
138      * {@code mark} method before subsequent calls to the
139      * {@code reset} method fail.
140      * Whenever the difference between {@code pos}
141      * and {@code markpos} exceeds {@code marklimit},
142      * then the  mark may be dropped by setting
143      * {@code markpos} to {@code -1}.
144      *
145      * @see     java.io.BufferedInputStream#mark(int)
146      * @see     java.io.BufferedInputStream#reset()
147      */
148     protected int marklimit;
149 
150     /**
151      * Check to make sure that underlying input stream has not been
152      * nulled out due to close; if not return it;
153      */
154     private InputStream getInIfOpen() throws IOException {
155         InputStream input = in;
156         if (input == null)
157             throw new IOException("Stream closed");
158         return input;
159     }
160 
161     /**
162      * Check to make sure that buffer has not been nulled out due to
163      * close; if not return it;
164      */
165     private byte[] getBufIfOpen() throws IOException {
166         byte[] buffer = buf;
167         if (buffer == null)
168             throw new IOException("Stream closed");
169         return buffer;
170     }
171 
172     /**
173      * Creates a {@code BufferedInputStream}
174      * and saves its  argument, the input stream
175      * {@code in}, for later use. An internal
176      * buffer array is created and  stored in {@code buf}.
177      *
178      * @param   in   the underlying input stream.
179      */
180     public BufferedInputStream(InputStream in) {
181         this(in, DEFAULT_BUFFER_SIZE);
182     }
183 
184     /**
185      * Creates a {@code BufferedInputStream}
186      * with the specified buffer size,
187      * and saves its  argument, the input stream
188      * {@code in}, for later use.  An internal
189      * buffer array of length  {@code size}
190      * is created and stored in {@code buf}.
191      *
192      * @param   in     the underlying input stream.
193      * @param   size   the buffer size.
194      * @throws  IllegalArgumentException if {@code size <= 0}.
195      */
196     public BufferedInputStream(InputStream in, int size) {
197         super(in);
198         if (size <= 0) {
199             throw new IllegalArgumentException("Buffer size <= 0");
200         }
201         buf = new byte[size];
202     }
203 
204     /**
205      * Fills the buffer with more data, taking into account
206      * shuffling and other tricks for dealing with marks.
207      * Assumes that it is being called by a synchronized method.
208      * This method also assumes that all data has already been read in,
209      * hence pos > count.
210      */
211     private void fill() throws IOException {
212         byte[] buffer = getBufIfOpen();
213         if (markpos < 0)
214             pos = 0;            /* no mark: throw away the buffer */
215         else if (pos >= buffer.length) { /* no room left in buffer */
216             if (markpos > 0) {  /* can throw away early part of the buffer */
217                 int sz = pos - markpos;
218                 System.arraycopy(buffer, markpos, buffer, 0, sz);
219                 pos = sz;
220                 markpos = 0;
221             } else if (buffer.length >= marklimit) {
222                 markpos = -1;   /* buffer got too big, invalidate mark */
223                 pos = 0;        /* drop buffer contents */
224             } else {            /* grow buffer */
225                 int nsz = ArraysSupport.newLength(pos,
226                         1,  /* minimum growth */
227                         pos /* preferred growth */);
228                 if (nsz > marklimit)
229                     nsz = marklimit;
230                 byte[] nbuf = new byte[nsz];
231                 System.arraycopy(buffer, 0, nbuf, 0, pos);
232                 if (!U.compareAndSetReference(this, BUF_OFFSET, buffer, nbuf)) {
233                     // Can't replace buf if there was an async close.
234                     // Note: This would need to be changed if fill()
235                     // is ever made accessible to multiple threads.
236                     // But for now, the only way CAS can fail is via close.
237                     // assert buf == null;
238                     throw new IOException("Stream closed");
239                 }
240                 buffer = nbuf;
241             }
242         }
243         count = pos;
244         int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
245         if (n > 0)
246             count = n + pos;
247     }
248 
249     /**
250      * See
251      * the general contract of the {@code read}
252      * method of {@code InputStream}.
253      *
254      * @return     the next byte of data, or {@code -1} if the end of the
255      *             stream is reached.
256      * @throws     IOException  if this input stream has been closed by
257      *                          invoking its {@link #close()} method,
258      *                          or an I/O error occurs.
259      * @see        java.io.FilterInputStream#in
260      */
261     public synchronized int read() throws IOException {
262         if (pos >= count) {
263             fill();
264             if (pos >= count)
265                 return -1;
266         }
267         return getBufIfOpen()[pos++] & 0xff;
268     }
269 
270     /**
271      * Read characters into a portion of an array, reading from the underlying
272      * stream at most once if necessary.
273      */
274     private int read1(byte[] b, int off, int len) throws IOException {
275         int avail = count - pos;
276         if (avail <= 0) {
277             /* If the requested length is at least as large as the buffer, and
278                if there is no mark/reset activity, do not bother to copy the
279                bytes into the local buffer.  In this way buffered streams will
280                cascade harmlessly. */
281             if (len >= getBufIfOpen().length && markpos < 0) {
282                 return getInIfOpen().read(b, off, len);
283             }
284             fill();
285             avail = count - pos;
286             if (avail <= 0) return -1;
287         }
288         int cnt = (avail < len) ? avail : len;
289         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
290         pos += cnt;
291         return cnt;
292     }
293 
294     /**
295      * Reads bytes from this byte-input stream into the specified byte array,
296      * starting at the given offset.
297      *
298      * <p> This method implements the general contract of the corresponding
299      * {@link InputStream#read(byte[], int, int) read} method of
300      * the {@link InputStream} class.  As an additional
301      * convenience, it attempts to read as many bytes as possible by repeatedly
302      * invoking the {@code read} method of the underlying stream.  This
303      * iterated {@code read} continues until one of the following
304      * conditions becomes true: <ul>
305      *
306      *   <li> The specified number of bytes have been read,
307      *
308      *   <li> The {@code read} method of the underlying stream returns
309      *   {@code -1}, indicating end-of-file, or
310      *
311      *   <li> The {@code available} method of the underlying stream
312      *   returns zero, indicating that further input requests would block.
313      *
314      * </ul> If the first {@code read} on the underlying stream returns
315      * {@code -1} to indicate end-of-file then this method returns
316      * {@code -1}.  Otherwise this method returns the number of bytes
317      * actually read.
318      *
319      * <p> Subclasses of this class are encouraged, but not required, to
320      * attempt to read as many bytes as possible in the same fashion.
321      *
322      * @param      b     destination buffer.
323      * @param      off   offset at which to start storing bytes.
324      * @param      len   maximum number of bytes to read.
325      * @return     the number of bytes read, or {@code -1} if the end of
326      *             the stream has been reached.
327      * @throws     IOException  if this input stream has been closed by
328      *                          invoking its {@link #close()} method,
329      *                          or an I/O error occurs.
330      */
331     public synchronized int read(byte[] b, int off, int len)
332         throws IOException
333     {
334         getBufIfOpen(); // Check for closed stream
335         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
336             throw new IndexOutOfBoundsException();
337         } else if (len == 0) {
338             return 0;
339         }
340 
341         int n = 0;
342         for (;;) {
343             int nread = read1(b, off + n, len - n);
344             if (nread <= 0)
345                 return (n == 0) ? nread : n;
346             n += nread;
347             if (n >= len)
348                 return n;
349             // if not closed but no bytes available, return
350             InputStream input = in;
351             if (input != null && input.available() <= 0)
352                 return n;
353         }
354     }
355 
356     /**
357      * See the general contract of the {@code skip}
358      * method of {@code InputStream}.
359      *
360      * @throws IOException  if this input stream has been closed by
361      *                      invoking its {@link #close()} method,
362      *                      {@code in.skip(n)} throws an IOException,
363      *                      or an I/O error occurs.
364      */
365     public synchronized long skip(long n) throws IOException {
366         getBufIfOpen(); // Check for closed stream
367         if (n <= 0) {
368             return 0;
369         }
370         long avail = count - pos;
371 
372         if (avail <= 0) {
373             // If no mark position set then don't keep in buffer
374             if (markpos <0)
375                 return getInIfOpen().skip(n);
376 
377             // Fill in buffer to save bytes for reset
378             fill();
379             avail = count - pos;
380             if (avail <= 0)
381                 return 0;
382         }
383 
384         long skipped = (avail < n) ? avail : n;
385         pos += skipped;
386         return skipped;
387     }
388 
389     /**
390      * Returns an estimate of the number of bytes that can be read (or
391      * skipped over) from this input stream without blocking by the next
392      * invocation of a method for this input stream. The next invocation might be
393      * the same thread or another thread.  A single read or skip of this
394      * many bytes will not block, but may read or skip fewer bytes.
395      * <p>
396      * This method returns the sum of the number of bytes remaining to be read in
397      * the buffer ({@code count - pos}) and the result of calling the
398      * {@link java.io.FilterInputStream#in in}{@code .available()}.
399      *
400      * @return     an estimate of the number of bytes that can be read (or skipped
401      *             over) from this input stream without blocking.
402      * @throws     IOException  if this input stream has been closed by
403      *                          invoking its {@link #close()} method,
404      *                          or an I/O error occurs.
405      */
406     public synchronized int available() throws IOException {
407         int n = count - pos;
408         int avail = getInIfOpen().available();
409         return n > (Integer.MAX_VALUE - avail)
410                     ? Integer.MAX_VALUE
411                     : n + avail;
412     }
413 
414     /**
415      * See the general contract of the {@code mark}
416      * method of {@code InputStream}.
417      *
418      * @param   readlimit   the maximum limit of bytes that can be read before
419      *                      the mark position becomes invalid.
420      * @see     java.io.BufferedInputStream#reset()
421      */
422     public synchronized void mark(int readlimit) {
423         marklimit = readlimit;
424         markpos = pos;
425     }
426 
427     /**
428      * See the general contract of the {@code reset}
429      * method of {@code InputStream}.
430      * <p>
431      * If {@code markpos} is {@code -1}
432      * (no mark has been set or the mark has been
433      * invalidated), an {@code IOException}
434      * is thrown. Otherwise, {@code pos} is
435      * set equal to {@code markpos}.
436      *
437      * @throws     IOException  if this stream has not been marked or,
438      *                  if the mark has been invalidated, or the stream
439      *                  has been closed by invoking its {@link #close()}
440      *                  method, or an I/O error occurs.
441      * @see        java.io.BufferedInputStream#mark(int)
442      */
443     public synchronized void reset() throws IOException {
444         getBufIfOpen(); // Cause exception if closed
445         if (markpos < 0)
446             throw new IOException("Resetting to invalid mark");
447         pos = markpos;
448     }
449 
450     /**
451      * Tests if this input stream supports the {@code mark}
452      * and {@code reset} methods. The {@code markSupported}
453      * method of {@code BufferedInputStream} returns
454      * {@code true}.
455      *
456      * @return  a {@code boolean} indicating if this stream type supports
457      *          the {@code mark} and {@code reset} methods.
458      * @see     java.io.InputStream#mark(int)
459      * @see     java.io.InputStream#reset()
460      */
461     public boolean markSupported() {
462         return true;
463     }
464 
465     /**
466      * Closes this input stream and releases any system resources
467      * associated with the stream.
468      * Once the stream has been closed, further read(), available(), reset(),
469      * or skip() invocations will throw an IOException.
470      * Closing a previously closed stream has no effect.
471      *
472      * @throws     IOException  if an I/O error occurs.
473      */
474     public void close() throws IOException {
475         byte[] buffer;
476         while ( (buffer = buf) != null) {
477             if (U.compareAndSetReference(this, BUF_OFFSET, buffer, null)) {
478                 InputStream input = in;
479                 in = null;
480                 if (input != null)
481                     input.close();
482                 return;
483             }
484             // Else retry in case a new buf was CASed in fill()
485         }
486     }
487 }