emul/src/main/java/java/io/PushbackInputStream.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 10 Nov 2012 19:01:28 +0100
branchjavap
changeset 149 32653a09f0db
parent 147 b20ead86892f
permissions -rw-r--r--
Compiling javap against the emul package. Still need impl for our copy of Hashtable and Vector
     1 /*
     2  * Copyright (c) 1994, 2011, 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 /**
    29  * A <code>PushbackInputStream</code> adds
    30  * functionality to another input stream, namely
    31  * the  ability to "push back" or "unread"
    32  * one byte. This is useful in situations where
    33  * it is  convenient for a fragment of code
    34  * to read an indefinite number of data bytes
    35  * that  are delimited by a particular byte
    36  * value; after reading the terminating byte,
    37  * the  code fragment can "unread" it, so that
    38  * the next read operation on the input stream
    39  * will reread the byte that was pushed back.
    40  * For example, bytes representing the  characters
    41  * constituting an identifier might be terminated
    42  * by a byte representing an  operator character;
    43  * a method whose job is to read just an identifier
    44  * can read until it  sees the operator and
    45  * then push the operator back to be re-read.
    46  *
    47  * @author  David Connelly
    48  * @author  Jonathan Payne
    49  * @since   JDK1.0
    50  */
    51 public
    52 class PushbackInputStream extends FilterInputStream {
    53     /**
    54      * The pushback buffer.
    55      * @since   JDK1.1
    56      */
    57     protected byte[] buf;
    58 
    59     /**
    60      * The position within the pushback buffer from which the next byte will
    61      * be read.  When the buffer is empty, <code>pos</code> is equal to
    62      * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
    63      * equal to zero.
    64      *
    65      * @since   JDK1.1
    66      */
    67     protected int pos;
    68 
    69     /**
    70      * Check to make sure that this stream has not been closed
    71      */
    72     private void ensureOpen() throws IOException {
    73         if (in == null)
    74             throw new IOException("Stream closed");
    75     }
    76 
    77     /**
    78      * Creates a <code>PushbackInputStream</code>
    79      * with a pushback buffer of the specified <code>size</code>,
    80      * and saves its  argument, the input stream
    81      * <code>in</code>, for later use. Initially,
    82      * there is no pushed-back byte  (the field
    83      * <code>pushBack</code> is initialized to
    84      * <code>-1</code>).
    85      *
    86      * @param  in    the input stream from which bytes will be read.
    87      * @param  size  the size of the pushback buffer.
    88      * @exception IllegalArgumentException if size is <= 0
    89      * @since  JDK1.1
    90      */
    91     public PushbackInputStream(InputStream in, int size) {
    92         super(in);
    93         if (size <= 0) {
    94             throw new IllegalArgumentException("size <= 0");
    95         }
    96         this.buf = new byte[size];
    97         this.pos = size;
    98     }
    99 
   100     /**
   101      * Creates a <code>PushbackInputStream</code>
   102      * and saves its  argument, the input stream
   103      * <code>in</code>, for later use. Initially,
   104      * there is no pushed-back byte  (the field
   105      * <code>pushBack</code> is initialized to
   106      * <code>-1</code>).
   107      *
   108      * @param   in   the input stream from which bytes will be read.
   109      */
   110     public PushbackInputStream(InputStream in) {
   111         this(in, 1);
   112     }
   113 
   114     /**
   115      * Reads the next byte of data from this input stream. The value
   116      * byte is returned as an <code>int</code> in the range
   117      * <code>0</code> to <code>255</code>. If no byte is available
   118      * because the end of the stream has been reached, the value
   119      * <code>-1</code> is returned. This method blocks until input data
   120      * is available, the end of the stream is detected, or an exception
   121      * is thrown.
   122      *
   123      * <p> This method returns the most recently pushed-back byte, if there is
   124      * one, and otherwise calls the <code>read</code> method of its underlying
   125      * input stream and returns whatever value that method returns.
   126      *
   127      * @return     the next byte of data, or <code>-1</code> if the end of the
   128      *             stream has been reached.
   129      * @exception  IOException  if this input stream has been closed by
   130      *             invoking its {@link #close()} method,
   131      *             or an I/O error occurs.
   132      * @see        java.io.InputStream#read()
   133      */
   134     public int read() throws IOException {
   135         ensureOpen();
   136         if (pos < buf.length) {
   137             return buf[pos++] & 0xff;
   138         }
   139         return super.read();
   140     }
   141 
   142     /**
   143      * Reads up to <code>len</code> bytes of data from this input stream into
   144      * an array of bytes.  This method first reads any pushed-back bytes; after
   145      * that, if fewer than <code>len</code> bytes have been read then it
   146      * reads from the underlying input stream. If <code>len</code> is not zero, the method
   147      * blocks until at least 1 byte of input is available; otherwise, no
   148      * bytes are read and <code>0</code> is returned.
   149      *
   150      * @param      b     the buffer into which the data is read.
   151      * @param      off   the start offset in the destination array <code>b</code>
   152      * @param      len   the maximum number of bytes read.
   153      * @return     the total number of bytes read into the buffer, or
   154      *             <code>-1</code> if there is no more data because the end of
   155      *             the stream has been reached.
   156      * @exception  NullPointerException If <code>b</code> is <code>null</code>.
   157      * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
   158      * <code>len</code> is negative, or <code>len</code> is greater than
   159      * <code>b.length - off</code>
   160      * @exception  IOException  if this input stream has been closed by
   161      *             invoking its {@link #close()} method,
   162      *             or an I/O error occurs.
   163      * @see        java.io.InputStream#read(byte[], int, int)
   164      */
   165     public int read(byte[] b, int off, int len) throws IOException {
   166         ensureOpen();
   167         if (b == null) {
   168             throw new NullPointerException();
   169         } else if (off < 0 || len < 0 || len > b.length - off) {
   170             throw new IndexOutOfBoundsException();
   171         } else if (len == 0) {
   172             return 0;
   173         }
   174 
   175         int avail = buf.length - pos;
   176         if (avail > 0) {
   177             if (len < avail) {
   178                 avail = len;
   179             }
   180             arraycopy(buf, pos, b, off, avail);
   181             pos += avail;
   182             off += avail;
   183             len -= avail;
   184         }
   185         if (len > 0) {
   186             len = super.read(b, off, len);
   187             if (len == -1) {
   188                 return avail == 0 ? -1 : avail;
   189             }
   190             return avail + len;
   191         }
   192         return avail;
   193     }
   194 
   195     /**
   196      * Pushes back a byte by copying it to the front of the pushback buffer.
   197      * After this method returns, the next byte to be read will have the value
   198      * <code>(byte)b</code>.
   199      *
   200      * @param      b   the <code>int</code> value whose low-order
   201      *                  byte is to be pushed back.
   202      * @exception IOException If there is not enough room in the pushback
   203      *            buffer for the byte, or this input stream has been closed by
   204      *            invoking its {@link #close()} method.
   205      */
   206     public void unread(int b) throws IOException {
   207         ensureOpen();
   208         if (pos == 0) {
   209             throw new IOException("Push back buffer is full");
   210         }
   211         buf[--pos] = (byte)b;
   212     }
   213 
   214     /**
   215      * Pushes back a portion of an array of bytes by copying it to the front
   216      * of the pushback buffer.  After this method returns, the next byte to be
   217      * read will have the value <code>b[off]</code>, the byte after that will
   218      * have the value <code>b[off+1]</code>, and so forth.
   219      *
   220      * @param b the byte array to push back.
   221      * @param off the start offset of the data.
   222      * @param len the number of bytes to push back.
   223      * @exception IOException If there is not enough room in the pushback
   224      *            buffer for the specified number of bytes,
   225      *            or this input stream has been closed by
   226      *            invoking its {@link #close()} method.
   227      * @since     JDK1.1
   228      */
   229     public void unread(byte[] b, int off, int len) throws IOException {
   230         ensureOpen();
   231         if (len > pos) {
   232             throw new IOException("Push back buffer is full");
   233         }
   234         pos -= len;
   235         arraycopy(b, off, buf, pos, len);
   236     }
   237 
   238     /**
   239      * Pushes back an array of bytes by copying it to the front of the
   240      * pushback buffer.  After this method returns, the next byte to be read
   241      * will have the value <code>b[0]</code>, the byte after that will have the
   242      * value <code>b[1]</code>, and so forth.
   243      *
   244      * @param b the byte array to push back
   245      * @exception IOException If there is not enough room in the pushback
   246      *            buffer for the specified number of bytes,
   247      *            or this input stream has been closed by
   248      *            invoking its {@link #close()} method.
   249      * @since     JDK1.1
   250      */
   251     public void unread(byte[] b) throws IOException {
   252         unread(b, 0, b.length);
   253     }
   254 
   255     /**
   256      * Returns an estimate of the number of bytes that can be read (or
   257      * skipped over) from this input stream without blocking by the next
   258      * invocation of a method for this input stream. The next invocation might be
   259      * the same thread or another thread.  A single read or skip of this
   260      * many bytes will not block, but may read or skip fewer bytes.
   261      *
   262      * <p> The method returns the sum of the number of bytes that have been
   263      * pushed back and the value returned by {@link
   264      * java.io.FilterInputStream#available available}.
   265      *
   266      * @return     the number of bytes that can be read (or skipped over) from
   267      *             the input stream without blocking.
   268      * @exception  IOException  if this input stream has been closed by
   269      *             invoking its {@link #close()} method,
   270      *             or an I/O error occurs.
   271      * @see        java.io.FilterInputStream#in
   272      * @see        java.io.InputStream#available()
   273      */
   274     public int available() throws IOException {
   275         ensureOpen();
   276         int n = buf.length - pos;
   277         int avail = super.available();
   278         return n > (Integer.MAX_VALUE - avail)
   279                     ? Integer.MAX_VALUE
   280                     : n + avail;
   281     }
   282 
   283     /**
   284      * Skips over and discards <code>n</code> bytes of data from this
   285      * input stream. The <code>skip</code> method may, for a variety of
   286      * reasons, end up skipping over some smaller number of bytes,
   287      * possibly zero.  If <code>n</code> is negative, no bytes are skipped.
   288      *
   289      * <p> The <code>skip</code> method of <code>PushbackInputStream</code>
   290      * first skips over the bytes in the pushback buffer, if any.  It then
   291      * calls the <code>skip</code> method of the underlying input stream if
   292      * more bytes need to be skipped.  The actual number of bytes skipped
   293      * is returned.
   294      *
   295      * @param      n  {@inheritDoc}
   296      * @return     {@inheritDoc}
   297      * @exception  IOException  if the stream does not support seek,
   298      *            or the stream has been closed by
   299      *            invoking its {@link #close()} method,
   300      *            or an I/O error occurs.
   301      * @see        java.io.FilterInputStream#in
   302      * @see        java.io.InputStream#skip(long n)
   303      * @since      1.2
   304      */
   305     public long skip(long n) throws IOException {
   306         ensureOpen();
   307         if (n <= 0) {
   308             return 0;
   309         }
   310 
   311         long pskip = buf.length - pos;
   312         if (pskip > 0) {
   313             if (n < pskip) {
   314                 pskip = n;
   315             }
   316             pos += pskip;
   317             n -= pskip;
   318         }
   319         if (n > 0) {
   320             pskip += super.skip(n);
   321         }
   322         return pskip;
   323     }
   324 
   325     /**
   326      * Tests if this input stream supports the <code>mark</code> and
   327      * <code>reset</code> methods, which it does not.
   328      *
   329      * @return   <code>false</code>, since this class does not support the
   330      *           <code>mark</code> and <code>reset</code> methods.
   331      * @see     java.io.InputStream#mark(int)
   332      * @see     java.io.InputStream#reset()
   333      */
   334     public boolean markSupported() {
   335         return false;
   336     }
   337 
   338     /**
   339      * Marks the current position in this input stream.
   340      *
   341      * <p> The <code>mark</code> method of <code>PushbackInputStream</code>
   342      * does nothing.
   343      *
   344      * @param   readlimit   the maximum limit of bytes that can be read before
   345      *                      the mark position becomes invalid.
   346      * @see     java.io.InputStream#reset()
   347      */
   348     public synchronized void mark(int readlimit) {
   349     }
   350 
   351     /**
   352      * Repositions this stream to the position at the time the
   353      * <code>mark</code> method was last called on this input stream.
   354      *
   355      * <p> The method <code>reset</code> for class
   356      * <code>PushbackInputStream</code> does nothing except throw an
   357      * <code>IOException</code>.
   358      *
   359      * @exception  IOException  if this method is invoked.
   360      * @see     java.io.InputStream#mark(int)
   361      * @see     java.io.IOException
   362      */
   363     public synchronized void reset() throws IOException {
   364         throw new IOException("mark/reset not supported");
   365     }
   366 
   367     /**
   368      * Closes this input stream and releases any system resources
   369      * associated with the stream.
   370      * Once the stream has been closed, further read(), unread(),
   371      * available(), reset(), or skip() invocations will throw an IOException.
   372      * Closing a previously closed stream has no effect.
   373      *
   374      * @exception  IOException  if an I/O error occurs.
   375      */
   376     public synchronized void close() throws IOException {
   377         if (in == null)
   378             return;
   379         in.close();
   380         in = null;
   381         buf = null;
   382     }
   383     static void arraycopy(byte[] value, int srcBegin, byte[] dst, int dstBegin, int count) {
   384         while (count-- > 0) {
   385             dst[dstBegin++] = value[srcBegin++];
   386         }
   387     }
   388 }