1. /*
  2. * @(#)BufferedInputStream.java 1.50 04/05/03
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
  9. /**
  10. * A <code>BufferedInputStream</code> adds
  11. * functionality to another input stream-namely,
  12. * the ability to buffer the input and to
  13. * support the <code>mark</code> and <code>reset</code>
  14. * methods. When the <code>BufferedInputStream</code>
  15. * is created, an internal buffer array is
  16. * created. As bytes from the stream are read
  17. * or skipped, the internal buffer is refilled
  18. * as necessary from the contained input stream,
  19. * many bytes at a time. The <code>mark</code>
  20. * operation remembers a point in the input
  21. * stream and the <code>reset</code> operation
  22. * causes all the bytes read since the most
  23. * recent <code>mark</code> operation to be
  24. * reread before new bytes are taken from
  25. * the contained input stream.
  26. *
  27. * @author Arthur van Hoff
  28. * @version 1.50, 05/03/04
  29. * @since JDK1.0
  30. */
  31. public
  32. class BufferedInputStream extends FilterInputStream {
  33. private static int defaultBufferSize = 8192;
  34. /**
  35. * The internal buffer array where the data is stored. When necessary,
  36. * it may be replaced by another array of
  37. * a different size.
  38. */
  39. protected volatile byte buf[];
  40. /**
  41. * Atomic updater to provide compareAndSet for buf. This is
  42. * necessary because closes can be asynchronous. We use nullness
  43. * of buf[] as primary indicator that this stream is closed. (The
  44. * "in" field is also nulled out on close.)
  45. */
  46. private static final
  47. AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
  48. AtomicReferenceFieldUpdater.newUpdater
  49. (BufferedInputStream.class, byte[].class, "buf");
  50. /**
  51. * The index one greater than the index of the last valid byte in
  52. * the buffer.
  53. * This value is always
  54. * in the range <code>0</code> through <code>buf.length</code>
  55. * elements <code>buf[0]</code> through <code>buf[count-1]
  56. * </code>contain buffered input data obtained
  57. * from the underlying input stream.
  58. */
  59. protected int count;
  60. /**
  61. * The current position in the buffer. This is the index of the next
  62. * character to be read from the <code>buf</code> array.
  63. * <p>
  64. * This value is always in the range <code>0</code>
  65. * through <code>count</code>. If it is less
  66. * than <code>count</code>, then <code>buf[pos]</code>
  67. * is the next byte to be supplied as input;
  68. * if it is equal to <code>count</code>, then
  69. * the next <code>read</code> or <code>skip</code>
  70. * operation will require more bytes to be
  71. * read from the contained input stream.
  72. *
  73. * @see java.io.BufferedInputStream#buf
  74. */
  75. protected int pos;
  76. /**
  77. * The value of the <code>pos</code> field at the time the last
  78. * <code>mark</code> method was called.
  79. * <p>
  80. * This value is always
  81. * in the range <code>-1</code> through <code>pos</code>.
  82. * If there is no marked position in the input
  83. * stream, this field is <code>-1</code>. If
  84. * there is a marked position in the input
  85. * stream, then <code>buf[markpos]</code>
  86. * is the first byte to be supplied as input
  87. * after a <code>reset</code> operation. If
  88. * <code>markpos</code> is not <code>-1</code>,
  89. * then all bytes from positions <code>buf[markpos]</code>
  90. * through <code>buf[pos-1]</code> must remain
  91. * in the buffer array (though they may be
  92. * moved to another place in the buffer array,
  93. * with suitable adjustments to the values
  94. * of <code>count</code>, <code>pos</code>,
  95. * and <code>markpos</code>); they may not
  96. * be discarded unless and until the difference
  97. * between <code>pos</code> and <code>markpos</code>
  98. * exceeds <code>marklimit</code>.
  99. *
  100. * @see java.io.BufferedInputStream#mark(int)
  101. * @see java.io.BufferedInputStream#pos
  102. */
  103. protected int markpos = -1;
  104. /**
  105. * The maximum read ahead allowed after a call to the
  106. * <code>mark</code> method before subsequent calls to the
  107. * <code>reset</code> method fail.
  108. * Whenever the difference between <code>pos</code>
  109. * and <code>markpos</code> exceeds <code>marklimit</code>,
  110. * then the mark may be dropped by setting
  111. * <code>markpos</code> to <code>-1</code>.
  112. *
  113. * @see java.io.BufferedInputStream#mark(int)
  114. * @see java.io.BufferedInputStream#reset()
  115. */
  116. protected int marklimit;
  117. /**
  118. * Check to make sure that underlying input stream has not been
  119. * nulled out due to close; if not return it;
  120. */
  121. private InputStream getInIfOpen() throws IOException {
  122. InputStream input = in;
  123. if (input == null)
  124. throw new IOException("Stream closed");
  125. return input;
  126. }
  127. /**
  128. * Check to make sure that buffer has not been nulled out due to
  129. * close; if not return it;
  130. */
  131. private byte[] getBufIfOpen() throws IOException {
  132. byte[] buffer = buf;
  133. if (buffer == null)
  134. throw new IOException("Stream closed");
  135. return buffer;
  136. }
  137. /**
  138. * Creates a <code>BufferedInputStream</code>
  139. * and saves its argument, the input stream
  140. * <code>in</code>, for later use. An internal
  141. * buffer array is created and stored in <code>buf</code>.
  142. *
  143. * @param in the underlying input stream.
  144. */
  145. public BufferedInputStream(InputStream in) {
  146. this(in, defaultBufferSize);
  147. }
  148. /**
  149. * Creates a <code>BufferedInputStream</code>
  150. * with the specified buffer size,
  151. * and saves its argument, the input stream
  152. * <code>in</code>, for later use. An internal
  153. * buffer array of length <code>size</code>
  154. * is created and stored in <code>buf</code>.
  155. *
  156. * @param in the underlying input stream.
  157. * @param size the buffer size.
  158. * @exception IllegalArgumentException if size <= 0.
  159. */
  160. public BufferedInputStream(InputStream in, int size) {
  161. super(in);
  162. if (size <= 0) {
  163. throw new IllegalArgumentException("Buffer size <= 0");
  164. }
  165. buf = new byte[size];
  166. }
  167. /**
  168. * Fills the buffer with more data, taking into account
  169. * shuffling and other tricks for dealing with marks.
  170. * Assumes that it is being called by a synchronized method.
  171. * This method also assumes that all data has already been read in,
  172. * hence pos > count.
  173. */
  174. private void fill() throws IOException {
  175. byte[] buffer = getBufIfOpen();
  176. if (markpos < 0)
  177. pos = 0; /* no mark: throw away the buffer */
  178. else if (pos >= buffer.length) /* no room left in buffer */
  179. if (markpos > 0) { /* can throw away early part of the buffer */
  180. int sz = pos - markpos;
  181. System.arraycopy(buffer, markpos, buffer, 0, sz);
  182. pos = sz;
  183. markpos = 0;
  184. } else if (buffer.length >= marklimit) {
  185. markpos = -1; /* buffer got too big, invalidate mark */
  186. pos = 0; /* drop buffer contents */
  187. } else { /* grow buffer */
  188. int nsz = pos * 2;
  189. if (nsz > marklimit)
  190. nsz = marklimit;
  191. byte nbuf[] = new byte[nsz];
  192. System.arraycopy(buffer, 0, nbuf, 0, pos);
  193. if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
  194. // Can't replace buf if there was an async close.
  195. // Note: This would need to be changed if fill()
  196. // is ever made accessible to multiple threads.
  197. // But for now, the only way CAS can fail is via close.
  198. // assert buf == null;
  199. throw new IOException("Stream closed");
  200. }
  201. buffer = nbuf;
  202. }
  203. count = pos;
  204. int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
  205. if (n > 0)
  206. count = n + pos;
  207. }
  208. /**
  209. * See
  210. * the general contract of the <code>read</code>
  211. * method of <code>InputStream</code>.
  212. *
  213. * @return the next byte of data, or <code>-1</code> if the end of the
  214. * stream is reached.
  215. * @exception IOException if an I/O error occurs.
  216. * @see java.io.FilterInputStream#in
  217. */
  218. public synchronized int read() throws IOException {
  219. if (pos >= count) {
  220. fill();
  221. if (pos >= count)
  222. return -1;
  223. }
  224. return getBufIfOpen()[pos++] & 0xff;
  225. }
  226. /**
  227. * Read characters into a portion of an array, reading from the underlying
  228. * stream at most once if necessary.
  229. */
  230. private int read1(byte[] b, int off, int len) throws IOException {
  231. int avail = count - pos;
  232. if (avail <= 0) {
  233. /* If the requested length is at least as large as the buffer, and
  234. if there is no mark/reset activity, do not bother to copy the
  235. bytes into the local buffer. In this way buffered streams will
  236. cascade harmlessly. */
  237. if (len >= getBufIfOpen().length && markpos < 0) {
  238. return getInIfOpen().read(b, off, len);
  239. }
  240. fill();
  241. avail = count - pos;
  242. if (avail <= 0) return -1;
  243. }
  244. int cnt = (avail < len) ? avail : len;
  245. System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
  246. pos += cnt;
  247. return cnt;
  248. }
  249. /**
  250. * Reads bytes from this byte-input stream into the specified byte array,
  251. * starting at the given offset.
  252. *
  253. * <p> This method implements the general contract of the corresponding
  254. * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
  255. * the <code>{@link InputStream}</code> class. As an additional
  256. * convenience, it attempts to read as many bytes as possible by repeatedly
  257. * invoking the <code>read</code> method of the underlying stream. This
  258. * iterated <code>read</code> continues until one of the following
  259. * conditions becomes true: <ul>
  260. *
  261. * <li> The specified number of bytes have been read,
  262. *
  263. * <li> The <code>read</code> method of the underlying stream returns
  264. * <code>-1</code>, indicating end-of-file, or
  265. *
  266. * <li> The <code>available</code> method of the underlying stream
  267. * returns zero, indicating that further input requests would block.
  268. *
  269. * </ul> If the first <code>read</code> on the underlying stream returns
  270. * <code>-1</code> to indicate end-of-file then this method returns
  271. * <code>-1</code>. Otherwise this method returns the number of bytes
  272. * actually read.
  273. *
  274. * <p> Subclasses of this class are encouraged, but not required, to
  275. * attempt to read as many bytes as possible in the same fashion.
  276. *
  277. * @param b destination buffer.
  278. * @param off offset at which to start storing bytes.
  279. * @param len maximum number of bytes to read.
  280. * @return the number of bytes read, or <code>-1</code> if the end of
  281. * the stream has been reached.
  282. * @exception IOException if an I/O error occurs.
  283. */
  284. public synchronized int read(byte b[], int off, int len)
  285. throws IOException
  286. {
  287. getBufIfOpen(); // Check for closed stream
  288. if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
  289. throw new IndexOutOfBoundsException();
  290. } else if (len == 0) {
  291. return 0;
  292. }
  293. int n = 0;
  294. for (;;) {
  295. int nread = read1(b, off + n, len - n);
  296. if (nread <= 0)
  297. return (n == 0) ? nread : n;
  298. n += nread;
  299. if (n >= len)
  300. return n;
  301. // if not closed but no bytes available, return
  302. InputStream input = in;
  303. if (input != null && input.available() <= 0)
  304. return n;
  305. }
  306. }
  307. /**
  308. * See the general contract of the <code>skip</code>
  309. * method of <code>InputStream</code>.
  310. *
  311. * @param n the number of bytes to be skipped.
  312. * @return the actual number of bytes skipped.
  313. * @exception IOException if an I/O error occurs.
  314. */
  315. public synchronized long skip(long n) throws IOException {
  316. getBufIfOpen(); // Check for closed stream
  317. if (n <= 0) {
  318. return 0;
  319. }
  320. long avail = count - pos;
  321. if (avail <= 0) {
  322. // If no mark position set then don't keep in buffer
  323. if (markpos <0)
  324. return getInIfOpen().skip(n);
  325. // Fill in buffer to save bytes for reset
  326. fill();
  327. avail = count - pos;
  328. if (avail <= 0)
  329. return 0;
  330. }
  331. long skipped = (avail < n) ? avail : n;
  332. pos += skipped;
  333. return skipped;
  334. }
  335. /**
  336. * Returns the number of bytes that can be read from this input
  337. * stream without blocking.
  338. * <p>
  339. * The <code>available</code> method of
  340. * <code>BufferedInputStream</code> returns the sum of the number
  341. * of bytes remaining to be read in the buffer
  342. * (<code>count - pos</code>)
  343. * and the result of calling the <code>available</code> method of the
  344. * underlying input stream.
  345. *
  346. * @return the number of bytes that can be read from this input
  347. * stream without blocking.
  348. * @exception IOException if an I/O error occurs.
  349. * @see java.io.FilterInputStream#in
  350. */
  351. public synchronized int available() throws IOException {
  352. return getInIfOpen().available() + (count - pos);
  353. }
  354. /**
  355. * See the general contract of the <code>mark</code>
  356. * method of <code>InputStream</code>.
  357. *
  358. * @param readlimit the maximum limit of bytes that can be read before
  359. * the mark position becomes invalid.
  360. * @see java.io.BufferedInputStream#reset()
  361. */
  362. public synchronized void mark(int readlimit) {
  363. marklimit = readlimit;
  364. markpos = pos;
  365. }
  366. /**
  367. * See the general contract of the <code>reset</code>
  368. * method of <code>InputStream</code>.
  369. * <p>
  370. * If <code>markpos</code> is <code>-1</code>
  371. * (no mark has been set or the mark has been
  372. * invalidated), an <code>IOException</code>
  373. * is thrown. Otherwise, <code>pos</code> is
  374. * set equal to <code>markpos</code>.
  375. *
  376. * @exception IOException if this stream has not been marked or
  377. * if the mark has been invalidated.
  378. * @see java.io.BufferedInputStream#mark(int)
  379. */
  380. public synchronized void reset() throws IOException {
  381. getBufIfOpen(); // Cause exception if closed
  382. if (markpos < 0)
  383. throw new IOException("Resetting to invalid mark");
  384. pos = markpos;
  385. }
  386. /**
  387. * Tests if this input stream supports the <code>mark</code>
  388. * and <code>reset</code> methods. The <code>markSupported</code>
  389. * method of <code>BufferedInputStream</code> returns
  390. * <code>true</code>.
  391. *
  392. * @return a <code>boolean</code> indicating if this stream type supports
  393. * the <code>mark</code> and <code>reset</code> methods.
  394. * @see java.io.InputStream#mark(int)
  395. * @see java.io.InputStream#reset()
  396. */
  397. public boolean markSupported() {
  398. return true;
  399. }
  400. /**
  401. * Closes this input stream and releases any system resources
  402. * associated with the stream.
  403. *
  404. * @exception IOException if an I/O error occurs.
  405. */
  406. public void close() throws IOException {
  407. byte[] buffer;
  408. while ( (buffer = buf) != null) {
  409. if (bufUpdater.compareAndSet(this, buffer, null)) {
  410. InputStream input = in;
  411. in = null;
  412. if (input != null)
  413. input.close();
  414. return;
  415. }
  416. // Else retry in case a new buf was CASed in fill()
  417. }
  418. }
  419. }