OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / io / LineNumberReader.java
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 /**
21  * Wraps an existing {@link Reader} and counts the line terminators encountered
22  * while reading the data. The line number starts at 0 and is incremented any
23  * time {@code '\r'}, {@code '\n'} or {@code "\r\n"} is read. The class has an
24  * internal buffer for its data. The size of the buffer defaults to 8 KB.
25  */
26 public class LineNumberReader extends BufferedReader {
27
28     private int lineNumber;
29
30     private int markedLineNumber = -1;
31
32     private boolean lastWasCR;
33
34     private boolean markedLastWasCR;
35
36     /**
37      * Constructs a new LineNumberReader on the Reader {@code in}. The internal
38      * buffer gets the default size (8 KB).
39      *
40      * @param in
41      *            the Reader that is buffered.
42      */
43     public LineNumberReader(Reader in) {
44         super(in);
45     }
46
47     /**
48      * Constructs a new LineNumberReader on the Reader {@code in}. The size of
49      * the internal buffer is specified by the parameter {@code size}.
50      *
51      * @param in
52      *            the Reader that is buffered.
53      * @param size
54      *            the size of the buffer to allocate.
55      * @throws IllegalArgumentException
56      *             if {@code size <= 0}.
57      */
58     public LineNumberReader(Reader in, int size) {
59         super(in, size);
60     }
61
62     /**
63      * Returns the current line number for this reader. Numbering starts at 0.
64      *
65      * @return the current line number.
66      */
67     public int getLineNumber() {
68         synchronized (lock) {
69             return lineNumber;
70         }
71     }
72
73     /**
74      * Sets a mark position in this reader. The parameter {@code readlimit}
75      * indicates how many characters can be read before the mark is invalidated.
76      * Sending {@code reset()} will reposition this reader back to the marked
77      * position, provided that {@code readlimit} has not been surpassed. The
78      * line number associated with this marked position is also stored so that
79      * it can be restored when {@code reset()} is called.
80      *
81      * @param readlimit
82      *            the number of characters that can be read from this stream
83      *            before the mark is invalidated.
84      * @throws IOException
85      *             if an error occurs while setting the mark in this reader.
86      * @see #markSupported()
87      * @see #reset()
88      */
89     @Override
90     public void mark(int readlimit) throws IOException {
91         synchronized (lock) {
92             super.mark(readlimit);
93             markedLineNumber = lineNumber;
94             markedLastWasCR = lastWasCR;
95         }
96     }
97
98     /**
99      * Reads a single character from the source reader and returns it as an
100      * integer with the two higher-order bytes set to 0. Returns -1 if the end
101      * of the source reader has been reached.
102      * <p>
103      * The line number count is incremented if a line terminator is encountered.
104      * Recognized line terminator sequences are {@code '\r'}, {@code '\n'} and
105      * {@code "\r\n"}. Line terminator sequences are always translated into
106      * {@code '\n'}.
107      *
108      * @return the character read or -1 if the end of the source reader has been
109      *         reached.
110      * @throws IOException
111      *             if the reader is closed or another IOException occurs.
112      */
113     @SuppressWarnings("fallthrough")
114     @Override
115     public int read() throws IOException {
116         synchronized (lock) {
117             int ch = super.read();
118             if (ch == '\n' && lastWasCR) {
119                 ch = super.read();
120             }
121             lastWasCR = false;
122             switch (ch) {
123                 case '\r':
124                     ch = '\n';
125                     lastWasCR = true;
126                     // fall through
127                 case '\n':
128                     lineNumber++;
129             }
130             return ch;
131         }
132     }
133
134     /**
135      * Reads at most {@code count} characters from the source reader and stores
136      * them in the character array {@code buffer} starting at {@code offset}.
137      * Returns the number of characters actually read or -1 if no characters
138      * have been read and the end of this reader has been reached.
139      * <p>
140      * The line number count is incremented if a line terminator is encountered.
141      * Recognized line terminator sequences are {@code '\r'}, {@code '\n'} and
142      * {@code "\r\n"}.
143      *
144      * @param buffer
145      *            the array in which to store the characters read.
146      * @param offset
147      *            the initial position in {@code buffer} to store the characters
148      *            read from this reader.
149      * @param count
150      *            the maximum number of characters to store in {@code buffer}.
151      * @return the number of characters actually read or -1 if the end of the
152      *         source reader has been reached while reading.
153      * @throws IOException
154      *             if this reader is closed or another IOException occurs.
155      */
156     @Override
157     public int read(char[] buffer, int offset, int count) throws IOException {
158         synchronized (lock) {
159             int read = super.read(buffer, offset, count);
160             if (read == -1) {
161                 return -1;
162             }
163             for (int i = 0; i < read; i++) {
164                 char ch = buffer[offset + i];
165                 if (ch == '\r') {
166                     lineNumber++;
167                     lastWasCR = true;
168                 } else if (ch == '\n') {
169                     if (!lastWasCR) {
170                         lineNumber++;
171                     }
172                     lastWasCR = false;
173                 } else {
174                     lastWasCR = false;
175                 }
176             }
177             return read;
178         }
179     }
180
181     /**
182      * Returns the next line of text available from this reader. A line is
183      * represented by 0 or more characters followed by {@code '\r'},
184      * {@code '\n'}, {@code "\r\n"} or the end of the stream. The returned
185      * string does not include the newline sequence.
186      *
187      * @return the contents of the line or {@code null} if no characters have
188      *         been read before the end of the stream has been reached.
189      * @throws IOException
190      *             if this reader is closed or another IOException occurs.
191      */
192     @Override
193     public String readLine() throws IOException {
194         synchronized (lock) {
195             if (lastWasCR) {
196                 chompNewline();
197                 lastWasCR = false;
198             }
199             String result = super.readLine();
200             if (result != null) {
201                 lineNumber++;
202             }
203             return result;
204         }
205     }
206
207     /**
208      * Resets this reader to the last marked location. It also resets the line
209      * count to what is was when this reader was marked. This implementation
210      * resets the source reader.
211      *
212      * @throws IOException
213      *             if this reader is already closed, no mark has been set or the
214      *             mark is no longer valid because more than {@code readlimit}
215      *             bytes have been read since setting the mark.
216      * @see #mark(int)
217      * @see #markSupported()
218      */
219     @Override
220     public void reset() throws IOException {
221         synchronized (lock) {
222             super.reset();
223             lineNumber = markedLineNumber;
224             lastWasCR = markedLastWasCR;
225         }
226     }
227
228     /**
229      * Sets the line number of this reader to the specified {@code lineNumber}.
230      * Note that this may have side effects on the line number associated with
231      * the last marked position.
232      *
233      * @param lineNumber
234      *            the new line number value.
235      * @see #mark(int)
236      * @see #reset()
237      */
238     public void setLineNumber(int lineNumber) {
239         synchronized (lock) {
240             this.lineNumber = lineNumber;
241         }
242     }
243
244     /**
245      * Skips {@code count} number of characters in this reader. Subsequent
246      * {@code read()}'s will not return these characters unless {@code reset()}
247      * is used. This implementation skips {@code count} number of characters in
248      * the source reader and increments the line number count whenever line
249      * terminator sequences are skipped.
250      *
251      * @param count
252      *            the number of characters to skip.
253      * @return the number of characters actually skipped.
254      * @throws IllegalArgumentException
255      *             if {@code count < 0}.
256      * @throws IOException
257      *             if this reader is closed or another IOException occurs.
258      * @see #mark(int)
259      * @see #read()
260      * @see #reset()
261      */
262     @Override
263     public long skip(long count) throws IOException {
264         if (count < 0) {
265             throw new IllegalArgumentException();
266         }
267         synchronized (lock) {
268             for (int i = 0; i < count; i++) {
269                 if (read() == -1) {
270                     return i;
271                 }
272             }
273             return count;
274         }
275     }
276 }