Complex Types

ByteStruct

Inheritance diagram of oser.ByteStruct
class oser.ByteStruct
decode(data: bytes, full_data: bytes = b'', context_data: bytes = b'') int

Decode a binary string and return the number of bytes that were decoded.

Parameters:
  • data – the data buffer that is decoded.

  • full_data – the binary data string until the part to be decoded. The user normally does not need to supply this.

  • context_data – the binary data of the current context. The user normally does not need to supply this.

Returns:

the number of bytes that were decoded.

Return type:

int

encode(full_data: bytes = b'', context_data: bytes = b'') bytes

Return the encoded binary string.

Parameters:
  • full_data – the binary data string until the part to be encoded. The user normally does not need to supply this.

  • context_data – the binary data of the current context. The user normally does not need to supply this.

from_dict(data: Dict) None

Fill self with data.

Parameters:

data – data to be used to fill the calling instance.

fuzzing_iterator(copy: bool = False) Generator[Any, None, None]

The fuzzing iterator iterates over all combinations of set fuzzing values (oser.ByteType.set_fuzzing_values()). If no fuzzing values are set the current struct is yielded.

Parameters:

copy=False – if set to True the generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set to False the original struct is retruned and the generated value must be used immediately since the next generated overwrites the values on the same value.

Yields:

the fuzzing combinations.

get_byte_size() int

Return the size in bytes.

Returns:

the length of the byte type in bytes.

Return type:

int

get_size() int

Return the size in bytes.

Returns:

the length of the byte type in bytes.

Return type:

int

introspect(stop_at: ByteStruct | BitStruct | ByteType | BitType | None = None) str

Return the introspection representation of the object as a string.

Parameters:

stop_at=None – stop introspection at stop_at.

root() ByteStruct | BitStruct

return root element

to_dict() Dict

Return self as a dict()

up() ByteStruct | BitStruct

return parent element

Usage:

>>> from oser import ByteStruct, UBInt8, UBInt16, UBInt32, to_hex

>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.a = UBInt8(1)
...         self.b = UBInt16(1000)
...         self.c = UBInt32(1000000)

>>> instance = Data()
>>> print(instance)
Data():
    a: 1 (UBInt8)
    b: 1000 (UBInt16)
    c: 1000000 (UBInt32)

>>> print(instance.introspect())
   -    -  Data():
   0 \x01      a: 1 (UBInt8)
   1 \x03      b: 1000 (UBInt16)
   2 \xe8
   3 \x00      c: 1000000 (UBInt32)
   4 \x0f
   5 \x42
   6 \x40

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6
\x01\x03\xE8\x00\x0F\x42\x40
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
7
>>> print(instance)
Data():
    a: 1 (UBInt8)
    b: 1000 (UBInt16)
    c: 1000000 (UBInt32)

BitStruct

oser.BitStruct is like a oser.ByteStruct for bit-aligned types.

Note: The result of oser.OserNode.encode() is byte-aligned. If the amount of bits is not a multiple of 8 the last bits are filled with don’t care values.

Inheritance diagram of oser.BitStruct
class oser.BitStruct
decode(data: bytes, full_data: bytes = b'', context_data: bytes = b'') int

Decode a binary string and return the number of bytes that were decoded.

Parameters:
  • data – the data buffer that is decoded.

  • full_data – the binary data string until the part to be decoded. The user normally does not need to supply this.

  • context_data – the binary data of the current context. The user normally does not need to supply this.

encode(full_data: bytes = b'', context_data: bytes = b'') bytes

Return the encoded binary string.

Parameters:
  • full_data – the binary data string until the part to be encoded. The user normally does not need to supply this.

  • context_data – the binary data of the current context. The user normally does not need to supply this.

from_dict(data: Dict) None

Fill self with data.

Parameters:

data – data to be used to fill the calling instance.

fuzzing_iterator(copy: bool = False) Generator[Any, None, None]

The fuzzing iterator iterates over all combinations of set fuzzing values (oser.ByteType.set_fuzzing_values()). If no fuzzing values are set the current struct is yielded.

Parameters:

copy=False – if set to True the generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set to False the original struct is retruned and the generated value must be used immediately since the next generated overwrites the values on the same value.

Yields:

the fuzzing combinations.

get_byte_size() int

Return the size in bytes.

Returns:

the length of the byte type in bytes.

Return type:

int

get_size() int

Return the size in bits.

Returns:

the length of the bit type in bits.

Return type:

int

introspect(stop_at: ByteStruct | BitStruct | ByteType | BitType | None = None) str

Return the introspection representation of the object as a string.

Parameters:

stop_at=None – stop introspection at stop_at.

root() ByteStruct | BitStruct

return root element

to_dict() Dict

Return self as a dict()

up() ByteStruct | BitStruct

return parent element

Usage:

>>> from oser import BitStruct, Flag, Nibble, BitField, to_hex

