Example #1
0
    def dumpTextures(self, path, outPath, raw=False):
        """Dump textures from files at `path` to dir `outPath`.

        path: eg "warlock/TEX0" (no extension)
        """
        if type(raw) is str: raw = (raw == '1')
        file = BinaryFile(path+'.bin', 'rb')
        tbl  = BinaryFile(path+'.tab', 'rb') # don't use TabFile
            # because it's not quite the same format here
        idx   = -1
        while True:
            idx += 1
            entry = tbl.readu32()
            if entry == 0xFFFFFFFF: break
            #if entry == 0x01000000: continue # skip
            flags =  entry >> 30
            count = (entry >> 24) & 0x3F
            offs  = (entry & 0xFFFFFF) * 2
            if flags == 0: continue # XXX meaning of these?
            printf("%04X %06X %X %02X\n", idx, offs, flags, count)

            try:
                file.seek(offs)
                if count > 1:
                    offsets = file.readu32(count=count)
                else: offsets = (0,)
                #printf("%04X %02X %02X %06X %s\n", idx, flags, count, offs,
                #    ' '.join(map(lambda n: '%08X'%n, offsets)))

                for i, offset in enumerate(offsets):
                    file.seek(offs + offset)
                    data = Zlb(file).decompress()
                    if raw:
                        name = "%s/%04X.%02X.tex" % (outPath, idx, i)
                        with open(name, 'wb') as outFile:
                            outFile.write(data)
                    else:
                        tex  = SfaTexture.fromData(data)
                        #printf("%04X.%02X: %3dx%3d %2dmip %s\n", idx, i,
                        #    tex.width, tex.height, tex.numMipMaps, tex.format.name)
                        name = "%s/%04X.%02X.%s.png" % (outPath, idx, i,
                            tex.format.name)
                        tex.image.save(name)
            except Exception as ex:
                printf("%04X ERROR: %s\n", idx, ex)
Example #2
0
 def listTable(self, inPath):
     """List entries in a TAB file."""
     file = BinaryFile(inPath, 'rb')
     tbl  = TabFile(file)
     print("Item C Flg Offset  (C=compressed?)")
     for i, entry in enumerate(tbl.getEntries()):
         printf("%5d: %s  %02X %06X\n", i,
             'Y' if entry['compressed'] else '-',
             entry['flags'], entry['offset'])
Example #3
0
 def dumpTexture(self, path, outPath, raw=False, offset=0):
     """Dump texture from file."""
     if type(raw) is str: raw = (raw == '1')
     if type(offset) is str: offset = int(offset, 0)
     file = BinaryFile(path, 'rb', offset=offset)
     head = file.readStruct('3b')
     file.seek(0)
     if head in (b'ZLB', b'DIR', b'\xFA\xCE\xFE'):
         data = Zlb(file).decompress()
     else:
         size = file.readu32(offset=0x44)
         file.seek(0)
         data = file.read(size+0x60)
     if raw:
         with open(outPath, 'wb') as outFile:
             outFile.write(data)
     else:
         tex = SfaTexture.fromData(data)
         printf("Texture size: %dx%d, fmt %s, %d mipmaps\n",
             tex.width, tex.height, tex.format.name,
             tex.numMipMaps)
         tex.image.save(outPath)
Example #4
0
 def listAnimations(self, discRoot, modelId):
     """List the animation IDs used by given model."""
     modelId = int(modelId, 0)
     modAnimTab = BinaryFile(discRoot+'/MODANIM.TAB', 'rb')
     modAnimOffs = modAnimTab.readu16(modelId << 1)
     nextOffs = modAnimTab.readu16((modelId+1) << 1)
     nAnims = (nextOffs - modAnimOffs) >> 1
     modAnimBin = BinaryFile(discRoot+'/MODANIM.BIN', 'rb')
     animIds = modAnimBin.readBytes(nAnims*2, modAnimOffs)
     animIds = struct.unpack('>%dh' % nAnims, animIds)
     printf("%4d animations; MODANIM.BIN 0x%06X - 0x%06X, min 0x%04X max 0x%04X\n",
         nAnims, modAnimOffs, modAnimOffs+(nAnims*2),
         max(0, min(animIds)), max(animIds))
     for i in range(0, nAnims, 8):
         printf('%04X: %s\n', i,
         ' '.join(map(lambda v: '%04X' % (v&0xFFFF), animIds[i:i+8])))
