1. /*
  2. * @(#)LineNumberInputStream.java 1.22 00/02/02
  3. *
  4. * Copyright 1995-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.io;
  11. /**
  12. * This class is an input stream filter that provides the added
  13. * functionality of keeping track of the current line number.
  14. * <p>
  15. * A line is a sequence of bytes ending with a carriage return
  16. * character (<code>'\r'</code>), a newline character
  17. * (<code>'\n'</code>), or a carriage return character followed
  18. * immediately by a linefeed character. In all three cases, the line
  19. * terminating character(s) are returned as a single newline character.
  20. * <p>
  21. * The line number begins at <code>0</code>, and is incremented by
  22. * <code>1</code> when a <code>read</code> returns a newline character.
  23. *
  24. * @author Arthur van Hoff
  25. * @version 1.22, 02/02/00
  26. * @see java.io.LineNumberReader
  27. * @since JDK1.0
  28. * @deprecated This class incorrectly assumes that bytes adequately represent
  29. * characters. As of JDK 1.1, the preferred way to operate on
  30. * character streams is via the new character-stream classes, which
  31. * include a class for counting line numbers.
  32. */
  33. public
  34. class LineNumberInputStream extends FilterInputStream {
  35. int pushBack = -1;
  36. int lineNumber;
  37. int markLineNumber;
  38. int markPushBack = -1;
  39. /**
  40. * Constructs a newline number input stream that reads its input
  41. * from the specified input stream.
  42. *
  43. * @param in the underlying input stream.
  44. */
  45. public LineNumberInputStream(InputStream in) {
  46. super(in);
  47. }
  48. /**
  49. * Reads the next byte of data from this input stream. The value
  50. * byte is returned as an <code>int</code> in the range
  51. * <code>0</code> to <code>255</code>. If no byte is available
  52. * because the end of the stream has been reached, the value
  53. * <code>-1</code> is returned. This method blocks until input data
  54. * is available, the end of the stream is detected, or an exception
  55. * is thrown.
  56. * <p>
  57. * The <code>read</code> method of
  58. * <code>LineNumberInputStream</code> calls the <code>read</code>
  59. * method of the underlying input stream. It checks for carriage
  60. * returns and newline characters in the input, and modifies the
  61. * current line number as appropriate. A carriage-return character or
  62. * a carriage return followed by a newline character are both
  63. * converted into a single newline character.
  64. *
  65. * @return the next byte of data, or <code>-1</code> if the end of this
  66. * stream is reached.
  67. * @exception IOException if an I/O error occurs.
  68. * @see java.io.FilterInputStream#in
  69. * @see java.io.LineNumberInputStream#getLineNumber()
  70. */
  71. public int read() throws IOException {
  72. int c = pushBack;
  73. if (c != -1) {
  74. pushBack = -1;
  75. } else {
  76. c = in.read();
  77. }
  78. switch (c) {
  79. case '\r':
  80. pushBack = in.read();
  81. if (pushBack == '\n') {
  82. pushBack = -1;
  83. }
  84. case '\n':
  85. lineNumber++;
  86. return '\n';
  87. }
  88. return c;
  89. }
  90. /**
  91. * Reads up to <code>len</code> bytes of data from this input stream
  92. * into an array of bytes. This method blocks until some input is available.
  93. * <p>
  94. * The <code>read</code> method of
  95. * <code>LineNumberInputStream</code> repeatedly calls the
  96. * <code>read</code> method of zero arguments to fill in the byte array.
  97. *
  98. * @param b the buffer into which the data is read.
  99. * @param off the start offset of the data.
  100. * @param len the maximum number of bytes read.
  101. * @return the total number of bytes read into the buffer, or
  102. * <code>-1</code> if there is no more data because the end of
  103. * this stream has been reached.
  104. * @exception IOException if an I/O error occurs.
  105. * @see java.io.LineNumberInputStream#read()
  106. */
  107. public int read(byte b[], int off, int len) throws IOException {
  108. if (b == null) {
  109. throw new NullPointerException();
  110. } else if ((off < 0) || (off > b.length) || (len < 0) ||
  111. ((off + len) > b.length) || ((off + len) < 0)) {
  112. throw new IndexOutOfBoundsException();
  113. } else if (len == 0) {
  114. return 0;
  115. }
  116. int c = read();
  117. if (c == -1) {
  118. return -1;
  119. }
  120. b[off] = (byte)c;
  121. int i = 1;
  122. try {
  123. for (; i < len ; i++) {
  124. c = read();
  125. if (c == -1) {
  126. break;
  127. }
  128. if (b != null) {
  129. b[off + i] = (byte)c;
  130. }
  131. }
  132. } catch (IOException ee) {
  133. }
  134. return i;
  135. }
  136. /**
  137. * Skips over and discards <code>n</code> bytes of data from this
  138. * input stream. The <code>skip</code> method may, for a variety of
  139. * reasons, end up skipping over some smaller number of bytes,
  140. * possibly <code>0</code>. The actual number of bytes skipped is
  141. * returned. If <code>n</code> is negative, no bytes are skipped.
  142. * <p>
  143. * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
  144. * a byte array and then repeatedly reads into it until
  145. * <code>n</code> bytes have been read or the end of the stream has
  146. * been reached.
  147. *
  148. * @param n the number of bytes to be skipped.
  149. * @return the actual number of bytes skipped.
  150. * @exception IOException if an I/O error occurs.
  151. * @see java.io.FilterInputStream#in
  152. */
  153. public long skip(long n) throws IOException {
  154. int chunk = 2048;
  155. long remaining = n;
  156. byte data[];
  157. int nr;
  158. if (n <= 0) {
  159. return 0;
  160. }
  161. data = new byte[chunk];
  162. while (remaining > 0) {
  163. nr = read(data, 0, (int) Math.min(chunk, remaining));
  164. if (nr < 0) {
  165. break;
  166. }
  167. remaining -= nr;
  168. }
  169. return n - remaining;
  170. }
  171. /**
  172. * Sets the line number to the specified argument.
  173. *
  174. * @param lineNumber the new line number.
  175. * @see #getLineNumber
  176. */
  177. public void setLineNumber(int lineNumber) {
  178. this.lineNumber = lineNumber;
  179. }
  180. /**
  181. * Returns the current line number.
  182. *
  183. * @return the current line number.
  184. * @see #setLineNumber
  185. */
  186. public int getLineNumber() {
  187. return lineNumber;
  188. }
  189. /**
  190. * Returns the number of bytes that can be read from this input
  191. * stream without blocking.
  192. * <p>
  193. * Note that if the underlying input stream is able to supply
  194. * <i>k</i> input characters without blocking, the
  195. * <code>LineNumberInputStream</code> can guarantee only to provide
  196. * <i>k</i>/2 characters without blocking, because the
  197. * <i>k</i> characters from the underlyhing input stream might
  198. * consist of <i>k</i>/2 pairs of <code>'\r'</code> and
  199. * <code>'\n'</code>, which are converted to just
  200. * <i>k</i>/2 <code>'\n'</code> characters.
  201. *
  202. * @return the number of bytes that can be read from this input stream
  203. * without blocking.
  204. * @exception IOException if an I/O error occurs.
  205. * @see java.io.FilterInputStream#in
  206. */
  207. public int available() throws IOException {
  208. return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
  209. }
  210. /**
  211. * Marks the current position in this input stream. A subsequent
  212. * call to the <code>reset</code> method repositions this stream at
  213. * the last marked position so that subsequent reads re-read the same bytes.
  214. * <p>
  215. * The <code>mark</code> method of
  216. * <code>LineNumberInputStream</code> remembers the current line
  217. * number in a private variable, and then calls the <code>mark</code>
  218. * method of the underlying input stream.
  219. *
  220. * @param readlimit the maximum limit of bytes that can be read before
  221. * the mark position becomes invalid.
  222. * @see java.io.FilterInputStream#in
  223. * @see java.io.LineNumberInputStream#reset()
  224. */
  225. public void mark(int readlimit) {
  226. markLineNumber = lineNumber;
  227. markPushBack = pushBack;
  228. in.mark(readlimit);
  229. }
  230. /**
  231. * Repositions this stream to the position at the time the
  232. * <code>mark</code> method was last called on this input stream.
  233. * <p>
  234. * The <code>reset</code> method of
  235. * <code>LineNumberInputStream</code> resets the line number to be
  236. * the line number at the time the <code>mark</code> method was
  237. * called, and then calls the <code>reset</code> method of the
  238. * underlying input stream.
  239. * <p>
  240. * Stream marks are intended to be used in
  241. * situations where you need to read ahead a little to see what's in
  242. * the stream. Often this is most easily done by invoking some
  243. * general parser. If the stream is of the type handled by the
  244. * parser, it just chugs along happily. If the stream is not of
  245. * that type, the parser should toss an exception when it fails,
  246. * which, if it happens within readlimit bytes, allows the outer
  247. * code to reset the stream and try another parser.
  248. *
  249. * @exception IOException if an I/O error occurs.
  250. * @see java.io.FilterInputStream#in
  251. * @see java.io.LineNumberInputStream#mark(int)
  252. */
  253. public void reset() throws IOException {
  254. lineNumber = markLineNumber;
  255. pushBack = markPushBack;
  256. in.reset();
  257. }
  258. }