Skip to content

Commit f8fb6b1

Browse files
committed
Add context manager
1 parent df8bbb9 commit f8fb6b1

2 files changed

Lines changed: 46 additions & 1 deletion

File tree

dissect/cstruct/cstruct.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
import types
99
import warnings
10+
from contextlib import contextmanager
1011
from pathlib import Path
1112
from typing import TYPE_CHECKING, Any, BinaryIO, Literal, TypeVar, cast
1213

@@ -31,7 +32,7 @@
3132
from dissect.cstruct.types.base import MetaType, normalize_endianness
3233

3334
if TYPE_CHECKING:
34-
from collections.abc import Iterable
35+
from collections.abc import Iterable, Iterator
3536
from typing import TypeAlias
3637

3738
from dissect.cstruct.types import (
@@ -222,9 +223,11 @@ def __copy__(self) -> cstruct:
222223

223224
# Update typedefs to point to the new cstruct instance
224225
for name, type in self.typedefs.items():
226+
# Skip all the default types
225227
if name in cs.typedefs:
226228
continue
227229

230+
# Update the cstruct instance for all other types
228231
if isinstance(type, MetaType):
229232
new_type = copy.copy(type)
230233
new_type.cs = cs
@@ -389,6 +392,25 @@ def copy(self) -> cstruct:
389392
"""
390393
return copy.copy(self)
391394

395+
@contextmanager
396+
def endianness(self, endian: AllowedEndianness) -> Iterator[cstruct]:
397+
"""Context manager for temporarily changing the endianness of this cstruct instance."""
398+
new = self.copy()
399+
new.endian = normalize_endianness(endian)
400+
yield new
401+
402+
@contextmanager
403+
def big_endian(self) -> Iterator[cstruct]:
404+
"""Context manager for temporarily changing the endianness to big endian."""
405+
with self.endianness(">") as cs:
406+
yield cs
407+
408+
@contextmanager
409+
def little_endian(self) -> Iterator[cstruct]:
410+
"""Context manager for temporarily changing the endianness to little endian."""
411+
with self.endianness("<") as cs:
412+
yield cs
413+
392414
def _make_type(
393415
self,
394416
name: str,

tests/test_basic.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,26 @@ def test_copy(cs: cstruct) -> None:
563563
# Verify that types in the copied cstruct reference the copied cstruct
564564
assert cs_copy.resolve("test").cs is cs_copy
565565
assert cs_copy.resolve("test2").cs is cs_copy
566+
567+
568+
def test_endianness(cs: cstruct) -> None:
569+
"""Test that the endianness context manager works correctly."""
570+
with cs.endianness(">") as big_endian_cs:
571+
assert big_endian_cs.endian == ">"
572+
assert big_endian_cs.uint32(b"\x00\x00\x00\x01") == 1
573+
574+
# Verify original cstruct is unchanged
575+
assert cs.endian == "<"
576+
assert cs.uint32(b"\x01\x00\x00\x00") == 1
577+
578+
with cs.endianness("<") as little_endian_cs:
579+
assert little_endian_cs.endian == "<"
580+
assert little_endian_cs.uint32(b"\x01\x00\x00\x00") == 1
581+
582+
with cs.big_endian() as big_endian_cs:
583+
assert big_endian_cs.endian == ">"
584+
assert big_endian_cs.uint32(b"\x00\x00\x00\x01") == 1
585+
586+
with cs.little_endian() as little_endian_cs:
587+
assert little_endian_cs.endian == "<"
588+
assert little_endian_cs.uint32(b"\x01\x00\x00\x00") == 1

0 commit comments

Comments
 (0)