Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions dissect/cstruct/cstruct.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import copy
import ctypes as _ctypes
import struct
import sys
Expand Down Expand Up @@ -27,6 +28,7 @@
Void,
Wchar,
)
from dissect.cstruct.types.base import MetaType

if TYPE_CHECKING:
from collections.abc import Iterable
Expand Down Expand Up @@ -325,6 +327,30 @@ def resolve(self, name: type[BaseType] | str) -> type[BaseType]:

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

def copy(self) -> cstruct:
"""Create a copy of this cstruct instance.

Returns:
A new cstruct instance with the same types and settings as this one.
"""
cs = cstruct(endian=self.endian, pointer=self.pointer.__name__)
cs._anonymous_count = self._anonymous_count
cs.consts = self.consts.copy()
cs.lookups = self.lookups.copy()
cs.includes = self.includes.copy()

# Update typedefs to point to the new cstruct instance
for name, type in self.typedefs.items():
if name in cs.typedefs:
continue

if isinstance(type, MetaType):
new_type = copy.copy(type)
new_type.cs = cs
cs.typedefs[name] = new_type

return cs

def _make_type(
self,
name: str,
Expand Down
29 changes: 29 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,32 @@ def test_linked_list(cs: cstruct) -> None:

assert obj.data == 1
assert obj.next.data == 2


def test_copy(cs: cstruct) -> None:
"""Test that copying a cstruct instance works as expected."""
cdef = """
struct test {
uint32 a;
};
"""
cs.load(cdef)

cs_copy = cs.copy()

# Modify the copy and verify the original is unchanged
cs_copy.load("""
struct test2 {
uint16 b;
};
""")

assert "test" in cs.typedefs
assert "test2" not in cs.typedefs

assert "test" in cs_copy.typedefs
assert "test2" in cs_copy.typedefs

# Verify that types in the copied cstruct reference the copied cstruct
assert cs_copy.resolve("test").cs is cs_copy
assert cs_copy.resolve("test2").cs is cs_copy