Example #5
0
 def decompress(self, inPath, outPath, inOffset=0):
     """Decompress a ZLB file."""
     if type(inOffset) is str: inOffset = int(inOffset, 0)
     file = BinaryFile(inPath, 'rb', offset=inOffset)
     with open(outPath, 'wb') as outFile:
         outFile.write(Zlb(file).decompress())
Example #6
0
    def readRomList(self, path, discRoot):
        """Read romlist.zlb file."""
        file = BinaryFile(path, 'rb', offset=0)
        data = Zlb(file).decompress()

        # read OBJINDEX.bin
        objIndex = []
        with open(discRoot+'/OBJINDEX.bin', 'rb') as objIdxFile:
            entries = objIdxFile.read()
            for i in range(0, len(entries), 2):
                it = struct.unpack_from('>H', entries, i)[0] # grumble
                objIndex.append(it)

        # read OBJECTS.tab
        objsTab = []
        with open(discRoot+'/OBJECTS.tab', 'rb') as objTabFile:
            entries = objTabFile.read()
            for i in range(0, len(entries), 4):
                it = struct.unpack_from('>I', entries, i)[0] # grumble
                objsTab.append(it)

        # read OBJECTS.bin to get names
        objNames = []
        with open(discRoot+'/OBJECTS.bin', 'rb') as objBinFile:
            for offs in objsTab:
                objBinFile.seek(offs + 0x91)
                name = objBinFile.read(11).decode('utf-8').replace('\0', '')
                objNames.append(name)

        offs, idx = 0, 0
        printf("Idx  Offs Type Obj  ObjName     Sz MapStates------X Fl 06 07      X        Y        Z   UniqueID SeqData\n")
        while offs < len(data):
            typ, length, states3, flags, states5, b6, b7, x, y, z, uniqueId = \
                struct.unpack_from('>hBBBBBBfffI', data, offs)
            if typ >= 0:
                if typ < len(objIndex): realTyp = objIndex[typ]
                else: realTyp = "????"
            else: realTyp = -typ
            if type(realTyp) != str:
                try: name = objNames[realTyp]
                except: name = "?"
                realTyp = '%04X' % realTyp
            else: name = "?"

            states = []
            for i in range(8):
                states.append('-' if (states3 >> i) & 1 else ('%X' % (i+1)))
            for i in range(8):
                states.append('-' if (states5 >> (7-i)) else ('%X' % ((i+9) & 0xF)))
            states = ''.join(states)

            # idx offs typ realTyp name sz states flags 06 07 X Y Z ID
            printf("%04X %04X %04X %s %-11s %02X %s %02X %02X %02X %+8.2f %+8.2f %+8.2f %08X ",
                idx, offs, typ, realTyp, name, length, states, flags, b6, b7, x, y, z,
                uniqueId)
            for i in range(0x18, length*4, 4): # SeqData
                printf("%02X%02X%02X%02X ", *data[offs+i: offs+i+4])
            printf("\n")

            if length == 0: break
            offs += length * 4
            idx  += 1
Example #7
0
    def _dumpRaw(self, binPath, tabPath, outPath, ignoreFlags=False,
    offsMask=0x0FFFFFFF, offsShift=0, nameFunc=None):
        """Dump raw data listed in table, where the next entry is used
        to calculate the size.
        """
        try: file = BinaryFile(binPath+'.bin', 'rb')
        except FileNotFoundError: file = BinaryFile(binPath+'.BIN', 'rb')
        try: tbl  = BinaryFile(tabPath+'.tab', 'rb')
        except FileNotFoundError: tbl  = BinaryFile(tabPath+'.TAB', 'rb')

        if nameFunc is None: nameFunc = lambda idx, data: '%04X.bin' % idx

        idx   = 0
        entry = tbl.readu32()
        while True:
            if entry == 0xFFFFFFFF: break
            eNext = tbl.readu32()
            flags = entry >> 24
            if flags != 0 or ignoreFlags:
                offs = entry & offsMask
                if offsShift >= 0: offs = offs >> offsShift
                else: offs = offs << -offsShift
                try:
                    file.seek(offs)
                    head = file.read(3)
                    file.seek(offs)
                    if head in (b'ZLB', b'DIR', b'\xFA\xCE\xFE'):
                        data = Zlb(file).decompress()
                    else:
                        oNext = eNext & offsMask
                        if offsShift >= 0: oNext = oNext >> offsShift
                        else: oNext = oNext << -offsShift
                        data = file.read(oNext - offs)

                    name = '%s/%s' % (outPath, nameFunc(idx,data))
                    #printf("%04X %02X %06X %06X %s\n", idx, flags, offs, len(data), name)
                    with open(name, 'wb') as outFile:
                        outFile.write(data)
                except Exception as ex:
                    printf("%04X %s ERROR: %s\n", idx, outPath, ex)
            idx += 1
            entry = eNext
