DexBackedClassDef.java revision db389aa3a1d898d3a452f3f0b2220b334b23cb4c
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.AnnotationsDirectory; 36import org.jf.dexlib2.dexbacked.util.FixedSizeList; 37import org.jf.dexlib2.dexbacked.util.StaticInitialValueIterator; 38import org.jf.dexlib2.dexbacked.util.VariableSizeListWithContext; 39import org.jf.dexlib2.iface.ClassDef; 40 41import javax.annotation.Nonnull; 42import javax.annotation.Nullable; 43import java.util.List; 44 45public class DexBackedClassDef implements ClassDef { 46 @Nonnull public final DexBuffer dexBuf; 47 private final int classDefOffset; 48 49 private int classDataOffset = -1; 50 51 @Nullable private AnnotationsDirectory annotationsDirectory; 52 53 //class_def_item offsets 54 private static final int CLASS_NAME_OFFSET = 0; 55 private static final int ACCESS_FLAGS_OFFSET = 4; 56 private static final int SUPERCLASS_OFFSET = 8; 57 private static final int INTERFACES_OFFSET = 12; 58 private static final int SOURCE_FILE_OFFSET = 16; 59 private static final int ANNOTATIONS_OFFSET = 20; 60 private static final int CLASS_DATA_OFFSET = 24; 61 private static final int STATIC_INITIAL_VALUES_OFFSET = 28; 62 63 public DexBackedClassDef(@Nonnull DexBuffer dexBuf, 64 int classDefOffset) { 65 this.dexBuf = dexBuf; 66 this.classDefOffset = classDefOffset; 67 } 68 69 @Nonnull 70 @Override 71 public String getType() { 72 return dexBuf.getType(dexBuf.readSmallUint(classDefOffset + CLASS_NAME_OFFSET)); 73 } 74 75 @Nullable 76 @Override 77 public String getSuperclass() { 78 return dexBuf.getOptionalType(dexBuf.readOptionalUint(classDefOffset + SUPERCLASS_OFFSET)); 79 } 80 81 @Override 82 public int getAccessFlags() { 83 return dexBuf.readSmallUint(classDefOffset + ACCESS_FLAGS_OFFSET); 84 } 85 86 @Nullable 87 @Override 88 public String getSourceFile() { 89 return dexBuf.getOptionalString(dexBuf.readOptionalUint(classDefOffset + SOURCE_FILE_OFFSET)); 90 } 91 92 @Nonnull 93 @Override 94 public List<String> getInterfaces() { 95 final int interfacesOffset = dexBuf.readSmallUint(classDefOffset + INTERFACES_OFFSET); 96 if (interfacesOffset > 0) { 97 final int size = dexBuf.readSmallUint(interfacesOffset); 98 return new FixedSizeList<String>() { 99 @Nonnull 100 @Override 101 public String readItem(int index) { 102 return dexBuf.getType(dexBuf.readUshort(interfacesOffset + 4 + (2*index))); 103 } 104 105 @Override public int size() { return size; } 106 }; 107 } 108 return ImmutableList.of(); 109 } 110 111 @Nonnull 112 @Override 113 public List<? extends DexBackedAnnotation> getAnnotations() { 114 return getAnnotationsDirectory().getClassAnnotations(); 115 } 116 117 @Nonnull 118 @Override 119 public List<? extends DexBackedField> getFields() { 120 int classDataOffset = getClassDataOffset(); 121 if (getClassDataOffset() != 0) { 122 DexReader reader = dexBuf.readerAt(classDataOffset); 123 final int staticFieldCount = reader.readSmallUleb128(); 124 int instanceFieldCount = reader.readSmallUleb128(); 125 final int fieldCount = staticFieldCount + instanceFieldCount; 126 if (fieldCount > 0) { 127 reader.skipUleb128(); //direct_methods_size 128 reader.skipUleb128(); //virtual_methods_size 129 130 final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); 131 final int staticInitialValuesOffset = 132 dexBuf.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET); 133 final int fieldsStartOffset = reader.getOffset(); 134 135 return new VariableSizeListWithContext<DexBackedField>() { 136 @Nonnull 137 @Override 138 public VariableSizeListIterator listIterator() { 139 return new VariableSizeListIterator(dexBuf, fieldsStartOffset) { 140 private int previousFieldIndex = 0; 141 @Nonnull private final AnnotationsDirectory.AnnotationIterator annotationIterator = 142 annotationsDirectory.getFieldAnnotationIterator(); 143 @Nonnull private final StaticInitialValueIterator staticInitialValueIterator = 144 StaticInitialValueIterator.newOrEmpty(dexBuf, staticInitialValuesOffset); 145 146 @Nonnull 147 @Override 148 protected DexBackedField readItem(@Nonnull DexReader reader, int index) { 149 if (index == staticFieldCount) { 150 // We reached the end of the static field, restart the numbering for 151 // instance fields 152 previousFieldIndex = 0; 153 annotationIterator.reset(); 154 } 155 DexBackedField item = new DexBackedField(reader, DexBackedClassDef.this, 156 previousFieldIndex, staticInitialValueIterator, annotationIterator); 157 previousFieldIndex = item.fieldIndex; 158 return item; 159 } 160 161 @Override 162 protected void skipItem(@Nonnull DexReader reader, int index) { 163 if (index == staticFieldCount) { 164 // We reached the end of the static field, restart the numbering for 165 // instance fields 166 previousFieldIndex = 0; 167 annotationIterator.reset(); 168 } 169 previousFieldIndex = DexBackedField.skipEncodedField(reader, previousFieldIndex); 170 staticInitialValueIterator.skipNext(); 171 } 172 }; 173 } 174 175 @Override public int size() { return fieldCount; } 176 }; 177 } 178 } 179 return ImmutableList.of(); 180 } 181 182 @Nonnull 183 @Override 184 public List<? extends DexBackedMethod> getMethods() { 185 int classDataOffset = getClassDataOffset(); 186 if (classDataOffset > 0) { 187 DexReader reader = dexBuf.readerAt(classDataOffset); 188 int staticFieldCount = reader.readSmallUleb128(); 189 int instanceFieldCount = reader.readSmallUleb128(); 190 final int directMethodCount = reader.readSmallUleb128(); 191 int virtualMethodCount = reader.readSmallUleb128(); 192 final int methodCount = directMethodCount + virtualMethodCount; 193 if (methodCount > 0) { 194 DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount); 195 196 final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); 197 final int methodsStartOffset = reader.getOffset(); 198 199 return new VariableSizeListWithContext<DexBackedMethod>() { 200 @Nonnull 201 @Override 202 public VariableSizeListIterator listIterator() { 203 return new VariableSizeListIterator(dexBuf, methodsStartOffset) { 204 private int previousMethodIndex = 0; 205 @Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator = 206 annotationsDirectory.getMethodAnnotationIterator(); 207 @Nonnull private final AnnotationsDirectory.AnnotationIterator parameterAnnotationIterator = 208 annotationsDirectory.getParameterAnnotationIterator(); 209 210 @Nonnull 211 @Override 212 protected DexBackedMethod readItem(@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 methodAnnotationIterator.reset(); 218 parameterAnnotationIterator.reset(); 219 } 220 DexBackedMethod item = new DexBackedMethod(reader, DexBackedClassDef.this, 221 previousMethodIndex, methodAnnotationIterator, parameterAnnotationIterator); 222 previousMethodIndex = item.methodIndex; 223 return item; 224 } 225 226 @Override 227 protected void skipItem(@Nonnull DexReader reader, int index) { 228 if (index == directMethodCount) { 229 // We reached the end of the direct methods, restart the numbering for 230 // virtual methods 231 previousMethodIndex = 0; 232 methodAnnotationIterator.reset(); 233 parameterAnnotationIterator.reset(); 234 } 235 previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex); 236 } 237 }; 238 } 239 240 @Override public int size() { return methodCount; } 241 }; 242 } 243 } 244 return ImmutableList.of(); 245 } 246 247 private int getClassDataOffset() { 248 if (classDataOffset == -1) { 249 classDataOffset = dexBuf.readSmallUint(classDefOffset + CLASS_DATA_OFFSET); 250 } 251 return classDataOffset; 252 } 253 254 private AnnotationsDirectory getAnnotationsDirectory() { 255 if (annotationsDirectory == null) { 256 int annotationsDirectoryOffset = dexBuf.readSmallUint(classDefOffset + ANNOTATIONS_OFFSET); 257 annotationsDirectory = AnnotationsDirectory.newOrEmpty(dexBuf, annotationsDirectoryOffset); 258 } 259 return annotationsDirectory; 260 } 261} 262