Skip to content

Commit c58b76f

Browse files
committed
Merge branch 'main' into rewrite-parser
2 parents c75df78 + 91f2347 commit c58b76f

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

.github/workflows/dissect-ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ jobs:
1515
with:
1616
run-benchmarks: true
1717

18-
1918
publish:
2019
if: ${{ github.ref_type == 'tag' }}
2120
needs: [ci]

dissect/cstruct/cstruct.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import copy
34
import ctypes as _ctypes
45
import struct
56
import sys
@@ -25,6 +26,7 @@
2526
Void,
2627
Wchar,
2728
)
29+
from dissect.cstruct.types.base import MetaType
2830

2931
if TYPE_CHECKING:
3032
from collections.abc import Iterable
@@ -205,6 +207,24 @@ def __getattr__(self, attr: str) -> Any:
205207

206208
raise AttributeError(f"Invalid attribute: {attr}")
207209

210+
def __copy__(self) -> cstruct:
211+
cs = cstruct(endian=self.endian, pointer=self.pointer.__name__)
212+
cs._anonymous_count = self._anonymous_count
213+
cs.consts = self.consts.copy()
214+
cs.includes = self.includes.copy()
215+
216+
# Update typedefs to point to the new cstruct instance
217+
for name, type in self.typedefs.items():
218+
if name in cs.typedefs:
219+
continue
220+
221+
if isinstance(type, MetaType):
222+
new_type = copy.copy(type)
223+
new_type.cs = cs
224+
cs.typedefs[name] = new_type
225+
226+
return cs
227+
208228
def _next_anonymous(self) -> str:
209229
name = f"__anonymous_{self._anonymous_count}__"
210230
self._anonymous_count += 1
@@ -323,6 +343,14 @@ def resolve(self, name: type[BaseType] | str) -> type[BaseType]:
323343

324344
raise ResolveError(f"Recursion limit exceeded while resolving type {name}")
325345

346+
def copy(self) -> cstruct:
347+
"""Create a copy of this cstruct instance.
348+
349+
Returns:
350+
A new cstruct instance with the same types and settings as this one.
351+
"""
352+
return copy.copy(self)
353+
326354
def _make_type(
327355
self,
328356
name: str,

tests/test_basic.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,3 +522,32 @@ def test_linked_list(cs: cstruct) -> None:
522522

523523
assert obj.data == 1
524524
assert obj.next.data == 2
525+
526+
527+
def test_copy(cs: cstruct) -> None:
528+
"""Test that copying a cstruct instance works as expected."""
529+
cdef = """
530+
struct test {
531+
uint32 a;
532+
};
533+
"""
534+
cs.load(cdef)
535+
536+
cs_copy = cs.copy()
537+
538+
# Modify the copy and verify the original is unchanged
539+
cs_copy.load("""
540+
struct test2 {
541+
uint16 b;
542+
};
543+
""")
544+
545+
assert "test" in cs.typedefs
546+
assert "test2" not in cs.typedefs
547+
548+
assert "test" in cs_copy.typedefs
549+
assert "test2" in cs_copy.typedefs
550+
551+
# Verify that types in the copied cstruct reference the copied cstruct
552+
assert cs_copy.resolve("test").cs is cs_copy
553+
assert cs_copy.resolve("test2").cs is cs_copy

0 commit comments

Comments
 (0)