dissect.cstruct 5.0.dev8__tar.gz → 5.0.dev10__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-5.0.dev8 → dissect_cstruct-5.0.dev10}/PKG-INFO +1 -1
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/bitbuffer.py +6 -6
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/compiler.py +28 -28
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/cstruct.py +60 -28
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/tools/stubgen.py +5 -5
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/base.py +121 -38
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/char.py +5 -5
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/enum.py +15 -15
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/int.py +4 -4
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/packed.py +26 -15
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/pointer.py +24 -24
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/structure.py +72 -51
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/void.py +1 -1
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/wchar.py +5 -5
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/util.py +12 -4
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/PKG-INFO +1 -1
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/scm_file_list.json +51 -51
- dissect_cstruct-5.0.dev10/dissect.cstruct.egg-info/scm_version.json +8 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_align.py +13 -13
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_basic.py +85 -13
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_benchmark.py +179 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_compiler.py +12 -18
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_parser.py +34 -34
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_base.py +4 -4
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_custom.py +15 -14
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_enum.py +4 -4
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_flag.py +4 -4
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_pointer.py +2 -2
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_structure.py +21 -21
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_union.py +12 -12
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tox.ini +2 -0
- dissect_cstruct-5.0.dev8/dissect.cstruct.egg-info/scm_version.json +0 -8
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/.git-blame-ignore-revs +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/.gitattributes +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/CHANGELOG.md +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/COPYRIGHT +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/LICENSE +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/MANIFEST.in +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/README.md +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/__init__.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/exception.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/expression.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/lexer.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/parser.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/tools/__init__.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/__init__.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/flag.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect/cstruct/types/leb128.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/SOURCES.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/dependency_links.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/entry_points.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/requires.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/dissect.cstruct.egg-info/top_level.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/examples/disk.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/examples/mirai.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/examples/pe.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/examples/protobuf.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/examples/secdesc.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/pyproject.toml +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/setup.cfg +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/__init__.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/_data/testdef.txt +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/_docs/Makefile +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/_docs/__init__.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/_docs/conf.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/_docs/index.rst +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/conftest.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_annotations.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_bitbuffer.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_bitfield.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_ctypes.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_expression.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_lexer.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_tools_stubgen.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_char.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_int.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_leb128.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_packed.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_void.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_types_wchar.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/test_utils.py +0 -0
- {dissect_cstruct-5.0.dev8 → dissect_cstruct-5.0.dev10}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.cstruct
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.dev10
|
|
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-Expression: Apache-2.0
|
|
@@ -19,11 +19,11 @@ class BitBuffer:
|
|
|
19
19
|
|
|
20
20
|
def read(self, field_type: type[BaseType], bits: int) -> int:
|
|
21
21
|
if self._remaining == 0 or self._type != field_type:
|
|
22
|
-
if field_type.
|
|
22
|
+
if field_type.__size__ is None:
|
|
23
23
|
raise ValueError("Reading variable-length fields is unsupported")
|
|
24
24
|
|
|
25
25
|
self._type = field_type
|
|
26
|
-
self._remaining = field_type.
|
|
26
|
+
self._remaining = field_type.__size__ * 8
|
|
27
27
|
self._buffer = field_type._read(self.stream, endian=self.endian)
|
|
28
28
|
|
|
29
29
|
if isinstance(self._buffer, bytes):
|
|
@@ -51,17 +51,17 @@ class BitBuffer:
|
|
|
51
51
|
if self._type:
|
|
52
52
|
self.flush()
|
|
53
53
|
|
|
54
|
-
if field_type.
|
|
54
|
+
if field_type.__size__ is None:
|
|
55
55
|
raise ValueError("Writing variable-length fields is unsupported")
|
|
56
56
|
|
|
57
|
-
self._remaining = field_type.
|
|
57
|
+
self._remaining = field_type.__size__ * 8
|
|
58
58
|
self._type = field_type
|
|
59
59
|
|
|
60
|
-
if self._type is None or self._type.
|
|
60
|
+
if self._type is None or self._type.__size__ is None:
|
|
61
61
|
raise ValueError("Invalid state")
|
|
62
62
|
|
|
63
63
|
if self.endian == "<":
|
|
64
|
-
self._buffer |= data << (self._type.
|
|
64
|
+
self._buffer |= data << (self._type.__size__ * 8 - self._remaining)
|
|
65
65
|
else:
|
|
66
66
|
self._buffer |= data << (self._remaining - bits)
|
|
67
67
|
|
|
@@ -58,7 +58,7 @@ python_compile = compile
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
def compile(structure: type[Structure]) -> type[Structure]:
|
|
61
|
-
return Compiler(structure.
|
|
61
|
+
return Compiler(structure.__cs__).compile(structure)
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
class Compiler:
|
|
@@ -163,7 +163,7 @@ class _ReadSourceGenerator:
|
|
|
163
163
|
field_type = field.type
|
|
164
164
|
|
|
165
165
|
if isinstance(field_type, EnumMetaType):
|
|
166
|
-
field_type = field_type.
|
|
166
|
+
field_type = field_type.__type__
|
|
167
167
|
|
|
168
168
|
if not issubclass(field_type, SUPPORTED_TYPES):
|
|
169
169
|
raise TypeError(f"Unsupported type for compiler: {field_type}")
|
|
@@ -188,7 +188,7 @@ class _ReadSourceGenerator:
|
|
|
188
188
|
|
|
189
189
|
# Array of structures and multi-dimensional arrays
|
|
190
190
|
elif issubclass(field_type, (Array, CharArray, WcharArray)) and (
|
|
191
|
-
issubclass(field_type.
|
|
191
|
+
issubclass(field_type.__type__, Structure) or issubclass(field_type.__type__, BaseArray) or is_dynamic
|
|
192
192
|
):
|
|
193
193
|
yield from flush()
|
|
194
194
|
yield from align_to_field(field)
|
|
@@ -222,22 +222,22 @@ class _ReadSourceGenerator:
|
|
|
222
222
|
yield from flush()
|
|
223
223
|
|
|
224
224
|
if self.align:
|
|
225
|
-
yield f"stream.seek(-stream.tell() & (cls.
|
|
225
|
+
yield f"stream.seek(-stream.tell() & (cls.__alignment__ - 1), {io.SEEK_CUR})"
|
|
226
226
|
|
|
227
227
|
def _generate_structure(self, field: Field) -> Iterator[str]:
|
|
228
228
|
template = f"""
|
|
229
|
-
{"_s = stream.tell()" if field.type.
|
|
229
|
+
{"_s = stream.tell()" if field.type.__dynamic__ else ""}
|
|
230
230
|
r["{field._name}"] = {self._map_field(field)}._read(stream, context=r, endian=endian)
|
|
231
|
-
{f's["{field._name}"] = stream.tell() - _s' if field.type.
|
|
231
|
+
{f's["{field._name}"] = stream.tell() - _s' if field.type.__dynamic__ else ""}
|
|
232
232
|
"""
|
|
233
233
|
|
|
234
234
|
yield dedent(template)
|
|
235
235
|
|
|
236
236
|
def _generate_array(self, field: Field) -> Iterator[str]:
|
|
237
237
|
template = f"""
|
|
238
|
-
{"_s = stream.tell()" if field.type.
|
|
238
|
+
{"_s = stream.tell()" if field.type.__dynamic__ else ""}
|
|
239
239
|
r["{field._name}"] = {self._map_field(field)}._read(stream, context=r, endian=endian)
|
|
240
|
-
{f's["{field._name}"] = stream.tell() - _s' if field.type.
|
|
240
|
+
{f's["{field._name}"] = stream.tell() - _s' if field.type.__dynamic__ else ""}
|
|
241
241
|
"""
|
|
242
242
|
|
|
243
243
|
yield dedent(template)
|
|
@@ -247,12 +247,12 @@ class _ReadSourceGenerator:
|
|
|
247
247
|
read_type = "_t"
|
|
248
248
|
field_type = field.type
|
|
249
249
|
if issubclass(field_type, (Enum, Flag)):
|
|
250
|
-
read_type += ".
|
|
251
|
-
field_type = field_type.
|
|
250
|
+
read_type += ".__type__"
|
|
251
|
+
field_type = field_type.__type__
|
|
252
252
|
|
|
253
253
|
if issubclass(field_type, Char):
|
|
254
|
-
field_type = field_type.
|
|
255
|
-
lookup = "cls.
|
|
254
|
+
field_type = field_type.__cs__.uint8
|
|
255
|
+
lookup = "cls.__cs__.uint8"
|
|
256
256
|
|
|
257
257
|
template = f"""
|
|
258
258
|
_t = {lookup}
|
|
@@ -277,17 +277,17 @@ class _ReadSourceGenerator:
|
|
|
277
277
|
read_type = _get_read_type(self.cs, field_type)
|
|
278
278
|
|
|
279
279
|
if issubclass(field_type, (Array, CharArray, WcharArray)):
|
|
280
|
-
count = field_type.
|
|
281
|
-
read_type = _get_read_type(self.cs, field_type.
|
|
280
|
+
count = field_type.__num_entries__
|
|
281
|
+
read_type = _get_read_type(self.cs, field_type.__type__)
|
|
282
282
|
|
|
283
283
|
if issubclass(read_type, (Char, Wchar, Int)):
|
|
284
|
-
count *= read_type.
|
|
284
|
+
count *= read_type.__size__
|
|
285
285
|
getter = f"buf[{size}:{size + count}]"
|
|
286
286
|
else:
|
|
287
287
|
getter = f"data[{slice_index}:{slice_index + count}]"
|
|
288
288
|
slice_index += count
|
|
289
289
|
elif issubclass(read_type, (Char, Wchar, Int)):
|
|
290
|
-
getter = f"buf[{size}:{size + read_type.
|
|
290
|
+
getter = f"buf[{size}:{size + read_type.__size__}]"
|
|
291
291
|
else:
|
|
292
292
|
getter = f"data[{slice_index}]"
|
|
293
293
|
slice_index += 1
|
|
@@ -302,13 +302,13 @@ class _ReadSourceGenerator:
|
|
|
302
302
|
# Create the final reading code
|
|
303
303
|
if issubclass(field_type, Array):
|
|
304
304
|
reads.append(f"_t = {self._map_field(field)}")
|
|
305
|
-
reads.append("_et = _t.
|
|
305
|
+
reads.append("_et = _t.__type__")
|
|
306
306
|
|
|
307
|
-
if issubclass(field_type.
|
|
307
|
+
if issubclass(field_type.__type__, Int):
|
|
308
308
|
reads.append(f"_b = {getter}")
|
|
309
|
-
item_parser = parser_template.format(type="_et", getter=f"_b[i:i + {field_type.
|
|
310
|
-
list_comp = f"[{item_parser} for i in range(0, {count}, {field_type.
|
|
311
|
-
elif issubclass(field_type.
|
|
309
|
+
item_parser = parser_template.format(type="_et", getter=f"_b[i:i + {field_type.__type__.__size__}]")
|
|
310
|
+
list_comp = f"[{item_parser} for i in range(0, {count}, {field_type.__type__.__size__})]"
|
|
311
|
+
elif issubclass(field_type.__type__, Pointer):
|
|
312
312
|
item_parser = "_et.__new__(_et, e, stream, context=r, endian=endian)"
|
|
313
313
|
list_comp = f"[{item_parser} for e in {getter}]"
|
|
314
314
|
else:
|
|
@@ -327,7 +327,7 @@ class _ReadSourceGenerator:
|
|
|
327
327
|
reads.append(f'r["{field._name}"] = {parser}')
|
|
328
328
|
reads.append("") # Generates a newline in the resulting code
|
|
329
329
|
|
|
330
|
-
size += field_type.
|
|
330
|
+
size += field_type.__size__
|
|
331
331
|
|
|
332
332
|
fmt = _optimize_struct_fmt(info)
|
|
333
333
|
if fmt == "x" or (len(fmt) == 2 and fmt[1] == "x"):
|
|
@@ -370,19 +370,19 @@ def _generate_struct_info(cs: cstruct, fields: list[Field], align: bool = False)
|
|
|
370
370
|
|
|
371
371
|
# Array of more complex types are handled elsewhere
|
|
372
372
|
if issubclass(read_type, (Array, CharArray, WcharArray)):
|
|
373
|
-
count = read_type.
|
|
374
|
-
read_type = _get_read_type(cs, read_type.
|
|
373
|
+
count = read_type.__num_entries__
|
|
374
|
+
read_type = _get_read_type(cs, read_type.__type__)
|
|
375
375
|
|
|
376
376
|
# Take the pack char for Packed
|
|
377
377
|
if issubclass(read_type, Packed):
|
|
378
|
-
yield field, count, read_type.
|
|
378
|
+
yield field, count, read_type.__fmt__
|
|
379
379
|
|
|
380
380
|
# Other types are byte based
|
|
381
381
|
# We don't actually unpack anything here but slice directly out of the buffer
|
|
382
382
|
elif issubclass(read_type, (Char, Wchar, Int)):
|
|
383
|
-
yield field, count * read_type.
|
|
383
|
+
yield field, count * read_type.__size__, "x"
|
|
384
384
|
|
|
385
|
-
size = count * read_type.
|
|
385
|
+
size = count * read_type.__size__
|
|
386
386
|
imaginary_offset += size
|
|
387
387
|
if current_offset is not None:
|
|
388
388
|
current_offset += size
|
|
@@ -416,7 +416,7 @@ def _optimize_struct_fmt(info: Iterator[tuple[Field, int, str]]) -> str:
|
|
|
416
416
|
|
|
417
417
|
def _get_read_type(cs: cstruct, type_: type[BaseType]) -> type[BaseType]:
|
|
418
418
|
if issubclass(type_, (Enum, Flag)):
|
|
419
|
-
type_ = type_.
|
|
419
|
+
type_ = type_.__type__
|
|
420
420
|
|
|
421
421
|
if issubclass(type_, Pointer):
|
|
422
422
|
type_ = cs.pointer
|
|
@@ -206,7 +206,28 @@ class cstruct:
|
|
|
206
206
|
if load:
|
|
207
207
|
self.load(load)
|
|
208
208
|
|
|
209
|
-
def __getattr__(
|
|
209
|
+
def __getattr__(
|
|
210
|
+
self, attr: str
|
|
211
|
+
) -> (
|
|
212
|
+
type[
|
|
213
|
+
LEB128
|
|
214
|
+
| BaseType
|
|
215
|
+
| Char
|
|
216
|
+
| Enum
|
|
217
|
+
| Flag
|
|
218
|
+
| Int
|
|
219
|
+
| Packed[int]
|
|
220
|
+
| Packed[float]
|
|
221
|
+
| Pointer
|
|
222
|
+
| Structure
|
|
223
|
+
| Union
|
|
224
|
+
| Void
|
|
225
|
+
| Wchar
|
|
226
|
+
]
|
|
227
|
+
| int
|
|
228
|
+
| str
|
|
229
|
+
| bytes
|
|
230
|
+
):
|
|
210
231
|
try:
|
|
211
232
|
return self.consts[attr]
|
|
212
233
|
except KeyError:
|
|
@@ -227,7 +248,7 @@ class cstruct:
|
|
|
227
248
|
# Update types to point to the new cstruct instance
|
|
228
249
|
for name, type_ in self.types.items():
|
|
229
250
|
new_type = copy.copy(type_)
|
|
230
|
-
new_type.
|
|
251
|
+
new_type.__cs__ = cs
|
|
231
252
|
cs.add_type(name, new_type, replace=True)
|
|
232
253
|
|
|
233
254
|
for name, value in self.consts.items():
|
|
@@ -288,8 +309,10 @@ class cstruct:
|
|
|
288
309
|
"""
|
|
289
310
|
# In cstruct 5.0 we changed the function signature of _read and _write
|
|
290
311
|
# Check if the function signature is compatible, and warn if not
|
|
291
|
-
for type_to_check in (type_, type_.
|
|
292
|
-
type_name = type_.__name__ + (
|
|
312
|
+
for type_to_check in (type_, type_.__ArrayType__):
|
|
313
|
+
type_name = type_.__name__ + (
|
|
314
|
+
f".{type_.__ArrayType__.__name__}" if type_to_check is type_.__ArrayType__ else ""
|
|
315
|
+
)
|
|
293
316
|
|
|
294
317
|
for method in ("_read", "_read_array", "_read_0", "_write", "_write_array", "_write_0"):
|
|
295
318
|
if not hasattr(type_to_check, method):
|
|
@@ -481,10 +504,10 @@ class cstruct:
|
|
|
481
504
|
attrs = attrs or {}
|
|
482
505
|
attrs.update(
|
|
483
506
|
{
|
|
484
|
-
"
|
|
485
|
-
"
|
|
486
|
-
"
|
|
487
|
-
"
|
|
507
|
+
"__cs__": self,
|
|
508
|
+
"__size__": size,
|
|
509
|
+
"__dynamic__": size is None,
|
|
510
|
+
"__alignment__": alignment or size,
|
|
488
511
|
}
|
|
489
512
|
)
|
|
490
513
|
return types.new_class(name, bases, {}, lambda ns: ns.update(attrs))
|
|
@@ -494,37 +517,37 @@ class cstruct:
|
|
|
494
517
|
if num_entries is None:
|
|
495
518
|
null_terminated = True
|
|
496
519
|
size = None
|
|
497
|
-
elif isinstance(num_entries, Expression) or type_.
|
|
520
|
+
elif isinstance(num_entries, Expression) or type_.__dynamic__:
|
|
498
521
|
size = None
|
|
499
522
|
else:
|
|
500
|
-
if type_.
|
|
523
|
+
if type_.__size__ is None:
|
|
501
524
|
raise ValueError(f"Cannot create array of dynamic type: {type_.__name__}")
|
|
502
|
-
size = num_entries * type_.
|
|
525
|
+
size = num_entries * type_.__size__
|
|
503
526
|
|
|
504
527
|
name = f"{type_.__name__}[]" if null_terminated else f"{type_.__name__}[{num_entries}]"
|
|
505
528
|
|
|
506
|
-
bases = (type_.
|
|
529
|
+
bases = (type_.__ArrayType__,)
|
|
507
530
|
|
|
508
531
|
attrs = {
|
|
509
|
-
"
|
|
510
|
-
"
|
|
511
|
-
"
|
|
532
|
+
"__type__": type_,
|
|
533
|
+
"__num_entries__": num_entries,
|
|
534
|
+
"__null_terminated__": null_terminated,
|
|
512
535
|
}
|
|
513
536
|
|
|
514
|
-
return cast("type[Array]", self._make_type(name, bases, size, alignment=type_.
|
|
537
|
+
return cast("type[Array]", self._make_type(name, bases, size, alignment=type_.__alignment__, attrs=attrs))
|
|
515
538
|
|
|
516
539
|
def _make_int_type(self, name: str, size: int, signed: bool, *, alignment: int | None = None) -> type[Int]:
|
|
517
540
|
return cast("type[Int]", self._make_type(name, (Int,), size, alignment=alignment, attrs={"signed": signed}))
|
|
518
541
|
|
|
519
|
-
def _make_packed_type(self, name: str,
|
|
542
|
+
def _make_packed_type(self, name: str, fmt: str, base: type, *, alignment: int | None = None) -> type[Packed]:
|
|
520
543
|
return cast(
|
|
521
544
|
"type[Packed]",
|
|
522
545
|
self._make_type(
|
|
523
546
|
name,
|
|
524
547
|
(base, Packed),
|
|
525
|
-
struct.calcsize(
|
|
548
|
+
struct.calcsize(fmt),
|
|
526
549
|
alignment=alignment,
|
|
527
|
-
attrs={"
|
|
550
|
+
attrs={"__fmt__": fmt},
|
|
528
551
|
),
|
|
529
552
|
)
|
|
530
553
|
|
|
@@ -538,9 +561,9 @@ class cstruct:
|
|
|
538
561
|
return self._make_type(
|
|
539
562
|
f"{target.__name__}*",
|
|
540
563
|
(Pointer,),
|
|
541
|
-
self.pointer.
|
|
542
|
-
alignment=self.pointer.
|
|
543
|
-
attrs={"
|
|
564
|
+
self.pointer.__size__,
|
|
565
|
+
alignment=self.pointer.__alignment__,
|
|
566
|
+
attrs={"__type__": target},
|
|
544
567
|
)
|
|
545
568
|
|
|
546
569
|
def _make_struct(
|
|
@@ -557,7 +580,7 @@ class cstruct:
|
|
|
557
580
|
(base,),
|
|
558
581
|
None,
|
|
559
582
|
attrs={
|
|
560
|
-
"
|
|
583
|
+
"__members__": fields,
|
|
561
584
|
"__align__": align,
|
|
562
585
|
"__anonymous__": anonymous,
|
|
563
586
|
},
|
|
@@ -568,6 +591,15 @@ class cstruct:
|
|
|
568
591
|
) -> type[Structure]:
|
|
569
592
|
return self._make_struct(name, fields, align=align, anonymous=anonymous, base=Union)
|
|
570
593
|
|
|
594
|
+
@property
|
|
595
|
+
def typedefs(self) -> dict[str, type[BaseType]]:
|
|
596
|
+
warnings.warn(
|
|
597
|
+
"The 'typedefs' property is deprecated, use 'types' instead.",
|
|
598
|
+
DeprecationWarning,
|
|
599
|
+
stacklevel=2,
|
|
600
|
+
)
|
|
601
|
+
return self.types
|
|
602
|
+
|
|
571
603
|
if TYPE_CHECKING:
|
|
572
604
|
# ruff: noqa: PYI042
|
|
573
605
|
_int = int
|
|
@@ -749,8 +781,8 @@ def ctypes_type(type_: type[BaseType]) -> Any:
|
|
|
749
781
|
"d": _ctypes.c_double,
|
|
750
782
|
}
|
|
751
783
|
|
|
752
|
-
if issubclass(type_, Packed) and type_.
|
|
753
|
-
return mapping[type_.
|
|
784
|
+
if issubclass(type_, Packed) and type_.__fmt__ in mapping:
|
|
785
|
+
return mapping[type_.__fmt__]
|
|
754
786
|
|
|
755
787
|
if issubclass(type_, Char):
|
|
756
788
|
return _ctypes.c_char
|
|
@@ -759,11 +791,11 @@ def ctypes_type(type_: type[BaseType]) -> Any:
|
|
|
759
791
|
return _ctypes.c_wchar
|
|
760
792
|
|
|
761
793
|
if issubclass(type_, BaseArray):
|
|
762
|
-
subtype = ctypes_type(type_.
|
|
763
|
-
return subtype * type_.
|
|
794
|
+
subtype = ctypes_type(type_.__type__)
|
|
795
|
+
return subtype * type_.__num_entries__
|
|
764
796
|
|
|
765
797
|
if issubclass(type_, Pointer):
|
|
766
|
-
subtype = ctypes_type(type_.
|
|
798
|
+
subtype = ctypes_type(type_.__type__)
|
|
767
799
|
return _ctypes.POINTER(subtype)
|
|
768
800
|
|
|
769
801
|
if issubclass(type_, Structure):
|
|
@@ -121,9 +121,9 @@ def generate_typehint(
|
|
|
121
121
|
if issubclass(type_, types.WcharArray):
|
|
122
122
|
return f"{module_prefix}WcharArray"
|
|
123
123
|
if issubclass(type_, types.Pointer):
|
|
124
|
-
return f"{module_prefix}Pointer[{generate_typehint(type_.
|
|
124
|
+
return f"{module_prefix}Pointer[{generate_typehint(type_.__type__, prefix, module_prefix)}]"
|
|
125
125
|
if issubclass(type_, types.Array):
|
|
126
|
-
return f"{module_prefix}Array[{generate_typehint(type_.
|
|
126
|
+
return f"{module_prefix}Array[{generate_typehint(type_.__type__, prefix, module_prefix)}]"
|
|
127
127
|
return f"{prefix}{type_.__name__}"
|
|
128
128
|
|
|
129
129
|
|
|
@@ -159,15 +159,15 @@ def generate_structure_stub(
|
|
|
159
159
|
indent = " " * 4
|
|
160
160
|
|
|
161
161
|
args = ["self"]
|
|
162
|
-
for field_name, field in structure.
|
|
162
|
+
for field_name, field in structure.__members__.items():
|
|
163
163
|
inlined = False
|
|
164
164
|
|
|
165
165
|
# If it's a structure and not globally defined, add an inline stub for it
|
|
166
166
|
nested_type = field.type
|
|
167
167
|
while issubclass(nested_type, types.BaseArray):
|
|
168
|
-
nested_type = nested_type.
|
|
168
|
+
nested_type = nested_type.__type__
|
|
169
169
|
|
|
170
|
-
if issubclass(nested_type, types.Structure) and nested_type.__name__ not in structure.
|
|
170
|
+
if issubclass(nested_type, types.Structure) and nested_type.__name__ not in structure.__cs__.types:
|
|
171
171
|
inlined = True
|
|
172
172
|
inline_stub = generate_structure_stub(nested_type, cs_prefix=cs_prefix, module_prefix=module_prefix)
|
|
173
173
|
|