mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-26 07:18:33 +03:00
filesystem: Introduce 'construct' support
This allows for pure declarative encoders/decoders for linear fixed and transparent EFs. Change-Id: Id0765ec3ddb8c044838ce47d0ff8740720a32b15
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
from construct import *
|
from construct import *
|
||||||
from pySim.utils import b2h, h2b
|
from pySim.utils import b2h, h2b, swap_nibbles
|
||||||
|
|
||||||
"""Utility code related to the integration of the 'construct' declarative parser."""
|
"""Utility code related to the integration of the 'construct' declarative parser."""
|
||||||
|
|
||||||
@@ -26,6 +26,13 @@ class HexAdapter(Adapter):
|
|||||||
def _encode(self, obj, context, path):
|
def _encode(self, obj, context, path):
|
||||||
return h2b(obj)
|
return h2b(obj)
|
||||||
|
|
||||||
|
class BcdAdapter(Adapter):
|
||||||
|
"""convert a bytes() type to a string of BCD nibbles."""
|
||||||
|
def _decode(self, obj, context, path):
|
||||||
|
return swap_nibbles(b2h(obj))
|
||||||
|
def _encode(self, obj, context, path):
|
||||||
|
return h2b(swap_nibbles(obj))
|
||||||
|
|
||||||
def filter_dict(d, exclude_prefix='_'):
|
def filter_dict(d, exclude_prefix='_'):
|
||||||
"""filter the input dict to ensure no keys starting with 'exclude_prefix' remain."""
|
"""filter the input dict to ensure no keys starting with 'exclude_prefix' remain."""
|
||||||
res = {}
|
res = {}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import argparse
|
|||||||
from typing import cast, Optional, Iterable, List, Any, Dict, Tuple
|
from typing import cast, Optional, Iterable, List, Any, Dict, Tuple
|
||||||
|
|
||||||
from pySim.utils import sw_match, h2b, b2h, is_hex
|
from pySim.utils import sw_match, h2b, b2h, is_hex
|
||||||
|
from pySim.construct import filter_dict
|
||||||
from pySim.exceptions import *
|
from pySim.exceptions import *
|
||||||
from pySim.jsonpath import js_path_find, js_path_modify
|
from pySim.jsonpath import js_path_find, js_path_modify
|
||||||
|
|
||||||
@@ -466,6 +467,7 @@ class TransparentEF(CardEF):
|
|||||||
size : tuple of (minimum_size, recommended_size)
|
size : tuple of (minimum_size, recommended_size)
|
||||||
"""
|
"""
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
||||||
|
self._construct = None
|
||||||
self.size = size
|
self.size = size
|
||||||
self.shell_commands = [self.ShellCommands()]
|
self.shell_commands = [self.ShellCommands()]
|
||||||
|
|
||||||
@@ -487,6 +489,8 @@ class TransparentEF(CardEF):
|
|||||||
method = getattr(self, '_decode_hex', None)
|
method = getattr(self, '_decode_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(b2h(raw_bin_data))
|
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 {'raw': raw_bin_data.hex()}
|
return {'raw': raw_bin_data.hex()}
|
||||||
|
|
||||||
def decode_hex(self, raw_hex_data:str) -> dict:
|
def decode_hex(self, raw_hex_data:str) -> dict:
|
||||||
@@ -508,6 +512,8 @@ class TransparentEF(CardEF):
|
|||||||
method = getattr(self, '_decode_bin', None)
|
method = getattr(self, '_decode_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(raw_bin_data)
|
return method(raw_bin_data)
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data)))
|
||||||
return {'raw': raw_bin_data.hex()}
|
return {'raw': raw_bin_data.hex()}
|
||||||
|
|
||||||
def encode_bin(self, abstract_data:dict) -> bytearray:
|
def encode_bin(self, abstract_data:dict) -> bytearray:
|
||||||
@@ -528,6 +534,8 @@ class TransparentEF(CardEF):
|
|||||||
method = getattr(self, '_encode_hex', None)
|
method = getattr(self, '_encode_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data))
|
return h2b(method(abstract_data))
|
||||||
|
if self._construct:
|
||||||
|
return self._construct.build(abstract_data)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def encode_hex(self, abstract_data:dict) -> str:
|
def encode_hex(self, abstract_data:dict) -> str:
|
||||||
@@ -549,6 +557,8 @@ class TransparentEF(CardEF):
|
|||||||
if callable(method):
|
if callable(method):
|
||||||
raw_bin_data = method(abstract_data)
|
raw_bin_data = method(abstract_data)
|
||||||
return b2h(raw_bin_data)
|
return b2h(raw_bin_data)
|
||||||
|
if self._construct:
|
||||||
|
return b2h(self._construct.build(abstract_data))
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@@ -683,6 +693,7 @@ class LinFixedEF(CardEF):
|
|||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
||||||
self.rec_len = rec_len
|
self.rec_len = rec_len
|
||||||
self.shell_commands = [self.ShellCommands()]
|
self.shell_commands = [self.ShellCommands()]
|
||||||
|
self._construct = None
|
||||||
|
|
||||||
def decode_record_hex(self, raw_hex_data:str) -> dict:
|
def decode_record_hex(self, raw_hex_data:str) -> dict:
|
||||||
"""Decode raw (hex string) data into abstract representation.
|
"""Decode raw (hex string) data into abstract representation.
|
||||||
@@ -703,6 +714,8 @@ class LinFixedEF(CardEF):
|
|||||||
method = getattr(self, '_decode_record_bin', None)
|
method = getattr(self, '_decode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(raw_bin_data)
|
return method(raw_bin_data)
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data)))
|
||||||
return {'raw': raw_bin_data.hex()}
|
return {'raw': raw_bin_data.hex()}
|
||||||
|
|
||||||
def decode_record_bin(self, raw_bin_data:bytearray) -> dict:
|
def decode_record_bin(self, raw_bin_data:bytearray) -> dict:
|
||||||
@@ -724,6 +737,8 @@ class LinFixedEF(CardEF):
|
|||||||
method = getattr(self, '_decode_record_hex', None)
|
method = getattr(self, '_decode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(raw_hex_data)
|
return method(raw_hex_data)
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data)))
|
||||||
return {'raw': raw_hex_data}
|
return {'raw': raw_hex_data}
|
||||||
|
|
||||||
def encode_record_hex(self, abstract_data:dict) -> str:
|
def encode_record_hex(self, abstract_data:dict) -> str:
|
||||||
@@ -745,6 +760,8 @@ class LinFixedEF(CardEF):
|
|||||||
if callable(method):
|
if callable(method):
|
||||||
raw_bin_data = method(abstract_data)
|
raw_bin_data = method(abstract_data)
|
||||||
return b2h(raw_bin_data)
|
return b2h(raw_bin_data)
|
||||||
|
if self._construct:
|
||||||
|
return b2h(self._construct.build(abstract_data))
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def encode_record_bin(self, abstract_data:dict) -> bytearray:
|
def encode_record_bin(self, abstract_data:dict) -> bytearray:
|
||||||
@@ -765,6 +782,8 @@ class LinFixedEF(CardEF):
|
|||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data))
|
return h2b(method(abstract_data))
|
||||||
|
if self._construct:
|
||||||
|
return self._construct.build(abstract_data)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class CyclicEF(LinFixedEF):
|
class CyclicEF(LinFixedEF):
|
||||||
@@ -813,10 +832,12 @@ class TransRecEF(TransparentEF):
|
|||||||
method = getattr(self, '_decode_record_hex', None)
|
method = getattr(self, '_decode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(raw_hex_data)
|
return method(raw_hex_data)
|
||||||
|
raw_bin_data = h2b(raw_hex_data)
|
||||||
method = getattr(self, '_decode_record_bin', None)
|
method = getattr(self, '_decode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
raw_bin_data = h2b(raw_hex_data)
|
|
||||||
return method(raw_bin_data)
|
return method(raw_bin_data)
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data)))
|
||||||
return {'raw': raw_hex_data}
|
return {'raw': raw_hex_data}
|
||||||
|
|
||||||
def decode_record_bin(self, raw_bin_data:bytearray) -> dict:
|
def decode_record_bin(self, raw_bin_data:bytearray) -> dict:
|
||||||
@@ -838,6 +859,8 @@ class TransRecEF(TransparentEF):
|
|||||||
method = getattr(self, '_decode_record_hex', None)
|
method = getattr(self, '_decode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(raw_hex_data)
|
return method(raw_hex_data)
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.parse(raw_bin_data, total_len=len(raw_bin_data)))
|
||||||
return {'raw': raw_hex_data}
|
return {'raw': raw_hex_data}
|
||||||
|
|
||||||
def encode_record_hex(self, abstract_data:dict) -> str:
|
def encode_record_hex(self, abstract_data:dict) -> str:
|
||||||
@@ -858,6 +881,8 @@ class TransRecEF(TransparentEF):
|
|||||||
method = getattr(self, '_encode_record_bin', None)
|
method = getattr(self, '_encode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return b2h(method(abstract_data))
|
return b2h(method(abstract_data))
|
||||||
|
if self._construct:
|
||||||
|
return b2h(filter_dict(self._construct.build(abstract_data)))
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def encode_record_bin(self, abstract_data:dict) -> bytearray:
|
def encode_record_bin(self, abstract_data:dict) -> bytearray:
|
||||||
@@ -878,6 +903,8 @@ class TransRecEF(TransparentEF):
|
|||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data))
|
return h2b(method(abstract_data))
|
||||||
|
if self._construct:
|
||||||
|
return filter_dict(self._construct.build(abstract_data))
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _decode_bin(self, raw_bin_data:bytearray):
|
def _decode_bin(self, raw_bin_data:bytearray):
|
||||||
|
|||||||
Reference in New Issue
Block a user