Example #1
0
def readShiftJIS(f, encoding="shift_jis"):
    strlen = f.readUInt()
    sjis = ""
    i = 0
    while i < strlen:
        b1 = f.readByte()
        if b1 == 0x0A:
            sjis += "|"
            i += 1
        else:
            b2 = f.readByte()
            if (b1, b2) in fixchars:
                sjis += fixchars[(b1, b2)]
                i += 2
            elif not common.checkShiftJIS(b1, b2):
                if b2 == 0x01:
                    sjis += "UNK(" + common.toHex(b1) + common.toHex(b2) + ")"
                    i += 2
                else:
                    f.seek(-1, 1)
                    sjis += chr(b1)
                    i += 1
            else:
                f.seek(-2, 1)
                try:
                    sjis += f.read(2).decode(encoding).replace("〜", "~")
                except UnicodeDecodeError:
                    common.logError("[ERROR] UnicodeDecodeError")
                    sjis += "[ERROR" + str(f.tell() - 2) + "]"
                i += 2
    return sjis
Example #2
0
def readShiftJIS(f):
    len = f.readShort()
    pos = f.tell()
    # Check if the string is all ascii
    ascii = True
    for i in range(len - 1):
        byte = f.readByte()
        if byte != 0x0A and (byte < 32 or byte > 122):
            ascii = False
            break
    if not ascii:
        f.seek(pos)
        sjis = ""
        i = 0
        while i < len - 1:
            byte = f.readByte()
            if byte in codes:
                sjis += "<" + common.toHex(byte) + ">"
                i += 1
            else:
                f.seek(-1, 1)
                try:
                    sjis += f.read(2).decode("shift-jis").replace("〜", "~")
                except UnicodeDecodeError:
                    common.logError("UnicodeDecodeError")
                    sjis += "|"
                i += 2
        return sjis
    return ""
Example #3
0
def readMappedImage(f, outfile, mapstart=0, num=1, bpp=2, width=0, height=0):
    f.seek(mapstart)
    maps = []
    for j in range(num):
        map = TileMap()
        if num > 1:
            map.name = outfile.replace(".png",
                                       "_" + str(j + 1).zfill(2) + ".png")
        else:
            map.name = outfile
        map.offset = f.tell()
        map.width = width
        if map.width == 0:
            map.width = f.readByte()
        map.height = height
        if map.height == 0:
            map.height = f.readByte()
        map.bpp = bpp
        common.logDebug(" ", mapstart, vars(map))
        map.map = []
        for i in range(map.width * map.height):
            tilemap = TileMap()
            tilemap.data = f.readUShort()
            tilemap.tile = tilemap.data & 0x1ff
            tilemap.pal = (tilemap.data >> 9) & 0xf
            tilemap.bank = (tilemap.data >> 13) & 1
            if tilemap.bank != 0 and bpp == 2:
                common.logError("Bank is not 0")
            tilemap.hflip = ((tilemap.data >> 14) & 1) == 1
            tilemap.vflip = ((tilemap.data >> 15) & 1) == 1
            map.map.append(tilemap)
        maps.append(map)
    common.logDebug("Map data ended at", common.toHex(f.tell()))
    return maps
Example #4
0
def repackBinaryStrings(elf,
                        section,
                        infile,
                        outfile,
                        readfunc,
                        writefunc,
                        encoding="shift_jis",
                        elfsections=[".rodata"]):
    with common.Stream(infile, "rb") as fi:
        with common.Stream(outfile, "r+b") as fo:
            for sectionname in elfsections:
                rodata = elf.sectionsdict[sectionname]
                fi.seek(rodata.offset)
                while fi.tell() < rodata.offset + rodata.size:
                    pos = fi.tell()
                    check = readfunc(fi, encoding)
                    if check != "":
                        if check in section and section[check][0] != "":
                            common.logDebug("Replacing string", check, "at",
                                            common.toHex(pos), "with",
                                            section[check][0])
                            fo.seek(pos)
                            endpos = fi.tell() - 1
                            newlen = writefunc(fo, section[check][0],
                                               endpos - pos + 1)
                            if newlen < 0:
                                fo.writeZero(1)
                                common.logError("String", section[check][0],
                                                "is too long.")
                            else:
                                fo.writeZero(endpos - fo.tell())
                        else:
                            pos = fi.tell() - 1
                    fi.seek(pos + 1)
