[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [31766] trunk/blender/intern/tools/pydna. py: Experemental module (for developers only), exposes DNA data via python

Campbell Barton ideasman42 at gmail.com
Sun Sep 5 14:53:55 CEST 2010


Revision: 31766
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=31766
Author:   campbellbarton
Date:     2010-09-05 14:53:55 +0200 (Sun, 05 Sep 2010)

Log Message:
-----------
Experemental module (for developers only), exposes DNA data via python
uses no blender/python modules, pure python + autogenerated ctypes api.

Exposes:
 * pydna.main: main database access.
 * pydna.types: a module of all DNA ctypes structures.

 * Utility method: CAST(dna_type)
 * Utility method for ListBase: ITER(dna_type)

Example:
 import sys
 sys.path.append("/b/intern/tools")

 import pydna

 for obj in pydna.main.object.ITER("Object"):
     print("Object:", obj.id.name)
     if obj.data:
         data = pydna.types.ID.from_address(obj.data)
         print("  ObData:", data.name)

Added Paths:
-----------
    trunk/blender/intern/tools/pydna.py

Added: trunk/blender/intern/tools/pydna.py
===================================================================
--- trunk/blender/intern/tools/pydna.py	                        (rev 0)
+++ trunk/blender/intern/tools/pydna.py	2010-09-05 12:53:55 UTC (rev 31766)
@@ -0,0 +1,332 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+Experemental module (for developers only), exposes DNA data via python
+uses no blender/python modules, pure python + autogenerated ctypes api.
+
+Exposes:
+ * pydna.main: main database access.
+ * pydna.types: a module of all DNA ctypes structures.
+
+ * Utility method: CAST(dna_type)
+ * Utility method for ListBase: ITER(dna_type)
+
+Example:
+ import sys
+ sys.path.append("/b/intern/tools")
+
+ import pydna
+
+ for obj in pydna.main.object.ITER("Object"):
+     print("Object:", obj.id.name)
+     if obj.data:
+         data = pydna.types.ID.from_address(obj.data)
+         print("  ObData:", data.name)
+"""
+
+import ctypes
+import struct
+
+def _api():
+
+    def is_ctypes_subclass(other, main_class):
+        while other:
+            if other is main_class:
+                return True
+            other = getattr(other, "_type_", None)
+        return False
+
+
+    def is_ctypes_initialized(other):
+        _other = other
+        while other:
+            if hasattr(other, "_fields_"):
+                return True
+            other = getattr(other, "_type_", None)
+        print(_other, "NOT INIT")
+        return False
+
+
+    def is_ctypes_base(other):
+        while type(getattr(other, "_type_", "")) != str:
+            other = other._type_
+        return other
+    
+    class MixIn:
+        pass
+    
+    blend_cdll = ctypes.CDLL("")
+    blend_lib = ctypes.LibraryLoader("")
+    
+    def blend_parse_dna():
+        # from dna.c
+        sdna_str_pt = blend_cdll.DNAstr
+        sdna_len_pt = blend_cdll.DNAlen
+
+        # cast
+        sdna_len_pt = ctypes.c_void_p.from_address(ctypes.addressof(sdna_len_pt))
+        sdna_len = ctypes.c_int.from_address(sdna_len_pt.value)
+
+        blend_sdna = ctypes.string_at(sdna_str_pt, sdna_len) # 58064
+        
+        ofs = 0
+        assert(blend_sdna[ofs:ofs + 8] == b'SDNANAME')
+        ofs += 8
+
+        sdna_names_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0]
+        ofs += 4
+        
+        blend_sdna_names = blend_sdna[ofs:].split(b'\0', sdna_names_len)
+        blend_sdna_remainder = blend_sdna_names.pop(-1) # last item is not a name.
+        ofs = len(blend_sdna) - len(blend_sdna_remainder)
+        ofs = (ofs + 3) & ~3
+
+        assert(blend_sdna[ofs:ofs + 4] == b'TYPE')
+        ofs += 4
+
+        sdna_types_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0]
+        ofs += 4
+        
+        blend_sdna_types = blend_sdna[ofs:].split(b'\0', sdna_types_len)
+        blend_sdna_remainder = blend_sdna_types.pop(-1)
+        ofs = len(blend_sdna) - len(blend_sdna_remainder)
+        ofs = (ofs + 3) & ~3
+
+        assert(blend_sdna[ofs:ofs + 4] == b'TLEN')
+        ofs += 4
+
+        blend_sdna_typelens = struct.unpack("%dh" % sdna_types_len, blend_sdna[ofs:ofs + (sdna_types_len * 2)])
+        ofs += sdna_types_len * 2
+        ofs = (ofs + 3) & ~3
+
+        # array of pointers to short arrays
+        assert(blend_sdna[ofs:ofs + 4] == b'STRC')
+        ofs += 4
+        
+        sdna_structs_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0]
+        ofs += 4
+        
+        
+        blend_sdna_structs = []
+        
+        for i in range(sdna_structs_len):
+            struct_type, struct_tot = struct.unpack("hh", blend_sdna[ofs:ofs + 4])
+            ofs += 4
+            struct_type_name_pairs = struct.unpack("%dh" % struct_tot * 2, blend_sdna[ofs:ofs + (struct_tot * 4)])
+        
+            # convert into pairs, easier to understand (type, name)
+            struct_type_name_pairs = [(struct_type_name_pairs[j], struct_type_name_pairs[j + 1]) for j in range(0, struct_tot * 2, 2)]
+
+            blend_sdna_structs.append((struct_type, struct_type_name_pairs))
+            ofs += struct_tot * 4
+            # ofs = (ofs + 1) & ~1
+        
+        return blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs
+
+    def create_dna_structs(blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs):
+        
+        # create all subclasses of ctypes.Structure
+        ctypes_structs = {name: type(name.decode(), (ctypes.Structure, MixIn), {}) for name in blend_sdna_types}
+        ctypes_basic = {b"float": ctypes.c_float, b"double": ctypes.c_double, b"int": ctypes.c_int, b"short": ctypes.c_short, b"char": ctypes.c_char, b"void": ctypes.c_void_p}
+        ctypes_fields = {}
+        
+        # collect fields
+        for struct_id, struct_type_name_pairs in blend_sdna_structs:
+            struct_name = blend_sdna_types[struct_id]
+            ctype_struct = ctypes_structs[struct_name]
+            fields = []
+            
+            for stype, sname in struct_type_name_pairs:
+                name_string = blend_sdna_names[sname]
+                type_string = blend_sdna_types[stype]
+                type_py = ctypes_basic.get(type_string)
+                if type_py is None:
+                    type_py = ctypes_structs.get(type_string)
+
+                # todo, these might need to be changed
+                name_string = name_string.replace(b"(", b"")
+                name_string = name_string.replace(b")", b"")
+
+                # * First parse the pointer *
+                pointer_count = 0
+                while name_string[0] == 42: # '*'
+                    pointer_count += 1
+                    name_string = name_string[1:]
+                
+                # alredy a pointer
+                if type_py is ctypes.c_void_p:
+                    pointer_count -= 1
+                elif type_py is ctypes.c_char and pointer_count == 1:
+                    type_py = ctypes.c_char_p
+                    pointer_count = 0
+                
+                if pointer_count < 0:
+                    Exception("error parsing pointer")
+
+                for i in range(pointer_count):
+                    type_py = ctypes.POINTER(type_py)
+                
+                # * Now parse the array [] *
+                if b'[' in name_string:
+                    name_string = name_string.replace(b'[', b' ')
+                    name_string = name_string.replace(b']', b' ')
+                    name_split = name_string.split()
+                    name_string = name_split[0]
+                    for array_dim in reversed(name_split[1:]):
+                        type_py = type_py * int(array_dim)
+
+                fields.append((name_string.decode(), type_py))
+
+            ctypes_fields[struct_name] = fields
+        
+        # apply fields all in one go!
+        for struct_id, struct_type_name_pairs in blend_sdna_structs:
+            struct_name = blend_sdna_types[struct_id]
+            ctype_struct = ctypes_structs[struct_name]
+            try:
+                ctype_struct._fields_ = ctypes_fields[struct_name]
+            except:
+                print("Error:", struct_name)
+                import traceback
+                traceback.print_exc()
+                # print(fields)
+
+        # test fields
+        for struct_id, struct_type_name_pairs in blend_sdna_structs:
+            ctype_struct = ctypes_structs[blend_sdna_types[struct_id]]
+            if blend_sdna_typelens[struct_id] != ctypes.sizeof(ctype_struct):
+                print("Size Mismatch for %r blender:%d vs python:%d" % (blend_sdna_types[struct_id], blend_sdna_typelens[struct_id], ctypes.sizeof(ctype_struct)))
+
+        return ctypes_structs
+
+    def decorate_api(struct_dict):
+        
+        # * Decotate the api *
+        
+        # listbase iter
+        
+        type_cast_lb = struct_dict[b'ListBase']
+        type_cast_link = struct_dict[b'Link']
+
+        def list_base_iter(self, type_name):
+            type_cast = struct_dict[type_name.encode('ASCII')]
+            try:
+                ret = type_cast_link.from_address(ctypes.addressof(self.first))
+            except:
+                ret = type_cast_link.from_address(self.first)
+                
+                
+
+            while ret is not None:
+                return_value = type_cast.from_address(ctypes.addressof(ret))
+                try:
+                    next_pointer = getattr(ret.next, "contents")
+                except:
+                    next_pointer = None
+
+                if next_pointer:
+                    ret = type_cast_link.from_address(ctypes.addressof(next_pointer))
+                else:
+                    ret = None
+
+                yield return_value
+
+        struct_dict[b'ListBase'].ITER = list_base_iter
+        
+        def CAST(self, to):
+            type_cast = struct_dict[to.encode('ASCII')]
+            return type_cast.from_address(ctypes.addressof(self))
+        
+        MixIn.CAST = CAST
+
+
+    blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs = blend_parse_dna()
+    struct_dict = create_dna_structs(blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs)
+
+    # print out all structs
+    '''
+    for struct_id, struct_type_name_pairs in blend_sdna_structs:
+        print("")
+        sruct_name = blend_sdna_types[struct_id].decode()
+        print("typedef struct %s {" % sruct_name)
+        for stype, sname in struct_type_name_pairs:
+            print("    %s %s;" % (blend_sdna_types[stype].decode(), blend_sdna_names[sname].decode()))
+        print("} %s;" % sruct_name)
+    '''
+    

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list