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