1/*
2 * Copyright (C) 2007 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.io;
18
19import java.io.IOException;
20import java.io.InputStream;
21import java.util.Iterator;
22
23/**
24 * An {@link InputStream} that concatenates multiple substreams. At most
25 * one stream will be open at a time.
26 *
27 * @author Chris Nokleberg
28 * @since 1.0
29 */
30final class MultiInputStream extends InputStream {
31
32  private Iterator<? extends InputSupplier<? extends InputStream>> it;
33  private InputStream in;
34
35  /**
36   * Creates a new instance.
37   *
38   * @param it an iterator of I/O suppliers that will provide each substream
39   */
40  public MultiInputStream(
41      Iterator<? extends InputSupplier<? extends InputStream>> it)
42      throws IOException {
43    this.it = it;
44    advance();
45  }
46
47  @Override public void close() throws IOException {
48    if (in != null) {
49      try {
50        in.close();
51      } finally {
52        in = null;
53      }
54    }
55  }
56
57  /**
58   * Closes the current input stream and opens the next one, if any.
59   */
60  private void advance() throws IOException {
61    close();
62    if (it.hasNext()) {
63      in = it.next().getInput();
64    }
65  }
66
67  @Override public int available() throws IOException {
68    if (in == null) {
69      return 0;
70    }
71    return in.available();
72  }
73
74  @Override public boolean markSupported() {
75    return false;
76  }
77
78  @Override public int read() throws IOException {
79    if (in == null) {
80      return -1;
81    }
82    int result = in.read();
83    if (result == -1) {
84      advance();
85      return read();
86    }
87    return result;
88  }
89
90  @Override public int read(byte[] b, int off, int len) throws IOException {
91    if (in == null) {
92      return -1;
93    }
94    int result = in.read(b, off, len);
95    if (result == -1) {
96      advance();
97      return read(b, off, len);
98    }
99    return result;
100  }
101
102  @Override public long skip(long n) throws IOException {
103    if (in == null || n <= 0) {
104      return 0;
105    }
106    long result = in.skip(n);
107    if (result != 0) {
108      return result;
109    }
110    if (read() == -1) {
111      return 0;
112    }
113    return 1 + in.skip(n - 1);
114  }
115}
116