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