Context Based Types
The Context
Every OSER instance is aware of the context it is located in. Context based types can use the context to realize context dependent instances. For example it is possible to create a variable length payload for a network packet or create one instance that can represent multiple different network packets, etc. .
The context can be used using a lambda-expression or a method.
String
A oser.String can be used to encode and decode strings.
The length can be either fixed (int), variable (callable) or None for null-terminated strings.
- class oser.String(length: Callable | int | None = None, value: bytes | str = b'', padding: bytes | str = b'\x00')
 Stringbuilds a string serializer with a fixed or variable length.- Parameters:
 length=None – states the string length. Can be a callable (e.g. lambda) or a scalar. If set to
Nonethe result is a null-terminated string. If set to an Integer the result is a fixed length string padded withpadding. If set to acallable(lambda or function) the result is a fixed or variable length string padded withpadding.value="" – the initial string value.
padding="" – that padding pattern used for filling the encoded data if value is shorter than length.
- 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:
 
- 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.
- Returns:
 the encoded binary string.
- Return type:
 
- 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
- set_fuzzing_values(values: Generator[Any, None, None] | List[Any] | None) None
 Set fuzzing values.
- Parameters:
 values – the values used for fuzzing.
- set_length(length: Callable | int | None) None
 Set the length.
- Parameters:
 length=None – states the string length. Can be a callable (e.g. lambda) or a scalar. If set to
Nonethe result is a null-terminated string. If set to an Integer the result is a fixed length string padded withpadding. If set to acallable(lambda or function) the result is a fixed or variable length string padded withpadding.
- up() ByteStruct | BitStruct
 Return the parent element.
Fixed length usage:
>>> from oser import String, to_hex
>>> instance = String(length=10, value=b"abcdefghi")
>>> print(instance)
'abcdefghi'
>>> print(instance.introspect())
   -    -  String():
   0 \x61      'a'
   1 \x62      'b'
   2 \x63      'c'
   3 \x64      'd'
   4 \x65      'e'
   5 \x66      'f'
   6 \x67      'g'
   7 \x68      'h'
   8 \x69      'i'
   9 \x00      '\x00'
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6|  7|  8|  9
\x61\x62\x63\x64\x65\x66\x67\x68\x69\x00
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
10
>>> print(instance)
'abcdefghi\x00'
Variable length usage in a oser.ByteStruct:
>>> from oser import ByteStruct, UBInt16, String, to_hex
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.length = UBInt16(12)
...         self.string = String(length=lambda self: self.length.get(), value="abcdefghijkl")
...
>>> instance = Data()
>>> print(instance)
Data():
    length: 12 (UBInt16)
    string: 'abcdefghijkl'
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      length: 12 (UBInt16)
   1 \x0c
   -    -      string: String():
   2 \x61          'a'
   3 \x62          'b'
   4 \x63          'c'
   5 \x64          'd'
   6 \x65          'e'
   7 \x66          'f'
   8 \x67          'g'
   9 \x68          'h'
  10 \x69          'i'
  11 \x6a          'j'
  12 \x6b          'k'
  13 \x6c          'l'
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6|  7|  8|  9| 10| 11| 12| 13
\x00\x0C\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C
>>> bytes_decoded = instance.decode(b"\x00\x1A\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x00")
>>> print(bytes_decoded)
28
>>> print(instance)
Data():
    length: 26 (UBInt16)
    string: 'abcdefghijklmnopqrstuvwxyz'
Null-terminated oser.String:
>>> from oser import String, to_hex
>>> instance = String(length=None, value=b"abc")
>>> print(instance)
'abc'
>>> print(instance.introspect())
   -    -  String():
   0 \x61      'a'
   1 \x62      'b'
   2 \x63      'c'
   3 \x00      '\x00'
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3
\x61\x62\x63\x00
>>> bytes_decoded = instance.decode(b"abcdefg\x00this text will not be parsed!")
>>> print(bytes_decoded)
8
>>> print(instance)
'abcdefg'
>>> print(instance.size())
8
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6|  7
\x61\x62\x63\x64\x65\x66\x67\x00
Data
A oser.Data can be used to encode and decode data (strings).
The length can be either fixed or variable.
- class oser.Data(length: Callable | int, value: bytes | str = b'', padding: bytes | str = b'\x00')
 Databuilds a data serializer with fixed or variable length. Extendsoser.Stringbut length must not beNone.- Parameters:
 length – states the data length. Must be a callable (e.g. lambda) or an integer.
value="" – the initial data value.
padding=b"" – that padding pattern used for filling the encoded data if value is shorter than length.
- 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:
 - Returns:
 the number of bytes that were decoded.
