structsgen.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #!/usr/bin/env python
  2. # -*- Coding: UTF-8 -*-
  3. # ---------------------------------------------------------------------------
  4. # Open Asset Import Library (ASSIMP)
  5. # ---------------------------------------------------------------------------
  6. #
  7. # Copyright (c) 2006-2010, ASSIMP Development Team
  8. #
  9. # All rights reserved.
  10. #
  11. # Redistribution and use of this software in source and binary forms,
  12. # with or without modification, are permitted provided that the following
  13. # conditions are met:
  14. #
  15. # * Redistributions of source code must retain the above
  16. # copyright notice, this list of conditions and the
  17. # following disclaimer.
  18. #
  19. # * Redistributions in binary form must reproduce the above
  20. # copyright notice, this list of conditions and the
  21. # following disclaimer in the documentation and/or other
  22. # materials provided with the distribution.
  23. #
  24. # * Neither the name of the ASSIMP team, nor the names of its
  25. # contributors may be used to endorse or promote products
  26. # derived from this software without specific prior
  27. # written permission of the ASSIMP Development Team.
  28. #
  29. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  32. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  33. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  35. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  36. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  37. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  39. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40. # ---------------------------------------------------------------------------
  41. """Update PyAssimp's data structures to keep up with the
  42. C/C++ headers."""
  43. import os
  44. import re
  45. #==[regexps]=================================================
  46. # Clean desc
  47. REdefine = re.compile(r''
  48. r'(?P<desc>)' # /** *desc */
  49. r'#\s*define\s(?P<name>[^(\n]+?)\s(?P<code>.+)$' # #define name value
  50. , re.MULTILINE)
  51. # Get structs
  52. REstructs = re.compile(r''
  53. #r'//\s?[\-]*\s(?P<desc>.*?)\*/\s' # /** *desc */
  54. #r'//\s?[\-]*(?P<desc>.*?)\*/(?:.*?)' # garbage
  55. r'//\s?[\-]*\s(?P<desc>.*?)\*/\W*?' # /** *desc */
  56. r'struct\s(?:ASSIMP_API\s)?(?P<name>[a-z][a-z0-9_]\w+\b)' # struct name
  57. r'[^{]*?\{' # {
  58. r'(?P<code>.*?)' # code
  59. r'\}\s*(PACK_STRUCT)?;' # };
  60. , re.IGNORECASE + re.DOTALL + re.MULTILINE)
  61. # Clean desc
  62. REdesc = re.compile(r''
  63. r'^\s*?([*]|/\*\*)(?P<line>.*?)' # * line
  64. , re.IGNORECASE + re.DOTALL + re.MULTILINE)
  65. # Remove #ifdef __cplusplus
  66. RErmifdef = re.compile(r''
  67. r'#ifdef __cplusplus' # #ifdef __cplusplus
  68. r'(?P<code>.*)' # code
  69. r'#endif(\s*//\s*!?\s*__cplusplus)*' # #endif
  70. , re.IGNORECASE + re.DOTALL)
  71. # Replace comments
  72. RErpcom = re.compile(r''
  73. r'\s*(/\*+\s|\*+/|\B\*\s|///?!?)' # /**
  74. r'(?P<line>.*?)' # * line
  75. , re.IGNORECASE + re.DOTALL)
  76. # Restructure
  77. def GetType(type, prefix='c_'):
  78. t = type
  79. while t.endswith('*'):
  80. t = t[:-1]
  81. if t[:5] == 'const':
  82. t = t[5:]
  83. # skip some types
  84. if t in skiplist:
  85. return None
  86. t = t.strip()
  87. types = {'unsigned int':'uint', 'unsigned char':'ubyte', 'size_t':'uint',}
  88. if t in types:
  89. t = types[t]
  90. t = prefix + t
  91. while type.endswith('*'):
  92. t = "POINTER(" + t + ")"
  93. type = type[:-1]
  94. return t
  95. def restructure( match ):
  96. type = match.group("type")
  97. if match.group("struct") == "":
  98. type = GetType(type)
  99. elif match.group("struct") == "C_ENUM ":
  100. type = "c_uint"
  101. else:
  102. type = GetType(type[2:], '')
  103. if type is None:
  104. return ''
  105. if match.group("index"):
  106. type = type + "*" + match.group("index")
  107. result = ""
  108. for name in match.group("name").split(','):
  109. result += "(\"" + name.strip() + "\", "+ type + "),"
  110. return result
  111. RErestruc = re.compile(r''
  112. r'(?P<struct>C_STRUCT\s|C_ENUM\s|)' # [C_STRUCT]
  113. r'(?P<type>\w+\s?\w+?[*]*)\s' # type
  114. #r'(?P<name>\w+)' # name
  115. r'(?P<name>\w+|[a-z0-9_, ]+)' # name
  116. r'(:?\[(?P<index>\w+)\])?;' # []; (optional)
  117. , re.DOTALL)
  118. #==[template]================================================
  119. template = """
  120. class $NAME$(Structure):
  121. \"\"\"
  122. $DESCRIPTION$
  123. \"\"\"
  124. $DEFINES$
  125. _fields_ = [
  126. $FIELDS$
  127. ]
  128. """
  129. templateSR = """
  130. class $NAME$(Structure):
  131. \"\"\"
  132. $DESCRIPTION$
  133. \"\"\"
  134. $DEFINES$
  135. $NAME$._fields_ = [
  136. $FIELDS$
  137. ]
  138. """
  139. skiplist = ("FileIO", "File", "locateFromAssimpHeap",'LogStream','MeshAnim','AnimMesh')
  140. #============================================================
  141. def Structify(fileName):
  142. file = open(fileName, 'r')
  143. text = file.read()
  144. result = []
  145. # Get defines.
  146. defs = REdefine.findall(text)
  147. # Create defines
  148. defines = "\n"
  149. for define in defs:
  150. # Clean desc
  151. desc = REdesc.sub('', define[0])
  152. # Replace comments
  153. desc = RErpcom.sub('#\g<line>', desc)
  154. defines += desc
  155. if len(define[2].strip()):
  156. # skip non-integral defines, we can support them right now
  157. try:
  158. int(define[2],0)
  159. except:
  160. continue
  161. defines += " "*4 + define[1] + " = " + define[2] + "\n"
  162. # Get structs
  163. rs = REstructs.finditer(text)
  164. fileName = os.path.basename(fileName)
  165. print fileName
  166. for r in rs:
  167. name = r.group('name')[2:]
  168. desc = r.group('desc')
  169. # Skip some structs
  170. if name in skiplist:
  171. continue
  172. text = r.group('code')
  173. # Clean desc
  174. desc = REdesc.sub('', desc)
  175. desc = "See '"+ fileName +"' for details." #TODO
  176. # Remove #ifdef __cplusplus
  177. text = RErmifdef.sub('', text)
  178. # Whether the struct contains more than just POD
  179. primitive = text.find('C_STRUCT') == -1
  180. # Restructure
  181. text = RErestruc.sub(restructure, text)
  182. # Replace comments
  183. text = RErpcom.sub('#\g<line>', text)
  184. # Whether it's selfreferencing: ex. struct Node { Node* parent; };
  185. selfreferencing = text.find('POINTER('+name+')') != -1
  186. complex = name == "Scene"
  187. # Create description
  188. description = ""
  189. for line in desc.split('\n'):
  190. description += " "*4 + line.strip() + "\n"
  191. description = description.rstrip()
  192. # Create fields
  193. fields = ""
  194. for line in text.split('\n'):
  195. fields += " "*12 + line.strip() + "\n"
  196. fields = fields.strip()
  197. if selfreferencing:
  198. templ = templateSR
  199. else:
  200. templ = template
  201. # Put it all together
  202. text = templ.replace('$NAME$', name)
  203. text = text.replace('$DESCRIPTION$', description)
  204. text = text.replace('$FIELDS$', fields)
  205. if ((name.lower() == fileName.split('.')[0][2:].lower()) and (name != 'Material')) or name == "String":
  206. text = text.replace('$DEFINES$', defines)
  207. else:
  208. text = text.replace('$DEFINES$', '')
  209. result.append((primitive, selfreferencing, complex, text))
  210. return result
  211. text = "#-*- coding: UTF-8 -*-\n\n"
  212. text += "from ctypes import POINTER, c_int, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte\n\n"
  213. structs1 = ""
  214. structs2 = ""
  215. structs3 = ""
  216. structs4 = ""
  217. path = '../include/'
  218. files = os.listdir (path)
  219. #files = ["aiScene.h", "aiTypes.h"]
  220. for fileName in files:
  221. if fileName.endswith('.h'):
  222. for struct in Structify(os.path.join(path, fileName)):
  223. primitive, sr, complex, struct = struct
  224. if primitive:
  225. structs1 += struct
  226. elif sr:
  227. structs2 += struct
  228. elif complex:
  229. structs4 += struct
  230. else:
  231. structs3 += struct
  232. text += structs1 + structs2 + structs3 + structs4
  233. file = open('structs.txt', 'w')
  234. file.write(text)
  235. file.close()