001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.io;
018
019import static com.google.common.base.Preconditions.checkArgument;
020import static com.google.common.base.Preconditions.checkNotNull;
021import static com.google.common.base.Preconditions.checkPositionIndex;
022
023import com.google.common.annotations.Beta;
024import com.google.common.hash.HashCode;
025import com.google.common.hash.HashFunction;
026
027import java.io.ByteArrayInputStream;
028import java.io.ByteArrayOutputStream;
029import java.io.DataInput;
030import java.io.DataInputStream;
031import java.io.DataOutput;
032import java.io.DataOutputStream;
033import java.io.EOFException;
034import java.io.FilterInputStream;
035import java.io.IOException;
036import java.io.InputStream;
037import java.io.OutputStream;
038import java.nio.ByteBuffer;
039import java.nio.channels.ReadableByteChannel;
040import java.nio.channels.WritableByteChannel;
041import java.util.Arrays;
042import java.util.zip.Checksum;
043
044/**
045 * Provides utility methods for working with byte arrays and I/O streams.
046 *
047 * @author Chris Nokleberg
048 * @author Colin Decker
049 * @since 1.0
050 */
051@Beta
052public final class ByteStreams {
053  private static final int BUF_SIZE = 0x1000; // 4K
054
055  private ByteStreams() {}
056
057  /**
058   * Returns a factory that will supply instances of
059   * {@link ByteArrayInputStream} that read from the given byte array.
060   *
061   * @param b the input buffer
062   * @return the factory
063   */
064  public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
065      byte[] b) {
066    return ByteStreams.asInputSupplier(asByteSource(b));
067  }
068
069  /**
070   * Returns a factory that will supply instances of
071   * {@link ByteArrayInputStream} that read from the given byte array.
072   *
073   * @param b the input buffer
074   * @param off the offset in the buffer of the first byte to read
075   * @param len the maximum number of bytes to read from the buffer
076   * @return the factory
077   */
078  public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
079      final byte[] b, final int off, final int len) {
080    return ByteStreams.asInputSupplier(asByteSource(b).slice(off, len));
081  }
082
083  /**
084   * Returns a new {@link ByteSource} that reads bytes from the given byte array.
085   *
086   * @since 14.0
087   */
088  public static ByteSource asByteSource(byte[] b) {
089    return new ByteArrayByteSource(b);
090  }
091
092  private static final class ByteArrayByteSource extends ByteSource {
093
094    private final byte[] bytes;
095
096    private ByteArrayByteSource(byte[] bytes) {
097      this.bytes = checkNotNull(bytes);
098    }
099
100    @Override
101    public InputStream openStream() throws IOException {
102      return new ByteArrayInputStream(bytes);
103    }
104
105    @Override
106    public long size() throws IOException {
107      return bytes.length;
108    }
109
110    @Override
111    public byte[] read() throws IOException {
112      return bytes.clone();
113    }
114
115    @Override
116    public long copyTo(OutputStream output) throws IOException {
117      output.write(bytes);
118      return bytes.length;
119    }
120
121    @Override
122    public HashCode hash(HashFunction hashFunction) throws IOException {
123      return hashFunction.hashBytes(bytes);
124    }
125
126    // TODO(user): Possibly override slice()
127
128    @Override
129    public String toString() {
130      return "ByteStreams.asByteSource(" + BaseEncoding.base16().encode(bytes) + ")";
131    }
132  }
133
134  /**
135   * Writes a byte array to an output stream from the given supplier.
136   *
137   * @param from the bytes to write
138   * @param to the output supplier
139   * @throws IOException if an I/O error occurs
140   */
141  public static void write(byte[] from,
142      OutputSupplier<? extends OutputStream> to) throws IOException {
143    asByteSink(to).write(from);
144  }
145
146  /**
147   * Opens input and output streams from the given suppliers, copies all
148   * bytes from the input to the output, and closes the streams.
149   *
150   * @param from the input factory
151   * @param to the output factory
152   * @return the number of bytes copied
153   * @throws IOException if an I/O error occurs
154   */
155  public static long copy(InputSupplier<? extends InputStream> from,
156      OutputSupplier<? extends OutputStream> to) throws IOException {
157    return asByteSource(from).copyTo(asByteSink(to));
158  }
159
160  /**
161   * Opens an input stream from the supplier, copies all bytes from the
162   * input to the output, and closes the input stream. Does not close
163   * or flush the output stream.
164   *
165   * @param from the input factory
166   * @param to the output stream to write to
167   * @return the number of bytes copied
168   * @throws IOException if an I/O error occurs
169   */
170  public static long copy(InputSupplier<? extends InputStream> from,
171      OutputStream to) throws IOException {
172    return asByteSource(from).copyTo(to);
173  }
174
175  /**
176   * Opens an output stream from the supplier, copies all bytes from the input
177   * to the output, and closes the output stream. Does not close or flush the
178   * input stream.
179   *
180   * @param from the input stream to read from
181   * @param to the output factory
182   * @return the number of bytes copied
183   * @throws IOException if an I/O error occurs
184   * @since 10.0
185   */
186  public static long copy(InputStream from,
187      OutputSupplier<? extends OutputStream> to) throws IOException {
188    return asByteSink(to).writeFrom(from);
189  }
190
191  /**
192   * Copies all bytes from the input stream to the output stream.
193   * Does not close or flush either stream.
194   *
195   * @param from the input stream to read from
196   * @param to the output stream to write to
197   * @return the number of bytes copied
198   * @throws IOException if an I/O error occurs
199   */
200  public static long copy(InputStream from, OutputStream to)
201      throws IOException {
202    checkNotNull(from);
203    checkNotNull(to);
204    byte[] buf = new byte[BUF_SIZE];
205    long total = 0;
206    while (true) {
207      int r = from.read(buf);
208      if (r == -1) {
209        break;
210      }
211      to.write(buf, 0, r);
212      total += r;
213    }
214    return total;
215  }
216
217  /**
218   * Copies all bytes from the readable channel to the writable channel.
219   * Does not close or flush either channel.
220   *
221   * @param from the readable channel to read from
222   * @param to the writable channel to write to
223   * @return the number of bytes copied
224   * @throws IOException if an I/O error occurs
225   */
226  public static long copy(ReadableByteChannel from,
227      WritableByteChannel to) throws IOException {
228    checkNotNull(from);
229    checkNotNull(to);
230    ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
231    long total = 0;
232    while (from.read(buf) != -1) {
233      buf.flip();
234      while (buf.hasRemaining()) {
235        total += to.write(buf);
236      }
237      buf.clear();
238    }
239    return total;
240  }
241
242  /**
243   * Reads all bytes from an input stream into a byte array.
244   * Does not close the stream.
245   *
246   * @param in the input stream to read from
247   * @return a byte array containing all the bytes from the stream
248   * @throws IOException if an I/O error occurs
249   */
250  public static byte[] toByteArray(InputStream in) throws IOException {
251    ByteArrayOutputStream out = new ByteArrayOutputStream();
252    copy(in, out);
253    return out.toByteArray();
254  }
255
256  /**
257   * Returns the data from a {@link InputStream} factory as a byte array.
258   *
259   * @param supplier the factory
260   * @throws IOException if an I/O error occurs
261   */
262  public static byte[] toByteArray(
263      InputSupplier<? extends InputStream> supplier) throws IOException {
264    return asByteSource(supplier).read();
265  }
266
267  /**
268   * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
269   * bytes} array from the beginning.
270   */
271  public static ByteArrayDataInput newDataInput(byte[] bytes) {
272    return new ByteArrayDataInputStream(bytes);
273  }
274
275  /**
276   * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
277   * bytes} array, starting at the given position.
278   *
279   * @throws IndexOutOfBoundsException if {@code start} is negative or greater
280   *     than the length of the array
281   */
282  public static ByteArrayDataInput newDataInput(byte[] bytes, int start) {
283    checkPositionIndex(start, bytes.length);
284    return new ByteArrayDataInputStream(bytes, start);
285  }
286
287  private static class ByteArrayDataInputStream implements ByteArrayDataInput {
288    final DataInput input;
289
290    ByteArrayDataInputStream(byte[] bytes) {
291      this.input = new DataInputStream(new ByteArrayInputStream(bytes));
292    }
293
294    ByteArrayDataInputStream(byte[] bytes, int start) {
295      this.input = new DataInputStream(
296          new ByteArrayInputStream(bytes, start, bytes.length - start));
297    }
298
299    @Override public void readFully(byte b[]) {
300      try {
301        input.readFully(b);
302      } catch (IOException e) {
303        throw new IllegalStateException(e);
304      }
305    }
306
307    @Override public void readFully(byte b[], int off, int len) {
308      try {
309        input.readFully(b, off, len);
310      } catch (IOException e) {
311        throw new IllegalStateException(e);
312      }
313    }
314
315    @Override public int skipBytes(int n) {
316      try {
317        return input.skipBytes(n);
318      } catch (IOException e) {
319        throw new IllegalStateException(e);
320      }
321    }
322
323    @Override public boolean readBoolean() {
324      try {
325        return input.readBoolean();
326      } catch (IOException e) {
327        throw new IllegalStateException(e);
328      }
329    }
330
331    @Override public byte readByte() {
332      try {
333        return input.readByte();
334      } catch (EOFException e) {
335        throw new IllegalStateException(e);
336      } catch (IOException impossible) {
337        throw new AssertionError(impossible);
338      }
339    }
340
341    @Override public int readUnsignedByte() {
342      try {
343        return input.readUnsignedByte();
344      } catch (IOException e) {
345        throw new IllegalStateException(e);
346      }
347    }
348
349    @Override public short readShort() {
350      try {
351        return input.readShort();
352      } catch (IOException e) {
353        throw new IllegalStateException(e);
354      }
355    }
356
357    @Override public int readUnsignedShort() {
358      try {
359        return input.readUnsignedShort();
360      } catch (IOException e) {
361        throw new IllegalStateException(e);
362      }
363    }
364
365    @Override public char readChar() {
366      try {
367        return input.readChar();
368      } catch (IOException e) {
369        throw new IllegalStateException(e);
370      }
371    }
372
373    @Override public int readInt() {
374      try {
375        return input.readInt();
376      } catch (IOException e) {
377        throw new IllegalStateException(e);
378      }
379    }
380
381    @Override public long readLong() {
382      try {
383        return input.readLong();
384      } catch (IOException e) {
385        throw new IllegalStateException(e);
386      }
387    }
388
389    @Override public float readFloat() {
390      try {
391        return input.readFloat();
392      } catch (IOException e) {
393        throw new IllegalStateException(e);
394      }
395    }
396
397    @Override public double readDouble() {
398      try {
399        return input.readDouble();
400      } catch (IOException e) {
401        throw new IllegalStateException(e);
402      }
403    }
404
405    @Override public String readLine() {
406      try {
407        return input.readLine();
408      } catch (IOException e) {
409        throw new IllegalStateException(e);
410      }
411    }
412
413    @Override public String readUTF() {
414      try {
415        return input.readUTF();
416      } catch (IOException e) {
417        throw new IllegalStateException(e);
418      }
419    }
420  }
421
422  /**
423   * Returns a new {@link ByteArrayDataOutput} instance with a default size.
424   */
425  public static ByteArrayDataOutput newDataOutput() {
426    return new ByteArrayDataOutputStream();
427  }
428
429  /**
430   * Returns a new {@link ByteArrayDataOutput} instance sized to hold
431   * {@code size} bytes before resizing.
432   *
433   * @throws IllegalArgumentException if {@code size} is negative
434   */
435  public static ByteArrayDataOutput newDataOutput(int size) {
436    checkArgument(size >= 0, "Invalid size: %s", size);
437    return new ByteArrayDataOutputStream(size);
438  }
439
440  @SuppressWarnings("deprecation") // for writeBytes
441  private static class ByteArrayDataOutputStream
442      implements ByteArrayDataOutput {
443
444    final DataOutput output;
445    final ByteArrayOutputStream byteArrayOutputSteam;
446
447    ByteArrayDataOutputStream() {
448      this(new ByteArrayOutputStream());
449    }
450
451    ByteArrayDataOutputStream(int size) {
452      this(new ByteArrayOutputStream(size));
453    }
454
455    ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputSteam) {
456      this.byteArrayOutputSteam = byteArrayOutputSteam;
457      output = new DataOutputStream(byteArrayOutputSteam);
458    }
459
460    @Override public void write(int b) {
461      try {
462        output.write(b);
463      } catch (IOException impossible) {
464        throw new AssertionError(impossible);
465      }
466    }
467
468    @Override public void write(byte[] b) {
469      try {
470        output.write(b);
471      } catch (IOException impossible) {
472        throw new AssertionError(impossible);
473      }
474    }
475
476    @Override public void write(byte[] b, int off, int len) {
477      try {
478        output.write(b, off, len);
479      } catch (IOException impossible) {
480        throw new AssertionError(impossible);
481      }
482    }
483
484    @Override public void writeBoolean(boolean v) {
485      try {
486        output.writeBoolean(v);
487      } catch (IOException impossible) {
488        throw new AssertionError(impossible);
489      }
490    }
491
492    @Override public void writeByte(int v) {
493      try {
494        output.writeByte(v);
495      } catch (IOException impossible) {
496        throw new AssertionError(impossible);
497      }
498    }
499
500    @Override public void writeBytes(String s) {
501      try {
502        output.writeBytes(s);
503      } catch (IOException impossible) {
504        throw new AssertionError(impossible);
505      }
506    }
507
508    @Override public void writeChar(int v) {
509      try {
510        output.writeChar(v);
511      } catch (IOException impossible) {
512        throw new AssertionError(impossible);
513      }
514    }
515
516    @Override public void writeChars(String s) {
517      try {
518        output.writeChars(s);
519      } catch (IOException impossible) {
520        throw new AssertionError(impossible);
521      }
522    }
523
524    @Override public void writeDouble(double v) {
525      try {
526        output.writeDouble(v);
527      } catch (IOException impossible) {
528        throw new AssertionError(impossible);
529      }
530    }
531
532    @Override public void writeFloat(float v) {
533      try {
534        output.writeFloat(v);
535      } catch (IOException impossible) {
536        throw new AssertionError(impossible);
537      }
538    }
539
540    @Override public void writeInt(int v) {
541      try {
542        output.writeInt(v);
543      } catch (IOException impossible) {
544        throw new AssertionError(impossible);
545      }
546    }
547
548    @Override public void writeLong(long v) {
549      try {
550        output.writeLong(v);
551      } catch (IOException impossible) {
552        throw new AssertionError(impossible);
553      }
554    }
555
556    @Override public void writeShort(int v) {
557      try {
558        output.writeShort(v);
559      } catch (IOException impossible) {
560        throw new AssertionError(impossible);
561      }
562    }
563
564    @Override public void writeUTF(String s) {
565      try {
566        output.writeUTF(s);
567      } catch (IOException impossible) {
568        throw new AssertionError(impossible);
569      }
570    }
571
572    @Override public byte[] toByteArray() {
573      return byteArrayOutputSteam.toByteArray();
574    }
575  }
576
577  private static final OutputStream NULL_OUTPUT_STREAM =
578      new OutputStream() {
579        /** Discards the specified byte. */
580        @Override public void write(int b) {
581        }
582        /** Discards the specified byte array. */
583        @Override public void write(byte[] b) {
584          checkNotNull(b);
585        }
586        /** Discards the specified byte array. */
587        @Override public void write(byte[] b, int off, int len) {
588          checkNotNull(b);
589        }
590
591        @Override
592        public String toString() {
593          return "ByteStreams.nullOutputStream()";
594        }
595      };
596
597  /**
598   * Returns an {@link OutputStream} that simply discards written bytes.
599   *
600   * @since 14.0 (since 1.0 as com.google.common.io.NullOutputStream)
601   */
602  public static OutputStream nullOutputStream() {
603    return NULL_OUTPUT_STREAM;
604  }
605
606  /**
607   * Wraps a {@link InputStream}, limiting the number of bytes which can be
608   * read.
609   *
610   * @param in the input stream to be wrapped
611   * @param limit the maximum number of bytes to be read
612   * @return a length-limited {@link InputStream}
613   * @since 14.0 (since 1.0 as com.google.common.io.LimitInputStream)
614   */
615  public static InputStream limit(InputStream in, long limit) {
616    return new LimitedInputStream(in, limit);
617  }
618
619  private static final class LimitedInputStream extends FilterInputStream {
620
621    private long left;
622    private long mark = -1;
623
624    LimitedInputStream(InputStream in, long limit) {
625      super(in);
626      checkNotNull(in);
627      checkArgument(limit >= 0, "limit must be non-negative");
628      left = limit;
629    }
630
631    @Override public int available() throws IOException {
632      return (int) Math.min(in.available(), left);
633    }
634
635    // it's okay to mark even if mark isn't supported, as reset won't work
636    @Override public synchronized void mark(int readLimit) {
637      in.mark(readLimit);
638      mark = left;
639    }
640
641    @Override public int read() throws IOException {
642      if (left == 0) {
643        return -1;
644      }
645
646      int result = in.read();
647      if (result != -1) {
648        --left;
649      }
650      return result;
651    }
652
653    @Override public int read(byte[] b, int off, int len) throws IOException {
654      if (left == 0) {
655        return -1;
656      }
657
658      len = (int) Math.min(len, left);
659      int result = in.read(b, off, len);
660      if (result != -1) {
661        left -= result;
662      }
663      return result;
664    }
665
666    @Override public synchronized void reset() throws IOException {
667      if (!in.markSupported()) {
668        throw new IOException("Mark not supported");
669      }
670      if (mark == -1) {
671        throw new IOException("Mark not set");
672      }
673
674      in.reset();
675      left = mark;
676    }
677
678    @Override public long skip(long n) throws IOException {
679      n = Math.min(n, left);
680      long skipped = in.skip(n);
681      left -= skipped;
682      return skipped;
683    }
684  }
685
686  /** Returns the length of a supplied input stream, in bytes. */
687  public static long length(
688      InputSupplier<? extends InputStream> supplier) throws IOException {
689    return asByteSource(supplier).size();
690  }
691
692  /**
693   * Returns true if the supplied input streams contain the same bytes.
694   *
695   * @throws IOException if an I/O error occurs
696   */
697  public static boolean equal(InputSupplier<? extends InputStream> supplier1,
698      InputSupplier<? extends InputStream> supplier2) throws IOException {
699    return asByteSource(supplier1).contentEquals(asByteSource(supplier2));
700  }
701
702  /**
703   * Attempts to read enough bytes from the stream to fill the given byte array,
704   * with the same behavior as {@link DataInput#readFully(byte[])}.
705   * Does not close the stream.
706   *
707   * @param in the input stream to read from.
708   * @param b the buffer into which the data is read.
709   * @throws EOFException if this stream reaches the end before reading all
710   *     the bytes.
711   * @throws IOException if an I/O error occurs.
712   */
713  public static void readFully(InputStream in, byte[] b) throws IOException {
714    readFully(in, b, 0, b.length);
715  }
716
717  /**
718   * Attempts to read {@code len} bytes from the stream into the given array
719   * starting at {@code off}, with the same behavior as
720   * {@link DataInput#readFully(byte[], int, int)}. Does not close the
721   * stream.
722   *
723   * @param in the input stream to read from.
724   * @param b the buffer into which the data is read.
725   * @param off an int specifying the offset into the data.
726   * @param len an int specifying the number of bytes to read.
727   * @throws EOFException if this stream reaches the end before reading all
728   *     the bytes.
729   * @throws IOException if an I/O error occurs.
730   */
731  public static void readFully(
732      InputStream in, byte[] b, int off, int len) throws IOException {
733    int read = read(in, b, off, len);
734    if (read != len) {
735      throw new EOFException("reached end of stream after reading "
736          + read + " bytes; " + len + " bytes expected");
737    }
738  }
739
740  /**
741   * Discards {@code n} bytes of data from the input stream. This method
742   * will block until the full amount has been skipped. Does not close the
743   * stream.
744   *
745   * @param in the input stream to read from
746   * @param n the number of bytes to skip
747   * @throws EOFException if this stream reaches the end before skipping all
748   *     the bytes
749   * @throws IOException if an I/O error occurs, or the stream does not
750   *     support skipping
751   */
752  public static void skipFully(InputStream in, long n) throws IOException {
753    long toSkip = n;
754    while (n > 0) {
755      long amt = in.skip(n);
756      if (amt == 0) {
757        // Force a blocking read to avoid infinite loop
758        if (in.read() == -1) {
759          long skipped = toSkip - n;
760          throw new EOFException("reached end of stream after skipping "
761              + skipped + " bytes; " + toSkip + " bytes expected");
762        }
763        n--;
764      } else {
765        n -= amt;
766      }
767    }
768  }
769
770  /**
771   * Process the bytes of a supplied stream
772   *
773   * @param supplier the input stream factory
774   * @param processor the object to which to pass the bytes of the stream
775   * @return the result of the byte processor
776   * @throws IOException if an I/O error occurs
777   */
778  public static <T> T readBytes(
779      InputSupplier<? extends InputStream> supplier,
780      ByteProcessor<T> processor) throws IOException {
781    checkNotNull(supplier);
782    checkNotNull(processor);
783
784    Closer closer = Closer.create();
785    try {
786      InputStream in = closer.register(supplier.getInput());
787      return readBytes(in, processor);
788    } catch (Throwable e) {
789      throw closer.rethrow(e);
790    } finally {
791      closer.close();
792    }
793  }
794
795  /**
796   * Process the bytes of the given input stream using the given processor.
797   *
798   * @param input the input stream to process
799   * @param processor the object to which to pass the bytes of the stream
800   * @return the result of the byte processor
801   * @throws IOException if an I/O error occurs
802   * @since 14.0
803   */
804  public static <T> T readBytes(
805      InputStream input, ByteProcessor<T> processor) throws IOException {
806    checkNotNull(input);
807    checkNotNull(processor);
808
809    byte[] buf = new byte[BUF_SIZE];
810    int read;
811    do {
812      read = input.read(buf);
813    } while (read != -1 && processor.processBytes(buf, 0, read));
814    return processor.getResult();
815  }
816
817  /**
818   * Computes and returns the checksum value for a supplied input stream.
819   * The checksum object is reset when this method returns successfully.
820   *
821   * @param supplier the input stream factory
822   * @param checksum the checksum object
823   * @return the result of {@link Checksum#getValue} after updating the
824   *     checksum object with all of the bytes in the stream
825   * @throws IOException if an I/O error occurs
826   * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
827   *     {@code Hashing.adler32()} hash functions instead. This method is
828   *     scheduled to be removed in Guava 15.0.
829   */
830  @Deprecated
831  public static long getChecksum(
832      InputSupplier<? extends InputStream> supplier, final Checksum checksum)
833      throws IOException {
834    checkNotNull(checksum);
835    return readBytes(supplier, new ByteProcessor<Long>() {
836      @Override
837      public boolean processBytes(byte[] buf, int off, int len) {
838        checksum.update(buf, off, len);
839        return true;
840      }
841      @Override
842      public Long getResult() {
843        long result = checksum.getValue();
844        checksum.reset();
845        return result;
846      }
847    });
848  }
849
850  /**
851   * Computes the hash code of the data supplied by {@code supplier} using {@code
852   * hashFunction}.
853   *
854   * @param supplier the input stream factory
855   * @param hashFunction the hash function to use to hash the data
856   * @return the {@link HashCode} of all of the bytes in the input stream
857   * @throws IOException if an I/O error occurs
858   * @since 12.0
859   */
860  public static HashCode hash(
861      InputSupplier<? extends InputStream> supplier, HashFunction hashFunction)
862      throws IOException {
863    return asByteSource(supplier).hash(hashFunction);
864  }
865
866  /**
867   * Reads some bytes from an input stream and stores them into the buffer array
868   * {@code b}. This method blocks until {@code len} bytes of input data have
869   * been read into the array, or end of file is detected. The number of bytes
870   * read is returned, possibly zero. Does not close the stream.
871   *
872   * <p>A caller can detect EOF if the number of bytes read is less than
873   * {@code len}. All subsequent calls on the same stream will return zero.
874   *
875   * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If
876   * {@code off} is negative, or {@code len} is negative, or {@code off+len} is
877   * greater than the length of the array {@code b}, then an
878   * {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then
879   * no bytes are read. Otherwise, the first byte read is stored into element
880   * {@code b[off]}, the next one into {@code b[off+1]}, and so on. The number
881   * of bytes read is, at most, equal to {@code len}.
882   *
883   * @param in the input stream to read from
884   * @param b the buffer into which the data is read
885   * @param off an int specifying the offset into the data
886   * @param len an int specifying the number of bytes to read
887   * @return the number of bytes read
888   * @throws IOException if an I/O error occurs
889   */
890  public static int read(InputStream in, byte[] b, int off, int len)
891      throws IOException {
892    checkNotNull(in);
893    checkNotNull(b);
894    if (len < 0) {
895      throw new IndexOutOfBoundsException("len is negative");
896    }
897    int total = 0;
898    while (total < len) {
899      int result = in.read(b, off + total, len - total);
900      if (result == -1) {
901        break;
902      }
903      total += result;
904    }
905    return total;
906  }
907
908  /**
909   * Returns an {@link InputSupplier} that returns input streams from the
910   * an underlying supplier, where each stream starts at the given
911   * offset and is limited to the specified number of bytes.
912   *
913   * @param supplier the supplier from which to get the raw streams
914   * @param offset the offset in bytes into the underlying stream where
915   *     the returned streams will start
916   * @param length the maximum length of the returned streams
917   * @throws IllegalArgumentException if offset or length are negative
918   */
919  public static InputSupplier<InputStream> slice(
920      final InputSupplier<? extends InputStream> supplier,
921      final long offset,
922      final long length) {
923    return asInputSupplier(asByteSource(supplier).slice(offset, length));
924  }
925
926  /**
927   * Joins multiple {@link InputStream} suppliers into a single supplier.
928   * Streams returned from the supplier will contain the concatenated data from
929   * the streams of the underlying suppliers.
930   *
931   * <p>Only one underlying input stream will be open at a time. Closing the
932   * joined stream will close the open underlying stream.
933   *
934   * <p>Reading from the joined stream will throw a {@link NullPointerException}
935   * if any of the suppliers are null or return null.
936   *
937   * @param suppliers the suppliers to concatenate
938   * @return a supplier that will return a stream containing the concatenated
939   *     stream data
940   */
941  public static InputSupplier<InputStream> join(
942      final Iterable<? extends InputSupplier<? extends InputStream>> suppliers) {
943    checkNotNull(suppliers);
944    return new InputSupplier<InputStream>() {
945      @Override public InputStream getInput() throws IOException {
946        return new MultiInputStream(suppliers.iterator());
947      }
948    };
949  }
950
951  /** Varargs form of {@link #join(Iterable)}. */
952  public static InputSupplier<InputStream> join(
953      InputSupplier<? extends InputStream>... suppliers) {
954    return join(Arrays.asList(suppliers));
955  }
956
957  // TODO(user): Remove these once Input/OutputSupplier methods are removed
958
959  static <S extends InputStream> InputSupplier<S> asInputSupplier(
960      final ByteSource source) {
961    checkNotNull(source);
962    return new InputSupplier<S>() {
963      @SuppressWarnings("unchecked") // used internally where known to be safe
964      @Override
965      public S getInput() throws IOException {
966        return (S) source.openStream();
967      }
968    };
969  }
970
971  static <S extends OutputStream> OutputSupplier<S> asOutputSupplier(
972      final ByteSink sink) {
973    checkNotNull(sink);
974    return new OutputSupplier<S>() {
975      @SuppressWarnings("unchecked") // used internally where known to be safe
976      @Override
977      public S getOutput() throws IOException {
978        return (S) sink.openStream();
979      }
980    };
981  }
982
983  static ByteSource asByteSource(
984      final InputSupplier<? extends InputStream> supplier) {
985    checkNotNull(supplier);
986    return new ByteSource() {
987      @Override
988      public InputStream openStream() throws IOException {
989        return supplier.getInput();
990      }
991    };
992  }
993
994  static ByteSink asByteSink(
995      final OutputSupplier<? extends OutputStream> supplier) {
996    checkNotNull(supplier);
997    return new ByteSink() {
998      @Override
999      public OutputStream openStream() throws IOException {
1000        return supplier.getOutput();
1001      }
1002    };
1003  }
1004}