dexter has uploaded this change for review. (
https://gerrit.osmocom.org/c/python/pyosmocom/+/39193?usp=email )
Change subject: construct: allow stripping of leading zeros with StripTrailerAdapter
......................................................................
construct: allow stripping of leading zeros with StripTrailerAdapter
The class StripTrailerAdapter is currently only able to strip zeros at the end
of an integer. What it can not do is stripping leading zeros. Let's add a
parameter for that and extend the unittests accordingly.
Related: OS#6679
Change-Id: I1a9fff17abbbef0c5f6d45f58198debfa12e78b6
---
M src/osmocom/construct.py
M tests/test_construct.py
2 files changed, 59 insertions(+), 6 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/python/pyosmocom refs/changes/93/39193/1
diff --git a/src/osmocom/construct.py b/src/osmocom/construct.py
index 1f5bd45..dd92165 100644
--- a/src/osmocom/construct.py
+++ b/src/osmocom/construct.py
@@ -420,19 +420,23 @@
where you have a bit-mask that may have 1, 2 or 3 bytes, depending on whether or not
any
of the LSBs are actually set.
"""
- def __init__(self, subcon, total_length:int, default_value=b'\x00',
min_len=1, steps:[int]=[]):
+ def __init__(self, subcon, total_length:int, default_value=b'\x00',
min_len=1, steps:[int]=[], reverse:bool = False):
super().__init__(subcon)
assert len(default_value) == 1
self.total_length = total_length
self.default_value = default_value
self.min_len = min_len
self.steps = steps
+ self.reverse = reverse
def _decode(self, obj, context, path):
assert isinstance(obj, bytes)
# pad with suppressed/missing bytes
if len(obj) < self.total_length:
- obj += self.default_value * (self.total_length - len(obj))
+ if self.reverse:
+ obj = self.default_value * (self.total_length - len(obj)) + obj
+ else:
+ obj += self.default_value * (self.total_length - len(obj))
return int.from_bytes(obj, 'big')
def _encode(self, obj, context, path):
@@ -441,10 +445,16 @@
# remove trailing bytes if they are zero
obj_step_aligned = obj
- while len(obj) > self.min_len and obj[-1] == self.default_value[0]:
- obj = obj[:-1]
- if len(obj) in self.steps:
- obj_step_aligned = obj
+ if self.reverse:
+ while len(obj) > self.min_len and obj[0] == self.default_value[0]:
+ obj = obj[1:]
+ if len(obj) in self.steps:
+ obj_step_aligned = obj
+ else:
+ while len(obj) > self.min_len and obj[-1] == self.default_value[0]:
+ obj = obj[:-1]
+ if len(obj) in self.steps:
+ obj_step_aligned = obj
if self.steps == []:
return obj
diff --git a/tests/test_construct.py b/tests/test_construct.py
index e4234db..4fb1a71 100755
--- a/tests/test_construct.py
+++ b/tests/test_construct.py
@@ -101,6 +101,11 @@
final_application=0x0200,
global_service=0x0100,
receipt_generation=0x80,
ciphered_load_file_data_block=0x40,
contactless_activation=0x20,
contactless_self_activation=0x10)
+ IntegerSteps = StripTrailerAdapter(GreedyBytes, 4, steps = [2,4])
+ Integer = StripTrailerAdapter(GreedyBytes, 4)
+ IntegerStepsReverse = StripTrailerAdapter(GreedyBytes, 4, steps = [2,4], reverse =
True)
+ IntegerReverse = StripTrailerAdapter(GreedyBytes, 4, reverse = True)
+
examples = ['00', '80', '8040', '400010']
def test_encdec(self):
for e in self.examples:
@@ -108,6 +113,44 @@
reenc = self.Privileges.build(dec)
self.assertEqual(e, b2h(reenc))
+ def test_encdec_integer(self):
+ enc = self.IntegerSteps.build(0x10000000)
+ self.assertEqual(b2h(enc), '1000')
+ enc = self.IntegerSteps.build(0x10200000)
+ self.assertEqual(b2h(enc), '1020')
+ enc = self.IntegerSteps.build(0x10203000)
+ self.assertEqual(b2h(enc), '10203000')
+ enc = self.IntegerSteps.build(0x10203040)
+ self.assertEqual(b2h(enc), '10203040')
+
+ enc = self.Integer.build(0x10000000)
+ self.assertEqual(b2h(enc), '10')
+ enc = self.Integer.build(0x10200000)
+ self.assertEqual(b2h(enc), '1020')
+ enc = self.Integer.build(0x10203000)
+ self.assertEqual(b2h(enc), '102030')
+ enc = self.Integer.build(0x10203040)
+ self.assertEqual(b2h(enc), '10203040')
+
+ def test_encdec_integer_reverse(self):
+ enc = self.IntegerStepsReverse.build(0x40)
+ self.assertEqual(b2h(enc), '0040')
+ enc = self.IntegerStepsReverse.build(0x3040)
+ self.assertEqual(b2h(enc), '3040')
+ enc = self.IntegerStepsReverse.build(0x203040)
+ self.assertEqual(b2h(enc), '00203040')
+ enc = self.IntegerStepsReverse.build(0x10203040)
+ self.assertEqual(b2h(enc), '10203040')
+
+ enc = self.IntegerReverse.build(0x40)
+ self.assertEqual(b2h(enc), '40')
+ enc = self.IntegerReverse.build(0x3040)
+ self.assertEqual(b2h(enc), '3040')
+ enc = self.IntegerReverse.build(0x203040)
+ self.assertEqual(b2h(enc), '203040')
+ enc = self.IntegerReverse.build(0x10203040)
+ self.assertEqual(b2h(enc), '10203040')
+
def test_enc(self):
enc = self.Privileges.build({'dap_verification' : True})
self.assertEqual(b2h(enc), '40')
--
To view, visit
https://gerrit.osmocom.org/c/python/pyosmocom/+/39193?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: python/pyosmocom
Gerrit-Branch: master
Gerrit-Change-Id: I1a9fff17abbbef0c5f6d45f58198debfa12e78b6
Gerrit-Change-Number: 39193
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>