Skip to content

Commit

Permalink
feat(common/base)!: Implement parser for numeric ranges (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
c0r0n3r committed Mar 5, 2024
1 parent b048895 commit 4d88ec5
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
49 changes: 49 additions & 0 deletions cryptoparser/common/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1044,3 +1044,52 @@ def compose(self):
@classmethod
def get_encoding(cls):
return 'utf-8'


@attr.s
class NumericRangeParsableBase(ParsableBase, Serializable):
value = attr.ib(validator=attr.validators.instance_of(six.integer_types))

@value.validator
def _validator_variant(self, _, value):
if value < self._get_value_min():
raise InvalidValue(value, type(self))

if value > self._get_value_max():
raise InvalidValue(value, type(self))

@classmethod
@abc.abstractmethod
def _get_value_min(cls):
raise NotImplementedError()

@classmethod
@abc.abstractmethod
def _get_value_max(cls):
raise NotImplementedError()

@classmethod
@abc.abstractmethod
def _get_value_length(cls):
raise NotImplementedError()

@classmethod
def _parse(cls, parsable):
parser = ParserBinary(parsable)

parser.parse_numeric('value', cls._get_value_length())

return cls(**parser), parser.parsed_length

def compose(self):
composer = ComposerBinary()

composer.compose_numeric(self.value, self._get_value_length())

return composer.composed

def __str__(self):
return str(self.value)

def _as_markdown(self, level):
return self._markdown_result(str(self), level)
15 changes: 15 additions & 0 deletions test/common/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
FourByteEnumParsable,
ListParamParsable,
ListParsable,
NumericRangeParsableBase,
OneByteEnumComposer,
OneByteEnumParsable,
OpaqueEnumComposer,
Expand Down Expand Up @@ -789,3 +790,17 @@ def _get_pem_str(self, public_key_file_name):

def _get_public_key_x509(self, public_key_file_name):
return PublicKeyX509.from_pem(self._get_pem_str(public_key_file_name))


class NumericRangeParsableTest(NumericRangeParsableBase):
@classmethod
def _get_value_min(cls):
return 0x01

@classmethod
def _get_value_max(cls):
return 0xfe

@classmethod
def _get_value_length(cls):
return 1
22 changes: 22 additions & 0 deletions test/common/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
FourByteEnumParsableTest,
ListParsableTest,
NByteEnumTest,
NumericRangeParsableTest,
OneByteEnumComposerTest,
OneByteEnumParsableTest,
OneByteOddParsable,
Expand Down Expand Up @@ -868,3 +869,24 @@ def test_parse(self):
parsable = bytearray(b'aaa')
self.assertEqual(VariantParsableExactTest.parse_mutable(parsable), StringEnumAAA.AAA)
self.assertEqual(parsable, b'')


class TestNumericRangeParsable(unittest.TestCase):
def test_error(self):
with self.assertRaises(InvalidValue) as context_manager:
NumericRangeParsableTest.parse_exact_size(b'\x00')
self.assertEqual(context_manager.exception.value, 0x00)

with self.assertRaises(InvalidValue) as context_manager:
NumericRangeParsableTest.parse_exact_size(b'\xff')
self.assertEqual(context_manager.exception.value, 0xff)

def test_parse(self):
self.assertEqual(NumericRangeParsableTest.parse_exact_size(b'\x01'), NumericRangeParsableTest(1))
self.assertEqual(NumericRangeParsableTest(1).compose(), b'\x01')

def test_str(self):
self.assertEqual(str(NumericRangeParsableTest(1)), '1')

def test_as_markdown(self):
self.assertEqual(NumericRangeParsableTest(1).as_markdown(), '1')

0 comments on commit 4d88ec5

Please sign in to comment.