1/* 2 * Copyright (c) 1997, 2013, 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/* FROM mail.jar */ 27package com.sun.xml.internal.org.jvnet.mimepull; 28 29import java.io.*; 30 31/** 32 * This class is to support reading CRLF terminated lines that 33 * contain only US-ASCII characters from an input stream. Provides 34 * functionality that is similar to the deprecated 35 * <code>DataInputStream.readLine()</code>. Expected use is to read 36 * lines as String objects from a RFC822 stream. 37 * 38 * It is implemented as a FilterInputStream, so one can just wrap 39 * this class around any input stream and read bytes from this filter. 40 * 41 * @author John Mani 42 */ 43 44final class LineInputStream extends FilterInputStream { 45 46 private char[] lineBuffer = null; // reusable byte buffer 47 private static int MAX_INCR = 1024*1024; // 1MB 48 49 public LineInputStream(InputStream in) { 50 super(in); 51 } 52 53 /** 54 * Read a line containing only ASCII characters from the input 55 * stream. A line is terminated by a CR or NL or CR-NL sequence. 56 * A common error is a CR-CR-NL sequence, which will also terminate 57 * a line. 58 * The line terminator is not returned as part of the returned 59 * String. Returns null if no data is available. <p> 60 * 61 * This class is similar to the deprecated 62 * <code>DataInputStream.readLine()</code> 63 */ 64 public String readLine() throws IOException { 65 //InputStream in = this.in; 66 char[] buf = lineBuffer; 67 68 if (buf == null) { 69 buf = lineBuffer = new char[128]; 70 } 71 72 int c1; 73 int room = buf.length; 74 int offset = 0; 75 76 while ((c1 = in.read()) != -1) { 77 if (c1 == '\n') { 78 break; 79 } else if (c1 == '\r') { 80 // Got CR, is the next char NL ? 81 boolean twoCRs = false; 82 if (in.markSupported()) { 83 in.mark(2); 84 } 85 int c2 = in.read(); 86 if (c2 == '\r') { // discard extraneous CR 87 twoCRs = true; 88 c2 = in.read(); 89 } 90 if (c2 != '\n') { 91 /* 92 * If the stream supports it (which we hope will always 93 * be the case), reset to after the first CR. Otherwise, 94 * we wrap a PushbackInputStream around the stream so we 95 * can unread the characters we don't need. The only 96 * problem with that is that the caller might stop 97 * reading from this LineInputStream, throw it away, 98 * and then start reading from the underlying stream. 99 * If that happens, the pushed back characters will be 100 * lost forever. 101 */ 102 if (in.markSupported()) { 103 in.reset(); 104 } else { 105 if (!(in instanceof PushbackInputStream)) { 106 in /*= this.in*/ = new PushbackInputStream(in, 2); 107 } 108 if (c2 != -1) { 109 ((PushbackInputStream)in).unread(c2); 110 } 111 if (twoCRs) { 112 ((PushbackInputStream)in).unread('\r'); 113 } 114 } 115 } 116 break; // outa here. 117 } 118 119 // Not CR, NL or CR-NL ... 120 // .. Insert the byte into our byte buffer 121 if (--room < 0) { // No room, need to grow. 122 if (buf.length < MAX_INCR) { 123 buf = new char[buf.length * 2]; 124 } else { 125 buf = new char[buf.length + MAX_INCR]; 126 } 127 room = buf.length - offset - 1; 128 System.arraycopy(lineBuffer, 0, buf, 0, offset); 129 lineBuffer = buf; 130 } 131 buf[offset++] = (char)c1; 132 } 133 134 if ((c1 == -1) && (offset == 0)) { 135 return null; 136 } 137 138 return String.copyValueOf(buf, 0, offset); 139 } 140} 141