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.cf.cst;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseException;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseObserver;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.Constant;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstDouble;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstFieldRef;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstFloat;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInteger;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInterfaceMethodRef;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstLong;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstMethodRef;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstNat;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstString;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstUtf8;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.StdConstantPool;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ByteArray;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport static com.android.dx.cf.cst.ConstantTags.*;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Parser for a constant pool embedded in a class file.
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class ConstantPoolParser {
4499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the bytes of the constant pool */
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ByteArray bytes;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} actual parsed constant pool contents */
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final StdConstantPool pool;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} byte offsets to each cst */
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int[] offsets;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * -1 || >= 10; the end offset of this constant pool in the
5599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code byte[]} which it came from or {@code -1} if not
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * yet parsed
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int endOffset;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
6099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code null-ok;} parse observer, if any */
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ParseObserver observer;
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
6699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} the bytes of the file
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ConstantPoolParser(ByteArray bytes) {
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = bytes.getUnsignedShort(8); // constant_pool_count
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.bytes = bytes;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.pool = new StdConstantPool(size);
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.offsets = new int[size];
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.endOffset = -1;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets the parse observer for this instance.
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
8099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param observer {@code null-ok;} the observer
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void setObserver(ParseObserver observer) {
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.observer = observer;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
8799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the end offset of this constant pool in the {@code byte[]}
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * which it came from.
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 10;} the end offset
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getEndOffset() {
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return endOffset;
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the actual constant pool.
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
10099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the constant pool
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public StdConstantPool getPool() {
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return pool;
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Runs {@link #parse} if it has not yet been run successfully.
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parseIfNecessary() {
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (endOffset < 0) {
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            parse();
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Does the actual parsing.
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parse() {
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        determineOffsets();
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (observer != null) {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, 8, 2,
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "constant_pool_count: " + Hex.u2(offsets.length));
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, 10, 0, "\nconstant_pool:");
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.changeIndent(1);
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 1; i < offsets.length; i++) {
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int offset = offsets[i];
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((offset != 0) && (pool.getOrNull(i) == null)) {
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                parse0(i);
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (observer != null) {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 1; i < offsets.length; i++) {
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Constant cst = pool.getOrNull(i);
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (cst == null) {
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    continue;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int offset = offsets[i];
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int nextOffset = endOffset;
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = i + 1; j < offsets.length; j++) {
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int off = offsets[j];
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (off != 0) {
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        nextOffset = off;
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        break;
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                observer.parsed(bytes, offset, nextOffset - offset,
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                Hex.u2(i) + ": " + cst.toString());
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.changeIndent(-1);
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, endOffset, 0, "end constant_pool");
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Populates {@link #offsets} and also completely parse utf8 constants.
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void determineOffsets() {
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = 10; // offset from the start of the file to the first cst
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastCategory;
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 1; i < offsets.length; i += lastCategory) {
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offsets[i] = at;
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int tag = bytes.getUnsignedByte(at);
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (tag) {
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Integer:
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Float:
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Fieldref:
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Methodref:
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_InterfaceMethodref:
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_NameAndType: {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastCategory = 1;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    at += 5;
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Long:
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Double: {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastCategory = 2;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    at += 9;
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Class:
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_String: {
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastCategory = 1;
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    at += 3;
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Utf8: {
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastCategory = 1;
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    at += bytes.getUnsignedShort(at + 1) + 3;
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                default: {
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ParseException ex =
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        new ParseException("unknown tag byte: " + Hex.u1(tag));
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ex.addContext("...while preparsing cst " + Hex.u2(i) +
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                  " at offset " + Hex.u4(at));
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw ex;
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endOffset = at;
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Parses the constant for the given index if it hasn't already been
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * parsed, also storing it in the constant pool. This will also
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * have the side effect of parsing any entries the indicated one
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * depends on.
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param idx which constant
21899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the parsed constant
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Constant parse0(int idx) {
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Constant cst = pool.getOrNull(idx);
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cst != null) {
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return cst;
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = offsets[idx];
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int tag = bytes.getUnsignedByte(at);
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (tag) {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Utf8: {
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = parseUtf8(at);
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Integer: {
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int value = bytes.getInt(at + 1);
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstInteger.make(value);
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Float: {
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int bits = bytes.getInt(at + 1);
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstFloat.make(bits);
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Long: {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    long value = bytes.getLong(at + 1);
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstLong.make(value);
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Double: {
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    long bits = bytes.getLong(at + 1);
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstDouble.make(bits);
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Class: {
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIndex = bytes.getUnsignedShort(at + 1);
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstUtf8 name = (CstUtf8) parse0(nameIndex);
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstType(Type.internClassName(name.getString()));
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_String: {
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int stringIndex = bytes.getUnsignedShort(at + 1);
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstUtf8 string = (CstUtf8) parse0(stringIndex);
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstString(string);
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Fieldref: {
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstType type = (CstType) parse0(classIndex);
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstNat nat = (CstNat) parse0(natIndex);
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstFieldRef(type, nat);
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Methodref: {
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstType type = (CstType) parse0(classIndex);
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstNat nat = (CstNat) parse0(natIndex);
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstMethodRef(type, nat);
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_InterfaceMethodref: {
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstType type = (CstType) parse0(classIndex);
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstNat nat = (CstNat) parse0(natIndex);
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstInterfaceMethodRef(type, nat);
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_NameAndType: {
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIndex = bytes.getUnsignedShort(at + 1);
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstUtf8 name = (CstUtf8) parse0(nameIndex);
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int descriptorIndex = bytes.getUnsignedShort(at + 3);
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    CstUtf8 descriptor = (CstUtf8) parse0(descriptorIndex);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstNat(name, descriptor);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (ParseException ex) {
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ex.addContext("...while parsing cst " + Hex.u2(idx) +
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          " at offset " + Hex.u4(at));
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ex;
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (RuntimeException ex) {
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ParseException pe = new ParseException(ex);
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pe.addContext("...while parsing cst " + Hex.u2(idx) +
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          " at offset " + Hex.u4(at));
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw pe;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pool.set(idx, cst);
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return cst;
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Parses a utf8 constant.
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param at offset to the start of the constant (where the tag byte is)
31999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the parsed value
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private CstUtf8 parseUtf8(int at) {
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = bytes.getUnsignedShort(at + 1);
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        at += 3; // Skip to the data.
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArray ubytes = bytes.slice(at, at + length);
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return new CstUtf8(ubytes);
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IllegalArgumentException ex) {
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Translate the exception
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new ParseException(ex);
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
336