1ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardpackage android.content.pm;
2ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
3ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.FilterInputStream;
4ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.IOException;
5ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardimport java.io.InputStream;
6103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Rootimport java.util.Arrays;
7ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
8ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward/**
9ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * A class that limits the amount of data that is read from an InputStream. When
10ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * the specified length is reached, the stream returns an EOF even if the
11ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * underlying stream still has more data.
12ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward *
13ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward * @hide
14ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward */
15ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Cowardpublic class LimitedLengthInputStream extends FilterInputStream {
16ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    /**
17ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     * The end of the stream where we don't want to allow more data to be read.
18ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     */
19103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root    private final long mEnd;
20ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
21ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    /**
22ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     * Current offset in the stream.
23ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     */
24103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root    private long mOffset;
25ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
26ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    /**
27ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     * @param in underlying stream to wrap
28ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     * @param offset offset into stream where data starts
29ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     * @param length length of data at offset
30103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root     * @throws IOException if an error occurred with the underlying stream
31ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward     */
32103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root    public LimitedLengthInputStream(InputStream in, long offset, long length) throws IOException {
33ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        super(in);
34ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
35ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (in == null) {
36ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            throw new IOException("in == null");
37ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
38ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
39ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (offset < 0) {
40103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root            throw new IOException("offset < 0");
41ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
42ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
43ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (length < 0) {
44103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root            throw new IOException("length < 0");
45103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        }
46103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root
47103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        if (length > Long.MAX_VALUE - offset) {
48103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root            throw new IOException("offset + length > Long.MAX_VALUE");
49ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
50ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
51ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        mEnd = offset + length;
52ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
53ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        skip(offset);
54ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        mOffset = offset;
55ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
56ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
57ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    @Override
58ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public synchronized int read() throws IOException {
59ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (mOffset >= mEnd) {
60ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            return -1;
61ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
62ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
63ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        mOffset++;
64ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return super.read();
65ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
66ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
67ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    @Override
68ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public int read(byte[] buffer, int offset, int byteCount) throws IOException {
69ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (mOffset >= mEnd) {
70ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            return -1;
71ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
72ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
73103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        final int arrayLength = buffer.length;
74103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        Arrays.checkOffsetAndCount(arrayLength, offset, byteCount);
75103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root
76103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        if (mOffset > Long.MAX_VALUE - byteCount) {
77103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root            throw new IOException("offset out of bounds: " + mOffset + " + " + byteCount);
78103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root        }
79103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root
80ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        if (mOffset + byteCount > mEnd) {
81103d53005e7a3c2735f4ac76fa9b795a7e7e39d7Kenny Root            byteCount = (int) (mEnd - mOffset);
82ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        }
83ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
84ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        final int numRead = super.read(buffer, offset, byteCount);
85ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        mOffset += numRead;
86ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
87ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return numRead;
88ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
89ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
90ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    @Override
91ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    public int read(byte[] buffer) throws IOException {
92ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        return read(buffer, 0, buffer.length);
93ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward    }
94ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward}
95