- Return type:
 
- 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_fuzzing_values(values: Generator[Any, None, None] | List[Any] | None) None
 Set fuzzing values.
- Parameters:
 values (iterable) – the values used for fuzzing.
- set_length(length: Callable | int | None) None
 Set the length.
- Parameters:
 length=None – states the string length. Can be a callable (e.g. lambda) or a scalar. If set to
Nonethe result is a null-terminated string. If set to an Integer the result is a fixed length string padded withpadding. If set to acallable(lambda or function) the result is a fixed or variable length string padded withpadding.
- up() ByteStruct | BitStruct
 Return the parent element.
Array
An oser.Array can be used to repeat parts of an instance.
The length can be either fixed or variable.
- class oser.Array(length: Callable | int, prototype: ByteStruct | BitStruct | ByteType | BitType, args: Tuple | None = None, kwargs: Dict | None = None, values: List[ByteStruct | BitStruct | ByteType | BitType] | None = None)
 Arraybuilds an array serializer with a fixed or variable length.- Parameters:
 length – states the array length. Can be a callable (e.g. lambda) or a scalar.
prototype – a class that is the prototype for values
args=None – a tuple of positional arguments that are passed to prototype when it is instantiated when array size is extended. Note: don’t forget a leading comma when passing one value
(1,)((1)is an integer!).kwargs=None – a dictionary of named arguments that are passed to prototype when it is instantiated when array size is extended.
values=None – the initial array values. Can be left empty. If empty the array is automatically resized with instances of
prototype(*args, **kwargs).
- 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:
 
- 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.
- Returns:
 the encoded binary string.
- Return type:
 
- 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
Truethe generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set toFalsethe 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.
- 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
- up() ByteStruct | BitStruct
 return parent element
Fixed length usage:
>>> from oser import Array, UBInt16, to_hex
>>> instance = Array(length=3, prototype=UBInt16, values=[UBInt16(ii) for ii in range(3)])
>>> print(instance)
Array():
[
    @0: 0 (UBInt16)
    @1: 1 (UBInt16)
    @2: 2 (UBInt16)
]
>>> print(instance.introspect())
   -    -  Array():
   -    -  [
   0 \x00      @0: 0 (UBInt16)
   1 \x00
   2 \x00      @1: 1 (UBInt16)
   3 \x01
   4 \x00      @2: 2 (UBInt16)
   5 \x02
   -    -  ]
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5
\x00\x00\x00\x01\x00\x02
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
6
>>> print(instance)
Array():
[
    @0: 0 (UBInt16)
    @1: 1 (UBInt16)
    @2: 2 (UBInt16)
]
>>> print(instance[10])
IndexError: list index out of range
Variable length usage:
>>> from oser import ByteStruct, Array, UBInt16, to_hex
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.length = UBInt16(4)
...         self.data = Array(length=lambda self: self.length.get(),
...                           prototype=UBInt16,
...                           args=(1337,), # when range is extended
...                                         # instantiate prototype with this arguments
...                           values=[UBInt16(ii) for ii in range(2)])
...
>>> instance = Data()
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 0 (UBInt16)
        @1: 1 (UBInt16)
        @2: 1337 (UBInt16)
        @3: 1337 (UBInt16)
    ]
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      length: 4 (UBInt16)
   1 \x04
   -    -      data: Array():
   -    -      [
   2 \x00          @0: 0 (UBInt16)
   3 \x00
   4 \x00          @1: 1 (UBInt16)
   5 \x01
   6 \x05          @2: 1337 (UBInt16)
   7 \x39
   8 \x05          @3: 1337 (UBInt16)
   9 \x39
   -    -      ]
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6|  7|  8|  9
\x00\x04\x00\x00\x00\x01\x05\x39\x05\x39
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
10
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 0 (UBInt16)
        @1: 1 (UBInt16)
        @2: 1337 (UBInt16)
        @3: 1337 (UBInt16)
    ]
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      length: 4 (UBInt16)
   1 \x04
   -    -      data: Array():
   -    -      [
   2 \x00          @0: 0 (UBInt16)
   3 \x00
   4 \x00          @1: 1 (UBInt16)
   5 \x01
   6 \x05          @2: 1337 (UBInt16)
   7 \x39
   8 \x05          @3: 1337 (UBInt16)
   9 \x39
   -    -      ]
>>> print(instance.data[3])
1337 (UBInt16)
>>> instance.decode(b"\x00\x14\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x09\x00\x0A\x00\x0B\x00\x0C\x00\x0D\x00\x0E\x00\x0F\x00\x10\x00\x11\x00\x12\x00\x13")
42
>>> print(instance)
Data():
    length: 20 (UBInt16)
    data: Array():
    [
        @0: 0 (UBInt16)
        @1: 1 (UBInt16)
        @2: 2 (UBInt16)
        @3: 3 (UBInt16)
        @4: 4 (UBInt16)
        @5: 5 (UBInt16)
        @6: 6 (UBInt16)
        @7: 7 (UBInt16)
        @8: 8 (UBInt16)
        @9: 9 (UBInt16)
        @10: 10 (UBInt16)
        @11: 11 (UBInt16)
        @12: 12 (UBInt16)
        @13: 13 (UBInt16)
        @14: 14 (UBInt16)
        @15: 15 (UBInt16)
        @16: 16 (UBInt16)
        @17: 17 (UBInt16)
        @18: 18 (UBInt16)
        @19: 19 (UBInt16)
    ]
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      length: 20 (UBInt16)
   1 \x14
   -    -      data: Array():
   -    -      [
   2 \x00          @0: 0 (UBInt16)
   3 \x00
   4 \x00          @1: 1 (UBInt16)
   5 \x01
   6 \x00          @2: 2 (UBInt16)
   7 \x02
   8 \x00          @3: 3 (UBInt16)
   9 \x03
  10 \x00          @4: 4 (UBInt16)
  11 \x04
  12 \x00          @5: 5 (UBInt16)
  13 \x05
  14 \x00          @6: 6 (UBInt16)
  15 \x06
  16 \x00          @7: 7 (UBInt16)
  17 \x07
  18 \x00          @8: 8 (UBInt16)
  19 \x08
  20 \x00          @9: 9 (UBInt16)
  21 \x09
  22 \x00          @10: 10 (UBInt16)
  23 \x0a
  24 \x00          @11: 11 (UBInt16)
  25 \x0b
  26 \x00          @12: 12 (UBInt16)
  27 \x0c
  28 \x00          @13: 13 (UBInt16)
  29 \x0d
  30 \x00          @14: 14 (UBInt16)
  31 \x0e
  32 \x00          @15: 15 (UBInt16)
  33 \x0f
  34 \x00          @16: 16 (UBInt16)
  35 \x10
  36 \x00          @17: 17 (UBInt16)
  37 \x11
  38 \x00          @18: 18 (UBInt16)
  39 \x12
  40 \x00          @19: 19 (UBInt16)
  41 \x13
   -    -      ]
>>> print(instance.data[15])
15 (UBInt16)
Setting and getting items:
>>> from oser import ByteStruct, Array, UBInt16
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.length = UBInt16(4)
...         self.data = Array(length=lambda self: self.length.get(),
...                           prototype=UBInt16,
...                           values=[UBInt16(ii) for ii in range(2)])
...
>>> instance = Data()
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 0 (UBInt16)
        @1: 1 (UBInt16)
        @2: 0 (UBInt16)
        @3: 0 (UBInt16)
    ]
>>> # set a single item
... instance.data[1] = 23
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 0 (UBInt16)
        @1: 23 (UBInt16)
        @2: 0 (UBInt16)
        @3: 0 (UBInt16)
    ]
>>> # set multiple items (with a slice)
... instance.data[:] = [1, 2, 3, 4]
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 1 (UBInt16)
        @1: 2 (UBInt16)
        @2: 3 (UBInt16)
        @3: 4 (UBInt16)
    ]
>>> # set every second item
... instance.data[::2] = [23, 24]
>>> print(instance)
Data():
    length: 4 (UBInt16)
    data: Array():
    [
        @0: 23 (UBInt16)
        @1: 2 (UBInt16)
        @2: 24 (UBInt16)
        @3: 4 (UBInt16)
    ]
>>> # get a single item
... print(instance.data[3])
4 (UBInt16)
>>> # get a slice
... print(instance.data[0:2])
[<oser.typedef.UBInt16 object at 0x7f8d8a86a748>, <oser.typedef.UBInt16 object at 0x7f8d8a86d470>]
If
oser.If is used to build conditional parsers when the condition is True or False.
Compared to IfElse If is invisble if the condition is False.
- class oser.If(condition: Callable | bool, if_true: ByteStruct | BitStruct | ByteType | BitType)
 Ifbuilds a conditional serializer for boolean conditions that is invisible if the condition isFalse.It is an alias for
IfElse(condition=condition, if_true=if_true, if_false=Nothing())- Parameters:
 condition – the condition which selects the desired values. Can be a callable (e.g. lambda) or a scalar.
