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: }
|