1// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.archivepatcher.applier;
16
17import java.io.FilterInputStream;
18import java.io.IOException;
19import java.io.InputStream;
20
21/**
22 * A stream that simulates EOF after a specified numToRead of bytes has been reached.
23 */
24public class LimitedInputStream extends FilterInputStream {
25  /**
26   * Current numToRead.
27   */
28  private long numToRead;
29
30  /**
31   * Buffer used for one-byte reads to keep all code on the same path.
32   */
33  private byte[] ONE_BYTE = new byte[1];
34
35  /**
36   * Creates a new limited stream that delegates operations to the specified stream.
37   * @param in the stream to limit
38   * @param numToRead the number of reads to allow before returning EOF
39   */
40  public LimitedInputStream(InputStream in, long numToRead) {
41    super(in);
42    if (numToRead < 0) {
43      throw new IllegalArgumentException("numToRead must be >= 0: " + numToRead);
44    }
45    this.numToRead = numToRead;
46  }
47
48  @Override
49  public int read() throws IOException {
50    if (read(ONE_BYTE, 0, 1) == 1) {
51      return ONE_BYTE[0];
52    }
53    return -1;
54  }
55
56  @Override
57  public int read(byte[] b) throws IOException {
58    return read(b, 0, b.length);
59  }
60
61  @Override
62  public int read(byte[] b, int off, int len) throws IOException {
63    if (numToRead == 0) {
64      return -1; // Simulate EOF
65    }
66    int maxRead = (int) Math.min(len, numToRead);
67    int numRead = in.read(b, off, maxRead);
68    if (numRead > 0) {
69      numToRead -= numRead;
70    }
71    return numRead;
72  }
73}
74