From af92e255033e4c0fc1ba7130be3d76c8090da23f Mon Sep 17 00:00:00 2001 From: idem-s1n <99683413+idem-s1n@users.noreply.github.com> Date: Mon, 4 Sep 2023 19:20:02 +0200 Subject: [PATCH] Add method to serialise records to a dict (#24) Co-authored-by: Erik Schamper <1254028+Schamper@users.noreply.github.com> --- dissect/esedb/record.py | 30 +++++++++++++++++++++++++++++- tests/test_record.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/test_record.py diff --git a/dissect/esedb/record.py b/dissect/esedb/record.py index 408f427..0cbe4c2 100644 --- a/dissect/esedb/record.py +++ b/dissect/esedb/record.py @@ -4,7 +4,7 @@ import struct from binascii import hexlify from functools import lru_cache -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any, Iterator, Optional from dissect.util.xmemoryview import xmemoryview @@ -50,6 +50,9 @@ def get(self, attr: str, raw: bool = False) -> RecordValue: column = self._table.column(attr) return self._data.get(column, raw) + def as_dict(self, raw: bool = False) -> dict[str, RecordValue]: + return self._data.as_dict(raw) + def __getitem__(self, attr: str) -> RecordValue: return self.get(attr) @@ -183,6 +186,31 @@ def get(self, column: Column, raw: bool = False) -> RecordValue: if value is not None: return self._parse_value(column, value, tag_field) + def as_dict(self, raw: bool = False) -> dict[str, RecordValue]: + """Serialize the record as a dictionary.""" + obj = {} + + def _iter_column_id() -> Iterator[Column]: + # Fixed + yield from range(1, self._last_fixed_id + 1) + + # Variable + yield from range(128, self._last_variable_id + 1) + + # Tagged + for idx in range(self._tagged_data_count): + yield self._get_tag_field(idx).identifier + + for column_id in _iter_column_id(): + column = self.table._column_id_map[column_id] + + try: + obj[column.name] = self.get(column, raw) + except Exception as e: + obj[column.name] = f"!ERROR! {e}" + + return obj + def _parse_value(self, column: Column, value: bytes, tag_field: TagField = None) -> RecordValue: """Parse the raw value into the appropriate type. diff --git a/tests/test_record.py b/tests/test_record.py new file mode 100644 index 0000000..afea747 --- /dev/null +++ b/tests/test_record.py @@ -0,0 +1,40 @@ +from typing import BinaryIO + +from dissect.esedb.esedb import EseDB + + +def test_as_dict(basic_db: BinaryIO): + db = EseDB(basic_db) + table = db.table("basic") + + records = list(table.records()) + assert len(records) == 2 + + assert [r.as_dict() for r in records] == [ + { + "Id": 1, + "Bit": False, + "UnsignedByte": 213, + "Short": -1337, + "Long": -13371337, + "Currency": 1337133713371337, + "IEEESingle": 1.0, + "IEEEDouble": 13371337.13371337, + "DateTime": 4675210852477960192, + "UnsignedLong": 13371337, + "LongLong": -13371337, + "GUID": "3f360af1-6766-46dc-9af2-0dacf295c2a1", + "UnsignedShort": 1337, + }, + { + "Id": 2, + "Bit": True, + "UnsignedByte": 255, + "Short": 1339, + "Long": 13391339, + "Currency": -1339133913391339, + "IEEESingle": -2.0, + "IEEEDouble": -13391339.13391339, + "DateTime": -4537072128574357504, + }, + ]