Exemplo n.º 1
0
def getFontData(data):
    fontconfig = data + "fontconfig.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    invtable = {}
    for c in table.keys():
        invtable[table[c][0]] = c
    with codecs.open(data + "table.txt", "r", "utf-8") as tablef:
        ccodes = common.getSection(tablef, "")
    glyphs = readFontGlyphs(fontconfig)
    return table, invtable, ccodes, glyphs
Exemplo n.º 2
0
def run(data, allfile=False):
    infolder = data + "extract/"
    outfile = data + "bin_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    if allfile:
        game.fileranges = {"bank_1d.bin": [(0x0, 0xfff0)]}

    with codecs.open(outfile, "w", "utf-8") as out:
        common.logMessage("Extracting bin to", outfile, "...")
        for file in common.showProgress(game.fileranges):
            out.write("!FILE:" + file + "\n")
            with common.Stream(infolder + file, "rb") as f:
                for range in game.fileranges[file]:
                    f.seek(range[0])
                    while f.tell() < range[1]:
                        if (len(range) >= 3):
                            f.seek(range[2], 1)
                        pos = f.tell()
                        binstr = game.readString(f, table, True)
                        if allfile and len(binstr) > 50:
                            f.seek(pos + 2)
                            continue
                        if binstr.startswith("|"):
                            f.seek(pos + 2)
                            continue
                        if binstr != "":
                            common.logDebug("Found string at", common.toHex(pos), binstr)
                            out.write(binstr + "=\n")
        common.logMessage("Done!")
Exemplo n.º 3
0
def repackFontData(infile, outfile, datafile):
    common.logMessage("Repacking font data from", datafile, "...")
    common.copyFile(infile, outfile)
    glyphs = getFontGlyphs(infile)
    with codecs.open(datafile, "r", "utf-8") as f:
        section = common.getSection(f, "")
    if len(section) == 0:
        return
    with common.Stream(outfile, "rb+", False) as f:
        # Header
        f.seek(36)
        hdwcoffset = f.readUInt()
        # HDWC
        f.seek(hdwcoffset - 4)
        hdwclen = f.readUInt()
        tilenum = (hdwclen - 16) // 3
        f.seek(8, 1)
        for i in range(tilenum):
            found = False
            for glyph in glyphs.values():
                if glyph.index == i:
                    sectionglyph = glyph.char if glyph.char != "=" else "<3D>"
                    if sectionglyph in section:
                        common.logDebug("Writing", section[sectionglyph][0],
                                        "at", f.tell())
                        fontdata = section[sectionglyph][0].split(",")
                        f.writeSByte(int(fontdata[0]))
                        f.writeByte(int(fontdata[1]))
                        f.writeByte(int(fontdata[2]))
                        found = True
                        break
            if not found:
                f.seek(3, 1)
    common.logMessage("Done!")
Exemplo n.º 4
0
def readFontGlyphs(file):
    glyphs = {}
    with codecs.open(file, "r", "utf-8") as f:
        fontconfig = common.getSection(f, "")
        for c in fontconfig:
            charlen = 0 if fontconfig[c][0] == "" else int(fontconfig[c][0])
            glyphs[c] = common.FontGlyph(0, charlen, charlen + 1)
    return glyphs
Exemplo n.º 5
0
def getFixChars():
    fixchars = []
    if not os.path.isfile("data/fontconfig.txt"):
        return fixchars
    with codecs.open("data/fontconfig.txt", "r", "utf-8") as f:
        chars = common.getSection(f, "", "|")
        for char in chars:
            fixchars.append((char, chars[char][0].replace("<3D>", "=")))
    return fixchars
Exemplo n.º 6
0
def translate(text):
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    invtable = {}
    for c in table.keys():
        invtable[table[c][0]] = c
    ret = ""
    for c in text:
        ret += invtable[c][-2:] + invtable[c][:2]
    common.logMessage(ret)
Exemplo n.º 7
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
Exemplo n.º 8
0
def run(data):
    infolder = data + "extract/"
    outfile = data + "credits_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")

    with codecs.open(outfile, "w", "utf-8") as out:
        common.logMessage("Extracting credits to", outfile, "...")
        with common.Stream(infolder + "bank_09.bin", "rb") as f:
            f.seek(0xf120)
            while f.tell() < 0xf9e2:
                b2 = f.readByte()
                b1 = f.readByte()
                utfc, _ = game.convertChar(b1, b2, table)
                if utfc == "<ffff>":
                    out.write("\n")
                else:
                    out.write(utfc)
        common.logMessage("Done!")
Exemplo n.º 9
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
Exemplo n.º 10
0
def run(data):
    infolder = data + "extract/"
    outfolder = data + "out_IMG/"

    common.logMessage("Extracting images to", outfolder, "...")
    common.makeFolder(outfolder)

    files = common.getFiles(infolder)

    extracted = 0
    with codecs.open(common.bundledFile("images.txt"), "r", "utf-8") as imagef:
        for file in files:
            section = common.getSection(imagef, file)
            with common.Stream(infolder + file, "rb") as f:
                for imgname in section.keys():
                    imgdata = section[imgname][0].split(",")
                    mapstart = int(imgdata[1], 16)
                    imgnum = int(imgdata[2]) if len(imgdata) >= 3 else 1
                    readpal = len(imgdata) >= 4 and imgdata[3] == "1"
                    extracted += imgnum
                    if "-" in imgdata[0]:
                        tilestart = int(imgdata[0].split("-")[0], 16)
                        tileend = int(imgdata[0].split("-")[1], 16)
                        for i in common.showProgress(range(tilestart, tileend + 1, 1)):
                            ws.extractMappedImage(f, outfolder + imgname + "_" + hex(i) + ".png", i, mapstart, imgnum, readpal)
                    else:
                        tilestart = int(imgdata[0], 16)
                        ws.extractMappedImage(f, outfolder + imgname + ".png", tilestart, mapstart, imgnum, readpal)
                if file == "bank_09.bin":
                    map = game.getBerserkMap(outfolder)
                    ws.writeMappedImage(f, 0xf080, [map], ws.bwpalette)
                    extracted += 1
    # Extract ramen stand image
    with common.Stream(infolder + "bank_03.bin", "rb") as f:
        map = game.getRamenMap(outfolder)
        ws.writeMappedImage(f, 0x3748, [map], ws.bwpalette)
        map = game.getLanternMap(outfolder)
        ws.writeMappedImage(f, 0x3748, [map], ws.bwpalette)
    common.logMessage("Done! Extracted", extracted, "files")
Exemplo n.º 11
0
def run(data):
    workfolder = data + "work_IMG/"
    infolder = data + "extract/"
    outfolder = data + "repack/"

    common.logMessage("Repacking images from", workfolder, "...")

    files = common.getFiles(infolder)

    repacked = 0
    with codecs.open(common.bundledFile("images.txt"), "r", "utf-8") as imagef:
        for file in files:
            section = common.getSection(imagef, file)
            if len(section) > 0:
                with common.Stream(outfolder + file, "rb+") as f:
                    for imgname in section.keys():
                        imgdata = section[imgname][0].split(",")
                        mapstart = int(imgdata[1], 16)
                        imgnum = int(imgdata[2]) if len(imgdata) >= 3 else 1
                        readpal = len(imgdata) >= 4 and imgdata[3] == "1"
                        writepal = len(imgdata) >= 5 and imgdata[4] == "1"
                        tilestart = int(imgdata[0], 16)
                        ws.repackMappedImage(f, workfolder + imgname + ".png",
                                             tilestart, mapstart, imgnum,
                                             readpal, writepal)
                        repacked += imgnum
                    if file == "bank_09.bin":
                        map = game.getBerserkMap(workfolder)
                        ws.repackMappedTiles(f, 0xf080, map, ws.bwpalette)
                        repacked += 1
    # Repack ramen stand images
    with common.Stream(outfolder + "bank_03.bin", "rb+") as f:
        map = game.getRamenMap(workfolder)
        ws.repackMappedTiles(f, 0x3748, map, ws.bwpalette)
        map = game.getLanternMap(workfolder)
        ws.repackMappedTiles(f, 0x3748, map, ws.bwpalette)
        repacked += 2
    common.logMessage("Done! Repacked", repacked, "files")
Exemplo n.º 12
0
def run(data, processed):
    infolder = data + ("extract/" if not processed else "repack/")
    files = ["bank_11.bin", "bank_12.bin"]
    outfile = data + "analyze_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    invtable = {}
    with codecs.open(data + "table.txt", "r", "utf-8") as tablef:
        convtable = common.getSection(tablef, "")
        for char in convtable:
            invtable[int(convtable[char][0], 16)] = char

    with codecs.open(outfile, "w", "utf-8") as out:
        for file in common.showProgress(files):
            common.logMessage("Processing", file, "...")
            out.write("!FILE:" + file + "\n")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 1:
                    pos = f.tell()
                    opcode = f.readByte()
                    if opcode in game.opcodes and game.opcodes[opcode] != -1:
                        addline = ""
                        if opcode in game.ptropcodes:
                            addline = " Pointer: " + repr(
                                game.ptropcodes[opcode])
                        if opcode == 0x0a:
                            if processed:
                                common.logDebug("Failing at",
                                                common.toHex(pos))
                                writeLine(
                                    out, pos, opcode,
                                    game.readString(f,
                                                    table,
                                                    processed=invtable))
                            else:
                                writeLine(out, pos, opcode,
                                          game.readString(f, table))
                        elif opcode in game.repopcodes:
                            readbytes = ""
                            replen = 0
                            while True:
                                byte = f.readBytes(1)
                                readbytes += byte
                                replen += 1
                                if byte == "FF " and (opcode
                                                      not in game.ptropcodes
                                                      or replen > 2):
                                    break
                            writeLine(out, pos, opcode, readbytes + addline)
                        else:
                            writeLine(
                                out, pos, opcode,
                                f.readBytes(game.opcodes[opcode]) + addline)
                            if opcode == 0xff:
                                out.write("\n")
                                check = f.readUInt()
                                check2 = f.readUInt()
                                f.seek(-8, 1)
                                if check == 0xffffffff and check2 == 0xffffffff:
                                    break
                    else:
                        common.logError("Uknown opcode", common.toHex(opcode),
                                        "at", common.toHex(pos))
                        writeLine(out, pos, opcode, "Unknown")
            out.write("\n\n")
        common.logMessage("Done! Extracted", len(files), "files")
