Source for java.io.BufferedReader

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