Esempio n. 1
0
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")
Esempio n. 2
0
def damage_request(name='damage_request'):
    return Struct(name, UBInt32('source_entity_id'),
                  UBInt32('target_entity_id'), UBInt8('hit_type'),
                  UBInt8('damage_type'), BFloat32('damage'),
                  BFloat32('knockback_x'), BFloat32('knockback_y'),
                  UBInt32('source_entity_id_wut'),
                  star_string('damage_source_kind'),
                  GreedyRange(star_string('stuats_effects')))
Esempio n. 3
0
 def __init__(self):
     self.constructFrame = Struct(
         'parser',
         OptionalGreedyRange(
             Struct(
                 'packets',
                 UBInt8('header'),
                 UBInt16('plen'),
                 UBInt8('functype'),
                 UBInt64('nodeid'),
                 UBInt8('sum'),
             )))
Esempio n. 4
0
def RRName(name):
    '''
    A Resource Record Name structure. Supports DNS pointer compression through
    the MovingPointer class
    '''
    return Struct(
        name,
        Anchor('_start'),
        Union(
            'length_or_offset',
            UBInt8('length'),  # regular label
            UBInt16('offset'),  # compression pointer
        ),
        IfThenElse(
            'name',
            this.length_or_offset.length & 0xc0 == 0xc0,
            # compression pointer
            MovingPointer(
                lambda ctx: ctx.length_or_offset.offset & ~0xc000,
                Label(name),
                offset=1,
                whence=os.SEEK_CUR,
            ),
            # regular label
            MovingPointer(this._start, Label(name)),
        ),
    )
Esempio n. 5
0
def InfiniPacket(name, identifier, subconstruct):
    """
    Common header structure for packets.

    This is possibly not the best way to go about building these kinds of
    things.
    """

    header = Struct("header",
        # XXX Should this be Magic(chr(identifier))?
        Const(UBInt8("identifier"), identifier),
        UBInt8("flags"),
        UBInt32("length"),
    )

    return Struct(name, header, subconstruct)
Esempio n. 6
0
 def __init__(self):
     self.constructFrameParse = Struct(
         "parser", OptionalGreedyRange(UBInt8("packets")),
         Value(
             "checkSum",
             lambda ctx: str(hex((255 - sum(ctx.packets[3:])) & 0xff))[
                 2:].zfill(2)[-2:]))
Esempio n. 7
0
 def data_class(self):
     """
     A :py:func:`construct.macros.UBInt8` construct that requires the
     input value to be equal to 6.
     """
     return TLSExprValidator(UBInt8('input_byte'),
                             lambda obj, ctx: obj == 6)
Esempio n. 8
0
 def __init__(self):
     self.constructFrameParse = Struct(
         "parser", OptionalGreedyRange(UBInt8("packets")),
         Value(
             "checkSum", lambda ctx: int((hex(
                 (255 - sum(ctx.packets[3:]))
                 & 0xffffffffffffffff)[-3:-1]), 16)))
Esempio n. 9
0
 def test(self):
     pstring = Struct(
         "pstring", UBInt8("length"),
         Struct(
             "inner",
             UBInt8("inner_length"),
             Bytes("data", foo),
         ))
     obj = pstring.parse(b"\x03\x02helloXXX")
     print(repr(obj))
     self.assertEqual(
         obj,
         Container(length=3, inner=Container(inner_length=2,
                                             data=b"hello")))
     size = pstring._sizeof(Container(inner_length=2,
                                      _=Container(length=3)))
     self.assertEqual(size, 7)
