Exemple #1
0
    def LoadTilesetNames(self):
        """
        Loads block 1, the tileset names
        """
        data = struct.unpack_from('32s32s32s32s', self.blocks[0])
        self.tileset0 = bytes_to_string(data[0])
        self.tileset1 = bytes_to_string(data[1])
        self.tileset2 = bytes_to_string(data[2])
        self.tileset3 = bytes_to_string(data[3])

        if self.tileset0 not in globals.szsData:
            ret = False
            if self.tileset0 in globals.Pa0Tilesets:
                reply = QtWidgets.QMessageBox.question(globals.mainWindow, 'Warning',
                                                       '"%s" tileset was not found in the level data!\n' \
                                                       'Do you want to load the default one from miyamotoextras?' % self.tileset0,
                                                       QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)

                if reply == QtWidgets.QMessageBox.Yes:
                    ret = globals.mainWindow.LoadDefaultTileset(self.tileset0, dirty=True)

            if not ret:
                self.tileset0 = ''

        if self.tileset1 not in globals.szsData:
            self.tileset1 = ''

        if self.tileset2 not in globals.szsData:
            self.tileset2 = ''

        if self.tileset3 not in globals.szsData:
            self.tileset3 = ''
Exemple #2
0
 def LoadTilesetNames(self):
     """
     Loads block 1, the tileset names
     """
     data = struct.unpack_from('32s32s32s32s', self.blocks[0])
     self.tileset0 = bytes_to_string(data[0])
     self.tileset1 = bytes_to_string(data[1])
     self.tileset2 = bytes_to_string(data[2])
     self.tileset3 = bytes_to_string(data[3])
     if self.tileset0 not in globals.szsData:
         self.tileset0 = ''
     if self.tileset1 not in globals.szsData:
         self.tileset1 = ''
     if self.tileset2 not in globals.szsData:
         self.tileset2 = ''
     if self.tileset3 not in globals.szsData:
         self.tileset3 = ''
