ctypes_generation now handle anonymous sub-struct/union

This commit is contained in:
hakril
2019-04-26 13:43:41 +02:00
parent 578392ffde
commit 5794a92168
3 changed files with 58 additions and 11 deletions
+2 -1
View File
@@ -231,7 +231,8 @@ class BasicTypeNodes(object):
@property
def exports(self):
# Let allow ourself to redefine the bugged BYTE define & MAX_PATH which is NOT A TYPE !
return set(dummy_wintypes.names) - set(["BYTE", "MAX_PATH"])
# Also ourself to redifine FILETIME (to trigger the extended struct generation)
return set(dummy_wintypes.names) - set(["BYTE", "MAX_PATH", "_FILETIME", "FILETIME"])
class FakeExporter(object):
def __init__(self, exports):
+24 -8
View File
@@ -24,8 +24,21 @@ class WinStructParser(Parser):
def parse_def(self):
if self.peek() == KeywordToken("struct"):
discard = self.next_token()
if type(self.peek()) != NameToken and self.peek() in (KeywordToken("union"), KeywordToken("struct")):
# Anonymous union-structure :)
# kword = self.assert_token_type(KeywordToken)
# Not a name. Anon union/struct ?
subdef_type = self.next_token() # union / struct
if type(self.peek()) == OpenBracketToken:
print("<{0}> ANON START WITH <{1}>".format(self._yolo, self.peek()))
sub = self.parse_winstruct(anonymous=True, anon_type=subdef_type)
print("Anon is <{0}>".format(sub))
return (sub, NameToken(None), 1)
else:
# struct _MYNAME_ -> no anon juste the name of the struct.
# Nothing special: juste drop the struct
assert subdef_type.value == "struct"
# Name will be enforced by nest line.
def_type_tok = self.assert_token_type(NameToken)
def_type = WinStructType(def_type_tok.value)
@@ -98,14 +111,17 @@ class WinStructParser(Parser):
return res_enum
def parse_winstruct(self):
def parse_winstruct(self, anonymous=False, anon_type=None):
is_typedef = False
peeked = self.peek()
if peeked == KeywordToken("typedef"):
self.assert_keyword("typedef")
is_typedef = True
def_type = self.assert_token_type(KeywordToken)
if not anonymous:
def_type = self.assert_token_type(KeywordToken)
else:
def_type = anon_type # Hack car le lexeing a ete fait avant, l'info est donc passee en param.
if def_type.value == "enum":
return self.parse_enum(is_typedef)
if def_type.value == "struct":
@@ -118,14 +134,14 @@ class WinStructParser(Parser):
# Not an anonymous structure def
struct_name = self.assert_token_type(NameToken).value
else:
# Anonymous structure def: check if we are ina typedef
if not is_typedef:
# Anonymous structure def: check if we are ina typedef
if not is_typedef and not anonymous:
raise ValueError("Anonymous structure/union not in a typedef")
struct_name = None #
struct_name = "anon"
self.assert_token_type(OpenBracketToken)
self._yolo = struct_name
result = WinDefType(struct_name, self.pack)
while type(self.peek()) != CloseBracketToken:
tok_type, tok_name, nb_rep = self.parse_def()
result.add_field((tok_type, tok_name.value, nb_rep))
+32 -2
View File
@@ -1,4 +1,5 @@
import collections
import itertools
#WinStructType = collections.namedtuple('WinStructType', ['name'])
@@ -58,7 +59,7 @@ class WinStruct(object):
if self.name is None:
raise ValueError("Anonymous struct first typedef ({0}) should not be a PTR type".format(name))
if name in self.typedef:
raise ValueError("nop")
raise ValueError("Multiple typedef for <{0}>".format(name))
self.typedef[name] = Ptr(self)
def is_self_referencing(self):
@@ -69,6 +70,27 @@ class WinStruct(object):
return True
return False
def contains_anon_struct(self):
return any(name is None for type,name,nb in self.fields)
def prepare_anon_struct(self):
new_fields = []
code = []
i = 0
for type, name, nb in self.fields:
if name is not None:
new_fields.append((type, name, nb))
continue
i += 1
# Should begin by "_ANON_" to trigger <generate_anonymous_union>
type.name = "_ANON_{0}_SUB_{1}_{2}".format(self.name, type.ctypes_type, i).upper()
code.append(type.generate_ctypes()) # Generate class for the code
# Replace the type name + field name in fields list
new_fields.append((WinStructType(type.name), "anon_{0:02}".format(i), nb))
self.fields = new_fields
return "\n".join(code)
def generate_selfref_ctypes_class(self):
res = ["# Self referencing struct tricks"]
res += ["""class {0}(Structure): pass""".format(self.name)]
@@ -129,13 +151,21 @@ class WinStruct(object):
return "\n".join(typedef_ctypes)
def generate_ctypes(self):
anon_code = ""
if self.contains_anon_struct():
anon_code = self.prepare_anon_struct()
if self.is_self_referencing():
print("{0} is self referencing".format(self.name))
return self.generate_selfref_ctypes_class() + "\n"
import pdb;pdb.set_trace()
print("LOL")
ctypes_class = self.generate_ctypes_class()
ctypes_typedef = self.generate_typedef_ctypes()
return "\n".join([ctypes_class, ctypes_typedef]) + "\n"
return anon_code + "\n".join([ctypes_class, ctypes_typedef]) + "\n"
class WinUnion(WinStruct):
ctypes_type = "Union"