changeset 14:e5a9ae57cbf8

Adapted class data parser to recent changes. * dex/ClassData.java: Resolves method ids, parses code and static field values. (accept, acceptField, acceptMethod): Implemented visitor pattern. * dex/ClassDef.java: Pass static values offset to class data parser.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Tue, 15 Mar 2011 00:43:32 +0100
parents cb4a1dc20293
children e825bcb0ee95
files src/main/java/org/icedrobot/daneel/dex/ClassData.java src/main/java/org/icedrobot/daneel/dex/ClassDef.java
diffstat 2 files changed, 104 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/ClassData.java	Tue Mar 15 00:11:00 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/ClassData.java	Tue Mar 15 00:43:32 2011 +0100
@@ -29,10 +29,13 @@
      * current position.
      * @param buffer The byte buffer to read from.
      * @param dex The DEX file currently being parsed.
+     * @param staticValuesOff Offset to the list of initial values for static
+     * fields as stored in {@code class_def_item}, or 0 in case there are none.
      * @return An object representing the parsed data.
      */
-    static ClassData parse(ByteBuffer buffer, DexFile dex) {
-        return new ClassData(buffer, dex);
+    public static ClassData parse(ByteBuffer buffer, DexFile dex,
+            int staticValuesOff) {
+        return new ClassData(buffer, dex, staticValuesOff);
     }
 
     private int staticFieldsSize;
@@ -49,15 +52,17 @@
     private FieldId[] instanceFieldsIds;
     private int[] instanceFieldsFlags;
 
-    private int[] directMethodsIdxDiff;
+    private final MethodId[] directMethodsIds;
     private int[] directMethodsFlags;
-    private int[] directMethodsCodeOff;
+    private final Code[] directMethodsCode;
 
-    private int[] virtualMethodsIdxDiff;
+    private final MethodId[] virtualMethodsIds;
     private int[] virtualMethodsFlags;
-    private int[] virtualMethodsCodeOff;
+    private final Code[] virtualMethodsCode;
 
-    private ClassData(ByteBuffer buffer, DexFile dex) {
+    private final Object[] staticValues;
+
+    private ClassData(ByteBuffer buffer, DexFile dex, int staticValuesOff) {
         staticFieldsSize = BufferUtil.getULEB128(buffer);
         instanceFieldsSize = BufferUtil.getULEB128(buffer);
         directMethodsSize = BufferUtil.getULEB128(buffer);
@@ -86,24 +91,42 @@
         }
 
         // Parse encoded_method structures in direct_methods array.
-        directMethodsIdxDiff = new int[directMethodsSize];
+        directMethodsIds = new MethodId[directMethodsSize];
         directMethodsFlags = new int[directMethodsSize];
-        directMethodsCodeOff = new int[directMethodsSize];
+        directMethodsCode = new Code[directMethodsSize];
+        int directMethodsIdx = 0;
         for (int i = 0; i < directMethodsSize; i++) {
-            directMethodsIdxDiff[i] = BufferUtil.getULEB128(buffer);
+            directMethodsIdx += BufferUtil.getULEB128(buffer);
+            directMethodsIds[i] = dex.getMethodId(directMethodsIdx);
             directMethodsFlags[i] = BufferUtil.getULEB128(buffer);
-            directMethodsCodeOff[i] = BufferUtil.getULEB128(buffer);
+            int codeOff = BufferUtil.getULEB128(buffer);
+            if (codeOff != 0)
+                directMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), dex);
         }
 
         // Parse encoded_method structures in virtual_methods array.
-        virtualMethodsIdxDiff = new int[virtualMethodsSize];
+        virtualMethodsIds = new MethodId[virtualMethodsSize];
         virtualMethodsFlags = new int[virtualMethodsSize];
-        virtualMethodsCodeOff = new int[virtualMethodsSize];
+        virtualMethodsCode = new Code[virtualMethodsSize];
+        int virtualMethodsIdx = 0;
         for (int i = 0; i < virtualMethodsSize; i++) {
-            virtualMethodsIdxDiff[i] = BufferUtil.getULEB128(buffer);
+            virtualMethodsIdx += BufferUtil.getULEB128(buffer);
+            virtualMethodsIds[i] = dex.getMethodId(virtualMethodsIdx);
             virtualMethodsFlags[i] = BufferUtil.getULEB128(buffer);
-            virtualMethodsCodeOff[i] = BufferUtil.getULEB128(buffer);
+            int codeOff = BufferUtil.getULEB128(buffer);
+            if (codeOff != 0)
+                virtualMethodsCode[i] = Code.parse(dex.getDataBuffer(codeOff), dex);
         }
+
+        // Parse encoded_array_item and contained encoded_value structures.
+        if (staticValuesOff != 0) {
+            ByteBuffer buf = dex.getDataBuffer(staticValuesOff);
+            int staticValuesSize = BufferUtil.getULEB128(buf);
+            staticValues = new Object[staticValuesSize];
+            for (int i = 0; i < staticValuesSize; i++)
+                staticValues[i] = EncodedValue.parse(buf, dex);
+        } else
+            staticValues = new Object[0];
     }
 
     public int getStaticFieldsSize() {
@@ -145,4 +168,69 @@
     public int getVirtualMethodsFlag(int idx) {
         return virtualMethodsFlags[idx];
     }
+
+    /**
+     * Allows the given visitor to visit this class data object.
+     * @param visitor The given DEX class visitor object.
+     */
+    public void accept(DexClassVisitor visitor) {
+
+        // Visit all static fields.
+        for (int i = 0; i < staticFieldsSize; i++) {
+            int access = staticFieldsFlags[i];
+            FieldId field = staticFieldsIds[i];
+            Object value = (i < staticValues.length) ? staticValues[i] : null;
+            acceptField(visitor, access, field, value);
+        }
+
+        // Visit all instance fields.
+        for (int i = 0; i < instanceFieldsSize; i++) {
+            int access = instanceFieldsFlags[i];
+            FieldId field = instanceFieldsIds[i];
+            acceptField(visitor, access, field, null);
+        }
+
+        // Visit all direct methods.
+        for (int i = 0; i < directMethodsSize; i++) {
+            int access = directMethodsFlags[i];
+            MethodId method = directMethodsIds[i];
+            Code code = directMethodsCode[i];
+            acceptMethod(visitor, access, method, code);
+        }
+
+        // Visit all virtual methods.
+        for (int i = 0; i < virtualMethodsSize; i++) {
+            int access = virtualMethodsFlags[i];
+            MethodId method = virtualMethodsIds[i];
+            Code code = virtualMethodsCode[i];
+            acceptMethod(visitor, access, method, code);
+        }
+    }
+
+    /**
+     * Helper method to visit a field.
+     */
+    private static void acceptField(DexClassVisitor visitor, int access,
+            FieldId field, Object value) {
+        DexFieldVisitor dfv = visitor.visitField(access, field.getName(),
+                field.getTypeDescriptor(), value);
+        if (dfv != null)
+            dfv.visitEnd();
+    }
+
+    /**
+     * Helper method to visit a method.
+     */
+    private static void acceptMethod(DexClassVisitor visitor, int access,
+            MethodId method, Code code) {
+        ProtoId proto = method.getProtoId();
+        DexMethodVisitor dmv = visitor.visitMethod(access,
+                method.getName(), proto.getShorty(), proto.getReturnType(),
+                proto.getParameters());
+        if (dmv == null)
+            return;
+        if (code != null)
+            code.accept(dmv);
+        dmv.visitEnd();
+    }
 }
--- a/src/main/java/org/icedrobot/daneel/dex/ClassDef.java	Tue Mar 15 00:11:00 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/ClassDef.java	Tue Mar 15 00:43:32 2011 +0100
@@ -73,7 +73,7 @@
 
         // Parse the associated class_data_item structure.
         buf.position(classDataOff);
-        classData = ClassData.parse(buf, dex);
+        classData = ClassData.parse(buf, dex, staticValuesOff);
     }
 
     public String getClassName() {