StrictLineReader.java revision 7899c5ab935cf542069835ec7d3e457db596dbf7
17899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath/* 27899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Copyright (C) 2012 The Android Open Source Project 37899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 47899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 57899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * you may not use this file except in compliance with the License. 67899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * You may obtain a copy of the License at 77899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 87899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 97899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Unless required by applicable law or agreed to in writing, software 117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * See the License for the specific language governing permissions and 147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * limitations under the License. 157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathpackage libcore.io; 187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.ByteArrayOutputStream; 207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.Closeable; 217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.EOFException; 227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException; 237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream; 247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.nio.charset.Charset; 257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport libcore.util.Charsets; 267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath/** 287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Buffers input from an {@link InputStream} for reading lines. 297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * This class is used for buffered reading of lines. For purposes of this class, a line ends with 317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated line at 327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * end of input is invalid and will be ignored, the caller may use {@code hasUnterminatedLine()} 337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * to detect it after catching the {@code EOFException}. 347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * This class is intended for reading input that strictly consists of lines, such as line-based 367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * cache entries or cache journal. Unlike the {@link BufferedReader} which in conjunction with 377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * {@link InputStreamReader} provides similar functionality, this class uses different 387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * end-of-input reporting and a more restrictive definition of a line. 397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * and 10, respectively, and the representation of no other character contains these values. 427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. 437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * The default charset is US_ASCII. 447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathpublic class StrictLineReader implements Closeable { 467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private static final byte CR = (byte) '\r'; 477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private static final byte LF = (byte) '\n'; 487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private final InputStream in; 507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private final Charset charset; 517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /* 537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end 547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * and the data in the range [pos, end) is buffered for reading. At end of input, if there is 557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * an unterminated line, we set end == -1, otherwise end == pos. If the underlying 567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. 577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private byte[] buf; 597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private int pos; 607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private int end; 617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Constructs a new {@code StrictLineReader} with the default capacity and charset. 647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param in the {@code InputStream} to read data from. 667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws NullPointerException if {@code in} is null. 677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public StrictLineReader(InputStream in) { 697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath this(in, 8192); 707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Constructs a new {@code LineReader} with the specified capacity and the default charset. 747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param in the {@code InputStream} to read data from. 767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param capacity the capacity of the buffer. 777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws NullPointerException if {@code in} is null. 787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IllegalArgumentException for negative or zero {@code capacity}. 797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public StrictLineReader(InputStream in, int capacity) { 817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath this(in, capacity, Charsets.US_ASCII); 827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Constructs a new {@code LineReader} with the specified charset and the default capacity. 867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param in the {@code InputStream} to read data from. 887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param charset the charset used to decode data. 897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Only US-ASCII, UTF-8 and ISO-8859-1 is supported. 907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws NullPointerException if {@code in} or {@code charset} is null. 917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IllegalArgumentException if the specified charset is not supported. 927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public StrictLineReader(InputStream in, Charset charset) { 947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath this(in, 8192, charset); 957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Constructs a new {@code LineReader} with the specified capacity and charset. 997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 1007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param in the {@code InputStream} to read data from. 1017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param capacity the capacity of the buffer. 1027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @param charset the charset used to decode data. 1037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Only US-ASCII, UTF-8 and ISO-8859-1 is supported. 1047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws NullPointerException if {@code in} or {@code charset} is null. 1057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IllegalArgumentException if {@code capacity} is negative or zero 1067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * or the specified charset is not supported. 1077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 1087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public StrictLineReader(InputStream in, int capacity, Charset charset) { 1097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (in == null || charset == null) { 1107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new NullPointerException(); 1117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (capacity < 0) { 1137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new IllegalArgumentException("capacity <= 0"); 1147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (!(charset.equals(Charsets.US_ASCII) || charset.equals(Charsets.UTF_8) 1167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath || charset.equals(Charsets.ISO_8859_1))) { 1177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new IllegalArgumentException("Unsupported encoding"); 1187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath this.in = in; 1217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath this.charset = charset; 1227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath buf = new byte[capacity]; 1237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 1267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Closes the reader by closing the underlying {@code InputStream} and 1277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * marking this reader as closed. 1287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 1297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IOException for errors when closing the underlying {@code InputStream}. 1307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 1317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath @Override 1327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public void close() throws IOException { 1337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath synchronized (in) { 1347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (buf != null) { 1357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath buf = null; 1367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath in.close(); 1377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 1427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, 1437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * this end of line marker is not included in the result. 1447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 1457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @return the next line from the input. 1467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IOException for underlying {@code InputStream} errors. 1477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws EOFException for the end of source stream. 1487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 1497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public String readLine() throws IOException { 1507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath synchronized (in) { 1517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (buf == null) { 1527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new IOException("LineReader is closed"); 1537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Read more data if we are at the end of the buffered data. 1567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Though it's an error to read after an exception, we will let {@code fillBuf()} 1577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // throw again if that happens; thus we need to handle end == -1 as well as end == pos. 1587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (pos >= end) { 1597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath fillBuf(); 1607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Try to find LF in the buffered data and return the line if successful. 1627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath for (int i = pos; i != end; ++i) { 1637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (buf[i] == LF) { 1647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; 1657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath String res = new String(buf, pos, lineEnd - pos, charset); 1667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath pos = i + 1; 1677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath return res; 1687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Let's anticipate up to 80 characters on top of those already read. 1727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { 1737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath @Override 1747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public String toString() { 1757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; 1767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath return new String(buf, 0, length, charset); 1777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath }; 1797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath while (true) { 1817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath out.write(buf, pos, end - pos); 1827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Mark unterminated line in case fillBuf throws EOFException or IOException. 1837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath end = -1; 1847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath fillBuf(); 1857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath // Try to find LF in the buffered data and return the line if successful. 1867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath for (int i = pos; i != end; ++i) { 1877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (buf[i] == LF) { 1887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (i != pos) { 1897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath out.write(buf, pos, i - pos); 1907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath pos = i + 1; 1927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath return out.toString(); 1937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 1987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 2007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Read an {@code int} from a line containing its decimal representation. 2017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 2027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @return the value of the {@code int} from the next line. 2037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IOException for underlying {@code InputStream} errors or conversion error. 2047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws EOFException for the end of source stream. 2057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 2067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public int readInt() throws IOException { 2077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath String intString = readLine(); 2087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath try { 2097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath return Integer.parseInt(intString); 2107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } catch (NumberFormatException e) { 2117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new IOException("expected an int but was \"" + intString + "\""); 2127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 2157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 2167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Check whether there was an unterminated line at end of input after the line reader reported 2177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * end-of-input with EOFException. The value is meaningless in any other situation. 2187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 2197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @return true if there was an unterminated line at end of input. 2207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 2217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath public boolean hasUnterminatedLine() { 2227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath return end == -1; 2237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 2257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath /** 2267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Reads new input data into the buffer. Call only with pos == end or end == -1, 2277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * depending on the desired outcome if the function throws. 2287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 2297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws IOException for underlying {@code InputStream} errors. 2307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * @throws EOFException for the end of source stream. 2317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 2327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath private void fillBuf() throws IOException { 2337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath int result = in.read(buf, 0, buf.length); 2347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath if (result == -1) { 2357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath throw new EOFException(); 2367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath pos = 0; 2387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath end = result; 2397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath} 2417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 242