Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2007 Google Inc.
      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 
     17 package com.google.common.io;
     18 
     19 import java.io.InputStream;
     20 import java.io.IOException;
     21 import 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 2009.09.15 <b>tentative</b>
     29  */
     30 final 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