changeset 19:d6245f2a61a6

Implemented parser interface to accept visitors. * dex/DexFile.java (classDefs): Switched to map for efficient lookup by name. * (accept): Implemented according to parser interface. * (getClassDef): Deprecated, should be removed soon.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Wed, 16 Mar 2011 00:39:45 +0100
parents 3a79fec307ae
children 03d932822bf7
files src/main/java/org/icedrobot/daneel/dex/DexFile.java
diffstat 1 files changed, 43 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/DexFile.java	Wed Mar 16 00:38:21 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/DexFile.java	Wed Mar 16 00:39:45 2011 +0100
@@ -2,10 +2,17 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 import org.icedrobot.daneel.util.BufferUtil;
 
-public class DexFile {
+/**
+ * This class reads the contents of a DEX file. It is the main entry point into
+ * our parser implementation and optimized towards {@link java.nio.ByteBuffer}
+ * data sources.
+ */
+public class DexFile implements DexReader {
 
     /** Constant used to indicate that an index value is absent. */
     public static final int NO_INDEX = 0xffffffff;
@@ -30,7 +37,7 @@
 
     private final MethodId[] methodIds;
 
-    private ClassDef[] classDefs;
+    private final Map<String, ClassDef> classDefs;
 
     private final ByteBuffer dataBuffer;
 
@@ -80,10 +87,15 @@
             methodIds[i] = MethodId.parse(buf, this);
 
         // Parse class_def_item structures.
-        classDefs = new ClassDef[header.getClassDefsSize()];
+        int classDefsSize = header.getClassDefsSize();
+        classDefs = new LinkedHashMap<String, ClassDef>(classDefsSize);
         buf.position(header.getClassDefsOff());
-        for (int i = 0; i < classDefs.length; i++)
-            classDefs[i] = ClassDef.parse(buf, this);
+        for (int i = 0; i < classDefsSize; i++) {
+            ClassDef classDef = ClassDef.parse(buf, this);
+            if (classDefs.put(classDef.getClassName(), classDef) != null)
+                throw new DexParseException("Redefinition of class: "
+                        + classDef.getClassName());
+        }
     }
 
     Header getHeader() {
@@ -124,8 +136,13 @@
         return methodIds[idx];
     }
 
+    @Deprecated
+    // XXX Direct access of class definition is not allowed, remove me!
     public ClassDef getClassDef(int idx) {
-        return classDefs[idx];
+        // XXX I know this is hacky, but it is only used by the prototype test.
+        if (idx != 0)
+            throw new DexParseException("You shouldn't have used me!");
+        return classDefs.values().iterator().next();
     }
 
     /**
@@ -156,12 +173,31 @@
      * 
      * @param visitor The given DEX file visitor object.
      */
+    @Override
     public void accept(DexFileVisitor visitor) {
-        for (ClassDef classDef : classDefs) {
+        for (ClassDef classDef : classDefs.values()) {
             DexClassVisitor dcv = visitor.visitClass(classDef.getClassName());
             if (dcv != null)
                 classDef.accept(dcv);
         }
         visitor.visitEnd();
     }
+
+    /**
+     * Allows the given visitor to visit a class inside this DEX file.
+     * 
+     * @param className The name of the class to visit as a type descriptor.
+     * @param visitor The given DEX class visitor object.
+     * @throws ClassNotFoundException In case the given class is not defined
+     *         inside this DEX file.
+     */
+    @Override
+    public void accept(String className, DexClassVisitor visitor)
+            throws ClassNotFoundException {
+        ClassDef classDef = classDefs.get(className);
+        if (classDef == null)
+            throw new ClassNotFoundException("Class not defined in DEX file: "
+                    + className);
+        classDef.accept(visitor);
+    }
 }