dissect.cstruct 4.6.dev5__tar.gz → 4.6.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/PKG-INFO +1 -1
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/parser.py +69 -5
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/tools/stubgen.py +3 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/PKG-INFO +1 -1
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_parser.py +137 -5
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_tools_stubgen.py +20 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/.git-blame-ignore-revs +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/.gitattributes +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/CHANGELOG.md +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/COPYRIGHT +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/LICENSE +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/MANIFEST.in +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/README.md +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/__init__.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/bitbuffer.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/compiler.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/cstruct.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/exceptions.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/expression.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/tools/__init__.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/__init__.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/base.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/char.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/enum.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/flag.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/int.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/leb128.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/packed.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/pointer.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/structure.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/void.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/types/wchar.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect/cstruct/utils.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/SOURCES.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/dependency_links.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/entry_points.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/requires.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/top_level.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/examples/disk.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/examples/mirai.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/examples/pe.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/examples/protobuf.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/examples/secdesc.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/pyproject.toml +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/setup.cfg +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/__init__.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/_data/testdef.txt +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/_docs/Makefile +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/_docs/__init__.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/_docs/conf.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/_docs/index.rst +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/conftest.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_align.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_annotations.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_basic.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_bitbuffer.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_bitfield.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_compiler.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_ctypes.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_expression.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_base.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_char.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_custom.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_enum.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_flag.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_int.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_leb128.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_packed.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_pointer.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_structure.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_union.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_void.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_types_wchar.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/test_utils.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tests/utils.py +0 -0
- {dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.cstruct
|
|
3
|
-
Version: 4.6.
|
|
3
|
+
Version: 4.6.dev7
|
|
4
4
|
Summary: A Dissect module implementing a parser for C-like structures: structure parsing in Python made easy
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -49,12 +49,18 @@ class TokenParser(Parser):
|
|
|
49
49
|
self.compiled = compiled
|
|
50
50
|
self.align = align
|
|
51
51
|
self.TOK = self._tokencollection()
|
|
52
|
+
self._conditionals = []
|
|
53
|
+
self._conditionals_depth = 0
|
|
52
54
|
|
|
53
55
|
@staticmethod
|
|
54
56
|
def _tokencollection() -> TokenCollection:
|
|
55
57
|
TOK = TokenCollection()
|
|
56
58
|
TOK.add(r"#\[(?P<values>[^\]]+)\](?=\s*)", "CONFIG_FLAG")
|
|
57
|
-
TOK.add(r"#define\s+(?P<name>[^\s]+)
|
|
59
|
+
TOK.add(r"#define\s+(?P<name>[^\s]+)(?P<value>[^\r\n]*)", "DEFINE")
|
|
60
|
+
TOK.add(r"#ifdef\s+(?P<name>[^\s]+)\s*", "IFDEF")
|
|
61
|
+
TOK.add(r"#ifndef\s+(?P<name>[^\s]+)\s*", "IFNDEF")
|
|
62
|
+
TOK.add(r"#else\s*", "ELSE")
|
|
63
|
+
TOK.add(r"#endif\s*", "ENDIF")
|
|
58
64
|
TOK.add(r"typedef(?=\s)", "TYPEDEF")
|
|
59
65
|
TOK.add(r"(?:struct|union)(?=\s|{)", "STRUCT")
|
|
60
66
|
TOK.add(
|
|
@@ -80,12 +86,61 @@ class TokenParser(Parser):
|
|
|
80
86
|
idents.append(tokens.consume())
|
|
81
87
|
return " ".join([i.value for i in idents])
|
|
82
88
|
|
|
89
|
+
def _conditional(self, tokens: TokenConsumer) -> None:
|
|
90
|
+
token = tokens.consume()
|
|
91
|
+
pattern = self.TOK.patterns[token.token]
|
|
92
|
+
match = pattern.match(token.value).groupdict()
|
|
93
|
+
|
|
94
|
+
value = match["name"]
|
|
95
|
+
|
|
96
|
+
if token.token == self.TOK.IFDEF:
|
|
97
|
+
self._conditionals.append(value in self.cstruct.consts)
|
|
98
|
+
elif token.token == self.TOK.IFNDEF:
|
|
99
|
+
self._conditionals.append(value not in self.cstruct.consts)
|
|
100
|
+
|
|
101
|
+
def _check_conditional(self, tokens: TokenConsumer) -> bool:
|
|
102
|
+
"""Check and handle conditionals. Return a boolean indicating if we need to continue to the next token."""
|
|
103
|
+
if self._conditionals and self._conditionals_depth == len(self._conditionals):
|
|
104
|
+
# If we have a conditional and the depth matches, handle it accordingly
|
|
105
|
+
if tokens.next == self.TOK.ELSE:
|
|
106
|
+
# Flip the last conditional
|
|
107
|
+
tokens.consume()
|
|
108
|
+
self._conditionals[-1] = not self._conditionals[-1]
|
|
109
|
+
return True
|
|
110
|
+
|
|
111
|
+
if tokens.next == self.TOK.ENDIF:
|
|
112
|
+
# Pop the last conditional
|
|
113
|
+
tokens.consume()
|
|
114
|
+
self._conditionals.pop()
|
|
115
|
+
self._conditionals_depth -= 1
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
if tokens.next in (self.TOK.IFDEF, self.TOK.IFNDEF):
|
|
119
|
+
# If we encounter a new conditional, increase the depth
|
|
120
|
+
self._conditionals_depth += 1
|
|
121
|
+
|
|
122
|
+
if tokens.next == self.TOK.ENDIF:
|
|
123
|
+
# Similarly, decrease the depth if needed
|
|
124
|
+
self._conditionals_depth -= 1
|
|
125
|
+
|
|
126
|
+
if self._conditionals and not self._conditionals[-1]:
|
|
127
|
+
# If the last conditional evaluated to False, skip the next token
|
|
128
|
+
tokens.consume()
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
if tokens.next in (self.TOK.IFDEF, self.TOK.IFNDEF):
|
|
132
|
+
# If the next token is a conditional, process it
|
|
133
|
+
self._conditional(tokens)
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
return False
|
|
137
|
+
|
|
83
138
|
def _constant(self, tokens: TokenConsumer) -> None:
|
|
84
139
|
const = tokens.consume()
|
|
85
140
|
pattern = self.TOK.patterns[self.TOK.DEFINE]
|
|
86
141
|
match = pattern.match(const.value).groupdict()
|
|
87
142
|
|
|
88
|
-
value = match["value"]
|
|
143
|
+
value = match["value"].strip()
|
|
89
144
|
try:
|
|
90
145
|
value = ast.literal_eval(value)
|
|
91
146
|
except (ValueError, SyntaxError):
|
|
@@ -208,6 +263,9 @@ class TokenParser(Parser):
|
|
|
208
263
|
tokens.consume()
|
|
209
264
|
break
|
|
210
265
|
|
|
266
|
+
if self._check_conditional(tokens):
|
|
267
|
+
continue
|
|
268
|
+
|
|
211
269
|
field = self._parse_field(tokens)
|
|
212
270
|
fields.append(field)
|
|
213
271
|
|
|
@@ -266,7 +324,7 @@ class TokenParser(Parser):
|
|
|
266
324
|
return Field(None, type_, None)
|
|
267
325
|
|
|
268
326
|
if tokens.next != self.TOK.NAME:
|
|
269
|
-
raise ParserError(f"line {self._lineno(tokens.next)}: expected name")
|
|
327
|
+
raise ParserError(f"line {self._lineno(tokens.next)}: expected name, got {tokens.next!r}")
|
|
270
328
|
nametok = tokens.consume()
|
|
271
329
|
|
|
272
330
|
type_, name, bits = self._parse_field_type(type_, nametok.value)
|
|
@@ -314,11 +372,11 @@ class TokenParser(Parser):
|
|
|
314
372
|
tokens.eol()
|
|
315
373
|
break
|
|
316
374
|
|
|
317
|
-
if tokens.next not in (self.TOK.NAME, self.TOK.DEFS):
|
|
375
|
+
if tokens.next not in (self.TOK.NAME, self.TOK.DEFS, self.TOK.IDENTIFIER):
|
|
318
376
|
break
|
|
319
377
|
|
|
320
378
|
ntoken = tokens.consume()
|
|
321
|
-
if ntoken
|
|
379
|
+
if ntoken in (self.TOK.NAME, self.TOK.IDENTIFIER):
|
|
322
380
|
names.append(ntoken.value.strip())
|
|
323
381
|
elif ntoken == self.TOK.DEFS:
|
|
324
382
|
names.extend([name.strip() for name in ntoken.value.strip().split(",")])
|
|
@@ -378,6 +436,9 @@ class TokenParser(Parser):
|
|
|
378
436
|
if token is None:
|
|
379
437
|
break
|
|
380
438
|
|
|
439
|
+
if self._check_conditional(tokens):
|
|
440
|
+
continue
|
|
441
|
+
|
|
381
442
|
if token == self.TOK.CONFIG_FLAG:
|
|
382
443
|
self._config_flag(tokens)
|
|
383
444
|
elif token == self.TOK.DEFINE:
|
|
@@ -395,6 +456,9 @@ class TokenParser(Parser):
|
|
|
395
456
|
else:
|
|
396
457
|
raise ParserError(f"line {self._lineno(token)}: unexpected token {token!r}")
|
|
397
458
|
|
|
459
|
+
if self._conditionals:
|
|
460
|
+
raise ParserError(f"line {self._lineno(tokens.previous)}: unclosed conditional statement")
|
|
461
|
+
|
|
398
462
|
|
|
399
463
|
class CStyleParser(Parser):
|
|
400
464
|
"""Definition parser for C-like structure syntax.
|
|
@@ -92,6 +92,9 @@ def generate_cstruct_stub(cs: cstruct, module_prefix: str = "", cls_name: str =
|
|
|
92
92
|
stub = f"{name}: TypeAlias = {typedef.__name__}"
|
|
93
93
|
elif issubclass(typedef, (types.Enum, types.Flag)):
|
|
94
94
|
stub = generate_enum_stub(typedef, cs_prefix=cs_prefix, module_prefix=module_prefix)
|
|
95
|
+
elif issubclass(typedef, types.Pointer):
|
|
96
|
+
typehint = generate_typehint(typedef, prefix=cs_prefix, module_prefix=module_prefix)
|
|
97
|
+
stub = f"{name}: TypeAlias = {typehint}"
|
|
95
98
|
elif issubclass(typedef, types.Structure):
|
|
96
99
|
stub = generate_structure_stub(typedef, cs_prefix=cs_prefix, module_prefix=module_prefix)
|
|
97
100
|
elif issubclass(typedef, types.BaseType):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.cstruct
|
|
3
|
-
Version: 4.6.
|
|
3
|
+
Version: 4.6.dev7
|
|
4
4
|
Summary: A Dissect module implementing a parser for C-like structures: structure parsing in Python made easy
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
3
|
from unittest.mock import Mock
|
|
5
4
|
|
|
6
5
|
import pytest
|
|
7
6
|
|
|
7
|
+
from dissect.cstruct import cstruct
|
|
8
8
|
from dissect.cstruct.exceptions import ParserError
|
|
9
9
|
from dissect.cstruct.parser import TokenParser
|
|
10
|
-
from dissect.cstruct.types import BaseArray, Pointer
|
|
10
|
+
from dissect.cstruct.types import BaseArray, Pointer, Structure
|
|
11
11
|
from tests.utils import verify_compiled
|
|
12
12
|
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
from dissect.cstruct import cstruct
|
|
15
|
-
|
|
16
13
|
|
|
17
14
|
def test_nested_structs(cs: cstruct, compiled: bool) -> None:
|
|
18
15
|
cdef = """
|
|
@@ -149,3 +146,138 @@ def test_includes(cs: cstruct) -> None:
|
|
|
149
146
|
assert cs.myStruct.__name__ == "myStruct"
|
|
150
147
|
assert len(cs.myStruct.fields) == 1
|
|
151
148
|
assert cs.myStruct.fields.get("charVal")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_typedef_pointer(cs: cstruct) -> None:
|
|
152
|
+
cdef = """
|
|
153
|
+
typedef struct _IMAGE_DATA_DIRECTORY {
|
|
154
|
+
DWORD VirtualAddress;
|
|
155
|
+
DWORD Size;
|
|
156
|
+
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
|
|
157
|
+
"""
|
|
158
|
+
cs.load(cdef)
|
|
159
|
+
|
|
160
|
+
assert issubclass(cs._IMAGE_DATA_DIRECTORY, Structure)
|
|
161
|
+
assert cs.IMAGE_DATA_DIRECTORY is cs._IMAGE_DATA_DIRECTORY
|
|
162
|
+
assert issubclass(cs.PIMAGE_DATA_DIRECTORY, Pointer)
|
|
163
|
+
assert cs.PIMAGE_DATA_DIRECTORY.type == cs._IMAGE_DATA_DIRECTORY
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_conditional_ifdef(cs: cstruct) -> None:
|
|
167
|
+
cdef = """
|
|
168
|
+
#define MY_CONST 42
|
|
169
|
+
|
|
170
|
+
#ifdef MY_CONST
|
|
171
|
+
struct test {
|
|
172
|
+
uint32 a;
|
|
173
|
+
};
|
|
174
|
+
#endif
|
|
175
|
+
"""
|
|
176
|
+
cs.load(cdef)
|
|
177
|
+
|
|
178
|
+
assert "test" in cs.typedefs
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_conditional_ifndef(cs: cstruct) -> None:
|
|
182
|
+
cdef = """
|
|
183
|
+
#ifndef MYVAR
|
|
184
|
+
#define MYVAR (1)
|
|
185
|
+
#endif
|
|
186
|
+
"""
|
|
187
|
+
cs.load(cdef)
|
|
188
|
+
|
|
189
|
+
assert "MYVAR" in cs.consts
|
|
190
|
+
assert cs.consts["MYVAR"] == 1
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_conditional_ifndef_guard(cs: cstruct) -> None:
|
|
194
|
+
cdef = """
|
|
195
|
+
/* Define Guard */
|
|
196
|
+
#ifndef __MYGUARD
|
|
197
|
+
#define __MYGUARD
|
|
198
|
+
|
|
199
|
+
typedef struct myStruct
|
|
200
|
+
{
|
|
201
|
+
char charVal[16];
|
|
202
|
+
}
|
|
203
|
+
#endif // __MYGUARD
|
|
204
|
+
"""
|
|
205
|
+
cs.load(cdef)
|
|
206
|
+
|
|
207
|
+
assert "__MYGUARD" in cs.consts
|
|
208
|
+
assert "myStruct" in cs.typedefs
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_conditional_nested() -> None:
|
|
212
|
+
cdef = """
|
|
213
|
+
#ifndef MYSWITCH1
|
|
214
|
+
#define MYVAR1 (1)
|
|
215
|
+
#else
|
|
216
|
+
#ifdef MYSWITCH2
|
|
217
|
+
#define MYVAR1 (2)
|
|
218
|
+
#else
|
|
219
|
+
#define MYVAR1 (3)
|
|
220
|
+
#endif
|
|
221
|
+
#endif
|
|
222
|
+
"""
|
|
223
|
+
cs = cstruct().load(cdef)
|
|
224
|
+
|
|
225
|
+
assert "MYVAR1" in cs.consts
|
|
226
|
+
assert cs.consts["MYVAR1"] == 1
|
|
227
|
+
|
|
228
|
+
cs = cstruct().load("#define MYSWITCH1")
|
|
229
|
+
|
|
230
|
+
assert "MYSWITCH1" in cs.consts
|
|
231
|
+
|
|
232
|
+
cs.load(cdef)
|
|
233
|
+
|
|
234
|
+
assert "MYVAR1" in cs.consts
|
|
235
|
+
assert cs.consts["MYVAR1"] == 3
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_conditional_in_struct(cs: cstruct) -> None:
|
|
239
|
+
cdef = """
|
|
240
|
+
struct t_bitfield {
|
|
241
|
+
union {
|
|
242
|
+
struct {
|
|
243
|
+
uint32_t bit0:1;
|
|
244
|
+
uint32_t bit1:1;
|
|
245
|
+
#ifdef MYSWT
|
|
246
|
+
uint32_t bit2:1;
|
|
247
|
+
#endif
|
|
248
|
+
} fval;
|
|
249
|
+
uint32_t bits;
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
"""
|
|
253
|
+
cs.load(cdef)
|
|
254
|
+
|
|
255
|
+
assert "t_bitfield" in cs.typedefs
|
|
256
|
+
assert "fval" in cs.t_bitfield.fields
|
|
257
|
+
assert "bit0" in cs.t_bitfield.fields["fval"].type.fields
|
|
258
|
+
assert "bit1" in cs.t_bitfield.fields["fval"].type.fields
|
|
259
|
+
assert "bit2" not in cs.t_bitfield.fields["fval"].type.fields
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_conditional_parsing_error(cs: cstruct) -> None:
|
|
263
|
+
cdef = """
|
|
264
|
+
#ifndef __HELP
|
|
265
|
+
#define __HELP
|
|
266
|
+
#endif
|
|
267
|
+
struct test {
|
|
268
|
+
uint32 a;
|
|
269
|
+
};
|
|
270
|
+
#endif
|
|
271
|
+
"""
|
|
272
|
+
with pytest.raises(ParserError, match="line 8: unexpected token .+ENDIF"):
|
|
273
|
+
cs.load(cdef)
|
|
274
|
+
|
|
275
|
+
cdef = """
|
|
276
|
+
#ifndef __HELP
|
|
277
|
+
#define __HELP
|
|
278
|
+
struct test {
|
|
279
|
+
uint32 a;
|
|
280
|
+
};
|
|
281
|
+
"""
|
|
282
|
+
with pytest.raises(ParserError, match="line 6: unclosed conditional statement"):
|
|
283
|
+
cs.load(cdef)
|
|
@@ -319,6 +319,26 @@ def test_generate_structure_stub(cs: cstruct, cdef: str, expected: str) -> None:
|
|
|
319
319
|
""",
|
|
320
320
|
id="define literals",
|
|
321
321
|
),
|
|
322
|
+
pytest.param(
|
|
323
|
+
"""
|
|
324
|
+
typedef struct _Test {
|
|
325
|
+
uint8 a;
|
|
326
|
+
} Test, *pTest;
|
|
327
|
+
""",
|
|
328
|
+
"""
|
|
329
|
+
class cstruct(cstruct):
|
|
330
|
+
class _Test(Structure):
|
|
331
|
+
a: cstruct.uint8
|
|
332
|
+
@overload
|
|
333
|
+
def __init__(self, a: cstruct.uint8 | None = ...): ...
|
|
334
|
+
@overload
|
|
335
|
+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
|
|
336
|
+
|
|
337
|
+
Test: TypeAlias = _Test
|
|
338
|
+
pTest: TypeAlias = Pointer[cstruct._Test]
|
|
339
|
+
""",
|
|
340
|
+
id="pointer alias",
|
|
341
|
+
),
|
|
322
342
|
],
|
|
323
343
|
)
|
|
324
344
|
def test_generate_cstruct_stub(cs: cstruct, cdef: str, expected: str) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_cstruct-4.6.dev5 → dissect_cstruct-4.6.dev7}/dissect.cstruct.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|