#!/usr/bin/python3 import ctypes, sys sharedlib = './lib3ddevil1.so' libc = ctypes.cdll.LoadLibrary(sharedlib) if not libc: print("Couldn't load %s" % sharedlib) sys.exit() del sys print("\nlib3ddevil1 loaded.") #--------------------------------------+ # Basic Struct #--------------------------------------+ class TexturePack(ctypes.Structure): _pack_ = 1 _fields_ = [ ("id", ctypes.c_char * 4), # fixed length 4, reverse order ("batchNumber", ctypes.c_int), ("firstBatchOffset", ctypes.c_int), ("unknownA", ctypes.c_int) ] class TextureBatchDescriptor(ctypes.Structure): _pack_ = 1 _fields_ = [ ("batchIdx", ctypes.c_int), ("hash", ctypes.c_int), ("texNumber", ctypes.c_int), ("unknownA", ctypes.c_int * 8), ("textureSize", ctypes.c_int), ("unknownB", ctypes.c_int * 30) ] class Texture(ctypes.Structure): _pack_ = 1 _fields_ = [ ("data", ctypes.POINTER(ctypes.c_ubyte)) ] class TextureBatch(ctypes.Structure): _pack_ = 1 _fields_ = [ ("batch", ctypes.POINTER(Texture)) ] class Devil1TEX_FN(ctypes.Structure): _fields_ = [ ("printheader", ctypes.CFUNCTYPE( None, ctypes.POINTER(TexturePack))), ("printbatchdesc", ctypes.CFUNCTYPE( None, ctypes.POINTER(TextureBatchDescriptor))), ("getheader", ctypes.CFUNCTYPE( ctypes.c_bool, ctypes.POINTER( ctypes.POINTER(TexturePack)), ctypes.c_char_p)), ("getbatchdesc", ctypes.CFUNCTYPE( ctypes.c_bool, ctypes.POINTER( ctypes.POINTER(TextureBatchDescriptor)), ctypes.c_uint, ctypes.c_char_p, ctypes.c_uint)), ("getbatch", ctypes.CFUNCTYPE( ctypes.c_bool, ctypes.POINTER( ctypes.POINTER(TextureBatch)), ctypes.c_uint, ctypes.c_char_p, ctypes.c_uint)), ("gettextures", ctypes.CFUNCTYPE( ctypes.c_bool, ctypes.POINTER(Texture), ctypes.c_uint, ctypes.c_char_p, ctypes.c_uint)) ] devil1tex = Devil1TEX_FN.in_dll(libc, "DEVIL1TEX") #--------------------------------------+ # Pythonic Object #--------------------------------------+ class TEXturePack: def __init__(self, filedata): self.cstruct = ctypes.pointer(TexturePack()) devil1tex.getheader(ctypes.byref(self.cstruct), filedata) return def show(self): devil1tex.printheader(self.cstruct) def getbatchno(self): return self.cstruct.contents.batchNumber def getfirstbatchoffset(self): return self.cstruct.contents.firstBatchOffset class TEXtureBatchDescriptor: def __init__(self, i, filedata): self.cstruct = ctypes.pointer(TextureBatchDescriptor()) ptrofptr = ctypes.byref(self.cstruct) if filedata: devil1tex.getbatchdesc(ptrofptr, i, filedata, len(filedata)) return def show(self): devil1tex.printbatchdesc(self.cstruct) def getbatchidx(self): return self.cstruct.contents.batchIdx def gethash(self): return self.cstruct.contents.hash def gettexno(self): return self.cstruct.contents.texNumber def gettexturesize(self): return self.cstruct.contents.textureSize class TEXtureBatch: def __init__(self, i, filedata): self.cstruct = TextureBatch() if filedata: self.cstruct.batch = None tbd = TEXtureBatchDescriptor(i, filedata) self.amount = tbd.gettexno() memsize = self.amount * tbd.gettexturesize() self.cstruct.batch = ctypes.cast( ctypes.create_string_buffer(memsize), ctypes.POINTER(Texture)) devil1tex.gettextures(self.cstruct.batch, i, filedata, len(filedata)) return def gettextures(self): return self.cstruct.batch[:self.amount]