def BooleanFlag(name, truth_value=1, false_value=0, default=False): """ Defines a Construct boolean type. The flag is coded as a 32 bit value """ """ A boolean field coded as integer. Flags are usually used to signify a Boolean value, and this construct maps values onto the ``bool`` type. .. note:: This construct works with both bit and byte contexts. .. warning:: Flags default to False, not True. This is different from the C and Python way of thinking about truth, and may be subject to change in the future. :param name: field name :param truth: value of truth (default 1) :param falsehood: value of falsehood (default 0) :param default: default value (default False) """ return SymmetricMapping( Field(name, 4), # FormatField(name, "<", "l") { True: int32_to_bytes(truth_value), False: int32_to_bytes(false_value) }, default=default, )
class TestThisExpressions(unittest.TestCase): this_example = Struct( "this_example", # straight-forward usage: instead of passing (lambda ctx: ctx["length"]) use this.length UBInt8("length"), Field("value", this.length), # an example of nesting: '_' refers to the parent's scope Struct("nested", UBInt8("b1"), UBInt8("b2"), Computed("b3", this.b1 * this.b2 + this._.length)), # and conditions work as expected IfThenElse( "condition", this.nested.b1 > 50, UBInt32("foo"), UBInt8("bar"), )) def test_parse(self): res = self.this_example.parse(b"\x05helloABXXXX") expected = Container(length=5)(value=b'hello')(nested=Container(b1=65)( b2=66)(b3=4295))(condition=1482184792) self.assertEquals(res, expected) def test_build(self): obj = dict(length=5, value=b'hello', nested=dict(b1=65, b2=66, b3=None), condition=1482184792) data = self.this_example.build(obj) self.assertEquals(data, b"\x05helloABXXXX")
def connect_success(name='connect_success'): return Struct( name, VLQ('client_id'), HexAdapter(Field('server_uuid', 16)), Struct('celestial_data', SBInt32('planet_orbital_levels'), SBInt32('satellite_orbital_levels'), SBInt32('chunk_size'), SBInt32('xy_min'), SBInt32('xy_max'), SBInt32('z_min'), SBInt32('z_max')))
def client_connect(name='client_connect'): return Struct( name, StarByteArray('asset_digest'), HexAdapter(Field('uuid', 16)), star_string('name'), star_string('species'), ChunkVariant('ship_data'), UBInt32('ship_level'), UBInt32('max_fuel'), VLQ('capabilities_length'), Array(lambda ctx: ctx.capabilities_length, Struct('capabilities', star_string('value'))), star_string('account'))
def warp_action(name='warp_action'): return Struct( name, Byte('warp_type'), Switch('warp_action_type', lambda ctx: ctx['warp_type'], { 1: LazyBound('next', lambda: WARP_WORLD), 2: HexAdapter(Field('uuid', 16)), 3: SBInt32('alias') }, default=Pass))
def _parse(self, stream, context): x = Byte("").parse_stream(stream) if x == 0: return None elif x == 1: return star_string().parse_stream(stream) elif x == 2: return None elif x == 3: flag = Flag("").parse_stream(stream) return Field("", 16).parse_stream(stream).encode("hex") elif x == 4: return star_string().parse_stream(stream)
def packet(name='base_packet'): return Struct(name, Byte('id'), SignedVLQ('payload_size'), Field('data', lambda ctx: abs(ctx.payload_size)))
import struct from helpers import * from construct import Field, Struct, UBInt8, UBInt16, SBInt16, Adapter, Array, LFloat32, GreedyRange, Embed, OptionalGreedyRange, UBInt32 class SmallNumber(Adapter): def _encode(self, obj, context): return struct.Struct(">L").pack(obj)[1:] def _decode(self, obj, context): return struct.unpack(">L", b"\x00" + obj)[0] struct_base = Struct("base", UBInt8("version"), SmallNumber(Field("size", 3))) struct_common = Struct("common", Embed(struct_base), UBInt8("msg_type"), \ UBInt8("device"), UBInt8("command"), Field("data", lambda c: c.size-7)) struct_initialize_ok = Struct("init_ok", UBInt8("response_code"), UBInt8("protocol_size"), \ Array(lambda c: c.protocol_size, UBInt8("protocols")), Array(12, UBInt8("model")), \ Array(8, UBInt8("serial_number")), Array(3, UBInt8("build")), UBInt8("watchdog"), \ UBInt32("free_ram"), UBInt32("free_print_mem"), UBInt32("free_page_mem"), UBInt8("machine_type")) struct_led = Struct("led", UBInt8("leds"), UBInt8("color"), UBInt16("period"), UBInt16("timeout")) struct_printer_get_status = Struct("printer_get_status", UBInt8("paper_out_1"), UBInt8("paper_out_2"), \ UBInt8("lever_open")) struct_print_buffer = Struct("print_buffer", UBInt16("size"), Array(lambda c: c.size, UBInt8("stream")), \
def _decode(self, obj, context): return time.ctime(obj) def _encode(self, obj, context): return int(time.mktime(time.strptime(obj))) packet_record = Struct( "packet_record", UBInt32("original_length"), UBInt32("included_length"), UBInt32("record_length"), UBInt32("cumulative_drops"), EpochTimeStampAdapter(UBInt32("timestamp_seconds")), UBInt32("timestamp_microseconds"), HexDumpAdapter(Field("data", lambda ctx: ctx.included_length)), # 24 being the static length of the packet_record header Padding(lambda ctx: ctx.record_length - ctx.included_length - 24), ) datalink_type = Enum( UBInt32("datalink"), IEEE802dot3=0, IEEE802dot4=1, IEEE802dot5=2, IEEE802dot6=3, ETHERNET=4, HDLC=5, CHARSYNC=6, IBMCHANNEL=7, FDDI=8,
def greedy_string(name): """ Variable-length string field. """ return Rename(name, StringAdapter(OptionalGreedyRange(Field(None, 1))))
def test_field_parse(self): f = Field('name', 6) self.assertEqual(f.parse(b'abcdef'), b'abcdef') self.assertEqual(f.parse(b'12abcdef'), b'12abcd')
EP_OPERATION_SET = 6 EP_ACT_INVALID = 0 EP_ACT_HELLO = 1 EP_ACT_CAPS = 2 EP_ACT_UE_REPORT = 4 EP_ACT_HANDOVER = 7 EP_ACT_RAN_SETUP = 9 EP_ACT_RAN_MAC_SLICE = 10 E_TYPE_SINGLE = 0x01 E_TYPE_SCHED = 0x02 E_TYPE_TRIG = 0x03 OPTIONS = Struct("options", UBInt16("type"), UBInt16("length"), Field("data", lambda ctx: ctx.length)) HEADER = Struct("header", UBInt8("type"), UBInt8("version"), Bytes("enbid", 8), UBInt16("cellid"), UBInt32("xid"), BitStruct("flags", Padding(15), Bit("dir")), UBInt32("seq"), UBInt16("length")) E_SCHED = Struct("e_sched", UBInt16("action"), UBInt8("opcode"), UBInt32("interval")) E_SINGLE = Struct("e_single", UBInt16("action"), UBInt8("opcode")) E_TRIG = Struct("e_trig", UBInt16("action"), UBInt8("opcode")) HELLO = Struct("hello", UBInt32("padding"))
"items", SBInt16("primary"), If( lambda context: context["primary"] >= 0, Embed( Struct( "item_information", UBInt8("count"), UBInt16("secondary"), )), ), ) # Metadata subconstruct. metadata = StringAdapter( RepeatUntil(lambda obj, ctx: obj == "\x7f", Field("metadata", 1))) # Build faces, used during dig and build. faces = { "noop": -1, "-y": 0, "+y": 1, "-z": 2, "+z": 3, "-x": 4, "+x": 5, } face = Enum(SBInt8("face"), **faces) packets = { 0:
orientation = Struct("orientation", BFloat32("rotation"), BFloat32("pitch")) # Notchian item packing items = Struct("items", SBInt16("primary"), If(lambda context: context["primary"] >= 0, Embed(Struct("item_information", UBInt8("count"), UBInt16("secondary"), )), ), ) # Metadata subconstruct. metadata = StringAdapter(RepeatUntil(lambda obj, ctx: obj == "\x7f", Field("metadata", 1))) # Build faces, used during dig and build. faces = { "noop": -1, "-y": 0, "+y": 1, "-z": 2, "+z": 3, "-x": 4, "+x": 5, } face = Enum(SBInt8("face"), **faces) packets = { 0: Struct("ping"),
def warp_toplayerworld_write(name='warp_toplayerworld_write'): return Struct(name, Byte('warp_type'), Byte('world_type'), HexAdapter(Field('uuid', 16)), Byte('has_position'))
def warp_toplayer_write(name='warp_toplayer_write'): return Struct(name, Byte('warp_type'), HexAdapter(Field('uuid', 16)))
""" from binascii import unhexlify from construct import Struct, Rename, HexDumpAdapter, Field, Switch, Pass from construct.protocols.layer2.ethernet import ethernet_header from construct.protocols.layer3.ipv4 import ipv4_header from construct.protocols.layer3.ipv6 import ipv6_header from construct.protocols.layer4.tcp import tcp_header from construct.protocols.layer4.udp import udp_header layer4_tcp = Struct("layer4_tcp", Rename("header", tcp_header), HexDumpAdapter( Field("next", lambda ctx: ctx["_"]["header"].payload_length - ctx["header"].header_length ) ), ) layer4_udp = Struct("layer4_udp", Rename("header", udp_header), HexDumpAdapter( Field("next", lambda ctx: ctx["header"].payload_length) ), ) layer3_payload = Switch("next", lambda ctx: ctx["header"].protocol, { "TCP" : layer4_tcp, "UDP" : layer4_udp,
def test_field_parse(self): f = Field("name", 6) self.assertEqual(f.parse(b"abcdef"), b"abcdef") self.assertEqual(f.parse(b"12abcdef"), b"12abcd")
from msa.core.armve.helpers import tohex class SizeAdapter(Adapter): def _encode(self, obj, context): encoded = tohex(obj) return encoded def _decode(self, obj, context): return unpack('>L', b'\x00' + obj)[0] struct_base = Struct("base", UBInt8("version"), SizeAdapter(Field("size", 3))) struct_common = Struct("common", Embed(struct_base), UBInt8("msg_type"), UBInt8("device"), UBInt8("command"), Field("data", lambda ctx: ctx.size - 7)) struct_byte = Struct("byte", UBInt8("byte")) struct_batt_connected = Struct("batt_connected", UBInt8("slots_number"), Array(lambda ctx: ctx.slots_number, UBInt8("slots"))) struct_batt_get_status = Struct("batt_get_status",
first combine all the TCP frames into a stream. See utils.tcpip for some solutions """ from construct import Struct, Rename, HexDumpAdapter, Field, Switch, Pass from construct.protocols.layer2.ethernet import ethernet_header from construct.protocols.layer3.ipv4 import ipv4_header from construct.protocols.layer3.ipv6 import ipv6_header from construct.protocols.layer4.tcp import tcp_header from construct.protocols.layer4.udp import udp_header layer4_tcp = Struct( "layer4_tcp", Rename("header", tcp_header), HexDumpAdapter( Field( "next", lambda ctx: ctx["_"]["header"].payload_length - ctx[ "header"].header_length)), ) layer4_udp = Struct( "layer4_udp", Rename("header", udp_header), HexDumpAdapter(Field("next", lambda ctx: ctx["header"].payload_length)), ) layer3_payload = Switch("next", lambda ctx: ctx["header"].protocol, { "TCP": layer4_tcp, "UDP": layer4_udp, }, default=Pass)
DATA_STOP=3, SENSOR_MAP=9, DATA_RATE=10 ), UBInt32('sending_node'), # byes 16-19 If(lambda ctx: ctx.payload_length > 8, # Message data is optional # message_length: bytes 20-23, message: bytes 24+ PascalString('message', length_field=UBInt32('message_length'), encoding='ascii') ) ) _EEG_data = Struct('embedded', BFloat32('timestamp'), # bytes 12-15 UBInt8('data_counter'), # byte 16; Unused, just 0 currently Field('ADC_status', 6), # bytes 17-22 Array(lambda ctx: (ctx.payload_length - 11)/4, BFloat32('sensor_data')) # bytes 23-26, 27-30, etc. ) _null = Struct('embedded', Array(111, UBInt8('none')) ) DSI_streamer_packet = Struct('DSI_streamer_packet', Embed(_header), Switch('payload', lambda ctx: ctx.type, {"NULL": Embed(_null), "EVENT": Embed(_event), "EEG_DATA": Embed(_EEG_data)}
def test_field_parse(self): f = Field('name', 6) self.assertEqual(f.parse(six.b('abcdef')), six.b('abcdef')) self.assertEqual(f.parse(six.b('12abcdef')), six.b('12abcd'))
Switch('world_type', lambda ctx: ctx['world_id'], { 1: LazyBound('next', lambda: WARP_WORLD_CELESTIAL), 2: LazyBound('next', lambda: WARP_WORLD_PLAYER), 3: LazyBound('next', lambda: WARP_WORLD_MISSION) }, default=Pass)) WARP_WORLD_CELESTIAL = Struct( 'celestial_world', SBInt32('x'), SBInt32('y'), SBInt32('z'), SBInt32('planet'), SBInt32('satellite'), Optional(Byte('has_position')), If(lambda ctx: ctx['has_position'], Struct('position', SBInt32('x'), SBInt32('y')))) WARP_WORLD_PLAYER = Struct( 'player_world', HexAdapter(Field('uuid', 16)), Optional(Byte('has_position')), If(lambda ctx: ctx['has_position'], Struct('position', SBInt32('x'), SBInt32('y')))) WARP_WORLD_MISSION = Struct( 'mission_world', star_string('mission_world_name'), Byte('check'), If(lambda ctx: ctx['check'] == 1, HexAdapter(Field('instance', 16)))) def packet(name='base_packet'): return Struct(name, Byte('id'), SignedVLQ('payload_size'), Field('data', lambda ctx: abs(ctx.payload_size))) def start_packet(name='interim_packet'):
def setUp(self): self.hda = HexDumpAdapter(Field("hexdumpadapter", 6))
from helpers import tohex from construct import Field, Struct, UBInt8, UBInt16, SBInt16, Adapter, \ Array, LFloat32, GreedyRange, Embed, OptionalGreedyRange, UBInt32 class SizeAdapter(Adapter): def _encode(self, obj, context): encoded = tohex(obj) return encoded def _decode(self, obj, context): return unpack('>L', '\x00' + obj)[0] struct_base = Struct("base", UBInt8("version"), SizeAdapter(Field("size", 3))) struct_common = Struct("common", Embed(struct_base), UBInt8("msg_type"), UBInt8("device"), UBInt8("command"), Field("data", lambda ctx: ctx.size - 7)) struct_byte = Struct("byte", UBInt8("byte")) struct_batt_connected = Struct( "batt_connected", UBInt8("slots_number"), Array(lambda ctx: ctx.slots_number, UBInt8("slots"))) struct_batt_get_status = Struct( "batt_get_status", UBInt8("batt_number"), Array( lambda ctx: ctx.batt_number, Struct("batt_data", UBInt8("slot_number"), UBInt16("tension"), SBInt16("corriente"), LFloat32("temp"), UBInt16("remaining"),