Exemplo n.º 13
0
def run(firstgame, analyzefile):
    infolder = "data/extract/data/script/"
    outfile = "data/wsb_output.txt"
    commonfile = "data/common.txt"
    analyzeout = "data/wsb_analysis.txt"

    commonstr = {}
    # Read common strings from another file
    if os.path.isfile(commonfile):
        with codecs.open(commonfile, "r", "utf-8") as commonf:
            commonstr = common.getSection(commonf, "COMMON")
    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Extracting WSB to", outfile, "...")
    with codecs.open(analyzeout, "w", "utf-8") as a:
        with codecs.open(outfile, "w", "utf-8") as out:
            if len(commonstr) > 0:
                out.write("!FILE:COMMON\n")
                for s in commonstr:
                    out.write(s + "=\n")
            files = common.getFiles(infolder, ".wsb")
            for file in common.showProgress(files):
                analyze = analyzefile != "" and file.endswith(analyzefile)
                if analyzefile != "" and not analyze:
                    continue
                first = True
                common.logDebug("Processing", file, "...")
                with common.Stream(infolder + file, "rb") as f:
                    f.seek(4)  # 0x10
                    codeoffset = f.readUInt()
                    f.seek(8, 1)  # all 0xFF
                    unk = f.readUInt()
                    textoffset = f.readUInt()
                    codeoffset2 = f.readUInt()
                    common.logDebug("codeoffset:", codeoffset, "unk:", unk,
                                    "textoffset:", textoffset, "codeoffset2:",
                                    codeoffset2)
                    f.seek(4, 1)
                    # Parse the various code blocks while looking for strings
                    while f.tell() < codeoffset:
                        pos = f.tell()
                        b1 = f.readByte()
                        b2 = f.readByte()
                        if (b1 == 0x55 and b2 == 0x08) or (b1 == 0x95
                                                           and b2 == 0x10):
                            # Found a string pointer
                            if analyze:
                                lenline = f.readBytes(4 if b1 == 0x95 else 2)
                                f.seek(-(4 if b1 == 0x95 else 2), 1)
                            sjis, strlen = game.readShiftJIS(
                                f, b1 == 0x95, False, encoding)
                            if sjis != "" and sjis != ">>" and sjis != " ":
                                sjissplit = sjis.split(">>")
                                for sjisline in sjissplit:
                                    if sjisline != "" and sjisline != " " and sjisline not in commonstr:
                                        if first:
                                            out.write("!FILE:" + file + "\n")
                                            first = False
                                        out.write(sjisline + "=\n")
                            if analyze:
                                # Try to calculate the length to check if the calculation is correct
                                addlen = ""
                                with common.Stream() as test:
                                    game.writeShiftJIS(test, sjis, b1 == 0x95,
                                                       False, 0, encoding,
                                                       firstgame)
                                    testlen = test.tell()
                                    test.seek(0)
                                    addlen = test.readBytes(4 if b1 ==
                                                            0x95 else 2)
                                    if lenline != addlen:
                                        test.seek(0)
                                        addlen += "\nDIFF\n" + test.readBytes(
                                            testlen) + "\n"
                                        fpos = f.tell()
                                        f.seek(pos + 2)
                                        addlen += f.readBytes(fpos - f.tell())
                                writeLine(a, pos, b1, b2,
                                          lenline + sjis + " " + addlen)
                        elif (b1, b2) in game.wsbcodes:
                            if analyze:
                                ptrstr = ""
                                if (b1, b2) in game.wsbpointers:
                                    ptrstr += "ptr"
                                writeLine(
                                    a, pos, b1, b2,
                                    f.readBytes(game.wsbcodes[(b1, b2)]) +
                                    ptrstr)
                            else:
                                f.seek(game.wsbcodes[(b1, b2)], 1)
                        else:
                            if analyze:
                                writeLine(a, pos, b1, b2, "Unknown!")
                    if codeoffset > 0:
                        codenum = f.readUInt()
                        for i in range(codenum):
                            f.seek(codeoffset + 4 + 4 * i)
                            codepointer = f.readUInt()
                            f.seek(codeoffset + codepointer)
                            sjis, codelen = game.readShiftJIS(
                                f, False, True, encoding)
                            # Ignore ASCII strings and a particular debug line found in every file
                            if not common.isAscii(sjis) and sjis.find(
                                    "%d, %d") < 0 and sjis not in commonstr:
                                if first:
                                    out.write("!FILE:" + file + "\n")
                                    first = False
                                out.write(sjis + "=\n")
                            if analyze:
                                writeLine(a, i, 0, 0,
                                          str(codepointer) + " " + sjis)
    common.logMessage("Done! Extracted", len(files), "files")
Exemplo n.º 14
0
def run(firstgame):
    infolder = "data/extract/data/script/"
    outfolder = "data/repack/data/script/"
    infile = "data/wsb_input.txt"
    fontfile = "data/replace/data/font/lcfont12.NFTR"
    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Repacking WSB from", infile, "...")
    # Read the glyph size from the font
    if not os.path.isfile(fontfile):
        fontfile = fontfile.replace("replace/", "extract/")
    glyphs = nitro.readNFTR(fontfile).glyphs
    wordwrap = game.wordwrap[0] if firstgame else game.wordwrap[1]
    fixchars = game.getFixChars()
    with codecs.open(infile, "r", "utf-8") as wsb:
        commonsection = common.getSection(wsb, "COMMON", fixchars=fixchars)
        chartot, transtot = common.getSectionPercentage(commonsection)
        files = common.getFiles(infolder, ".wsb")
        for file in common.showProgress(files):
            section = common.getSection(wsb, file, fixchars=fixchars)
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            pointerdiff = {}
            pointers = {}
            common.logDebug(" Processing", file, "...")
            insize = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    # Copy header
                    fin.seek(4)  # 0x10
                    codeoffset = fin.readUInt()
                    if codeoffset == 0 and not firstgame:
                        fin.seek(0)
                        f.write(fin.read())
                        continue
                    fin.seek(8, 1)  # all 0xFF
                    unk = fin.readUInt()
                    textoffset = fin.readUInt()
                    codeoffset2 = fin.readUInt()
                    fin.seek(0)
                    f.write(fin.read(32))
                    # Write new strings
                    while fin.tell() < codeoffset:
                        pos = fin.tell()
                        fpos = f.tell()
                        b1 = fin.readByte()
                        b2 = fin.readByte()
                        f.writeByte(b1)
                        f.writeByte(b2)
                        if (b1 == 0x55 and b2 == 0x08) or (b1 == 0x95
                                                           and b2 == 0x10):
                            sjis, oldlen = game.readShiftJIS(
                                fin, b1 == 0x95, False, encoding)
                            # Fix a bugged line with wrong speaker code
                            if file == "event/ev_mou/mou_10.wsb" and sjis == "そうじゃな。|わっちの直感が申すには……>>":
                                f.seek(fpos - 12)
                                f.writeByte(0x53)
                                f.seek(fpos + 2)
                            strreplaced = False
                            if sjis != "" and sjis != ">>":
                                sjissplit = sjis.split(">>")
                                for i in range(len(sjissplit)):
                                    newsjis = sjisline = sjissplit[i]
                                    if sjisline in commonsection:
                                        newsjis = commonsection[sjisline][0]
                                    elif sjisline in section:
                                        newsjis = section[sjisline].pop(0)
                                        if len(section[sjisline]) == 0:
                                            del section[sjisline]
                                    if newsjis != "":
                                        # Disable wordwrap for strings that contain replace codes
                                        if newsjis.count("@<") > 0:
                                            sjissplit[i] = newsjis
                                        # Check for automatic centering
                                        elif newsjis.count("<<") > 0:
                                            sjissplit[i] = common.centerLines(
                                                newsjis,
                                                glyphs,
                                                wordwrap,
                                                centercode="<<")
                                        else:
                                            sjissplit[i] = common.wordwrap(
                                                newsjis, glyphs, wordwrap)
                                            if sjissplit[i].count("|") > 2:
                                                common.logError(
                                                    "Sub-line too long:",
                                                    sjissplit[i])
                                                cutsplit = sjissplit[i].split(
                                                    "|")
                                                sjissplit[i] = cutsplit[
                                                    0] + "|" + cutsplit[
                                                        1] + "|" + cutsplit[2]
                                newsjis = ">>".join(sjissplit)
                                if newsjis != sjis and newsjis != "" and newsjis != ">>":
                                    common.logDebug("Repacking", newsjis, "at",
                                                    common.toHex(pos))
                                    strreplaced = True
                                    if newsjis == "!":
                                        newsjis = ""
                                    newlen = game.writeShiftJIS(
                                        f, newsjis, b1 == 0x95, False, 0,
                                        encoding, firstgame)
                                    lendiff = newlen - oldlen
                                    if newlen > (0x80 if firstgame else
                                                 0x70) and b1 == 0x55:
                                        common.logDebug(
                                            "String is too long", newlen,
                                            "changing to 0x95")
                                        f.seek(fpos)
                                        f.writeByte(0x95)
                                        f.writeByte(0x10)
                                        game.writeShiftJIS(
                                            f, newsjis, True, False, 0,
                                            encoding, firstgame)
                                        lendiff += 2
                                    if lendiff != 0:
                                        common.logDebug(
                                            "Adding", lendiff, "at", pos)
                                        pointerdiff[pos - 16] = lendiff
                            if not strreplaced:
                                fin.seek(pos + 2)
                                f.write(
                                    fin.read(oldlen +
                                             (4 if b1 == 0x95 else 2)))
                        elif (b1, b2) in game.wsbcodes:
                            if (b1, b2) in game.wsbpointers:
                                if b1 == 0x81 and b2 == 0xB9:
                                    f.write(fin.read(2))
                                pointer = fin.readUInt()
                                pointers[f.tell()] = pointer
                                f.writeUInt(pointer)
                            else:
                                f.write(fin.read(game.wsbcodes[(b1, b2)]))
                    # Write code section
                    if codeoffset > 0:
                        newcodeoffset = f.tell()
                        codediff = 0
                        codenum = fin.readUInt()
                        f.writeUInt(codenum)
                        for i in range(codenum):
                            fin.seek(codeoffset + 4 + 4 * i)
                            f.seek(newcodeoffset + 4 + 4 * i)
                            codepointer = fin.readUInt()
                            f.writeUInt(codepointer + codediff)
                            fin.seek(codeoffset + codepointer)
                            f.seek(newcodeoffset + codepointer + codediff)
                            sjis, codelen = game.readShiftJIS(
                                fin, False, True, encoding)
                            strreplaced = False
                            if sjis in section or sjis in commonsection:
                                if sjis in commonsection:
                                    newsjis = commonsection[sjis][0]
                                else:
                                    newsjis = section[sjis].pop(0)
                                    if len(section[sjis]) == 0:
                                        del section[sjis]
                                if newsjis != "":
                                    strreplaced = True
                                    newcodelen = game.writeShiftJIS(
                                        f, newsjis, False, True, 0, encoding,
                                        firstgame)
                                    if codelen != newcodelen:
                                        codediff += newcodelen - codelen
                            if not strreplaced:
                                fin.seek(codeoffset + codepointer)
                                f.write(fin.read(codelen))
                    f.writeZero(insize - fin.tell())
                    # Write new header offsets
                    f.seek(4)
                    f.writeUInt(common.shiftPointer(codeoffset, pointerdiff))
                    f.seek(8, 1)
                    f.writeUInt(common.shiftPointer(unk, pointerdiff))
                    f.writeUInt(common.shiftPointer(textoffset, pointerdiff))
                    f.writeUInt(common.shiftPointer(codeoffset2, pointerdiff))
                    # Shift pointers
                    for k, v in pointers.items():
                        f.seek(k)
                        f.writeUInt(common.shiftPointer(v, pointerdiff))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 15
