Container Fields

Generic List Fields

class pcapkit.corekit.fields.collections.ListField[_TL: (Schema, FieldBase, bytes)](length=lambda _: ..., item_type=None, callback=lambda *_: ..., count=-1)[source]

Bases: FieldBase[list[_TL]], Generic[_TL]

Field list for protocol fields.

Parameters:
  • length (int | Callable[[dict[str, Any]], int]) – Field size (in bytes); if a callable is given, it should return an integer value and accept the current packet as its only argument.

  • item_type (FieldBase | None) – Field type of the contained items.

  • callback (Callable[[Self, dict[str, Any]], None]) – Callback function to be called upon self.__call__.

  • count (int | Callable[[dict[str, Any]], int]) – Number of items a field before this one counts, for a list running to the end of the data; if a callable is given, it should return an integer value and accept the current packet as its only argument. A negative value, the default, counts none.

This field is used to represent a list of fields, as in the case of lists of constant-length-field items in a protocol.

A list whose octets hold fewer items than count ended with the data before the rest, and reports them as shortfall, so that Schema.unpack records the cut; the items absent are not made up. A schema item it counts is read with __data_end__ in its packet, since its octets end where the data does, so an item the data ends inside records the cut as its short read rather than warn that its fields run past the length it was given.

Changed in version 1.6.0: Takes count (#2711), and reads a schema item it counts as ending with the data (#2749).

property length: int

Field size.

property optional: bool

Field is optional.

property count: int

Number of items counted; negative where none are.

property shortfall: int

Number of the items counted that the octets last unpacked did not hold.

__call__(packet)[source]

Update field attributes.

Parameters:

packet (dict[str, Any]) – Packet data.

Return type:

Self

Returns:

Updated field instance.

This method will return a new instance of ListField instead of updating the current instance.

pack(value, packet)[source]

Pack field value into bytes.

Parameters:
Return type:

bytes

Returns:

Packed field value.

Without an item_type, unpack() returns the field’s octets as a single bytes, so such a value is written as-is rather than iterated item by item.

unpack(buffer, packet)[source]

Unpack field value from bytes.

Parameters:
Return type:

bytes | list[_TL]

Returns:

Unpacked field value.

Raises:

FieldValueError – If the items overrun the field, if a schema item consumes nothing from buffer, or if schema items short of the field’s length cannot be zero-filled.

When buffer falls short of the field’s length, the item it ends inside is read as though its missing octets were zeros, as FieldBase.unpack reads any other field, and the list ends with that item: none is read from past the data, which holds no octet of it. A __data_present__ key in packet says that buffer holds the data that many octets in, and past them the zeros an enclosing list of schema items was filled out with, as Schema.unpack tells the fields of the item the data ends inside; the list then ends with the data there.

A __zero_tail__ key in packet, true, says instead that the octets past buffer are zeros of the data, as radiotap.org reads the octets a producer leaves off a TLV item (#2655), so the list reads its items on through them to its length.

Changed in version 1.6.0: A list the data ends inside ends with the data, the item it ends inside read with its missing octets as zeros, where a schema item past the data was refused as consuming nothing and a plain value past it was read as zeros, and so does a list in an item the data ends inside (#2686, #2756, #2760).

_unpack_items(file, packet, is_schema, present=-1)[source]

Unpack the field’s items from file.

Parameters:
  • file (IO[bytes]) – Stream the items are read from.

  • packet (dict[str, Any]) – Packet data.

  • is_schema (bool) – Whether the items are schemas.

  • present (int) – Octets of file the data holds, past which file ends or holds zeros a fill made up; negative where it holds the data to the field’s length.

Return type:

list[_TL]

Returns:

Unpacked items.

Raises:

FieldValueError – If the items overrun the field, or if a schema item consumes nothing from file – see the note below.

Option List Fields

class pcapkit.corekit.fields.collections.OptionField[_TS: Schema](length=lambda _: ..., base_schema=None, type_name='type', registry=None, eool=None, callback=lambda *_: ...)[source]

Bases: ListField, Generic[_TS]

Field list for protocol options.

Parameters:
  • length (int | Callable[[dict[str, Any]], int]) – Field size (in bytes); if a callable is given, it should return an integer value and accept the current packet as its only argument.

  • base_schema (Type[_TS] | None) – Base schema for option fields.

  • type_name (str) – Name of the option type field.

  • registry (defaultdict[int | IntEnum | aenum.IntEnum, Type[_TS]] | None) – Option registry, as in a mapping from option types (enumeration values) to option schemas, with the default value being the unknown option schema.

  • eool (int | IntEnum | aenum.IntEnum | None) – Enumeration of the EOOL (end-of-option-list, or equivalent) option

  • callback (Callable[[Self, dict[str, Any]], None]) – Callback function to be called upon self.__call__.

This field is used to represent a list of fields, as in the case of lists of options and/or parameters in a protocol.

Note

self.unpack selects an option’s schema by reading the type_name field of base_schema alone off the front of the option, instead of unpacking the whole base schema and keeping only that one value. That is only the same read when the following hold of the type field:

  1. it is the base schema’s first field, so that it is what sits at the front of the option;

  2. it is a NumberField, so that Schema.unpack reads it through its ordinary per-field branch;

  3. its length is a fixed integer rather than a callable, so that its width does not depend on packet data the shortcut has not read.

All of that is true of every OptionField declared in this package. A base schema registered from outside it – cf. pcapkit.foundation.registry – need not satisfy it, and is not rejected: such a base schema is unpacked in full. It parses correctly and pays the cost of the second parse. Only the shortcut is withheld, so a base schema whose type field comes second cannot be silently misread.

property base_schema: Type[_TS]

Base schema.

property type_name: str

Type name.

property registry: defaultdict[int | IntEnum | aenum.IntEnum, Type[_TS]]

Option registry.

property eool: int | IntEnum | aenum.IntEnum

EOOL option.

property option_padding: int

Length of option padding data.

unpack(buffer, packet)[source]

Unpack field value from bytes.

Parameters:
Return type:

list[_TS]

Returns:

Unpacked field value.

Important

If the option list ended before the specified size limit, self.option_padding is set to the remaining length, which Schema.unpack records in packet as __option_padding__ so that the next fields can be aware of it.

A __capture_cut__ key in packet, false, says that the data ends at the length the enclosing layer declares for it, so that an area the data ends inside runs past that length rather than being cut short by the capture, as IPv6 tells the extension headers it walks (#2694). Absent, the data may end at a cut.

Raises:
  • FieldValueError – If an option consumes nothing from buffer, since the loop below has then no way to get past it.

  • ProtocolError – If an option that begins with octets present reads past the end of the data, unless the data ends inside the area, the option’s fields fit it and _accepts_cut() keeps it, or _accepts_short_read() accepts it. Or if the area runs past the end of the data where packet gives __capture_cut__ as false, the data ending at the length the enclosing layer declares rather than at a cut.

Changed in version 1.5.0: An option that begins with octets present and reads past the end of the data raises ProtocolError, where it was parsed from zero-filled octets (#1325).

Changed in version 1.6.0: Where the data ends inside the area, as a capture cut short leaves it, the list ends with the data, and an option it ends inside is kept if its fields fit the area, so Schema.unpack records the cut as a short read rather than either error being raised (#2694). See _accepts_cut(), and __capture_cut__ above.

_accepts_short_read(option)[source]

Whether an option that read past the end of the data may stand.

Parameters:

option (_TS) – Option just unpacked, which read short and ran past its area or past the data at the end of the area.

Return type:

bool

Returns:

False, so that unpack() refuses the option (#1325): padding cut short may be content the option’s own length declares, as a PadN option’s is. A list whose items’ lengths leave out their trailing padding may override this, as PaddedOptionField does; Schema.pack then writes back only the octets read.

_accepts_cut(option)[source]

Whether an option the data ends inside, inside its area, may stand.

Parameters:

option (_TS) – Option just unpacked, which read short where the data ends short of the area declared, and whose fields fit the area.

Return type:

bool

Returns:

True, so that unpack() keeps the option, as the short read Schema.unpack records (#2694). A list that keeps such an area as the octets captured instead may override this, as OptionAreaField does.

Type Variables

pcapkit.corekit.fields.collections._TL: pcapkit.protocols.schema.Schema | pcapkit.corekit.fields.field.FieldBase | bytes
pcapkit.corekit.fields.collections._TS: pcapkit.protocols.schema.Schema