1. /*
  2. * @(#)SequenceInputStream.java 1.28 04/05/12
  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.io.InputStream;
  9. import java.util.Enumeration;
  10. import java.util.Vector;
  11. /**
  12. * A <code>SequenceInputStream</code> represents
  13. * the logical concatenation of other input
  14. * streams. It starts out with an ordered
  15. * collection of input streams and reads from
  16. * the first one until end of file is reached,
  17. * whereupon it reads from the second one,
  18. * and so on, until end of file is reached
  19. * on the last of the contained input streams.
  20. *
  21. * @author Author van Hoff
  22. * @version 1.28, 05/12/04
  23. * @since JDK1.0
  24. */
  25. public
  26. class SequenceInputStream extends InputStream {
  27. Enumeration e;
  28. InputStream in;
  29. /**
  30. * Initializes a newly created <code>SequenceInputStream</code>
  31. * by remembering the argument, which must
  32. * be an <code>Enumeration</code> that produces
  33. * objects whose run-time type is <code>InputStream</code>.
  34. * The input streams that are produced by
  35. * the enumeration will be read, in order,
  36. * to provide the bytes to be read from this
  37. * <code>SequenceInputStream</code>. After
  38. * each input stream from the enumeration
  39. * is exhausted, it is closed by calling its
  40. * <code>close</code> method.
  41. *
  42. * @param e an enumeration of input streams.
  43. * @see java.util.Enumeration
  44. */
  45. public SequenceInputStream(Enumeration<? extends InputStream> e) {
  46. this.e = e;
  47. try {
  48. nextStream();
  49. } catch (IOException ex) {
  50. // This should never happen
  51. throw new Error("panic");
  52. }
  53. }
  54. /**
  55. * Initializes a newly
  56. * created <code>SequenceInputStream</code>
  57. * by remembering the two arguments, which
  58. * will be read in order, first <code>s1</code>
  59. * and then <code>s2</code>, to provide the
  60. * bytes to be read from this <code>SequenceInputStream</code>.
  61. *
  62. * @param s1 the first input stream to read.
  63. * @param s2 the second input stream to read.
  64. */
  65. public SequenceInputStream(InputStream s1, InputStream s2) {
  66. Vector v = new Vector(2);
  67. v.addElement(s1);
  68. v.addElement(s2);
  69. e = v.elements();
  70. try {
  71. nextStream();
  72. } catch (IOException ex) {
  73. // This should never happen
  74. throw new Error("panic");
  75. }
  76. }
  77. /**
  78. * Continues reading in the next stream if an EOF is reached.
  79. */
  80. final void nextStream() throws IOException {
  81. if (in != null) {
  82. in.close();
  83. }
  84. if (e.hasMoreElements()) {
  85. in = (InputStream) e.nextElement();
  86. if (in == null)
  87. throw new NullPointerException();
  88. }
  89. else in = null;
  90. }
  91. /**
  92. * Returns the number of bytes available on the current stream.
  93. *
  94. * @since JDK1.1
  95. */
  96. public int available() throws IOException {
  97. if(in == null) {
  98. return 0; // no way to signal EOF from available()
  99. }
  100. return in.available();
  101. }
  102. /**
  103. * Reads the next byte of data from this input stream. The byte is
  104. * returned as an <code>int</code> in the range <code>0</code> to
  105. * <code>255</code>. If no byte is available because the end of the
  106. * stream has been reached, the value <code>-1</code> is returned.
  107. * This method blocks until input data is available, the end of the
  108. * stream is detected, or an exception is thrown.
  109. * <p>
  110. * This method
  111. * tries to read one character from the current substream. If it
  112. * reaches the end of the stream, it calls the <code>close</code>
  113. * method of the current substream and begins reading from the next
  114. * substream.
  115. *
  116. * @return the next byte of data, or <code>-1</code> if the end of the
  117. * stream is reached.
  118. * @exception IOException if an I/O error occurs.
  119. */
  120. public int read() throws IOException {
  121. if (in == null) {
  122. return -1;
  123. }
  124. int c = in.read();
  125. if (c == -1) {
  126. nextStream();
  127. return read();
  128. }
  129. return c;
  130. }
  131. /**
  132. * Reads up to <code>len</code> bytes of data from this input stream
  133. * into an array of bytes. This method blocks until at least 1 byte
  134. * of input is available. If the first argument is <code>null</code>,
  135. * up to <code>len</code> bytes are read and discarded.
  136. * <p>
  137. * The <code>read</code> method of <code>SequenceInputStream</code>
  138. * tries to read the data from the current substream. If it fails to
  139. * read any characters because the substream has reached the end of
  140. * the stream, it calls the <code>close</code> method of the current
  141. * substream and begins reading from the next substream.
  142. *
  143. * @param b the buffer into which the data is read.
  144. * @param off the start offset of the data.
  145. * @param len the maximum number of bytes read.
  146. * @return int the number of bytes read.
  147. * @exception IOException if an I/O error occurs.
  148. */
  149. public int read(byte b[], int off, int len) throws IOException {
  150. if (in == null) {
  151. return -1;
  152. } else if (b == null) {
  153. throw new NullPointerException();
  154. } else if ((off < 0) || (off > b.length) || (len < 0) ||
  155. ((off + len) > b.length) || ((off + len) < 0)) {
  156. throw new IndexOutOfBoundsException();
  157. } else if (len == 0) {
  158. return 0;
  159. }
  160. int n = in.read(b, off, len);
  161. if (n <= 0) {
  162. nextStream();
  163. return read(b, off, len);
  164. }
  165. return n;
  166. }
  167. /**
  168. * Closes this input stream and releases any system resources
  169. * associated with the stream.
  170. * A closed <code>SequenceInputStream</code>
  171. * cannot perform input operations and cannot
  172. * be reopened.
  173. * <p>
  174. * If this stream was created
  175. * from an enumeration, all remaining elements
  176. * are requested from the enumeration and closed
  177. * before the <code>close</code> method returns.
  178. * of <code>InputStream</code> .
  179. *
  180. * @exception IOException if an I/O error occurs.
  181. */
  182. public void close() throws IOException {
  183. do {
  184. nextStream();
  185. } while (in != null);
  186. }
  187. }