0
def repackPGFData(fontin, fontout, configfile, bitmapin=""):
    pgf = readPGFData(fontin)
    section = {}
    if os.path.isfile(configfile):
        with codecs.open(configfile, "r", "utf-8") as f:
            section = common.getSection(f, "", "##")
    with common.Stream(fontin, "rb") as fin:
        # Set the new glyphs information
        for char in section:
            jsondata = json.loads(section[char][0])
            char = char.replace("<3D>", "=")
            for glyphindex in pgf.reversetable[char]:
                glyph = pgf.glyphs[glyphindex]
                newsize = 8
                glyph.width = int(jsondata["width"])
                glyph.height = int(jsondata["height"])
                glyph.left = int(jsondata["left"])
                glyph.top = int(jsondata["top"])
                glyph.dimension["x"] = float(jsondata["dimension"]["x"])
                glyph.dimension["y"] = float(jsondata["dimension"]["y"])
                glyph.dimensionid = checkPGFDataMap(pgf.dimensionmap,
                                                    glyph.dimension)
                newsize += 1 if glyph.dimensionid >= 0 else 8
                glyph.bearingx["x"] = float(jsondata["bearingx"]["x"])
                glyph.bearingx["y"] = float(jsondata["bearingx"]["y"])
                glyph.bearingxid = checkPGFDataMap(pgf.bearingxmap,
                                                   glyph.bearingx)
                newsize += 1 if glyph.bearingxid >= 0 else 8
                glyph.bearingy["x"] = float(jsondata["bearingy"]["x"])
                glyph.bearingy["y"] = float(jsondata["bearingy"]["y"])
                glyph.bearingyid = checkPGFDataMap(pgf.bearingymap,
                                                   glyph.bearingy)
                newsize += 1 if glyph.bearingyid >= 0 else 8
                glyph.advance["x"] = float(jsondata["advance"]["x"])
                glyph.advance["y"] = float(jsondata["advance"]["y"])
                glyph.advanceid = checkPGFDataMap(pgf.advancemap,
                                                  glyph.advance)
                newsize += 1 if glyph.advanceid >= 0 else 8
                bitmapfile = bitmapin + str(glyph.index).zfill(4) + ".png"
                if not os.path.isfile(bitmapfile):
                    fin.seek(pgf.glyphpos + pgf.charptr[glyph.index] +
                             glyph.totlen // 8)
                    glyph.bitmap = fin.read(glyph.size - glyph.totlen // 8)
                    rleflag = glyph.flag & 0b11
                else:
                    glyph.bitmap, rleflag, glyph.width, glyph.height = repackPGFBitmap(
                        glyph, bitmapfile)
                glyph.oldsize = glyph.size
                glyph.size = newsize + len(glyph.bitmap)
                if not glyph.shadow:
                    glyph.shadowid = 0
                    glyph.shadowflag = 21
                else:
                    # TODO: shadow support
                    pass
                glyph.flag = rleflag
                if glyph.dimensionid >= 0:
                    glyph.flag |= 0b000100
                if glyph.bearingxid >= 0:
                    glyph.flag |= 0b001000
                if glyph.bearingyid >= 0:
                    glyph.flag |= 0b010000
                if glyph.advanceid >= 0:
                    glyph.flag |= 0b100000
        pgf.dimensionlen = len(pgf.dimensionmap)
        pgf.bearingxlen = len(pgf.bearingxmap)
        pgf.bearingylen = len(pgf.bearingymap)
        pgf.advancelen = len(pgf.advancemap)
        # Write the file
        with common.Stream(fontout, "wb") as f:
            # Copy the header
            fin.seek(0)
            f.write(fin.read(pgf.headerlen))
            # Write the new lengths
            f.seek(0x102)
            f.writeByte(pgf.dimensionlen)
            f.writeByte(pgf.bearingxlen)
            f.writeByte(pgf.bearingylen)
            f.writeByte(pgf.advancelen)
            # Write the maps
            f.seek(pgf.headerlen)
            for i in range(pgf.dimensionlen):
                f.writeInt(int(pgf.dimensionmap[i]["x"] * 64))
                f.writeInt(int(pgf.dimensionmap[i]["y"] * 64))
            for i in range(pgf.bearingxlen):
                f.writeInt(int(pgf.bearingxmap[i]["x"] * 64))
                f.writeInt(int(pgf.bearingxmap[i]["y"] * 64))
            for i in range(pgf.bearingylen):
                f.writeInt(int(pgf.bearingymap[i]["x"] * 64))
                f.writeInt(int(pgf.bearingymap[i]["y"] * 64))
            for i in range(pgf.advancelen):
                f.writeInt(int(pgf.advancemap[i]["x"] * 64))
                f.writeInt(int(pgf.advancemap[i]["y"] * 64))
            # Copy other tables
            fin.seek(pgf.mapend)
            if pgf.shadowmaplen > 0:
                f.write(
                    fin.read(
                        ((pgf.shadowmaplen * pgf.shadowmapbpe + 31) // 32) *
                        4))
            f.write(
                fin.read(((pgf.charmaplen * pgf.charmapbpe + 31) // 32) * 4))
            charptrpos = f.tell()
            f.write(
                fin.read(((pgf.charptrlen * pgf.charptrbpe + 31) // 32) * 4))
            # Write the characters and store the pointers
            charptrs = []
            glyphpos = f.tell()
            for i in range(len(pgf.glyphs)):
                glyph = pgf.glyphs[i]
                glyphptr = f.tell() - glyphpos
                charptrs.append(glyphptr // pgf.charptrscale)
                data = bytearray(8)
                pos = 0
                pos = setBPEValue(14, data, pos, glyph.size)
                pos = setBPEValue(7, data, pos, glyph.width)
                pos = setBPEValue(7, data, pos, glyph.height)
                pos = setBPEValue(7, data, pos, glyph.left)
                pos = setBPEValue(7, data, pos, glyph.top)
                pos = setBPEValue(6, data, pos, glyph.flag)
                pos = setBPEValue(7, data, pos, glyph.shadowflag)
                pos = setBPEValue(9, data, pos, glyph.shadowid)
                f.write(data)
                if glyph.dimensionid >= 0:
                    f.writeByte(glyph.dimensionid)
                else:
                    f.writeInt(int(glyph.dimension["x"] * 64))
                    f.writeInt(int(glyph.dimension["y"] * 64))
                if glyph.bearingxid >= 0:
                    f.writeByte(glyph.bearingxid)
                else:
                    f.writeInt(int(glyph.bearingx["x"] * 64))
                    f.writeInt(int(glyph.bearingx["y"] * 64))
                if glyph.bearingyid >= 0:
                    f.writeByte(glyph.bearingyid)
                else:
                    f.writeInt(int(glyph.bearingy["x"] * 64))
                    f.writeInt(int(glyph.bearingy["y"] * 64))
                if glyph.advanceid >= 0:
                    f.writeByte(glyph.advanceid)
                else:
                    f.writeInt(int(glyph.advance["x"] * 64))
                    f.writeInt(int(glyph.advance["y"] * 64))
                if glyph.width > 0 and glyph.height > 0:
                    if glyph.bitmap is None:
                        fin.seek(pgf.glyphpos + pgf.charptr[glyph.index] +
                                 glyph.totlen // 8)
                        glyph.bitmap = fin.read((glyph.oldsize if glyph.
                                                 oldsize > 0 else glyph.size) -
                                                glyph.totlen // 8)
                    f.write(glyph.bitmap)
                if (f.tell() - glyphpos) % pgf.charptrscale > 0:
                    f.writeZero(pgf.charptrscale -
                                ((f.tell() - pgf.glyphpos) % pgf.charptrscale))
            # Write the new char ptr table
            f.seek(charptrpos)
            setBPETable(f, pgf.charptrlen, pgf.charptrbpe, charptrs)
Exemplo n.º 16
0
def run(firstgame, no_redirect):
    infolder = "data/extract/data/data/"
    outfolder = "data/repack/data/data/"
    infile = "data/dat_input.txt"
    redfile = "data/redirects.asm"
    fontfile = "data/replace/data/font/lcfont12.NFTR"
    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return
    common.makeFolder(outfolder)
    chartot = transtot = 0
    monthsection, skipsection = game.monthsection, game.skipsection
    game.monthsection = game.skipsection = None

    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Repacking DAT from", infile, "...")
    # Read the glyph size from the font
    if not os.path.isfile(fontfile):
        fontfile = fontfile.replace("replace/", "extract/")
    glyphs = nitro.readNFTR(fontfile).glyphs
    fixchars = game.getFixChars()
    # Copy this txt file
    if not firstgame and os.path.isfile(infolder + "facilityhelp.txt"):
        common.copyFile(infolder + "facilityhelp.txt",
                        outfolder + "facilityhelp.txt")
    redirects = []
    with codecs.open(infile, "r", "utf-8") as dat:
        files = common.getFiles(infolder, ".dat")
        for file in common.showProgress(files):
            section = common.getSection(dat, file, fixchars=fixchars)
            # If there are no lines, just copy the file
            if len(section) == 0:
                common.copyFile(infolder + file, outfolder + file)
                # Part of the AP patch
                if not firstgame and file == "route.dat":
                    with common.Stream(outfolder + file, "rb+") as f:
                        f.seek(0x5ee8)
                        f.writeByte(0x0)
                continue
            i = 0
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            common.logDebug("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    f.write(fin.read())
                    fin.seek(0)
                    # Loop the file and replace strings as needed
                    while fin.tell() < size - 2:
                        pos = fin.tell()
                        check = game.detectShiftJIS(fin, encoding)
                        if check != "":
                            if file == "entrance_icon.dat":
                                # For entrance_icon, just write the string and update the pointer
                                if check in section:
                                    # For the first one, seek to the correct position in the output file
                                    if i == 0:
                                        f.seek(pos)
                                    # Write the string
                                    newsjis = check
                                    if check in section and section[check][
                                            0] != "":
                                        common.logDebug(
                                            "Replacing string at", pos)
                                        newsjis = section[check][0]
                                    startpos = f.tell()
                                    game.writeShiftJIS(f, newsjis, False, True,
                                                       0, encoding)
                                    endpos = f.tell()
                                    # Update the pointer
                                    f.seek(0x1c98 + 4 * i)
                                    f.writeUInt(startpos - 0x1c98)
                                    f.seek(endpos)
                                    i += 1
                            else:
                                # Found a SJIS string, check if we have to replace it
                                if check in section and section[check][0] != "":
                                    common.logDebug("Replacing string at", pos)
                                    f.seek(pos)
                                    newsjis = section[check][0]
                                    maxlen = 0
                                    if file == "goods.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 170)
                                        maxlen = 60
                                    elif file == "gossip.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 190)
                                        if newsjis.count("<<") > 0:
                                            newsjis = common.centerLines(
                                                newsjis,
                                                glyphs,
                                                190,
                                                centercode="<<")
                                        if fin.tell() - pos < 35:
                                            maxlen = 35
                                        else:
                                            maxlen = 160
                                    elif file == "scenarioguide.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 165)
                                        maxlen = 60
                                        if newsjis.count("|") > 1:
                                            common.logError(
                                                "scenarioguide line", newsjis,
                                                "too long")
                                    newlen = game.writeShiftJIS(
                                        f, newsjis, False, True, maxlen,
                                        encoding)
                                    if newlen < 0:
                                        if file != "gossip.dat" or no_redirect or maxlen != 160:
                                            common.logError(
                                                "String {} is too long ({}/{})."
                                                .format(
                                                    newsjis, len(newsjis),
                                                    maxlen))
                                        else:
                                            common.logWarning(
                                                "String {} is too long ({}/{})."
                                                .format(
                                                    newsjis, len(newsjis),
                                                    maxlen))
                                            # Doesn't fit, write it shorter
                                            f.seek(pos)
                                            cutat = 155 if firstgame else 150
                                            while ord(newsjis[cutat]) > 127:
                                                cutat -= 1
                                            stringfit = newsjis[:cutat]
                                            stringrest = newsjis[cutat:]
                                            game.writeShiftJIS(
                                                f, stringfit, False, True,
                                                maxlen, encoding)
                                            f.seek(-1, 1)
                                            f.writeByte(0x1f)
                                            f.writeByte(len(redirects))
                                            redirects.append(stringrest)
                                    # Pad with 0s if the line is shorter
                                    while f.tell() < fin.tell():
                                        f.writeByte(0x00)
                            pos = fin.tell() - 1
                        fin.seek(pos + 1)
    with codecs.open(redfile, "w", "utf-8") as f:
        f.write(".ascii \"NDSC\"\n\n")
        f.write("REDIRECT_START:\n\n")
        for i in range(len(redirects)):
            f.write(".dh REDIRECT_{} - REDIRECT_START\n".format(i))
        for i in range(len(redirects)):
            f.write("\nREDIRECT_{}:\n".format(i))
            redirect = redirects[i].replace("\"", "\\\"")
            redirect = redirect.replace("|", "\" :: .db 0xa :: .ascii \"")
            redirectascii = ""
            for c in redirect:
                if ord(c) > 127:
                    sjisc = common.toHex(
                        int.from_bytes(c.encode(encoding), "big"))
                    redirectascii += "\" :: .db 0x" + sjisc[:2] + " :: .db 0x" + sjisc[
                        2:] + " :: .ascii \""
                else:
                    redirectascii += c
            f.write(".ascii \"{}\" :: .db 0\n".format(redirectascii))
    game.monthsection, game.skipsection = monthsection, skipsection
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 17
0
def run():
    infolder = "data/extract_NFP/SPC.NFP/"
    outfolder = "data/work_NFP/SPC.NFP/"
    infile = "data/spc_input.txt"
    infixfile = "data/sprite_fix.txt"
    tablefile = "data/table.txt"
    chartot = transtot = 0

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found.")
        return
    common.makeFolder(outfolder)

    common.logMessage("Repacking SPC from", infile, "...")
    common.loadTable(tablefile)
    spritefixf = codecs.open(infixfile, "r", "utf-8")
    with codecs.open(infile, "r", "utf-8") as spc:
        files = common.getFiles(infolder, [".SPC", ".SET"])
        for file in common.showProgress(files):
            section = common.getSection(spc, file, "#", game.fixchars)
            spritefix = common.getSection(spritefixf, file, "#")
            if len(section) == 0 and len(spritefix) == 0:
                common.copyFile(infolder + file, outfolder + file)
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            common.logDebug("Repacking", file, "...")
            codepointers = []
            pointerdiff = {}
            funcpointers = {"MswMess": [], "MswHit": []}
            nextstr = None
            addstr = ""
            last29 = []
            oldstrpos = 0
            f = open(outfolder + file, "wb")
            f.close()
            with common.Stream(outfolder + file, "r+b") as f:
                with common.Stream(infolder + file, "rb") as fin:
                    # Write the header
                    f.writeString("SCRP")
                    fin.seek(4)
                    f.writeUInt(fin.readUInt())
                    f.writeString("CODE")
                    fin.seek(4, 1)
                    codesize = fin.readUInt()
                    f.writeUInt(codesize)
                    f.write(fin.read(6))
                    # Loop the file and shift pointers
                    while fin.tell() < 16 + codesize - 2:
                        pos = fin.tell()
                        byte = fin.readByte()
                        f.writeByte(byte)
                        if byte == 0x10:
                            oldlen = fin.readUShort()
                            fin.seek(-2, 1)
                            strpos = fin.tell()
                            strposf = f.tell()
                            sjis = game.readShiftJIS(fin)
                            if (sjis != "" and sjis
                                    in section) or nextstr is not None:
                                common.logDebug("Found SJIS string at",
                                                strpos + 16)
                                # Check if we have a nextstr to inject instead of using the section
                                if nextstr is None:
                                    newsjis = section[sjis].pop(0)
                                    if len(section[sjis]) == 0:
                                        del section[sjis]
                                    if newsjis == "!":
                                        newsjis = ""
                                        # Center the line
                                        savestrpos = f.tell()
                                        f.seek(oldstrpos - 28)
                                        checkbyte = f.readByte()
                                        if checkbyte == 0x02:
                                            f.seek(-1, 1)
                                            f.writeByte(1)
                                        f.seek(savestrpos)
                                    elif newsjis == "":
                                        newsjis = sjis
                                else:
                                    newsjis = nextstr
                                    nextstr = None
                                # If the string starts with <<, pad it with spaces
                                if newsjis.startswith("<<"):
                                    newsjis = newsjis[2:]
                                    pad = " " * ((20 - len(newsjis)) // 2)
                                    newsjis = pad + newsjis + pad
                                # If the string starts with "[xx]", add mouth flapping
                                if newsjis.startswith(
                                        "[") and newsjis[3] == "]":
                                    flapbyte = newsjis[1:3]
                                    newsjis = newsjis[4:]
                                    flappos = f.tell()
                                    f.seek(strposf - 5)
                                    f.writeByte(int(flapbyte, 16))
                                    f.seek(flappos)
                                # If the string contains a >>, split it and save it for later
                                if newsjis.find(">>") > 0:
                                    splitstr = newsjis.split(">>", 1)
                                    newsjis = splitstr[0]
                                    addstr = splitstr[1]
                                # Check if we have a string after
                                savepos = fin.tell()
                                fin.seek(9, 1)
                                b1 = fin.readByte()
                                b2 = fin.readByte()
                                fin.seek(savepos)
                                if b1 == 0x10 and b2 == 0x01:
                                    nextstr = ""
                                # If the string contains a |, try to turn the string into a 2-lines message
                                if newsjis.find("|") > 0:
                                    splitstr = newsjis.split("|", 1)
                                    newsjis = splitstr[0]
                                    nextstr = splitstr[1]
                                    newsjis = newsjis.replace("|", "<0A>")
                                    # Change the byte 0x1C bytes before the string to 2 if it's 1
                                    checkpos = 28
                                    if newsjis.startswith("FIX("):
                                        splitstr = newsjis.split(")", 1)
                                        newsjis = splitstr[1]
                                        checkpos = int(splitstr[0].replace(
                                            "FIX(", ""))
                                    f.seek(-checkpos, 1)
                                    checkbyte = f.readByte()
                                    if checkbyte == 0x01:
                                        f.seek(-1, 1)
                                        f.writeByte(2)
                                    f.seek(checkpos - 1, 1)
                                # Write the SJIS string
                                newlen = game.writeShiftJIS(f, newsjis)
                                lendiff = newlen - oldlen
                                if lendiff != 0:
                                    common.logDebug("Adding", lendiff, "at",
                                                    strpos)
                                    pointerdiff[strpos - 16] = lendiff
                                fin.seek(1, 1)
                            else:
                                common.logDebug(
                                    "Found ASCII or unaltered string at",
                                    strpos + 16)
                                fixPos = pos - 16
                                # Patch RITT_02 to add Dayakka's missing text
                                if file == "RITT_02.SPC" and fixPos == 1775:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("APP_DAYA")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 8
                                elif file == "RITT_02.SPC" and fixPos == 1810:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("DAYA_004")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 8
                                elif file == "RITT_02.SPC" and fixPos == 1845:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x05)
                                    f.writeString("AWAY")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 4
                                elif file == "SYS_054.SPC" and fixPos == 4233:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("MSW_C083")
                                    f.writeByte(0x00)
                                else:
                                    fin.seek(strpos + 2)
                                    asciistr = fin.readNullString()
                                    if asciistr in spritefix:
                                        fin.seek(strpos + oldlen + 2)
                                        f.writeUShort(0x08)
                                        f.writeString(spritefix[asciistr][0])
                                        f.writeByte(0x00)
                                    else:
                                        fin.seek(strpos)
                                        f.write(fin.read(oldlen + 2))
                            f.write(fin.read(2))
                            pointer = fin.readUInt()
                            f.writeUInt(
                                common.shiftPointer(pointer, pointerdiff))
                            # Check if we have an addstr
                            if addstr != "" and nextstr is None:
                                addstrsplit = addstr.split(">>")
                                for addstr in addstrsplit:
                                    strsplit = addstr.split("|")
                                    startpointer = f.tell()
                                    startpointeri = fin.tell()
                                    f.writeByte(0x28)
                                    f.writeByte(0x00)
                                    funcpointers["MswMess"].append(f.tell() -
                                                                   16)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x03)
                                    f.writeByte(0x80)
                                    f.writeUInt(0x00)
                                    f.writeByte(0x2A)
                                    f.writeByte(0x00)
                                    f.writeByte(0x31)
                                    f.writeByte(0x0F)
                                    f.writeUInt(0x0C)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x00)
                                    funcpointers["MswHit"].append(f.tell() -
                                                                  16)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x01)
                                    f.writeByte(0x80)
                                    f.writeUInt(0x00)
                                    f.writeByte(0x2A)
                                    f.writeByte(0x00)
                                    f.writeByte(0x31)
                                    f.writeByte(0x0F)
                                    f.writeUInt(0x04)
                                    f.writeByte(0x29)
                                    f.writeUInt(last29[len(last29) - 1])
                                    f.writeByte(0x10)
                                    strpointer = f.tell()
                                    game.writeShiftJIS(f, strsplit[0])
                                    f.writeByte(0x22)
                                    f.writeByte(0x00)
                                    f.writeUInt(strpointer - 16 - 4)
                                    f.writeByte(0x28)
                                    f.writeByte(0x00)
                                    f.writeByte(0x10)
                                    strpointer2 = f.tell()
                                    game.writeShiftJIS(
                                        f, strsplit[1]
                                        if len(strsplit) == 2 else "")
                                    f.writeByte(0x22)
                                    f.writeByte(0x00)
                                    f.writeUInt(strpointer2 - 16 - 4)
                                    endpointer = f.tell()
                                    common.logDebug("Adding new str",
                                                    endpointer - startpointer,
                                                    "at", startpointeri)
                                    if startpointeri - 16 not in pointerdiff:
                                        pointerdiff[startpointeri - 16] = 0
                                    pointerdiff[
                                        startpointeri -
                                        16] += endpointer - startpointer
                                addstr = ""
                            oldstrpos = strposf
                        elif byte == 0x15:
                            f.write(fin.read(1))
                            bytelen = fin.readByte()
                            f.writeByte(bytelen)
                            for i in range(bytelen):
                                f.write(fin.read(4))
                                codepointers.append(f.tell())
                                f.write(fin.read(4))
                        elif byte in game.spccodes:
                            if byte == 0x11:
                                codepointers.append(f.tell())
                            elif byte == 0x12:
                                codepointers.append(f.tell() + 1)
                            elif byte == 0x29:
                                last29.append(fin.readUInt())
                                fin.seek(-4, 1)
                            # Patch SYS_046/7 and fix the disappearing cut-in sprites
                            fixPos = pos - 16
                            if (file == "SYS_046.SPC" and byte == 0x29
                                    and fixPos
                                    in [9660, 11356, 11915, 13108, 13646]) or (
                                        file == "SYS_047.SPC" and byte == 0x29
                                        and fixPos == 1607):
                                f.writeUInt(0x0A)
                                fin.seek(4, 1)
                            else:
                                f.write(fin.read(game.spccodes[byte]))
                        common.logDebug("Unknown byte", common.toHex(byte),
                                        "at", pos)
                    f.writeByte(0x8F)
                    f.writeByte(0x00)
                    f.writeByte(0x00)
                    endpos = f.tell()
                    # Shift the other code pointers
                    for codepointer in codepointers:
                        f.seek(codepointer)
                        pointer = f.readUInt()
                        f.seek(-4, 1)
                        f.writeUInt(common.shiftPointer(pointer, pointerdiff))
                    # Write the code section size in the header
                    f.seek(12)
                    f.writeUInt(endpos - 16)
                    f.seek(endpos)
                    # Function section
                    fin.seek(codesize + 16)
                    f.writeString("FUNC")
                    fin.seek(4, 1)
                    funcsize = fin.readUInt()
                    f.writeUInt(funcsize)
                    # Copy the function section while shifting pointers
                    common.logDebug(str(funcpointers))
                    while True:
                        # Read the function name
                        function = fin.readNullString()
                        if function == "":
                            break
                        f.writeString(function)
                        f.writeZero(1)
                        common.logDebug("Found function:", function)
                        # Read the pointers until we find 0
                        while True:
                            pointer = fin.readUInt()
                            if pointer == 0:
                                f.writeUInt(0)
                                break
                            else:
                                pointer = common.shiftPointer(
                                    pointer, pointerdiff)
                                if function in funcpointers and len(
                                        funcpointers[function]) > 0:
                                    for newpointer in funcpointers[function]:
                                        common.logDebug(
                                            function, "new:", newpointer,
                                            "poi:", pointer)
                                        if pointer > newpointer:
                                            f.writeUInt(newpointer)
                                            funcpointers[function].remove(
                                                newpointer)
                                f.writeUInt(pointer)
                    f.writeZero(1)
                    # Write the file size in the header
                    pos = f.tell()
                    f.seek(4)
                    f.writeUInt(pos - 4)
                    f.seek(pos)
                    # Write TERM and pad with 0s
                    f.writeString("TERM")
                    f.writeZero(16 - (f.tell() % 16))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 18
0
def run(data):
    fontfile = data + "font.png"
    fontconfigfile = data + "fontconfig.txt"
    infont = data + "font_output.png"
    outfont = data + "font_input.png"
    outtable = data + "table.txt"
    bankfile = data + "repack/bank_10.bin"

    common.logMessage("Repacking font ...")
    # List of characters and positions in the font.png file
    chars = {}
    positions = {}
    bigrams = []
    with codecs.open(fontconfigfile, "r", "utf-8") as f:
        fontconfig = common.getSection(f, "")
        x = 0
        for c in fontconfig:
            if fontconfig[c][0] == "":
                if c in bigrams:
                    common.logError("Duplicate bigram", c)
                    continue
                bigrams.append(c)
                chars[c] = chars[c[0]] + 1 + chars[c[1]]
                continue
            chars[c] = int(fontconfig[c][0])
            positions[c] = x
            if chars[c] > 7:
                x += 15
            else:
                x += 7
    glyphs = game.readFontGlyphs(fontconfigfile)
    skipcodes = [0x0, 0x40, 0x80, 0xc0]

    # Open the images
    img = Image.open(infont).convert("RGB")
    pixels = img.load()
    font = Image.open(fontfile).convert("RGB")
    fontpixels = font.load()

    # Generate the image and table
    fontx = 0
    fonty = 0xa3 * 16 + 1
    fontwidths = []
    x = 0x20
    tablestr = ""
    for item in glyphs:
        while x in skipcodes:
            fontx += 16
            if fontx == 16 * 4:
                fontx = 0
                fonty += 16
            x += 1
            fontwidths.append(0)
        if item in bigrams:
            for i2 in range(7):
                for j2 in range(15):
                    pixels[fontx + i2,
                           fonty + j2] = fontpixels[positions[item[0]] + i2,
                                                    j2]
            for i2 in range(7):
                for j2 in range(15):
                    pixels[fontx + chars[item[0]] + 1 + i2,
                           fonty + j2] = fontpixels[positions[item[1]] + i2,
                                                    j2]
        else:
            for i2 in range(15 if chars[item] > 7 else 7):
                for j2 in range(15):
                    pixels[fontx + i2,
                           fonty + j2] = fontpixels[positions[item] + i2, j2]
        if chars[item] < 15:
            for i2 in range(15 - chars[item]):
                for j2 in range(15):
                    pixels[fontx + chars[item] + i2,
                           fonty + j2] = fontpixels[positions[" "], j2]
        fontwidths.append(chars[item] + 1)
        fontx += 16
        if fontx == 16 * 4:
            fontx = 0
            fonty += 16
        tablestr += (item + "=" + common.toHex(x) + "\n")
        x += 1
        if fonty >= img.height:
            break
    with codecs.open(outtable, "w", "utf-8") as f:
        f.write(tablestr)
    # Replace the original ASCII character as well
    fontx = 0
    fonty = 1
    asciiglyphs = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    asciiwidths = []
    for asciiglyph in asciiglyphs:
        for i2 in range(7):
            for j2 in range(15):
                pixels[fontx + i2,
                       fonty + j2] = fontpixels[positions[asciiglyph] + i2, j2]
        for i2 in range(15 - chars[asciiglyph]):
            for j2 in range(15):
                pixels[fontx + chars[asciiglyph] + i2,
                       fonty + j2] = fontpixels[positions[" "], j2]
        asciiwidths.append(chars[asciiglyph] + 1)
        fontx += 16
        if fontx == 16 * 4:
            fontx = 0
            fonty += 16
    img.save(outfont, "PNG")

    # Put the font back in the bank and set the font widths
    with common.Stream(bankfile, "rb+") as f:
        ws.repackTiledImage(f, outfont, 16 * 4, 16 * 244)
        f.seek(0)
        for i in range(len(asciiwidths)):
            f.writeByte(asciiwidths[i])
            f.seek(63, 1)
        f.seek((0xa3 * 4) * 64)
        for i in range(len(fontwidths)):
            if 0x20 + i not in skipcodes:
                f.writeByte(fontwidths[i])
            else:
                f.seek(1, 1)
            f.seek(63, 1)

    common.logMessage("Done!")
Exemplo n.º 19
0
def run(data, allfile=False):
    infolder = data + "extract/"
    outfolder = data + "repack/"
    infile = data + "bin_input.txt"
    infilename = data + "name_input.txt"
    chartot = transtot = 0
    table, invtable, ccodes, glyphs = game.getFontData(data)

    with codecs.open(infile, "r", "utf-8") as bin:
        common.logMessage("Repacking bin from", infile, "...")
        for file in common.showProgress(game.fileranges):
            section = common.getSection(bin, file)
            if len(section) == 0:
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logMessage("Processing", file, "...")
            common.copyFile(infolder + file, outfolder + file)
            with common.Stream(outfolder + file, "rb+") as f:
                if file != "bank_1d.bin":
                    for binrange in game.fileranges[file]:
                        f.seek(binrange[0])
                        while f.tell() < binrange[1]:
                            if (len(binrange) >= 3):
                                f.seek(binrange[2], 1)
                            strpos = f.tell()
                            readstr = game.readString(f, table, True)
                            if allfile and len(readstr) > 50:
                                f.seek(strpos + 2)
                                continue
                            if readstr.startswith("|"):
                                f.seek(strpos + 2)
                                continue
                            if readstr != "":
                                newstr = ""
                                if readstr in section:
                                    newstr = section[readstr].pop(0)
                                    if len(section[readstr]) == 0:
                                        del section[readstr]
                                strend = f.tell()
                                if newstr != "":
                                    if newstr == "!":
                                        newstr = ""
                                    common.logDebug("Repacking", newstr, "at",
                                                    common.toHex(strpos))
                                    f.seek(strpos)
                                    game.writeString(f, newstr, invtable,
                                                     ccodes,
                                                     strend - strpos - 2, True)
                                    while f.tell() < strend:
                                        f.writeByte(int(ccodes[" "][0], 16))
                                    f.seek(strend - 2)
                                    f.writeUShort(0xffff)
                else:
                    # String pointers are stored starting at 0xcd00
                    f.seek(0xcd00)
                    ptrs = []
                    for i in range(23):
                        ptrs.append(f.readUShort())
                        f.seek(14, 1)
                    strings = []
                    for ptr in ptrs:
                        f.seek(ptr)
                        strings.append(game.readString(f, table, True))
                    newptrs = []
                    f.seek(0xce70)
                    for i in range(len(strings)):
                        if strings[i] in section:
                            newstr = section[strings[i]].pop(0)
                        else:
                            newstr = strings[i]
                        newstr = common.wordwrap(newstr, glyphs,
                                                 game.wordwrap_angel,
                                                 game.detectTextCode)
                        common.logDebug("Repacking", newstr, "at",
                                        common.toHex(f.tell()))
                        newstr = newstr.split("|")
                        if len(newstr) > 8:
                            common.logError("Line too long",
                                            str(len(newstr)) + "/8", newstr[0])
                            newstr = newstr[:8]
                        while len(newstr) < 8:
                            newstr.append("")
                        for binstr in newstr:
                            if not binstr.startswith("▼"):
                                binstr = " " + binstr
                            newptrs.append(f.tell())
                            game.writeString(f, binstr, invtable, ccodes, -1,
                                             True)
                            f.writeUShort(0xffff)
                    f.seek(0xcd00)
                    for newptr in newptrs:
                        f.writeUShort(newptr)
    # Set the name input selection glyphs in bank 14
    newglyphs = {}
    with codecs.open(infilename, "r", "utf-8") as name:
        nameglyphs = name.read().replace("\r",
                                         "").replace("\n",
                                                     "").replace("#", "")
    with common.Stream(outfolder + "bank_14.bin", "rb+") as f:
        # Write the new name input values
        f.seek(0xc250)
        for nameglyph in nameglyphs:
            if nameglyph in invtable and invtable[nameglyph][:2] != 'ff':
                f.writeUShort(int(invtable[nameglyph], 16))
            else:
                glyphcode = int(ccodes[nameglyph][0], 16) - 0x20
                glyphcode <<= 6
                glyphcode += 0xa300
                newglyphs[nameglyph] = glyphcode
                f.writeUShort(glyphcode)
        # Write "Adam", but using the long glyphs
        f.seek(0x296c + 3)
        f.writeUShort(int(invtable["A"], 16))
        f.seek(3, 1)
        f.writeUShort(newglyphs["d"])
        f.seek(3, 1)
        f.writeUShort(newglyphs["a"])
        f.seek(3, 1)
        f.writeUShort(newglyphs["m"])
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))

    nasm.run(common.bundledFile("bin_patch.asm"))
Exemplo n.º 20
0
def run(data, speaker=True, scene=False, merge=False):
    infolder = data + "extract/"
    files = ["bank_11.bin", "bank_12.bin"]
    outfile = data + "script_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    if merge:
        mergescript = codecs.open(data + "script_input.txt", "r", "utf-8")

    # Get the scenes list from the debug menu
    if scene:
        scenenames = {"bank_11.bin": [], "bank_12.bin": []}
        with common.Stream(infolder + "bank_1e.bin", "rb") as f:
            f.seek(0xcd90)
            while True:
                unk = f.readUShort()
                if unk == 0xffff:
                    break
                scenepos = f.readUShort()
                scenebank = "bank_11.bin" if f.readUShort(
                ) == 0x00f1 else "bank_12.bin"
                scenename = f.readNullString()
                scenenames[scenebank].append({
                    'pos': scenepos,
                    'name': scenename
                })
                f.seek(1, 1)  # Always 0x90
        for bankname in scenenames:
            scenenames[bankname] = sorted(scenenames[bankname],
                                          key=lambda i: i['pos'])

    # Extract the scripts
    with codecs.open(outfile, "w", "utf-8") as out:
        common.logMessage("Extracting script to", outfile, "...")
        for file in common.showProgress(files):
            common.logMessage("Processing", file, "...")
            out.write("!FILE:" + file + "\n")
            size = os.path.getsize(infolder + file)
            lastspeaker = -1
            if scene:
                nextscene = scenenames[file].pop(0)
            if merge:
                mergesection = common.getSection(mergescript, file)
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 1:
                    opcode = f.readByte()
                    if opcode == 0x0a:
                        strpos = f.tell()
                        # Print the scene name
                        if scene:
                            if (nextscene is not None
                                    and strpos >= nextscene['pos']):
                                out.write("\n\n##SCENE:" + nextscene['name'] +
                                          "\n")
                                nextscene = scenenames[file].pop(0) if len(
                                    scenenames[file]) > 0 else None
                        # Add the speaker name
                        if speaker:
                            # Usually 7 bytes before there's a 0x10 byte, followed by the speaker expression and then the speaker sprite
                            speakercode = -1
                            f.seek(-7, 1)
                            checkspeaker = f.readByte()
                            if checkspeaker == 0x10:
                                f.seek(1, 1)
                                speakercode = f.readByte()
                            else:
                                # Sometimes, it's 6 bytes before instead so check that one too
                                checkspeaker = f.readByte()
                                if checkspeaker == 0x10:
                                    f.seek(1, 1)
                                    speakercode = f.readByte()
                            if speakercode != -1:
                                if speakercode not in game.speakercodes:
                                    common.logDebug("Unknown speaker code",
                                                    speakercode)
                                else:
                                    if speakercode != lastspeaker:
                                        out.write(
                                            "#" +
                                            game.speakercodes[speakercode] +
                                            "\n")
                                    lastspeaker = speakercode
                        # Read the string
                        f.seek(strpos)
                        readstr = game.readString(f, table)
                        if readstr != "":
                            if readstr[-2:] == ">>":
                                readstr = readstr[:-2]
                            out.write(readstr)
                            out.write("=")
                            if merge and readstr in mergesection:
                                out.write(mergesection[readstr].pop(0))
                                if len(mergesection[readstr]) == 0:
                                    del mergesection[readstr]
                            out.write("\n")
                            common.logDebug("Read string:", readstr)
                    elif opcode in game.repopcodes:
                        while f.readByte() != 0xff:
                            pass
                    else:
                        f.seek(game.opcodes[opcode], 1)
            out.write("\n\n")
        common.logMessage("Done! Extracted", len(files), "files")
Exemplo n.º 21
0
def run(data):
    infolder = data + "extract/"
    outfolder = data + "repack/"
    files = ["bank_11.bin", "bank_12.bin"]
    binfile = outfolder + "bank_14.bin"
    debugfile = outfolder + "bank_1e.bin"
    infile = data + "script_input.txt"
    chartot = transtot = 0
    table, invtable, ccodes, glyphs = game.getFontData(data)

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    pointers = {}
    pointerdiff = {}
    common.logMessage("Repacking script from", infile, "...")
    with codecs.open(infile, "r", "utf-8") as script:
        for file in common.showProgress(files):
            section = common.getSection(script, file)
            pointers[file] = []
            pointerdiff[file] = {}
            if len(section) == 0:
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logMessage("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    while fin.tell() < size:
                        opcode = fin.readByte()
                        if opcode == 0x0a:
                            f.writeByte(opcode)
                            strpos2 = f.tell()
                            strpos = fin.tell()
                            readstr = game.readString(fin, table)
                            newstr = ""
                            if readstr != "":
                                addend = ""
                                if readstr[-2:] == ">>":
                                    addend = ">>"
                                    readstr = readstr[:-2]
                                if readstr in section:
                                    newstr = section[readstr].pop(0)
                                    if len(section[readstr]) == 0:
                                        del section[readstr]
                            strend = fin.tell()
                            if newstr != "":
                                newstr = common.wordwrap(
                                    newstr, glyphs, game.wordwrap,
                                    game.detectTextCode)
                                if newstr == "!":
                                    newstr = ""
                                newstr += addend
                                common.logDebug("Writing string at",
                                                common.toHex(strpos),
                                                common.toHex(strpos2), newstr)
                                game.writeString(f, newstr, invtable, ccodes)
                                f.writeUShort(0xffff)
                                strend2 = f.tell()
                                lendiff = (strend2 - strpos2) - (strend -
                                                                 strpos)
                                if lendiff != 0:
                                    common.logDebug("Adding", lendiff, "at",
                                                    common.toHex(strpos))
                                    pointerdiff[file][strpos + 1] = lendiff
                            else:
                                fin.seek(strpos)
                                f.write(fin.read(strend - strpos))
                        elif opcode in game.repopcodes:
                            if opcode in game.ptropcodes:
                                pointers[file].append(f.tell())
                            f.writeByte(opcode)
                            replen = 0
                            while True:
                                loopbyte = fin.readByte()
                                f.writeByte(loopbyte)
                                replen += 1
                                if loopbyte == 0xff and (opcode
                                                         not in game.ptropcodes
                                                         or replen > 2):
                                    break
                        else:
                            if opcode in game.ptropcodes:
                                pointers[file].append(f.tell())
                            f.writeByte(opcode)
                            f.write(fin.read(game.opcodes[opcode]))
                            if opcode == 0xff:
                                check = fin.readUInt()
                                check2 = fin.readUInt()
                                fin.seek(-8, 1)
                                if check == 0xffffffff and check2 == 0xffffffff:
                                    break
                    # Pad with 0xffff
                    f.writeBytes(0xff, 0xffff - f.tell() + 1)
    common.logMessage("Shifting script pointers ...")
    for file in common.showProgress(files):
        with common.Stream(outfolder + file, "rb+") as f:
            for pointerpos in pointers[file]:
                f.seek(pointerpos)
                opcode = f.readByte()
                for pointeroff in game.ptropcodes[opcode]:
                    pointerfile = file
                    if type(pointeroff) == tuple:
                        f.seek(pointerpos + 1 + pointeroff[1])
                        bankid = f.readUShort()
                        pointerfile = files[0] if bankid == 0x00f1 else files[1]
                        pointeroff = pointeroff[0]
                    f.seek(pointerpos + 1 + pointeroff)
                    pointer = f.readUShort()
                    if pointer != 0xffff:
                        newpointer = common.shiftPointer(
                            pointer, pointerdiff[pointerfile])
                    else:
                        newpointer = pointer
                    f.seek(-2, 1)
                    f.writeUShort(newpointer)
    common.logMessage("Shifting bin pointers ...")
    # Read pointer tables in the bin file
    with common.Stream(binfile.replace("/repack/", "/extract/"), "rb+") as f:
        f.seek(0x23b0)
        while f.tell() < 0x2740:
            pos1 = f.tell()
            ptr1 = f.readUShort()
            bank1 = f.readUShort()
            pos2 = f.tell()
            ptr2 = f.readUShort()
            bank2 = f.readUShort()
            game.binptrs.append((pos1, ptr1, bank1))
            game.binptrs.append((pos2, ptr2, bank2))
            f.seek(8, 1)
        for binrange in [(0x2ff7, 0x3027), (0x3063, 0x309b), (0x480f, 0x481f),
                         (0x496b, 0x499b), (0x4a01, 0x4a39)]:
            f.seek(binrange[0])
            while f.tell() < binrange[1]:
                pos = f.tell()
                ptr = f.readUShort()
                bank = f.readUShort()
                game.binptrs.append((pos, ptr, bank))
        f.seek(0x902e)
        while f.tell() < 0x9106:
            pos = f.tell()
            ptr = f.readUShort()
            game.binptrs.append((pos, ptr, 0xf2))
    game.binptrs.append((0x26b8, 0x3d7b, 0xf2))
    shiftPointers(binfile, game.binptrs, pointerdiff)
    # Shift debug pointers
    debugptrs = []
    with common.Stream(debugfile.replace("/repack/", "/extract/"), "rb+") as f:
        f.seek(0xcd92)
        while f.tell() < 0xd420:
            pos1 = f.tell()
            ptr1 = f.readUShort()
            bank1 = f.readUShort()
            debugptrs.append((pos1, ptr1, bank1))
            f.seek(12, 1)
    shiftPointers(debugfile, debugptrs, pointerdiff)
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 22
0
def run():
    infolder = "data/extract/data/Rom/event/script/"
    outfolder = "data/repack/data/Rom/event/script/"
    infile = "data/cnut_input.txt"
    fontfile = "data/repack/data/Rom/font/font0.NFTR"
    replacefontfile = "data/replace/data/Rom/font/font0.NFTR"
    chartot = transtot = 0

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    common.logMessage("Repacking CNUT from", infile, "...")
    if os.path.isfile(replacefontfile):
        glyphs = nitro.readNFTR(replacefontfile).glyphs
    else:
        glyphs = nitro.readNFTR(fontfile).glyphs
    with codecs.open(infile, "r", "utf-8") as cnut:
        files = common.getFiles(infolder, ".cnut")
        for file in common.showProgress(files):
            section = common.getSection(cnut, file, "//")
            if len(section) == 0:
                common.makeFolders(outfolder + file)
                common.copyFile(infolder + file, outfolder + file)
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logDebug("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            lastpos = 0
            with common.Stream(infolder + file, "rb") as fin:
                common.makeFolders(infolder + file)
                with common.Stream(outfolder + file, "wb") as f:
                    while fin.tell() < size - 4:
                        pos = fin.tell()
                        b1 = fin.readByte()
                        b2 = fin.readByte()
                        b3 = fin.readByte()
                        b4 = fin.readByte()
                        if b1 == 0x10 and b2 == 0x00 and b3 == 0x00 and b4 == 0x08:
                            # Found a string
                            check = game.readShiftJIS(fin)
                            pre = post = ""
                            # Add back some codes that are removed from extracted lines
                            if check.startswith("#CLR()"):
                                pre = "#CLR()"
                                check = check[6:]
                            if check.startswith("#ARW("):
                                pre += check[:7]
                                check = check[7:]
                            if check.endswith("#INP()"):
                                post = "#INP()"
                                check = check[:-6]
                            # Check if the line is translated and replace it
                            if check in section:
                                newsjis = section[check].pop(0)
                                if len(section[check]) == 0:
                                    del section[check]
                                if newsjis != "":
                                    newsjis = pre + newsjis + post
                                    if newsjis != check:
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 205,
                                            game.detectTextCode)
                                        newsjis = newsjis.replace(
                                            ">>", "#INP()" + pre).replace(
                                                "|", "<0A>")
                                        # Copy data up to here
                                        endpos = fin.tell()
                                        fin.seek(lastpos)
                                        f.write(fin.read(pos + 4 - lastpos))
                                        lastpos = endpos
                                        common.logDebug("  Repacking at", pos)
                                        game.writeShiftJIS(f, newsjis)
                        else:
                            fin.seek(pos + 1)
                    fin.seek(lastpos)
                    f.write(fin.read(size - lastpos))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 23
0
def run():
    binin = "data/extract/arm9.bin"
    binout = "data/repack/arm9.bin"
    binfile = "data/bin_input.txt"
    tablefile = "data/table.txt"
    if not os.path.isfile(binfile):
        common.logError("Input file", binfile, "not found.")
        return
    common.copyFile(binin, binout)

    freeranges = [(0xEA810, 0xEEC00)]
    currentrange = 0
    rangepos = 0

    section = {}
    with codecs.open(binfile, "r", "utf-8") as bin:
        section = common.getSection(bin, "", "#", game.fixchars)
        chartot, transtot = common.getSectionPercentage(section)

    common.logMessage("Repacking BIN from", binfile, "...")
    common.loadTable(tablefile)
    rangepos = freeranges[currentrange][0]
    with common.Stream(binin, "rb") as fi:
        allbin = fi.read()
        strpointers = {}
        with common.Stream(binout, "r+b") as fo:
            # Skip the beginning and end of the file to avoid false-positives
            fi.seek(992000)
            while fi.tell() < 1180000:
                pos = fi.tell()
                if pos < 1010000 or pos > 1107700:
                    check = game.detectShiftJIS(fi)
                    if check in section and section[check][0] != "":
                        common.logDebug("Replacing string at", pos)
                        newstr = section[check][0]
                        # Check how much padding space we have
                        padding = 0
                        while True:
                            if fi.readByte() == 0x00:
                                padding += 1
                            else:
                                fi.seek(-1, 1)
                                break
                        fo.seek(pos)
                        endpos = fi.tell() - 1
                        newlen = game.writeShiftJIS(fo, newstr, False,
                                                    endpos - pos)
                        if newlen < 0:
                            if rangepos >= freeranges[currentrange][
                                    1] and newstr not in strpointers:
                                common.logWarning("No more room! Skipping ...")
                            else:
                                # Write the string in a new portion of the rom
                                if newstr in strpointers:
                                    newpointer = strpointers[newstr]
                                else:
                                    common.logDebug(
                                        "No room for the string, redirecting to",
                                        rangepos)
                                    fo.seek(rangepos)
                                    game.writeShiftJIS(fo, newstr, False)
                                    fo.writeZero(1)
                                    newpointer = 0x02000000 + rangepos
                                    rangepos = fo.tell()
                                    strpointers[newstr] = newpointer
                                    if rangepos >= freeranges[currentrange][1]:
                                        if currentrange + 1 < len(freeranges):
                                            currentrange += 1
                                            rangepos = freeranges[
                                                currentrange][0]
                                # Search and replace the old pointer
                                pointer = 0x02000000 + pos
                                pointersearch = struct.pack("<I", pointer)
                                index = 0
                                common.logDebug("Searching for pointer",
                                                pointersearch.hex().upper())
                                while index < len(allbin):
                                    index = allbin.find(pointersearch, index)
                                    if index < 0:
                                        break
                                    common.logDebug("  Replaced pointer at",
                                                    str(index))
                                    fo.seek(index)
                                    fo.writeUInt(newpointer)
                                    index += 4
                        else:
                            fo.writeZero(endpos - fo.tell())
                    if check != "":
                        pos = fi.tell() - 1
                fi.seek(pos + 1)
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Exemplo n.º 24
0
def run():
    xmlfile = "data/fontdump.xml"
    imgfile = "data/fontdump.png"
    fontfile = "font.png"
    fontconfigfile = "fontconfig.txt"
    outfile = "data/fontout.png"
    infont = "data/extract_NFP/ETC.NFP/GL_12FNT.NFT"
    tempfont = "data/GL_12FNT.NFTR"
    outfont = "data/work_NFP/ETC.NFP/GL_12FNT.NFT"
    binin = "data/bin_input.txt"
    spcin = "data/spc_input.txt"
    table = "data/table.txt"

    common.logMessage("Repacking font ...")
    fontexe = common.bundledFile("NerdFontTerminatoR.exe")
    if not os.path.isfile(fontexe):
        common.logError("NerdFontTerminatoR not found")
        return

    # List of characters
    with codecs.open(fontconfigfile, "r", "utf-8") as f:
        fontconfig = common.getSection(f, "")
        upperchars = fontconfig["upperchars"][0].split("|")
        lowerchars = fontconfig["lowerchars"][0].split("|")
        numbers = fontconfig["numbers"][0].split("|")
        punctuation = fontconfig["punctuation"][0].split("|")
        customs = fontconfig["customs"][0].split("|")
        all = upperchars + lowerchars + numbers + punctuation + customs

    # X Position in the font.png file
    positions = {}
    for i in range(len(upperchars)):
        positions[upperchars[i]] = i * 12
        positions[lowerchars[i]] = (i * 12) + 6
    for i in range(len(numbers)):
        positions[numbers[i]] = (len(upperchars) * 12) + (i * 6)
    for i in range(len(punctuation)):
        positions[punctuation[i]] = (len(upperchars) * 12) + (len(numbers) * 6) + (i * 6)
    for i in range(len(customs)):
        positions[customs[i]] = (len(upperchars) * 12) + (len(numbers) * 6) + (len(punctuation) * 6) + (i * 12)

    # Fix the font size before dumping it
    with common.Stream(infont, "rb") as font:
        with common.Stream(tempfont, "wb") as temp:
            font.seek(8)
            size = font.readUInt()
            font.seek(0)
            temp.write(font.read(size))
    # Dump the font
    common.execute(fontexe + " -e " + tempfont + " " + xmlfile + " " + imgfile, False)

    # Generate the code range
    coderanges = [(0x89, 0x9F), (0xE0, 0xEA)]
    skipcodes = [0x7F]
    charrange = (0x40, 0xFC)
    codes = []
    for coderange in coderanges:
        for i in range(coderange[0], coderange[1] + 1):
            first = charrange[0]
            if i == 0x88:
                first = 0x9F
            last = charrange[1]
            if i == 0xEA:
                last = 0xA4
            for j in range(first, last + 1):
                if j in skipcodes:
                    continue
                hexcode = i * 0x100 + j
                if hexcode > 0x9872 and hexcode < 0x989F:
                    continue
                codes.append(hexcode)

    # Generate a basic bigrams list
    items = ["  "]
    for char1 in upperchars:
        for char2 in lowerchars:
            items.append(char1 + char2)
    for char1 in upperchars:
        items.append(" " + char1)
        items.append(char1 + " ")
        for char2 in upperchars:
            if char1 + char2 not in items:
                items.append(char1 + char2)
    for char1 in lowerchars:
        items.append(" " + char1)
        items.append(char1 + " ")
        for char2 in lowerchars:
            if char1 + char2 not in items:
                items.append(char1 + char2)
    for custom in customs:
        items.append(custom)
    # And a complete one from all the bigrams
    with codecs.open(spcin, "r", "utf-8") as spc:
        inputs = common.getSection(spc, "", "#", game.fixchars)
    with codecs.open(binin, "r", "utf-8") as bin:
        inputs.update(common.getSection(bin, "", "#", game.fixchars))
    for k, input in inputs.items():
        for str in input:
            str = "<0A>".join(str.replace("|", "<0A>").split(">>"))
            if str.startswith("<<"):
                str = str[2:]
                pad = " " * ((20 - len(str)) // 2)
                str = pad + str + pad
            if str.startswith("[") and str[3] == "]":
                str = str[4:]
            i = 0
            while i < len(str):
                if i < len(str) - 1 and str[i+1] == "<":
                    str = str[:i+1] + " " + str[i+1:]
                elif i < len(str) - 4 and (str[i+1:i+5] == "UNK(" or str[i+1:i+5] == "CUS("):
                    str = str[:i+1] + " " + str[i+1:]
                char = str[i]
                if char == "<" and i < len(str) - 3 and str[i+3] == ">":
                    i += 4
                elif char == "U" and i < len(str) - 4 and str[i:i+4] == "UNK(":
                    i += 9
                elif char == "C" and i < len(str) - 4 and str[i:i+4] == "CUS(":
                    i += 9
                else:
                    if i + 1 == len(str):
                        bigram = char + " "
                    else:
                        bigram = char + str[i+1]
                    i += 2
                    if bigram not in items:
                        if bigram[0] not in all or bigram[1] not in all:
                            common.logError("Invalid bigram", bigram, "from phrase", str)
                        else:
                            items.append(bigram)

    # Open the images
    img = Image.open(imgfile)
    pixels = img.load()
    font = Image.open(fontfile)
    fontpixels = font.load()

    # Generate the image and table
    fontx = 106
    fonty = 5644
    x = len(codes) - 1
    tablestr = ""
    for item in items:
        if item in customs:
            for i2 in range(11):
                for j2 in range(11):
                    pixels[fontx + i2, fonty + j2] = fontpixels[positions[item] + i2, j2]
        else:
            for i2 in range(5):
                for j2 in range(11):
                    pixels[fontx + i2, fonty + j2] = fontpixels[positions[item[0]] + i2, j2]
            for j2 in range(11):
                pixels[fontx + 5, fonty + j2] = fontpixels[positions[" "], j2]
            for i2 in range(5):
                for j2 in range(11):
                    pixels[fontx + i2 + 6, fonty + j2] = fontpixels[positions[item[1]] + i2, j2]
        fontx -= 13
        if fontx < 0:
            fontx = 197
            fonty -= 13
        tablestr = (item + "=" + common.toHex(codes[x]) + "\n") + tablestr
        x -= 1
    with codecs.open(table, "w", "utf-8") as f:
        f.write(tablestr)
    img.save(outfile, "PNG")

    # Generate the new font
    common.execute(fontexe + " -i " + xmlfile + " " + outfile + " " + tempfont, False)
    common.copyFile(tempfont, outfont)
    # Clean up the temp files
    os.remove(xmlfile)
    os.remove(imgfile)
    os.remove(outfile)
    os.remove(tempfont)

    if x < len(items):
        common.logMessage("Done! Couldn't fit", len(items) - x, "bigrams")
    else:
        common.logMessage("Done! Room for", x - len(items), "more bigrams")