pycstructdataparser-lib 1.0.1__tar.gz → 1.0.3__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.
- {pycstructdataparser_lib-1.0.1/pycstructdataparser_lib.egg-info → pycstructdataparser_lib-1.0.3}/PKG-INFO +9 -5
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/README.md +8 -4
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/cstruct_parser.py +90 -13
- pycstructdataparser_lib-1.0.3/ctype_map_def.py +113 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3/pycstructdataparser_lib.egg-info}/PKG-INFO +9 -5
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/pyproject.toml +1 -1
- pycstructdataparser_lib-1.0.1/ctype_map_def.py +0 -65
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/LICENSE +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/MANIFEST.in +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/pycstructdataparser_lib.egg-info/SOURCES.txt +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/pycstructdataparser_lib.egg-info/dependency_links.txt +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/pycstructdataparser_lib.egg-info/top_level.txt +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/pycstructdataparser_lib.py +0 -0
- {pycstructdataparser_lib-1.0.1 → pycstructdataparser_lib-1.0.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycstructdataparser-lib
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: Parse C/C++ struct definitions from header text and serialize/deserialize binary data with ctypes — no compilation needed
|
|
5
5
|
Author: NGC13009
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -33,7 +33,7 @@ Dynamic: license-file
|
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
35
|
<p align="center">
|
|
36
|
-
[<a href="README_CN.md">中文说明书</a>] | English
|
|
36
|
+
[<a href="https://github.com/NGC13009/pycstructdataparser_lib/blob/main/README_CN.md">中文说明书</a>] | English
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
**Automatically parse struct definitions directly from C/C++ header text and process binary data in Python** — No compilation required, no manual `ctypes.Structure` subclass writing needed, zero boilerplate code. Seamless data transfer between C/C++ and Python with automated data unpacking/packing.
|
|
@@ -107,7 +107,7 @@ pack output: 21 bytes
|
|
|
107
107
|
- **Nested Structs**: Supports struct types used as fields within other structs
|
|
108
108
|
- **Serialization (pack)**: Converts Python dictionaries into C struct binary bytes
|
|
109
109
|
- **Deserialization (unpack)**: Parses raw bytes back into nested Python dictionaries
|
|
110
|
-
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing
|
|
110
|
+
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing, plus value‑domain checks (bitfield overflow, integer type range)
|
|
111
111
|
|
|
112
112
|
## Installation Methods
|
|
113
113
|
|
|
@@ -239,7 +239,10 @@ Serializes a Python dictionary into binary bytes corresponding to a C struct.
|
|
|
239
239
|
- `parser`: A `CStructParser` instance on which `parse()` has been called.
|
|
240
240
|
- `struct_name`: The target struct type name.
|
|
241
241
|
- `data_dict`: A dictionary mapping field names to field values.
|
|
242
|
-
- `strict`: If `True` (default)
|
|
242
|
+
- `strict`: If `True` (default):
|
|
243
|
+
- Raises `ValueError` when a **non-bitfield** field is missing.
|
|
244
|
+
- Performs **value‑domain validation** on each scalar value: bitfield values must be within `[0, 2^width - 1]`; integer types must be within their type min/max (e.g. `uint8_t` → `[0, 255]`, `int32_t` → `[-2147483648, 2147483647]`); floating‑point and struct types are not range‑checked.
|
|
245
|
+
- If `False`, missing fields are silently filled with 0 and no value‑domain checks are performed.
|
|
243
246
|
|
|
244
247
|
### `unpack(parser, struct_name, data)`
|
|
245
248
|
|
|
@@ -295,4 +298,5 @@ Deserializes raw binary bytes into a nested Python dictionary.
|
|
|
295
298
|
|
|
296
299
|
## License
|
|
297
300
|
|
|
298
|
-
This project is licensed under [GPLv3.0](
|
|
301
|
+
This project is licensed under [GPLv3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
|
302
|
+
[NGC13009/pycstructdataparser_lib.git](https://github.com/NGC13009/pycstructdataparser_lib.git)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
[<a href="README_CN.md">中文说明书</a>] | English
|
|
10
|
+
[<a href="https://github.com/NGC13009/pycstructdataparser_lib/blob/main/README_CN.md">中文说明书</a>] | English
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
13
|
**Automatically parse struct definitions directly from C/C++ header text and process binary data in Python** — No compilation required, no manual `ctypes.Structure` subclass writing needed, zero boilerplate code. Seamless data transfer between C/C++ and Python with automated data unpacking/packing.
|
|
@@ -81,7 +81,7 @@ pack output: 21 bytes
|
|
|
81
81
|
- **Nested Structs**: Supports struct types used as fields within other structs
|
|
82
82
|
- **Serialization (pack)**: Converts Python dictionaries into C struct binary bytes
|
|
83
83
|
- **Deserialization (unpack)**: Parses raw bytes back into nested Python dictionaries
|
|
84
|
-
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing
|
|
84
|
+
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing, plus value‑domain checks (bitfield overflow, integer type range)
|
|
85
85
|
|
|
86
86
|
## Installation Methods
|
|
87
87
|
|
|
@@ -213,7 +213,10 @@ Serializes a Python dictionary into binary bytes corresponding to a C struct.
|
|
|
213
213
|
- `parser`: A `CStructParser` instance on which `parse()` has been called.
|
|
214
214
|
- `struct_name`: The target struct type name.
|
|
215
215
|
- `data_dict`: A dictionary mapping field names to field values.
|
|
216
|
-
- `strict`: If `True` (default)
|
|
216
|
+
- `strict`: If `True` (default):
|
|
217
|
+
- Raises `ValueError` when a **non-bitfield** field is missing.
|
|
218
|
+
- Performs **value‑domain validation** on each scalar value: bitfield values must be within `[0, 2^width - 1]`; integer types must be within their type min/max (e.g. `uint8_t` → `[0, 255]`, `int32_t` → `[-2147483648, 2147483647]`); floating‑point and struct types are not range‑checked.
|
|
219
|
+
- If `False`, missing fields are silently filled with 0 and no value‑domain checks are performed.
|
|
217
220
|
|
|
218
221
|
### `unpack(parser, struct_name, data)`
|
|
219
222
|
|
|
@@ -269,4 +272,5 @@ Deserializes raw binary bytes into a nested Python dictionary.
|
|
|
269
272
|
|
|
270
273
|
## License
|
|
271
274
|
|
|
272
|
-
This project is licensed under [GPLv3.0](
|
|
275
|
+
This project is licensed under [GPLv3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
|
276
|
+
[NGC13009/pycstructdataparser_lib.git](https://github.com/NGC13009/pycstructdataparser_lib.git)
|
|
@@ -14,7 +14,49 @@ import re
|
|
|
14
14
|
import ctypes
|
|
15
15
|
from typing import Any, Dict, List, Optional, Tuple
|
|
16
16
|
|
|
17
|
-
from ctype_map_def import TYPE_MAP
|
|
17
|
+
from ctype_map_def import TYPE_MAP, get_value_range
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Value‑range validation (used by pack() when strict=True)
|
|
21
|
+
def _validate_value(value: Any, ctypes_type: Any, bitwidth: Optional[int] = None, field_path: str = "?") -> None:
|
|
22
|
+
"""Validate *value* against the domain of *ctypes_type*.
|
|
23
|
+
|
|
24
|
+
Rules (applied only when *strict* is True):
|
|
25
|
+
|
|
26
|
+
* **Bitfield** (``bitwidth is not None``):
|
|
27
|
+
Raises :exc:`ValueError` if *value* < 0 or *value* >= 2\\ :sup:`bitwidth`.
|
|
28
|
+
* **Integer type** (registered in ``_VALUE_RANGE_DEFS``):
|
|
29
|
+
Raises :exc:`ValueError` if *value* lies outside ``[min, max]``.
|
|
30
|
+
* **Floating‑point types / structs / pointers**:
|
|
31
|
+
No validation performed (silently passes).
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
value: The raw Python value (typically ``int``) to validate.
|
|
35
|
+
ctypes_type: The target ctypes type (e.g. ``ctypes.c_uint8``).
|
|
36
|
+
bitwidth: Bit‑width for bitfield fields; ``None`` for normal fields.
|
|
37
|
+
field_path: Human‑readable path used in error messages
|
|
38
|
+
(e.g. ``"BBBtype.eee"``).
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValueError: If the value is out of the allowed domain.
|
|
42
|
+
"""
|
|
43
|
+
# --- 1. Bitfield check ---
|
|
44
|
+
if bitwidth is not None:
|
|
45
|
+
max_val = (1 << bitwidth) - 1
|
|
46
|
+
if not isinstance(value, int) or value < 0 or value > max_val:
|
|
47
|
+
raise ValueError(f"Value {value} out of range for bitfield '{field_path}' "
|
|
48
|
+
f"(width={bitwidth}, allowed [0, {max_val}])")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# --- 2. Integer type range check ---
|
|
52
|
+
rng = get_value_range(ctypes_type)
|
|
53
|
+
if rng is None:
|
|
54
|
+
return # float / struct / pointer — skip
|
|
55
|
+
|
|
56
|
+
lo, hi = rng
|
|
57
|
+
if not isinstance(value, int) or value < lo or value > hi:
|
|
58
|
+
raise ValueError(f"Value {value} out of range for field '{field_path}' "
|
|
59
|
+
f"(type={ctypes_type.__name__}, allowed [{lo}, {hi}])")
|
|
18
60
|
|
|
19
61
|
|
|
20
62
|
# Recursive conversion helper (dict ↔ ctypes.Structure)
|
|
@@ -37,37 +79,63 @@ def _struct_to_dict(obj: Any) -> Any:
|
|
|
37
79
|
return obj
|
|
38
80
|
|
|
39
81
|
|
|
40
|
-
def _dict_to_struct(obj: ctypes.Structure, data: Dict[str, Any], strict: bool = True) -> None:
|
|
82
|
+
def _dict_to_struct(obj: ctypes.Structure, data: Dict[str, Any], strict: bool = True, parent_path: str = "") -> None:
|
|
41
83
|
"""Recursively fill a ctypes Structure from a plain Python dict.
|
|
42
84
|
|
|
43
|
-
When *strict* is True
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
When *strict* is True:
|
|
86
|
+
|
|
87
|
+
* Raises :exc:`ValueError` if *data* is missing a **non-bitfield** key.
|
|
88
|
+
Bitfield fields are always optional (default to 0).
|
|
89
|
+
* Validates each scalar value against its type domain (bitwidth for
|
|
90
|
+
bitfields, integer range for integer types).
|
|
91
|
+
|
|
92
|
+
When *strict* is False, all missing keys silently default to 0 and
|
|
93
|
+
no value‑domain checks are performed.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
obj: The ctypes Structure instance to fill.
|
|
97
|
+
data: The source dictionary.
|
|
98
|
+
strict: Enable strict validation.
|
|
99
|
+
parent_path: Accumulated field path for error messages
|
|
100
|
+
(e.g. ``"BBBtype"``, ``"BBBtype.aaalist[3]"``).
|
|
46
101
|
"""
|
|
47
|
-
# Pre-compute bitfield
|
|
48
|
-
|
|
102
|
+
# Pre-compute bitfield name→width map for validation
|
|
103
|
+
bitfield_widths: Dict[str, int] = {}
|
|
49
104
|
for f in obj._fields_:
|
|
50
105
|
if len(f) == 3: # (name, type, width)
|
|
51
|
-
|
|
106
|
+
bitfield_widths[f[0]] = f[2]
|
|
52
107
|
|
|
53
108
|
for f in obj._fields_:
|
|
54
109
|
field_name = f[0]
|
|
110
|
+
ftype = f[1] # ctypes type
|
|
55
111
|
is_bitfield = len(f) == 3
|
|
112
|
+
field_path = f"{parent_path}.{field_name}" if parent_path else field_name
|
|
56
113
|
|
|
57
114
|
if field_name in data:
|
|
58
115
|
value = data[field_name]
|
|
59
116
|
target = getattr(obj, field_name)
|
|
60
117
|
|
|
61
118
|
if isinstance(target, ctypes.Structure):
|
|
62
|
-
|
|
119
|
+
# Nested struct — recurse
|
|
120
|
+
_dict_to_struct(target, value, strict, field_path)
|
|
121
|
+
|
|
63
122
|
elif isinstance(target, ctypes.Array):
|
|
123
|
+
elem_type = target._type_
|
|
64
124
|
for i, item in enumerate(value):
|
|
65
125
|
elem = target[i]
|
|
126
|
+
elem_path = f"{field_path}[{i}]"
|
|
66
127
|
if isinstance(elem, ctypes.Structure):
|
|
67
|
-
_dict_to_struct(elem, item, strict)
|
|
128
|
+
_dict_to_struct(elem, item, strict, elem_path)
|
|
68
129
|
else:
|
|
130
|
+
# Scalar array element — validate in strict mode
|
|
131
|
+
if strict:
|
|
132
|
+
_validate_value(item, elem_type, None, elem_path)
|
|
69
133
|
target[i] = item
|
|
70
134
|
else:
|
|
135
|
+
# Plain scalar — validate in strict mode, then assign
|
|
136
|
+
if strict:
|
|
137
|
+
bw = f[2] if is_bitfield else None
|
|
138
|
+
_validate_value(value, ftype, bw, field_path)
|
|
71
139
|
setattr(obj, field_name, value)
|
|
72
140
|
|
|
73
141
|
elif strict and not is_bitfield:
|
|
@@ -324,9 +392,18 @@ def pack(parser: CStructParser, struct_name: str, data_dict: Dict[str, Any], str
|
|
|
324
392
|
parser: A :class:`CStructParser` that has had :meth:`parse` called.
|
|
325
393
|
struct_name: The struct type name to use.
|
|
326
394
|
data_dict: A dictionary whose keys correspond to struct field names.
|
|
327
|
-
strict: If ``True`` (default)
|
|
328
|
-
|
|
329
|
-
|
|
395
|
+
strict: If ``True`` (default):
|
|
396
|
+
|
|
397
|
+
* Raises :class:`ValueError` when a **non‑bitfield** key is missing.
|
|
398
|
+
* Validates each scalar value against its type domain:
|
|
399
|
+
|
|
400
|
+
* **Bitfields** — value must be in ``[0, 2\\ :sup:`width`\\ - 1]``.
|
|
401
|
+
* **Integer types** — value must be in ``[type_min, type_max]``
|
|
402
|
+
(e.g. ``uint8_t`` → ``[0, 255]``, ``int32_t`` → ``[-2147483648, 2147483647]``).
|
|
403
|
+
* **Floating‑point / struct** types are **not** range‑checked.
|
|
404
|
+
|
|
405
|
+
If ``False``, missing keys silently default to 0 and no value‑domain
|
|
406
|
+
checks are performed.
|
|
330
407
|
|
|
331
408
|
Returns:
|
|
332
409
|
Raw binary bytes.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# coding = utf-8
|
|
2
|
+
# Arch = manyArch
|
|
3
|
+
#
|
|
4
|
+
# @File name: type_map_def.py
|
|
5
|
+
# @brief: Type definition file for Python struct parser
|
|
6
|
+
# @attention: None
|
|
7
|
+
# @Author: NGC13009
|
|
8
|
+
# @History: 2026-05-07 Create
|
|
9
|
+
|
|
10
|
+
import ctypes
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
12
|
+
|
|
13
|
+
# Character types
|
|
14
|
+
_CHAR_TYPES = {
|
|
15
|
+
'char': ctypes.c_byte,
|
|
16
|
+
'signed char': ctypes.c_byte,
|
|
17
|
+
'unsigned char': ctypes.c_ubyte,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Integer types (short/int/long)
|
|
21
|
+
_INTEGER_TYPES = {
|
|
22
|
+
'short': ctypes.c_short,
|
|
23
|
+
'unsigned short': ctypes.c_ushort,
|
|
24
|
+
'short int': ctypes.c_short,
|
|
25
|
+
'unsigned short int': ctypes.c_ushort,
|
|
26
|
+
'int': ctypes.c_int,
|
|
27
|
+
'signed int': ctypes.c_int,
|
|
28
|
+
'unsigned int': ctypes.c_uint,
|
|
29
|
+
'long': ctypes.c_long,
|
|
30
|
+
'unsigned long': ctypes.c_ulong,
|
|
31
|
+
'long int': ctypes.c_long,
|
|
32
|
+
'unsigned long int': ctypes.c_ulong,
|
|
33
|
+
'long long': ctypes.c_longlong,
|
|
34
|
+
'unsigned long long': ctypes.c_ulonglong,
|
|
35
|
+
'long long int': ctypes.c_longlong,
|
|
36
|
+
'unsigned long long int': ctypes.c_ulonglong,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Floating-point types
|
|
40
|
+
_FLOAT_TYPES = {
|
|
41
|
+
'float': ctypes.c_float,
|
|
42
|
+
'double': ctypes.c_double,
|
|
43
|
+
'long double': ctypes.c_longdouble,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Fixed-width types (stdint.h)
|
|
47
|
+
_STDINT_TYPES = {
|
|
48
|
+
'int8_t': ctypes.c_int8,
|
|
49
|
+
'uint8_t': ctypes.c_uint8,
|
|
50
|
+
'int16_t': ctypes.c_int16,
|
|
51
|
+
'uint16_t': ctypes.c_uint16,
|
|
52
|
+
'int32_t': ctypes.c_int32,
|
|
53
|
+
'uint32_t': ctypes.c_uint32,
|
|
54
|
+
'int64_t': ctypes.c_int64,
|
|
55
|
+
'uint64_t': ctypes.c_uint64,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Alias mapping
|
|
59
|
+
_ALIAS_TYPES = {
|
|
60
|
+
'float32_t': ctypes.c_float,
|
|
61
|
+
'float64_t': ctypes.c_double,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Final aggregation
|
|
65
|
+
TYPE_MAP: Dict[str, Any] = {**_CHAR_TYPES, **_INTEGER_TYPES, **_FLOAT_TYPES, **_STDINT_TYPES, **_ALIAS_TYPES}
|
|
66
|
+
|
|
67
|
+
# Value‑range definitions for strict value‑domain validation
|
|
68
|
+
#
|
|
69
|
+
# Each entry is a (min, max) tuple for the corresponding ctypes type.
|
|
70
|
+
# Used by _validate_value() in cstruct_parser.py when pack(strict=True).
|
|
71
|
+
# Floating‑point types and struct types are omitted — they are not
|
|
72
|
+
# subject to integer‑range validation.
|
|
73
|
+
#
|
|
74
|
+
# Overflow definitions follow the C standard two's‑complement ranges.
|
|
75
|
+
# For unsigned types, min is always 0.
|
|
76
|
+
|
|
77
|
+
_VALUE_RANGE_DEFS: Dict[Any, Tuple[int, int]] = {
|
|
78
|
+
# Character types
|
|
79
|
+
ctypes.c_byte: (-128, 127),
|
|
80
|
+
ctypes.c_ubyte: (0, 255),
|
|
81
|
+
|
|
82
|
+
# Short types
|
|
83
|
+
ctypes.c_short: (-32768, 32767),
|
|
84
|
+
ctypes.c_ushort: (0, 65535),
|
|
85
|
+
|
|
86
|
+
# Int types
|
|
87
|
+
ctypes.c_int: (-2147483648, 2147483647),
|
|
88
|
+
ctypes.c_uint: (0, 4294967295),
|
|
89
|
+
|
|
90
|
+
# Long types (platform‑dependent; these are Win64 / LP64 values)
|
|
91
|
+
ctypes.c_long: (-9223372036854775808, 9223372036854775807),
|
|
92
|
+
ctypes.c_ulong: (0, 18446744073709551615),
|
|
93
|
+
|
|
94
|
+
# Long‑long types
|
|
95
|
+
ctypes.c_longlong: (-9223372036854775808, 9223372036854775807),
|
|
96
|
+
ctypes.c_ulonglong: (0, 18446744073709551615),
|
|
97
|
+
|
|
98
|
+
# Fixed‑width stdint types
|
|
99
|
+
ctypes.c_int8: (-128, 127),
|
|
100
|
+
ctypes.c_uint8: (0, 255),
|
|
101
|
+
ctypes.c_int16: (-32768, 32767),
|
|
102
|
+
ctypes.c_uint16: (0, 65535),
|
|
103
|
+
ctypes.c_int32: (-2147483648, 2147483647),
|
|
104
|
+
ctypes.c_uint32: (0, 4294967295),
|
|
105
|
+
ctypes.c_int64: (-9223372036854775808, 9223372036854775807),
|
|
106
|
+
ctypes.c_uint64: (0, 18446744073709551615),
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_value_range(ctypes_type: Any) -> Optional[Tuple[int, int]]:
|
|
111
|
+
"""Return the ``(min, max)`` integer range for *ctypes_type*, or ``None``
|
|
112
|
+
if the type has no range constraint (floats, structs, pointers, etc.)."""
|
|
113
|
+
return _VALUE_RANGE_DEFS.get(ctypes_type)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycstructdataparser-lib
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: Parse C/C++ struct definitions from header text and serialize/deserialize binary data with ctypes — no compilation needed
|
|
5
5
|
Author: NGC13009
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -33,7 +33,7 @@ Dynamic: license-file
|
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
35
|
<p align="center">
|
|
36
|
-
[<a href="README_CN.md">中文说明书</a>] | English
|
|
36
|
+
[<a href="https://github.com/NGC13009/pycstructdataparser_lib/blob/main/README_CN.md">中文说明书</a>] | English
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
**Automatically parse struct definitions directly from C/C++ header text and process binary data in Python** — No compilation required, no manual `ctypes.Structure` subclass writing needed, zero boilerplate code. Seamless data transfer between C/C++ and Python with automated data unpacking/packing.
|
|
@@ -107,7 +107,7 @@ pack output: 21 bytes
|
|
|
107
107
|
- **Nested Structs**: Supports struct types used as fields within other structs
|
|
108
108
|
- **Serialization (pack)**: Converts Python dictionaries into C struct binary bytes
|
|
109
109
|
- **Deserialization (unpack)**: Parses raw bytes back into nested Python dictionaries
|
|
110
|
-
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing
|
|
110
|
+
- **Strict Mode**: Optionally validates that all non-bitfield fields are present during packing, plus value‑domain checks (bitfield overflow, integer type range)
|
|
111
111
|
|
|
112
112
|
## Installation Methods
|
|
113
113
|
|
|
@@ -239,7 +239,10 @@ Serializes a Python dictionary into binary bytes corresponding to a C struct.
|
|
|
239
239
|
- `parser`: A `CStructParser` instance on which `parse()` has been called.
|
|
240
240
|
- `struct_name`: The target struct type name.
|
|
241
241
|
- `data_dict`: A dictionary mapping field names to field values.
|
|
242
|
-
- `strict`: If `True` (default)
|
|
242
|
+
- `strict`: If `True` (default):
|
|
243
|
+
- Raises `ValueError` when a **non-bitfield** field is missing.
|
|
244
|
+
- Performs **value‑domain validation** on each scalar value: bitfield values must be within `[0, 2^width - 1]`; integer types must be within their type min/max (e.g. `uint8_t` → `[0, 255]`, `int32_t` → `[-2147483648, 2147483647]`); floating‑point and struct types are not range‑checked.
|
|
245
|
+
- If `False`, missing fields are silently filled with 0 and no value‑domain checks are performed.
|
|
243
246
|
|
|
244
247
|
### `unpack(parser, struct_name, data)`
|
|
245
248
|
|
|
@@ -295,4 +298,5 @@ Deserializes raw binary bytes into a nested Python dictionary.
|
|
|
295
298
|
|
|
296
299
|
## License
|
|
297
300
|
|
|
298
|
-
This project is licensed under [GPLv3.0](
|
|
301
|
+
This project is licensed under [GPLv3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
|
302
|
+
[NGC13009/pycstructdataparser_lib.git](https://github.com/NGC13009/pycstructdataparser_lib.git)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pycstructdataparser-lib"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.3"
|
|
8
8
|
description = "Parse C/C++ struct definitions from header text and serialize/deserialize binary data with ctypes — no compilation needed"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-3.0-only"
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# coding = utf-8
|
|
2
|
-
# Arch = manyArch
|
|
3
|
-
#
|
|
4
|
-
# @File name: type_map_def.py
|
|
5
|
-
# @brief: Type definition file for Python struct parser
|
|
6
|
-
# @attention: None
|
|
7
|
-
# @Author: NGC13009
|
|
8
|
-
# @History: 2026-05-07 Create
|
|
9
|
-
|
|
10
|
-
import ctypes
|
|
11
|
-
from typing import Any, Dict, List, Optional, Tuple
|
|
12
|
-
|
|
13
|
-
# Character types
|
|
14
|
-
_CHAR_TYPES = {
|
|
15
|
-
'char': ctypes.c_byte,
|
|
16
|
-
'signed char': ctypes.c_byte,
|
|
17
|
-
'unsigned char': ctypes.c_ubyte,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
# Integer types (short/int/long)
|
|
21
|
-
_INTEGER_TYPES = {
|
|
22
|
-
'short': ctypes.c_short,
|
|
23
|
-
'unsigned short': ctypes.c_ushort,
|
|
24
|
-
'short int': ctypes.c_short,
|
|
25
|
-
'unsigned short int': ctypes.c_ushort,
|
|
26
|
-
'int': ctypes.c_int,
|
|
27
|
-
'signed int': ctypes.c_int,
|
|
28
|
-
'unsigned int': ctypes.c_uint,
|
|
29
|
-
'long': ctypes.c_long,
|
|
30
|
-
'unsigned long': ctypes.c_ulong,
|
|
31
|
-
'long int': ctypes.c_long,
|
|
32
|
-
'unsigned long int': ctypes.c_ulong,
|
|
33
|
-
'long long': ctypes.c_longlong,
|
|
34
|
-
'unsigned long long': ctypes.c_ulonglong,
|
|
35
|
-
'long long int': ctypes.c_longlong,
|
|
36
|
-
'unsigned long long int': ctypes.c_ulonglong,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# Floating-point types
|
|
40
|
-
_FLOAT_TYPES = {
|
|
41
|
-
'float': ctypes.c_float,
|
|
42
|
-
'double': ctypes.c_double,
|
|
43
|
-
'long double': ctypes.c_longdouble,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# Fixed-width types (stdint.h)
|
|
47
|
-
_STDINT_TYPES = {
|
|
48
|
-
'int8_t': ctypes.c_int8,
|
|
49
|
-
'uint8_t': ctypes.c_uint8,
|
|
50
|
-
'int16_t': ctypes.c_int16,
|
|
51
|
-
'uint16_t': ctypes.c_uint16,
|
|
52
|
-
'int32_t': ctypes.c_int32,
|
|
53
|
-
'uint32_t': ctypes.c_uint32,
|
|
54
|
-
'int64_t': ctypes.c_int64,
|
|
55
|
-
'uint64_t': ctypes.c_uint64,
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
# Alias mapping
|
|
59
|
-
_ALIAS_TYPES = {
|
|
60
|
-
'float32_t': ctypes.c_float,
|
|
61
|
-
'float64_t': ctypes.c_double,
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
# Final aggregation
|
|
65
|
-
TYPE_MAP: Dict[str, Any] = {**_CHAR_TYPES, **_INTEGER_TYPES, **_FLOAT_TYPES, **_STDINT_TYPES, **_ALIAS_TYPES}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|