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