Example #8
0
    def mapstoFakeLZO(self, path, tabPath, outBinPath, outTabPath):
        """Convert MAPS.BIN file's contents to "fake LZO" format.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,       'rb')
        tabFile = BinaryFile(tabPath,    'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        offs    = tabFile.readu32()
        while offs != 0xFFFFFFFF:
            nextOffs = tabFile.readu32()
            inLen    = nextOffs - offs
            inFile.seek(offs)

            tabVal = outBin.tell()
            outTab.writeu32(tabVal)

            while offs < nextOffs:
                inFile.seek(offs)
                data = inFile.read(4)
                if len(data) == 0: break
                elif data == b'\xFA\xCE\xFE\xED':
                    rawLen, zlbOffs, compLen = inFile.readStruct('3I')
                    dOut = data + struct.pack('>3I', rawLen+0x28, zlbOffs, rawLen+4)
                    printf("Write FACEFEED at %08X: %s\r\n", outBin.tell(),
                        dOut.hex())
                    outBin.write(dOut)
                    for i in range(zlbOffs):
                        outBin.writeu16(inFile.readu16())
                    offs += len(data)
                elif data == b'ZLB\0':
                    inFile.seek(offs)
                    data = inZlb.decompress()
                    dl   = len(data) + 4
                    outBin.write(b'LZO\0' + struct.pack('3I', 0, 0, dl) + b'Rena' + data)
                else:
                    outBin.write(data)
                offs = inFile.tell()
            offs = nextOffs

        tabVal = outBin.tell()
        outTab.writeu32(tabVal)
        outTab.writeu32(0xFFFFFFFF)
        for i in range(3):
            outTab.writeu32(0)
Example #9
0
    def packTextures(self, path, outPath, which):
        """Pack images in `path` to TEXn.bin, TEXn.tab files, where n=which."""
        textures = {} # ID => tex
        # get list of files to pack
        for name in os.listdir(path):
            if re.match(r'^[0-9a-fA-F]+\.[0-9a-fA-F]+\.', name):
                fields = name.split('.')
                tid = int(fields[0], 16) # texture ID
                mid = int(fields[1], 16) # mipmap ID
                if tid not in textures: textures[tid] = {}
                textures[tid][mid] = name

        printf("Packing %d textures to %s.bin/tab\n", len(textures), outPath)

        # write out bin and tab files
        binFile = BinaryFile(outPath+'.bin', 'wb')
        tabFile = BinaryFile(outPath+'.tab', 'wb')
        maxId = self.MAX_TEX0_ID if str(which) == '0' else self.MAX_TEX1_ID
        for tid in range(maxId):
            if tid in textures:
                printf("%04X... ", tid)
                mips = textures[tid]
                offs = binFile.tell()
                nMips = len(mips)
                printf("%2d mips, %08X  ", nMips, offs)
                tabFile.writeu32(
                    0x80000000 | (offs>>1) | (nMips << 24))

                mipData = []
                for mip in range(nMips):
                    name = mips[mip]
                    fPath = os.path.join(path, name)
                    if name.endswith('.tex') or name.endswith('.bin'):
                        with open(fPath, 'rb') as file:
                            data = file.read()
                    else: # image file
                        fields = name.split('.')
                        fmt = ImageFormat[fields[2]]
                        img = Image.open(fPath)
                        tex = SfaTexture.fromImage(img, fmt=format, numMipMaps=numMipMaps)
                        data = tex.toData()
                    data = Zlb(None).compress(data)
                    pad = len(data) & 0x3
                    if pad: data += b'\0' * (4 - pad)
                    mipData.append(data)

                # write the mipmap offsets
                if nMips > 1:
                    mipOffs = 4 * (nMips+1)
                    for data in mipData:
                        binFile.writeu32(mipOffs)
                        mipOffs += len(data)
                    binFile.writeu32(mipOffs)

                # write the data
                for data in mipData:
                    binFile.write(data)

                # align to 32 bytes - required by game
                pad = binFile.tell() & 0x1F
                if pad: binFile.write(b'\0' * (32 - pad))

                printf("OK\n")
            else:
                tabFile.writeu32(0x01000000)
        # write size of last item and terminator
        tabFile.writeu32(binFile.tell() >> 1)
        tabFile.writeu32(0xFFFFFFFF)
        tabFile.writeu32(0xCFA2) # XXX what is this? never read?
        tabFile.writeu32(0, 0, 0, 0, 0, 0, 0)
        binFile.close()
        tabFile.close()
Example #10
0
    def textoDIR(self, path, tabPath, outBinPath, outTabPath):
        """Convert a texture file's contents to uncompressed DIR format.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,       'rb')
        tabFile = BinaryFile(tabPath,    'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        tabCksum = 0
        while True:
            offs    = tabFile.readu32()
            if offs == 0xFFFFFFFF: break
            high = offs & 0xFF000000
            if high & 0x80000000:
                offs = (offs & 0xFFFFFF) * 2
                nFrames = (high >> 24) & 0x3F
                inFile.seek(offs)

                # read frame values
                if nFrames > 1: frameData = inFile.readu32(nFrames+1)
                else: frameData = []

                data = inZlb.decompress()
                #data = b'\0\0\0\0' + b'\0\0\0\0' + b'\0\0\0\0' + data
                dl = len(data)
                header = b'DIR\0' + struct.pack('>3I', 0, dl, dl)
                header += b'\0\0\0\0' + b'\0\0\0\0' + b'\0\0\0\0' + b'\0\0\0\0'
                data = header + data
                tabVal = (outBin.tell() >> 1) | high
                if nFrames > 1: outBin.writeu32(*frameData)
                outBin.write(data)
                while outBin.tell() & 0xF: outBin.writeu8(0)

            else: # don't use this texture
                tabVal = 0x01000000
            tabCksum += ((tabVal >> 24) & 0xFF)
            tabCksum += ((tabVal >> 16) & 0xFF)
            tabCksum += ((tabVal >>  8) & 0xFF)
            tabCksum += ( tabVal        & 0xFF)
            outTab.writeu32(tabVal)
        outTab.writeu32(0xFFFFFFFF)
        tabCksum += (0xFF * 4)
        outTab.writeu32(tabCksum & 0xFFFFFFFF)
        for i in range(7):
            outTab.writeu32(0)
Example #11
0
    def modelstoFakeLZO(self, path, tabPath, outBinPath, outTabPath):
        """Convert a model file's contents to "fake LZO" format.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,       'rb')
        tabFile = BinaryFile(tabPath,    'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        tabCksum = 0
        while True:
            offs    = tabFile.readu32()
            if offs == 0xFFFFFFFF: break
            high = offs & 0xFF000000
            if high & 0x10000000:
                #printf("Model %08X\r\n", offs)
                offs = offs & 0xFFFFFF
                inFile.seek(offs)

                data = inFile.read(4)
                if data == b'\xFA\xCE\xFE\xED':
                    while data not in (b'ZLB\0', b'DIR\0', b'\xE0\xE0\xE0\xE0', b'\xF0\xF0\xF0\xF0'):
                        outBin.write(data)
                        data = inFile.read(4)
                inFile.seek(offs)

                data = inZlb.decompress()
                header = b'ZLB\0' + struct.pack('>3I', 1, len(data), len(data)) + b'Rena'
                data = header + data
                tabVal = outBin.tell() | high
                outBin.write(data)
                while outBin.tell() & 0xF: outBin.writeu8(0)

            else: # don't use this model
                tabVal = 0x00000000
            tabCksum += ((tabVal >> 24) & 0xFF)
            tabCksum += ((tabVal >> 16) & 0xFF)
            tabCksum += ((tabVal >>  8) & 0xFF)
            tabCksum += ( tabVal        & 0xFF)
            outTab.writeu32(tabVal)

        tabVal = outBin.tell()
        outTab.writeu32(tabVal)
        tabCksum += ((tabVal >> 24) & 0xFF)
        tabCksum += ((tabVal >> 16) & 0xFF)
        tabCksum += ((tabVal >>  8) & 0xFF)
        tabCksum += ( tabVal        & 0xFF)

        outTab.writeu32(0xFFFFFFFF)
        tabCksum += (0xFF * 4)
        outTab.writeu32(tabCksum & 0xFFFFFFFF)
        for i in range(7):
            outTab.writeu32(0)
Example #12
0
    def textoLZO(self, path, tabPath, outBinPath, outTabPath):
        """Convert a texture file's contents to LZO.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,    'rb')
        tabFile = BinaryFile(tabPath, 'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        outLzo  = DPLZO(outBin)
        tabCksum = 0
        while True:
            offs    = tabFile.readu32()
            if offs == 0xFFFFFFFF: break
            high = offs & 0xFF000000
            if high & 0x80000000:
                offs = (offs & 0xFFFFFF) * 2
                nFrames = (high >> 24) & 0x3F
                inFile.seek(offs)

                # read frame values
                if nFrames > 1: frameData = inFile.readu32(nFrames+1)
                else: frameData = []

                data = outLzo.compress(inZlb.decompress())
                tabVal = (outBin.tell() >> 1) | (high & 0xC0000000) | ((nFrames-1) << 24)
                if nFrames > 1: outBin.writeu32(*frameData)
                outBin.write(data)
                while outBin.tell() & 0xF: outBin.writeu8(0)

            else: # don't use this texture
                tabVal = 0x01000000
            tabCksum += ((tabVal >> 24) & 0xFF)
            tabCksum += ((tabVal >> 16) & 0xFF)
            tabCksum += ((tabVal >>  8) & 0xFF)
            tabCksum += ( tabVal        & 0xFF)
            outTab.writeu32(tabVal)
        outTab.writeu32(0xFFFFFFFF)
        tabCksum += (0xFF * 4)
        outTab.writeu32(tabCksum & 0xFFFFFFFF)
        for i in range(7):
            outTab.writeu32(0)
Example #13
0
 def compressLZO(self, inPath, outPath, inOffset=0):
     """Compress a LZO file."""
     if type(inOffset) is str: inOffset = int(inOffset, 0)
     file = BinaryFile(inPath, 'rb', offset=inOffset)
     with open(outPath, 'wb') as outFile:
         outFile.write(DPLZO(file).compress())
Example #14
0
    def toFakeLZO(self, path, tabPath, outBinPath, outTabPath):
        """Convert a file's contents to "fake LZO" format.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,    'rb')
        tabFile = BinaryFile(tabPath, 'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        offs    = tabFile.readu32()
        while True:
            nextOffs = tabFile.readu32()
            if nextOffs == 0xFFFFFFFF: break
            high = offs & 0xFF000000
            offs &= 0xFFFFFF
            size = (nextOffs & 0xFFFFFF) - offs
            if size > 0:
                inFile.seek(offs)
                data = inZlb.decompress()
                header = b'LZO\0' + struct.pack('>3I', 1, len(data), len(data)) + b'Rena'
                pad  = len(data) & 0xF
                if pad: data += b'\0' * (16-pad)
            outTab.writeu32(outBin.tell() | high)
            if size > 0: outBin.write(header + data)
            offs = nextOffs
        outTab.writeu32(outBin.tell()) # XXX verify
        outTab.writeu32(0xFFFFFFFF)
Example #15
0
    def toLZO(self, path, tabPath, outBinPath, outTabPath):
        """Convert a file's contents to LZO.

        path: input file to convert.
        tabPath: table for input file.
        outBinPath: output path for .bin file.
        outTabPath: output path for .tab file.
        """
        inFile  = BinaryFile(path,    'rb')
        tabFile = BinaryFile(tabPath, 'rb')
        outBin  = BinaryFile(outBinPath, 'wb')
        outTab  = BinaryFile(outTabPath, 'wb')
        inZlb   = Zlb(inFile)
        outLzo  = DPLZO(outBin)
        while True:
            offs    = tabFile.readu32()
            if offs == 0xFFFFFFFF: break
            high = offs & 0xFF000000
            inFile.seek(offs & 0xFFFFFF)
            data = inZlb.decompress()
            pad  = len(data) & 0xF
            if pad: data += b'\0' * (16-pad)
            outTab.writeu32(outBin.tell() | high)
            outBin.write(outLzo.compress(data))
        outTab.writeu32(outBin.tell()) # XXX verify
        outTab.writeu32(0xFFFFFFFF)
Example #16
0
 def __init__(self, file: (BinaryFile, str)):
     if type(file) is str: file = BinaryFile(file, 'rb')
     self.file = file