import struct
class v_enum: pass
[docs] def __init__(self):
self._vs_meta = {}
def vsGetMeta(self, name, defval=None):
[docs] def vsCalculate(self): pass
[docs] def vsIsPrim(self): return NotImplemented
[docs] def vsGetTypeName(self): return NotImplemented
[docs]
def __init__(self):
v_base.__init__(self)
# Used by base len(),vsGetFormat, etc...
self._vs_value = None
self._vs_length = None
self._vs_fmt = None
self._vs_align = None
def vsIsPrim(self):
[docs] return True
def vsGetTypeName(self):
[docs] return self.__class__.__name__
def vsParse(self, bytes, offset=0):
[docs] """
Parser for primitives which assumes we are
calling parse directly.
"""
return NotImplemented
def vsParseFd(self, fd):
[docs] # Most primitives should be able to simply use this...
fbytes = fd.read(self._vs_length)
if len(fbytes) != self._vs_length:
raise Excetpion('Not enough data in fd!')
self.vsParse(fbytes)
def vsEmit(self):
[docs] '''
Return the actual bytes which represent this field
'''
return NotImplemented
def vsGetValue(self):
[docs] """
Get the type specific value for this field.
(Used by the structure dereference method to return
a python native for the field by name)
"""
return self._vs_value
def vsSetValue(self, value):
[docs] """
Set the type specific value for this field.
"""
self._vs_value = value
def vsSetLength(self, size):
[docs] '''
Set the length of this primitive type. This may be used to
dynamically update the length of string fields, etc...
'''
return NotImplemented
def __repr__(self):
return repr(self.vsGetValue())
def __len__(self):
return self._vs_length
def __str__(self):
return str(self.vsGetValue())
num_fmts = {
(True,1):'>B',
(True,2):'>H',
(True,4):'>I',
(True,8):'>Q',
(False,1):'<B',
(False,2):'<H',
(False,4):'<I',
(False,8):'<Q',
}
class v_number(v_prim):
[docs]
_vs_length = 1
def __init__(self, value=0, bigend=False):
v_prim.__init__(self)
self._vs_bigend = bigend
self._vs_value = value
self._vs_length = self.__class__._vs_length
self._vs_fmt = num_fmts.get( (bigend, self._vs_length) )
def vsGetValue(self):
[docs] return self._vs_value
def vsParse(self, fbytes, offset=0):
[docs] '''
Parse the given numeric type from the given bytes...
'''
sizeoff = offset + self._vs_length
if self._vs_fmt != None:
b = fbytes[ offset : sizeoff ]
self._vs_value = struct.unpack(self._vs_fmt, b)[0]
else:
r = []
for i in range(self._vs_length):
r.append( ord( fbytes[ offset + i ] ) )
if not self._vs_bigend:
r.reverse()
self._vs_value = 0
for x in r:
self._vs_value = (self._vs_value << 8) + x
return sizeoff
def vsEmit(self):
[docs] '''
Emit the bytes for this numeric type...
'''
if self._vs_fmt != None:
return struct.pack(self._vs_fmt, self._vs_value)
r = []
for i in range(self._vs_length):
r.append( chr( (self._vs_value >> (i*8)) & 0xff) )
if self._vs_bigend:
r.reverse()
return ''.join(r)
def vsSetValue(self, value):
[docs] """
Assure that the value is long() able for all numeric types.
"""
self._vs_value = long(value)
def __int__(self):
return int(self._vs_value)
def __long__(self):
return long(self._vs_value)
##################################################################
# Implement the number API
def __add__(self, other): return long(self) + long(other)
def __sub__(self, other): return long(self) - long(other)
def __mul__(self, other): return long(self) * long(other)
def __div__(self, other): return long(self) / long(other)
def __floordiv__(self, other): return long(self) // long(other)
def __mod__(self, other): return long(self) % long(other)
def __divmod__(self, other): return divmod(long(self), long(other))
def __pow__(self, other, modulo=None): return pow(long(self), long(other), modulo)
def __lshift__(self, other): return long(self) << long(other)
def __rshift__(self, other): return long(self) >> long(other)
def __and__(self, other): return long(self) & long(other)
def __xor__(self, other): return long(self) ^ long(other)
def __or__(self, other): return long(self) | long(other)
# Operator swapped variants
def __radd__(self, other): return long(other) + long(self)
def __rsub__(self, other): return long(other) - long(self)
def __rmul__(self, other): return long(other) * long(self)
def __rdiv__(self, other): return long(other) / long(self)
def __rfloordiv__(self, other): return long(other) // long(self)
def __rmod__(self, other): return long(other) % long(self)
def __rdivmod__(self, other): return divmod(long(other), long(self))
def __rpow__(self, other, modulo=None): return pow(long(other), long(self), modulo)
def __rlshift__(self, other): return long(other) << long(self)
def __rrshift__(self, other): return long(other) >> long(self)
def __rand__(self, other): return long(other) & long(self)
def __rxor__(self, other): return long(other) ^ long(self)
def __ror__(self, other): return long(other) | long(self)
# Inplace variants
def __iadd__(self, other): self.vsSetValue(self+other); return self
def __isub__(self, other): self.vsSetValue(self - other); return self
def __imul__(self, other): self.vsSetValue(self*other); return self
def __idiv__(self, other): self.vsSetValue(self/other); return self
def __ifloordiv__(self, other): self.vsSetValue(self // other); return self
def __imod__(self, other): self.vsSetValue(self % other); return self
def __ipow__(self, other, modulo=None): self.vsSetValue(pow(self, other, modulo)); return self
def __ilshift__(self, other): self.vsSetValue(self << other); return self
def __irshift__(self, other): self.vsSetValue(self >> other); return self
def __iand__(self, other): self.vsSetValue(self & other); return self
def __ixor__(self, other): self.vsSetValue(self ^ other); return self
def __ior__(self, other): self.vsSetValue(self | other); return self
# operator helpers
def __neg__(self): return -(long(self))
def __pos__(self): return +(long(self))
def __abs__(self): return abs(long(self))
def __invert__(self): return ~(long(self))
# index use helper
def __index__(self): return long(self)
def __coerce__(self, other):
try:
return long(self),long(other)
except Exception, e:
return NotImplemented
# Print helpers
def __hex__(self): return hex(long(self))
def __oct__(self): return oct(long(self))
class v_uint8(v_number):
[docs] _vs_builder = True
_vs_length = 1
class v_uint16(v_number):
[docs] _vs_builder = True
_vs_length = 2
class v_uint24(v_number):
[docs] _vs_builder = True
_vs_length = 3
class v_uint32(v_number):
[docs] _vs_builder = True
_vs_length = 4
class v_uint64(v_number):
[docs] _vs_builder = True
_vs_length = 8
class v_int8(v_number):
[docs] _vs_builder = True
_vs_length = 1
class v_int16(v_number):
[docs] _vs_builder = True
_vs_length = 2
class v_int24(v_number):
[docs] _vs_builder = True
_vs_length = 3
class v_int32(v_number):
[docs] _vs_builder = True
_vs_length = 4
class v_int64(v_number):
[docs] _vs_builder = True
_vs_length = 8
pointersize = struct.calcsize("P")
class v_size_t(v_number):
[docs] _vs_builder = True
_vs_length = pointersize
def __repr__(self):
return "0x%.8x" % self._vs_value
class v_ptr(v_size_t):
[docs] pass
class v_ptr32(v_ptr):
[docs] _vs_builder = True
_vs_length = 4
class v_ptr64(v_ptr):
[docs] _vs_builder = True
_vs_length = 8
class v_bytes(v_prim):
[docs]
'''
v_bytes is used for fixed width byte fields.
'''
_vs_builder = True
def __init__(self, size=0, vbytes=None):
v_prim.__init__(self)
if vbytes == None:
vbytes = '\x00' * size
self._vs_length = len(vbytes)
self._vs_value = vbytes
self._vs_align = 1
def vsSetValue(self, val):
[docs] if len(val) != self._vs_length:
raise Exception('v_bytes field set to wrong length!')
self._vs_value = val
# We have a winner!
def vsParse(self, fbytes, offset=0):
[docs] offend = offset + self._vs_length
self._vs_value = fbytes[offset : offend]
return offend
def vsEmit(self):
[docs] return self._vs_value
def vsSetLength(self, size):
[docs] size = int(size)
self._vs_length = size
# Either chop or expand my string...
b = self._vs_value[:size]
self._vs_value = b.ljust(size, '\x00')
def __repr__(self):
return self._vs_value.encode('hex')
class v_str(v_prim):
[docs] '''
A string placeholder class which will automagically return
up to a null terminator (and will keep it's size by null
padding when assigned to)
'''
_vs_builder = True
def __init__(self, size=4, val=''):
v_prim.__init__(self)
self._vs_length = size
self._vs_value = val.ljust(size, '\x00')
self._vs_align = 1
def vsParse(self, fbytes, offset=0):
[docs] offend = offset + self._vs_length
self._vs_value = fbytes[offset : offend]
return offend
def vsEmit(self):
[docs] return self._vs_value
def vsGetValue(self):
[docs] s = self._vs_value.split("\x00")[0]
return s
def vsSetValue(self, val):
[docs] self._vs_value = val.ljust(self._vs_length, '\x00')
def vsSetLength(self, size):
[docs] size = int(size)
self._vs_length = size
# Either chop or expand my string...
b = self._vs_value[:size]
self._vs_value = b.ljust(size, '\x00')
class v_zstr(v_prim):
[docs] '''
A string placeholder class which will automagically return
up to a null terminator dynamically.
'''
_vs_builder = True
def __init__(self, val=''):
v_prim.__init__(self)
self._vs_value = val + '\x00'
self._vs_length = len(self._vs_value)
self._vs_align = 1
def vsParse(self, fbytes, offset=0):
[docs] nulloff = fbytes.find('\x00', offset)
if nulloff == -1:
raise Exception('v_zstr found no NULL terminator!')
nulloff += 1 # *include* the null
self._vs_value = fbytes[offset : nulloff]
self._vs_len = len(self._vs_value)
return nulloff
def vsEmit(self):
[docs] return self._vs_value
def vsGetValue(self):
[docs] return self._vs_value[:-1]
def vsSetValue(self, val):
[docs] self._vs_value = val + '\x00'
def vsSetLength(self, size):
[docs] raise Exception('Cannot vsSetLength on v_zstr! (its dynamic)')
class v_wstr(v_str):
[docs] '''
Unicode variant of the above string class
NOTE: the size paramater is in WCHARs!
'''
_vs_builder = True
def __init__(self, size=4, encode='utf-16le', val=''):
v_prim.__init__(self)
b = val.ljust(size, '\x00').encode(encode)
self._vs_length = len(b)
self._vs_value = b
self._vs_encode = encode
self._vs_align = 2
def vsParse(self, fbytes, offset=0):
[docs] offend = offset + self._vs_length
self._vs_value = fbytes[offset : offend]
return offend
def vsEmit(self):
[docs] return self._vs_value
def vsGetValue(self):
cstr = self._vs_value.decode(self._vs_encode)
return cstr.split('\x00')[0]
def vsSetValue(self, val):
[docs] rbytes = val.encode(self._vs_encode)
self._vs_value = rbytes.ljust(len(self), '\x00')
def vsGetValue(self):
[docs] s = self._vs_value.decode(self._vs_encode)
s = s.split("\x00")[0]
return s
class GUID(v_prim):
[docs]
_vs_builder = True
def __init__(self, guidstr=None):
"""
Construct a new GUID primitive. You may specify a GUID string in the
constructor to populate initial values.
"""
v_prim.__init__(self)
self._vs_length = 16
self._vs_value = "\x00" * 16
self._vs_fmt = "16s"
self._guid_fields = (0,0,0,0,0,0,0,0,0,0,0)
if guidstr != None:
self._parseGuidStr(guidstr)
def vsParse(self, fbytes, offset=0):
[docs] offend = offset + self._vs_length
self._guid_fields = struct.unpack("<IHH8B", bytes[offset:offend])
return offend
def vsEmit(self):
[docs] return struck.pack("<IHH8B", *self._guid_fields)
def _parseGuidStr(self, gstr):
gstr = gstr.replace("{","")
gstr = gstr.replace("}","")
gstr = gstr.replace("-","")
bytes = gstr.decode("hex")
# Totally cheating... ;)
self._guid_fields = struct.unpack(">IHH8B", bytes)
def vsSetValue(self, guidstr):
[docs] self._parseGuidStr(guidstr)
def vsGetValue(self):
[docs] return repr(self)
def __repr__(self):
base = "{%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}"
return base % self._guid_fields