LineNumberInputStream.java revision fdb2704414a9ed92394ada0d1395e4db86889465
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
18package java.io;
19
20/**
21 * LineNumberInputStream is a filter class which counts the number of line
22 * terminators from the data read from the target InputStream. A line delimiter
23 * sequence is determined by '\r', '\n', or '\r\n'. When using <code>read</code>,
24 * the sequence is always translated into '\n'.
25 *
26 * @deprecated Use {@link LineNumberReader}
27 */
28@Deprecated
29public class LineNumberInputStream extends FilterInputStream {
30
31    private int lineNumber;
32
33    private int markedLineNumber = -1;
34
35    private int lastChar = -1;
36
37    private int markedLastChar;
38
39    /**
40     * Constructs a new LineNumberInputStream on the InputStream <code>in</code>.
41     * All reads are now filtered through this stream and line numbers will be
42     * counted for all data read from this Stream.
43     *
44     * @param in
45     *            The non-null InputStream to count line numbers.
46     */
47    public LineNumberInputStream(InputStream in) {
48        super(in);
49    }
50
51    /**
52     * Returns a int representing the number of bytes that are available before
53     * this LineNumberInputStream will block. This method returns the number of
54     * bytes available in the target stream. Since the target input stream may
55     * just be a sequence of <code>\r\n</code> characters and this filter only
56     * returns <code>\n<code> then <code>available</code> can only
57     * guarantee <code>target.available()/2</code> characters.
58     *
59     * @return int the number of bytes available before blocking.
60     *
61     * @throws IOException If an error occurs in this stream.
62     */
63    @Override
64    public int available() throws IOException {
65        return in.available() / 2 + (lastChar == -1 ? 0 : 1);
66    }
67
68    /**
69     * Returns a int representing the current line number for this
70     * LineNumberInputStream.
71     *
72     * @return int the current line number.
73     */
74    public int getLineNumber() {
75        return lineNumber;
76    }
77
78    /**
79     * Set a Mark position in this LineNumberInputStream. The parameter
80     * <code>readLimit</code> indicates how many bytes can be read before a
81     * mark is invalidated. Sending reset() will reposition the Stream back to
82     * the marked position provided <code>readLimit</code> has not been
83     * surpassed. The lineNumber count will also be reset to the last marked
84     * lineNumber count.
85     * <p>
86     * This implementation sets a mark in the target stream.
87     *
88     * @param readlimit
89     *            The number of bytes to be able to read before invalidating the
90     *            mark.
91     */
92    @Override
93    public void mark(int readlimit) {
94        in.mark(readlimit);
95        markedLineNumber = lineNumber;
96        markedLastChar = lastChar;
97    }
98
99    /**
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    @Override
114    public int read() throws IOException {
115        int currentChar = lastChar;
116        if (currentChar == -1) {
117            currentChar = in.read();
118        } else {
119            lastChar = -1;
120        }
121        switch (currentChar) {
122            case '\r':
123                currentChar = '\n';
124                lastChar = in.read();
125                if (lastChar == '\n') {
126                    lastChar = -1;
127                }
128                // fall through
129            case '\n':
130                lineNumber++;
131        }
132        return currentChar;
133    }
134
135    /**
136     * Reads at most <code>length</code> bytes from this LineNumberInputStream
137     * and stores them in byte array <code>buffer</code> starting at
138     * <code>offset</code>. Answer the number of bytes actually read or -1 if
139     * no bytes were read and end of stream was encountered. This implementation
140     * reads bytes from the target stream. The line number count is incremented
141     * if a line terminator is encountered. A line delimiter sequence is
142     * determined by '\r', '\n', or '\r\n'. In this method, the sequence is
143     * always translated into '\n'.
144     *
145     * @param buffer
146     *            the non-null byte array in which to store the read bytes.
147     * @param offset
148     *            the offset in <code>buffer</code> to store the read bytes.
149     * @param length
150     *            the maximum number of bytes to store in <code>buffer</code>.
151     * @return The number of bytes actually read or -1 if end of stream.
152     *
153     * @throws IOException
154     *             If the stream is already closed or another IOException
155     *             occurs.
156     * @throws NullPointerException
157     *             If <code>buffer</code> is <code>null</code>.
158     * @throws IllegalArgumentException
159     *             If <code>offset</code> or <code>count</code> are out of
160     *             bounds.
161     */
162    @Override
163    public int read(byte[] buffer, int offset, int length) throws IOException {
164        if (buffer == null) {
165            throw new NullPointerException();
166        }
167        // avoid int overflow
168        if (offset < 0 || offset > buffer.length || length < 0
169                || length > buffer.length - offset) {
170            throw new ArrayIndexOutOfBoundsException();
171        }
172
173        for (int i = 0; i < length; i++) {
174            int currentChar;
175            try {
176                currentChar = read();
177            } catch (IOException e) {
178                if (i != 0) {
179                    return i;
180                }
181                throw e;
182            }
183            if (currentChar == -1) {
184                return i == 0 ? -1 : i;
185            }
186            buffer[offset + i] = (byte) currentChar;
187        }
188        return length;
189    }
190
191    /**
192     * Reset this LineNumberInputStream to the last marked location. If the
193     * <code>readlimit</code> has been passed or no <code>mark</code> has
194     * been set, throw IOException. This implementation resets the target
195     * stream. It also resets the line count to what is was when this Stream was
196     * marked.
197     *
198     * @throws IOException
199     *             If the stream is already closed or another IOException
200     *             occurs.
201     */
202    @Override
203    public void reset() throws IOException {
204        in.reset();
205        lineNumber = markedLineNumber;
206        lastChar = markedLastChar;
207    }
208
209    /**
210     * Sets the lineNumber of this LineNumberInputStream to the specified
211     * <code>lineNumber</code>. Note that this may have side effects on the
212     * line number associated with the last marked position.
213     *
214     * @param lineNumber
215     *            the new lineNumber value.
216     */
217    public void setLineNumber(int lineNumber) {
218        this.lineNumber = lineNumber;
219    }
220
221    /**
222     * Skips <code>count</code> number of bytes in this InputStream.
223     * Subsequent <code>read()</code>'s will not return these bytes unless
224     * <code>reset()</code> is used. This implementation skips
225     * <code>count</code> number of bytes in the target stream and increments
226     * the lineNumber count as bytes are skipped.
227     *
228     * @param count
229     *            the number of bytes to skip.
230     * @return the number of bytes actually skipped.
231     *
232     * @throws IOException
233     *             If the stream is already closed or another IOException
234     *             occurs.
235     */
236    @Override
237    public long skip(long count) throws IOException {
238        if (count <= 0) {
239            return 0;
240        }
241        for (int i = 0; i < count; i++) {
242            int currentChar = read();
243            if (currentChar == -1) {
244                return i;
245            }
246        }
247        return count;
248    }
249}
250