1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.util;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.Writer;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Implementation of {@link AnnotatedOutput} which stores the written data
2599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * into a {@code byte[]}.
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p><b>Note:</b> As per the {@link Output} interface, multi-byte
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * writes all use little-endian order.</p>
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class ByteArrayAnnotatedOutput
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        implements AnnotatedOutput {
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** default size for stretchy instances */
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int DEFAULT_SIZE = 1000;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * whether the instance is stretchy, that is, whether its array
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * may be resized to increase capacity
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final boolean stretchy;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the data itself */
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private byte[] data;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code >= 0;} current output cursor */
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int cursor;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** whether annotations are to be verbose */
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean verbose;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
5199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null-ok;} list of annotations, or {@code null} if this instance
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * isn't keeping them
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ArrayList<Annotation> annotations;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code >= 40 (if used);} the desired maximum annotation width */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int annotationWidth;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
6099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code >= 8 (if used);} the number of bytes of hex output to use
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in annotations
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int hexCols;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance with a fixed maximum size. Note that the
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * given array is the only one that will be used to store data. In
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * particular, no reallocation will occur in order to expand the
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * capacity of the resulting instance. Also, the constructed
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * instance does not keep annotations by default.
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param data {@code non-null;} data array to use for output
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ByteArrayAnnotatedOutput(byte[] data) {
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this(data, false);
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs a "stretchy" instance. The underlying array may be
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * reallocated. The constructed instance does not keep annotations
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * by default.
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ByteArrayAnnotatedOutput() {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this(new byte[DEFAULT_SIZE], true);
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Internal constructor.
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param data {@code non-null;} data array to use for output
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param stretchy whether the instance is to be stretchy
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (data == null) {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("data == null");
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.stretchy = stretchy;
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.data = data;
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cursor = 0;
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.verbose = false;
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.annotations = null;
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.annotationWidth = 0;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.hexCols = 0;
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
10899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the underlying {@code byte[]} of this instance, which
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * may be larger than the number of bytes written
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see #toByteArray
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
11399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the {@code byte[]}
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] getArray() {
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return data;
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Constructs and returns a new {@code byte[]} that contains
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the written contents exactly (that is, with no extra unwritten
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * bytes at the end).
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see #getArray
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
12699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} an appropriately-constructed array
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public byte[] toByteArray() {
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] result = new byte[cursor];
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(data, 0, result, 0, cursor);
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result;
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getCursor() {
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return cursor;
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void assertCursor(int expectedCursor) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cursor != expectedCursor) {
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new ExceptionWithContext("expected cursor " +
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    expectedCursor + "; actual value: " + cursor);
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeByte(int value) {
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + 1;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt] = (byte) value;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeShort(int value) {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + 2;
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt] = (byte) value;
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 1] = (byte) (value >> 8);
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeInt(int value) {
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + 4;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt] = (byte) value;
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 1] = (byte) (value >> 8);
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 2] = (byte) (value >> 16);
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 3] = (byte) (value >> 24);
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeLong(long value) {
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + 8;
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int half = (int) value;
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt] = (byte) half;
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 1] = (byte) (half >> 8);
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 2] = (byte) (half >> 16);
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 3] = (byte) (half >> 24);
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        half = (int) (value >> 32);
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 4] = (byte) half;
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 5] = (byte) (half >> 8);
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 6] = (byte) (half >> 16);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        data[writeAt + 7] = (byte) (half >> 24);
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int writeUnsignedLeb128(int value) {
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int remaining = value >> 7;
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int count = 0;
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while (remaining != 0) {
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            writeByte((value & 0x7f) | 0x80);
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            value = remaining;
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            remaining >>= 7;
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            count++;
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        writeByte(value & 0x7f);
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return count + 1;
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int writeSignedLeb128(int value) {
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int remaining = value >> 7;
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int count = 0;
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean hasMore = true;
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while (hasMore) {
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hasMore = (remaining != end)
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                || ((remaining & 1) != ((value >> 6) & 1));
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            writeByte((value & 0x7f) | (hasMore ? 0x80 : 0));
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            value = remaining;
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            remaining >>= 7;
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            count++;
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return count;
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void write(ByteArray bytes) {
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int blen = bytes.size();
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + blen;
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytes.getBytes(data, writeAt);
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void write(byte[] bytes, int offset, int length) {
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int writeAt = cursor;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = writeAt + length;
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int bytesEnd = offset + length;
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IndexOutOfBoundsException("bytes.length " +
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                                bytes.length + "; " +
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                                offset + "..!" + end);
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        System.arraycopy(bytes, offset, data, writeAt, length);
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void write(byte[] bytes) {
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        write(bytes, 0, bytes.length);
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeZeroes(int count) {
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (count < 0) {
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("count < 0");
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = cursor + count;
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * There is no need to actually write zeroes, since the array is
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * already preinitialized with zeroes.
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void alignTo(int alignment) {
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int mask = alignment - 1;
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((alignment < 0) || ((mask & alignment) != 0)) {
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("bogus alignment");
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int end = (cursor + mask) & ~mask;
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stretchy) {
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ensureCapacity(end);
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (end > data.length) {
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throwBounds();
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * There is no need to actually write zeroes, since the array is
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * already preinitialized with zeroes.
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cursor = end;
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public boolean annotates() {
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (annotations != null);
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public boolean isVerbose() {
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return verbose;
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void annotate(String msg) {
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (annotations == null) {
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endAnnotation();
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        annotations.add(new Annotation(cursor, msg));
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void annotate(int amt, String msg) {
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (annotations == null) {
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endAnnotation();
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int asz = annotations.size();
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int startAt;
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (lastEnd <= cursor) {
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startAt = cursor;
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startAt = lastEnd;
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        annotations.add(new Annotation(startAt, startAt + amt, msg));
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void endAnnotation() {
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (annotations == null) {
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = annotations.size();
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sz != 0) {
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            annotations.get(sz - 1).setEndIfUnset(cursor);
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getAnnotationWidth() {
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return annotationWidth - leftWidth;
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Indicates that this instance should keep annotations. This method may
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * be called only once per instance, and only before any data has been
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * written to the it.
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
42299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param annotationWidth {@code >= 40;} the desired maximum annotation width
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param verbose whether or not to indicate verbose annotations
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void enableAnnotations(int annotationWidth, boolean verbose) {
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((annotations != null) || (cursor != 0)) {
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException("cannot enable annotations");
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (annotationWidth < 40) {
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("annotationWidth < 40");
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (hexCols < 6) {
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hexCols = 6;
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (hexCols > 10) {
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hexCols = 10;
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.annotations = new ArrayList<Annotation>(1000);
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.annotationWidth = annotationWidth;
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.hexCols = hexCols;
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.verbose = verbose;
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Finishes up annotation processing. This closes off any open
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * annotations and removes annotations that don't refer to written
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * data.
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void finishAnnotating() {
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Close off the final annotation, if any.
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endAnnotation();
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Remove annotations that refer to unwritten data.
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (annotations != null) {
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int asz = annotations.size();
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (asz > 0) {
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Annotation last = annotations.get(asz - 1);
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (last.getStart() > cursor) {
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    annotations.remove(asz - 1);
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    asz--;
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (last.getEnd() > cursor) {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    last.setEnd(cursor);
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Writes the annotated content of this instance to the given writer.
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
47799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to write to
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeAnnotationsTo(Writer out) throws IOException {
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int width2 = getAnnotationWidth();
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int width1 = annotationWidth - width2 - 1;
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Writer left = twoc.getLeft();
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Writer right = twoc.getRight();
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int leftAt = 0; // left-hand byte output cursor
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int rightAt = 0; // right-hand annotation index
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int rightSz = annotations.size();
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while ((leftAt < cursor) && (rightAt < rightSz)) {
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Annotation a = annotations.get(rightAt);
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int start = a.getStart();
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int end;
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String text;
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (leftAt < start) {
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // This is an area with no annotation.
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                end = start;
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                start = leftAt;
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                text = "";
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // This is an area with an annotation.
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                end = a.getEnd();
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                text = a.getText();
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                rightAt++;
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            right.write(text);
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            twoc.flush();
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            leftAt = end;
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (leftAt < cursor) {
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // There is unannotated output at the end.
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                hexCols, 6));
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while (rightAt < rightSz) {
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // There are zero-byte annotations at the end.
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            right.write(annotations.get(rightAt).getText());
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            rightAt++;
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        twoc.flush();
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Throws the excpetion for when an attempt is made to write past the
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * end of the instance.
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void throwBounds() {
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throw new IndexOutOfBoundsException("attempt to write past the end");
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Reallocates the underlying array if necessary. Calls to this method
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * should be guarded by a test of {@link #stretchy}.
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
54199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param desiredSize {@code >= 0;} the desired minimum total size of the array
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void ensureCapacity(int desiredSize) {
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (data.length < desiredSize) {
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            byte[] newData = new byte[desiredSize * 2 + 1000];
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.arraycopy(data, 0, newData, 0, cursor);
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            data = newData;
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Annotation on output.
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class Annotation {
55599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code >= 0;} start of annotated range (inclusive) */
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final int start;
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
55999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * {@code >= 0;} end of annotated range (exclusive);
56099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * {@code Integer.MAX_VALUE} if unclosed
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int end;
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code non-null;} annotation text */
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final String text;
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs an instance.
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
57099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param start {@code >= 0;} start of annotated range
57199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param end {@code >= start;} end of annotated range (exclusive) or
57299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * {@code Integer.MAX_VALUE} if unclosed
57399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param text {@code non-null;} annotation text
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public Annotation(int start, int end, String text) {
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.start = start;
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.end = end;
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.text = text;
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs an instance. It is initally unclosed.
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
58499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param start {@code >= 0;} start of annotated range
58599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param text {@code non-null;} annotation text
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public Annotation(int start, String text) {
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this(start, Integer.MAX_VALUE, text);
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Sets the end as given, but only if the instance is unclosed;
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * otherwise, do nothing.
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
59599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param end {@code >= start;} the end
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void setEndIfUnset(int end) {
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (this.end == Integer.MAX_VALUE) {
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                this.end = end;
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Sets the end as given.
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
60699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param end {@code >= start;} the end
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void setEnd(int end) {
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.end = end;
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Gets the start.
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return the start
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int getStart() {
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return start;
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Gets the end.
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return the end
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int getEnd() {
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return end;
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Gets the text.
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
63399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @return {@code non-null;} the text
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String getText() {
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return text;
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
640