construct / construct

Construct: Declarative data structures for python that allow symmetric parsing and building
http://construct.readthedocs.org
Other
906 stars 153 forks source link

Question: how to get the subcontext length in an Adapter? #1072

Closed bradh closed 5 months ago

bradh commented 6 months ago

I am trying to build an Adapter to write out a number as a zero-padded string. As an example 2 (as an integer) becomes 0x30 0x32 (as bytes). The file format I'm working with (NITFS) does this in lots of places, so a re-usable adapter would be ideal.

I have this:

import construct

class NPI(construct.Adapter):
    def __init__(self, subcon, length):
        construct.Adapter.__init__(self, subcon)
        self.length = length

    def _decode(self, obj, context, path):
        # TODO
        pass

    def _encode(self, obj, context, path):
        return str(obj).zfill(self.length).encode('ascii')

class NitfFile:
    def writeFile(self):
        rootStructure = construct.Struct(
            "FHDR" / construct.Const(b"NITF"),
            "CLEVEL" / NPI(construct.Byte[2], length=2)
        )
        bytes = rootStructure.build(dict(CLEVEL=3))

(Minimised - the actual format is obviously larger).

The part I'd like to avoid is specifying the length twice in the NPI(construct.Byte[2], length=2) field. Its always going to be the same.

Is there a way to get the number of bytes within my Adapter? Or is there a better pattern to address this kind of concern?

(I also posted this at https://stackoverflow.com/questions/78054840/number-of-bytes-in-python-construct-subcontext - an answer there would be OK too).

jpsnyder commented 5 months ago

The wrapped construct can be pulled from self.subcon.

Since Byte[X] is an Array class you could pull from the .count variable.

str(obj).zfill(self.subcon.count).encode('ascii')
bradh commented 5 months ago

Thanks.