>>> class Data(BitStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.a = Flag(1)
...         self.b = Nibble(5)
...         self.c = BitField(value=57, length=6)
...
>>> instance = Data()
>>> print(instance)
Data():
    a: 1 (Flag)
    b: 5 (Nibble)
    c: 57 (BitField(6))

>>> print(instance.introspect())
   -    -  Data():
   0.7  1      a: 1 (Flag)
   0.6  0      b: 5 (Nibble)
   0.5  1
   0.4  0
   0.3  1
   0.2  1      c: 57 (BitField(6))
   0.1  1
   0.0  1
   1.7  0
   1.6  0
   1.5  1
   1.4  x
   1.3  x
   1.2  x
   1.1  x
   1.0  x

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\xAF\x20
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
2
>>> print(instance)
Data():
    a: 1 (Flag)
    b: 5 (Nibble)
    c: 57 (BitField(6))

Enum

An oser.Enum is most commonly used to give values human readable names. It can be used in bit-aligned context and byte-aligned context.

Inheritance diagram of oser.Enum
class oser.Enum(prototype: ByteStruct | BitStruct | ByteType | BitType, values: Dict[ByteStruct | BitStruct | ByteType | BitType, Any], value: Any | None = None, strict: bool = False)

An enumeration serializer.

Parameters:
  • prototype – the class of the underlying data type.

  • values – a dictionary of key-value-pairs. The keys are translated into binary data represented by the values.

  • value=None (object) – the initial value.

  • strict=False (bool) – If set to True only keys and values appearing in values are accepted. Else all values are accepted.

decode(data: bytes, full_data: bytes = b'', context_data: bytes = b'') int

Decode a binary string and return the number of bytes that were decoded.

Parameters:
  • data (bytes) – the data buffer that is decoded.

  • full_data (bytes) – the binary data string until the part to be decoded. The user normally does not need to supply this.

  • context_data (bytes) – the binary data of the current context. The user normally does not need to supply this.

Returns:

the number of bytes that were decoded.

Return type:

int

encode(full_data: bytes = b'', context_data: bytes = b'') bytes

Return the encoded binary string.

Parameters:
  • full_data (bytes) – the binary data string until the part to be encoded. The user normally does not need to supply this.

  • context_data (bytes) – the binary data of the current context. The user normally does not need to supply this.

Returns:

the encoded binary string.

Return type:

bytes

get() Any

Return the value as string representation if possible of the raw value else.

Returns:

the value as string or raw

Return type:

object

get_byte_size() int

Return the size in bytes.

get_size() int

Return the size in bits or bytes, depending on the prototype.

get_value() Any

Return the raw value.

Returns:

the raw value.

Return type:

object

introspect(stop_at: ByteStruct | BitStruct | ByteType | BitType | None = None) str

Return the introspection representation of the object as a string.

Parameters:

stop_at=None (object) – stop introspection at stop_at.

root() ByteStruct | BitStruct

return root element

set(value: Any) None

Set the value.

Parameters:

value – the new value

set_fuzzing_values(values: Generator[Any, None, None] | List[Any] | None) None

Set fuzzing values.

Parameters:

values (iterable) – the values used for fuzzing.

up() ByteStruct | BitStruct

Return the parent element.

Usage in byte context:

>>> from oser import ByteStruct, Enum, UBInt16, to_hex

>>> class Data(ByteStruct):
...         def __init__(self):
...             super(Data, self).__init__()
...             self.enum = Enum(prototype=UBInt16,
...                              values={
...                                  "A": 1,
...                                  "B": 2,
...                                  "C": 3,
...                                  "D": 4,
...                              }, value="C")
...
>>> instance = Data()
>>> print(instance)
Data():
    enum: 'C' (UBInt16)

>>> print(instance.introspect())
   -    -  Data():
   0 \x00      enum: 3 (UBInt16)
   1 \x03

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\x00\x03
>>> instance.enum.set("B")
>>> print(instance)
Data():
    enum: 'B' (UBInt16)

>>> print(instance.introspect())
   -    -  Data():
   0 \x00      enum: 2 (UBInt16)
   1 \x02

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\x00\x02
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
2
>>> print(instance)
Data():
    enum: 'B' (UBInt16)

>>> instance.decode(b"\x01\x4D")
2
>>> print(instance)
Data():
    enum: '333' (UBInt16)

>>> print(instance.introspect())
   -    -  Data():
   0 \x01      enum: 333 (UBInt16)
   1 \x4d

Usage in bit context:

>>> from oser import BitStruct, Enum, Flag, to_hex

>>> class Data(BitStruct):
...         def __init__(self):
...             super(Data, self).__init__()
...             self.enum = Enum(prototype=Flag,
...                              values={
...                                  "false" : 0,
...                                  "true" : 1,
...                              }, value="true")
...
>>> instance = Data()
>>> print(instance)
Data():
    enum: 'true' (Flag)

>>> print(instance.introspect())
   -    -  Data():
   0.7  1      enum: 1 (Flag)
   0.6  x
   0.5  x
   0.4  x
   0.3  x
   0.2  x
   0.1  x
   0.0  x

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0
\x80

>>> instance.enum.set("false")
>>> print(instance)
Data():
    enum: 'false' (Flag)

>>> print(instance.introspect())
   -    -  Data():
   0.7  0      enum: 0 (Flag)
   0.6  x
   0.5  x
   0.4  x
   0.3  x
   0.2  x
   0.1  x
   0.0  x

>>> binary = instance.encode()
>>> print(to_hex(binary))
   0
\x00
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
1
>>> print(instance)
Data():
    enum: 'false' (Flag)


>>> instance.decode(b"\x80")
1
>>> print(instance)
Data():
    enum: 'true' (Flag)

>>> print(instance.introspect())
   -    -  Data():
   0.7  1      enum: 1 (Flag)
   0.6  x
   0.5  x
   0.4  x
   0.3  x
   0.2  x
   0.1  x
   0.0  x