Example #5
0
def extract(file, outfolder, guessextension=None):
    common.logDebug("Processing", file, "...")
    common.makeFolder(outfolder)
    cpk = readCPK(file)
    if cpk is None:
        common.logError("Error reading CPK")
        return
    if len(cpk.filetable) == 0:
        common.logError("No files in CPK filetable")
        return
    with common.Stream(file, "rb") as f:
        for entry in cpk.filetable:
            if entry.filetype != "FILE":
                continue
            folder, filename = entry.getFolderFile(outfolder)
            f.seek(entry.fileoffset)
            data = f.read(entry.filesize)
            f.seek(entry.fileoffset)
            checkcomp = f.readString(8)
            if checkcomp == "CRILAYLA":
                extractsize = entry.extractsize if entry.extractsize != 0 else entry.filesize
                if extractsize != 0:
                    data = compression.decompressCRILAYLA(f, entry.fileoffset)
            if guessextension is not None:
                filename = guessextension(data, entry, filename)
            if not os.path.isdir(folder):
                common.makeFolders(folder)
            with common.Stream(folder + filename, "wb") as fout:
                fout.write(data)
Example #6
0
def readGIM(file, start=0):
    gim = GIM()
    with common.Stream(file, "rb") as f:
        f.seek(start)
        if f.readString(3) == 'MIG':
            f.seek(start + 16)
            gim.rootoff = f.tell()
            id = f.readUShort()
            if id != 0x02:
                common.logError("Unexpected id in block 0:", common.toHex(id),
                                common.toHex(f.tell() - 2))
                return None
            f.seek(2, 1)
            gim.rootsize = f.readUInt()
            nextblock = gim.rootoff + f.readUInt()
            image = None
            while nextblock > 0 and nextblock < start + gim.rootsize + 16:
                f.seek(nextblock)
                nextblock, image = readGIMBlock(f, gim, image)
        else:
            # This is a TGA file, assuming 32bit RGBA
            image = TGAImage()
            image.rootoff = f.tell()
            f.seek(start + 2)
            image.format = f.readByte()
            f.seek(9, 1)
            image.width = f.readUShort()
            image.height = f.readUShort()
            f.seek(2, 1)
            image.imgoff = f.tell()
            for i in range(image.height):
                for j in range(image.width):
                    image.colors.append(readColor(f, 0x03))
            gim = image
    return gim
Example #7
0
def writeString(f, s, table, ccodes, maxlen=0, usebigrams=False):
    s = s.replace("~", "〜")
    x = i = 0
    while x < len(s):
        c = s[x]
        if c == "<" and x < len(s) - 4 and s[x:x + 4] in codes:
            number = int(s[x + 4:].split(">", 1)[0])
            f.writeUShort(codes[s[x:x + 4]])
            f.writeUShort(number)
            x += 4 + len(str(number))
            i += 4
        elif c == "<":
            code = s[x + 1:].split(">", 1)[0]
            if code in singlecodes:
                f.writeUShort(singlecodes[code])
            else:
                f.writeUShort(int(code, 16))
            x += 1 + len(code)
            i += 2
        elif c == "U" and x < len(s) - 4 and s[x:x + 4] == "UNK(":
            code = s[x + 6] + s[x + 7]
            f.writeByte(int(code, 16))
            code = s[x + 4] + s[x + 5]
            f.writeByte(int(code, 16))
            x += 8
            i += 2
        elif c == ">" and s[x + 1] == ">":
            f.writeUShort(0xff00)
            f.writeUShort(0xff04)
            x += 1
            i += 4
        elif c == "|":
            i += 2
            f.writeUShort(0xff02)
        elif c in ccodes or ord(c) < 256:
            i += 1
            if c not in ccodes:
                common.logError("Character not found:", c, "in string", s)
                c = " "
            if x < len(s) - 1 and c + s[x + 1] in ccodes:
                f.writeByte(int(ccodes[c + s[x + 1]][0], 16))
                x += 1
            else:
                f.writeByte(int(ccodes[c][0], 16))
        else:
            if c in table:
                f.writeUShort(int(table[c], 16))
            else:
                f.writeUShort(0)
            i += 2
        x += 1
        if maxlen > 0 and i > maxlen:
            common.logError("Line too long",
                            str(i) + "/" + str(len(s) - x) + "/" + str(maxlen),
                            s)
            i = -1
            break
    return i
Example #8
0
def readGTOC(f, cpk, tocoffset):
    f.seek(tocoffset)
    headercheck = f.readString(4)
    if headercheck != "GTOC":
        common.logError("Wrong GTOC header", headercheck)
        return
    utfpacket, utfsize, encrypted = readUTFData(f)
    tocentry = cpk.getFileEntry("GTOC_HDR")
    tocentry.encrypted = encrypted
    tocentry.filesize = utfsize
    files = readUTF(utfpacket, tocoffset)
Example #9
0
def extractBRFNT(infile, outfile):
    brfnt2tpl = common.bundledExecutable("brfnt2tpl.exe")
    if not os.path.isfile(brfnt2tpl):
        common.logError("brfnt2tpl not found")
        return
    common.execute(brfnt2tpl + " {file}".format(file=infile), False)
    common.execute(
        "wimgt DECODE " + infile.replace(".brfnt", ".tpl") + " -D " + outfile,
        False)
    os.remove(infile.replace(".brfnt", ".tpl"))
    os.remove(infile.replace(".brfnt", ".vbfta"))
