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.dex.file;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.Constant;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.TypeList;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.AnnotatedOutput;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collection;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
3099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Class definitions list section of a {@code .dex} file.
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class ClassDefsSection extends UniformItemSection {
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
3499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} map from type constants for classes to {@link
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * ClassDefItem} instances that define those classes
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final TreeMap<Type, ClassDefItem> classDefs;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code null-ok;} ordered list of classes; set in {@link #orderItems} */
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ArrayList<ClassDefItem> orderedDefs;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance. The file offset is initially unknown.
44de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
4599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param file {@code non-null;} file that this instance is part of
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ClassDefsSection(DexFile file) {
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super("class_defs", file, 4);
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        classDefs = new TreeMap<Type, ClassDefItem>();
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        orderedDefs = null;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Collection<? extends Item> items() {
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (orderedDefs != null) {
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return orderedDefs;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
60de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return classDefs.values();
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public IndexedItem get(Constant cst) {
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cst == null) {
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("cst == null");
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throwIfNotPrepared();
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Type type = ((CstType) cst).getClassType();
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IndexedItem result = classDefs.get(type);
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result == null) {
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("not found");
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result;
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Writes the portion of the file header that refers to this instance.
85de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
8699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to write
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void writeHeaderPart(AnnotatedOutput out) {
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throwIfNotPrepared();
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = classDefs.size();
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int offset = (sz == 0) ? 0 : getFileOffset();
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (out.annotates()) {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.annotate(4, "class_defs_size: " + Hex.u4(sz));
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.annotate(4, "class_defs_off:  " + Hex.u4(offset));
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.writeInt(sz);
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.writeInt(offset);
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds an element to this instance. It is illegal to attempt to add more
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * than one class with the same name.
106de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
10799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param clazz {@code non-null;} the class def to add
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void add(ClassDefItem clazz) {
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Type type;
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            type = clazz.getThisClass().getClassType();
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (NullPointerException ex) {
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Elucidate the exception.
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("clazz == null");
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throwIfPrepared();
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (classDefs.get(type) != null) {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("already added: " + type);
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        classDefs.put(type, clazz);
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected void orderItems() {
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = classDefs.size();
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = 0;
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        orderedDefs = new ArrayList<ClassDefItem>(sz);
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Iterate over all the classes, recursively assigning an
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * index to each, implicitly skipping the ones that have
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * already been assigned by the time this (top-level)
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * iteration reaches them.
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Type type : classDefs.keySet()) {
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            idx = orderItems0(type, idx, sz - idx);
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #orderItems}, which recursively assigns indices
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to classes.
150de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
15199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param type {@code null-ok;} type ref to assign, if any
15299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param idx {@code >= 0;} the next index to assign
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param maxDepth maximum recursion depth; if negative, this will
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throw an exception indicating class definition circularity
15599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the next index to assign
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int orderItems0(Type type, int idx, int maxDepth) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassDefItem c = classDefs.get(type);
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((c == null) || (c.hasIndex())) {
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return idx;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (maxDepth < 0) {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException("class circularity with " + type);
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        maxDepth--;
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CstType superclassCst = c.getSuperclass();
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (superclassCst != null) {
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type superclass = superclassCst.getClassType();
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            idx = orderItems0(superclass, idx, maxDepth);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TypeList interfaces = c.getInterfaces();
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = interfaces.size();
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            idx = orderItems0(interfaces.getType(i), idx, maxDepth);
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        c.setIndex(idx);
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        orderedDefs.add(c);
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return idx + 1;
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
187