2.1. Public API Interfaces

class namedstruct.typedef

Base class for type definitions. Types defined with nstruct, prim, optional, bitfield all have these interfaces.

__call__(*args, **kwargs)

Same as new()

__getitem__(size)

Same as array(size), make it similar to C/Java type array definitions. It is worth to notice that the array is in column order, unlike in C. For example, uint16[3][4] is a list with 4 elements, each is a list of 3 uint16. uint16[5][0] is a variable length array, whose elements are lists of 5 uint16.

__weakref__

list of weak references to the object (if defined)

array(size)

Create an array type, with elements of this type. Also available as indexer([]), so mytype[12] creates a array with fixed size 12; mytype[0] creates a variable size array. :param size: the size of the array, 0 for variable size array.

create(buffer)

Create a object from all the bytes. If there are additional bytes, they may be fed greedily to a variable length type, or may be used as “extra” data. :param buffer: bytes of a packed struct. :returns: an object with exactly the same bytes when packed. :raises: BadFormatError or BadLenError if the bytes cannot completely form this type.

formatdump(dumpvalue, v)

Format the dumpvalue when dump() is called with humanread = True

Parameters:
  • dumpvalue – the return value of dump() before formatting.
  • v – the original data
Returns:

return a formatted version of the value.

inline()

Returns whether this type can be “inlined” into other types. If the type is inlined into other types, it is splitted and re-arranged to form a FormatParser to improve performance. If not, the parser is used instead. :returns: None if this type cannot be inlined; a format definition similar to FormatParser if it can.

isextra()

Returns whether this type can take extra data. For example, a variable size array will be empty when parsed, but will have elements when fed with extra data (like when create() is called)

new(*args, **kwargs)

Create a new object of this type. It is also available as __call__, so you can create a new object just like creating a class instance: a = mytype(a=1,b=2)

Parameters:
  • args – Replace the embedded struct type. Each argument is a tuple (name, newtype). It is equivalent to call _replace_embedded_type with name and newtype one by one. Both the “directly” embedded struct and the embedded struct inside another embedded struct can be set. If you want to replace an embedded struct in a replaced struct type, make sure the outer struct is replaced first. The embeded struct type must have a name to be replaced by specify name option.
  • kwargs – extra key-value arguments, each one will be set on the new object, to set value to the fields conveniently.
Returns:

a new object, with the specified “kwargs” set.

parse(buffer)

Parse the type from specified bytes stream, and return the first one if exists.

Parameters:buffer – bytes from a stream, may contains only part of the struct, exactly one struct, or additional bytes after the struct.
Returns:None if the data is incomplete; (data, size) else, where data is the parsed data, size is the used bytes length, so the next struct begins from buffer[size:]
parser()

Get parser for this type. Create the parser on first call.

tobytes(obj)

Convert the object to packed bytes. If the object is a NamedStruct, it is usually obj._tobytes(); but it is not possible to call _tobytes() for primitive types.

vararray()

Same as array(0)

class namedstruct.nstruct(*members, **arguments)

Generic purpose struct definition. Struct is defined by fields and options, for example:

mystruct = nstruct((uint32, 'a'),
                    (uint16[2], 'b'),
                    (mystruct2,'c'),
                    (uint8,),
                    (mystruct3,),
                    name = 'mystruct')

uint32, uint16, uint8 are standard types from stdprim. uint16[2] creates an array type with fixed size of 2. Field names must be valid attribute names, and CANNOT begin with ‘_’, because names begin with ‘_’ is preserved for internal use. The defined struct is similar to C struct:

typedef struct{
    int a;
    short b[2];
    struct mystruct2 c;
    char _padding;
    struct mystruct3;
} mystruct;

A struct is in big-endian (network order) by default. If you need a little-endian struct, specify endian option to ‘<’ and use little-endian version of types at the same time:

mystruct_le = nstruct((uint32_le, 'a'),
                    (uint16_le[2], 'b'),
                    (mystruct2_le,'c'),
                    (uint8_le,),
                    (mystruct3_le,),
                    name = 'mystruct_le',
                    endian = '<')