Example #10
0
def extractRom(romfile, extractfolder, workfolder=""):
    common.logMessage("Extracting ROM", romfile, "...")
    ndstool = common.bundledExecutable("ndstool.exe")
    if not os.path.isfile(ndstool):
        common.logError("ndstool not found")
        return
    common.makeFolder(extractfolder)
    common.execute(ndstool + " -x {rom} -9 {folder}arm9.bin -7 {folder}arm7.bin -y9 {folder}y9.bin -y7 {folder}y7.bin -t {folder}banner.bin -h {folder}header.bin -d {folder}data -y {folder}overlay".
                   format(rom=romfile, folder=extractfolder), False)
    if workfolder != "":
        common.copyFolder(extractfolder, workfolder)
    common.logMessage("Done!")
Example #11
0
def readUTF(f, baseoffset, storeraw=False):
    offset = f.tell()
    headercheck = f.readString(4)
    if headercheck != "@UTF":
        common.logError("Wrong UTF header", headercheck)
        return None
    utf = UTF()
    utf.tablesize = f.readInt()
    utf.rowsoffset = f.readInt() + offset + 8
    utf.stringsoffset = f.readInt() + offset + 8
    utf.dataoffset = f.readInt() + offset + 8
    utf.tablename = f.readInt()
    utf.numcolumns = f.readShort()
    utf.rowlength = f.readShort()
    utf.numrows = f.readInt()
    utf.baseoffset = baseoffset
    if storeraw:
        utf.rawpacket = f
    # common.logDebug("UTF", vars(utf))
    for i in range(utf.numcolumns):
        column = UTFColumn()
        column.flags = f.readByte()
        if column.flags == 0:
            common.logDebug("Column flag is 0, skipping 3 bytes")
            f.seek(3, 1)
            column.flags = f.readByte()
        column.storagetype = column.flags & UTFColumnFlags.STORAGE_MASK
        nameoffset = f.readInt() + utf.stringsoffset
        # Assume ASCII, might be better to assume UTF8?
        column.name = f.readNullStringAt(nameoffset)
        if column.flags & UTFColumnFlags.STORAGE_MASK == UTFColumnFlags.STORAGE_CONSTANT:
            column.position = f.tell()
            column.data, column.type = readUTFTypedData(f, utf, column.flags)
        utf.columns.append(column)
        utf.columnlookup[column.name] = i
        common.logDebug("UTFColumn", i, vars(column))
    for j in range(utf.numrows):
        f.seek(utf.rowsoffset + (j * utf.rowlength))
        rows = []
        for i in range(utf.numcolumns):
            column = utf.columns[i]
            row = UTFRow()
            if column.storagetype == UTFColumnFlags.STORAGE_ZERO:
                row.data = 0
            elif column.storagetype == UTFColumnFlags.STORAGE_CONSTANT:
                row.data = column.data
            elif column.storagetype == UTFColumnFlags.STORAGE_PERROW:
                row.position = f.tell()
                row.data, row.type = readUTFTypedData(f, utf, column.flags)
            rows.append(row)
            # common.logDebug("UTFRow", j, i, column.name, vars(row))
        utf.rows.append(rows)
    return utf
Example #12
0
def repackRom(romfile, rompatch, workfolder, patchfile=""):
    common.logMessage("Repacking ROM", rompatch, "...")
    ndstool = common.bundledExecutable("ndstool.exe")
    if not os.path.isfile(ndstool):
        common.logError("ndstool not found")
        return
    common.execute(ndstool + " -c {rom} -9 {folder}arm9.bin -7 {folder}arm7.bin -y9 {folder}y9.bin -y7 {folder}y7.bin -t {folder}banner.bin -h {folder}header.bin -d {folder}data -y {folder}overlay".
                   format(rom=rompatch, folder=workfolder), False)
    common.logMessage("Done!")
    # Create xdelta patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, romfile, rompatch)
Example #13
0
def readSprite(f,
               spritelen,
               outfile,
               spritestart=0,
               bpp=2,
               width=0,
               height=0,
               ignorepal=False):
    f.seek(spritestart)
    xmax = ymax = 0
    tiles = []
    for i in range(spritelen):
        spritemap = SpriteData()
        spritemap.data = f.readUInt()
        spritemap.tile = spritemap.data & 0x1ff
        spritemap.pal = (spritemap.data >> 9) & 0x7
        spritemap.hflip = ((spritemap.data >> 14) & 1) == 1
        spritemap.vflip = ((spritemap.data >> 15) & 1) == 1
        spritemap.ypos = (spritemap.data >> 16) & 0xff
        if spritemap.ypos % 8 != 0:
            common.logError("Sprite ypos is not a multiple of 8",
                            spritemap.ypos)
        spritemap.xpos = (spritemap.data >> 24) & 0xff
        if spritemap.xpos % 8 != 0:
            common.logError("Sprite xpos is not a multiple of 8",
                            spritemap.xpos)
        if spritemap.ypos > ymax:
            ymax = spritemap.ypos
        if spritemap.xpos > xmax:
            xmax = spritemap.xpos
        tiles.append(spritemap)
    # Convert this to map data
    map = TileMap()
    map.name = outfile
    map.offset = spritestart
    map.width = (xmax + 8) // 8
    map.height = (ymax + 8) // 8
    map.bpp = bpp
    map.map = []
    for y in range(map.height):
        for x in range(map.width):
            data = TileData(0)
            # Search for a sprite with these coordinates
            for i in range(len(tiles)):
                if tiles[i].ypos == y * 8 and tiles[i].xpos == x * 8:
                    data.tile = tiles[i].tile
                    if not ignorepal:
                        data.pal = tiles[i].pal
                    data.hflip = tiles[i].hflip
                    data.vflip = tiles[i].vflip
                    break
            map.map.append(data)
    return [map]
