1 package android.content.pm;
2 
3 import com.android.internal.util.ArrayUtils;
4 
5 import java.io.FilterInputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 
9 /**
10  * A class that limits the amount of data that is read from an InputStream. When
11  * the specified length is reached, the stream returns an EOF even if the
12  * underlying stream still has more data.
13  *
14  * @hide
15  */
16 public class LimitedLengthInputStream extends FilterInputStream {
17     /**
18      * The end of the stream where we don't want to allow more data to be read.
19      */
20     private final long mEnd;
21 
22     /**
23      * Current offset in the stream.
24      */
25     private long mOffset;
26 
27     /**
28      * @param in underlying stream to wrap
29      * @param offset offset into stream where data starts
30      * @param length length of data at offset
31      * @throws IOException if an error occurred with the underlying stream
32      */
LimitedLengthInputStream(InputStream in, long offset, long length)33     public LimitedLengthInputStream(InputStream in, long offset, long length) throws IOException {
34         super(in);
35 
36         if (in == null) {
37             throw new IOException("in == null");
38         }
39 
40         if (offset < 0) {
41             throw new IOException("offset < 0");
42         }
43 
44         if (length < 0) {
45             throw new IOException("length < 0");
46         }
47 
48         if (length > Long.MAX_VALUE - offset) {
49             throw new IOException("offset + length > Long.MAX_VALUE");
50         }
51 
52         mEnd = offset + length;
53 
54         skip(offset);
55         mOffset = offset;
56     }
57 
58     @Override
read()59     public synchronized int read() throws IOException {
60         if (mOffset >= mEnd) {
61             return -1;
62         }
63 
64         mOffset++;
65         return super.read();
66     }
67 
68     @Override
read(byte[] buffer, int offset, int byteCount)69     public int read(byte[] buffer, int offset, int byteCount) throws IOException {
70         if (mOffset >= mEnd) {
71             return -1;
72         }
73 
74         final int arrayLength = buffer.length;
75         ArrayUtils.throwsIfOutOfBounds(arrayLength, offset, byteCount);
76 
77         if (mOffset > Long.MAX_VALUE - byteCount) {
78             throw new IOException("offset out of bounds: " + mOffset + " + " + byteCount);
79         }
80 
81         if (mOffset + byteCount > mEnd) {
82             byteCount = (int) (mEnd - mOffset);
83         }
84 
85         final int numRead = super.read(buffer, offset, byteCount);
86         mOffset += numRead;
87 
88         return numRead;
89     }
90 
91     @Override
read(byte[] buffer)92     public int read(byte[] buffer) throws IOException {
93         return read(buffer, 0, buffer.length);
94     }
95 }
96