structsgen.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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|\*/|\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. types = {'unsigned int':'uint', 'unsigned char':'ubyte', 'size_t':'uint',}
  82. if t in types:
  83. t = types[t]
  84. t = prefix + t
  85. while type.endswith('*'):
  86. t = "POINTER(" + t + ")"
  87. type = type[:-1]
  88. return t
  89. def restructure( match ):
  90. type = match.group("type")
  91. if match.group("struct") == "":
  92. type = GetType(type)
  93. elif match.group("struct") == "C_ENUM ":
  94. type = "c_uint"
  95. else:
  96. type = GetType(type[2:], '')
  97. if match.group("index"):
  98. type = type + "*" + match.group("index")
  99. result = ""
  100. for name in match.group("name").split(','):
  101. result += "(\"" + name.strip() + "\", "+ type + "),"
  102. return result
  103. RErestruc = re.compile(r''
  104. r'(?P<struct>C_STRUCT\s|C_ENUM\s|)' # [C_STRUCT]
  105. r'(?P<type>\w+\s?\w+?[*]*)\s' # type
  106. #r'(?P<name>\w+)' # name
  107. r'(?P<name>\w+|[a-z0-9_, ]+)' # name
  108. r'(:?\[(?P<index>\w+)\])?;' # []; (optional)
  109. , re.DOTALL)
  110. #==[template]================================================
  111. template = """
  112. class $NAME$(Structure):
  113. \"\"\"
  114. $DESCRIPTION$
  115. \"\"\"
  116. $DEFINES$
  117. _fields_ = [
  118. $FIELDS$
  119. ]
  120. """
  121. templateSR = """
  122. class $NAME$(Structure):
  123. \"\"\"
  124. $DESCRIPTION$
  125. \"\"\"
  126. $DEFINES$
  127. $NAME$._fields_ = [
  128. $FIELDS$
  129. ]
  130. """
  131. #============================================================
  132. def Structify(fileName):
  133. file = open(fileName, 'r')
  134. text = file.read()
  135. result = []
  136. # Get defines.
  137. defs = REdefine.findall(text)
  138. # Create defines
  139. defines = "\n"
  140. for define in defs:
  141. # Clean desc
  142. desc = REdesc.sub('', define[0])
  143. # Replace comments
  144. desc = RErpcom.sub('#\g<line>', desc)
  145. defines += desc
  146. defines += " "*4 + define[1] + " = " + define[2] + "\n"
  147. # Get structs
  148. rs = REstructs.finditer(text)
  149. fileName = os.path.basename(fileName)
  150. print fileName
  151. for r in rs:
  152. name = r.group('name')[2:]
  153. desc = r.group('desc')
  154. # Skip some structs
  155. if name == "FileIO" or name == "File" or name == "locateFromAssimpHeap":
  156. continue
  157. text = r.group('code')
  158. # Clean desc
  159. desc = REdesc.sub('', desc)
  160. desc = "See '"+ fileName +"' for details." #TODO
  161. # Remove #ifdef __cplusplus
  162. text = RErmifdef.sub('', text)
  163. # Whether the struct contains more than just POD
  164. primitive = text.find('C_STRUCT') == -1
  165. # Restructure
  166. text = RErestruc.sub(restructure, text)
  167. # Replace comments
  168. text = RErpcom.sub('#\g<line>', text)
  169. # Whether it's selfreferencing: ex. struct Node { Node* parent; };
  170. selfreferencing = text.find('POINTER('+name+')') != -1
  171. complex = name == "Scene"
  172. # Create description
  173. description = ""
  174. for line in desc.split('\n'):
  175. description += " "*4 + line.strip() + "\n"
  176. description = description.rstrip()
  177. # Create fields
  178. fields = ""
  179. for line in text.split('\n'):
  180. fields += " "*12 + line.strip() + "\n"
  181. fields = fields.strip()
  182. if selfreferencing:
  183. templ = templateSR
  184. else:
  185. templ = template
  186. # Put it all together
  187. text = templ.replace('$NAME$', name)
  188. text = text.replace('$DESCRIPTION$', description)
  189. text = text.replace('$FIELDS$', fields)
  190. if ((name.lower() == fileName.split('.')[0][2:].lower()) and (name != 'Material')) or name == "String":
  191. text = text.replace('$DEFINES$', defines)
  192. else:
  193. text = text.replace('$DEFINES$', '')
  194. result.append((primitive, selfreferencing, complex, text))
  195. return result
  196. text = "#-*- coding: UTF-8 -*-\n\n"
  197. text += "from ctypes import POINTER, c_int, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte\n\n"
  198. structs1 = ""
  199. structs2 = ""
  200. structs3 = ""
  201. structs4 = ""
  202. path = '../include/'
  203. files = os.listdir (path)
  204. #files = ["aiScene.h", "aiTypes.h"]
  205. for fileName in files:
  206. if fileName.endswith('.h'):
  207. for struct in Structify(os.path.join(path, fileName)):
  208. primitive, sr, complex, struct = struct
  209. if primitive:
  210. structs1 += struct
  211. elif sr:
  212. structs2 += struct
  213. elif complex:
  214. structs4 += struct
  215. else:
  216. structs3 += struct
  217. text += structs1 + structs2 + structs3 + structs4
  218. file = open('structs.txt', 'w')
  219. file.write(text)
  220. file.close()