001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.io;
019:
020: import java.util.Enumeration;
021: import java.util.Vector;
022:
023: /**
024: * SequenceInputStream is used for streaming over a sequence of streams
025: * concatenated together. Reads are taken from the first stream until it ends,
026: * then the next stream is used until the last stream returns end of file.
027: *
028: */
029: public class SequenceInputStream extends InputStream {
030: /**
031: * An enumeration which will return types of InputStream.
032: */
033: private Enumeration<? extends InputStream> e;
034:
035: /**
036: * The current input stream.
037: */
038: private InputStream in;
039:
040: /**
041: * Constructs a new SequenceInputStream using the two streams
042: * <code>s1</code> and <code>s2</code> as the sequence of streams to
043: * read from.
044: *
045: * @param s1
046: * the first stream to get bytes from
047: * @param s2
048: * the second stream to get bytes from
049: */
050: public SequenceInputStream(InputStream s1, InputStream s2) {
051: if (s1 == null) {
052: throw new NullPointerException();
053: }
054: Vector<InputStream> inVector = new Vector<InputStream>(1);
055: inVector.addElement(s2);
056: e = inVector.elements();
057: in = s1;
058: }
059:
060: /**
061: * Constructs a new SequenceInputStream using the elements returned from
062: * Enumeration <code>e</code> as the stream sequence. The types returned
063: * from nextElement() must be of InputStream.
064: *
065: * @param e
066: * the Enumeration of InputStreams to get bytes from
067: */
068: public SequenceInputStream(Enumeration<? extends InputStream> e) {
069: this .e = e;
070: if (e.hasMoreElements()) {
071: in = e.nextElement();
072: if (in == null) {
073: throw new NullPointerException();
074: }
075: }
076: }
077:
078: /**
079: * Answers a int representing then number of bytes that are available before
080: * this InputStream will block.
081: *
082: * @return the number of bytes available before blocking.
083: *
084: * @throws IOException
085: * If an error occurs in this InputStream.
086: */
087: @Override
088: public int available() throws IOException {
089: if (e != null && in != null) {
090: return in.available();
091: }
092: return 0;
093: }
094:
095: /**
096: * Close the SequenceInputStream. All streams in this sequence are closed
097: * before returning from this method. This stream cannot be used for input
098: * once it has been closed.
099: *
100: * @throws IOException
101: * If an error occurs attempting to close this FileInputStream.
102: */
103: @Override
104: public void close() throws IOException {
105: while (in != null) {
106: nextStream();
107: }
108: e = null;
109: }
110:
111: /**
112: * Sets up the next InputStream or leaves it alone if there are none left.
113: *
114: * @throws IOException
115: */
116: private void nextStream() throws IOException {
117: if (in != null) {
118: in.close();
119: }
120: if (e.hasMoreElements()) {
121: in = e.nextElement();
122: if (in == null) {
123: throw new NullPointerException();
124: }
125: } else {
126: in = null;
127: }
128: }
129:
130: /**
131: * Reads a single byte from this SequenceInputStream and returns the result
132: * as an int. The low-order byte is returned or -1 of the end of stream was
133: * encountered. The current stream is read from. If it reaches the end of
134: * file, the next stream is read from.
135: *
136: * @return the byte read or -1 if end of stream.
137: *
138: * @throws IOException
139: * If an error occurs while reading the stream
140: */
141: @Override
142: public int read() throws IOException {
143: while (in != null) {
144: int result = in.read();
145: if (result >= 0) {
146: return result;
147: }
148: nextStream();
149: }
150: return -1;
151: }
152:
153: /**
154: * Reads at most <code>count</code> bytes from this SequenceInputStream
155: * and stores them in byte array <code>buffer</code> starting at
156: * <code>offset</code>. Answer the number of bytes actually read or -1 if
157: * no bytes were read and end of stream was encountered.
158: *
159: * @param buffer
160: * the byte array in which to store the read bytes.
161: * @param offset
162: * the offset in <code>buffer</code> to store the read bytes.
163: * @param count
164: * the maximum number of bytes to store in <code>buffer</code>.
165: * @return the number of bytes actually read or -1 if end of stream.
166: *
167: * @throws IOException
168: * If an error occurs while reading the stream
169: */
170: @Override
171: public int read(byte[] buffer, int offset, int count)
172: throws IOException {
173: if (in == null) {
174: return -1;
175: }
176: if (buffer == null) {
177: throw new NullPointerException();
178: }
179: // avoid int overflow
180: if (offset < 0 || offset > buffer.length - count || count < 0) {
181: throw new IndexOutOfBoundsException();
182: }
183: while (in != null) {
184: int result = in.read(buffer, offset, count);
185: if (result >= 0) {
186: return result;
187: }
188: nextStream();
189: }
190: return -1;
191: }
192: }
|