if_true – is used if condition is True.
- 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:
 - Returns:
 the number of bytes that were decoded.
- Return type:
 
- from_dict(data: Dict) None
 Fill self with data.
- Parameters:
 data (dict) – 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 (bool) – if set to
Truethe generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set toFalsethe 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() ByteStruct | BitStruct | ByteType | BitType
 Return the current value.
- get_current() ByteStruct | BitStruct | ByteType | BitType
 Return the currently selected object.
- get_false_value() ByteStruct | BitStruct | ByteType | BitType
 Return the value for a
Falsecondition.
- get_true_value() ByteStruct | BitStruct | ByteType | BitType
 Return the value for a
Truecondition.
- 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: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value.
- Parameters:
 value – the new value
- set_false_value(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value for a
Falsecondition.- Parameters:
 value – the new value for a
Falsecondition.
- set_true_value(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value for a
Truecondition.- Parameters:
 value – the new value for a
Truecondition.
- up() ByteStruct | BitStruct
 return parent element
Usage:
>>> from oser import ByteStruct, If, UBInt8, UBInt64, to_hex
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.condition = UBInt8(1)
...         self.data = If(condition=lambda self: self.condition.get() > 0,
...                        if_true=UBInt8(1))
...
>>> instance = Data()
>>> print(instance)
Data():
    condition: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      condition: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\x01\x01
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
2
>>> print(instance)
Data():
    condition: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      condition: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> instance.condition.set(0)
>>> print(instance)
Data():
    condition: 0 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      condition: 0 (UBInt8)
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0
\x00
IfElse
oser.IfElse is used to build conditional parsers when the condition is True or False.
If there are more possible values oser.Switch can be used.
- class oser.IfElse(condition: Callable | bool, if_true: ByteStruct | BitStruct | ByteType | BitType, if_false: ByteStruct | BitStruct | ByteType | BitType)
 IfElsebuilds a conditional serializer for boolean conditions.- Parameters:
 condition – the condition which selects the desired values. Can be a callable (e.g. lambda) or a scalar.
if_true – is used if condition is True.
if_false – is used if condition is False.
- 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:
 
- 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.
- Returns:
 the encoded binary string.
- Return type:
 
- 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
Truethe generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set toFalsethe 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() ByteStruct | BitStruct | ByteType | BitType
 Return the current value.
- get_current() ByteStruct | BitStruct | ByteType | BitType
 Return the currently selected object.
- get_false_value() ByteStruct | BitStruct | ByteType | BitType
 Return the value for a
Falsecondition.
- get_true_value() ByteStruct | BitStruct | ByteType | BitType
 Return the value for a
Truecondition.
- 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
- set(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value.
- Parameters:
 value – the new value
- set_false_value(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value for a
Falsecondition.- Parameters:
 value – the new value for a
Falsecondition.
- set_true_value(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the value for a
Truecondition.- Parameters:
 value – the new value for a
Truecondition.
- up() ByteStruct | BitStruct
 return parent element
Usage:
>>> from oser import ByteStruct, IfElse, UBInt8, UBInt64, to_hex
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.condition = UBInt8(1)
...         self.data = IfElse(condition=lambda self: self.condition.get() > 0,
...                            if_true=UBInt8(1),
...                            if_false=UBInt64(0x0123456789abcdef)
...                            )
...
>>> instance = Data()
>>> print(instance)
Data():
    condition: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      condition: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\x01\x01
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
2
>>> print(instance)
Data():
    condition: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      condition: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> instance.condition.set(0)
>>> print(instance)
Data():
    condition: 0 (UBInt8)
    data: 81985529216486895 (UBInt64)
>>> print(instance.introspect())
   -    -  Data():
   0 \x00      condition: 0 (UBInt8)
   1 \x01      data: 81985529216486895 (UBInt64)
   2 \x23
   3 \x45
   4 \x67
   5 \x89
   6 \xab
   7 \xcd
   8 \xef
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4|  5|  6|  7|  8
\x00\x01\x23\x45\x67\x89\xAB\xCD\xEF
Switch
oser.Switch is used to build conditional parsers where condition is not only True or False.
If the condition can only be True or False oser.IfElse can be used, too.
- class oser.Switch(condition: Callable | int, values: Dict[Any, ByteStruct | BitStruct | ByteType | BitType], default: ByteStruct | BitStruct | ByteType | BitType | None = None)
 Switchbuilds a conditional serializer.- Parameters:
 condition – the key which selects the desired values. Can be a callable (e.g. lambda) or a scalar.
values – a dictionary that holds key-value pairs. The key is selected by the value (or return value) of condition and the value is used as the actual serializer.
default=None – if not None this value is used as a serializer if condition is not found in values
- 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:
 
- delete_value(key: Any) None
 Delete the value identified by
key.- Parameters:
 key – the key for the value to be deleted.
- 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.
- Returns:
 the encoded binary string.
- Return type:
 
- 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
Truethe generated fuzzing values are deep copies of the original. Creating these deep copies is slow. If set toFalsethe 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() ByteStruct | BitStruct | ByteType | BitType
 Return the current value.
- get_current() ByteStruct | BitStruct | ByteType | BitType
 Return the currently selected object.
- get_items() Iterable[ByteStruct | BitStruct | ByteType | BitType]
 Return the items of the values (like in a
dict).
- get_value(key: Any) ByteStruct | BitStruct | ByteType | BitType
 Get the value for
key.- Parameters:
 key – the key for the condition.
- Returns:
 the value for the
conditionkey.
- get_values() Iterable[ByteStruct | BitStruct | ByteType | BitType]
 Return the values of the
values(like in adict).
- 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
- set(value: ByteStruct | BitStruct | ByteType | BitType) None
 Set the current value.
- Parameters:
 value – the new value.
- set_value(key: Any, value: ByteStruct | BitStruct | ByteType | BitType) None
 Get the value for
key.- Parameters:
 key – the key for the condition.
value – the value for the
key.
- up() ByteStruct | BitStruct
 return parent element
Usage:
>>> from oser import ByteStruct, Switch, UBInt8, UBInt16, UBInt32, Null, to_hex
>>> class Data(ByteStruct):
...     def __init__(self):
...         super(Data, self).__init__()
...
...         self.type = UBInt8(1)
...         self.data = Switch(lambda self: self.type.get(),
...                            values={
...                                1: UBInt8(1),
...                                2: UBInt16(2),
...                                3: UBInt32(3)
...                            },
...                            default=Null())
...
>>> instance = Data()
>>> print(instance)
Data():
    type: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      type: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1
\x01\x01
>>> bytes_decoded = instance.decode(binary)
>>> print(bytes_decoded)
2
>>> print(instance)
Data():
    type: 1 (UBInt8)
    data: 1 (UBInt8)
>>> print(instance.introspect())
   -    -  Data():
   0 \x01      type: 1 (UBInt8)
   1 \x01      data: 1 (UBInt8)
>>> # 3
... instance.type.set(3)
>>> print(instance)
Data():
    type: 3 (UBInt8)
    data: 3 (UBInt32)
>>> print(instance.introspect())
   -    -  Data():
   0 \x03      type: 3 (UBInt8)
   1 \x00      data: 3 (UBInt32)
   2 \x00
   3 \x00
   4 \x03
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0|  1|  2|  3|  4
\x03\x00\x00\x00\x03
>>> # non existent value -> Null()
... instance.type.set(100)
>>> print(instance)
Data():
    type: 100 (UBInt8)
    data: Null (Null)
>>> print(instance.introspect())
   -    -  Data():
   0 \x64      type: 100 (UBInt8)
   -    -      data: Null
>>> binary = instance.encode()
>>> print(to_hex(binary))
   0
\x64
Value
oser.Value evaluates a value that only appears in string or introspection representation
but not in the encoded data.
- class oser.Value(value: Callable | Any, format: str | None = None)
 Valueevaluates a value for introspection. It does not appear in the encoded data.- Parameters:
 value (callable) – a method or a lambda to generate the value.
format=None (string) – Use “hex” to format values to hexadecimal. Use “bin” to format values to binary.
- 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:
 - Returns:
 the number of bytes that were decoded.
- Return type:
 
- 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_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:
>>> from oser import ByteStruct, ULInt8, ULInt16, to_hex, Value
>>> class Foo(ByteStruct):
...     def __init__(self):
...         super(Foo, self).__init__()
...         self.a = ULInt8(2)
...         self.b = ULInt16(7)
...         self.value = Value(value=lambda self: self.a.get() * self.b.get())
...
>>> foo = Foo()
>>> print(foo)
Foo():
    a: 2 (ULInt8)
    b: 7 (ULInt16)
    value: 14 (Value)
>>> print(foo.introspect())
   -    -  Foo():
   0 \x02      a: 2 (ULInt8)
   1 \x07      b: 7 (ULInt16)
   2 \x00
   -    -      value: 14
>>> binary = foo.encode()
>>> print(to_hex(binary))
   0|  1|  2
\x02\x07\x00