1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.util;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.DataInputStream;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.IOException;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.InputStream;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Wrapper for a {@code byte[]}, which provides read-only access and
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * can "reveal" a partial slice of the underlying array.
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <b>Note:</b> Multibyte accessors all use big-endian order.
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class ByteArray {
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} underlying array */
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final byte[] bytes;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code >= 0}; start index of the slice (inclusive) */
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int start;
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code >= 0, <= bytes.length}; size computed as
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code end - start} (in the constructor) */
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int size;
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance.
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bytes {@code non-null;} the underlying array
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param start {@code >= 0;} start index of the slice (inclusive)
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param end {@code >= start, <= bytes.length;} end index of
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the slice (exclusive)
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ByteArray(byte[] bytes, int start, int end) {
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (bytes == null) {
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("bytes == null");
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (start < 0) {
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("start < 0");
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (end < start) {
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("end < start");
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (end > bytes.length) {
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("end > bytes.length");
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.bytes = bytes;
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.start = start;
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.size = end - start;
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance from an entire {@code byte[]}.
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bytes {@code non-null;} the underlying array
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ByteArray(byte[] bytes) {
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this(bytes, 0, bytes.length);
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the size of the array, in bytes.
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code >= 0;} the size
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int size() {
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return size;
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns a slice (that is, a sub-array) of this instance.
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param start {@code >= 0;} start index of the slice (inclusive)
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param end {@code >= start, <= size();} end index of
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the slice (exclusive)
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the slice
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ByteArray slice(int start, int end) {
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(start, end);
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new ByteArray(bytes, start + this.start, end + this.start);
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns the offset into the given array represented by the given
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * offset into this instance.
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param offset offset into this instance
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bytes {@code non-null;} (alleged) underlying array
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return corresponding offset into {@code bytes}
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IllegalArgumentException thrown if {@code bytes} is
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * not the underlying array of this instance
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int underlyingOffset(int offset, byte[] bytes) {
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (bytes != this.bytes) {
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("wrong bytes");
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return start + offset;
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code signed byte} value at a particular offset.
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < size();} offset to fetch
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code signed byte} at that offset
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int getByte(int off) {
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 1);
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return getByte0(off);
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code signed short} value at a particular offset.
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < (size() - 1);} offset to fetch
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code signed short} at that offset
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int getShort(int off) {
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 2);
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code signed int} value at a particular offset.
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < (size() - 3);} offset to fetch
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code signed int} at that offset
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int getInt(int off) {
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 4);
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (getByte0(off) << 24) |
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 1) << 16) |
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 2) << 8) |
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            getUnsignedByte0(off + 3);
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code signed long} value at a particular offset.
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < (size() - 7);} offset to fetch
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code signed int} at that offset
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public long getLong(int off) {
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 8);
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int part1 = (getByte0(off) << 24) |
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 1) << 16) |
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 2) << 8) |
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            getUnsignedByte0(off + 3);
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int part2 = (getByte0(off + 4) << 24) |
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 5) << 16) |
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (getUnsignedByte0(off + 6) << 8) |
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            getUnsignedByte0(off + 7);
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (part2 & 0xffffffffL) | ((long) part1) << 32;
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code unsigned byte} value at a particular offset.
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < size();} offset to fetch
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code unsigned byte} at that offset
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int getUnsignedByte(int off) {
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 1);
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return getUnsignedByte0(off);
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code unsigned short} value at a particular offset.
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off {@code >= 0, < (size() - 1);} offset to fetch
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code unsigned short} at that offset
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int getUnsignedShort(int off) {
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        checkOffsets(off, off + 2);
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Copies the contents of this instance into the given raw
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code byte[]} at the given offset. The given array must be
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * large enough.
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} array to hold the output
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param offset {@code non-null;} index into {@code out} for the first
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * byte of output
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void getBytes(byte[] out, int offset) {
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((out.length - offset) < size) {
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IndexOutOfBoundsException("(out.length - offset) < " +
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                                "size()");
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        System.arraycopy(bytes, start, out, offset, size);
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Checks a range of offsets for validity, throwing if invalid.
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param s start offset (inclusive)
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param e end offset (exclusive)
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void checkOffsets(int s, int e) {
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((s < 0) || (e < s) || (e > size)) {
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("bad range: " + s + ".." + e +
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                               "; actual size " + size);
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code signed byte} value at the given offset,
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * without doing any argument checking.
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off offset to fetch
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return byte at that offset
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int getByte0(int off) {
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return bytes[start + off];
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the {@code unsigned byte} value at the given offset,
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * without doing any argument checking.
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param off offset to fetch
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return byte at that offset
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int getUnsignedByte0(int off) {
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return bytes[start + off] & 0xff;
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets a {@code DataInputStream} that reads from this instance,
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * with the cursor starting at the beginning of this instance's data.
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * if needed.
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} an appropriately-constructed
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code DataInputStream} instance
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public MyDataInputStream makeDataInputStream() {
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new MyDataInputStream(makeInputStream());
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets a {@code InputStream} that reads from this instance,
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * with the cursor starting at the beginning of this instance's data.
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <b>Note:</b> The returned instance may be cast to {@link #GetCursor}
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * if needed.
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} an appropriately-constructed
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code InputStream} instancex
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public MyInputStream makeInputStream() {
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new MyInputStream();
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper interface that allows one to get the cursor (of a stream).
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public interface GetCursor {
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the current cursor.
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code 0..size();} the cursor
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int getCursor();
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper class for {@link #makeInputStream}, which implements the
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * stream functionality.
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public class MyInputStream extends InputStream {
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** 0..size; the cursor */
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private int cursor;
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** 0..size; the mark */
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private int mark;
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public MyInputStream() {
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cursor = 0;
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            mark = 0;
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int read() throws IOException {
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (cursor >= size) {
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return -1;
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int result = getUnsignedByte0(cursor);
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cursor++;
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return result;
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int read(byte[] arr, int offset, int length) {
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((offset + length) > arr.length) {
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                length = arr.length - offset;
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int maxLength = size - cursor;
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (length > maxLength) {
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                length = maxLength;
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.arraycopy(bytes, cursor + start, arr, offset, length);
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cursor += length;
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return length;
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int available() {
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return size - cursor;
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void mark(int reserve) {
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            mark = cursor;
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void reset() {
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cursor = mark;
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean markSupported() {
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return true;
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper class for {@link #makeDataInputStream}. This is used
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * simply so that the cursor of a wrapped {@link #MyInputStream}
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instance may be easily determined.
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static class MyDataInputStream extends DataInputStream {
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} the underlying {@link #MyInputStream} */
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final MyInputStream wrapped;
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public MyDataInputStream(MyInputStream wrapped) {
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super(wrapped);
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.wrapped = wrapped;
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
362