diff options
-rw-r--r-- | pySim/construct.py | 29 | ||||
-rw-r--r-- | pySim/filesystem.py | 14 |
2 files changed, 36 insertions, 7 deletions
diff --git a/pySim/construct.py b/pySim/construct.py index a903305..1527291 100644 --- a/pySim/construct.py +++ b/pySim/construct.py @@ -1,3 +1,4 @@ +import typing from construct import * from pySim.utils import b2h, h2b, swap_nibbles import gsm0338 @@ -82,6 +83,34 @@ def filter_dict(d, exclude_prefix='_'): res[key] = value return res +from construct.lib.containers import Container, ListContainer +from construct.core import EnumIntegerString + +def normalize_construct(c): + """Convert a construct specific type to a related base type, mostly useful + so we can serialize it.""" + # we need to include the filter_dict as we otherwise get elements like this + # in the dict: '_io': <_io.BytesIO object at 0x7fdb64e05860> which we cannot json-serialize + if isinstance(c, Container): + return {k : normalize_construct(filter_dict(v)) for (k, v) in c.items()} + if isinstance(c, dict): + return {k : normalize_construct(filter_dict(v)) for (k, v) in c.items()} + if isinstance(c, ListContainer): + return [normalize_construct(filter_dict(x)) for x in c] + if isinstance(c, list): + return [normalize_construct(filter_dict(x)) for x in c] + if isinstance(c, EnumIntegerString): + return str(c) + else: + return c + +def parse_construct(c, raw_bin_data:bytes, length:typing.Optional[int]=None, exclude_prefix:str='_'): + """Helper function to wrap around normalize_construct() and filter_dict().""" + if not length: + length = len(raw_bin_data) + parsed = c.parse(raw_bin_data, total_len=length) + return normalize_construct(parsed) + # here we collect some shared / common definitions of data types LV = Prefixed(Int8ub, HexAdapter(GreedyBytes)) diff --git a/pySim/filesystem.py b/pySim/filesystem.py index 8c45ba1..9a2f4e1 100644 --- a/pySim/filesystem.py +++ b/pySim/filesystem.py @@ -35,7 +35,7 @@ import argparse from typing import cast, Optional, Iterable, List, Any, Dict, Tuple from pySim.utils import sw_match, h2b, b2h, i2h, is_hex, auto_int, bertlv_parse_one, Hexstr -from pySim.construct import filter_dict +from pySim.construct import filter_dict, parse_construct from pySim.exceptions import * from pySim.jsonpath import js_path_find, js_path_modify @@ -490,7 +490,7 @@ class TransparentEF(CardEF): if callable(method): return method(b2h(raw_bin_data)) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_bin_data.hex()} def decode_hex(self, raw_hex_data:str) -> dict: @@ -513,7 +513,7 @@ class TransparentEF(CardEF): if callable(method): return method(raw_bin_data) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_bin_data.hex()} def encode_bin(self, abstract_data:dict) -> bytearray: @@ -712,7 +712,7 @@ class LinFixedEF(CardEF): if callable(method): return method(raw_bin_data) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_bin_data.hex()} def decode_record_bin(self, raw_bin_data:bytearray) -> dict: @@ -735,7 +735,7 @@ class LinFixedEF(CardEF): if callable(method): return method(raw_hex_data) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_hex_data} def encode_record_hex(self, abstract_data:dict) -> str: @@ -834,7 +834,7 @@ class TransRecEF(TransparentEF): if callable(method): return method(raw_bin_data) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_hex_data} def decode_record_bin(self, raw_bin_data:bytearray) -> dict: @@ -857,7 +857,7 @@ class TransRecEF(TransparentEF): if callable(method): return method(raw_hex_data) if self._construct: - return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data))) + return parse_construct(self._construct, raw_bin_data) return {'raw': raw_hex_data} def encode_record_hex(self, abstract_data:dict) -> str: |