Fields can be named or anonymous. Following rules are applied: - A named field parses a specified type and set the result to attribute with the specified name

  • A anonymous struct field embeds the struct into this struct: every attribute of the embedded struct can be accessed from the parent struct, and every attribute of parent struct can also be accessed from the embedded struct.
  • Any anonymous primitive types act as padding bytes, so there is not a specialized padding type
  • Anonymous array is not allowed.

Structs are aligned to 8-bytes (*padding* = 8) boundaries by default, so if a struct defines fields of only 5 bytes, 3 extra padding bytes are appended to the struct automatically. The struct is always padded to make the size multiplies of “padding” even if it contains complex sub-structs or arrays, so it is more convenient than adding padding bytes to definitions. For example, if a struct contains a variable array of 7-bytes size data type, you must add 1 byte when the variable array has only one element, and add 2 bytes when the variable array has two elements. The alignment (padding) can be adjusted with padding option. Specify 4 for 4-bytes (32-bit) alignment, 2 for 2-bytes (16-bit), etc. Specify 1 for 1-bytes alignment, which equals to disable alignment.

Structs can hold more bytes than the size of defined fields. A struct created with create() takes all the input bytes as part of the struct. The extra bytes are used in variable length data types, or stored as “extra” data to serve automatic sub-class.

A variable length data type is a kind of data type whose size cannot be determined by itself. For example, a variable array can have 0 - infinite elements, and the actual size cannot be determined by the serialized bytes. If you merge multiple variable arrays into one bytes stream, the boundary of each array disappears. These kinds of data types usually can use as much data as possible. A struct contains a variable length data type as the last field type is also variable length. For example:

varray = nstruct((uint16, 'length'),
                (mystruct[0], 'structs'),
                name = 'varray')

When use parse() to parse from a bytes stream, the length of “structs” array is always 0, because parse() takes bytes only when they are ensured to be part of the struct. When use create() to create a struct from bytes, all the following bytes are parsed into “structs” array, which creates a array with correct length.

Usually we want to be able to unpack the packed bytes and get exactly what are packed, so it is necessary to have a way to determine the struct size, for example, from the struct size stored in a field before the variable size part. Set size option to a function to retrieve the actual struct size:

varray2 = nstruct((uint16, 'length'),
                  (mystruct[0], 'structs'),
                  name = 'varray2',
                  size = lambda x: x.length,
                  prepack = packrealsize('length')
                  )

When this struct is parsed from a bytes stream, it is parsed in three steps: - A first parse to get the non-variable parts of the struct, just like what is done when size is not set

  • size function is called on the parsed result, and returns the struct size
  • A second parse is done with the correct size of data, like what is done with create()

Usually the size function should return “real” size, which means size without the padding bytes at the end of struct, but it is usually OK to return the padded size. Variable length array ignores extra bytes which is not enough to form a array element. If the padding bytes are long enough to form a array element, the parsed result may contain extra empty elements and must be processed by user.

The prepack option is a function which is executed just before pack, so the actual size is automatically stored to ‘length’ field. There is no need to care about the ‘length’ field manually. Other processes may also be done with prepack option.

A struct without variable length fields can also have the size option to preserve data for extension. The bytes preserved are called “extra” data and stored in “_extra” attribute of the parsed result. You may use the “extra” data with _getextra() and _setextra() interface of the returned NamedStruct object. On packing, the “extra” data is appended directly after the last field, before the “padding” bytes, and counts for struct size, means the “extra” data is preserved in packing and unpacking:

base1 = nstruct((uint16, 'length'),
                (uint8, 'type'),
                (uint8,),
                name = 'base1',
                size = lambda x: x.length,
                prepack = packrealsize('length'))

The extra data can be used in sub-class. A sub-classed struct is a struct begins with the base struct, and use the “extra” data of the base struct as the data of the extended fields. It works like the C++ class derive:

child1 = nstruct((uint16, 'a1'),
                (uint16, 'b1'),
                base = base1,
                criteria = lambda x: x.type == 1,
                init = packvalue(1, 'type'),
                name = 'child1')
