Home | History | Annotate | Download | only in reader
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dex.reader;
     18 
     19 import java.lang.reflect.Modifier;
     20 import java.util.ArrayList;
     21 import java.util.HashMap;
     22 import java.util.HashSet;
     23 import java.util.LinkedList;
     24 import java.util.List;
     25 import java.util.Map;
     26 import java.util.Set;
     27 
     28 import dex.reader.DexFileReader.ClassDefItem;
     29 import dex.reader.DexFileReader.FieldIdItem;
     30 import dex.reader.DexFileReader.MethodsIdItem;
     31 import dex.reader.DexFileReader.ProtIdItem;
     32 import dex.structure.DexAnnotation;
     33 import dex.structure.DexClass;
     34 import dex.structure.DexField;
     35 import dex.structure.DexMethod;
     36 
     37 /* package */final class DexClassImpl implements DexClass {
     38     // constant
     39     private final int NO_INDEX = -1;
     40     // dex bytes
     41     private final DexBuffer buffer;
     42     // allready parsed
     43     private final ClassDefItem classDefItem;
     44     private final int[] typeIds;
     45     private final String[] stringPool;
     46     private ProtIdItem[] protoIdItems;
     47     private FieldIdItem[] fieldIdItems;
     48     private MethodsIdItem[] methodIdItems;
     49 
     50     //
     51     private List<DexField> fields;
     52     private List<DexMethod> methods;
     53     private List<String> interfaces;
     54     private ClassDataItem classDataItem;
     55     private AnnotationsDirectoryItem annotationDir;
     56     private Map<Integer, FieldAnnotation> idToFieldAnnotation =
     57             new HashMap<Integer, FieldAnnotation>();
     58     private Map<Integer, MethodAnnotation> idToMethodAnnotation =
     59             new HashMap<Integer, MethodAnnotation>();
     60     private Map<Integer, ParameterAnnotation> idToParameterAnnotation =
     61             new HashMap<Integer, ParameterAnnotation>();
     62 
     63     private Set<DexAnnotation> annotations;
     64     private TypeFormatter formatter = new TypeFormatter();
     65 
     66     private boolean hasClassData;
     67 
     68 
     69     public DexClassImpl(DexBuffer buffer, ClassDefItem classDefItem,
     70             String[] stringPool, int[] typeIds, ProtIdItem[] protoIdItems,
     71             FieldIdItem[] fieldIdItems, MethodsIdItem[] methodIdItems) {
     72         this.buffer = buffer;
     73         this.classDefItem = classDefItem;
     74         this.stringPool = stringPool;
     75         this.typeIds = typeIds;
     76         this.protoIdItems = protoIdItems;
     77         this.fieldIdItems = fieldIdItems;
     78         this.methodIdItems = methodIdItems;
     79         hasClassData = classDefItem.class_data_off != 0;
     80         parseClassData();
     81         parseAnnotationDirectory();
     82         parseClassAnnotations();
     83     }
     84 
     85     static class AnnotationsDirectoryItem {
     86         int class_annotations_off; // uint
     87         int fields_size; // uint
     88         int methods_size; // uint
     89         int annotated_params_size; // uint
     90         FieldAnnotation[] fieldAnnotations;
     91         MethodAnnotation[] methodAnnotations;
     92         ParameterAnnotation[] parameterAnnotations;
     93     }
     94 
     95     static class AnnotationSetItem {
     96         int size;// uint
     97         int[] annotationOffItem;
     98     }
     99 
    100     static class FieldAnnotation {
    101         int fieldIdx;// uint
    102         int annotationsOff;// uint
    103         AnnotationSetItem[] annotationSetItems;
    104     }
    105 
    106     static class MethodAnnotation {
    107         int methodIdx;// uint
    108         int annotationsOff;// uint
    109         AnnotationSetItem[] annotationSetItems;
    110     }
    111 
    112     static class ParameterAnnotation {
    113         int methodIdx;// uint
    114         int annotationsOff;// uint
    115         // AnnotationSetRefListItem[] annotationSetRefListItems;
    116     }
    117 
    118     private void parseAnnotationDirectory() {
    119         if (classDefItem.annotations_off != 0) {
    120             buffer.setPosition(classDefItem.annotations_off);
    121             annotationDir = new AnnotationsDirectoryItem();
    122             annotationDir.class_annotations_off = buffer.readUInt();
    123             annotationDir.fields_size = buffer.readUInt();
    124             annotationDir.methods_size = buffer.readUInt();
    125             annotationDir.annotated_params_size = buffer.readUInt();
    126 
    127             if (annotationDir.fields_size != 0) {
    128                 annotationDir.fieldAnnotations =
    129                         new FieldAnnotation[annotationDir.fields_size];
    130                 for (int i = 0; i < annotationDir.fields_size; i++) {
    131                     annotationDir.fieldAnnotations[i] = new FieldAnnotation();
    132                     annotationDir.fieldAnnotations[i].fieldIdx = buffer
    133                             .readUInt();
    134                     annotationDir.fieldAnnotations[i].annotationsOff = buffer
    135                             .readUInt();
    136                     idToFieldAnnotation.put(
    137                             annotationDir.fieldAnnotations[i].fieldIdx,
    138                             annotationDir.fieldAnnotations[i]);
    139                 }
    140             }
    141             if (annotationDir.methods_size != 0) {
    142                 annotationDir.methodAnnotations =
    143                         new MethodAnnotation[annotationDir.methods_size];
    144                 for (int i = 0; i < annotationDir.methods_size; i++) {
    145                     annotationDir.methodAnnotations[i] = new MethodAnnotation();
    146                     annotationDir.methodAnnotations[i].methodIdx = buffer
    147                             .readUInt();
    148                     annotationDir.methodAnnotations[i].annotationsOff = buffer
    149                             .readUInt();
    150                     idToMethodAnnotation.put(
    151                             annotationDir.methodAnnotations[i].methodIdx,
    152                             annotationDir.methodAnnotations[i]);
    153                 }
    154             }
    155             if (annotationDir.annotated_params_size != 0) {
    156                 annotationDir.parameterAnnotations =
    157                         new ParameterAnnotation[annotationDir
    158                                 .annotated_params_size];
    159                 for (int i = 0; i < annotationDir.annotated_params_size; i++) {
    160                     annotationDir.parameterAnnotations[i] =
    161                             new ParameterAnnotation();
    162                     annotationDir.parameterAnnotations[i].methodIdx = buffer
    163                             .readUInt();
    164                     annotationDir.parameterAnnotations[i].annotationsOff =
    165                             buffer.readUInt();
    166                     idToParameterAnnotation.put(
    167                             annotationDir.parameterAnnotations[i].methodIdx,
    168                             annotationDir.parameterAnnotations[i]);
    169                 }
    170             }
    171         }
    172     }
    173 
    174     static class ClassDataItem {
    175         int static_fields_size;// uleb128
    176         int instance_fields_size;// uleb128
    177         int direct_methods_size;// uleb128
    178         int virtual_methods_size;// uleb128
    179         EncodedField[] staticFields;
    180         EncodedField[] instanceFields;
    181         EncodedMethod[] directMethods;
    182         EncodedMethod[] virtualMethods;
    183     }
    184 
    185     static class EncodedField {
    186         int field_idx_diff; // uleb128
    187         int access_flags; // uleb128
    188     }
    189 
    190     static class EncodedMethod {
    191         int method_idx_diff;// uleb128
    192         int access_flags;// uleb128
    193         int code_off; // uleb128
    194     }
    195 
    196     private void parseClassData() {
    197         if (hasClassData) {
    198             buffer.setPosition(classDefItem.class_data_off);
    199             classDataItem = new ClassDataItem();
    200             classDataItem.static_fields_size = buffer.readUleb128();
    201             classDataItem.instance_fields_size = buffer.readUleb128();
    202             classDataItem.direct_methods_size = buffer.readUleb128();
    203             classDataItem.virtual_methods_size = buffer.readUleb128();
    204             classDataItem.staticFields = parseFields(
    205                     classDataItem.static_fields_size);
    206             classDataItem.instanceFields = parseFields(
    207                     classDataItem.instance_fields_size);
    208             classDataItem.directMethods = parseMethods(
    209                     classDataItem.direct_methods_size);
    210             classDataItem.virtualMethods = parseMethods(
    211                     classDataItem.virtual_methods_size);
    212         }
    213     }
    214 
    215     private EncodedField[] parseFields(int size) {
    216         EncodedField[] fields = new EncodedField[size];
    217         for (int i = 0; i < fields.length; i++) {
    218             fields[i] = new EncodedField();
    219             fields[i].field_idx_diff = buffer.readUleb128();
    220             fields[i].access_flags = buffer.readUleb128();
    221         }
    222         return fields;
    223     }
    224 
    225     private EncodedMethod[] parseMethods(int size) {
    226         EncodedMethod[] methods = new EncodedMethod[size];
    227         for (int i = 0; i < methods.length; i++) {
    228             methods[i] = new EncodedMethod();
    229             methods[i].method_idx_diff = buffer.readUleb128();
    230             methods[i].access_flags = buffer.readUleb128();
    231             methods[i].code_off = buffer.readUleb128();
    232         }
    233         return methods;
    234     }
    235 
    236     private void parseClassAnnotations() {
    237         annotations = new HashSet<DexAnnotation>();
    238         if (annotationDir != null && annotationDir.class_annotations_off != 0) {
    239             buffer.setPosition(annotationDir.class_annotations_off);
    240             final int size = buffer.readUInt();
    241             for (int i = 0; i < size; i++) {
    242                 annotations.add(new DexAnnotationImpl(buffer.createCopy(),
    243                         buffer.readUInt(), typeIds, stringPool, fieldIdItems));
    244             }
    245         }
    246     }
    247 
    248     public synchronized List<DexField> getFields() {
    249         if (fields == null) {
    250             fields = new ArrayList<DexField>();
    251             if (hasClassData) {
    252                 fields.addAll(getDexFields(classDataItem.staticFields));
    253                 fields.addAll(getDexFields(classDataItem.instanceFields));
    254             }
    255         }
    256         return fields;
    257     }
    258 
    259     private List<DexField> getDexFields(EncodedField[] fields) {
    260         List<DexField> dexFields = new ArrayList<DexField>(fields.length);
    261         if (fields.length != 0) {
    262             int fieldIdIdx = 0;
    263             for (int i = 0; i < fields.length; i++) {
    264                 int accessFlags = fields[i].access_flags;
    265                 fieldIdIdx = (i == 0) ? fields[i].field_idx_diff : fieldIdIdx
    266                         + fields[i].field_idx_diff;
    267                 dexFields.add(new DexFieldImpl(buffer.createCopy(), this,
    268                         fieldIdItems[fieldIdIdx], accessFlags,
    269                         idToFieldAnnotation.get(fieldIdIdx), stringPool,
    270                         typeIds, fieldIdItems));
    271             }
    272         }
    273         return dexFields;
    274     }
    275 
    276     public synchronized List<DexMethod> getMethods() {
    277         if (methods == null) {
    278             methods = new ArrayList<DexMethod>();
    279             if (hasClassData) {
    280                 methods.addAll(getDexMethods(classDataItem.directMethods));
    281                 methods.addAll(getDexMethods(classDataItem.virtualMethods));
    282             }
    283         }
    284         return methods;
    285     }
    286 
    287     private List<DexMethod> getDexMethods(EncodedMethod[] methods) {
    288         List<DexMethod> dexMethods = new ArrayList<DexMethod>(methods.length);
    289         if (methods.length != 0) {
    290             int methodIdIdx = 0;
    291             EncodedMethod method = null;
    292             for (int i = 0; i < methods.length; i++) {
    293                 method = methods[i];
    294                 methodIdIdx = (i == 0) ? method.method_idx_diff : methodIdIdx
    295                         + method.method_idx_diff;
    296                 dexMethods.add(new DexMethodImpl(buffer, this,
    297                         methodIdItems[methodIdIdx],
    298                         protoIdItems[methodIdItems[methodIdIdx].proto_idx],
    299                         method.access_flags, idToMethodAnnotation
    300                                 .get(methodIdIdx), idToParameterAnnotation
    301                                 .get(methodIdIdx), stringPool, typeIds,
    302                         fieldIdItems));
    303             }
    304         }
    305         return dexMethods;
    306     }
    307 
    308 
    309 
    310     public synchronized List<String> getInterfaces() {
    311         if (interfaces == null) {
    312             interfaces = new LinkedList<String>();
    313             if (classDefItem.interfaces_off != 0) {
    314                 buffer.setPosition(classDefItem.interfaces_off);
    315                 int size = buffer.readUInt();
    316                 for (int i = 0; i < size; i++) {
    317                     interfaces.add(stringPool[typeIds[buffer.readUShort()]]);
    318                 }
    319             }
    320         }
    321         return interfaces;
    322     }
    323 
    324     // returns null if no super class is present
    325     public String getSuperClass() {
    326         return classDefItem.superclass_idx == NO_INDEX ? null
    327                 : stringPool[typeIds[classDefItem.superclass_idx]];
    328     }
    329 
    330     public Set<DexAnnotation> getAnnotations() {
    331         return annotations;
    332     }
    333 
    334     public String getName() {
    335         return stringPool[typeIds[classDefItem.class_idx]];
    336     }
    337 
    338     public int getModifiers() {
    339         return classDefItem.access_flags;
    340     }
    341 
    342     @Override
    343     public String toString() {
    344         StringBuilder builder = new StringBuilder();
    345         builder.append(formatter.formatAnnotations(getAnnotations()));
    346         builder.append(Modifier.toString(getModifiers()));
    347         builder.append(" class ");
    348         builder.append(formatter.format(getName()));
    349         if (getSuperClass() != null) {
    350             builder.append(" extends ");
    351             builder.append(formatter.format(getSuperClass()));
    352         }
    353         if (!getInterfaces().isEmpty()) {
    354             builder.append(" implements ");
    355             builder.append(formatter.format(getInterfaces()));
    356         }
    357         return builder.toString();
    358     }
    359 
    360 }
    361