001 /*
002 * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.io;
027
028 /**
029 * This class is an input stream filter that provides the added
030 * functionality of keeping track of the current line number.
031 * <p>
032 * A line is a sequence of bytes ending with a carriage return
033 * character (<code>'\r'</code>), a newline character
034 * (<code>'\n'</code>), or a carriage return character followed
035 * immediately by a linefeed character. In all three cases, the line
036 * terminating character(s) are returned as a single newline character.
037 * <p>
038 * The line number begins at <code>0</code>, and is incremented by
039 * <code>1</code> when a <code>read</code> returns a newline character.
040 *
041 * @author Arthur van Hoff
042 * @version 1.34, 05/05/07
043 * @see java.io.LineNumberReader
044 * @since JDK1.0
045 * @deprecated This class incorrectly assumes that bytes adequately represent
046 * characters. As of JDK 1.1, the preferred way to operate on
047 * character streams is via the new character-stream classes, which
048 * include a class for counting line numbers.
049 */
050 @Deprecated
051 public class LineNumberInputStream extends FilterInputStream {
052 int pushBack = -1;
053 int lineNumber;
054 int markLineNumber;
055 int markPushBack = -1;
056
057 /**
058 * Constructs a newline number input stream that reads its input
059 * from the specified input stream.
060 *
061 * @param in the underlying input stream.
062 */
063 public LineNumberInputStream(InputStream in) {
064 super (in);
065 }
066
067 /**
068 * Reads the next byte of data from this input stream. The value
069 * byte is returned as an <code>int</code> in the range
070 * <code>0</code> to <code>255</code>. If no byte is available
071 * because the end of the stream has been reached, the value
072 * <code>-1</code> is returned. This method blocks until input data
073 * is available, the end of the stream is detected, or an exception
074 * is thrown.
075 * <p>
076 * The <code>read</code> method of
077 * <code>LineNumberInputStream</code> calls the <code>read</code>
078 * method of the underlying input stream. It checks for carriage
079 * returns and newline characters in the input, and modifies the
080 * current line number as appropriate. A carriage-return character or
081 * a carriage return followed by a newline character are both
082 * converted into a single newline character.
083 *
084 * @return the next byte of data, or <code>-1</code> if the end of this
085 * stream is reached.
086 * @exception IOException if an I/O error occurs.
087 * @see java.io.FilterInputStream#in
088 * @see java.io.LineNumberInputStream#getLineNumber()
089 */
090 public int read() throws IOException {
091 int c = pushBack;
092
093 if (c != -1) {
094 pushBack = -1;
095 } else {
096 c = in.read();
097 }
098
099 switch (c) {
100 case '\r':
101 pushBack = in.read();
102 if (pushBack == '\n') {
103 pushBack = -1;
104 }
105 case '\n':
106 lineNumber++;
107 return '\n';
108 }
109 return c;
110 }
111
112 /**
113 * Reads up to <code>len</code> bytes of data from this input stream
114 * into an array of bytes. This method blocks until some input is available.
115 * <p>
116 * The <code>read</code> method of
117 * <code>LineNumberInputStream</code> repeatedly calls the
118 * <code>read</code> method of zero arguments to fill in the byte array.
119 *
120 * @param b the buffer into which the data is read.
121 * @param off the start offset of the data.
122 * @param len the maximum number of bytes read.
123 * @return the total number of bytes read into the buffer, or
124 * <code>-1</code> if there is no more data because the end of
125 * this stream has been reached.
126 * @exception IOException if an I/O error occurs.
127 * @see java.io.LineNumberInputStream#read()
128 */
129 public int read(byte b[], int off, int len) throws IOException {
130 if (b == null) {
131 throw new NullPointerException();
132 } else if ((off < 0) || (off > b.length) || (len < 0)
133 || ((off + len) > b.length) || ((off + len) < 0)) {
134 throw new IndexOutOfBoundsException();
135 } else if (len == 0) {
136 return 0;
137 }
138
139 int c = read();
140 if (c == -1) {
141 return -1;
142 }
143 b[off] = (byte) c;
144
145 int i = 1;
146 try {
147 for (; i < len; i++) {
148 c = read();
149 if (c == -1) {
150 break;
151 }
152 if (b != null) {
153 b[off + i] = (byte) c;
154 }
155 }
156 } catch (IOException ee) {
157 }
158 return i;
159 }
160
161 /**
162 * Skips over and discards <code>n</code> bytes of data from this
163 * input stream. The <code>skip</code> method may, for a variety of
164 * reasons, end up skipping over some smaller number of bytes,
165 * possibly <code>0</code>. The actual number of bytes skipped is
166 * returned. If <code>n</code> is negative, no bytes are skipped.
167 * <p>
168 * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
169 * a byte array and then repeatedly reads into it until
170 * <code>n</code> bytes have been read or the end of the stream has
171 * been reached.
172 *
173 * @param n the number of bytes to be skipped.
174 * @return the actual number of bytes skipped.
175 * @exception IOException if an I/O error occurs.
176 * @see java.io.FilterInputStream#in
177 */
178 public long skip(long n) throws IOException {
179 int chunk = 2048;
180 long remaining = n;
181 byte data[];
182 int nr;
183
184 if (n <= 0) {
185 return 0;
186 }
187
188 data = new byte[chunk];
189 while (remaining > 0) {
190 nr = read(data, 0, (int) Math.min(chunk, remaining));
191 if (nr < 0) {
192 break;
193 }
194 remaining -= nr;
195 }
196
197 return n - remaining;
198 }
199
200 /**
201 * Sets the line number to the specified argument.
202 *
203 * @param lineNumber the new line number.
204 * @see #getLineNumber
205 */
206 public void setLineNumber(int lineNumber) {
207 this .lineNumber = lineNumber;
208 }
209
210 /**
211 * Returns the current line number.
212 *
213 * @return the current line number.
214 * @see #setLineNumber
215 */
216 public int getLineNumber() {
217 return lineNumber;
218 }
219
220 /**
221 * Returns the number of bytes that can be read from this input
222 * stream without blocking.
223 * <p>
224 * Note that if the underlying input stream is able to supply
225 * <i>k</i> input characters without blocking, the
226 * <code>LineNumberInputStream</code> can guarantee only to provide
227 * <i>k</i>/2 characters without blocking, because the
228 * <i>k</i> characters from the underlying input stream might
229 * consist of <i>k</i>/2 pairs of <code>'\r'</code> and
230 * <code>'\n'</code>, which are converted to just
231 * <i>k</i>/2 <code>'\n'</code> characters.
232 *
233 * @return the number of bytes that can be read from this input stream
234 * without blocking.
235 * @exception IOException if an I/O error occurs.
236 * @see java.io.FilterInputStream#in
237 */
238 public int available() throws IOException {
239 return (pushBack == -1) ? super .available() / 2 : super
240 .available() / 2 + 1;
241 }
242
243 /**
244 * Marks the current position in this input stream. A subsequent
245 * call to the <code>reset</code> method repositions this stream at
246 * the last marked position so that subsequent reads re-read the same bytes.
247 * <p>
248 * The <code>mark</code> method of
249 * <code>LineNumberInputStream</code> remembers the current line
250 * number in a private variable, and then calls the <code>mark</code>
251 * method of the underlying input stream.
252 *
253 * @param readlimit the maximum limit of bytes that can be read before
254 * the mark position becomes invalid.
255 * @see java.io.FilterInputStream#in
256 * @see java.io.LineNumberInputStream#reset()
257 */
258 public void mark(int readlimit) {
259 markLineNumber = lineNumber;
260 markPushBack = pushBack;
261 in.mark(readlimit);
262 }
263
264 /**
265 * Repositions this stream to the position at the time the
266 * <code>mark</code> method was last called on this input stream.
267 * <p>
268 * The <code>reset</code> method of
269 * <code>LineNumberInputStream</code> resets the line number to be
270 * the line number at the time the <code>mark</code> method was
271 * called, and then calls the <code>reset</code> method of the
272 * underlying input stream.
273 * <p>
274 * Stream marks are intended to be used in
275 * situations where you need to read ahead a little to see what's in
276 * the stream. Often this is most easily done by invoking some
277 * general parser. If the stream is of the type handled by the
278 * parser, it just chugs along happily. If the stream is not of
279 * that type, the parser should toss an exception when it fails,
280 * which, if it happens within readlimit bytes, allows the outer
281 * code to reset the stream and try another parser.
282 *
283 * @exception IOException if an I/O error occurs.
284 * @see java.io.FilterInputStream#in
285 * @see java.io.LineNumberInputStream#mark(int)
286 */
287 public void reset() throws IOException {
288 lineNumber = markLineNumber;
289 pushBack = markPushBack;
290 in.reset();
291 }
292 }
|