diff options
author | Robert Falkenberg <robert.falkenberg@tu-dortmund.de> | 2021-05-07 15:23:20 +0200 |
---|---|---|
committer | Robert Falkenberg <robert.falkenberg@tu-dortmund.de> | 2021-05-10 06:15:39 +0200 |
commit | b07a3e9c87fc742aab2515ce1e6f9e4d20c91cae (patch) | |
tree | a73e9b021eeeeede426702535923a6eb3a933d4c /pySim/construct.py | |
parent | c957ce8adc4ecd5084cd8f7ed86b8c4e200c22f6 (diff) |
Add codecs for EF_SPN and GSM strings via construct
This will replace the hand-crafted codec for EF_SPN
by a struct definition using the construct library.
Old encoders are updated and kept for API compatibility
but are not used internally anymore.
New data structures:
* Rpad(Adapter): Right-padded bytestring (0xff, adjustable)
* GsmStringAdapter(Adapter): Codec for "SMS default 7-bit
coded alphabet as defined int TS 23.038" using
the gsm0338 library.
* GsmString(n): Convenient wrapper of both above
Adjustments:
* utils: update+deprecate old dec_spn(), enc_spn()
* remove refs to deprecated functions
Change-Id: Ia1d3a3835933bac0002b7c52511481dd8094b994
Diffstat (limited to 'pySim/construct.py')
-rw-r--r-- | pySim/construct.py | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/pySim/construct.py b/pySim/construct.py index b0f03b7..a903305 100644 --- a/pySim/construct.py +++ b/pySim/construct.py @@ -1,5 +1,6 @@ from construct import * from pySim.utils import b2h, h2b, swap_nibbles +import gsm0338 """Utility code related to the integration of the 'construct' declarative parser.""" @@ -33,6 +34,42 @@ class BcdAdapter(Adapter): def _encode(self, obj, context, path): return h2b(swap_nibbles(obj)) +class Rpad(Adapter): + """ + Encoder appends padding bytes (b'\\xff') up to target size. + Decoder removes trailing padding bytes. + + Parameters: + subcon: Subconstruct as defined by construct library + pattern: set padding pattern (default: b'\\xff') + """ + + def __init__(self, subcon, pattern=b'\xff'): + super().__init__(subcon) + self.pattern = pattern + + def _decode(self, obj, context, path): + return obj.rstrip(self.pattern) + + def _encode(self, obj, context, path): + if len(obj) > self.sizeof(): + raise SizeofError("Input ({}) exceeds target size ({})".format(len(obj), self.sizeof())) + return obj + self.pattern * (self.sizeof() - len(obj)) + +class GsmStringAdapter(Adapter): + """Convert GSM 03.38 encoded bytes to a string.""" + + def __init__(self, subcon, codec='gsm03.38', err='strict'): + super().__init__(subcon) + self.codec = codec + self.err = err + + def _decode(self, obj, context, path): + return obj.decode(self.codec) + + def _encode(self, obj, context, path): + return obj.encode(self.codec, self.err) + def filter_dict(d, exclude_prefix='_'): """filter the input dict to ensure no keys starting with 'exclude_prefix' remain.""" res = {} @@ -88,3 +125,17 @@ def BytesRFU(n=1): n (Integer): Number of bytes (default: 1) ''' return Default(Bytes(n), __RFU_VALUE) + +def GsmString(n): + ''' + GSM 03.38 encoded byte string of fixed length n. + Encoder appends padding bytes (b'\\xff') to maintain + length. Decoder removes those trailing bytes. + + Exceptions are raised for invalid characters + and length excess. + + Parameters: + n (Integer): Fixed length of the encoded byte string + ''' + return GsmStringAdapter(Rpad(Bytes(n), pattern=b'\xff'), codec='gsm03.38') |