child2 = nstruct((uint8, 'a2'),
                (uint32, 'b2'),
                base = base1,
                criteria = lambda x: x.type == 2,
                init = packvalue(2, 'type'),
                name = 'child2')

A “child1” struct consists of a uint16 ‘length’, a uint8 ‘type’, a uint8 padding byte, a uint16 ‘a1’, a uint16 ‘b1’; the “child2” struct consists of a uint16 ‘length’, a uint8 ‘type’, a uint8 padding byte, a uint8 ‘a2’, a uint32 ‘b2’, and 7 padding bytes (to make the total size 16-bytes).

criteria option determines when will the base class be sub-classed into this type. It is a function which takes the base class parse result as the paramter, and return True if the base class should be sub-classed into this type. init is the struct initializer. When create a new struct with new(), all fields will be initialized to 0 if init is not specified; if init is specified, the function is executed to initialize some fields to a pre-defined value. Usually sub-classed types need to initialize a field in the base class to identity the sub-class type, so it is common to use init together with criteria.

The packed bytes of both “child1” and “child2” can be parsed with type “base1”. The parsing is done with the following steps: - base1 is parsed, size is executed and extra data is stored in “_extra” attribute

  • every criteria of sub-class types is executed until one returns True
  • extended fields of the sub-class struct is created with “extra” data of base1, and the _extra attribute is removed, just like create() on a struct without base class.
  • if none of the criteria returns True, the base1 struct is unchanged.

If there are a lot of sub-class types, executes a lot of criteria is a O(n) procedure and is not very efficient. The base class may set classifier option, which is executed and returns a hashable value. The sub-class type set classifyby option, which is a tuple of valid values. If the return value of classifier matches any value in classifyby, the base class is sub-classed to that type. The procedure is O(1).

The size of a sub-classed type is determined by the base type. If the base type has no “extra” bytes, it cannot be sub-classed. If the base type does not have a size option, it is not possible to parse the struct and sub-class it from a bytes stream. But it is still possible to use create() to create the struct and automatically sub-class it. It is useless to set size option on a struct type with base type, though not harmful. prepack can still be used, and will be executed in base first, then the sub-class type.

If there are still bytes not used by the sub-class type, they are stored as the “extra” data of the sub-class type, so the sub-class type can be sub-classed again. Also _getextra and _setextra can be used.

Every time a base class is parsed, the same steps are done, so it is possible to use a base class as a field type, or even a array element type:

base1array = nstruct((uint16, 'length'),
                    (base1[0], 'items'),
                    size = lambda x: x.length,
                    prepack = packrealsize('length'),
                    name = 'base1array')

The base1array type can take any number of child1 and child2 in “items” with any order, even if they have different size.

It is often ambiguous for a struct with additional bytes: they can be “extra” data of the struct itself, or they can be “extra” data of last field. Set lastextra option to strictly specify how they are treated. When lastextra is True, the “extra” data is considered to be “extra” data of last field if possible; when lastextra is False, the “extra” data is considered to be “extra” data of the struct itself. If nether is specified (or set None), the lastextra is determined by following rules:

  • A type is a variable length type if isextra of the type returns True. In particular, variable length arrays, raw bytes(raw, varchr) are variable length types.

  • A struct type is a variable length type if all the following criterias met:
    • it does not have a base type
    • it does not have a size option
    • lastextra is True (either strictly specified or automatically determined)
  • If the last field can be “inlined” (see option inline), lastextra is False (even if you strictly specify True)

  • The struct lastextra is True if the last field of the struct is a variable length type

In summary, a struct lastextra is True if the last field is variable length, and itself is also variable length if no base or size is specified. For complicated struct definitions, you should consider strictly specify it. A struct with lastextra = True cannot have sub-class types since it does not have “extra” bytes.

A simple enough struct may be “inlined” into another struct to improve performance, which means it is splitted into fields, and merged to another struct which has a field of this type. Option inline controls whether the struct should be “inlined” into other structs. By default, inline is automatically determined by the number of fields. Types with base, size, prepack, or init set will not be inlined. You should strictly specify inline = False when: - A inner struct has different endian with outer struct - The struct is a base type but size is not defined

