• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.io;
19 
20 import java.util.Arrays;
21 import libcore.io.Streams;
22 
23 /**
24  * Wraps an existing {@link InputStream} and counts the line terminators
25  * encountered while reading the data. Line numbering starts at 0. Recognized
26  * line terminator sequences are {@code '\r'}, {@code '\n'} and {@code "\r\n"}.
27  * When using {@code read}, line terminator sequences are always translated into
28  * {@code '\n'}.
29  *
30  * @deprecated Use {@link LineNumberReader} instead.
31  */
32 @Deprecated
33 public class LineNumberInputStream extends FilterInputStream {
34 
35     private int lineNumber;
36 
37     private int markedLineNumber = -1;
38 
39     private int lastChar = -1;
40 
41     private int markedLastChar;
42 
43     /**
44      * Constructs a new {@code LineNumberInputStream} on the {@link InputStream}
45      * {@code in}. Line numbers are counted for all data read from this stream.
46      *
47      * <p><strong>Warning:</strong> passing a null source creates an invalid
48      * {@code LineNumberInputStream}. All operations on such a stream will fail.
49      *
50      * @param in
51      *            The non-null input stream to count line numbers.
52      */
LineNumberInputStream(InputStream in)53     public LineNumberInputStream(InputStream in) {
54         super(in);
55     }
56 
57     /**
58      * {@inheritDoc}
59      *
60      * <p>Note that the source stream may just be a sequence of {@code "\r\n"} bytes
61      * which are converted into {@code '\n'} by this stream. Therefore,
62      * {@code available} returns only {@code in.available() / 2} bytes as
63      * result.
64      */
65     @Override
available()66     public int available() throws IOException {
67         return in.available() / 2 + (lastChar == -1 ? 0 : 1);
68     }
69 
70     /**
71      * Returns the current line number for this stream. Numbering starts at 0.
72      *
73      * @return the current line number.
74      */
getLineNumber()75     public int getLineNumber() {
76         return lineNumber;
77     }
78 
79     /**
80      * Sets a mark position in this stream. The parameter {@code readlimit}
81      * indicates how many bytes can be read before the mark is invalidated.
82      * Sending {@code reset()} will reposition this stream back to the marked
83      * position, provided that {@code readlimit} has not been surpassed.
84      * The line number count will also be reset to the last marked
85      * line number count.
86      * <p>
87      * This implementation sets a mark in the filtered stream.
88      *
89      * @param readlimit
90      *            the number of bytes that can be read from this stream before
91      *            the mark is invalidated.
92      * @see #markSupported()
93      * @see #reset()
94      */
95     @Override
mark(int readlimit)96     public void mark(int readlimit) {
97         in.mark(readlimit);
98         markedLineNumber = lineNumber;
99         markedLastChar = lastChar;
100     }
101 
102     /**
103      * Reads a single byte from the filtered stream and returns it as an integer
104      * in the range from 0 to 255. Returns -1 if the end of this stream has been
105      * reached.
106      * <p>
107      * The line number count is incremented if a line terminator is encountered.
108      * Recognized line terminator sequences are {@code '\r'}, {@code '\n'} and
109      * {@code "\r\n"}. Line terminator sequences are always translated into
110      * {@code '\n'}.
111      *
112      * @return the byte read or -1 if the end of the filtered stream has been
113      *         reached.
114      * @throws IOException
115      *             if the stream is closed or another IOException occurs.
116      */
117     @SuppressWarnings("fallthrough")
118     @Override
read()119     public int read() throws IOException {
120         int currentChar = lastChar;
121         if (currentChar == -1) {
122             currentChar = in.read();
123         } else {
124             lastChar = -1;
125         }
126         switch (currentChar) {
127             case '\r':
128                 currentChar = '\n';
129                 lastChar = in.read();
130                 if (lastChar == '\n') {
131                     lastChar = -1;
132                 }
133                 // fall through
134             case '\n':
135                 lineNumber++;
136         }
137         return currentChar;
138     }
139 
140     /**
141      * Reads up to {@code byteCount} bytes from the filtered stream and stores
142      * them in the byte array {@code buffer} starting at {@code byteOffset}.
143      * Returns the number of bytes actually read or -1 if no bytes have been
144      * read and the end of this stream has been reached.
145      *
146      * <p>The line number count is incremented if a line terminator is encountered.
147      * Recognized line terminator sequences are {@code '\r'}, {@code '\n'} and
148      * {@code "\r\n"}. Line terminator sequences are always translated into
149      * {@code '\n'}.
150      *
151      * @throws IndexOutOfBoundsException
152      *     if {@code byteOffset < 0 || byteCount < 0 || byteOffset + byteCount > buffer.length}.
153      * @throws IOException
154      *             if this stream is closed or another IOException occurs.
155      * @throws NullPointerException
156      *             if {@code buffer == null}.
157      */
158     @Override
read(byte[] buffer, int byteOffset, int byteCount)159     public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
160         Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount);
161         for (int i = 0; i < byteCount; ++i) {
162             int currentChar;
163             try {
164                 currentChar = read();
165             } catch (IOException e) {
166                 if (i != 0) {
167                     return i;
168                 }
169                 throw e;
170             }
171             if (currentChar == -1) {
172                 return i == 0 ? -1 : i;
173             }
174             buffer[byteOffset + i] = (byte) currentChar;
175         }
176         return byteCount;
177     }
178 
179     /**
180      * Resets this stream to the last marked location. It also resets the line
181      * count to what is was when this stream was marked.
182      *
183      * @throws IOException
184      *             if this stream is already closed, no mark has been set or the
185      *             mark is no longer valid because more than {@code readlimit}
186      *             bytes have been read since setting the mark.
187      * @see #mark(int)
188      * @see #markSupported()
189      */
190     @Override
reset()191     public void reset() throws IOException {
192         in.reset();
193         lineNumber = markedLineNumber;
194         lastChar = markedLastChar;
195     }
196 
197     /**
198      * Sets the line number of this stream to the specified
199      * {@code lineNumber}. Note that this may have side effects on the
200      * line number associated with the last marked position.
201      *
202      * @param lineNumber
203      *            the new lineNumber value.
204      * @see #mark(int)
205      * @see #reset()
206      */
setLineNumber(int lineNumber)207     public void setLineNumber(int lineNumber) {
208         this.lineNumber = lineNumber;
209     }
210 
211     /**
212      * Skips {@code count} number of bytes in this stream. Subsequent
213      * calls to {@code read} will not return these bytes unless {@code reset} is
214      * used. This implementation skips {@code byteCount} bytes in the
215      * filtered stream and increments the line number count whenever line
216      * terminator sequences are skipped.
217      *
218      * @param byteCount
219      *            the number of bytes to skip.
220      * @return the number of bytes actually skipped.
221      * @throws IOException
222      *             if this stream is closed or another IOException occurs.
223      * @see #mark(int)
224      * @see #read()
225      * @see #reset()
226      */
227     @Override
skip(long byteCount)228     public long skip(long byteCount) throws IOException {
229         return Streams.skipByReading(this, byteCount);
230     }
231 }
232