Skip to content

Commit ba86f0d

Browse files
committed
feat: add more integer types
TODO: consider Python ctypes
1 parent 36723d3 commit ba86f0d

8 files changed

Lines changed: 149 additions & 150 deletions

File tree

libdestruct/c/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
# Licensed under the MIT license. See LICENSE file in the project root for details.
55
#
66

7-
from libdestruct.c.c_int import c_int
8-
from libdestruct.c.c_long import c_long
7+
from libdestruct.c.c_integer_types import c_char, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort
98
from libdestruct.c.c_str import c_str
10-
from libdestruct.c.c_uint import c_uint
11-
from libdestruct.c.c_ulong import c_ulong
129

13-
__all__ = ["c_int", "c_long", "c_str", "c_uint", "c_ulong"]
10+
__all__ = ["c_char", "c_uchar", "c_short", "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_str"]
1411

1512
import libdestruct.c.base_type_inflater # noqa: F401

libdestruct/c/base_type_inflater.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66

77
from __future__ import annotations
88

9-
from libdestruct.c.c_int import c_int
10-
from libdestruct.c.c_long import c_long
9+
from libdestruct.c.c_integer_types import c_char, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort
1110
from libdestruct.c.c_str import c_str
12-
from libdestruct.c.c_uint import c_uint
13-
from libdestruct.c.c_ulong import c_ulong
1411
from libdestruct.common.type_registry import TypeRegistry
1512

1613
registry = TypeRegistry()
1714

1815

16+
registry.register_mapping(c_char, c_char)
17+
registry.register_mapping(c_uchar, c_uchar)
18+
registry.register_mapping(c_short, c_short)
19+
registry.register_mapping(c_ushort, c_ushort)
1920
registry.register_mapping(c_int, c_int)
2021
registry.register_mapping(c_uint, c_uint)
2122
registry.register_mapping(c_long, c_long)

libdestruct/c/c_int.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

libdestruct/c/c_integer_types.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#
2+
# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct).
3+
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
4+
# Licensed under the MIT license. See LICENSE file in the project root for details.
5+
#
6+
7+
from __future__ import annotations
8+
9+
from libdestruct.common.obj import obj
10+
11+
12+
class _c_integer(obj):
13+
"""A generic C integer, to be subclassed by signed and unsigned integers."""
14+
15+
size: int
16+
"""The size of an integer in bytes."""
17+
18+
signed: bool
19+
"""Whether the integer is signed."""
20+
21+
_frozen_value: int | None = None
22+
"""The frozen value of the integer."""
23+
24+
def get(self: _c_integer) -> int:
25+
"""Return the value of the integer."""
26+
return int.from_bytes(self.memory[self.address : self.address + self.size], self.endianness, signed=self.signed)
27+
28+
def to_bytes(self: _c_integer) -> bytes:
29+
"""Return the serialized representation of the object."""
30+
if self._frozen:
31+
return self._frozen_value.to_bytes(self.size, self.endianness, signed=self.signed)
32+
33+
return self.memory[self.address : self.address + self.size]
34+
35+
def _set(self: _c_integer, value: int) -> None:
36+
"""Set the value of the integer to the given value."""
37+
self.memory[self.address : self.address + self.size] = value.to_bytes(
38+
self.size,
39+
self.endianness,
40+
signed=self.signed,
41+
)
42+
43+
def __int__(self: _c_integer) -> int:
44+
"""Return the value of the integer."""
45+
return self.get()
46+
47+
48+
class c_char(_c_integer):
49+
"""A C char."""
50+
51+
size: int = 1
52+
"""The size of a char in bytes."""
53+
54+
signed: bool = True
55+
"""Whether the char is signed."""
56+
57+
58+
class c_uchar(_c_integer):
59+
"""A C unsigned char."""
60+
61+
size: int = 1
62+
"""The size of a char in bytes."""
63+
64+
signed: bool = False
65+
"""Whether the char is signed."""
66+
67+
68+
class c_short(_c_integer):
69+
"""A C short."""
70+
71+
size: int = 2
72+
"""The size of a short in bytes."""
73+
74+
signed: bool = True
75+
"""Whether the short is signed."""
76+
77+
78+
class c_ushort(_c_integer):
79+
"""A C unsigned short."""
80+
81+
size: int = 2
82+
"""The size of a short in bytes."""
83+
84+
signed: bool = False
85+
"""Whether the short is signed."""
86+
87+
88+
class c_int(_c_integer):
89+
"""A C integer."""
90+
91+
size: int = 4
92+
"""The size of an integer in bytes."""
93+
94+
signed: bool = True
95+
"""Whether the integer is signed."""
96+
97+
98+
class c_uint(_c_integer):
99+
"""A C unsigned integer."""
100+
101+
size: int = 4
102+
"""The size of an integer in bytes."""
103+
104+
signed: bool = False
105+
"""Whether the integer is signed."""
106+
107+
108+
class c_long(_c_integer):
109+
"""A C long."""
110+
111+
size: int = 8
112+
"""The size of a long in bytes."""
113+
114+
signed: bool = True
115+
"""Whether the long is signed."""
116+
117+
118+
class c_ulong(_c_integer):
119+
"""A C unsigned long."""
120+
121+
size: int = 8
122+
"""The size of a long in bytes."""
123+
124+
signed: bool = False
125+
"""Whether the long is signed."""

libdestruct/c/c_long.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

libdestruct/c/c_uint.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

libdestruct/c/c_ulong.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

libdestruct/common/obj.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class obj(ABC):
2020
"""The address of the object in the memory view."""
2121

2222
endianness: str = "little"
23-
"""The endianness of the backing refenrece view."""
23+
"""The endianness of the backing reference view."""
2424

2525
memory: MutableSequence
2626
"""The backing memory view."""
@@ -86,6 +86,18 @@ def freeze(self: obj) -> None:
8686
self._frozen_value = self.get()
8787
self._frozen = True
8888

89+
def diff(self: obj) -> tuple[object, object]:
90+
"""Return the difference between the current value and the frozen value."""
91+
return self._frozen_value, self.get()
92+
93+
def reset(self: obj) -> None:
94+
"""Reset the object to its frozen value."""
95+
self._set(self._frozen_value)
96+
97+
def update(self: obj) -> None:
98+
"""Update the object with the given value."""
99+
self._frozen_value = self.get()
100+
89101
@property
90102
def value(self: obj) -> object:
91103
"""Return the value of the object."""
@@ -105,6 +117,10 @@ def to_str(self: obj, indent: int = 0) -> str:
105117
"""Return a string representation of the object."""
106118
return f"{' ' * indent}{self.get()}"
107119

120+
def pdiff(self: obj) -> str:
121+
"""Return a string representation of the difference between the current value and the frozen value."""
122+
return f"{self._frozen_value} -> {self.get()}"
123+
108124
def __str__(self: obj) -> str:
109125
"""Return a string representation of the object."""
110126
return self.to_str()

0 commit comments

Comments
 (0)