dexter has uploaded this change for review.

View Change

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 change 39193. To unsubscribe, or for help writing mail filters, visit settings.

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@sysmocom.de>