The number one sore spot for me when using construct is the absence of specifying that some field carries the size of the enclosing struct.
Consider this C struct:
struct header {
int magic;
int hdr_size;
int version_major;
int version_minor;
};
struct header_ext {
struct header hdr;
char name[30];
char surname[30];
};
the intention of struct header is that it can be extended.
if i want to parse it generically out of a stream, i'm currently writing something like this:
Header = c.Struct(
"_start" / c.Tell,
"magic" / c.Int32ul,
"hdr_size" / c.Int32ul,
"version_major" / c.Int32ul,
"version_minor" / c.Int32ul,
"_end" / c.Tell,
"trailing_data" / # the abomination!
c.Bytes(c.this.hdr_size - c.this._end + c.this._start)
)
but then I can't build that from scratch!
i can either
- hard-code that the size of the common prefix is, in this case, 16 bytes, which will break if i ever modify the common header
- say that
trailing_data is actually c.Default(c.Bytes(<the horrible expression>), b"\x00 * <the horrible expression>, then not provide the trailing data, set hdr_size to something big enough, read out the trailing data ......... blech
consider the alternative:
Header = c.Struct(
"magic" / c.Int32ul,
"hdr_size" / c.SizeOfSelf(c.Int32ul),
"version_major" / c.Int32ul,
"version_minor" / c.Int32ul,
"trailing_data" / c.GreedyBytes,
)
when parsing hdr_size, the parser will limit the current struct to hdr_size - <size of already parsed>, and raise if that ends up negative
and when building, the builder will just do what it does, then go back Pointer-like to the right place and write the final value
The number one sore spot for me when using construct is the absence of specifying that some field carries the size of the enclosing struct.
Consider this C struct:
the intention of
struct headeris that it can be extended.if i want to parse it generically out of a stream, i'm currently writing something like this:
but then I can't build that from scratch!
i can either
trailing_datais actuallyc.Default(c.Bytes(<the horrible expression>), b"\x00 * <the horrible expression>, then not provide the trailing data, sethdr_sizeto something big enough, read out the trailing data ......... blechconsider the alternative:
when parsing
hdr_size, the parser will limit the current struct tohdr_size - <size of already parsed>, and raise if that ends up negativeand when building, the builder will just do what it does, then go back
Pointer-like to the right place and write the final value