Example #14
0
def mpstopmf(infile, outfile, duration):
    with common.Stream(infile, "rb", False) as fin:
        # Check header
        check1 = fin.readUInt()
        check2 = fin.readByte()
        if check1 != 0x1ba or check2 != 0x44:
            common.logError("Input header is wrong", common.toHex(check1),
                            common.toHeck(check2))
            return
        fin.seek(0)
        mpsdata = fin.read()
    # https://github.com/TeamPBCN/pmftools/blob/main/mps2pmf/mps2pmf.cpp
    with common.Stream(outfile, "wb", False) as f:
        # Magic
        f.writeString("PSMF")
        f.writeString("0012")
        # Header size
        f.writeUInt(0x800)
        # MPS size
        f.writeUInt(len(mpsdata))
        f.seek(0x50)
        # Other header values
        f.writeUInt(0x4e)
        f.writeUInt(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0)
        f.writeUInt(duration)
        f.writeUInt(0x61a8)
        f.writeUShort(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0x201)
        f.writeUShort(0)
        f.writeUShort(0x34)
        f.writeUShort(0)
        f.writeUShort(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0)
        f.writeUInt(duration)
        f.writeUShort(1)
        f.writeUInt(0x22)
        f.writeUShort(0x2)
        f.writeUShort(0xe000)
        f.writeUShort(0x21ef)
        f.writeUShort(0)
        f.writeUInt(0x0)
        f.writeUInt(0x1e11)
        f.writeUInt(0xbd00)
        f.writeUShort(0x2004)
        f.seek(0xa0)
        f.writeUShort(0x202)
        # Everything else is 0, write the MPS data
        f.seek(0x800)
        f.write(mpsdata)
Example #15
0
def writeMappedImage(f, tilestart, maps, palettes, num=1, skipzero=False):
    maxtile = tilesize = 0
    for i in range(num):
        mapdata = maps[i]
        if mapdata.width == 0:
            common.logError("Width is 0")
            continue
        if mapdata.height == 0:
            common.logError("Height is 0")
            continue
        imgwidth = mapdata.width * 8
        imgheight = mapdata.height * 8
        pali = 0
        if mapdata.bpp == 4 and palettes != colpalette:
            imgwidth += 40
            for palette in palettes:
                if palette.count((0x0, 0x0, 0x0, 0xff)) == 16:
                    break
                pali += 1
            imgheight = max(imgheight, pali * 10)
        img = Image.new("RGB", (imgwidth, imgheight), (0x0, 0x0, 0x0))
        pixels = img.load()
        x = y = 0
        for map in mapdata.map:
            tilesize = (16 if mapdata.bpp == 2 else 32)
            if map.tile > maxtile:
                maxtile = map.tile
            if (map.tile > 0 or not skipzero) and (mapdata.bpp != 2
                                                   or map.bank == 0):
                f.seek(tilestart + map.bank * 0x4000 + map.tile * tilesize)
                try:
                    readTile(
                        f, pixels, x * 8, y * 8, palettes[map.pal]
                        if map.pal < len(palettes) else palettes[0], map.hflip,
                        map.vflip, mapdata.bpp)
                except struct.error:
                    pass
                except IndexError:
                    pass
            x += 1
            if x == mapdata.width:
                y += 1
                x = 0
        if pali > 0:
            palstart = 0
            for i in range(pali):
                pixels = common.drawPalette(pixels, palettes[i], imgwidth - 40,
                                            palstart * 10)
                palstart += 1
        img.save(mapdata.name, "PNG")
    common.logDebug("Tile data ended at",
                    common.toHex(tilestart + maxtile * tilesize + tilesize))
Example #16
0
def patchdump():
    patchfile = "data/bad_to_good.xdelta"
    common.logMessage("Creating xdelta patch", patchfile, "...")
    xdelta = common.bundledFile("xdelta.exe")
    if not os.path.isfile(xdelta):
        common.logError("xdelta not found")
        return
    common.execute(
        xdelta + " -f -e -s {rom} {rompatch} {patch}".format(
            rom=romfile.replace(".nds", "_bad.nds"),
            rompatch=romfile,
            patch=patchfile), False)
    common.logMessage("Done!")
