001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: /**
021: * LineNumberInputStream is a filter class which counts the number of line
022: * terminators from the data read from the target InputStream. A line delimiter
023: * sequence is determined by '\r', '\n', or '\r\n'. When using <code>read</code>,
024: * the sequence is always translated into '\n'.
025: *
026: * @deprecated Use LineNumberReader
027: */
028: @Deprecated
029: public class LineNumberInputStream extends FilterInputStream {
030:
031: private int lineNumber;
032:
033: private int markedLineNumber = -1;
034:
035: private int lastChar = -1;
036:
037: private int markedLastChar;
038:
039: /**
040: * Constructs a new LineNumberInputStream on the InputStream <code>in</code>.
041: * All reads are now filtered through this stream and line numbers will be
042: * counted for all data read from this Stream.
043: *
044: * @param in
045: * The non-null InputStream to count line numbers.
046: */
047: public LineNumberInputStream(InputStream in) {
048: super (in);
049: }
050:
051: /**
052: * Answers a int representing the number of bytes that are available before
053: * this LineNumberInputStream will block. This method returns the number of
054: * bytes available in the target stream. Since the target input stream may
055: * just be a sequence of <code>\r\n</code> characters and this filter only
056: * returns <code>\n<code> then <code>available</code> can only
057: * guarantee <code>target.available()/2</code> characters.
058: *
059: * @return int the number of bytes available before blocking.
060: *
061: * @throws IOException If an error occurs in this stream.
062: */
063: @Override
064: public int available() throws IOException {
065: return in.available() / 2 + (lastChar == -1 ? 0 : 1);
066: }
067:
068: /**
069: * Answers a int representing the current line number for this
070: * LineNumberInputStream.
071: *
072: * @return int the current line number.
073: */
074: public int getLineNumber() {
075: return lineNumber;
076: }
077:
078: /**
079: * Set a Mark position in this LineNumberInputStream. The parameter
080: * <code>readLimit</code> indicates how many bytes can be read before a
081: * mark is invalidated. Sending reset() will reposition the Stream back to
082: * the marked position provided <code>readLimit</code> has not been
083: * surpassed. The lineNumber count will also be reset to the last marked
084: * lineNumber count.
085: * <p>
086: * This implementation sets a mark in the target stream.
087: *
088: * @param readlimit
089: * The number of bytes to be able to read before invalidating the
090: * mark.
091: */
092: @Override
093: public void mark(int readlimit) {
094: in.mark(readlimit);
095: markedLineNumber = lineNumber;
096: markedLastChar = lastChar;
097: }
098:
099: /**
100: * Reads a single byte from this LineNumberInputStream and returns the
101: * result as an int. The low-order byte is returned or -1 of the end of
102: * stream was encountered. This implementation returns a byte from the
103: * target stream. The line number count is incremented if a line terminator
104: * is encountered. A line delimiter sequence is determined by '\r', '\n', or
105: * '\r\n'. In this method, the sequence is always translated into '\n'.
106: *
107: * @return int The byte read or -1 if end of stream.
108: *
109: * @throws IOException
110: * If the stream is already closed or another IOException
111: * occurs.
112: */
113: @SuppressWarnings("fallthrough")
114: @Override
115: public int read() throws IOException {
116: int currentChar = lastChar;
117: if (currentChar == -1) {
118: currentChar = in.read();
119: } else {
120: lastChar = -1;
121: }
122: switch (currentChar) {
123: case '\r':
124: currentChar = '\n';
125: lastChar = in.read();
126: if (lastChar == '\n') {
127: lastChar = -1;
128: }
129: // fall through
130: case '\n':
131: lineNumber++;
132: }
133: return currentChar;
134: }
135:
136: /**
137: * Reads at most <code>length</code> bytes from this LineNumberInputStream
138: * and stores them in byte array <code>buffer</code> starting at
139: * <code>offset</code>. Answer the number of bytes actually read or -1 if
140: * no bytes were read and end of stream was encountered. This implementation
141: * reads bytes from the target stream. The line number count is incremented
142: * if a line terminator is encountered. A line delimiter sequence is
143: * determined by '\r', '\n', or '\r\n'. In this method, the sequence is
144: * always translated into '\n'.
145: *
146: * @param buffer
147: * the non-null byte array in which to store the read bytes.
148: * @param offset
149: * the offset in <code>buffer</code> to store the read bytes.
150: * @param length
151: * the maximum number of bytes to store in <code>buffer</code>.
152: * @return The number of bytes actually read or -1 if end of stream.
153: *
154: * @throws IOException
155: * If the stream is already closed or another IOException
156: * occurs.
157: * @throws NullPointerException
158: * If <code>buffer</code> is <code>null</code>.
159: * @throws IllegalArgumentException
160: * If <code>offset</code> or <code>count</code> are out of
161: * bounds.
162: */
163: @Override
164: public int read(byte[] buffer, int offset, int length)
165: throws IOException {
166: if (buffer == null) {
167: throw new NullPointerException();
168: }
169: // avoid int overflow
170: if (offset < 0 || offset > buffer.length || length < 0
171: || length > buffer.length - offset) {
172: throw new ArrayIndexOutOfBoundsException();
173: }
174:
175: for (int i = 0; i < length; i++) {
176: int currentChar;
177: try {
178: currentChar = read();
179: } catch (IOException e) {
180: if (i != 0) {
181: return i;
182: }
183: throw e;
184: }
185: if (currentChar == -1) {
186: return i == 0 ? -1 : i;
187: }
188: buffer[offset + i] = (byte) currentChar;
189: }
190: return length;
191: }
192:
193: /**
194: * Reset this LineNumberInputStream to the last marked location. If the
195: * <code>readlimit</code> has been passed or no <code>mark</code> has
196: * been set, throw IOException. This implementation resets the target
197: * stream. It also resets the line count to what is was when this Stream was
198: * marked.
199: *
200: * @throws IOException
201: * If the stream is already closed or another IOException
202: * occurs.
203: */
204: @Override
205: public void reset() throws IOException {
206: in.reset();
207: lineNumber = markedLineNumber;
208: lastChar = markedLastChar;
209: }
210:
211: /**
212: * Sets the lineNumber of this LineNumberInputStream to the specified
213: * <code>lineNumber</code>. Note that this may have side effects on the
214: * line number associated with the last marked position.
215: *
216: * @param lineNumber
217: * the new lineNumber value.
218: */
219: public void setLineNumber(int lineNumber) {
220: this .lineNumber = lineNumber;
221: }
222:
223: /**
224: * Skips <code>count</code> number of bytes in this InputStream.
225: * Subsequent <code>read()</code>'s will not return these bytes unless
226: * <code>reset()</code> is used. This implementation skips
227: * <code>count</code> number of bytes in the target stream and increments
228: * the lineNumber count as bytes are skipped.
229: *
230: * @param count
231: * the number of bytes to skip.
232: * @return the number of bytes actually skipped.
233: *
234: * @throws IOException
235: * If the stream is already closed or another IOException
236: * occurs.
237: */
238: @Override
239: public long skip(long count) throws IOException {
240: if (count <= 0) {
241: return 0;
242: }
243: for (int i = 0; i < count; i++) {
244: int currentChar = read();
245: if (currentChar == -1) {
246: return i;
247: }
248: }
249: return count;
250: }
251: }
|