1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import struct
class StructField: def __init__(self, format_str, offset): self.format_str = format_str self.offset = offset
def __get__(self, instance, cls): if instance is None: return self else: r = struct.unpack_from(self.format_str, instance._buffer, self.offset) return r[0] if len(r) == 1 else r
class StructureMeta(type): def __init__(self, clsname, bases, clsdict): fields = getattr(self, '_fields_', []) byte_order = '' offset = 0 for format_str, fieldname in fields: if format_str.startswith(('<', '>', '!', '@')): byte_order = format_str[0] format_str = format_str[1:] format_str = byte_order + format_str setattr(self, fieldname, StructField(format_str, offset)) offset += struct.calcsize(format_str) setattr(self, 'struct_size', offset)
class Structure(metaclass=StructureMeta): def __init__(self, bytedata): self._buffer = bytedata
@classmethod def from_file(cls, fh): return cls(fh.read(cls.struct_size))
class GifHeader(Structure): '''https://www.w3.org/Graphics/GIF/spec-gif89a.txt''' _fields_ = [('3s', 'signature'), ('3s', 'version')]
if __name__ == '__main__': with open('bin.gif', 'rb') as fh: gif_header = GifHeader.from_file(fh) print('signature: ', gif_header.signature.decode()) print('version: ', gif_header.version.decode())
|