1. /*
  2. * @(#)PushbackReader.java 1.14 00/02/02
  3. *
  4. * Copyright 1996-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. * A character-stream reader that allows characters to be pushed back into the
  13. * stream.
  14. *
  15. * @version 1.14, 00/02/02
  16. * @author Mark Reinhold
  17. * @since JDK1.1
  18. */
  19. public class PushbackReader extends FilterReader {
  20. /** Pushback buffer */
  21. private char[] buf;
  22. /** Current position in buffer */
  23. private int pos;
  24. /**
  25. * Create a new pushback reader with a pushback buffer of the given size.
  26. *
  27. * @param in The reader from which characters will be read
  28. * @param size The size of the pushback buffer
  29. * @exception IllegalArgumentException if size is <= 0
  30. */
  31. public PushbackReader(Reader in, int size) {
  32. super(in);
  33. if (size <= 0) {
  34. throw new IllegalArgumentException("size <= 0");
  35. }
  36. this.buf = new char[size];
  37. this.pos = size;
  38. }
  39. /**
  40. * Create a new pushback reader with a one-character pushback buffer.
  41. *
  42. * @param in The reader from which characters will be read
  43. */
  44. public PushbackReader(Reader in) {
  45. this(in, 1);
  46. }
  47. /** Check to make sure that the stream has not been closed. */
  48. private void ensureOpen() throws IOException {
  49. if (buf == null)
  50. throw new IOException("Stream closed");
  51. }
  52. /**
  53. * Read a single character.
  54. *
  55. * @return The character read, or -1 if the end of the stream has been
  56. * reached
  57. *
  58. * @exception IOException If an I/O error occurs
  59. */
  60. public int read() throws IOException {
  61. synchronized (lock) {
  62. ensureOpen();
  63. if (pos < buf.length)
  64. return buf[pos++];
  65. else
  66. return super.read();
  67. }
  68. }
  69. /**
  70. * Read characters into a portion of an array.
  71. *
  72. * @param cbuf Destination buffer
  73. * @param off Offset at which to start writing characters
  74. * @param len Maximum number of characters to read
  75. *
  76. * @return The number of characters read, or -1 if the end of the
  77. * stream has been reached
  78. *
  79. * @exception IOException If an I/O error occurs
  80. */
  81. public int read(char cbuf[], int off, int len) throws IOException {
  82. synchronized (lock) {
  83. ensureOpen();
  84. try {
  85. if (len <= 0) {
  86. if (len < 0) {
  87. throw new IndexOutOfBoundsException();
  88. } else if ((off < 0) || (off > cbuf.length)) {
  89. throw new IndexOutOfBoundsException();
  90. }
  91. return 0;
  92. }
  93. int avail = buf.length - pos;
  94. if (avail > 0) {
  95. if (len < avail)
  96. avail = len;
  97. System.arraycopy(buf, pos, cbuf, off, avail);
  98. pos += avail;
  99. off += avail;
  100. len -= avail;
  101. }
  102. if (len > 0) {
  103. len = super.read(cbuf, off, len);
  104. if (len == -1) {
  105. return (avail == 0) ? -1 : avail;
  106. }
  107. return avail + len;
  108. }
  109. return avail;
  110. } catch (ArrayIndexOutOfBoundsException e) {
  111. throw new IndexOutOfBoundsException();
  112. }
  113. }
  114. }
  115. /**
  116. * Push back a single character.
  117. *
  118. * @param c The character to push back
  119. *
  120. * @exception IOException If the pushback buffer is full,
  121. * or if some other I/O error occurs
  122. */
  123. public void unread(int c) throws IOException {
  124. synchronized (lock) {
  125. ensureOpen();
  126. if (pos == 0)
  127. throw new IOException("Pushback buffer overflow");
  128. buf[--pos] = (char) c;
  129. }
  130. }
  131. /**
  132. * Push back a portion of an array of characters by copying it to the
  133. * front of the pushback buffer. After this method returns, the next
  134. * character to be read will have the value <code>cbuf[off]</code>, the
  135. * character after that will have the value <code>cbuf[off+1]</code>, and
  136. * so forth.
  137. *
  138. * @param cbuf Character array
  139. * @param off Offset of first character to push back
  140. * @param len Number of characters to push back
  141. *
  142. * @exception IOException If there is insufficient room in the pushback
  143. * buffer, or if some other I/O error occurs
  144. */
  145. public void unread(char cbuf[], int off, int len) throws IOException {
  146. synchronized (lock) {
  147. ensureOpen();
  148. if (len > pos)
  149. throw new IOException("Pushback buffer overflow");
  150. pos -= len;
  151. System.arraycopy(cbuf, off, buf, pos, len);
  152. }
  153. }
  154. /**
  155. * Push back an array of characters by copying it to the front of the
  156. * pushback buffer. After this method returns, the next character to be
  157. * read will have the value <code>cbuf[0]</code>, the character after that
  158. * will have the value <code>cbuf[1]</code>, and so forth.
  159. *
  160. * @param cbuf Character array to push back
  161. *
  162. * @exception IOException If there is insufficient room in the pushback
  163. * buffer, or if some other I/O error occurs
  164. */
  165. public void unread(char cbuf[]) throws IOException {
  166. unread(cbuf, 0, cbuf.length);
  167. }
  168. /**
  169. * Tell whether this stream is ready to be read.
  170. *
  171. * @exception IOException If an I/O error occurs
  172. */
  173. public boolean ready() throws IOException {
  174. synchronized (lock) {
  175. ensureOpen();
  176. return (pos < buf.length) || super.ready();
  177. }
  178. }
  179. /**
  180. * Mark the present position in the stream. The <code>mark</code>
  181. * for class <code>PushbackReader</code> always throws an exception.
  182. *
  183. * @exception IOException Always, since mark is not supported
  184. */
  185. public void mark(int readAheadLimit) throws IOException {
  186. throw new IOException("mark/reset not supported");
  187. }
  188. /**
  189. * Reset the stream. The <code>reset</code> method of
  190. * <code>PushbackReader</code> always throws an exception.
  191. *
  192. * @exception IOException Always, since reset is not supported
  193. */
  194. public void reset() throws IOException {
  195. throw new IOException("mark/reset not supported");
  196. }
  197. /**
  198. * Tell whether this stream supports the mark() operation, which it does
  199. * not.
  200. */
  201. public boolean markSupported() {
  202. return false;
  203. }
  204. /**
  205. * Close the stream.
  206. *
  207. * @exception IOException If an I/O error occurs
  208. */
  209. public void close() throws IOException {
  210. super.close();
  211. buf = null;
  212. }
  213. }