home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Internet / Javadraw / DATA.Z / BufferedInputStream.java < prev    next >
Text File  |  1997-08-30  |  12KB  |  333 lines

  1. /*
  2.  * @(#)BufferedInputStream.java    1.26 97/03/03
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.io;
  24.  
  25. /**
  26.  * The class implements a buffered input stream. By setting up such 
  27.  * an input stream, an application can read bytes from a stream 
  28.  * without necessarily causing a call to the underlying system for 
  29.  * each byte read. The data is read by blocks into a buffer; 
  30.  * subsequent reads can access the data directly from the buffer. 
  31.  *
  32.  * @author  Arthur van Hoff
  33.  * @version 1.26, 03/03/97
  34.  * @since   JDK1.0
  35.  */
  36. public
  37. class BufferedInputStream extends FilterInputStream {
  38.     /**
  39.      * The buffer where data is stored. 
  40.      *
  41.      * @since   JDK1.0
  42.      */
  43.     protected byte buf[];
  44.  
  45.     /**
  46.      * The index one greater than the index of the last valid byte in 
  47.      * the buffer. 
  48.      *
  49.      * @since   JDK1.0
  50.      */
  51.     protected int count;
  52.  
  53.     /**
  54.      * The current position in the buffer. This is the index of the next 
  55.      * character to be read from the <code>buf</code> array. 
  56.      *
  57.      * @see     java.io.BufferedInputStream#buf
  58.      * @since   JDK1.0
  59.      */
  60.     protected int pos;
  61.     
  62.     /**
  63.      * The value of the <code>pos</code> field at the time the last 
  64.      * <code>mark</code> method was called. The value of this field is 
  65.      * <code>-1</code> if there is no current mark. 
  66.      *
  67.      * @see     java.io.BufferedInputStream#mark(int)
  68.      * @see     java.io.BufferedInputStream#pos
  69.      * @since   JDK1.0
  70.      */
  71.     protected int markpos = -1;
  72.  
  73.     /**
  74.      * The maximum read ahead allowed after a call to the 
  75.      * <code>mark</code> method before subsequent calls to the 
  76.      * <code>reset</code> method fail. 
  77.      *
  78.      * @see     java.io.BufferedInputStream#mark(int)
  79.      * @see     java.io.BufferedInputStream#reset()
  80.      * @since   JDK1.0
  81.      */
  82.     protected int marklimit;
  83.  
  84.     /**
  85.      * Creates a new buffered input stream to read data from the 
  86.      * specified input stream with a default 512-byte buffer size. 
  87.      *
  88.      * @param   in   the underlying input stream.
  89.      * @since   JDK1.0
  90.      */
  91.     public BufferedInputStream(InputStream in) {
  92.     this(in, 2048);
  93.     }
  94.  
  95.     /**
  96.      * Creates a new buffered input stream to read data from the 
  97.      * specified input stream with the specified buffer size. 
  98.      *
  99.      * @param   in     the underlying input stream.
  100.      * @param   size   the buffer size.
  101.      * @since   JDK1.0
  102.      */
  103.     public BufferedInputStream(InputStream in, int size) {
  104.     super(in);
  105.     buf = new byte[size];
  106.     }
  107.  
  108.     /**
  109.      * Fills the buffer with more data, taking into account
  110.      * shuffling and other tricks for dealing with marks.
  111.      * Assumes that it is being called by a synchronized method.
  112.      * This method also assumes that all data has already been read in,
  113.      * hence pos > count.
  114.      */
  115.     private void fill() throws IOException {
  116.     if (markpos < 0)
  117.         pos = 0;        /* no mark: throw away the buffer */
  118.     else if (pos >= buf.length)    /* no room left in buffer */
  119.         if (markpos > 0) {    /* can throw away early part of the buffer */
  120.         int sz = pos - markpos;
  121.         System.arraycopy(buf, markpos, buf, 0, sz);
  122.         pos = sz;
  123.         markpos = 0;
  124.         } else if (buf.length >= marklimit) {
  125.         markpos = -1;    /* buffer got too big, invalidate mark */
  126.         pos = 0;    /* drop buffer contents */
  127.         } else {        /* grow buffer */
  128.         int nsz = pos * 2;
  129.         if (nsz > marklimit)
  130.             nsz = marklimit;
  131.         byte nbuf[] = new byte[nsz];
  132.         System.arraycopy(buf, 0, nbuf, 0, pos);
  133.         buf = nbuf;
  134.         }
  135.     int n = in.read(buf, pos, buf.length - pos);
  136.     count = n <= 0 ? pos : n + pos;
  137.     }
  138.  
  139.     /**
  140.      * Reads the next byte of data from this buffered input stream. The 
  141.      * value byte is returned as an <code>int</code> in the range 
  142.      * <code>0</code> to <code>255</code>. If no byte is available 
  143.      * because the end of the stream has been reached, the value 
  144.      * <code>-1</code> is returned. This method blocks until input data 
  145.      * is available, the end of the stream is detected, or an exception 
  146.      * is thrown. 
  147.      * <p>
  148.      * The <code>read</code> method of <code>BufferedInputStream</code> 
  149.      * returns the next byte of data from its buffer if the buffer is not 
  150.      * empty. Otherwise, it refills the buffer from the underlying input 
  151.      * stream and returns the next character, if the underlying stream 
  152.      * has not returned an end-of-stream indicator. 
  153.      *
  154.      * @return     the next byte of data, or <code>-1</code> if the end of the
  155.      *             stream is reached.
  156.      * @exception  IOException  if an I/O error occurs.
  157.      * @see        java.io.FilterInputStream#in
  158.      * @since      JDK1.0
  159.      */
  160.     public synchronized int read() throws IOException {
  161.     if (pos >= count) {
  162.         fill();
  163.         if (pos >= count)
  164.         return -1;
  165.     }
  166.     return buf[pos++] & 0xff;
  167.     }
  168.  
  169.     /**
  170.      * Reads bytes into a portion of an array.  This method will block until
  171.      * some input is available, an I/O error occurs, or the end of the stream
  172.      * is reached.
  173.      *
  174.      * <p> If this stream's buffer is not empty, bytes are copied from it into
  175.      * the array argument.  Otherwise, the buffer is refilled from the
  176.      * underlying input stream and, unless the stream returns an end-of-stream
  177.      * indication, the array argument is filled with characters from the
  178.      * newly-filled buffer.
  179.      *
  180.      * <p> As an optimization, if the buffer is empty, the mark is not valid,
  181.      * and <code>len</code> is at least as large as the buffer, then this
  182.      * method will read directly from the underlying stream into the given
  183.      * array.  Thus redundant <code>BufferedInputStream</code>s will not copy
  184.      * data unnecessarily.
  185.      *
  186.      * @param      b     destination buffer.
  187.      * @param      off   offset at which to start storing bytes.
  188.      * @param      len   maximum number of bytes to read.
  189.      * @return     the number of bytes read, or <code>-1</code> if the end of
  190.      *             the stream has been reached.
  191.      * @exception  IOException  if an I/O error occurs.
  192.      */
  193.     public synchronized int read(byte b[], int off, int len) throws IOException {
  194.     int avail = count - pos;
  195.     if (avail <= 0) {
  196.         /* If the requested length is larger than the buffer, and if there
  197.            is no mark/reset activity, do not bother to copy the bytes into
  198.            the local buffer.  In this way buffered streams will cascade
  199.            harmlessly. */
  200.         if (len >= buf.length && markpos < 0) {
  201.         return in.read(b, off, len);
  202.         }
  203.         fill();
  204.         avail = count - pos;
  205.         if (avail <= 0)
  206.         return -1;
  207.     }
  208.     int cnt = (avail < len) ? avail : len;
  209.     System.arraycopy(buf, pos, b, off, cnt);
  210.     pos += cnt;
  211.     return cnt;
  212.     }
  213.  
  214.     /**
  215.      * Skips over and discards <code>n</code> bytes of data from the 
  216.      * input stream. The <code>skip</code> method may, for a variety of 
  217.      * reasons, end up skipping over some smaller number of bytes, 
  218.      * possibly zero. The actual number of bytes skipped is returned. 
  219.      * <p>
  220.      * The <code>skip</code> method of <code>BufferedInputStream</code> 
  221.      * compares the number of bytes it has available in its buffer, 
  222.      * <i>k</i>, where <i>k</i> = <code>count - pos</code>, 
  223.      * with <code>n</code>. If <code>n</code> ≤ <i>k</i>, 
  224.      * then the <code>pos</code> field is incremented by <code>n</code>. 
  225.      * Otherwise, the <code>pos</code> field is incremented to have the 
  226.      * value <code>count</code>, and the remaining bytes are skipped by 
  227.      * calling the <code>skip</code> method on the underlying input 
  228.      * stream, supplying the argument <code>n -</code> <i>k</i>. 
  229.      *
  230.      * @param      n   the number of bytes to be skipped.
  231.      * @return     the actual number of bytes skipped.
  232.      * @exception  IOException  if an I/O error occurs.
  233.      * @since      JDK1.0
  234.      */
  235.     public synchronized long skip(long n) throws IOException {
  236.     if (n < 0) {
  237.         return 0;
  238.     }
  239.     long avail = count - pos;
  240.  
  241.     if (avail >= n) {
  242.         pos += n;
  243.         return n;
  244.     }
  245.  
  246.     pos += avail;
  247.     return avail + in.skip(n - avail);
  248.     }
  249.  
  250.     /**
  251.      * Returns the number of bytes that can be read from this input 
  252.      * stream without blocking. 
  253.      * <p>
  254.      * The <code>available</code> method of 
  255.      * <code>BufferedInputStream</code> returns the sum of the the number 
  256.      * of bytes remaining to be read in the buffer 
  257.      * (<code>count - pos</code>) 
  258.      * and the result of calling the <code>available</code> method of the 
  259.      * underlying input stream. 
  260.      *
  261.      * @return     the number of bytes that can be read from this input
  262.      *             stream without blocking.
  263.      * @exception  IOException  if an I/O error occurs.
  264.      * @see        java.io.FilterInputStream#in
  265.      * @since      JDK1.0
  266.      */
  267.     public synchronized int available() throws IOException {
  268.     return (count - pos) + in.available();
  269.     }
  270.  
  271.     /**
  272.      * Marks the current position in this input stream. A subsequent 
  273.      * call to the <code>reset</code> method repositions the stream at 
  274.      * the last marked position so that subsequent reads re-read the same 
  275.      * bytes. 
  276.      * <p>
  277.      * The <code>readlimit</code> argument tells the input stream to 
  278.      * allow that many bytes to be read before the mark position gets 
  279.      * invalidated. 
  280.      *
  281.      * @param   readlimit   the maximum limit of bytes that can be read before
  282.      *                      the mark position becomes invalid.
  283.      * @see     java.io.BufferedInputStream#reset()
  284.      * @since   JDK1.0
  285.      */
  286.     public synchronized void mark(int readlimit) {
  287.     marklimit = readlimit;
  288.     markpos = pos;
  289.     }
  290.  
  291.     /**
  292.      * Repositions this stream to the position at the time the 
  293.      * <code>mark</code> method was last called on this input stream. 
  294.      * <p>
  295.      * If the stream has not been marked, or if the mark has been invalidated,
  296.      * an IOException is thrown. Stream marks are intended to be used in
  297.      * situations where you need to read ahead a little to see what's in
  298.      * the stream. Often this is most easily done by invoking some
  299.      * general parser. If the stream is of the type handled by the
  300.      * parser, it just chugs along happily. If the stream is not of
  301.      * that type, the parser should toss an exception when it fails. If an
  302.      * exception gets tossed within readlimit bytes, the parser will allow the
  303.      * outer code to reset the stream and to try another parser.
  304.      *
  305.      * @exception  IOException  if this stream has not been marked or
  306.      *               if the mark has been invalidated.
  307.      * @see        java.io.BufferedInputStream#mark(int)
  308.      * @since      JDK1.0
  309.      */
  310.     public synchronized void reset() throws IOException {
  311.     if (markpos < 0)
  312.         throw new IOException("Resetting to invalid mark");
  313.     pos = markpos;
  314.     }
  315.  
  316.     /**
  317.      * Tests if this input stream supports the <code>mark</code> 
  318.      * and <code>reset</code> methods. The <code>markSupported</code> 
  319.      * method of <code>BufferedInputStream</code> returns 
  320.      * <code>true</code>. 
  321.      *
  322.      * @return  a <code>boolean</code> indicating if this stream type supports
  323.      *          the <code>mark</code> and <code>reset</code> methods.
  324.      * @see     java.io.InputStream#mark(int)
  325.      * @see     java.io.InputStream#reset()
  326.      * @since   JDK1.0
  327.  
  328.      */
  329.     public boolean markSupported() {
  330.     return true;
  331.     }
  332. }
  333.