Welcome, guest | Sign In | My Account | Store | Cart
import struct

def preargs(cls):
    def _pre_init(*args1, **kwargs1):
        def _my_init(*args2, **kwargs2):
            args = args1 + args2
            return cls(*args, **kwargs1)
        return _my_init
    return _pre_init

class BinaryMetaType(type):
    def __getitem__(self, val):
        return array(self, val)

class BinaryType(metaclass=BinaryMetaType):
    def __init__(self, **kwargs):
        self._kwargs = kwargs

    def to_binary(self, val):

    def from_binary(self, binary):

class SimpleBinaryType(BinaryType):
    def __init__(self, fmt):
        self._struct = struct.Struct(fmt)

    def to_binary(self, val):
        return self._struct.pack(val)

    def from_binary(self, binary):
        return (self._struct.size,

class array(BinaryType):
    def __init__(self, arrtype, arrlen, **kwargs):
        self._arrtype, self._arrlen = arrtype(**kwargs), arrlen

    def to_binary(self, val):
        res = []
        for i,v in enumerate(val):
            if i+1 == self._arrlen: break
        return b''.join(res)

    def from_binary(self, binary):
        res = []
        ssum = 0
        for i in range(self._arrlen):
            s,v = self._arrtype.from_binary(binary[ssum:])
            ssum += s
        return ssum, res

class dword(SimpleBinaryType):
    def __init__(self, **kwargs):
        super().__init__('I', **kwargs)

class char(SimpleBinaryType):
    def __init__(self, **kwargs):
        super().__init__('c', **kwargs)

class BinaryBuilder(dict):
    def __init__(self, **kwargs):
        self.members = []
        self._kwargs = kwargs

    def __setitem__(self, key, value):
        if key ==  '__module__': return
        if key not in self:
            self.members.append((key, value(**self._kwargs)))
        super().__setitem__(key, value)

class Binary(type):
    def __prepare__(*bases, **kwargs):
        # In the future kwargs can contain things such as endianity
        # and alignment
        return BinaryBuilder(**kwargs)

    def __new__(cls, name, bases, classdict):
        # There are nicer ways of doing this, but as a hack it works
        def fixupdict(d):
            def to_binary(clas, datadict):
                res = []
                for k,v in clas.members:
                return b''.join(res)

            def from_binary(cls, bytesin):
                res = {}
                ssum = 0
                for k,v in cls.members:
                    i, d = v.from_binary(bytesin[ssum:])
                    ssum += i
                    res[k] = d
                return ssum, res

            nd = {'to_binary': to_binary,
              'from_binary': from_binary,
              'members': d.members}
            return nd

        return super().__new__(cls, name, bases, fixupdict(classdict))

#### How one would use the above module

class BMP(metaclass=Binary):
    # The point was to try and get this C-like syntax
    bfType = char[2]
    bfSize = dword
    bfReserved = dword
    bfOffBits = dword

    {'bfType': 'BM',
     'bfSize': 2359350,
     'bfReserved': 0,
     'bfOffBits': 54}))