aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pySim/construct.py29
-rw-r--r--pySim/filesystem.py14
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: