import struct __all__ = ['DataType', 'Array', 'Struct', 'Byte', 'Word', 'Dword', 'ArrayOf', 'RT_RCDATA', 'RT_VERSION', 'UpdateResource', 'SetSubsystem', ] try: # Python 2.3+ issubclass(type, ()) except TypeError: # Python 2.2 import __builtin__ def issubclass(subclass, class_or_tuple): if isinstance(class_or_tuple, tuple): for class_ in class_or_tuple: if issubclass(subclass, class_): return True return False return __builtin__.issubclass(subclass, class_or_tuple) class DataType(type): def __init__(cls, name, bases, namespace): if Struct in bases: assert '__fields__' in namespace slots = [] format = '<' for datatype, field in namespace['__fields__']: slots.append(field) if issubclass(datatype, (Struct, Array)): format += '%ds' % datatype.__size__ else: format += datatype.__format__[1:] cls.__slots__ = tuple(slots) cls.__format__ = format else: assert '__format__' in namespace cls.__slots__ = () # Update (cache) the record size cls.__size__ = struct.calcsize(cls.__format__) return super(DataType, cls).__init__(name, bases, namespace) # allow the DataType metaclass to do its thing on the 'Struct' class Struct = None class Struct(object): __metaclass__ = DataType __format__ = '' def __init__(self, bytes=None): if bytes is None: bytes = '\0' * self.__size__ values = struct.unpack(self.__format__, bytes) for (datatype, name), value in zip(self.__fields__, values): setattr(self, name, datatype(value)) return def __repr__(self): values = [] for format, name in self.__fields__: value = getattr(self, name) if issubclass(format, Struct): members = repr(value).split('\n') members.insert(0, '<%s>' % format.__name__) value = '\n '.join(members) values.append('%s: %s' % (name, value)) return '\n'.join(values) #@classmethod def load(cls, stream): return cls(stream.read(cls.__size__)) load = classmethod(load) def pack(self): values = [] for datatype, field in self.__fields__: value = getattr(self, field) if issubclass(datatype, (Struct, Array)): value = value.pack() values.append(value) return struct.pack(self.__format__, *values) class Array(list): def __init__(self, bytes=None): if bytes is None: bytes = '\0' * self.__size__ values = struct.unpack(self.__format__, bytes) if self.__itemtype__: values = map(self.__itemtype__, values) list.__init__(self, values) def pack(self): values = self if self.__itemtype__ is not None: values = [ item.pack() for item in values ] return struct.pack(self.__format__, *values) class Byte(int): __metaclass__ = DataType __format__ = '