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
19333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Class;
20333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Double;
21333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Fieldref;
22333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Float;
23333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Integer;
24333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_InterfaceMethodref;
25333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Long;
26333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Methodref;
27333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_NameAndType;
28333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_String;
29333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_Utf8;
305ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartinimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_MethodHandle;
315ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartinimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_MethodType;
325ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartinimport static com.android.dx.cf.cst.ConstantTags.CONSTANT_InvokeDynamic;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseException;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseObserver;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.Constant;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstDouble;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstFieldRef;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstFloat;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInteger;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInterfaceMethodRef;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstLong;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstMethodRef;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstNat;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstString;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.StdConstantPool;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ByteArray;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
50333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport java.util.BitSet;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Parser for a constant pool embedded in a class file.
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class ConstantPoolParser {
5699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the bytes of the constant pool */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ByteArray bytes;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} actual parsed constant pool contents */
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final StdConstantPool pool;
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} byte offsets to each cst */
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int[] offsets;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * -1 || >= 10; the end offset of this constant pool in the
6799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code byte[]} which it came from or {@code -1} if not
68de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     * yet parsed
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int endOffset;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code null-ok;} parse observer, if any */
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ParseObserver observer;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
77de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} the bytes of the file
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ConstantPoolParser(ByteArray bytes) {
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = bytes.getUnsignedShort(8); // constant_pool_count
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.bytes = bytes;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.pool = new StdConstantPool(size);
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.offsets = new int[size];
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.endOffset = -1;
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets the parse observer for this instance.
91de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
9299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param observer {@code null-ok;} the observer
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void setObserver(ParseObserver observer) {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.observer = observer;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
9999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the end offset of this constant pool in the {@code byte[]}
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * which it came from.
101de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
10299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 10;} the end offset
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getEndOffset() {
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return endOffset;
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the actual constant pool.
111de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
11299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the constant pool
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public StdConstantPool getPool() {
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return pool;
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Runs {@link #parse} if it has not yet been run successfully.
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parseIfNecessary() {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (endOffset < 0) {
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            parse();
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Does the actual parsing.
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parse() {
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        determineOffsets();
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (observer != null) {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, 8, 2,
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "constant_pool_count: " + Hex.u2(offsets.length));
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, 10, 0, "\nconstant_pool:");
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.changeIndent(1);
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
141333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson        /*
142333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson         * Track the constant value's original string type. True if constants[i] was
143333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson         * a CONSTANT_Utf8, false for any other type including CONSTANT_string.
144333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson         */
145333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson        BitSet wasUtf8 = new BitSet(offsets.length);
146333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 1; i < offsets.length; i++) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int offset = offsets[i];
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((offset != 0) && (pool.getOrNull(i) == null)) {
150333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                parse0(i, wasUtf8);
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (observer != null) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 1; i < offsets.length; i++) {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Constant cst = pool.getOrNull(i);
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (cst == null) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    continue;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int offset = offsets[i];
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int nextOffset = endOffset;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = i + 1; j < offsets.length; j++) {
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int off = offsets[j];
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (off != 0) {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        nextOffset = off;
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        break;
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
169333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                String human = wasUtf8.get(i)
170333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                        ? Hex.u2(i) + ": utf8{\"" + cst.toHuman() + "\"}"
171333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                        : Hex.u2(i) + ": " + cst.toString();
172333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                observer.parsed(bytes, offset, nextOffset - offset, human);
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.changeIndent(-1);
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, endOffset, 0, "end constant_pool");
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Populates {@link #offsets} and also completely parse utf8 constants.
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void determineOffsets() {
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = 10; // offset from the start of the file to the first cst
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastCategory;
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 1; i < offsets.length; i += lastCategory) {
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offsets[i] = at;
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int tag = bytes.getUnsignedByte(at);
1905ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin            try {
1915ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                switch (tag) {
1925ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Integer:
1935ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Float:
1945ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Fieldref:
1955ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Methodref:
1965ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_InterfaceMethodref:
1975ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_NameAndType: {
1985ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        lastCategory = 1;
1995ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        at += 5;
2005ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        break;
2015ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2025ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Long:
2035ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Double: {
2045ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        lastCategory = 2;
2055ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        at += 9;
2065ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        break;
2075ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2085ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Class:
2095ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_String: {
2105ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        lastCategory = 1;
2115ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        at += 3;
2125ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        break;
2135ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2145ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_Utf8: {
2155ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        lastCategory = 1;
2165ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        at += bytes.getUnsignedShort(at + 1) + 3;
2175ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        break;
2185ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2195ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_MethodHandle: {
2205ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        throw new ParseException("MethodHandle not supported");
2215ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2225ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_MethodType: {
2235ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        throw new ParseException("MethodType not supported");
2245ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2255ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    case CONSTANT_InvokeDynamic: {
2265ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        throw new ParseException("InvokeDynamic not supported");
2275ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
2285ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    default: {
2295ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                        throw new ParseException("unknown tag byte: " + Hex.u1(tag));
2305ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    }
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
2325ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin            } catch (ParseException ex) {
2335ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                ex.addContext("...while preparsing cst " + Hex.u2(i) + " at offset " + Hex.u4(at));
2345ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                throw ex;
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endOffset = at;
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Parses the constant for the given index if it hasn't already been
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * parsed, also storing it in the constant pool. This will also
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * have the side effect of parsing any entries the indicated one
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * depends on.
246de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param idx which constant
24899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the parsed constant
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
250333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson    private Constant parse0(int idx, BitSet wasUtf8) {
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Constant cst = pool.getOrNull(idx);
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cst != null) {
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return cst;
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = offsets[idx];
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int tag = bytes.getUnsignedByte(at);
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (tag) {
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Utf8: {
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = parseUtf8(at);
263333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    wasUtf8.set(idx);
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Integer: {
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int value = bytes.getInt(at + 1);
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstInteger.make(value);
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Float: {
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int bits = bytes.getInt(at + 1);
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstFloat.make(bits);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Long: {
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    long value = bytes.getLong(at + 1);
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstLong.make(value);
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Double: {
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    long bits = bytes.getLong(at + 1);
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = CstDouble.make(bits);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Class: {
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIndex = bytes.getUnsignedShort(at + 1);
288333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstType(Type.internClassName(name.getString()));
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_String: {
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int stringIndex = bytes.getUnsignedShort(at + 1);
294333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    cst = parse0(stringIndex, wasUtf8);
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Fieldref: {
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
299333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstType type = (CstType) parse0(classIndex, wasUtf8);
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
301333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstFieldRef(type, nat);
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_Methodref: {
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
307333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstType type = (CstType) parse0(classIndex, wasUtf8);
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
309333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstMethodRef(type, nat);
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_InterfaceMethodref: {
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int classIndex = bytes.getUnsignedShort(at + 1);
315333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstType type = (CstType) parse0(classIndex, wasUtf8);
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int natIndex = bytes.getUnsignedShort(at + 3);
317333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstInterfaceMethodRef(type, nat);
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case CONSTANT_NameAndType: {
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIndex = bytes.getUnsignedShort(at + 1);
323333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int descriptorIndex = bytes.getUnsignedShort(at + 3);
325333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson                    CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cst = new CstNat(name, descriptor);
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
3295ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                case CONSTANT_MethodHandle: {
3305ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    throw new ParseException("MethodHandle not supported");
3315ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                }
3325ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                case CONSTANT_MethodType: {
3335ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    throw new ParseException("MethodType not supported");
3345ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                }
3355ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                case CONSTANT_InvokeDynamic: {
3365ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    throw new ParseException("InvokeDynamic not supported");
3375ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                }
3385ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                default: {
3395ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                    throw new ParseException("unknown tag byte: " + Hex.u1(tag));
3405ca383d7373cf7c54706b8e70d534deee8d2e3addelphinemartin                }
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (ParseException ex) {
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ex.addContext("...while parsing cst " + Hex.u2(idx) +
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          " at offset " + Hex.u4(at));
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ex;
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (RuntimeException ex) {
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ParseException pe = new ParseException(ex);
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pe.addContext("...while parsing cst " + Hex.u2(idx) +
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          " at offset " + Hex.u4(at));
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw pe;
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pool.set(idx, cst);
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return cst;
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Parses a utf8 constant.
359de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param at offset to the start of the constant (where the tag byte is)
36199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the parsed value
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
363333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson    private CstString parseUtf8(int at) {
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = bytes.getUnsignedShort(at + 1);
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        at += 3; // Skip to the data.
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArray ubytes = bytes.slice(at, at + length);
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
371333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson            return new CstString(ubytes);
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IllegalArgumentException ex) {
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Translate the exception
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new ParseException(ex);
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
378