DexBackedClassDef.java revision 1b598a1817aa0ae18a9020bed728b6842c287c91
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;
37
38import javax.annotation.Nonnull;
39import javax.annotation.Nullable;
40import java.util.List;
41
42public class DexBackedClassDef implements ClassDef {
43    @Nonnull public final DexBuffer dexBuf;
44
45    @Nonnull public final String name;
46    public final int accessFlags;
47    @Nullable public final String superclass;
48    @Nullable public final String sourceFile;
49
50    @Nonnull private final AnnotationsDirectory annotationsDirectory;
51    private final int staticInitialValuesOffset;
52
53    private final int interfacesOffset;
54    private final int classDataOffset;
55
56    //class_def_item offsets
57    private static final int ACCESS_FLAGS_OFFSET = 4;
58    private static final int SUPERCLASS_OFFSET = 8;
59    private static final int INTERFACES_OFFSET = 12;
60    private static final int SOURCE_FILE_OFFSET = 16;
61    private static final int ANNOTATIONS_OFFSET = 20;
62    private static final int CLASS_DATA_OFFSET = 24;
63    private static final int STATIC_INITIAL_VALUES_OFFSET = 28;
64
65    public DexBackedClassDef(@Nonnull DexBuffer dexBuf,
66                             int classDefOffset) {
67        this.dexBuf = dexBuf;
68
69        this.name = dexBuf.getType(dexBuf.readSmallUint(classDefOffset));
70        this.accessFlags = dexBuf.readSmallUint(classDefOffset + ACCESS_FLAGS_OFFSET);
71        this.superclass = dexBuf.getOptionalType(dexBuf.readOptionalUint(classDefOffset + SUPERCLASS_OFFSET));
72        this.interfacesOffset = dexBuf.readSmallUint(classDefOffset + INTERFACES_OFFSET);
73        this.sourceFile = dexBuf.getOptionalString(dexBuf.readOptionalUint(classDefOffset + SOURCE_FILE_OFFSET));
74
75        int annotationsDirectoryOffset = dexBuf.readSmallUint(classDefOffset + ANNOTATIONS_OFFSET);
76        this.annotationsDirectory = AnnotationsDirectory.newOrEmpty(dexBuf, annotationsDirectoryOffset);
77
78        this.classDataOffset = dexBuf.readSmallUint(classDefOffset + CLASS_DATA_OFFSET);
79        this.staticInitialValuesOffset = dexBuf.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET);
80    }
81
82
83    @Nonnull @Override public String getName() { return name; }
84    @Override public int getAccessFlags() { return accessFlags; }
85    @Nullable @Override public String getSuperclass() { return superclass; }
86    @Nullable @Override public String getSourceFile() { return sourceFile; }
87
88    @Nonnull
89    @Override
90    public List<String> getInterfaces() {
91        if (interfacesOffset > 0) {
92            final int size = dexBuf.readSmallUint(interfacesOffset);
93            return new FixedSizeList<String>() {
94                @Nonnull
95                @Override
96                public String readItem(int index) {
97                    return dexBuf.getType(dexBuf.readUshort(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            DexReader reader = dexBuf.readerAt(classDataOffset);
117            final 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(dexBuf, 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(dexBuf, staticInitialValuesOffset);
136
137                            @Nonnull
138                            @Override
139                            protected DexBackedField readItem(@Nonnull DexReader reader, int index) {
140                                if (index == staticFieldCount) {
141                                    // We reached the end of the static field, restart the numbering for
142                                    // instance fields
143                                    previousFieldIndex = 0;
144                                }
145                                DexBackedField item = new DexBackedField(reader, previousFieldIndex,
146                                        staticInitialValueIterator, annotationIterator);
147                                previousFieldIndex = item.fieldIndex;
148                                return item;
149                            }
150
151                            @Override
152                            protected void skipItem(@Nonnull DexReader reader, int index) {
153                                if (index == staticFieldCount) {
154                                    // We reached the end of the static field, restart the numbering for
155                                    // instance fields
156                                    previousFieldIndex = 0;
157                                }
158                                previousFieldIndex = DexBackedField.skipEncodedField(reader, previousFieldIndex);
159                                staticInitialValueIterator.skipNext();
160                            }
161                        };
162                    }
163
164                    @Override public int size() { return fieldCount; }
165                };
166            }
167        }
168        return ImmutableList.of();
169    }
170
171    @Nonnull
172    @Override
173    public List<? extends DexBackedMethod> getMethods() {
174        if (classDataOffset > 0) {
175            DexReader reader = dexBuf.readerAt(classDataOffset);
176            int staticFieldCount = reader.readSmallUleb128();
177            int instanceFieldCount = reader.readSmallUleb128();
178            final int directMethodCount = reader.readSmallUleb128();
179            int virtualMethodCount = reader.readSmallUleb128();
180            final int methodCount = directMethodCount + virtualMethodCount;
181            if (methodCount > 0) {
182                DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount);
183
184                final int methodsStartOffset = reader.getOffset();
185
186                return new VariableSizeListWithContext<DexBackedMethod>() {
187                    @Nonnull
188                    @Override
189                    public Iterator listIterator() {
190                        return new Iterator(dexBuf, methodsStartOffset) {
191                            private int previousMethodIndex = 0;
192                            @Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
193                                    annotationsDirectory.getMethodAnnotationIterator();
194                            @Nonnull private final AnnotationsDirectory.AnnotationIterator parameterAnnotationIterator =
195                                    annotationsDirectory.getParameterAnnotationIterator();
196
197                            @Nonnull
198                            @Override
199                            protected DexBackedMethod readItem(@Nonnull DexReader reader, int index) {
200                                if (index == directMethodCount) {
201                                    // We reached the end of the direct methods, restart the numbering for
202                                    // virtual methods
203                                    previousMethodIndex = 0;
204                                }
205                                DexBackedMethod item = new DexBackedMethod(reader, previousMethodIndex,
206                                        methodAnnotationIterator, parameterAnnotationIterator);
207                                previousMethodIndex = item.methodIndex;
208                                return item;
209                            }
210
211                            @Override
212                            protected void skipItem(@Nonnull DexReader reader, int index) {
213                                if (index == directMethodCount) {
214                                    // We reached the end of the direct methods, restart the numbering for
215                                    // virtual methods
216                                    previousMethodIndex = 0;
217                                }
218                                previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex);
219                            }
220                        };
221                    }
222
223                    @Override public int size() { return methodCount; }
224                };
225            }
226        }
227        return ImmutableList.of();
228    }
229}
230