001: /*
002: * @(#)SequenceInputStream.java 1.30 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.io;
029:
030: import java.io.InputStream;
031: import java.util.Enumeration;
032: import java.util.Vector;
033:
034: /**
035: * A <code>SequenceInputStream</code> represents
036: * the logical concatenation of other input
037: * streams. It starts out with an ordered
038: * collection of input streams and reads from
039: * the first one until end of file is reached,
040: * whereupon it reads from the second one,
041: * and so on, until end of file is reached
042: * on the last of the contained input streams.
043: *
044: * @author Author van Hoff
045: * @version 1.23, 02/02/00
046: * @since JDK1.0
047: */
048: public class SequenceInputStream extends InputStream {
049: Enumeration e;
050: InputStream in;
051:
052: /**
053: * Initializes a newly created <code>SequenceInputStream</code>
054: * by remembering the argument, which must
055: * be an <code>Enumeration</code> that produces
056: * objects whose run-time type is <code>InputStream</code>.
057: * The input streams that are produced by
058: * the enumeration will be read, in order,
059: * to provide the bytes to be read from this
060: * <code>SequenceInputStream</code>. After
061: * each input stream from the enumeration
062: * is exhausted, it is closed by calling its
063: * <code>close</code> method.
064: *
065: * @param e an enumeration of input streams.
066: * @see java.util.Enumeration
067: */
068: public SequenceInputStream(Enumeration e) {
069: this .e = e;
070: try {
071: nextStream();
072: } catch (IOException ex) {
073: // This should never happen
074: throw new Error("panic");
075: }
076: }
077:
078: /**
079: * Initializes a newly
080: * created <code>SequenceInputStream</code>
081: * by remembering the two arguments, which
082: * will be read in order, first <code>s1</code>
083: * and then <code>s2</code>, to provide the
084: * bytes to be read from this <code>SequenceInputStream</code>.
085: *
086: * @param s1 the first input stream to read.
087: * @param s2 the second input stream to read.
088: */
089: public SequenceInputStream(InputStream s1, InputStream s2) {
090: Vector v = new Vector(2);
091:
092: v.addElement(s1);
093: v.addElement(s2);
094: e = v.elements();
095: try {
096: nextStream();
097: } catch (IOException ex) {
098: // This should never happen
099: throw new Error("panic");
100: }
101: }
102:
103: /**
104: * Continues reading in the next stream if an EOF is reached.
105: */
106: final void nextStream() throws IOException {
107: if (in != null) {
108: in.close();
109: }
110:
111: if (e.hasMoreElements()) {
112: in = (InputStream) e.nextElement();
113: if (in == null)
114: throw new NullPointerException();
115: } else
116: in = null;
117:
118: }
119:
120: /**
121: * Returns the number of bytes available on the current stream.
122: *
123: * @since JDK1.1
124: */
125: public int available() throws IOException {
126: if (in == null) {
127: return 0; // no way to signal EOF from available()
128: }
129: return in.available();
130: }
131:
132: /**
133: * Reads the next byte of data from this input stream. The byte is
134: * returned as an <code>int</code> in the range <code>0</code> to
135: * <code>255</code>. If no byte is available because the end of the
136: * stream has been reached, the value <code>-1</code> is returned.
137: * This method blocks until input data is available, the end of the
138: * stream is detected, or an exception is thrown.
139: * <p>
140: * This method
141: * tries to read one character from the current substream. If it
142: * reaches the end of the stream, it calls the <code>close</code>
143: * method of the current substream and begins reading from the next
144: * substream.
145: *
146: * @return the next byte of data, or <code>-1</code> if the end of the
147: * stream is reached.
148: * @exception IOException if an I/O error occurs.
149: */
150: public int read() throws IOException {
151: if (in == null) {
152: return -1;
153: }
154: int c = in.read();
155: if (c == -1) {
156: nextStream();
157: return read();
158: }
159: return c;
160: }
161:
162: /**
163: * Reads up to <code>len</code> bytes of data from this input stream
164: * into an array of bytes. This method blocks until at least 1 byte
165: * of input is available. If the first argument is <code>null</code>,
166: * up to <code>len</code> bytes are read and discarded.
167: * <p>
168: * The <code>read</code> method of <code>SequenceInputStream</code>
169: * tries to read the data from the current substream. If it fails to
170: * read any characters because the substream has reached the end of
171: * the stream, it calls the <code>close</code> method of the current
172: * substream and begins reading from the next substream.
173: *
174: * @param b the buffer into which the data is read.
175: * @param off the start offset of the data.
176: * @param len the maximum number of bytes read.
177: * @return int the number of bytes read.
178: * @exception IOException if an I/O error occurs.
179: */
180: public int read(byte b[], int off, int len) throws IOException {
181: if (in == null) {
182: return -1;
183: } else if (b == null) {
184: throw new NullPointerException();
185: } else if ((off < 0) || (off > b.length) || (len < 0)
186: || ((off + len) > b.length) || ((off + len) < 0)) {
187: throw new IndexOutOfBoundsException();
188: } else if (len == 0) {
189: return 0;
190: }
191:
192: int n = in.read(b, off, len);
193: if (n <= 0) {
194: nextStream();
195: return read(b, off, len);
196: }
197: return n;
198: }
199:
200: /**
201: * Closes this input stream and releases any system resources
202: * associated with the stream.
203: * A closed <code>SequenceInputStream</code>
204: * cannot perform input operations and cannot
205: * be reopened.
206: * <p>
207: * If this stream was created
208: * from an enumeration, all remaining elements
209: * are requested from the enumeration and closed
210: * before the <code>close</code> method returns.
211: * of <code>InputStream</code> .
212: *
213: * @exception IOException if an I/O error occurs.
214: */
215: public void close() throws IOException {
216: do {
217: nextStream();
218: } while (in != null);
219: }
220: }
|