Parsing a string from a BitStruct

117 views
Skip to first unread message

sigusr

unread,
Nov 16, 2015, 7:41:12 AM11/16/15
to Construct
I am using the following code to parse incoming binary data.

from construct import BitStruct, BitField, Padding, String

struct = BitStruct("foo",
  BitField("bar", 8),
  BitField("baz", 16),
  Padding(4),
  BitField("bat", 4)
)

struct2 = BitStruct("foo",
  BitField("bar", 8),
  String("baz", 16),
  Padding(4),
  BitField("bat", 4)
)

data = "\x01AB\xCD"

print struct.parse(data)
print struct2.parse(data)

This prints the output:
Container:
    bar = 1
    baz = 16706
    bat = 13
Container:
    bar = 1
    baz = '\x00\x01\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x01\x00'
    bat = 13

I was expecting that String would give me back AB as an actual string. However it is returning the equivalent binary string instead.

How can I persuade construct to return me the actual ASCII string?

Thanks.

Chris Chow

unread,
Nov 16, 2015, 7:17:03 PM11/16/15
to Construct
I had a problem with this recently, and I solved it by using something like 

String('magic', 3, encoding='ascii')


instead of 

String("baz", 16)

sigusr

unread,
Nov 17, 2015, 2:44:39 AM11/17/15
to Construct
Unfortunately that doesn't seem to work either.  With a length of 2 the following exception is raised:

 File "C:\Python27\lib\site-packages\construct\macros.py", line 354, in resizer
    raise SizeofError("size must be a multiple of 8", length)
construct.core.SizeofError: ('size must be a multiple of 8', 18)

This makes sense because it's wrapped in a BitStruct.

Using encoding="ascii" with a 16 bit length coerces the string to unicode but doesn't change anything else - it's still a string representation of binary values.

David

Steven Michalske

unread,
Nov 17, 2015, 4:03:21 AM11/17/15
to const...@googlegroups.com
The BitStruct container works on bits.  I can see how the string representation of a sequence of bits is printed as that...  Not that I agree.  I would want your desired behavior.

You might need to use a union at the byte level for the string.

You might need to write a subclass of string to recompose the data.   Think 7bit ascii :-)
--
You received this message because you are subscribed to the Google Groups "Construct" group.
To unsubscribe from this group and stop receiving emails from it, send an email to construct3+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

sigusr

unread,
Nov 17, 2015, 6:04:58 PM11/17/15
to Construct
Thanks Steven - this pointed me along the right lines.  I ended up creating an adapter, a small successful test case looks like:

from binascii import hexlify
from construct import BitStruct, BitField, Padding, Array, Octet, Adapter

class BitStringAdapter(Adapter):
  def _encode(self, obj, context):
    return list(ord(b) for b in obj)
  def _decode(self, obj, context):
    return "".join(chr(b) for b in obj)


struct = BitStruct("foo",
  BitField("bar", 8),

  BitStringAdapter(Array(2, Octet("baz"))),

  Padding(4),
  BitField("bat", 4)
)

data = "\x01AB\xCD"


out = struct.parse(data)
print hexlify(struct.build(out))


I also documented this on Stackoverflow[1].

David

Arek Bulski

unread,
Sep 26, 2016, 10:38:26 AM9/26/16
to Construct
Look at new Bytewise wrapper. Should do it for ya.
Reply all
Reply to author
Forward
0 new messages