Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
115 lines (93 sloc) 3.81 KB
from construct import *
StrictRepeater = Array
from stuff import OConst, call
# note: structdefpatch.py is optional, but it allows everything but the actual pointer data to be omitted in the input
# to make this nicer, block and offset/size names ought to start with _, so they are also omitted in the output
# it should be correct on the second run if pointers are always before the corresponding data, but might require more if not.
class fakestream(object):
def __init__(self):
self.pos = 0
def write(self, obj):
self.pos += len(obj)
def tell(self):
return self.pos
class Nobody(object):
def __init__(self, name):
self.name = name
self.pdata = {}
self.ddata = None
self.offsetof = {}
# If the same BPointer is reused with the same object, we want to repeat the data if it's in an array, but not if this is another invocation of build*.
# We must act properly with a regular fakestream, but not a very fake stream.
self.stream = None
def __repr__(self):
return '<%r Nobody: %x>' % (self.name, hash(self))
def _getdata(self, idx):
if self.ddata is not None:
return self.ddata[idx]
else:
return 42
def getoffset(self):
return self._getdata(0)
def getsize(self):
return self._getdata(1)
class Block(Construct):
def __init__(self, name):
Construct.__init__(self, name)
#self.subcon = self.context = None
def _parse(self, stream, context):
return Nobody(self.name)
def _build(self, obj, stream, context):
assert isinstance(obj, Nobody)
def _getdefault(self, context):
return Nobody(self.name)
def _sizeof(self, context):
return 0
class BPointer(Pointer):
def __init__(self, nobodyfunc, offsetfunc, subcon):
Pointer.__init__(self, offsetfunc, subcon)
self.nobodyfunc = nobodyfunc
def _build(self, obj, stream, context):
nobody = self.nobodyfunc(context)
assert isinstance(nobody, Nobody)
if nobody.stream is not stream:
nobody.pdata = {}
nobody.stream = stream
nobody.offsetof = {}
nobody.pdata[self] = (self.subcon, obj, context)
class BData(Construct):
def __init__(self, nobodyfunc, align = 1, pattern = "\x00"):
Construct.__init__(self, '_bd')
self.nobodyfunc = nobodyfunc
self.align = align
self.pattern = pattern
def _parse(self, stream, context):
return None
def _build(self, obj, stream, context):
assert obj is None
nobody = self.nobodyfunc(context)
offset = stream.tell()
if self.align != 1:
diff = -offset % self.align
padding = (self.pattern * (diff / len(self.pattern) + 1))[:diff]
offset += diff
stream.write(padding)
for (subcon, obj, context) in nobody.pdata.itervalues():
#nobody.offsetof[stream.tell() - offset
subcon._build(obj, stream, context)
size = stream.tell() - offset
nobody.ddata = (offset, stream.tell() - offset)
def _sizeof(self, context):
nobody = self.nobodyfunc(context)
result += 0
for (subcon, obj, context) in nobody.pdata.itervalues():
result += obj._sizeof(context)
return result
def _getdefault(self, context):
return None
def BOffset(nobodyfunc, subcon, minus=0):
return OConst(subcon, lambda ctx: call(nobodyfunc, ctx).getoffset() - call(minus))
def BSize(nobodyfunc, subcon, divide=1):
return OConst(subcon, lambda ctx: call(nobodyfunc, ctx).getsize() / call(divide))
def BOffsetSize(nobodyfunc, subcon1, subcon2, divide=1, minus=0):
return Embedded(Struct('boffsetsize', BOffset(nobodyfunc, subcon1, minus), BSize(nobodyfunc, subcon2, divide)))