Skip to content
This repository has been archived by the owner on Sep 1, 2021. It is now read-only.

MetaFiled requires length attribute to be present on build #18

Open
ruletko opened this issue Mar 1, 2012 · 3 comments
Open

MetaFiled requires length attribute to be present on build #18

ruletko opened this issue Mar 1, 2012 · 3 comments

Comments

@ruletko
Copy link

ruletko commented Mar 1, 2012

This is more like a question rather an issue. I'd expect MEtaField's related length fiekd to be autopopulated on building a structure, however this does not happen:

>>> from construct import *
>>> foo = Struct("foo",
... Byte("length"),
... MetaField("data", lambda ctx: ctx["length"])
... )

>>> foo.build(Container(data="test"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/pymodules/python2.6/construct/core.py", line 206, in build
    self.build_stream(obj, stream)
  File "/usr/lib/pymodules/python2.6/construct/core.py", line 214, in build_stream
    self._build(obj, stream, Container())
  File "/usr/lib/pymodules/python2.6/construct/core.py", line 662, in _build
    subobj = getattr(obj, sc.name)
AttributeError: 'Container' object has no attribute 'length'

Could you explain correct behavior?

@MostAwesomeDude
Copy link
Owner

Part of me wants to say "use a PascalString," but that's not a good long-term solution, is it? The problem is mostly that there's no indication of the dependency of length on data in this Struct, so Construct is a bit bamboozled about how to build this. PascalString gets it right though.

@ZiglioUK
Copy link

Interesting question, I haven't looked at PascalString yet to see how that works.
Haven't really had to do any serious 'building' yet, all parsing

@posborne
Copy link

In a library I created (not open sourced, unfortunately, as it is for my employer), I ended up doing the following. Unlike construct, the syntax for the DSL we ended up creating is more heavily metaclass based:

class PascalString(BaseMessage):
    length = LengthField(UBInt8())
    payload = VariableRawPayload(length)

Variable length fields require either a static length or a length_field parameter. These two are couple on message instances and I can pack a message with the correct length automatically:

>>> m = PascalString()
>>> m.payload = "Hello, world"
>>> m.pack()
"\x0cHello, World"

The invariant in our system is that when unpacking the length of the next field being unpacked must always be known immediately before it will be unpacked. In most cases this is the case. In other cases (for instance, a delimiter in a chunk) we currently just handle that outside of our library or create a special construct.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants