Skip to content

Instantly share code, notes, and snippets.

@berdario
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save berdario/cc83de66f0f2dd261065 to your computer and use it in GitHub Desktop.
Save berdario/cc83de66f0f2dd261065 to your computer and use it in GitHub Desktop.
from math import ceil
from collections import namedtuple
def calc_bitmasks(bitlengths):
size = sum(bitlengths)
assert size % 8 == 0
assert all(x < 65 for x in bitlengths)
remaining = size
for x in bitlengths:
remaining -= x
yield int(x * '1' + remaining * '0', 2), remaining
def parse_struct(struct, bytez):
val = int.from_bytes(bytez, byteorder='big')
return struct(*(((val & mask) >> shift ).to_bytes(l, byteorder='big')
for mask, l, shift in
zip(struct.bitmasks, struct.fieldlengths, struct.bitshifts)))
def get_bitstruct(structname, fieldnames, bitlengths):
s = namedtuple(structname, 'body_size header_size content_type content_sub_type')
assert len(s._fields) == len(bitlengths)
s.fieldlengths = tuple(ceil(x / 8) for x in bitlengths)
s.bitmasks, s.bitshifts = list(zip(*calc_bitmasks(bitlengths)))
return s
if __name__ == '__main__':
Header = get_bitstruct('Header',
'body_size header_size content_type content_sub_type',
(28, 13, 6, 9))
bytez = ['\x00','\x05','\x11','\x90','\x00','\x04','\x01']
bytez = bytes(map(ord, bytez)) # convert bytez to the proper type
print(parse_struct(Header, bytez))
import pytest
from _7byteproto import get_bitstruct, parse_struct
@pytest.yield_fixture()
def header_struct():
bitlengths = (28, 13, 6, 9)
Header = get_bitstruct('Header',
'body_size header_size content_type content_sub_type',
bitlengths)
yield bitlengths, Header
def test_sane(header_struct):
bl, Header = header_struct
bytez = b'\x00\x05\x11\x90\x00\x04\x01'
val = bin(int.from_bytes(bytez, byteorder='big'))[2:].rjust(sum(bl), '0')
h1 = parse_struct(Header, bytez)
val2 = ''.join(bin(int.from_bytes(field, byteorder='big'))[2:].rjust(x, '0')
for field, x in zip(h1, bl))
assert val == val2
def test_parse_twice(header_struct):
bl, Header = header_struct
bytez = b'\x00\x05\x11\x90\x00\x04\x01'
h1 = parse_struct(Header, bytez)
h2 = parse_struct(Header, bytez)
assert h1 == h2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment