From 5794a921683e89e8bdecd46cb7f78b1af08dce08 Mon Sep 17 00:00:00 2001 From: hakril Date: Fri, 26 Apr 2019 13:43:41 +0200 Subject: [PATCH] ctypes_generation now handle anonymous sub-struct/union --- ctypes_generation/generate.py | 3 ++- ctypes_generation/struct_parser.py | 32 +++++++++++++++++++++------- ctypes_generation/winstruct.py | 34 ++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/ctypes_generation/generate.py b/ctypes_generation/generate.py index 580e9d4..6109c36 100644 --- a/ctypes_generation/generate.py +++ b/ctypes_generation/generate.py @@ -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): diff --git a/ctypes_generation/struct_parser.py b/ctypes_generation/struct_parser.py index 209cb74..e0004c8 100644 --- a/ctypes_generation/struct_parser.py +++ b/ctypes_generation/struct_parser.py @@ -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)) diff --git a/ctypes_generation/winstruct.py b/ctypes_generation/winstruct.py index 6cadc6c..76c0e2e 100644 --- a/ctypes_generation/winstruct.py +++ b/ctypes_generation/winstruct.py @@ -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 + 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"