changeset 8:59dd10bf60f2

Parse annotation items
author Thinker K.F. Li <thinker@codemud.net>
date Tue, 24 May 2011 14:55:18 +0800
parents 1d776ec496e5
children 9a49826b26d4
files paraspace/dexfile.py
diffstat 1 files changed, 212 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dexfile.py	Tue May 24 10:28:30 2011 +0800
+++ b/paraspace/dexfile.py	Tue May 24 14:55:18 2011 +0800
@@ -75,6 +75,15 @@
     return v
 
 
+def _to_int(data):
+    v = _to_uint(data)
+    sz = len(data)
+    if sz and ((1 << (sz * 8 - 1)) & v):
+        v = -((1 << (sz * 8)) - v)
+        pass
+    return v
+
+
 def _uleb128(data):
     sh = 0
     v = 0
@@ -682,6 +691,183 @@
     pass
 
 
+##
+#
+# \see createAnnotationMember() in dalvik/vm/reflect/Annotation.c
+#
+class _DEX_AnnotationMember(object):
+    nameIdx = None              # optional
+    valueType = None            # 1 byte
+    value = None
+    
+    #
+    # Constants from DexFile.h
+    #
+    kDexAnnotationByte = 0x00
+    kDexAnnotationShort = 0x02
+    kDexAnnotationChar = 0x03
+    kDexAnnotationInt = 0x04
+    kDexAnnotationLong = 0x06
+    kDexAnnotationFloat = 0x10
+    kDexAnnotationDouble = 0x11
+    kDexAnnotationString = 0x17
+    kDexAnnotationType = 0x18
+    kDexAnnotationField = 0x19
+    kDexAnnotationMethod = 0x1a
+    kDexAnnotationEnum = 0x1b
+    kDexAnnotationArray = 0x1c
+    kDexAnnotationAnnotation = 0x1d
+    kDexAnnotationNull = 0x1e
+    kDexAnnotationBoolean = 0x1f
+    
+    kDexAnnotationValueTypeMask = 0x1f
+    kDexAnnotationValueArgShift = 5
+
+    data_size = None
+
+    def parse(self, data, off):
+        self.nameIdx, sh = _uleb128(data[off:off + 5])
+        
+        self.parse_noname(data, off + sh)
+        
+        self.data_size = self.data_size + sh
+        pass
+
+    def parse_noname(self, data, off):
+        moff = man_off(off)
+        
+        valueType = _to_uint(data[moff(1):moff()])
+        self.valueType = valueType
+        width = valueType >> self.kDexAnnotationValueArgShift
+        
+        vtype = valueType & self.kDexAnnotationValueTypeMask
+
+        if vtype == self.kDexAnnotationByte:
+            self.value = _to_int(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationShort:
+            self.value = _to_int(data[moff(width):moff()])
+            pass
+        elif vtype == self.kDexAnnotationChar:
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationInt:
+            self.value = _to_int(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationLong:
+            self.value = _to_int(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationFloat:
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationDouble:
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationBoolean:
+            self.value = width != 0
+            pass
+        elif vtype == self.kDexAnnotationString: # string index
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationType: # TypeId index
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationMethod: # MethodId index
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationField:
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationEnum: # FieldId index
+            self.value = _to_uint(data[moff(width):moff()])
+            moff(1)
+            pass
+        elif vtype == self.kDexAnnotationArray:
+            size, sh = _uleb128(data[moff():moff() + 5])
+            moff(sh)
+            
+            def parse_array_elm():
+                elm = _DEX_AnnotationMember()
+                elm.parse_noname(data, moff())
+                moff(elm.data_size)
+                return elm
+            
+            self.value = [parse_array_elm()
+                          for i in range(size)]
+            pass
+        elif vtype == self.kDexAnnotationAnnotation:
+            annoitem = _DEX_AnnotationItem()
+            annoitem.parse_novisibility(data, moff())
+            moff(annoitem.data_size)
+            self.value = annoitem
+            pass
+        elif vtype == self.kDexAnnotationNull:
+            self.value = 0
+            pass
+        else:
+            raise ValueError, \
+                'Bad annotation element value byte 0x02x' % (valueType)
+        
+        self.data_size = moff() - off
+        pass
+    pass
+
+
+## \brief Annotation item
+#
+# \see processEncodedAnnotation() in dalvik/vm/reflect/Annotation.c
+#
+class _DEX_AnnotationItem(object):
+    visibility = None           # 1 byte (optional)
+    typeIdx = None
+    members = None
+
+    kDexVisibilityBuild = 0x00
+    kDexVisibilityRuntime = 0x01
+    kDexVisibilitySystem = 0x02
+    
+    data_size = None
+
+    def parse(self, data, off):
+        self.visibility = _to_uint(data[off:off + 1])
+
+        self.parse_novisibility(data, off + 1)
+
+        self.data_size = self.data_size + 1
+        pass
+
+    def parse_novisibility(self, data, off):
+        moff = man_off(off)
+        
+        self.typeIdx, sh = _uleb128(data[moff():moff() + 5])
+        moff(sh)
+        size, sh = _uleb128(data[moff():moff() + 5])
+        moff(sh)
+        
+        def parse_AnnotationMemmber():
+            member = _DEX_AnnotationMember()
+            member.parse(data, moff())
+            moff(member.data_size)
+            return member
+        
+        self.members = [parse_AnnotationMemmber()
+                        for i in range(size)]
+
+        self.data_size = moff() - off
+        pass
+    pass
+
+
 class DEXFile(object):
     _data = None
     _header = None
@@ -697,6 +883,7 @@
     _codeItems = None
     _annotationSetItems = None
     _annotationsDirectoryItems = None
+    _annotationItems = None
     
     def __init__(self):
         pass
@@ -958,6 +1145,25 @@
                                            for i in range(annodir_map.size)]
         pass
 
+    def _parse_annotationItems(self):
+        data = self._data
+        
+        annoitem_map = self.find_map_item_name('kDexTypeAnnotationItem')
+        if annoitem_map is None:
+            return
+
+        moff = man_off(annoitem_map.offset)
+
+        def parse_annotationItem():
+            item = _DEX_AnnotationItem()
+            item.parse(data, moff())
+            moff(item.data_size)
+            return item
+
+        self._annotationItems = [parse_annotationItem()
+                                 for i in range(annoitem_map.size)]
+        pass
+
     def parse(self, data):
         self._data = data
         header = _DEX_header()
@@ -976,6 +1182,7 @@
         self._parse_codeItems()
         self._parse_annotationSetItems()
         self._parse_annotationsDirectoryItems()
+        self._parse_annotationItems()
         pass
     pass
 
@@ -1044,6 +1251,11 @@
     print
     print 'AnnotationsDirtoryItems size is %d bytes' % (bytes)
     
+    bytes = sum([annoitem.data_size
+                 for annoitem in dex._annotationItems])
+    print
+    print 'AnnotationItems size is %d bytes' % (bytes)
+    
     print
     print 'Data maps'
     maps = dex._maps