DexBackedClassDef.java revision dc9e5455bc40510088daa43ec6a3bca77ffc48bc
1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked;
33
34import com.google.common.collect.ImmutableList;
35import org.jf.dexlib2.dexbacked.util.*;
36import org.jf.dexlib2.iface.ClassDef;
37import org.jf.dexlib2.iface.Method;
38
39import javax.annotation.Nonnull;
40import javax.annotation.Nullable;
41import java.util.List;
42
43public class DexBackedClassDef implements ClassDef {
44    @Nonnull public final DexFileBuffer dexFile;
45
46    @Nonnull public final String name;
47    public final int accessFlags;
48    @Nullable public final String superclass;
49    @Nullable public final String sourceFile;
50
51    @Nonnull private final AnnotationsDirectory annotationsDirectory;
52    private final int staticInitialValuesOffset;
53
54    private final int interfacesOffset;
55    private final int classDataOffset;
56
57    //class_def_item offsets
58    private static final int ACCESS_FLAGS_OFFSET = 4;
59    private static final int SUPERCLASS_OFFSET = 8;
60    private static final int INTERFACES_OFFSET = 12;
61    private static final int SOURCE_FILE_OFFSET = 16;
62    private static final int ANNOTATIONS_OFFSET = 20;
63    private static final int CLASS_DATA_OFFSET = 24;
64    private static final int STATIC_INITIAL_VALUES_OFFSET = 28;
65
66    public DexBackedClassDef(@Nonnull DexFileBuffer dexFile,
67                             int classDefOffset) {
68        this.dexFile = dexFile;
69
70        this.name = dexFile.getType(dexFile.readSmallUint(classDefOffset));
71        this.accessFlags = dexFile.readSmallUint(classDefOffset + ACCESS_FLAGS_OFFSET);
72        this.superclass = dexFile.getOptionalString(dexFile.readSmallUint(classDefOffset + SUPERCLASS_OFFSET));
73        this.interfacesOffset = dexFile.readSmallUint(classDefOffset + INTERFACES_OFFSET);
74        this.sourceFile = dexFile.getOptionalString(dexFile.readSmallUint(classDefOffset + SOURCE_FILE_OFFSET));
75
76        int annotationsDirectoryOffset = dexFile.readSmallUint(classDefOffset + ANNOTATIONS_OFFSET);
77        this.annotationsDirectory = AnnotationsDirectory.newOrEmpty(dexFile, annotationsDirectoryOffset);
78
79        this.classDataOffset = dexFile.readSmallUint(CLASS_DATA_OFFSET);
80        this.staticInitialValuesOffset = dexFile.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET);
81    }
82
83
84    @Nonnull @Override public String getName() { return name; }
85    @Override public int getAccessFlags() { return accessFlags; }
86    @Nullable @Override public String getSuperclass() { return superclass; }
87    @Nullable @Override public String getSourceFile() { return sourceFile; }
88
89    @Nonnull
90    @Override
91    public List<String> getInterfaces() {
92        if (interfacesOffset > 0) {
93            final int size = dexFile.readSmallUint(interfacesOffset);
94            return new FixedSizeList<String>() {
95                @Override
96                public String readItem(int index) {
97                    return dexFile.getString(dexFile.readSmallUint(interfacesOffset + 4 + (2*index)));
98                }
99
100                @Override public int size() { return size; }
101            };
102        }
103        return ImmutableList.of();
104    }
105
106    @Nonnull
107    @Override
108    public List<? extends DexBackedAnnotation> getAnnotations() {
109        return annotationsDirectory.getClassAnnotations();
110    }
111
112    @Nonnull
113    @Override
114    public List<? extends DexBackedField> getFields() {
115        if (classDataOffset != 0) {
116            DexFileReader reader = dexFile.readerAt(classDataOffset);
117            int staticFieldCount = reader.readSmallUleb128();
118            int instanceFieldCount = reader.readSmallUleb128();
119            final int fieldCount = staticFieldCount + instanceFieldCount;
120            if (fieldCount > 0) {
121                reader.skipUleb128(); //direct_methods_size
122                reader.skipUleb128(); //virtual_methods_size
123
124                final int fieldsStartOffset = reader.getOffset();
125
126                return new VariableSizeListWithContext<DexBackedField>() {
127                    @Nonnull
128                    @Override
129                    public Iterator listIterator() {
130                        return new Iterator(dexFile, fieldsStartOffset) {
131                            private int previousFieldIndex = 0;
132                            @Nonnull private final AnnotationsDirectory.AnnotationIterator annotationIterator =
133                                    annotationsDirectory.getFieldAnnotationIterator();
134                            @Nonnull private final StaticInitialValueIterator staticInitialValueIterator =
135                                    StaticInitialValueIterator.newOrEmpty(dexFile, staticInitialValuesOffset);
136
137                            @Nonnull
138                            @Override
139                            protected DexBackedField readItem(DexFileReader reader, int index) {
140                                DexBackedField item = new DexBackedField(reader, previousFieldIndex,
141                                        staticInitialValueIterator, annotationIterator);
142                                previousFieldIndex = item.fieldIndex;
143                                return item;
144                            }
145
146                            @Override
147                            protected void skipItem(DexFileReader reader, int index) {
148                                previousFieldIndex = DexBackedField.skipEncodedField(reader, previousFieldIndex);
149                                staticInitialValueIterator.skipNext();
150                            }
151                        };
152                    }
153
154                    @Override public int size() { return fieldCount; }
155                };
156            }
157        }
158        return ImmutableList.of();
159    }
160
161    @Nonnull
162    @Override
163    public List<? extends Method> getMethods() {
164        if (classDataOffset > 0) {
165            DexFileReader reader = dexFile.readerAt(classDataOffset);
166            int staticFieldCount = reader.readSmallUleb128();
167            int instanceFieldCount = reader.readSmallUleb128();
168            int directMethodCount = reader.readSmallUleb128();
169            int virtualMethodCount = reader.readSmallUleb128();
170            final int methodCount = directMethodCount + virtualMethodCount;
171            if (methodCount > 0) {
172                DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount);
173
174                final int methodsStartOffset = reader.getOffset();
175
176                return new VariableSizeListWithContext<DexBackedMethod>() {
177                    @Nonnull
178                    @Override
179                    public Iterator listIterator() {
180                        return new Iterator(dexFile, methodsStartOffset) {
181                            private int previousMethodIndex = 0;
182                            @Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
183                                    annotationsDirectory.getMethodAnnotationIterator();
184                            @Nonnull private final AnnotationsDirectory.AnnotationIterator parameterAnnotationIterator =
185                                    annotationsDirectory.getParameterAnnotationIterator();
186                            @Nonnull private final StaticInitialValueIterator staticInitialValueIterator =
187                                    StaticInitialValueIterator.newOrEmpty(dexFile, staticInitialValuesOffset);
188
189                            @Nonnull
190                            @Override
191                            protected DexBackedMethod readItem(DexFileReader reader, int index) {
192                                DexBackedMethod item = new DexBackedMethod(reader, previousMethodIndex,
193                                        methodAnnotationIterator, parameterAnnotationIterator);
194                                previousMethodIndex = item.methodIndex;
195                                return item;
196                            }
197
198                            @Override
199                            protected void skipItem(DexFileReader reader, int index) {
200                                previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex);
201                                staticInitialValueIterator.skipNext();
202                            }
203                        };
204                    }
205
206                    @Override public int size() { return methodCount; }
207                };
208            }
209        }
210        return ImmutableList.of();
211    }
212}
213