001    /* BufferedReader.java
002       Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
003         Free Software Foundation, Inc.
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011     
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    
040    package java.io;
041    
042    /* Written using "Java Class Libraries", 2nd edition, plus online
043     * API docs for JDK 1.2 beta from http://www.javasoft.com.
044     * Status:  Believed complete and correct.
045     */
046    
047    /**
048     * This subclass of <code>FilterReader</code> buffers input from an 
049     * underlying implementation to provide a possibly more efficient read
050     * mechanism.  It maintains the buffer and buffer state in instance 
051     * variables that are available to subclasses.  The default buffer size
052     * of 8192 chars can be overridden by the creator of the stream.
053     * <p>
054     * This class also implements mark/reset functionality.  It is capable
055     * of remembering any number of input chars, to the limits of
056     * system memory or the size of <code>Integer.MAX_VALUE</code>
057     *
058     * @author Per Bothner (bothner@cygnus.com)
059     * @author Aaron M. Renn (arenn@urbanophile.com)
060     */
061    public class BufferedReader extends Reader
062    {
063      Reader in;
064      char[] buffer;
065      /* Index of current read position.  Must be >= 0 and <= limit. */
066      /* There is a special case where pos may be equal to limit+1; this
067       * is used as an indicator that a readLine was done with a '\r' was
068       * the very last char in the buffer.  Since we don't want to read-ahead
069       * and potentially block, we set pos this way to indicate the situation
070       * and deal with it later.  Doing it this way rather than having a
071       * separate boolean field to indicate the condition has the advantage
072       * that it is self-clearing on things like mark/reset.
073       */
074      int pos;
075      /* Limit of valid data in buffer.  Must be >= pos and <= buffer.length. */
076      /* This can be < pos in the one special case described above. */
077      int limit;
078    
079      /* The value -1 means there is no mark, or the mark has been invalidated.
080         Otherwise, markPos is the index in the buffer of the marked position.
081         Must be >= 0 and <= pos.
082         Note we do not explicitly store the read-limit.
083         The implicit read-limit is (buffer.length - markPos), which is
084         guaranteed to be >= the read-limit requested in the call to mark. */
085      int markPos = -1;
086    
087      // The JCL book specifies the default buffer size as 8K characters.
088      // This is package-private because it is used by LineNumberReader.
089      static final int DEFAULT_BUFFER_SIZE = 8192;
090    
091      /**
092       * The line buffer for <code>readLine</code>.
093       */
094      private StringBuffer sbuf = null;
095    
096      /**
097        * Create a new <code>BufferedReader</code> that will read from the 
098        * specified subordinate stream with a default buffer size of 8192 chars.
099        *
100        * @param in The subordinate stream to read from
101        */
102      public BufferedReader(Reader in)
103      {
104        this(in, DEFAULT_BUFFER_SIZE);
105      }
106    
107      /**
108       * Create a new <code>BufferedReader</code> that will read from the 
109       * specified subordinate stream with a buffer size that is specified by the 
110       * caller.
111       *
112       * @param in The subordinate stream to read from
113       * @param size The buffer size to use
114       *
115       * @exception IllegalArgumentException if size &lt;= 0
116       */
117      public BufferedReader(Reader in, int size)
118      {
119        super(in.lock);
120        if (size <= 0)
121          throw new IllegalArgumentException("Illegal buffer size: " + size);
122        this.in = in;
123        buffer = new char[size];
124      }
125    
126      /**
127       * This method closes the underlying stream and frees any associated
128       * resources.
129       *
130       * @exception IOException If an error occurs
131       */
132      public void close() throws IOException
133      {
134        synchronized (lock)
135          {
136            if (in != null)
137              in.close();
138            in = null;
139            buffer = null;
140          }
141      }
142    
143      /**
144       * Returns <code>true</code> to indicate that this class supports mark/reset 
145       * functionality.
146       *
147       * @return <code>true</code>
148       */
149      public boolean markSupported()
150      {
151        return true;
152      }
153    
154      /**
155       * Mark a position in the input to which the stream can be
156       * "reset" by calling the <code>reset()</code> method.  The parameter
157       * <code>readLimit</code> is the number of chars that can be read from the 
158       * stream after setting the mark before the mark becomes invalid.  For
159       * example, if <code>mark()</code> is called with a read limit of 10, then 
160       * when 11 chars of data are read from the stream before the 
161       * <code>reset()</code> method is called, then the mark is invalid and the 
162       * stream object instance is not required to remember the mark.
163       * <p>
164       * Note that the number of chars that can be remembered by this method
165       * can be greater than the size of the internal read buffer.  It is also
166       * not dependent on the subordinate stream supporting mark/reset
167       * functionality.
168       *
169       * @param readLimit The number of chars that can be read before the mark 
170       *        becomes invalid
171       *
172       * @exception IOException If an error occurs
173       * @exception IllegalArgumentException if readLimit is negative.
174       */
175      public void mark(int readLimit) throws IOException
176      {
177        if (readLimit < 0)
178          throw new IllegalArgumentException("Read-ahead limit is negative");
179    
180        synchronized (lock)
181          {
182            checkStatus();
183            // In this method we need to be aware of the special case where
184            // pos + 1 == limit.  This indicates that a '\r' was the last char
185            // in the buffer during a readLine.  We'll want to maintain that
186            // condition after we shift things around and if a larger buffer is
187            // needed to track readLimit, we'll have to make it one element
188            // larger to ensure we don't invalidate the mark too early, if the
189            // char following the '\r' is NOT a '\n'.  This is ok because, per
190            // the spec, we are not required to invalidate when passing readLimit.
191            //
192            // Note that if 'pos > limit', then doing 'limit -= pos' will cause
193            // limit to be negative.  This is the only way limit will be < 0.
194    
195            if (pos + readLimit > limit)
196              {
197                char[] old_buffer = buffer;
198                int extraBuffSpace = 0;
199                if (pos > limit)
200                  extraBuffSpace = 1;
201                if (readLimit + extraBuffSpace > limit)
202                  buffer = new char[readLimit + extraBuffSpace];
203                limit -= pos;
204                if (limit >= 0)
205                  {
206                    System.arraycopy(old_buffer, pos, buffer, 0, limit);
207                    pos = 0;
208                  }
209              }
210    
211            if (limit < 0)
212              {
213                // Maintain the relationship of 'pos > limit'.
214                pos = 1;
215                limit = markPos = 0;
216              }
217            else
218              markPos = pos;
219            // Now pos + readLimit <= buffer.length. thus if we need to read
220            // beyond buffer.length, then we are allowed to invalidate markPos.
221          }
222      }
223    
224      /**
225       * Reset the stream to the point where the <code>mark()</code> method
226       * was called.  Any chars that were read after the mark point was set will
227       * be re-read during subsequent reads.
228       * <p>
229       * This method will throw an IOException if the number of chars read from
230       * the stream since the call to <code>mark()</code> exceeds the mark limit
231       * passed when establishing the mark.
232       *
233       * @exception IOException If an error occurs;
234       */
235      public void reset() throws IOException
236      {
237        synchronized (lock)
238          {
239            checkStatus();
240            if (markPos < 0)
241              throw new IOException("mark never set or invalidated");
242    
243            // Need to handle the extremely unlikely case where a readLine was
244            // done with a '\r' as the last char in the buffer; which was then
245            // immediately followed by a mark and a reset with NO intervening
246            // read of any sort.  In that case, setting pos to markPos would
247            // lose that info and a subsequent read would thus not skip a '\n'
248            // (if one exists).  The value of limit in this rare case is zero.
249            // We can assume that if limit is zero for other reasons, then
250            // pos is already set to zero and doesn't need to be readjusted.
251            if (limit > 0)
252              pos = markPos;
253          }
254      }
255    
256      /**
257       * This method determines whether or not a stream is ready to be read.  If
258       * this method returns <code>false</code> then this stream could (but is
259       * not guaranteed to) block on the next read attempt.
260       *
261       * @return <code>true</code> if this stream is ready to be read, 
262       * <code>false</code> otherwise
263       *
264       * @exception IOException If an error occurs
265       */
266      public boolean ready() throws IOException
267      {
268        synchronized (lock)
269          {
270            checkStatus();
271            return pos < limit || in.ready();
272          }
273      }
274    
275      /**
276       * This method read chars from a stream and stores them into a caller
277       * supplied buffer.  It starts storing the data at index 
278       * <code>offset</code> into
279       * the buffer and attempts to read <code>len</code> chars.  This method can
280       * return before reading the number of chars requested.  The actual number
281       * of chars read is returned as an int.  A -1 is returned to indicate the
282       * end of the stream.
283       * <p>
284       * This method will block until some data can be read.
285       *
286       * @param buf The array into which the chars read should be stored
287       * @param offset The offset into the array to start storing chars
288       * @param count The requested number of chars to read
289       *
290       * @return The actual number of chars read, or -1 if end of stream.
291       *
292       * @exception IOException If an error occurs.
293       * @exception IndexOutOfBoundsException If offset and count are not
294       * valid regarding buf.
295       */
296      public int read(char[] buf, int offset, int count) throws IOException
297      {
298        if (offset < 0 || offset + count > buf.length || count < 0)
299          throw new IndexOutOfBoundsException();
300    
301        synchronized (lock)
302          {
303            checkStatus();
304            // Once again, we need to handle the special case of a readLine
305            // that has a '\r' at the end of the buffer.  In this case, we'll
306            // need to skip a '\n' if it is the next char to be read.
307            // This special case is indicated by 'pos > limit'.
308            boolean retAtEndOfBuffer = false;
309    
310            int avail = limit - pos;
311            if (count > avail)
312              {
313                if (avail > 0)
314                  count = avail;
315                else // pos >= limit
316                  {
317                    if (limit == buffer.length)
318                      markPos = -1; // read too far - invalidate the mark.
319                    if (pos > limit)
320                      {
321                        // Set a boolean and make pos == limit to simplify things.
322                        retAtEndOfBuffer = true;
323                        --pos;
324                      }
325                    if (markPos < 0)
326                      {
327                        // Optimization:  can read directly into buf.
328                        if (count >= buffer.length && !retAtEndOfBuffer)
329                          return in.read(buf, offset, count);
330                        pos = limit = 0;
331                      }
332                    avail = in.read(buffer, limit, buffer.length - limit);
333                    if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n')
334                      {
335                        --avail;
336                        limit++;
337                      }
338                    if (avail < count)
339                      {
340                        if (avail <= 0)
341                          return avail;
342                        count = avail;
343                      }
344                    limit += avail;
345                  }
346              }
347            System.arraycopy(buffer, pos, buf, offset, count);
348            pos += count;
349            return count;
350          }
351      }
352    
353      /* Read more data into the buffer.  Update pos and limit appropriately.
354         Assumes pos==limit initially.  May invalidate the mark if read too much.
355         Return number of chars read (never 0), or -1 on eof. */
356      private int fill() throws IOException
357      {
358        checkStatus();
359        // Handle the special case of a readLine that has a '\r' at the end of
360        // the buffer.  In this case, we'll need to skip a '\n' if it is the
361        // next char to be read.  This special case is indicated by 'pos > limit'.
362        boolean retAtEndOfBuffer = false;
363        if (pos > limit)
364          {
365            retAtEndOfBuffer = true;
366            --pos;
367          }
368    
369        if (markPos >= 0 && limit == buffer.length)
370          markPos = -1;
371        if (markPos < 0)
372          pos = limit = 0;
373        int count = in.read(buffer, limit, buffer.length - limit);
374        if (count > 0)
375          limit += count;
376    
377        if (retAtEndOfBuffer && buffer[pos] == '\n')
378          {
379            --count;
380            // If the mark was set to the location of the \n, then we
381            // must change it to fully pretend that the \n does not
382            // exist.
383            if (markPos == pos)
384              ++markPos;
385            ++pos;
386          }
387    
388        return count;
389      }
390      
391      public int read() throws IOException
392      {
393        synchronized (lock)
394          {
395            checkStatus();
396            if (pos >= limit && fill () <= 0)
397              return -1;
398            return buffer[pos++];
399          }
400      }
401    
402      /* Return the end of the line starting at this.pos and ending at limit.
403       * The index returns is *before* any line terminators, or limit
404       * if no line terminators were found.
405       */
406      private int lineEnd(int limit)
407      {
408        int i = pos;
409        for (; i < limit; i++)
410          {
411            char ch = buffer[i];
412            if (ch == '\n' || ch == '\r')
413              break;
414          }
415        return i;
416      }
417    
418      /**
419       * This method reads a single line of text from the input stream, returning
420       * it as a <code>String</code>.  A line is terminated by "\n", a "\r", or
421       * an "\r\n" sequence.  The system dependent line separator is not used.
422       * The line termination characters are not returned in the resulting
423       * <code>String</code>.
424       * 
425       * @return The line of text read, or <code>null</code> if end of stream.
426       * 
427       * @exception IOException If an error occurs
428       */
429      public String readLine() throws IOException
430      {
431        checkStatus();
432        // Handle the special case where a previous readLine (with no intervening
433        // reads/skips) had a '\r' at the end of the buffer.
434        // In this case, we'll need to skip a '\n' if it's the next char to be read.
435        // This special case is indicated by 'pos > limit'.
436        if (pos > limit)
437          {
438            int ch = read();
439            if (ch < 0)
440              return null;
441            if (ch != '\n')
442              --pos;
443          }
444        int i = lineEnd(limit);
445        if (i < limit)
446          {
447            String str = String.valueOf(buffer, pos, i - pos);
448            pos = i + 1;
449            // If the last char in the buffer is a '\r', we must remember
450            // to check if the next char to be read after the buffer is refilled
451            // is a '\n'.  If so, skip it.  To indicate this condition, we set pos
452            // to be limit + 1, which normally is never possible.
453            if (buffer[i] == '\r')
454              if (pos == limit || buffer[pos] == '\n')
455                pos++;
456            return str;
457          }
458        if (sbuf == null)
459          sbuf = new StringBuffer(200);
460        else
461          sbuf.setLength(0);
462        sbuf.append(buffer, pos, i - pos);
463        pos = i;
464        // We only want to return null when no characters were read before
465        // EOF.  So we must keep track of this separately.  Otherwise we
466        // would treat an empty `sbuf' as an EOF condition, which is wrong
467        // when there is just a newline.
468        boolean eof = false;
469        for (;;)
470          {
471            // readLine should block. So we must not return until a -1 is reached.
472            if (pos >= limit)
473              {
474                // here count == 0 isn't sufficient to give a failure.
475                int count = fill();
476                if (count < 0)
477                  {
478                    eof = true;
479                    break;
480                  }
481                continue;
482              }
483            int ch = buffer[pos++];
484            if (ch == '\n' || ch == '\r')
485              {
486                // Check here if a '\r' was the last char in the buffer; if so,
487                // mark it as in the comment above to indicate future reads
488                // should skip a newline that is the next char read after
489                // refilling the buffer.
490                if (ch == '\r')
491                  if (pos == limit || buffer[pos] == '\n')
492                    pos++;
493                break;
494              }
495            i = lineEnd(limit);
496            sbuf.append(buffer, pos - 1, i - (pos - 1));
497            pos = i;
498          }
499        return (sbuf.length() == 0 && eof) ? null : sbuf.toString();
500      }
501    
502      /**
503       * This method skips the specified number of chars in the stream.  It
504       * returns the actual number of chars skipped, which may be less than the
505       * requested amount.
506       * <p>
507       * This method first discards chars in the buffer, then calls the
508       * <code>skip</code> method on the underlying stream to skip the 
509       * remaining chars.
510       *
511       * @param count The requested number of chars to skip
512       *
513       * @return The actual number of chars skipped.
514       *
515       * @exception IOException If an error occurs.
516       * @exception IllegalArgumentException If count is negative.
517       */
518      public long skip(long count) throws IOException
519      {
520        synchronized (lock)
521          {
522            checkStatus();
523            if (count < 0)
524              throw new IllegalArgumentException("skip value is negative");
525            if (count == 0)
526              return 0;
527            // Yet again, we need to handle the special case of a readLine
528            // that has a '\r' at the end of the buffer.  In this case, we need
529            // to ignore a '\n' if it is the next char to be read.
530            // This special case is indicated by 'pos > limit' (i.e. avail < 0).
531            // To simplify things, if we're dealing with the special case for
532            // readLine, just read the next char (since the fill method will
533            // skip the '\n' for us).  By doing this, we'll have to back up pos.
534            // That's easier than trying to keep track of whether we've skipped
535            // one element or not.
536            if (pos > limit)
537              {
538                if (read() < 0)
539                  return 0;
540                else
541                  --pos; 
542              }
543    
544            int avail = limit - pos;
545    
546            if (count < avail)
547              {
548                pos += count;
549                return count;
550              }
551    
552            pos = limit;
553            long todo = count - avail;
554            if (todo > buffer.length)
555              {
556                markPos = -1;
557                todo -= in.skip(todo);
558              }
559            else
560              {
561                while (todo > 0)
562                  {
563                    avail = fill();
564                    if (avail <= 0)
565                      break;
566                    if (avail > todo)
567                      avail = (int) todo;
568                    pos += avail;
569                    todo -= avail;
570                  }
571              }
572            return count - todo;
573          }
574      }
575      
576      private void checkStatus() throws IOException
577      {
578        if (in == null)
579          throw new IOException("Stream closed");
580      }  
581    }