Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/io/BufferedInputStream.java
38829 views
/*1* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;26import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;2728/**29* A <code>BufferedInputStream</code> adds30* functionality to another input stream-namely,31* the ability to buffer the input and to32* support the <code>mark</code> and <code>reset</code>33* methods. When the <code>BufferedInputStream</code>34* is created, an internal buffer array is35* created. As bytes from the stream are read36* or skipped, the internal buffer is refilled37* as necessary from the contained input stream,38* many bytes at a time. The <code>mark</code>39* operation remembers a point in the input40* stream and the <code>reset</code> operation41* causes all the bytes read since the most42* recent <code>mark</code> operation to be43* reread before new bytes are taken from44* the contained input stream.45*46* @author Arthur van Hoff47* @since JDK1.048*/49public50class BufferedInputStream extends FilterInputStream {5152private static int DEFAULT_BUFFER_SIZE = 8192;5354/**55* The maximum size of array to allocate.56* Some VMs reserve some header words in an array.57* Attempts to allocate larger arrays may result in58* OutOfMemoryError: Requested array size exceeds VM limit59*/60private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;6162/**63* The internal buffer array where the data is stored. When necessary,64* it may be replaced by another array of65* a different size.66*/67protected volatile byte buf[];6869/**70* Atomic updater to provide compareAndSet for buf. This is71* necessary because closes can be asynchronous. We use nullness72* of buf[] as primary indicator that this stream is closed. (The73* "in" field is also nulled out on close.)74*/75private static final76AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =77AtomicReferenceFieldUpdater.newUpdater78(BufferedInputStream.class, byte[].class, "buf");7980/**81* The index one greater than the index of the last valid byte in82* the buffer.83* This value is always84* in the range <code>0</code> through <code>buf.length</code>;85* elements <code>buf[0]</code> through <code>buf[count-1]86* </code>contain buffered input data obtained87* from the underlying input stream.88*/89protected int count;9091/**92* The current position in the buffer. This is the index of the next93* character to be read from the <code>buf</code> array.94* <p>95* This value is always in the range <code>0</code>96* through <code>count</code>. If it is less97* than <code>count</code>, then <code>buf[pos]</code>98* is the next byte to be supplied as input;99* if it is equal to <code>count</code>, then100* the next <code>read</code> or <code>skip</code>101* operation will require more bytes to be102* read from the contained input stream.103*104* @see java.io.BufferedInputStream#buf105*/106protected int pos;107108/**109* The value of the <code>pos</code> field at the time the last110* <code>mark</code> method was called.111* <p>112* This value is always113* in the range <code>-1</code> through <code>pos</code>.114* If there is no marked position in the input115* stream, this field is <code>-1</code>. If116* there is a marked position in the input117* stream, then <code>buf[markpos]</code>118* is the first byte to be supplied as input119* after a <code>reset</code> operation. If120* <code>markpos</code> is not <code>-1</code>,121* then all bytes from positions <code>buf[markpos]</code>122* through <code>buf[pos-1]</code> must remain123* in the buffer array (though they may be124* moved to another place in the buffer array,125* with suitable adjustments to the values126* of <code>count</code>, <code>pos</code>,127* and <code>markpos</code>); they may not128* be discarded unless and until the difference129* between <code>pos</code> and <code>markpos</code>130* exceeds <code>marklimit</code>.131*132* @see java.io.BufferedInputStream#mark(int)133* @see java.io.BufferedInputStream#pos134*/135protected int markpos = -1;136137/**138* The maximum read ahead allowed after a call to the139* <code>mark</code> method before subsequent calls to the140* <code>reset</code> method fail.141* Whenever the difference between <code>pos</code>142* and <code>markpos</code> exceeds <code>marklimit</code>,143* then the mark may be dropped by setting144* <code>markpos</code> to <code>-1</code>.145*146* @see java.io.BufferedInputStream#mark(int)147* @see java.io.BufferedInputStream#reset()148*/149protected int marklimit;150151/**152* Check to make sure that underlying input stream has not been153* nulled out due to close; if not return it;154*/155private InputStream getInIfOpen() throws IOException {156InputStream input = in;157if (input == null)158throw new IOException("Stream closed");159return input;160}161162/**163* Check to make sure that buffer has not been nulled out due to164* close; if not return it;165*/166private byte[] getBufIfOpen() throws IOException {167byte[] buffer = buf;168if (buffer == null)169throw new IOException("Stream closed");170return buffer;171}172173/**174* Creates a <code>BufferedInputStream</code>175* and saves its argument, the input stream176* <code>in</code>, for later use. An internal177* buffer array is created and stored in <code>buf</code>.178*179* @param in the underlying input stream.180*/181public BufferedInputStream(InputStream in) {182this(in, DEFAULT_BUFFER_SIZE);183}184185/**186* Creates a <code>BufferedInputStream</code>187* with the specified buffer size,188* and saves its argument, the input stream189* <code>in</code>, for later use. An internal190* buffer array of length <code>size</code>191* is created and stored in <code>buf</code>.192*193* @param in the underlying input stream.194* @param size the buffer size.195* @exception IllegalArgumentException if {@code size <= 0}.196*/197public BufferedInputStream(InputStream in, int size) {198super(in);199if (size <= 0) {200throw new IllegalArgumentException("Buffer size <= 0");201}202buf = new byte[size];203}204205/**206* Fills the buffer with more data, taking into account207* shuffling and other tricks for dealing with marks.208* Assumes that it is being called by a synchronized method.209* This method also assumes that all data has already been read in,210* hence pos > count.211*/212private void fill() throws IOException {213byte[] buffer = getBufIfOpen();214if (markpos < 0)215pos = 0; /* no mark: throw away the buffer */216else if (pos >= buffer.length) /* no room left in buffer */217if (markpos > 0) { /* can throw away early part of the buffer */218int sz = pos - markpos;219System.arraycopy(buffer, markpos, buffer, 0, sz);220pos = sz;221markpos = 0;222} else if (buffer.length >= marklimit) {223markpos = -1; /* buffer got too big, invalidate mark */224pos = 0; /* drop buffer contents */225} else if (buffer.length >= MAX_BUFFER_SIZE) {226throw new OutOfMemoryError("Required array size too large");227} else { /* grow buffer */228int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?229pos * 2 : MAX_BUFFER_SIZE;230if (nsz > marklimit)231nsz = marklimit;232byte nbuf[] = new byte[nsz];233System.arraycopy(buffer, 0, nbuf, 0, pos);234if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {235// Can't replace buf if there was an async close.236// Note: This would need to be changed if fill()237// is ever made accessible to multiple threads.238// But for now, the only way CAS can fail is via close.239// assert buf == null;240throw new IOException("Stream closed");241}242buffer = nbuf;243}244count = pos;245int n = getInIfOpen().read(buffer, pos, buffer.length - pos);246if (n > 0)247count = n + pos;248}249250/**251* See252* the general contract of the <code>read</code>253* method of <code>InputStream</code>.254*255* @return the next byte of data, or <code>-1</code> if the end of the256* stream is reached.257* @exception IOException if this input stream has been closed by258* invoking its {@link #close()} method,259* or an I/O error occurs.260* @see java.io.FilterInputStream#in261*/262public synchronized int read() throws IOException {263if (pos >= count) {264fill();265if (pos >= count)266return -1;267}268return getBufIfOpen()[pos++] & 0xff;269}270271/**272* Read characters into a portion of an array, reading from the underlying273* stream at most once if necessary.274*/275private int read1(byte[] b, int off, int len) throws IOException {276int avail = count - pos;277if (avail <= 0) {278/* If the requested length is at least as large as the buffer, and279if there is no mark/reset activity, do not bother to copy the280bytes into the local buffer. In this way buffered streams will281cascade harmlessly. */282if (len >= getBufIfOpen().length && markpos < 0) {283return getInIfOpen().read(b, off, len);284}285fill();286avail = count - pos;287if (avail <= 0) return -1;288}289int cnt = (avail < len) ? avail : len;290System.arraycopy(getBufIfOpen(), pos, b, off, cnt);291pos += cnt;292return cnt;293}294295/**296* Reads bytes from this byte-input stream into the specified byte array,297* starting at the given offset.298*299* <p> This method implements the general contract of the corresponding300* <code>{@link InputStream#read(byte[], int, int) read}</code> method of301* the <code>{@link InputStream}</code> class. As an additional302* convenience, it attempts to read as many bytes as possible by repeatedly303* invoking the <code>read</code> method of the underlying stream. This304* iterated <code>read</code> continues until one of the following305* conditions becomes true: <ul>306*307* <li> The specified number of bytes have been read,308*309* <li> The <code>read</code> method of the underlying stream returns310* <code>-1</code>, indicating end-of-file, or311*312* <li> The <code>available</code> method of the underlying stream313* returns zero, indicating that further input requests would block.314*315* </ul> If the first <code>read</code> on the underlying stream returns316* <code>-1</code> to indicate end-of-file then this method returns317* <code>-1</code>. Otherwise this method returns the number of bytes318* actually read.319*320* <p> Subclasses of this class are encouraged, but not required, to321* attempt to read as many bytes as possible in the same fashion.322*323* @param b destination buffer.324* @param off offset at which to start storing bytes.325* @param len maximum number of bytes to read.326* @return the number of bytes read, or <code>-1</code> if the end of327* the stream has been reached.328* @exception IOException if this input stream has been closed by329* invoking its {@link #close()} method,330* or an I/O error occurs.331*/332public synchronized int read(byte b[], int off, int len)333throws IOException334{335getBufIfOpen(); // Check for closed stream336if ((off | len | (off + len) | (b.length - (off + len))) < 0) {337throw new IndexOutOfBoundsException();338} else if (len == 0) {339return 0;340}341342int n = 0;343for (;;) {344int nread = read1(b, off + n, len - n);345if (nread <= 0)346return (n == 0) ? nread : n;347n += nread;348if (n >= len)349return n;350// if not closed but no bytes available, return351InputStream input = in;352if (input != null && input.available() <= 0)353return n;354}355}356357/**358* See the general contract of the <code>skip</code>359* method of <code>InputStream</code>.360*361* @exception IOException if the stream does not support seek,362* or if this input stream has been closed by363* invoking its {@link #close()} method, or an364* I/O error occurs.365*/366public synchronized long skip(long n) throws IOException {367getBufIfOpen(); // Check for closed stream368if (n <= 0) {369return 0;370}371long avail = count - pos;372373if (avail <= 0) {374// If no mark position set then don't keep in buffer375if (markpos <0)376return getInIfOpen().skip(n);377378// Fill in buffer to save bytes for reset379fill();380avail = count - pos;381if (avail <= 0)382return 0;383}384385long skipped = (avail < n) ? avail : n;386pos += skipped;387return skipped;388}389390/**391* Returns an estimate of the number of bytes that can be read (or392* skipped over) from this input stream without blocking by the next393* invocation of a method for this input stream. The next invocation might be394* the same thread or another thread. A single read or skip of this395* many bytes will not block, but may read or skip fewer bytes.396* <p>397* This method returns the sum of the number of bytes remaining to be read in398* the buffer (<code>count - pos</code>) and the result of calling the399* {@link java.io.FilterInputStream#in in}.available().400*401* @return an estimate of the number of bytes that can be read (or skipped402* over) from this input stream without blocking.403* @exception IOException if this input stream has been closed by404* invoking its {@link #close()} method,405* or an I/O error occurs.406*/407public synchronized int available() throws IOException {408int n = count - pos;409int avail = getInIfOpen().available();410return n > (Integer.MAX_VALUE - avail)411? Integer.MAX_VALUE412: n + avail;413}414415/**416* See the general contract of the <code>mark</code>417* method of <code>InputStream</code>.418*419* @param readlimit the maximum limit of bytes that can be read before420* the mark position becomes invalid.421* @see java.io.BufferedInputStream#reset()422*/423public synchronized void mark(int readlimit) {424marklimit = readlimit;425markpos = pos;426}427428/**429* See the general contract of the <code>reset</code>430* method of <code>InputStream</code>.431* <p>432* If <code>markpos</code> is <code>-1</code>433* (no mark has been set or the mark has been434* invalidated), an <code>IOException</code>435* is thrown. Otherwise, <code>pos</code> is436* set equal to <code>markpos</code>.437*438* @exception IOException if this stream has not been marked or,439* if the mark has been invalidated, or the stream440* has been closed by invoking its {@link #close()}441* method, or an I/O error occurs.442* @see java.io.BufferedInputStream#mark(int)443*/444public synchronized void reset() throws IOException {445getBufIfOpen(); // Cause exception if closed446if (markpos < 0)447throw new IOException("Resetting to invalid mark");448pos = markpos;449}450451/**452* Tests if this input stream supports the <code>mark</code>453* and <code>reset</code> methods. The <code>markSupported</code>454* method of <code>BufferedInputStream</code> returns455* <code>true</code>.456*457* @return a <code>boolean</code> indicating if this stream type supports458* the <code>mark</code> and <code>reset</code> methods.459* @see java.io.InputStream#mark(int)460* @see java.io.InputStream#reset()461*/462public boolean markSupported() {463return true;464}465466/**467* Closes this input stream and releases any system resources468* associated with the stream.469* Once the stream has been closed, further read(), available(), reset(),470* or skip() invocations will throw an IOException.471* Closing a previously closed stream has no effect.472*473* @exception IOException if an I/O error occurs.474*/475public void close() throws IOException {476byte[] buffer;477while ( (buffer = buf) != null) {478if (bufUpdater.compareAndSet(this, buffer, null)) {479InputStream input = in;480in = null;481if (input != null)482input.close();483return;484}485// Else retry in case a new buf was CASed in fill()486}487}488}489490491