Esempio n. 10
0
class InstantSoupData(object):

    # common
    server = Struct("server", CString("server_id"),
                    PrefixedArray(CString('channels'), UBInt8("num_channels")))

    # structures from rfc
    opt_client_nick = CString('nickname')

    opt_client_membership = PrefixedArray(server, UBInt8("num_servers"))

    opt_server = Struct("opt_server", UBInt16("port"))

    opt_server_channels = Struct(
        "opt_server_channels",
        PrefixedArray(CString("channels"), UBInt8("num_channels")))

    opt_server_invite = Struct(
        "opt_server_invite", CString("channel_id"),
        PrefixedArray(CString("client_id"), UBInt8("num_clients")))

    # option fields
    option = Struct(
        "option",
        Enum(UBInt8("option_id"),
             CLIENT_NICK_OPTION=0x01,
             CLIENT_MEMBERSHIP_OPTION=0x02,
             SERVER_OPTION=0x10,
             SERVER_CHANNELS_OPTION=0x11,
             SERVER_INVITE_OPTION=0x12),
        Switch(
            "option_data", lambda ctx: ctx["option_id"], {
                "CLIENT_NICK_OPTION": opt_client_nick,
                "CLIENT_MEMBERSHIP_OPTION": opt_client_membership,
                "SERVER_OPTION": opt_server,
                "SERVER_CHANNELS_OPTION": opt_server_channels,
                "SERVER_INVITE_OPTION": opt_server_invite
            }))

    # the peer pdu itself
    peer_pdu = Struct("peer_pdu", CString('id'), OptionalGreedyRange(option))

    command = PascalString("command",
                           length_field=UBInt32("length"),
                           encoding='utf8')
Esempio n. 11
0
 def TLSUBInt8Length5Array(self):  # noqa
     """
     Like
     :py:meth:`TLSPrefixedArrayWithLengthValidator.TLSUBInt8Length5Array`,
     but only accepts arrays of length 5.
     """
     return TLSPrefixedArray("data",
                             UBInt8("datum"),
                             length_validator=Equals5)
Esempio n. 12
0
 def tls_array(self):
     """
     A :py:func:`tls._common._constructs.TLSPrefixedArray` of
     :py:func:`construct.macros.UBInt8` where the length prefix for the
     array size is specified with a :py:class`UBInt24` value.
     """
     return TLSPrefixedArray("digits",
                             UBInt8("digit"),
                             length_field_size=UBInt24)
Esempio n. 13
0
 def UBInt8EnumMappedStructWithDefault(self):  # noqa
     """
     Like ``UBInt8EnumMappedStruct`` but with a default value.
     """
     return Struct(
         "UBInt8EnumMappedStructWithDefault",
         *EnumSwitch(type_field=UBInt8("type"),
                     type_enum=IntegerEnum,
                     value_field="value",
                     value_choices={IntegerEnum.FIRST: UBInt16("UBInt16")},
                     default=Pass))
Esempio n. 14
0
class TranslucentColor(Color):
    classID = 31
    _construct = Struct(
        "",
        Embed(Color._construct),
        UBInt8("alpha"),  # I think.
    )
    _construct_32 = Struct(
        "",
        UBInt8("alpha"),
        UBInt8("r"),
        UBInt8("g"),
        UBInt8("b"),
    )

    def __init__(self, value):
        self.value = value

    def to_value(self):
        (r, g, b, alpha) = self.value
        return Container(r=r, g=g, b=b, alpha=alpha)

    @classmethod
    def from_value(cls, value):
        return cls((value.r, value.g, value.b, value.alpha))

    @classmethod
    def from_32bit_raw_argb(cls, raw):
        container = cls._construct_32.parse(raw)
        parts = cls.from_value(container)
        color = cls(*(x << 2 for x in parts.value))
        if color.alpha == 0 and (color.r > 0 or color.g > 0 or color.b > 0):
            color.alpha = 1023
        return color

    def to_rgba_array(self):
        return array('B', self.to_8bit())

    def to_argb_array(self):
        (r, g, b, a) = self.to_8bit()
        return bytearray((a, r, g, b))
Esempio n. 15
0
 def __init__(self):
     self.constructFrame = Struct(
         "parser",
         OptionalGreedyRange(
             Struct(
                 "packets",
                 UBInt8("header"),
                 UBInt16("plen"),
                 UBInt8("dir"),
                 ULInt64("nodeid"),
                 UBInt16("funcid"),
                 Array(
                     lambda ctx: (ctx.plen - 1 - 8 - 2) / 8,
                     Struct(
                         "datas",
                         ULInt16("type"),
                         ULInt16("unit"),
                         LFloat32("value"),
                     )),
                 UBInt8("sum"),
                 # UBInt8("simulation")
             ), ),
         OptionalGreedyRange(UBInt8("leftovers"), ),
     )