formatter and extend options have effect on human readable dump result. When you call dump() on a NamedStruct, or a value with a NamedStruct inside, and specify humanread = True, the dump result is converted to a human readable format. The formatter option is a function which takes the dump result of this struct (a dictionary) as a parameter. The fields in the dump result are already formatted by the type definitions. the formatter should modify the dump result and return the modified result. The formatter option is not inherited to sub-classed types, so if the struct is sub-classed, the formatter is not executed. The formatter option will not be executed in a embedded struct, because the struct shares data with the parent struct and cannot be formatted itself.

extend is another method to modify the output format. If a type defines a “formatter” method, it is used by the parent struct when a struct with fields of this type is formatted. The “formatter” method only affects fields in structs because a primitive value (like a integer) does not have enough information on the original type. You may add customized formatters to a custom type:

uint32_hex = prim('I', 'uint32_hex')
uint32_hex.formatter = lambda x: ('0x%08x' % (x,))    # Convert the value to a hex string

When a field of this type is defined in a struct, the dump result will be formatted with the “formatter”. Elements of an array of this type is also formatted by the “formatter”. Notice that an array type can also have a “formatter” defined, in that case the elements are first formatted by the inner type “formatter”, then a list of the formatted results are passed to the array “formatter” to format the array as a whole. enum types and some pre-defined types like ip_addr, mac_addr have defined their own “formatter”s.

extend overrides the “formatter” of specified fields. extend option is a dictionary, whose keys are field names, or tuple of names (a property path). The values are data types, instances of nstruct, enum or any other subclasses of typedef. If the new data type has a “formatter”, the original formatter of that type is replaced by the new formatter i.e. the original formatter is NOT executed and the new formatter will execute with the original dump result. It is often used to override the type of a field in the base type. For example, a base type defineds a “flags” field but the format differs in every sub-classed type, then every sub-classed type may override the “flags” field to a different enum to show different result. If the extend type does not have a formatter defined, the original formatter is NOT replaced. Add a formatter which does not modify the result i.e. (lambda x: x) to explicitly disable the original formatter.

It is also convenient to use extend with array fields. The “formatter” of array element are overridden to the new element type of the extended array type. If a “formatter” is defined on the array, it also overrides the original array “formatter”.

You may also override fields of a named field or anonymous field. Specify a key with a tuple like (f1, f2, f3...) will override the field self.f1.f2.f3. But notice that the original formatter is only replaced if the struct is “inlined” into this struct. If it is not, the formatter cannot be replaced since it is not part of the “formatting procedure” of this struct. For named fields, the original formatter is executed before the extended formatter; for anonymous fields, the original formatter is executed after the extended formatter. It is not assured that this order is kept unchanged in future versions. If the original type does not have a formatter, it is safe to extend it at any level.

The extend options are inherited by the sub-classed types, so a sub-classed struct will still use the extend option defined in the base class. If the sub-classed type overrides a field again with extend option, the corresponding override from the base class is replaced again with the formatter from the sub-classed type.

The overall formatting procedure of a struct is in this order:

  1. Dump result of every field (including fields of base type, fields of embedded structs) is calculated. If the field value is a struct, the struct formatting is the same as this procedure.
  2. Fields defined in this struct (including fields of base type, excluding fields of embedded structs) is formatted with the “formatter”, either from the original type or from the extend type. If any descendant fields are extended with extend, they are also formatted.
  3. Embedded structs are formatted like in 2 i.e. fields with “formatter” and fields in extend are formatted.
  4. formatter is executed if it is defined in the struct type.

Structs may also define “formatter” like other types, besides the formatter option. It is useful in embedded structs because the formatter of embedded struct is not executed. But it is only executed when it is contained in another struct either named or embedded, like in other types.

Exceptions in formatters are always ignored. A debug level information is logged with logging module, you may enable debug logging to view them.

__init__(*members, **arguments)