Exemple #3
0
def convFile(f, dest, dest_bom):
    magic = bytes_to_string(f[:4])
    if magic in supp_STM and dest in supp_STM:
        outputBuffer = STMtoSTM(f, magic, dest, dest_bom)

    elif magic in supp_WAV and dest in supp_WAV:
        outputBuffer = WAVtoWAV(f, magic, dest, dest_bom)

    elif magic in supp_STM and dest in supp_WAV:
        outputBuffer = STMtoWAV(f, magic, dest, dest_bom)

    elif magic in supp_WAV and dest in supp_STM:
        print("\nBFWAV/BCWAV to BFSTM/BCSTM/BFSTP is not implemented!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    else:
        print("\nUnsupported file format!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    return outputBuffer
Exemple #4
0
 def LoadTilesetNames(self):
     data = struct.unpack_from('32s32s32s32s', self.blocks[0])
     self.tileset0 = bytes_to_string(data[0])
     self.tileset1 = bytes_to_string(data[1])
     self.tileset2 = bytes_to_string(data[2])
     self.tileset3 = bytes_to_string(data[3])
Exemple #5
0
def readFile(f):
    pos = 0

    if f[4:6] == b'\xFF\xFE':
        bom = '<'

    elif f[4:6] == b'\xFE\xFF':
        bom = '>'

    else:
        print("\nInvalid BOM!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    header = Header(bom)
    header.data(f, pos)

    if bytes_to_string(header.magic) not in ["FWAV", "CWAV"]:
        print("\nUnsupported file format!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    print("\nMagic: " + bytes_to_string(header.magic))
    print("Header size: " + hex(header.size_))
    print("File version: " + hex(header.version))
    print("File size: " + hex(header.fileSize))
    print("Number of blocks: " + str(header.numBlocks))

    pos += header.size
    sized_refs = {}

    for i in range(1, header.numBlocks + 1):
        sized_refs[i] = Ref(bom)
        sized_refs[i].data(f, pos + 12 * (i - 1))
        sized_refs[i].block_size = struct.unpack(
            bom + "I", f[pos + 12 * (i - 1) + 8:pos + 12 * i])[0]

        if sized_refs[i].offset not in [0, -1]:
            if sized_refs[i].type_ == 0x7000:
                print("\nInfo Block offset: " + hex(sized_refs[i].offset))

            elif sized_refs[i].type_ == 0x7001:
                print("\nData Block offset: " + hex(sized_refs[i].offset))

            else:
                print("\n" + hex(sized_refs[i].type_) + " Block offset: " +
                      hex(sized_refs[i].offset))

            print("Size: " + hex(sized_refs[i].block_size))

    if sized_refs[1].type_ != 0x7000 or sized_refs[1].offset in [0, -1]:
        print("\nSomething went wrong!\nError code: 5")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    pos = sized_refs[1].offset

    info = BLKHeader(bom)
    info.data(f, pos)
    info.pos = pos

    print("\nInfo Block Magic: " + bytes_to_string(info.magic))
    print("Size: " + hex(info.size_))

    pos += info.size

    wavInfo = WAVInfo(bom)
    wavInfo.data(f, pos)

    codec = {0: "PCM8", 1: "PCM16", 2: "DSP ADPCM", 3: "IMA ADPCM"}
    if wavInfo.codec in codec:
        print("\nEncoding: " + codec[wavInfo.codec])

    else:
        print("\nEncoding: " + str(wavInfo.codec))

    print("Loop Flag: " + str(wavInfo.loop_flag))
    print("Sample Rate: " + str(wavInfo.sample))
    print("Loop Start Frame: " + str(wavInfo.loop_start))
    print("Loop End Frame: " + str(wavInfo.loop_end))

    pos += wavInfo.size

    channelInfoTable = {}
    ADPCMInfo_ref = {}

    count = struct.unpack(bom + "I", f[pos:pos + 4])[0]
    print("Channel Count: " + str(count))
    countPos = pos

    for i in range(1, count + 1):
        pos = countPos + 4
        channelInfoTable[i] = Ref(bom)
        channelInfoTable[i].data(f, pos + 8 * (i - 1))

        if channelInfoTable[i].offset not in [0, -1]:
            pos = channelInfoTable[i].offset + countPos
            print("\nChannel " + str(i) + " Info Entry offset: " + hex(pos))

            sampleData_ref = Ref(bom)
            sampleData_ref.data(f, pos)

            if sampleData_ref.offset not in [0, -1]:
                for z in range(1, header.numBlocks + 1):
                    if sized_refs[z].offset not in [0, -1]:
                        if sized_refs[z].type_ == 0x7001:
                            print("\nChannel " + str(i) +
                                  " Info Entry Sample Data offset: " +
                                  hex(sampleData_ref.offset +
                                      sized_refs[z].offset + 8))

            pos += 8

            print("\nChannel " + str(i) +
                  " Info Entry ADPCM Info Reference offset: " + hex(pos))

            ADPCMInfo_ref[i] = Ref(bom)
            ADPCMInfo_ref[i].data(f, pos)

            if ADPCMInfo_ref[i].offset not in [0, -1]:
                print("\nADPCM Info offset: " +
                      hex(ADPCMInfo_ref[i].offset + pos - 8))
                print("Type: " + hex(ADPCMInfo_ref[i].type_))

                pos = ADPCMInfo_ref[i].offset + pos - 8
                if ADPCMInfo_ref[i].type_ == 0x0300:
                    param = b''
                    for i in range(1, 17):
                        param += struct.unpack(
                            bom + "H", f[pos + 2 * (i - 1):pos + 2 * (i - 1) +
                                         2])[0].to_bytes(2, 'big')

                    print("Param: " + str(param))

                    pos += 32
                    context = DSPContext(bom)
                    context.data(f, pos)

                    print("Context Predictor and Scale: " +
                          hex(context.predictor_scale))
                    print("Context Previous Sample: " + hex(context.preSample))
                    print("Context Second Previous Sample: " +
                          hex(context.preSample2))

                    pos += context.size
                    loopContext = DSPContext(bom)
                    loopContext.data(f, pos)

                    print("Loop Context Predictor and Scale: " +
                          hex(loopContext.predictor_scale))
                    print("Loop Context Previous Sample: " +
                          hex(loopContext.preSample))
                    print("Loop Context Second Previous Sample: " +
                          hex(loopContext.preSample2))

                    pos += loopContext.size
                    pos += 2

                elif ADPCMInfo_ref[i].type_ == 0x0301:
                    context = IMAContext(bom)
                    context.data(f, pos)

                    print("Context Data: " + hex(context.data_))
                    print("Context Table Index: " + hex(context.tableIndex))

                    pos += context.size
                    loopContext = IMAContext(bom)
                    loopContext.data(f, pos)

                    print("Loop Context Data: " + hex(loopContext.data_))
                    print("Loop Context Table Index: " +
                          hex(loopContext.tableIndex))

                    pos += loopContext.size

    for i in range(1, header.numBlocks + 1):
        if sized_refs[i].offset not in [0, -1]:
            if sized_refs[i].type_ == 0x7001:
                pos = sized_refs[i].offset
                data = BLKHeader(bom)
                data.data(f, pos)

                print("\nData Block Magic: " + bytes_to_string(data.magic))
                print("Size: " + hex(data.size_))

                pos += data.size
                data.data_ = f[pos:pos + data.size_ - 8]
Exemple #6
0
def read(file):
    with open(file, "rb") as inf:
        f = inf.read()

    if f[:4] != b"FRES" or f[4:8] == b'    ':
        QtWidgets.QMessageBox.warning(None, "Error", "Invalid file header!")
        return False

    version = f[4]

    if version not in [3, 4]:
        QtWidgets.QMessageBox.warning(None, "Error",
                                      "Unsupported BFRES version!")
        return False

    group = empty()
    group.pos = struct.unpack(">i", f[0x24:0x28])[0]

    if group.pos == 0:
        return False

    group.pos += 0x28
    group.count = struct.unpack(">i", f[group.pos:group.pos + 4])[0]
    group.pos += 20

    textures = []
    texNames = []
    texSizes = []

    for i in range(group.count):
        nameAddr = struct.unpack(
            ">i", f[group.pos + 16 * i + 8:group.pos + 16 * i + 12])[0]
        nameAddr += group.pos + 16 * i + 8

        name = bytes_to_string(f, nameAddr)

        pos = struct.unpack(">i", f[group.pos + 16 * i + 12:group.pos +
                                    16 * i + 16])[0]
        pos += group.pos + 16 * i + 12

        ftex = empty()
        ftex.headAddr = pos

        pos += 4

        surface = GX2Surface()
        surface.data(f, pos)
        pos += surface.size

        if version == 4:
            surface.numMips = 1

        elif surface.numMips > 14:
            continue

        mipOffsets = []
        for j in range(13):
            mipOffsets.append(f[j * 4 + pos] << 24
                              | f[j * 4 + 1 + pos] << 16
                              | f[j * 4 + 2 + pos] << 8
                              | f[j * 4 + 3 + pos])

        pos += 68

        compSel = []
        compSel2 = []
        for j in range(4):
            comp = f[pos + j]
            compSel2.append(comp)
            if comp == 4:  # Sorry, but this is unsupported.
                comp = j

            compSel.append(comp)

        pos += 24

        ftex.name = name
        ftex.dim = surface.dim
        ftex.width = surface.width
        ftex.height = surface.height
        ftex.depth = surface.depth
        ftex.numMips = surface.numMips
        ftex.format = surface.format_
        ftex.aa = surface.aa
        ftex.use = surface.use
        ftex.imageSize = surface.imageSize
        ftex.imagePtr = surface.imagePtr
        ftex.mipSize = surface.mipSize
        ftex.mipPtr = surface.mipPtr
        ftex.tileMode = surface.tileMode
        ftex.swizzle = surface.swizzle
        ftex.alignment = surface.alignment
        ftex.pitch = surface.pitch
        ftex.compSel = compSel
        ftex.compSel2 = compSel2
        ftex.mipOffsets = mipOffsets

        ftex.surfInfo = addrlib.getSurfaceInfo(ftex.format, ftex.width,
                                               ftex.height, ftex.depth,
                                               ftex.dim, ftex.tileMode,
                                               ftex.aa, 0)

        if ftex.format in globals.BCn_formats:
            ftex.blkWidth, ftex.blkHeight = 4, 4

        else:
            ftex.blkWidth, ftex.blkHeight = 1, 1

        ftex.bpp = addrlib.surfaceGetBitsPerPixel(surface.format_) // 8

        dataAddr = struct.unpack(">i", f[ftex.headAddr + 0xB0:ftex.headAddr +
                                         0xB4])[0]
        dataAddr += ftex.headAddr + 0xB0

        ftex.dataAddr = dataAddr
        ftex.data = f[dataAddr:dataAddr + ftex.imageSize]

        mipAddr = struct.unpack(">i", f[ftex.headAddr + 0xB4:ftex.headAddr +
                                        0xB8])[0]
        if mipAddr and ftex.mipSize:
            mipAddr += ftex.headAddr + 0xB4
            ftex.mipData = f[mipAddr:mipAddr + ftex.mipSize]

        else:
            ftex.mipData = b''

        textures.append(ftex)
        texNames.append(name)
        texSizes.append([ftex.imageSize, ftex.mipSize])

    globals.fileData = bytearray(f)
    globals.texSizes = texSizes

    return textures, texNames
Exemple #7
0
def readFile(f):
    pos = 0

    if f[4:6] == b'\xFF\xFE':
        bom = '<'

    elif f[4:6] == b'\xFE\xFF':
        bom = '>'

    else:
        print("Invalid BOM!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    header = Header(bom)
    header.data(f, pos)

    if bytes_to_string(header.magic) not in ["FSTM", "CSTM", "FSTP"]:
        print("Unsupported file format!")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    print("Magic: " + bytes_to_string(header.magic))
    print("Header size: " + hex(header.size_))
    print("File version: " + hex(header.version))
    print("File size: " + hex(header.fileSize))
    print("Number of blocks: " + str(header.numBlocks))

    pos += header.size
    sized_refs = {}

    for i in range(1, header.numBlocks + 1):
        sized_refs[i] = Ref(bom)
        sized_refs[i].data(f, pos + 12 * (i - 1))
        sized_refs[i].block_size = struct.unpack(
            bom + "I", f[pos + 12 * (i - 1) + 8:pos + 12 * i])[0]

        if sized_refs[i].offset not in [0, -1]:
            if sized_refs[i].type_ == 0x4000:
                print("\nInfo Block offset: " + hex(sized_refs[i].offset))

            elif sized_refs[i].type_ == 0x4001:
                print("\nSeek Block offset: " + hex(sized_refs[i].offset))

            elif sized_refs[i].type_ == 0x4002:
                print("\nData Block offset: " + hex(sized_refs[i].offset))

            elif sized_refs[i].type_ == 0x4004:
                print("\nPrefetch Data Block offset: " +
                      hex(sized_refs[i].offset))

            else:
                print("\n" + hex(sized_refs[i].type_) + " Block offset: " +
                      hex(sized_refs[i].offset))

            print("Size: " + hex(sized_refs[i].block_size))

    if sized_refs[1].type_ != 0x4000 or sized_refs[1].offset in [0, -1]:
        print("\nSomething went wrong!\nError code: 1")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    pos = sized_refs[1].offset

    info = BLKHeader(bom)
    info.data(f, pos)

    print("\nInfo Block Magic: " + bytes_to_string(info.magic))
    print("Size: " + hex(info.size_))

    pos += info.size

    stmInfo_ref = Ref(bom)
    stmInfo_ref.data(f, pos)

    if stmInfo_ref.type_ != 0x4100 or stmInfo_ref.offset in [0, -1]:
        print("\nSomething went wrong!\nError code: 2")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    print("\nStream Info offset: " + hex(stmInfo_ref.offset + pos))

    stmInfo_ref.pos = pos
    pos += stmInfo_ref.size

    trkInfoTable_ref = Ref(bom)
    trkInfoTable_ref.data(f, pos)

    if trkInfoTable_ref.offset not in [0, -1
                                       ] and trkInfoTable_ref.type_ == 0x0101:
        print("\nTrack Info Reference Table offset: " +
              hex(trkInfoTable_ref.offset + stmInfo_ref.pos))

    elif not trkInfoTable_ref.type_ or trkInfoTable_ref.offset in [0, -1]:
        pass

    else:
        print("\nSomething went wrong!\nError code: 3")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    pos += trkInfoTable_ref.size

    channelInfoTable_ref = Ref(bom)
    channelInfoTable_ref.data(f, pos)

    if channelInfoTable_ref.type_ != 0x0101:
        print("\nSomething went wrong!\nError code: 4")
        print("\nExiting in 5 seconds...")
        time.sleep(5)
        sys.exit(1)

    if channelInfoTable_ref.offset not in [0, -1]:
        print("\nChannel Info Reference Table offset: " +
              hex(channelInfoTable_ref.offset + stmInfo_ref.pos))

    pos = stmInfo_ref.offset + stmInfo_ref.pos
    stmInfo = STMInfo(bom)
    stmInfo.data(f, pos)

    codec = {0: "PCM8", 1: "PCM16", 2: "DSP ADPCM", 3: "IMA ADPCM"}
    if stmInfo.codec in codec:
        print("\nEncoding: " + codec[stmInfo.codec])

    else:
        print("\nEncoding: " + str(stmInfo.codec))

    print("Loop Flag: " + str(stmInfo.loop_flag))
    print("Channel Count: " + str(stmInfo.count))
    print("Sample Rate: " + str(stmInfo.sample))
    print("Loop Start Frame: " + str(stmInfo.loop_start))
    print("Loop End Frame: " + str(stmInfo.loop_end))
    print("Sample Block Count: " + str(stmInfo.sampleBlk_count))
    print("Sample Block Size: " + hex(stmInfo.sampleBlk_size))
    print("Sample Block Sample Count: " + str(stmInfo.sampleBlk_sampleCount))
    print("Last Sample Block Size: " + hex(stmInfo.lSampleBlk_size))
    print("Last Sample Block Sample Count: " +
          str(stmInfo.lSampleBlk_sampleCount))
    print("Last Sample Block Padded Size: " + hex(stmInfo.lSampleBlk_padSize))
    print("Seek Data Size: " + hex(stmInfo.seek_size))
    print("Seek Interval Sample Count: " + str(stmInfo.SISC))

    pos += stmInfo.size

    sampleData_ref = Ref(bom)
    sampleData_ref.data(f, pos)

    if sampleData_ref.offset not in [0, -1]:
        for i in range(1, header.numBlocks + 1):
            if sized_refs[i].offset not in [0, -1]:
                if sized_refs[i].type_ == 0x4002:
                    print("Sample Data offset: " +
                          hex(sampleData_ref.offset + sized_refs[i].offset +
                              8))
                if sized_refs[i].type_ == 0x4004:
                    print("Prefetch Data offset: " +
                          hex(sampleData_ref.offset))

    pos += 8

    trkInfoTable = {}
    trkInfo = {}

    if trkInfoTable_ref.offset not in [0, -1]:
        pos = trkInfoTable_ref.offset + stmInfo_ref.pos
        count = struct.unpack(bom + "I", f[pos:pos + 4])[0]
        pos += 4

        for i in range(1, count + 1):
            pos = trkInfoTable_ref.offset + stmInfo_ref.pos + 4
            trkInfoTable[i] = Ref(bom)
            trkInfoTable[i].data(f, pos + 8 * (i - 1))

            if trkInfoTable[i].offset not in [0, -1]:
                print("\nTrack Info Entry " + str(i) + " offset: " +
                      hex(trkInfoTable[i].offset + pos - 4))

                pos = trkInfoTable[i].offset + pos - 4
                trkInfo[i] = TRKInfo(bom)
                trkInfo[i].data(f, pos)

                print("Volume: " + str(trkInfo[i].volume))
                print("Pan: " + str(trkInfo[i].pan))
                print("Unknown value: " + str(trkInfo[i].unk))
                pos += trkInfo[i].size
                channelIndexByteTable_ref = Ref(bom)
                channelIndexByteTable_ref.data(f, pos)

                if channelIndexByteTable_ref.offset not in [0, -1]:
                    print("Channel Index Byte Table offset: " +
                          hex(channelIndexByteTable_ref.offset + pos -
                              trkInfo[i].size))

                    pos = channelIndexByteTable_ref.offset + pos - trkInfo[
                        i].size
                    count = struct.unpack(bom + "I", f[pos:pos + 4])[0]
                    pos += 4
                    elem = f[pos:pos + count]

                    print("Elements: " + str(elem))

    channelInfoTable = {}
    ADPCMInfo_ref = {}

    pos = channelInfoTable_ref.offset + stmInfo_ref.pos
    count = struct.unpack(bom + "I", f[pos:pos + 4])[0]
    pos += 4

    for i in range(1, count + 1):
        pos = channelInfoTable_ref.offset + stmInfo_ref.pos + 4
        channelInfoTable[i] = Ref(bom)
        channelInfoTable[i].data(f, pos + 8 * (i - 1))

        if channelInfoTable[i].offset not in [0, -1]:
            print("\nChannel " + str(i) +
                  " Info Entry ADPCM Info Reference offset: " +
                  hex(channelInfoTable[i].offset + pos - 4))

            pos = channelInfoTable[i].offset + pos - 4
            ADPCMInfo_ref[i] = Ref(bom)
            ADPCMInfo_ref[i].data(f, pos)

            if ADPCMInfo_ref[i].offset not in [0, -1]:
                print("\nADPCM Info offset: " +
                      hex(ADPCMInfo_ref[i].offset + pos))
                print("Type: " + hex(ADPCMInfo_ref[i].type_))

                pos = ADPCMInfo_ref[i].offset + pos
                if ADPCMInfo_ref[i].type_ == 0x0300:
                    param = b''
                    for i in range(1, 17):
                        param += struct.unpack(
                            bom + "H", f[pos + 2 * (i - 1):pos + 2 * (i - 1) +
                                         2])[0].to_bytes(2, 'big')
                    print("Param: " + str(param))

                    pos += 32
                    context = DSPContext(bom)
                    context.data(f, pos)

                    print("Context Predictor and Scale: " +
                          hex(context.predictor_scale))
                    print("Context Previous Sample: " + hex(context.preSample))
                    print("Context Second Previous Sample: " +
                          hex(context.preSample2))

                    pos += context.size
                    loopContext = DSPContext(bom)
                    loopContext.data(f, pos)

                    print("Loop Context Predictor and Scale: " +
                          hex(loopContext.predictor_scale))
                    print("Loop Context Previous Sample: " +
                          hex(loopContext.preSample))
                    print("Loop Context Second Previous Sample: " +
                          hex(loopContext.preSample2))

                    pos += loopContext.size
                    pos += 2

                elif ADPCMInfo_ref[i].type_ == 0x0301:
                    context = IMAContext(bom)
                    context.data(f, pos)

                    print("Context Data: " + hex(context.data_))
                    print("Context Table Index: " + hex(context.tableIndex))

                    pos += context.size
                    loopContext = IMAContext(bom)
                    loopContext.data(f, pos)

                    print("Loop Context Data: " + hex(loopContext.data_))
                    print("Loop Context Table Index: " +
                          hex(loopContext.tableIndex))

                    pos += loopContext.size

    for i in range(1, header.numBlocks + 1):
        if sized_refs[i].offset not in [0, -1]:
            if sized_refs[i].type_ == 0x4001:
                pos = sized_refs[i].offset
                seek = BLKHeader(bom)
                seek.data(f, pos)

                print('')
                print("Seek Block Magic: " + bytes_to_string(seek.magic))
                print("Size: " + hex(seek.size_))
                pos += seek.size

                seek.data_ = f[pos:pos + seek.size_ - 8]

            elif sized_refs[i].type_ in [0x4002, 0x4004]:
                pos = sized_refs[i].offset
                data = BLKHeader(bom)
                data.data(f, pos)

                print('')
                if sized_refs[i].type_ == 0x4002:
                    print("Data Block Magic: " + bytes_to_string(data.magic))
                else:
                    print("Prefetch Data Block Magic: " +
                          bytes_to_string(data.magic))
                print("Size: " + hex(data.size_))

                pos += data.size
                data.data_ = f[pos:pos + data.size_ - 8]
Exemple #8
0
def read(file):
    with open(file, "rb") as inf:
        f = inf.read()

    pos = 0

    if f[0xc:0xe] == b'\xFF\xFE':
        bom = '<'

    elif f[0xc:0xe] == b'\xFE\xFF':
        bom = '>'

    else:
        QtWidgets.QMessageBox.warning(None, "Error", "Invalid BOM!")
        return False

    header = BNTXHeader(bom)
    header.data(f, pos)
    pos += header.size

    if header.magic != b'BNTX\0\0\0\0':
        QtWidgets.QMessageBox.warning(None, "Error", "Invalid file header!")
        return False

    fnameLen = struct.unpack(bom + 'H',
                             f[header.fileNameAddr - 2:header.fileNameAddr])[0]
    fname = bytes_to_string(
        f[header.fileNameAddr:header.fileNameAddr + fnameLen], fnameLen)

    texContainer = TexContainer(bom)
    texContainer.data(f, pos)
    pos += texContainer.size

    if texContainer.target not in [b'NX  ', b'Gen ']:
        QtWidgets.QMessageBox.warning(None, "Error",
                                      "Unsupported target platform!")
        return False

    target = 0 if texContainer.target == b'Gen ' else 1

    textures = []
    texNames = []
    texSizes = []

    for i in range(texContainer.count):
        pos = struct.unpack(
            bom + 'q', f[texContainer.infoPtrsAddr +
                         i * 8:texContainer.infoPtrsAddr + i * 8 + 8])[0]

        infoHeader = BlockHeader(bom)
        infoHeader.data(f, pos)
        pos += infoHeader.size

        info = TextureInfo(bom)
        info.data(f, pos)

        if infoHeader.magic != b'BRTI':
            continue

        nameLen = struct.unpack(bom + 'H',
                                f[info.nameAddr:info.nameAddr + 2])[0]
        name = bytes_to_string(
            f[info.nameAddr + 2:info.nameAddr + 2 + nameLen], nameLen)

        compSel = []
        compSel2 = []
        for i in range(4):
            value = (info.compSel >> (8 * (3 - i))) & 0xff
            compSel2.append(value)
            if value == 0:
                value = 5 - len(compSel)

            compSel.append(value)

        if info.type_ not in globals.types:
            globals.types[info.type_] = "Unknown"

        dataAddr = struct.unpack(bom + 'q',
                                 f[info.ptrsAddr:info.ptrsAddr + 8])[0]
        mipOffsets = {0: 0}

        for i in range(1, info.numMips):
            mipOffset = struct.unpack(
                bom + 'q',
                f[info.ptrsAddr + (i * 8):info.ptrsAddr + (i * 8) + 8])[0]
            mipOffsets[i] = mipOffset - dataAddr

        tex = TexInfo()

        tex.infoAddr = pos
        tex.info = info
        tex.bom = bom
        tex.target = target

        tex.name = name

        tex.readTexLayout = info.flags & 1
        tex.sparseBinding = info.flags >> 1
        tex.sparseResidency = info.flags >> 2
        tex.dim = info.dim
        tex.tileMode = info.tileMode
        tex.numMips = info.numMips
        tex.width = info.width
        tex.height = info.height
        tex.format = info.format_
        tex.arrayLength = info.arrayLength
        tex.blockHeightLog2 = info.textureLayout & 7
        tex.imageSize = info.imageSize

        tex.compSel = compSel
        tex.compSel2 = compSel2

        tex.alignment = info.alignment
        tex.type = info.type_

        tex.mipOffsets = mipOffsets
        tex.dataAddr = dataAddr

        tex.data = f[dataAddr:dataAddr + info.imageSize]

        textures.append(tex)
        texNames.append(name)
        texSizes.append(info.imageSize)

    globals.fileData = bytearray(f)
    globals.texSizes = texSizes

    return fname, texContainer.target.decode('utf-8'), textures, texNames
Exemple #9
0
    def _load(self, data):

        # SARC Header -----------------------------------------

        # File magic (0x00 - 0x03)
        if not data.startswith(b'SARC'):
            return 1

        # Come back to header length later, when we have endianness

        # Endianness/BOM (0x06 - 0x07)
        bom = bytes(data[0x06:0x08])
        endians = {b'\xFE\xFF': '>', b'\xFF\xFE': '<'}
        if bom not in endians:
            return 2

        self.endianness = endians[bom]

        # Header length (0x04 - 0x05)
        headLen = struct.unpack(self.endianness + 'H', data[0x04:0x06])[0]
        if headLen != 0x14:
            return 3

        # File Length (0x08 - 0x0B)
        filelen = struct.unpack(self.endianness + 'I', data[0x08:0x0C])[0]
        if len(data) != filelen:
            return 4

        # Beginning Of Data offset (0x0C - 0x0F)
        begOfDat = struct.unpack(self.endianness + 'I', data[0x0C:0x10])[0]

        # SFAT Header -----------------------------------------

        # Sanity check (0x14 - 0x17)
        if data[0x14:0x18] != b'SFAT':
            return 5

        # Header length (0x18 - 0x19)
        headLen = struct.unpack(self.endianness + 'H', data[0x18:0x1A])[0]
        if headLen != 0x0C:
            return 6

        # Node count (0x1A - 0x1C)
        nodeCount = struct.unpack(self.endianness + 'H', data[0x1A:0x1C])[0]

        # Hash multiplier (0x1D - 0x1F)
        self.hashMultiplier = struct.unpack(self.endianness + 'I', data[0x1C:0x20])[0]

        # SFAT Nodes (0x20 - 0x20+(0x10*nodeCount))
        SFATNodes = []

        SFATNodeOffset = 0x20
        for nodeNum in range(nodeCount):
            if self.endianness == '>':
                unkFlagOffset = SFATNodeOffset + 4
                fileNameTableEntryOffsetOffset = SFATNodeOffset + 5

            else:
                unkFlagOffset = SFATNodeOffset + 7
                fileNameTableEntryOffsetOffset = SFATNodeOffset + 4

            # Unknown flag: Could function as a file/folder flag.
            unkFlag = data[unkFlagOffset]

            # File Name Table Entry offset
            if self.endianness == '>':
                fileNameTableEntryOffsetData = (b'\x00' +
                                                data[fileNameTableEntryOffsetOffset:
                                                     fileNameTableEntryOffsetOffset + 3])

            else:
                fileNameTableEntryOffsetData = \
                    data[fileNameTableEntryOffsetOffset:
                         fileNameTableEntryOffsetOffset + 3] + b'\x00'

            fileNameTableEntryOffset = struct.unpack(
                self.endianness + 'I',
                fileNameTableEntryOffsetData)[0]

            # Beginning of Node File Data
            fileDataStart = struct.unpack(
                self.endianness + 'I', data[SFATNodeOffset + 8:SFATNodeOffset + 0x0C])[0]

            # End of Node File Data
            fileDataEnd = struct.unpack(
                self.endianness + 'I', data[SFATNodeOffset + 0x0C:SFATNodeOffset + 0x10])[0]

            # Calculate file data length
            fileDataLength = fileDataEnd - fileDataStart

            # Add an entry to the node list
            SFATNodes.append(
                (unkFlag, fileNameTableEntryOffset, fileDataStart, fileDataLength))

            # Increment the offset counter
            SFATNodeOffset += 0x10

        # SFNT Header -----------------------------------------

        # From now on we need to keep track of an offset variable
        offset = 0x20 + (0x10 * nodeCount)

        # Sanity check (offset - offset+0x03)
        if data[offset:offset + 0x04] != b'SFNT':
            return 7

        # Header length (offset+0x04 - offset+0x05)
        headLen = struct.unpack(self.endianness + 'H', data[offset + 0x04:offset + 0x06])[0]
        if headLen != 0x08:
            return 8

        # Increment the offset
        offset += 0x08

        # Add the files to the self.contents set --------------
        self.clear()
        for unkFlag, fileNameTableEntryOffset, fileDataStart, fileDataLength in SFATNodes:

            # Get the file name (search for the first null byte manually)
            nameOffset = offset + (fileNameTableEntryOffset * 4)
            name = bytes_to_string(data, nameOffset)

            # Get the file data
            fileData = data[begOfDat + fileDataStart:
                            begOfDat + fileDataStart + fileDataLength]

            # Split it into its folders
            folderStructure = name.split('/')

            # Handle it differently if the file is not in a folder
            if len(folderStructure) == 1:
                self.contents.add(File(name, fileData))

            else:

                # Get the first folder, or make one if needed
                folderName = folderStructure[0]
                for foundFolder in self.contents:
                    if not isinstance(foundFolder, Folder):
                        continue

                    if foundFolder.name == folderName:
                        break

                else:
                    foundFolder = Folder(folderName)
                    self.contents.add(foundFolder)

                # Now find/make the rest of them
                outerFolder = foundFolder
                for folderName in folderStructure[1:-1]:
                    for foundFolder in outerFolder.contents:
                        if not isinstance(foundFolder, Folder):
                            continue

                        if foundFolder.name == folderName:
                            break

                    else:
                        foundFolder = Folder(folderName)
                        outerFolder.addFolder(foundFolder)

                    outerFolder = foundFolder

                # Now make a new file and add it to self.contents
                outerFolder.addFile(File(folderStructure[-1], fileData))

        # We're done! Return True so no exception will be thrown.
        return True