Esempio n. 16
0
 def UBInt8EnumMappedStruct(self):  # noqa
     """
     A :py:class:`construct.core.Struct` containing an
     :py:func:`tls._common._constructs.EnumSwitch` that switches on
     :py:class:`IntegerEnum`.  The struct's ``value`` field varies
     depending on the value of its ``type`` and the corresponding
     enum member specified in the ``value_choices`` dictionary
     passed to the :py:func:`tls._common._constructs.EnumSwitch`.
     """
     return Struct(
         "UBInt8EnumMappedStruct",
         *EnumSwitch(type_field=UBInt8("type"),
                     type_enum=IntegerEnum,
                     value_field="value",
                     value_choices={
                         IntegerEnum.FIRST: UBInt16("UBInt16"),
                         IntegerEnum.SECOND: UBInt24("UBInt24")
                     }))
Esempio n. 17
0
 def setUp(self):
     self.o = OneOf(UBInt8("foo"), [4, 5, 6, 7])
Esempio n. 18
0
class Color(FixedObject):
    """A 32-bit RGB color value.
    Each component r, g, b has a value between 0 and 1023.

    However, Colors are considered equal if they have the same 8-bit value.
    """
    classID = 30
    _construct = BitStruct(
        "value",
        Padding(2),
        Bits("r", 10),
        Bits("g", 10),
        Bits("b", 10),
    )

    _construct_32_rgba = Struct(
        "",
        UBInt8("r"),
        UBInt8("g"),
        UBInt8("b"),
        UBInt8("alpha"),
    )

    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return (isinstance(other, Color) and self.to_8bit() == other.to_8bit())

    def __ne__(self, other):
        return not self == other

    @classmethod
    def from_value(cls, value):
        return cls((value.r, value.g, value.b))

    def to_value(self):
        (r, g, b) = self.value
        return Container(r=r, g=g, b=b)

    @classmethod
    def from_8bit(self, r, g=None, b=None):
        if g is None and b is None:
            rgb = r
        else:
            rgb = (r, g, b)

        return Color((x << 2 for x in rgb))

    def to_8bit(self):
        """Returns value with components between 0-255."""
        return tuple(x >> 2 for x in self.value)

    def __repr__(self):
        return "%s(%s)" % (
            self.__class__.__name__,
            repr(self.value).strip("()"),
        )

    def to_rgba_array(self):
        (r, g, b) = self.to_8bit()
        return array('B', (r, g, b, 255))

    def to_argb_array(self):
        (r, g, b) = self.to_8bit()
        return bytearray((255, r, g, b))
Esempio n. 19
0
EP_ACT_CCAP = 3
EP_ACT_UE_REPORT = 4
EP_ACT_UE_MEASURE = 5
EP_ACT_HANDOVER = 7

PT_BYE = 0xFF00
PT_REGISTER = 0xFF01
PT_UE_JOIN = 0xFF02
PT_UE_LEAVE = 0xFF03

E_TYPE_SINGLE = 0x01
E_TYPE_SCHED = 0x02
E_TYPE_TRIG = 0x03

HEADER = Struct("header",
                UBInt8("type"),
                UBInt8("version"),
                UBInt32("enbid"),
                UBInt16("cellid"),
                UBInt32("modid"),
                UBInt16("length"),
                UBInt32("seq"))

E_SCHED = Struct("e_sched",
                 UBInt8("action"),
                 UBInt8("dir"),
                 UBInt8("op"),
                 UBInt32("interval"))