Example #17
0
def repackBRFNT(outfile, workfile):
    brfnt2tpl = common.bundledExecutable("brfnt2tpl.exe")
    if not os.path.isfile(brfnt2tpl):
        common.logError("brfnt2tpl not found")
        return
    common.execute(brfnt2tpl + " {file}".format(file=outfile), False)
    tplfile = outfile.replace(".brfnt", ".tpl")
    tpl = readTPL(tplfile)
    writeTPL(tplfile, tpl, workfile)
    common.execute(
        brfnt2tpl + " {file}".format(file=outfile.replace(".brfnt", ".tpl")),
        False)
    os.remove(outfile.replace(".brfnt", ".tpl"))
    os.remove(outfile.replace(".brfnt", ".vbfta"))
Example #18
0
def repackEXE(binrange,
              freeranges=None,
              manualptrs=None,
              readfunc=common.detectEncodedString,
              writefunc=common.writeEncodedString,
              encoding="shift_jis",
              comments="#",
              exein="",
              exeout="",
              ptrfile="data/manualptrs.asm",
              exefile="data/exe_input.txt"):
    if not os.path.isfile(exefile):
        common.logError("Input file", exefile, "not found")
        return False

    common.copyFile(exein, exeout)
    common.logMessage("Repacking EXE from", exefile, "...")
    section = {}
    with codecs.open(exefile, "r", "utf-8") as bin:
        section = common.getSection(bin, "", comments)
        chartot, transtot = common.getSectionPercentage(section)
    if type(binrange) == tuple:
        binrange = [binrange]
    notfound = common.repackBinaryStrings(section, exein, exeout, binrange,
                                          freeranges, readfunc, writefunc,
                                          encoding, 0x8000F800)
    # Handle not found pointers by manually replacing the opcodes
    if len(notfound) > 0 and manualptrs is not None:
        with open(ptrfile, "w") as f:
            for ptr in notfound:
                if ptr.old not in manualptrs:
                    common.logError("Manual pointer", common.toHex(ptr.old),
                                    "->", common.toHex(ptr.new),
                                    "not found for string", ptr.str)
                    continue
                for manualptr in manualptrs[ptr.old]:
                    ptrloc = manualptr[0]
                    ptrreg = manualptr[1]
                    common.logDebug("Reassembling manual pointer",
                                    common.toHex(ptr.old), "->",
                                    common.toHex(ptr.new), "at",
                                    common.toHex(ptrloc), ptrreg)
                    f.write(".org 0x" + common.toHex(ptrloc) + "\n")
                    f.write(".area 0x8,0x0\n")
                    f.write("  li " + ptrreg + ",0x" + common.toHex(ptr.new) +
                            "\n")
                    f.write(".endarea\n\n")
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
    return True
Example #19
0
def extractBIN(infolder, outfolder, cuefile, data="data/"):
    common.logMessage("Extracting BIN", cuefile, "...")
    if not os.path.isfile("psximager\\psxrip.exe"):
        common.logError("psximager not found")
        return
    common.clearFolder(infolder)
    common.execute(
        "psximager\\psxrip.exe \"{iso}\" \"{folder}\"".format(
            iso=cuefile, folder=infolder[:-1]), False)
    common.copyFile(data + "extract.sys", data + "repack.sys")
    with open(data + "extract.cat", "r") as fin:
        with open(data + "repack.cat", "w") as fout:
            fout.write(fin.read().replace(data + "extract", data + "repack"))
    common.copyFolder(infolder, outfolder)
    common.logMessage("Done!")
