home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / io / PushbackInputStream.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  9.4 KB  |  288 lines

  1. /*
  2.  * @(#)PushbackInputStream.java    1.21 98/03/18
  3.  *
  4.  * Copyright 1994-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. /**
  18.  * This class is an input stream filter that provides a buffer into which data
  19.  * can be "unread."  An application may unread data at any time by pushing it
  20.  * back into the buffer, as long as the buffer has sufficient room.  Subsequent
  21.  * reads will read all of the pushed-back data in the buffer before reading
  22.  * from the underlying input stream.
  23.  *
  24.  * <p>
  25.  * This functionality is useful when a fragment of code should read 
  26.  * an indefinite number of data bytes that are delimited by 
  27.  * particular byte values. After reading the terminating byte the
  28.  * code fragment can push it back, so that the next read 
  29.  * operation on the input stream will re-read that byte.
  30.  *
  31.  * @author  David Connelly
  32.  * @author  Jonathan Payne
  33.  * @version 1.21, 03/18/98
  34.  * @since   JDK1.0
  35.  */
  36. public
  37. class PushbackInputStream extends FilterInputStream {
  38.     /**
  39.      * The pushback buffer.
  40.      * @since   JDK1.1
  41.      */
  42.     protected byte[] buf;
  43.  
  44.     /**
  45.      * The position within the pushback buffer from which the next byte will
  46.      * be read.  When the buffer is empty, <code>pos</code> is equal to
  47.      * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
  48.      * equal to zero.
  49.      *
  50.      * @since   JDK1.1
  51.      */
  52.     protected int pos;
  53.  
  54.     /**
  55.      * Check to make sure that this stream has not been closed
  56.      */
  57.     private void ensureOpen() throws IOException {
  58.     if (in == null)
  59.         throw new IOException("Stream closed");
  60.     }
  61.  
  62.     /**
  63.      * Creates a new pushback input stream with a pushback buffer
  64.      * of the specified size.
  65.      *
  66.      * @param  in    the input stream from which bytes will be read.
  67.      * @param  size  the size of the pushback buffer.
  68.      * @since  JDK1.1
  69.      */
  70.     public PushbackInputStream(InputStream in, int size) {
  71.     super(in);
  72.     this.buf = new byte[size];
  73.     this.pos = size;
  74.     }
  75.  
  76.     /**
  77.      * Creates a new pushback input stream with a one-byte pushback buffer.
  78.      *
  79.      * @param   in   the input stream from which bytes will be read.
  80.      */
  81.     public PushbackInputStream(InputStream in) {
  82.     this(in, 1);
  83.     }
  84.  
  85.     /**
  86.      * Reads the next byte of data from this input stream. The value 
  87.      * byte is returned as an <code>int</code> in the range 
  88.      * <code>0</code> to <code>255</code>. If no byte is available 
  89.      * because the end of the stream has been reached, the value 
  90.      * <code>-1</code> is returned. This method blocks until input data 
  91.      * is available, the end of the stream is detected, or an exception 
  92.      * is thrown. 
  93.      *
  94.      * <p> This method returns the most recently pushed-back byte, if there is
  95.      * one, and otherwise calls the <code>read</code> method of its underlying
  96.      * input stream and returns whatever value that method returns.
  97.      *
  98.      * @return     the next byte of data, or <code>-1</code> if the end of the
  99.      *             stream has been reached.
  100.      * @exception  IOException  if an I/O error occurs.
  101.      * @see        java.io.InputStream#read()
  102.      */
  103.     public int read() throws IOException {
  104.         ensureOpen();
  105.     if (pos < buf.length) {
  106.         return buf[pos++] & 0xff;
  107.     }
  108.     return super.read();
  109.     }
  110.  
  111.     /**
  112.      * Reads up to <code>len</code> bytes of data from this input stream into
  113.      * an array of bytes.  This method first reads any pushed-back bytes; after
  114.      * that, if fewer than than <code>len</code> bytes have been read then it
  115.      * reads from the underlying input stream.  This method blocks until at
  116.      * least 1 byte of input is available.
  117.      *
  118.      * @param      b     the buffer into which the data is read.
  119.      * @param      off   the start offset of the data.
  120.      * @param      len   the maximum number of bytes read.
  121.      * @return     the total number of bytes read into the buffer, or
  122.      *             <code>-1</code> if there is no more data because the end of
  123.      *             the stream has been reached.
  124.      * @exception  IOException  if an I/O error occurs.
  125.      */
  126.     public int read(byte[] b, int off, int len) throws IOException {
  127.         ensureOpen();
  128.     if (len <= 0) {
  129.         return 0;
  130.     }
  131.     int avail = buf.length - pos;
  132.     if (avail > 0) {
  133.         if (len < avail) {
  134.         avail = len;
  135.         }
  136.         System.arraycopy(buf, pos, b, off, avail);
  137.         pos += avail;
  138.         off += avail;
  139.         len -= avail;
  140.     }
  141.     if (len > 0) {
  142.         len = super.read(b, off, len);
  143.         if (len == -1) {
  144.         return avail == 0 ? -1 : avail;
  145.         }
  146.         return avail + len;
  147.     }
  148.     return avail;
  149.     }
  150.  
  151.     /**
  152.      * Pushes back a byte by copying it to the front of the pushback buffer.
  153.      * After this method returns, the next byte to be read will have the value
  154.      * <code>(byte)b</code>.
  155.      *
  156.      * @param      b   the <code>int</code> value whose low-order 
  157.      *             byte is to be pushed back.
  158.      * @exception IOException If there is not enough room in the pushback
  159.      *                  buffer for the byte.
  160.      */
  161.     public void unread(int b) throws IOException {
  162.         ensureOpen();
  163.     if (pos == 0) {
  164.         throw new IOException("Push back buffer is full");
  165.     }
  166.     buf[--pos] = (byte)b;
  167.     }
  168.  
  169.     /**
  170.      * Pushes back a portion of an array of bytes by copying it to the front
  171.      * of the pushback buffer.  After this method returns, the next byte to be
  172.      * read will have the value <code>b[off]</code>, the byte after that will
  173.      * have the value <code>b[off+1]</code>, and so forth.
  174.      *
  175.      * @param b the byte array to push back.
  176.      * @param off the start offset of the data.
  177.      * @param len the number of bytes to push back.
  178.      * @exception IOException If there is not enough room in the pushback
  179.      *                  buffer for the specified number of bytes.
  180.      * @since     JDK1.1
  181.      */
  182.     public void unread(byte[] b, int off, int len) throws IOException {
  183.         ensureOpen();
  184.     if (len > pos) {
  185.         throw new IOException("Push back buffer is full");
  186.     }
  187.     pos -= len;
  188.     System.arraycopy(b, off, buf, pos, len);
  189.     }
  190.  
  191.     /**
  192.      * Pushes back an array of bytes by copying it to the front of the
  193.      * pushback buffer.  After this method returns, the next byte to be read
  194.      * will have the value <code>b[0]</code>, the byte after that will have the
  195.      * value <code>b[1]</code>, and so forth.
  196.      *
  197.      * @param b the byte array to push back
  198.      * @exception IOException If there is not enough room in the pushback
  199.      *                  buffer for the specified number of bytes.
  200.      * @since     JDK1.1
  201.      */
  202.     public void unread(byte[] b) throws IOException {
  203.     unread(b, 0, b.length);
  204.     }
  205.  
  206.     /**
  207.      * Returns the number of bytes that can be read from this input stream
  208.      * without blocking.  This method calls the <code>available</code> method
  209.      * of the underlying input stream; it returns that value plus the number of
  210.      * bytes that have been pushed back.
  211.      *
  212.      * @return     the number of bytes that can be read from the input stream
  213.      *             without blocking.
  214.      * @exception  IOException  if an I/O error occurs.
  215.      * @see        java.io.FilterInputStream#in
  216.      */
  217.     public int available() throws IOException {
  218.         ensureOpen();
  219.     return (buf.length - pos) + super.available();
  220.     }
  221.  
  222.     /**
  223.      * Skips over and discards <code>n</code> bytes of data from this 
  224.      * input stream. The <code>skip</code> method may, for a variety of 
  225.      * reasons, end up skipping over some smaller number of bytes, 
  226.      * possibly zero.  If <code>n</code> is negative, no bytes are skipped.
  227.      * 
  228.      * <p> The <code>skip</code> method of <code>PushbackInputStream</code>
  229.      * first skips over the bytes in the pushback buffer, if any.  It then
  230.      * calls the <code>skip</code> method of the underlying input stream if
  231.      * more bytes need to be skipped.  The actual number of bytes skipped
  232.      * is returned.
  233.      *
  234.      * @param      n   the number of bytes to be skipped.
  235.      * @return     the actual number of bytes skipped.
  236.      * @exception  IOException  if an I/O error occurs.
  237.      * @see        java.io.FilterInputStream#in
  238.      * @since      JDK1.2
  239.      */
  240.     public long skip(long n) throws IOException {
  241.         ensureOpen();
  242.     if (n <= 0) {
  243.         return 0;
  244.     }
  245.  
  246.     long pskip = buf.length - pos;
  247.     if (pskip > 0) {
  248.         if (n < pskip) {
  249.         pskip = n;
  250.         }
  251.         pos += pskip;
  252.         n -= pskip;
  253.     }
  254.     if (n > 0) {
  255.         pskip += super.skip(n);
  256.     }
  257.     return pskip;
  258.     }
  259.  
  260.     /**
  261.      * Tests if this input stream supports the <code>mark</code> and
  262.      * <code>reset</code> methods, which it does not.
  263.      *
  264.      * @return   <code>false</code>, since this class does not support the
  265.      *           <code>mark</code> and <code>reset</code> methods.
  266.      * @see     java.io.InputStream#mark(int)
  267.      * @see     java.io.InputStream#reset()
  268.      */
  269.     public boolean markSupported() {
  270.     return false;
  271.     }
  272.  
  273.     /**
  274.      * Closes this input stream and releases any system resources 
  275.      * associated with the stream. 
  276.      *
  277.      * @exception  IOException  if an I/O error occurs.
  278.      */
  279.     public synchronized void close() throws IOException {
  280.         if (in == null)
  281.             return;
  282.         in.close();
  283.         in = null;
  284.         buf = null;
  285.     }
  286.  
  287. }
  288.