E_SINGLE = Struct("e_sched",
                  UBInt8("action"),
Esempio n. 20
0
from empower.main import RUNTIME

R_GT = 'GT'
R_LT = 'LT'
R_EQ = 'EQ'
R_GE = 'GE'
R_LE = 'LE'

RELATIONS = {R_EQ: 0, R_GT: 1, R_LT: 2, R_GE: 3, R_LE: 4}

PT_ADD_BUSYNESS = 0x39
PT_BUSYNESS = 0x40
PT_DEL_BUSYNESS = 0x41

ADD_BUSYNESS_TRIGGER = Struct("add_busyness_trigger", UBInt8("version"),
                              UBInt8("type"),
                              UBInt32("length"),
                              UBInt32("seq"),
                              UBInt32("module_id"),
                              Bytes("hwaddr", 6),
                              UBInt8("channel"),
                              UBInt8("band"),
                              UBInt8("relation"),
                              UBInt32("value"),
                              UBInt16("period"))

BUSYNESS_TRIGGER = Struct("busyness_trigger", UBInt8("version"),
                          UBInt8("type"),
                          UBInt32("length"),
                          UBInt32("seq"),
Esempio n. 21
0
from empower.lvapp.lvappserver import ModuleLVAPPWorker
from empower.core.module import Module
from empower.core.app import EmpowerApp

from empower.main import RUNTIME


PT_WTP_STATS_REQUEST = 0x41
PT_WTP_STATS_RESPONSE = 0x42

WTP_STATS = Sequence("stats",
                     Bytes("lvap", 6),
                     UBInt16("bytes"),
                     UBInt32("count"))

WTP_STATS_REQUEST = Struct("stats_request", UBInt8("version"),
                           UBInt8("type"),
                           UBInt32("length"),
                           UBInt32("seq"),
                           UBInt32("module_id"))

WTP_STATS_RESPONSE = \
    Struct("stats_response", UBInt8("version"),
           UBInt8("type"),
           UBInt32("length"),
           UBInt32("seq"),
           UBInt32("module_id"),
           Bytes("wtp", 6),
           UBInt16("nb_tx"),
           UBInt16("nb_rx"),
           Array(lambda ctx: ctx.nb_tx + ctx.nb_rx, WTP_STATS))
Esempio n. 22
0
from construct import Struct, UBInt8, UBInt16, OptionalGreedyRange, Container

#OptionalGreedyRange(subcon) berguna agar field tersebut berupa optional yang artinya boleh kosong kalau error juga akan diisi kongong

mo_payload = Struct('mo_payload', UBInt8('destination'), UBInt8('flags'),
                    UBInt16('msg_id'), OptionalGreedyRange(UBInt8("payload")))

payload = "Ini pesannya"
a = Container(destination=1, msg_id=1, flags=1, payload=payload)
print "a : ", a

#build
b = mo_payload.build(a)
print "b : ", b

#parse
c = mo_payload.parse(b)
print "c : ", c

print "===================================="
#lihat isi payload "ini pesannya hilang karna yang diutuhkan adalah Unsign bigendianes Integer 8 bit"
#maka bisa dengan bantuan fungsi ord yang mengubah character dalam bentuk angka
print "payload dlm bentuk symbol ASCII = ", payload
print "len = ", len(payload)
payload = map(ord, payload)
print "payload dikonversi dari symbol ke integer= ", payload
print "len = ", len(payload)
hexa = map(hex, payload)
print "dalam bentuk hexa(16) = ", hexa
print "len dalam bentuk hexa(16) = ", len(hexa)
Esempio n. 23
0
from construct import Struct, UBInt8, Debugger, Enum

foo = Struct(
    "foo",
    UBInt8("bar"),
    Debugger(Enum(
        UBInt8("spam"),
        ABC=1,
        DEF=2,
        GHI=3,
    )),
    UBInt8("eggs"),
)

print foo.parse("\x01\x02\x03")

print foo.parse("\x01\x04\x03")
Esempio n. 24
0
from empower.main import RUNTIME

PT_POLLER_REQ_MSG_TYPE = 0x27
PT_POLLER_RESP_MSG_TYPE = 0x28


POLLER_ENTRY_TYPE = Sequence("img_entries",
                             Bytes("addr", 6),
                             UBInt32("last_rssi_std"),
                             SBInt32("last_rssi_avg"),
                             UBInt32("last_packets"),
                             UBInt32("hist_packets"),
                             SBInt32("ewma_rssi"),
                             SBInt32("sma_rssi"))

POLLER_REQUEST = Struct("poller_request", UBInt8("version"),
                        UBInt8("type"),
                        UBInt16("length"),
                        UBInt32("seq"),
                        UBInt32("module_id"),
                        Bytes("addrs", 6),
                        Bytes("hwaddr", 6),
                        UBInt8("channel"),
                        UBInt8("band"))

POLLER_RESPONSE = Struct("poller_response", UBInt8("version"),
                         UBInt8("type"),
                         UBInt16("length"),
                         UBInt32("seq"),
                         UBInt32("module_id"),
                         Bytes("wtp", 6),
Esempio n. 25
0
#!/usr/bin/env python
"""Contains things like packet header structure, flags,
and packet specific enums."""

# Required modules
from construct import Container, UBInt8, UBInt32, Struct
from enum import IntEnum

__all__ = ["header", "HEADER_SIZE", "Flags", "PacketTypes", "PACKET_TYPES"]

header = Struct("packet", UBInt8("type"), UBInt8("stream"), UBInt8("flags"),
                UBInt8("payload_length"), UBInt32("sequence"), UBInt32("tag"))
HEADER_SIZE = 0x0c


class Flags(IntEnum):
    # Flag fields
    NONE = 0X00
    ALL = 0XFF
    INIT = (1 << 0)
    DATA = (1 << 1)
    FINISH = (1 << 2)
    COMPRESS = (1 << 3)
    META = (1 << 4)


class PacketTypes(IntEnum):
    """Packet types"""
    AGENT_HELLO = 0X01
    HANDLER_HELLO = 0X02
    AGENT_ACK = 0X03
Esempio n. 26
0
 def setUp(self):
     self.n = NoneOf(UBInt8("foo"), [4, 5, 6, 7])
Esempio n. 27
0
PT_CAPS_REQUEST = 0x16
PT_CAPS_RESPONSE = 0x17
PT_ADD_VAP = 0x32
PT_DEL_VAP = 0x33
PT_STATUS_VAP = 0x34
PT_ADD_LVAP_RESPONSE = 0x51
PT_DEL_LVAP_RESPONSE = 0x52
PT_LVAP_STATUS_REQUEST = 0x53
PT_VAP_STATUS_REQUEST = 0x54
PT_SET_TRAFFIC_RULE = 0x56
PT_DEL_TRAFFIC_RULE = 0x57
PT_STATUS_TRAFFIC_RULE = 0x58
PT_TRAFFIC_RULE_STATUS_REQUEST = 0x61
PT_PORT_STATUS_REQUEST = 0x62

HEADER = Struct("header", UBInt8("version"), UBInt8("type"), UBInt32("length"))

SSIDS = Range(
    1, 10,
    Struct("ssids", UBInt8("length"), Bytes("ssid", lambda ctx: ctx.length)))

HELLO = Struct("hello", UBInt8("version"), UBInt8("type"), UBInt32("length"),
               UBInt32("seq"), Bytes("wtp", 6), UBInt32("period"))

PROBE_REQUEST = Struct("probe_request", UBInt8("version"), UBInt8("type"),
                       UBInt32("length"), UBInt32("seq"), Bytes("wtp", 6),
                       Bytes("sta", 6), Bytes("hwaddr", 6), UBInt8("channel"),
                       UBInt8("band"), UBInt8("supported_band"),
                       Bytes("ssid", lambda ctx: ctx.length - 31))

PROBE_RESPONSE = Struct("probe_response", UBInt8("version"), UBInt8("type"),
Esempio n. 28
0
class Bitmap(FixedObjectByteArray):
    classID = 13
    _construct = Struct(
        "",
        UBInt32("length"),
        construct.String("items", lambda ctx: ctx.length * 4),
        # Identically named "String" class -_-
    )

    @classmethod
    def from_value(cls, obj):
        return cls(obj.items)

    def to_value(self):
        value = self.value
        length = (len(value) + 3) / 4
        value += "\x00" * (length * 4 - len(value))  # padding
        return Container(items=value, length=length)

    _int = Struct(
        "int",
        UBInt8("_value"),
        If(
            lambda ctx: ctx._value > 223,
            IfThenElse(
                "", lambda ctx: ctx._value <= 254,
                Embed(
                    Struct(
                        "",
                        UBInt8("_second_byte"),
                        Value(
                            "_value", lambda ctx:
                            (ctx._value - 224) * 256 + ctx._second_byte),
                    )), Embed(Struct(
                        "",
                        UBInt32("_value"),
                    )))),
    )

    _length_run_coding = Struct(
        "",
        Embed(_int),  #ERROR?
        Value("length", lambda ctx: ctx._value),
        OptionalGreedyRepeater(
            Struct(
                "data",
                Embed(_int),
                Value("data_code", lambda ctx: ctx._value % 4),
                Value("run_length", lambda ctx:
                      (ctx._value - ctx.data_code) / 4),
                Switch(
                    "", lambda ctx: ctx.data_code, {
                        0:
                        Embed(
                            Struct(
                                "",
                                StrictRepeater(
                                    get_run_length,
                                    Value("pixels",
                                          lambda ctx: "\x00\x00\x00\x00")),
                            )),
                        1:
                        Embed(
                            Struct(
                                "",
                                Bytes("_b", 1),
                                StrictRepeater(
                                    get_run_length,
                                    Value("pixels", lambda ctx: ctx._b * 4),
                                ),
                            )),
                        2:
                        Embed(
                            Struct(
                                "",
                                Bytes("_pixel", 4),
                                StrictRepeater(
                                    get_run_length,
                                    Value("pixels", lambda ctx: ctx._pixel),
                                ),
                            )),
                        3:
                        Embed(
                            Struct(
                                "",
                                StrictRepeater(
                                    get_run_length,
                                    Bytes("pixels", 4),
                                ),
                            )),
                    }),
            )))

    @classmethod
    def from_byte_array(cls, bytes_):
        """Decodes a run-length encoded ByteArray and returns a Bitmap.
        The ByteArray decompresses to a sequence of 32-bit values, which are
        stored as a byte string. (The specific encoding depends on Form.depth.)
        """
        runs = cls._length_run_coding.parse(bytes_)
        pixels = (run.pixels for run in runs.data)
        data = "".join(itertools.chain.from_iterable(pixels))
        return cls(data)

    def compress(self):
        """Compress to a ByteArray"""
        raise NotImplementedError
Esempio n. 29
0
from empower.core.app import EmpowerApp
from empower.datatypes.etheraddress import EtherAddress
from empower.core.vbs import Cell
from empower.vbsp.vbspserver import ModuleVBSPWorker
from empower.core.module import ModuleTrigger
from empower.vbsp import PT_VERSION
from empower.vbsp import E_TYPE_TRIG
from empower.vbsp import EP_DIR_REQUEST
from empower.vbsp import EP_OPERATION_ADD

from empower.main import RUNTIME

EP_ACT_MAC_REPORTS = 0x06

MAC_REPORTS_REQ = Struct("mac_reports_req", UBInt8("type"), UBInt8("version"),
                         UBInt32("enbid"), UBInt16("cellid"), UBInt32("modid"),
                         UBInt16("length"), UBInt32("seq"), UBInt8("action"),
                         UBInt8("dir"), UBInt8("op"), UBInt16("deadline"))

MAC_REPORTS_RESP = Struct("mac_reports_resp", UBInt8("DL_prbs_total"),
                          UBInt8("DL_prbs_in_use"), UBInt16("DL_prbs_avg"),
                          UBInt8("UL_prbs_total"), UBInt8("UL_prbs_in_use"),
                          UBInt16("UL_prbs_avg"))


class MACReports(ModuleTrigger):
    """ LVAPStats object. """

    MODULE_NAME = "mac_reports"
    REQUIRED = ['module_type', 'worker', 'tenant_id', 'cell', 'deadline']
Esempio n. 30
0
from construct import SBInt8, SBInt16, SBInt32, SBInt64
from construct import BFloat32, BFloat64
from construct import BitStruct, BitField

DUMP_ALL_PACKETS = False

# Our tricky Java string decoder.
# Note that Java has a weird encoding for the NULL byte which we do not
# respect or honor since no client will generate it. Instead, we will get two
# NULL bytes in a row.
AlphaString = functools.partial(PascalString,
                                length_field=UBInt16("length"),
                                encoding="utf8")

# Flying, position, and orientation, reused in several places.
grounded = Struct("grounded", UBInt8("grounded"))
position = Struct("position", BFloat64("x"), BFloat64("y"), BFloat64("stance"),
                  BFloat64("z"))
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"),