Example #20
0
def readCPK(file):
    with common.Stream(file, "rb") as f:
        magic = f.readString(4)
        if magic != 'CPK ':
            common.logError("Wrong magic:", magic)
            return None
        cpk = CPK()
        utfoffset = f.tell()
        utfpacket, utfsize, encrypted = readUTFData(f)
        cpak = CPKFileEntry()
        cpak.filename = "CPK_HDR"
        cpak.fileoffsetpos = f.tell() + 0x10
        cpak.filesize = utfsize
        cpak.encrypted = encrypted
        cpak.filetype = "CPK"
        utf = readUTF(utfpacket, utfoffset, True)
        if utf is None:
            common.logError("Error reading first UTF")
            return None
        cpak.utf = utf
        cpk.filetable.append(cpak)
        tocoffset, tocoffsetpos = utf.getColumnData(0, "TocOffset", UTFStructTypes.DATA_TYPE_UINT64)
        etocoffset, etocoffsetpos = utf.getColumnData(0, "EtocOffset", UTFStructTypes.DATA_TYPE_UINT64)
        itocoffset, itocoffsetpos = utf.getColumnData(0, "ItocOffset", UTFStructTypes.DATA_TYPE_UINT64)
        gtocoffset, gtocoffsetpos = utf.getColumnData(0, "GtocOffset", UTFStructTypes.DATA_TYPE_UINT64)
        contentoffset, contentoffsetpos = utf.getColumnData(0, "ContentOffset", UTFStructTypes.DATA_TYPE_UINT64)
        cpk.filetable.append(CPKFileEntry.createEntry("CONTENT_OFFSET", contentoffset, UTFStructTypes.DATA_TYPE_UINT64, contentoffsetpos, "CPK", "CONTENT", False))
        files, _ = utf.getColumnData(0, "Files", UTFStructTypes.DATA_TYPE_UINT32)
        cpk.align, _ = utf.getColumnData(0, "Align", UTFStructTypes.DATA_TYPE_UINT16)
        common.logDebug("tocoffset", common.toHex(tocoffset), "tocoffsetpos", common.toHex(tocoffsetpos))
        common.logDebug("etocoffset", common.toHex(etocoffset), "etocoffsetpos", common.toHex(etocoffsetpos))
        common.logDebug("itocoffset", common.toHex(itocoffset), "itocoffsetpos", common.toHex(itocoffsetpos))
        common.logDebug("gtocoffset", common.toHex(gtocoffset), "gtocoffsetpos", common.toHex(gtocoffsetpos))
        common.logDebug("contentoffset", common.toHex(contentoffset), "contentoffsetpos", common.toHex(contentoffsetpos))
        common.logDebug("files", common.toHex(files), "align", common.toHex(cpk.align))
        if tocoffset != 0xffffffffffffffff:
            cpk.filetable.append(CPKFileEntry.createEntry("TOC_HDR", tocoffset, UTFStructTypes.DATA_TYPE_UINT64, tocoffsetpos, "CPK", "HDR", False))
            readTOC(f, cpk, tocoffset, contentoffset)
        if etocoffset != 0xffffffffffffffff:
            cpk.filetable.append(CPKFileEntry.createEntry("ETOC_HDR", etocoffset, UTFStructTypes.DATA_TYPE_UINT64, etocoffsetpos, "CPK", "HDR", False))
            readETOC(f, cpk, etocoffset)
        if itocoffset != 0xffffffffffffffff:
            cpk.filetable.append(CPKFileEntry.createEntry("ITOC_HDR", itocoffset, UTFStructTypes.DATA_TYPE_UINT64, itocoffsetpos, "CPK", "HDR", False))
            readITOC(f, cpk, itocoffset, contentoffset, cpk.align)
        if gtocoffset != 0xffffffffffffffff:
            cpk.filetable.append(CPKFileEntry.createEntry("GTOC_HDR", gtocoffset, UTFStructTypes.DATA_TYPE_UINT64, gtocoffsetpos, "CPK", "HDR", False))
            readGTOC(f, cpk, gtocoffset)
        return cpk
Example #21
0
def readTIM(f, forcesize=0):
    tim = TIM()
    # Read header
    header = f.readUInt()
    if header != 0x10:
        return None
    type = f.readUInt()
    if type == 0x08:
        tim.bpp = 4
    elif type == 0x09:
        tim.bpp = 8
    elif type == 0x02:
        tim.bpp = 16
    elif type == 0x03:
        tim.bpp = 24
    else:
        common.logError("Unknown TIM type", common.toHex(type))
        return None
    # Read palettes
    if tim.bpp == 4 or tim.bpp == 8:
        tim.clutsize = f.readUInt()
        tim.clutposx = f.readUShort()
        tim.clutposy = f.readUShort()
        tim.clutwidth = f.readUShort()
        tim.clutheight = f.readUShort()
        tim.clutoff = f.tell()
        for i in range(tim.clutheight):
            clut = readCLUTData(f, tim.clutwidth)
            tim.cluts.append(clut)
    # Read size
    tim.size = f.readUInt()
    tim.posx = f.readUShort()
    tim.posy = f.readUShort()
    tim.width = f.readUShort()
    tim.height = f.readUShort()
    if tim.bpp == 4:
        tim.width *= 4
    elif tim.bpp == 8:
        tim.width *= 2
    elif tim.bpp == 24:
        tim.width //= 1.5
    tim.dataoff = f.tell()
    common.logDebug("TIM bpp", tim.bpp, "width", tim.width, "height",
                    tim.height, "size", tim.size)
    pixelnum = forcesize if forcesize != 0 else (((tim.size - 12) * 8) //
                                                 tim.bpp)
    readTIMData(f, tim, pixelnum)
    return tim
