OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / cts / tools / dex-tools / src / dex / reader / DexClassImpl.java
diff --git a/cts/tools/dex-tools/src/dex/reader/DexClassImpl.java b/cts/tools/dex-tools/src/dex/reader/DexClassImpl.java
new file mode 100644 (file)
index 0000000..f15e809
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dex.reader;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import dex.reader.DexFileReader.ClassDefItem;
+import dex.reader.DexFileReader.FieldIdItem;
+import dex.reader.DexFileReader.MethodsIdItem;
+import dex.reader.DexFileReader.ProtIdItem;
+import dex.structure.DexAnnotation;
+import dex.structure.DexClass;
+import dex.structure.DexField;
+import dex.structure.DexMethod;
+
+/* package */final class DexClassImpl implements DexClass {
+    // constant
+    private final int NO_INDEX = -1;
+    // dex bytes
+    private final DexBuffer buffer;
+    // allready parsed
+    private final ClassDefItem classDefItem;
+    private final int[] typeIds;
+    private final String[] stringPool;
+    private ProtIdItem[] protoIdItems;
+    private FieldIdItem[] fieldIdItems;
+    private MethodsIdItem[] methodIdItems;
+
+    //
+    private List<DexField> fields;
+    private List<DexMethod> methods;
+    private List<String> interfaces;
+    private ClassDataItem classDataItem;
+    private AnnotationsDirectoryItem annotationDir;
+    private Map<Integer, FieldAnnotation> idToFieldAnnotation =
+            new HashMap<Integer, FieldAnnotation>();
+    private Map<Integer, MethodAnnotation> idToMethodAnnotation =
+            new HashMap<Integer, MethodAnnotation>();
+    private Map<Integer, ParameterAnnotation> idToParameterAnnotation =
+            new HashMap<Integer, ParameterAnnotation>();
+
+    private Set<DexAnnotation> annotations;
+    private TypeFormatter formatter = new TypeFormatter();
+
+    private boolean hasClassData;
+
+
+    public DexClassImpl(DexBuffer buffer, ClassDefItem classDefItem,
+            String[] stringPool, int[] typeIds, ProtIdItem[] protoIdItems,
+            FieldIdItem[] fieldIdItems, MethodsIdItem[] methodIdItems) {
+        this.buffer = buffer;
+        this.classDefItem = classDefItem;
+        this.stringPool = stringPool;
+        this.typeIds = typeIds;
+        this.protoIdItems = protoIdItems;
+        this.fieldIdItems = fieldIdItems;
+        this.methodIdItems = methodIdItems;
+        hasClassData = classDefItem.class_data_off != 0;
+        parseClassData();
+        parseAnnotationDirectory();
+        parseClassAnnotations();
+    }
+
+    static class AnnotationsDirectoryItem {
+        int class_annotations_off; // uint
+        int fields_size; // uint
+        int methods_size; // uint
+        int annotated_params_size; // uint
+        FieldAnnotation[] fieldAnnotations;
+        MethodAnnotation[] methodAnnotations;
+        ParameterAnnotation[] parameterAnnotations;
+    }
+
+    static class AnnotationSetItem {
+        int size;// uint
+        int[] annotationOffItem;
+    }
+
+    static class FieldAnnotation {
+        int fieldIdx;// uint
+        int annotationsOff;// uint
+        AnnotationSetItem[] annotationSetItems;
+    }
+
+    static class MethodAnnotation {
+        int methodIdx;// uint
+        int annotationsOff;// uint
+        AnnotationSetItem[] annotationSetItems;
+    }
+
+    static class ParameterAnnotation {
+        int methodIdx;// uint
+        int annotationsOff;// uint
+        // AnnotationSetRefListItem[] annotationSetRefListItems;
+    }
+
+    private void parseAnnotationDirectory() {
+        if (classDefItem.annotations_off != 0) {
+            buffer.setPosition(classDefItem.annotations_off);
+            annotationDir = new AnnotationsDirectoryItem();
+            annotationDir.class_annotations_off = buffer.readUInt();
+            annotationDir.fields_size = buffer.readUInt();
+            annotationDir.methods_size = buffer.readUInt();
+            annotationDir.annotated_params_size = buffer.readUInt();
+
+            if (annotationDir.fields_size != 0) {
+                annotationDir.fieldAnnotations =
+                        new FieldAnnotation[annotationDir.fields_size];
+                for (int i = 0; i < annotationDir.fields_size; i++) {
+                    annotationDir.fieldAnnotations[i] = new FieldAnnotation();
+                    annotationDir.fieldAnnotations[i].fieldIdx = buffer
+                            .readUInt();
+                    annotationDir.fieldAnnotations[i].annotationsOff = buffer
+                            .readUInt();
+                    idToFieldAnnotation.put(
+                            annotationDir.fieldAnnotations[i].fieldIdx,
+                            annotationDir.fieldAnnotations[i]);
+                }
+            }
+            if (annotationDir.methods_size != 0) {
+                annotationDir.methodAnnotations =
+                        new MethodAnnotation[annotationDir.methods_size];
+                for (int i = 0; i < annotationDir.methods_size; i++) {
+                    annotationDir.methodAnnotations[i] = new MethodAnnotation();
+                    annotationDir.methodAnnotations[i].methodIdx = buffer
+                            .readUInt();
+                    annotationDir.methodAnnotations[i].annotationsOff = buffer
+                            .readUInt();
+                    idToMethodAnnotation.put(
+                            annotationDir.methodAnnotations[i].methodIdx,
+                            annotationDir.methodAnnotations[i]);
+                }
+            }
+            if (annotationDir.annotated_params_size != 0) {
+                annotationDir.parameterAnnotations =
+                        new ParameterAnnotation[annotationDir
+                                .annotated_params_size];
+                for (int i = 0; i < annotationDir.annotated_params_size; i++) {
+                    annotationDir.parameterAnnotations[i] =
+                            new ParameterAnnotation();
+                    annotationDir.parameterAnnotations[i].methodIdx = buffer
+                            .readUInt();
+                    annotationDir.parameterAnnotations[i].annotationsOff =
+                            buffer.readUInt();
+                    idToParameterAnnotation.put(
+                            annotationDir.parameterAnnotations[i].methodIdx,
+                            annotationDir.parameterAnnotations[i]);
+                }
+            }
+        }
+    }
+
+    static class ClassDataItem {
+        int static_fields_size;// uleb128
+        int instance_fields_size;// uleb128
+        int direct_methods_size;// uleb128
+        int virtual_methods_size;// uleb128
+        EncodedField[] staticFields;
+        EncodedField[] instanceFields;
+        EncodedMethod[] directMethods;
+        EncodedMethod[] virtualMethods;
+    }
+
+    static class EncodedField {
+        int field_idx_diff; // uleb128
+        int access_flags; // uleb128
+    }
+
+    static class EncodedMethod {
+        int method_idx_diff;// uleb128
+        int access_flags;// uleb128
+        int code_off; // uleb128
+    }
+
+    private void parseClassData() {
+        if (hasClassData) {
+            buffer.setPosition(classDefItem.class_data_off);
+            classDataItem = new ClassDataItem();
+            classDataItem.static_fields_size = buffer.readUleb128();
+            classDataItem.instance_fields_size = buffer.readUleb128();
+            classDataItem.direct_methods_size = buffer.readUleb128();
+            classDataItem.virtual_methods_size = buffer.readUleb128();
+            classDataItem.staticFields = parseFields(
+                    classDataItem.static_fields_size);
+            classDataItem.instanceFields = parseFields(
+                    classDataItem.instance_fields_size);
+            classDataItem.directMethods = parseMethods(
+                    classDataItem.direct_methods_size);
+            classDataItem.virtualMethods = parseMethods(
+                    classDataItem.virtual_methods_size);
+        }
+    }
+
+    private EncodedField[] parseFields(int size) {
+        EncodedField[] fields = new EncodedField[size];
+        for (int i = 0; i < fields.length; i++) {
+            fields[i] = new EncodedField();
+            fields[i].field_idx_diff = buffer.readUleb128();
+            fields[i].access_flags = buffer.readUleb128();
+        }
+        return fields;
+    }
+
+    private EncodedMethod[] parseMethods(int size) {
+        EncodedMethod[] methods = new EncodedMethod[size];
+        for (int i = 0; i < methods.length; i++) {
+            methods[i] = new EncodedMethod();
+            methods[i].method_idx_diff = buffer.readUleb128();
+            methods[i].access_flags = buffer.readUleb128();
+            methods[i].code_off = buffer.readUleb128();
+        }
+        return methods;
+    }
+
+    private void parseClassAnnotations() {
+        annotations = new HashSet<DexAnnotation>();
+        if (annotationDir != null && annotationDir.class_annotations_off != 0) {
+            buffer.setPosition(annotationDir.class_annotations_off);
+            final int size = buffer.readUInt();
+            for (int i = 0; i < size; i++) {
+                annotations.add(new DexAnnotationImpl(buffer.createCopy(),
+                        buffer.readUInt(), typeIds, stringPool, fieldIdItems));
+            }
+        }
+    }
+
+    public synchronized List<DexField> getFields() {
+        if (fields == null) {
+            fields = new ArrayList<DexField>();
+            if (hasClassData) {
+                fields.addAll(getDexFields(classDataItem.staticFields));
+                fields.addAll(getDexFields(classDataItem.instanceFields));
+            }
+        }
+        return fields;
+    }
+
+    private List<DexField> getDexFields(EncodedField[] fields) {
+        List<DexField> dexFields = new ArrayList<DexField>(fields.length);
+        if (fields.length != 0) {
+            int fieldIdIdx = 0;
+            for (int i = 0; i < fields.length; i++) {
+                int accessFlags = fields[i].access_flags;
+                fieldIdIdx = (i == 0) ? fields[i].field_idx_diff : fieldIdIdx
+                        + fields[i].field_idx_diff;
+                dexFields.add(new DexFieldImpl(buffer.createCopy(), this,
+                        fieldIdItems[fieldIdIdx], accessFlags,
+                        idToFieldAnnotation.get(fieldIdIdx), stringPool,
+                        typeIds, fieldIdItems));
+            }
+        }
+        return dexFields;
+    }
+
+    public synchronized List<DexMethod> getMethods() {
+        if (methods == null) {
+            methods = new ArrayList<DexMethod>();
+            if (hasClassData) {
+                methods.addAll(getDexMethods(classDataItem.directMethods));
+                methods.addAll(getDexMethods(classDataItem.virtualMethods));
+            }
+        }
+        return methods;
+    }
+
+    private List<DexMethod> getDexMethods(EncodedMethod[] methods) {
+        List<DexMethod> dexMethods = new ArrayList<DexMethod>(methods.length);
+        if (methods.length != 0) {
+            int methodIdIdx = 0;
+            EncodedMethod method = null;
+            for (int i = 0; i < methods.length; i++) {
+                method = methods[i];
+                methodIdIdx = (i == 0) ? method.method_idx_diff : methodIdIdx
+                        + method.method_idx_diff;
+                dexMethods.add(new DexMethodImpl(buffer, this,
+                        methodIdItems[methodIdIdx],
+                        protoIdItems[methodIdItems[methodIdIdx].proto_idx],
+                        method.access_flags, idToMethodAnnotation
+                                .get(methodIdIdx), idToParameterAnnotation
+                                .get(methodIdIdx), stringPool, typeIds,
+                        fieldIdItems));
+            }
+        }
+        return dexMethods;
+    }
+
+
+
+    public synchronized List<String> getInterfaces() {
+        if (interfaces == null) {
+            interfaces = new LinkedList<String>();
+            if (classDefItem.interfaces_off != 0) {
+                buffer.setPosition(classDefItem.interfaces_off);
+                int size = buffer.readUInt();
+                for (int i = 0; i < size; i++) {
+                    interfaces.add(stringPool[typeIds[buffer.readUShort()]]);
+                }
+            }
+        }
+        return interfaces;
+    }
+
+    // returns null if no super class is present
+    public String getSuperClass() {
+        return classDefItem.superclass_idx == NO_INDEX ? null
+                : stringPool[typeIds[classDefItem.superclass_idx]];
+    }
+
+    public Set<DexAnnotation> getAnnotations() {
+        return annotations;
+    }
+
+    public String getName() {
+        return stringPool[typeIds[classDefItem.class_idx]];
+    }
+
+    public int getModifiers() {
+        return classDefItem.access_flags;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(formatter.formatAnnotations(getAnnotations()));
+        builder.append(Modifier.toString(getModifiers()));
+        builder.append(" class ");
+        builder.append(formatter.format(getName()));
+        if (getSuperClass() != null) {
+            builder.append(" extends ");
+            builder.append(formatter.format(getSuperClass()));
+        }
+        if (!getInterfaces().isEmpty()) {
+            builder.append(" implements ");
+            builder.append(formatter.format(getInterfaces()));
+        }
+        return builder.toString();
+    }
+
+}