Stream manipulation


Certain constructs are available only for seekable or tellable streams (in-memory and files). Sockets and pipes do not support neither, so you’ll have to first read the data from the stream and parse it in-memory, or use experimental Rebuffered wrapper.

Field wrappers

Pointer allows for non-sequential construction. The pointer first moves the stream into new position, does the construction, and then restores the stream back to original position. This allows for random-access within the stream.

>>> d = Pointer(8, Bytes(1))
>>> d.parse(b"abcdefghijkl")

Peek parses a field but restores the stream position afterwards (it does peeking). Building does nothing, it does NOT defer to subcon.

>>> d = Sequence(Peek(Int8ub), Peek(Int16ub))
>>> d.parse(b"\x01\x02")
[1, 258]
>>> d.sizeof()

Pure side effects

Seek makes a jump within the stream and leaves it there, for other constructs to follow up from that location. It does not read or write anything to the stream by itself.

>>> d = (Bytes(10) >> Seek(5) >> Byte)
>>>[b"0123456789", None, 255])

Tell checks the current stream position and returns it. The returned value gets automatically inserted into the context dictionary. It also does not read or write anything to the stream by itself.

>>> d = Struct("num"/VarInt, "offset"/Tell)
>>> d.parse(b"X")

Other fields

Pass literally does nothing. It can be useful as default case in Switch, its also used internally by If(IfThenElse) and Padding(Padded).

>>> Pass.parse(b"")
>>> Pass.sizeof()

Terminated only works during parsing. It checks if the stream reached EOF and raises error if not.

>>> Terminated.parse(b"")
>>> Terminated.parse(b"remaining")
construct.core.TerminatedError: expected end of stream