Example #22
0
def repackBIN(binfile, binpatch, cuefile, patchfile="", data="data/"):
    common.logMessage("Repacking BIN", binpatch, "...")
    if not os.path.isfile("psximager\\psxbuild.exe"):
        common.logError("psximager not found")
        return
    common.execute(
        "psximager\\psxbuild.exe \"{cat}\" \"{bin}\"".format(
            cat=data + "repack.cat", bin=binpatch), False)
    with open(cuefile, "w") as fout:
        fout.write("FILE \"" + binpatch.replace(data, "") + "\" BINARY\r\n")
        fout.write("  TRACK 01 MODE2/2352\r\n")
        fout.write("    INDEX 01 00:00:00\r\n")
    common.logMessage("Done!")
    # Create xdelta patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, binfile, binpatch)
Example #23
0
def asmPatch(file, workfolder, banks=[0x0], banksize=0x4000):
    common.logMessage("Applying ASM patch ...")
    wlagb = common.bundledExecutable("wla-gb.exe")
    if not os.path.isfile(wlagb):
        common.logError("wla-gb not found")
        return
    wlalink = common.bundledExecutable("wlalink.exe")
    if not os.path.isfile(wlalink):
        common.logError("wlalink not found")
        return
    # Create the output file
    ofile = file.replace(".asm", ".o")
    if os.path.isfile(ofile):
        os.remove(ofile)
    common.execute(
        wlagb + " -o {ofile} {binpatch}".format(binpatch=file, ofile=ofile),
        False)
    if not os.path.isfile(ofile):
        return
    # Run the linker and create a temporary patched ROM
    tempfile = file.replace(".asm", ".txt")
    deletetemp = False
    if not os.path.isfile(tempfile):
        deletetemp = True
        with open(tempfile, "w") as f:
            f.write("[objects]\n")
            f.write(ofile + "\n")
    temprom = "temprom.gb"
    common.execute(
        wlalink +
        " -r {tempfile} {temprom}".format(tempfile=tempfile, temprom=temprom),
        False)
    if deletetemp:
        os.remove(tempfile)
    os.remove(ofile)
    # Extract the banks we're interested in from the temp ROM
    with common.Stream(temprom, "rb") as f:
        for i in banks:
            bankname = "bank_"
            if i < 0x10:
                bankname += "0"
            bankname += format(i, 'x')
            f.seek(i * banksize)
            with common.Stream(workfolder + bankname + ".bin", "wb") as fout:
                fout.write(f.read(banksize))
    os.remove(temprom)
    common.logMessage("Done!")
Example #24
0
def repackUMD(isofile, isopatch, workfolder, patchfile=""):
    common.logMessage("Repacking ISO", isopatch, "...")
    common.copyFile(isofile, isopatch)
    umdreplace = common.bundledExecutable("UMD-replace.exe")
    if not os.path.isfile(umdreplace):
        common.logError("UMD-replace not found")
        return
    files = common.getFiles(workfolder)
    for file in common.showProgress(files):
        common.execute(
            umdreplace +
            " \"{imagename}\" \"/{filename}\" \"{newfile}\"".format(
                imagename=isopatch, filename=file, newfile=workfolder + file),
            False)
    common.logMessage("Done!")
    # Create xdelta patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, isofile, isopatch)
Example #25
0
def repackMappedTiles(f, tilestart, mapdata, palettes):
    imgname = mapdata.name
    if not os.path.isfile(mapdata.name):
        imgname = imgname.replace("work_IMG", "out_IMG")
    if not os.path.isfile(imgname):
        common.logError("Image", imgname, "not found")
        return
    img = Image.open(imgname)
    img = img.convert("RGB")
    pixels = img.load()
    x = y = 0
    for tiledata in mapdata.map:
        if not tiledata.hflip and not tiledata.vflip:
            f.seek(tilestart + (tiledata.tile * 16))
            writeTile(f, pixels, x * 8, y * 8, palettes[0], mapdata.bpp)
        x += 1
        if x == mapdata.width:
            y += 1
            x = 0
Example #26
0
def repackBIN(binrange, freeranges=None, readfunc=common.detectEncodedString, writefunc=common.writeEncodedString, encoding="shift_jis", comments="#",
              binin="data/extract/arm9.bin", binout="data/repack/arm9.bin", binfile="data/bin_input.txt", fixchars=[]):
    if not os.path.isfile(binfile):
        common.logError("Input file", binfile, "not found")
        return False

    common.copyFile(binin, binout)
    common.logMessage("Repacking BIN from", binfile, "...")
    section = {}
    with codecs.open(binfile, "r", "utf-8") as bin:
        section = common.getSection(bin, "", comments, fixchars=fixchars)
        chartot, transtot = common.getSectionPercentage(section)
    if type(binrange) == tuple:
        binrange = [binrange]
    notfound = common.repackBinaryStrings(section, binin, binout, binrange, freeranges, readfunc, writefunc, encoding, 0x02000000)
    for pointer in notfound:
        common.logError("Pointer", common.toHex(pointer.old), "->", common.toHex(pointer.new), "not found for string", pointer.str)
    common.logMessage("Done! Translation is at {0:.2f}%".format((100 * transtot) / chartot))
    return True