nstruct initializer, create a new nstruct type

Parameters:
  • members – field definitions, either named or anonymous; named field is a tuple with 2 members (type, name); anonymous field is a tuple with only 1 member (type,)
  • arguments

    optional keyword arguments, see nstruct docstring for more details:

    size
    A function to retrieve the struct size
    prepack
    A function to be executed just before packing, usually used to automatically store the struct size to a specified field (with packsize() or packrealsize())
    base
    This type is a sub-class type of a base type, should be used with criteria and/or classifyby
    criteria
    A function determines whether this struct (of base type) should be sub-classed into this type
    endian
    Default to ‘>’ as big endian or “network order”. Specify ‘<’ to use little endian.
    padding
    Default to 8. The struct is automatically padded to align to “padding” bytes boundary, i.e. padding the size to be ((_realsize + (padding - 1)) // padding). Specify 1 to disable alignment.
    lastextra
    Strictly specify whether the unused bytes should be considered to be the “extra” data of the last field, or the “extra” data of the struct itself. See nstruct docstring for more details.
    name
    Specify a readable struct name. It is always recommended to specify a name. A warning is generated if you do not specify one.
    inline
    Specify if the struct can be “inlined” into another struct. See nstruct docstring for details.
    init
    initializer of the struct, executed when a new struct is created with new()
    classifier
    defined in a base class to get a classify value, see nstruct docstring for details
    classifyby
    a tuple of hashable values. The values is inserted into a dictionary to quickly find the correct sub-class type with classify value. See nstruct docstring for details.
    formatter
    A customized function to modify the human readable dump result. The input parameter is the current dump result; the return value is the modified result, and will replace the current dump result.
    extend
    Another method to modify the human readable dump result of the struct. It uses the corresponding type to format the specified field, instead of the default type, e.g. extend a uint16 into an enumerate type to show the enumerate name; extend a 6-bytes string to mac_addr_bytes to format the raw data to MAC address format, etc.
class namedstruct.enum(readablename=None, namespace=None, basefmt='I', bitwise=False, **kwargs)

Enumerate types are extensions to standard primitives. They are exactly same with the base type, only with the exception that when converted into human readable format with dump(), they are converted to corresponding enumerate names for better readability:

myenum = enum('myenum', globals(), uint16,
                MYVALUE1 = 1,
                MYVALUE2 = 2,
                MYVALUE3 = 3)

To access the defined enumerate values:

v = myenum.MYVALUE1            # 1

When globals() is specified as the second parameter, the enumerate names are exported to current module, so it is also accessible from module globals():

v = MYVALUE2    # 2

If you do not want to export the names, specify None for namespace parameter.

A enumerate type can be bitwise, or non-bitwise. Non-bitwise enumerate types stand for values exactly matches the enumerate values. When formatted, they are converted to the corresponding enumerate name, or keep unchanged if there is not a corresponding name with that value. Bitwise enumerate types stand for values that are bitwise OR (|) of zero, one or more enumerate values. When a bitwise enumerate value is formatted, it is formatted like the following example:

mybitwise = enum('mybitwise', globals(), uint16, True,
                A = 0x1,
                B = 0x2,
                C = 0x4,
                D = 0x8,
# It is not necessary (though common) to have only 2-powered values. Merge of two or more
# values may stand for a special meaning.
                E = 0x9)

# Formatting:
# 0x1 -> 'A'
# 0x3 -> 'A B'
# 0x8 -> 'D'
# 0x9 -> 'E'    (prefer to match more bits as a whole)
# 0xb -> 'B E'
# 0x1f -> 'B C E 0x10' (extra bits are appended to the sequence in hex format)
# 0x10 -> '0x10'
# 0x0 -> 0      (0 is unchanged)
__contains__(item)

Test whether a value is defined.

__init__(readablename=None, namespace=None, basefmt='I', bitwise=False, **kwargs)

Initializer :param readablename: name of this enumerate type

Parameters:
  • namespace – A dictionary, usually specify globals(). The kwargs are updated to this dictionary, so the enumerate names are exported to current globals and you do not need to define them in the module again. None to disable this feature.
  • basefmt – base type of this enumerate type, can be format strings or a prim type
  • bitwise – if True, the enumerate type is bitwise, and will be formatted to space-separated names; if False, the enumerate type is non-bitwise and will be formatted to a single name.
  • kwargs – ENUMERATE_NAME = ENUMERATE_VALUE format definitions of enumerate values.
astype(primtype, bitwise=False)

Create a new enumerate type with same enumerate values but a different primitive type e.g. convert a 16-bit enumerate type to fit in a 32-bit field. :param primtype: new primitive type :param bitwise: whether or not the new enumerate type should be bitwise

extend(namespace=None, name=None, **kwargs)

Create a new enumerate with current values merged with new enumerate values :param namespace: same as __init__ :param name: same as __init__ :param kwargs: same as __init__ :returns: a new enumerate type

formatter(value)

Format a enumerate value to enumerate names if possible. Used to generate human readable dump result.

getDict()

Returns a dictionary whose keys are enumerate names, and values are corresponding enumerate values.

getName(value, defaultName=None)

Get the enumerate name of a specified value. :param value: the enumerate value :param defaultName: returns if the enumerate value is not defined :returns: the corresponding enumerate value or defaultName if not found

getValue(name, defaultValue=None)

Get the enumerate value of a specified name. :param name: the enumerate name :param defaultValue: returns if the enumerate name is not defined :returns: the corresponding enumerate value or defaultValue if not found

importAll(gs)

Import all the enumerate values from this enumerate to gs :param gs: usually globals(), a dictionary. At lease __setitem__ should be implemented if not a dictionary.

merge(otherenum)

Return a new enumerate type, which has the same primitive type as this type, and has enumerate values defined both from this type and from otherenum :param otherenum: another enumerate type :returns: a new enumerate type

tostr(value)

Convert the value to string representation. The formatter is first used, and if the return value of the formatter is still a integer, it is converted to string. Suitable for human read represent. :param value: enumerate value :returns: a string represent the enumerate value

class namedstruct.bitfield(basetype, *properties, **arguments)

bitfield are mini-struct with bit fields. It splits a integer primitive type like uint32 to several bit fields. The splitting is always performed with big-endian, which means the fields are ordered from the highest bits to lowest bits. Base type endian only affects the bit order when parsing the bytes to integer, but not the fields order. Unlike bit-fields in C/C++, the fields does not need to be aligned to byte boundary, and no padding between the fields unless defined explicitly. For example:

mybit = bitfield(uint64,
                (4, 'first'),
                (5, 'second'),
                (2,),    # Padding bits
                (19, 'third'),    # Can cross byte border
                (1, 'array', 20), # A array of 20 1-bit numbers
                name = 'mybit',
                init = packvalue(2, 'second'),
                extend = {'first': myenum, 'array': myenum2[20]})
__init__(basetype, *properties, **arguments)

Initializer :param basetype: A integer primitive type to provide the bits

Parameters:
  • properties – placed arguments, definitions of fields. Each argument is a tuple, the first element is the bit-width, the second element is a field name. If a third element appears, the field is an bit-field array; if the second element does not appear, the field is some padding bits.
  • arguments

    keyword options

    name
    the type name
    init
    a initializer to initialize the struct
    extend
    similar to extend option in nstruct
    formatter
    similar to formatter option in nstruct
    prepack
    similar to prepack option in nstruct
class namedstruct.optional(basetype, name, criteria, prepackfunc=None)

Create a “optional” field in a struct. On unpacking, the field is only parsed when the specified criteria is met; on packing, the field is only packed when it appears (hasattr returns True). This function may also be done with sub-classing, but using optional is more convenient:

myopt = nstruct((uint16, 'data'),
                (uint8, 'hasextra'),
                (optional(uint32, 'extra', lambda x: x.hasextra),),
                name = 'myopt',
                prepack = packexpr(lambda x: hasattr(x, 'extra'), 'hasextra'))
  • A optional type is placed in an anonymous field. In fact it creates an embedded struct with only one (optional) field.
  • The criteria can only use fields that are defined before the optional field because the other fields are not yet parsed.
  • Usually you should specify a prepack function to pack some identifier into the struct to identify that the optional field appears.
  • The optional field does not exists when the struct is created with new(). Simply set a value to the attribute to create the optional field: myopt(data = 7, extra = 12)
  • The optional type is a variable length type if and only if the basetype is a variable length type
__init__(basetype, name, criteria, prepackfunc=None)

Initializer.

Parameters:
  • basetype – the optional field type
  • name – the name of the optional field
  • criteria – a function to determine whether the optional field should be parsed.
  • prepackfunc – function to execute before pack, like in nstruct
class namedstruct.darray(innertype, name, size, padding=1, prepack=None)

Create a dynamic array field in a struct. The length of the array is calculated by other fields of the struct. If the total size of the struct is stored, you should consider use size option and a variable length array (sometype[0]) as the last field, instead of calculating the array size yourself. If the array contains very simple elements like primitives, it may be a better idea to calculate the total size of the struct from the array length and return the size from size option, because if the data is incomplete, the parsing quickly stops without the need to parse part of the array. Only use dynamic array when: the bytes size of the array cannot be determined, but the element size of the array is stored:

myopt = nstruct((uint16, 'data'),
                (uint8, 'extrasize'),
                (darray(mystruct, 'extras', lambda x: x.extrasize),),
                name = 'myopt',
                prepack = packexpr(lambda x: len(x.extras), 'hasextra'))
  • A darray type is placed in an anonymous field. In fact it creates an embedded struct with only one field.
  • The size function can only use fields that are defined before the optional field because the other fields are not yet parsed.
  • Usually you should specify a prepack function to pack the array size into the struct
  • padding option is available if it is necessary to pad the bytes size of the whole array to multiply of padding
  • You can use extend with an array type (mystruct2[0]) to override the formatting of inner types or the whole array
__init__(innertype, name, size, padding=1, prepack=None)

Initializer.

Parameters:
  • innertype – type of array element
  • name – field name
  • size – a function to calculate the array length
  • padding – align the array to padding-bytes boundary, like in nstruct
  • prepack – prepack function, like in nstruct
class namedstruct.nvariant(name, header=None, classifier=None, prepackfunc=None, padding=1)

An nvariant struct is a specialized base for nstruct. Different from normal nstruct, it does not have size option, instead, its size is determined by subclassed structs.

A variant type can not be parsed with enough compatibility: if a new type of subclassed struct is not recognized, the whole data may be corrupted. It is not recommended to use this type for newly designed data structures, only use them to define data structures that: already exists; cannot be parsed by other ways.

__init__(name, header=None, classifier=None, prepackfunc=None, padding=1)

Initializer.

Parameters:
  • name – type name
  • header – An embedded type, usually an nstruct. It is embedded to the nvariant and parsed before subclassing.
  • classifier – same as nstruct
  • prepackfunc – same as nstruct
namedstruct.dump(val, humanread=True, dumpextra=False, typeinfo='flat')

Convert a parsed NamedStruct (probably with additional NamedStruct as fields) into a JSON-friendly format, with only Python primitives (dictionaries, lists, bytes, integers etc.) Then you may use json.dumps, or pprint to further process the result.

Parameters:
  • val – parsed result, may contain NamedStruct
  • humanread – if True (default), convert raw data into readable format with type-defined formatters. For example, enumerators are converted into names, IP addresses are converted into dotted formats, etc.
  • dumpextra – if True, dump “extra” data in ‘_extra’ field. False (default) to ignore them.
  • typeinfo

    Add struct type information in the dump result. May be the following values:

    DUMPTYPE_FLAT (‘flat’)
    add a field ‘_type’ for the type information (default)
    DUMPTYPE_KEY (‘key’)
    convert the value to dictionary like: {‘<struc_type>’: value}
    DUMPTYPE_NONE (‘none’)
    do not add type information
Returns:

“dump” format of val, suitable for JSON-encode or print.