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 1.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 peekNextStream(); 69 } 70 71 /** 72 * Initializes a newly 73 * created <code>SequenceInputStream</code> 74 * by remembering the two arguments, which 75 * will be read in order, first <code>s1</code> 76 * and then <code>s2</code>, to provide the 77 * bytes to be read from this <code>SequenceInputStream</code>. 78 * 79 * @param s1 the first input stream to read. 80 * @param s2 the second input stream to read. 81 */ SequenceInputStream(InputStream s1, InputStream s2)82 public SequenceInputStream(InputStream s1, InputStream s2) { 83 Vector<InputStream> v = new Vector<>(2); 84 v.addElement(s1); 85 v.addElement(s2); 86 e = v.elements(); 87 peekNextStream(); 88 } 89 90 /** 91 * Continues reading in the next stream if an EOF is reached. 92 */ nextStream()93 final void nextStream() throws IOException { 94 if (in != null) { 95 in.close(); 96 } 97 peekNextStream(); 98 } 99 peekNextStream()100 private void peekNextStream() { 101 if (e.hasMoreElements()) { 102 in = (InputStream) e.nextElement(); 103 if (in == null) 104 throw new NullPointerException(); 105 } else { 106 in = null; 107 } 108 } 109 110 /** 111 * Returns an estimate of the number of bytes that can be read (or 112 * skipped over) from the current underlying input stream without 113 * blocking by the next invocation of a method for the current 114 * underlying input stream. The next invocation might be 115 * the same thread or another thread. A single read or skip of this 116 * many bytes will not block, but may read or skip fewer bytes. 117 * <p> 118 * This method simply calls {@code available} of the current underlying 119 * input stream and returns the result. 120 * 121 * @return an estimate of the number of bytes that can be read (or 122 * skipped over) from the current underlying input stream 123 * without blocking or {@code 0} if this input stream 124 * has been closed by invoking its {@link #close()} method 125 * @exception IOException if an I/O error occurs. 126 * 127 * @since 1.1 128 */ available()129 public int available() throws IOException { 130 if (in == null) { 131 return 0; // no way to signal EOF from available() 132 } 133 return in.available(); 134 } 135 136 /** 137 * Reads the next byte of data from this input stream. The byte is 138 * returned as an <code>int</code> in the range <code>0</code> to 139 * <code>255</code>. If no byte is available because the end of the 140 * stream has been reached, the value <code>-1</code> is returned. 141 * This method blocks until input data is available, the end of the 142 * stream is detected, or an exception is thrown. 143 * <p> 144 * This method 145 * tries to read one character from the current substream. If it 146 * reaches the end of the stream, it calls the <code>close</code> 147 * method of the current substream and begins reading from the next 148 * substream. 149 * 150 * @return the next byte of data, or <code>-1</code> if the end of the 151 * stream is reached. 152 * @exception IOException if an I/O error occurs. 153 */ read()154 public int read() throws IOException { 155 while (in != null) { 156 int c = in.read(); 157 if (c != -1) { 158 return c; 159 } 160 nextStream(); 161 } 162 return -1; 163 } 164 165 /** 166 * Reads up to <code>len</code> bytes of data from this input stream 167 * into an array of bytes. If <code>len</code> is not zero, the method 168 * blocks until at least 1 byte of input is available; otherwise, no 169 * bytes are read and <code>0</code> is returned. 170 * <p> 171 * The <code>read</code> method of <code>SequenceInputStream</code> 172 * tries to read the data from the current substream. If it fails to 173 * read any characters because the substream has reached the end of 174 * the stream, it calls the <code>close</code> method of the current 175 * substream and begins reading from the next substream. 176 * 177 * @param b the buffer into which the data is read. 178 * @param off the start offset in array <code>b</code> 179 * at which the data is written. 180 * @param len the maximum number of bytes read. 181 * @return int the number of bytes read. 182 * @exception NullPointerException If <code>b</code> is <code>null</code>. 183 * @exception IndexOutOfBoundsException If <code>off</code> is negative, 184 * <code>len</code> is negative, or <code>len</code> is greater than 185 * <code>b.length - off</code> 186 * @exception IOException if an I/O error occurs. 187 */ read(byte b[], int off, int len)188 public int read(byte b[], int off, int len) throws IOException { 189 if (in == null) { 190 return -1; 191 } else if (b == null) { 192 throw new NullPointerException(); 193 } else if (off < 0 || len < 0 || len > b.length - off) { 194 throw new IndexOutOfBoundsException(); 195 } else if (len == 0) { 196 return 0; 197 } 198 do { 199 int n = in.read(b, off, len); 200 if (n > 0) { 201 return n; 202 } 203 nextStream(); 204 } while (in != null); 205 return -1; 206 } 207 208 /** 209 * Closes this input stream and releases any system resources 210 * associated with the stream. 211 * A closed <code>SequenceInputStream</code> 212 * cannot perform input operations and cannot 213 * be reopened. 214 * <p> 215 * If this stream was created 216 * from an enumeration, all remaining elements 217 * are requested from the enumeration and closed 218 * before the <code>close</code> method returns. 219 * 220 * @exception IOException if an I/O error occurs. 221 */ close()222 public void close() throws IOException { 223 do { 224 nextStream(); 225 } while (in != null); 226 } 227 } 228