Example #27
0
def writeTIM(f, tim, infile, transp=False, forcepal=-1):
    if tim.bpp > 8:
        common.logError("writeTIM bpp", tim.bpp, "not supported")
        return
    clut = forcepal if forcepal != -1 else getUniqueCLUT(tim, transp)
    img = Image.open(infile)
    img = img.convert("RGBA")
    pixels = img.load()
    f.seek(tim.dataoff)
    for i in range(tim.height):
        for j in range(tim.width):
            index = common.getPaletteIndex(tim.cluts[clut],
                                           pixels[j, i],
                                           checkalpha=transp,
                                           zerotransp=False)
            if tim.bpp == 4:
                f.writeHalf(index)
            else:
                f.writeByte(index)
Example #28
0
def readETOC(f, cpk, tocoffset):
    f.seek(tocoffset)
    headercheck = f.readString(4)
    if headercheck != "ETOC":
        common.logError("Wrong ETOC header", headercheck)
        return
    utfoffset = f.tell()
    utfpacket, utfsize, encrypted = readUTFData(f)
    tocentry = cpk.getFileEntry("ETOC_HDR")
    tocentry.encrypted = encrypted
    tocentry.filesize = utfsize
    files = readUTF(utfpacket, utfoffset)
    entries = cpk.getEntries("FILE")
    for i in range(len(entries)):
        entries[i].localdir, _, _ = files.getColumnDataType(i, "LocalDir")
        updatetime, _, _ = files.getColumnDataType(i, "UpdateDateTime")
        if updatetime is None:
            updatetime = 0
        entries[i].updatetime = updatetime
Example #29
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    outfolder = "data/out_VSC/"
    common.makeFolder(outfolder)

    common.logMessage("Extracting VSC to", outfolder, "...")
    files = common.getFiles(infolder, ".VSC")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as f:
            # Read header
            f.seek(4)
            unk1 = f.readUShort()
            unk2 = f.readUShort()
            size = f.readUInt()
            unk3 = f.readUInt()
            bpp = 4 if f.readUInt() == 1 else 8
            width = f.readUInt()
            height = f.readUInt()
            unk4 = f.readUInt()
            mapsize = f.readUInt()
            unk5 = f.readUInt()
            tilesize = f.readUInt()
            common.logDebug("size:", size, "width:", width, "height:", height, "mapsize:", mapsize, "tilesize:", tilesize, "bpp:", bpp)
            common.logDebug("unk1:", unk1, "unk2:", unk2, "unk3:", unk3, "unk4:", unk4, "unk5:", unk5)
            # Read data
            common.logDebug("mapoffset:", f.tell())
            mapdata = f.read(mapsize)
            common.logDebug("tileoffset:", f.tell())
            tiledata = f.read(tilesize)
            common.logDebug("paloffset:", f.tell())
            cpal = f.readString(4)
            if cpal != "CPAL":
                common.logError("Palette header", cpal)
                continue
            f.seek(20, 1)
            palnum = f.readUShort()
            f.seek(4, 1)
            paldata = f.read(palnum * 32)
            # Draw the image
            img = game.drawMappedImage(width, height, mapdata, tiledata, paldata, 8, bpp)
            img.save(outfolder + file.replace(".VSC", ".png"), "PNG")
    common.logMessage("Done! Extracted", len(files), "files")
Example #30
0
def readTPL(file):
    tpl = TPL()
    with common.Stream(file, "rb", False) as f:
        f.seek(4)  # Header
        tpl.imgnum = f.readUInt()
        tpl.tableoff = f.readUInt()
        tpl.images = []
        for i in range(tpl.imgnum):
            image = TPLImage()
            tpl.images.append(image)
            f.seek(tpl.tableoff + i * 8)
            image.imgoff = f.readUInt()
            image.paloff = f.readUInt()
            if image.paloff > 0:
                f.seek(image.paloff)
                palcount = f.readUShort()
                f.seek(1, 1)  # Unpacked
                f.seek(1, 1)  # Padding
                image.palformat = f.readUInt()
                image.paldataoff = f.readUInt()
                if image.palformat != 0x02:
                    common.logError("Unimplemented palette format:",
                                    image.palformat)
                    continue
                f.seek(image.paldataoff)
                image.palette = []
                for j in range(palcount):
                    image.palette.append(common.readRGB5A3(f.readShort()))
            f.seek(image.imgoff)
            image.height = f.readUShort()
            image.width = f.readUShort()
            image.format = f.readUInt()
            image.dataoff = f.readUInt()
            if image.format != 0x02 and image.format != 0x08 and image.format != 0x09:
                common.logError("Unimplemented image format:", image.format)
                continue
            image.tilewidth = 8
            image.tileheight = 8 if image.format == 0x08 else 4
            image.blockwidth = math.ceil(
                image.width / image.tilewidth) * image.tilewidth
            image.blockheight = math.ceil(
                image.height / image.tileheight) * image.tileheight
    return tpl