Пример #1
0
def extract(rom, font, bin, script, credits, img):
    all = not rom and not font and not bin and not script and not credits and not img
    if all or rom:
        ws.extractRom(romfile, infolder, outfolder)
    if all or bin:
        import extract_bin
        extract_bin.run(data)
    if all or font:
        with common.Stream(infolder + "bank_10.bin", "rb") as f:
            ws.extractTiledImage(f, data + "font_output.png", 16 * 4, 16 * 244)
        with common.Stream(data + "table_output.txt", "w") as f:
            columns = ("00", "40", "80", "c0")
            for row in range(244):
                for column in range(4):
                    if row < 0x10:
                        f.write("0")
                    f.write(format(row, "x") + columns[column] + "=\n")
                f.write("\n")
    if all or script:
        import extract_script
        extract_script.run(data)
    if all or credits:
        import extract_credits
        extract_credits.run(data)
    if all or img:
        import extract_img
        extract_img.run(data)
Пример #2
0
def repackBinaryStrings(elf,
                        section,
                        infile,
                        outfile,
                        readfunc,
                        writefunc,
                        encoding="shift_jis",
                        elfsections=[".rodata"]):
    with common.Stream(infile, "rb") as fi:
        with common.Stream(outfile, "r+b") as fo:
            for sectionname in elfsections:
                rodata = elf.sectionsdict[sectionname]
                fi.seek(rodata.offset)
                while fi.tell() < rodata.offset + rodata.size:
                    pos = fi.tell()
                    check = readfunc(fi, encoding)
                    if check != "":
                        if check in section and section[check][0] != "":
                            common.logDebug("Replacing string", check, "at",
                                            common.toHex(pos), "with",
                                            section[check][0])
                            fo.seek(pos)
                            endpos = fi.tell() - 1
                            newlen = writefunc(fo, section[check][0],
                                               endpos - pos + 1)
                            if newlen < 0:
                                fo.writeZero(1)
                                common.logError("String", section[check][0],
                                                "is too long.")
                            else:
                                fo.writeZero(endpos - fo.tell())
                        else:
                            pos = fi.tell() - 1
                    fi.seek(pos + 1)
Пример #3
0
def extract(file, outfolder, guessextension=None):
    common.logDebug("Processing", file, "...")
    common.makeFolder(outfolder)
    cpk = readCPK(file)
    if cpk is None:
        common.logError("Error reading CPK")
        return
    if len(cpk.filetable) == 0:
        common.logError("No files in CPK filetable")
        return
    with common.Stream(file, "rb") as f:
        for entry in cpk.filetable:
            if entry.filetype != "FILE":
                continue
            folder, filename = entry.getFolderFile(outfolder)
            f.seek(entry.fileoffset)
            data = f.read(entry.filesize)
            f.seek(entry.fileoffset)
            checkcomp = f.readString(8)
            if checkcomp == "CRILAYLA":
                extractsize = entry.extractsize if entry.extractsize != 0 else entry.filesize
                if extractsize != 0:
                    data = compression.decompressCRILAYLA(f, entry.fileoffset)
            if guessextension is not None:
                filename = guessextension(data, entry, filename)
            if not os.path.isdir(folder):
                common.makeFolders(folder)
            with common.Stream(folder + filename, "wb") as fout:
                fout.write(data)
Пример #4
0
def repackRom(romfile, rompatch, workfolder, patchfile="", banksize=0x4000):
    common.logMessage("Repacking ROM", rompatch, "...")
    filesize = os.path.getsize(romfile)
    banknum = filesize // banksize
    common.logMessage("Repacking", banknum, "banks ...")
    with common.Stream(rompatch, "wb") as fout:
        for i in range(banknum):
            bankname = "bank_"
            if i < 0x10:
                bankname += "0"
            bankname += format(i, 'x')
            with common.Stream(workfolder + bankname + ".bin", "rb") as f:
                fout.write(f.read())
    # Calculate and write the global checksum
    with common.Stream(rompatch, "rb+", False) as fout:
        checksum = sum(fout.read(0x14e))
        fout.seek(0x150)
        checksum += sum(fout.read(filesize - 0x150))
        fout.seek(0x14e)
        fout.writeUShort(checksum & 0xffff)
    common.logMessage("Done!")
    # Create patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, romfile, rompatch)
        common.ipsPatch(patchfile.replace(".xdelta", ".ips"), romfile,
                        rompatch)
Пример #5
0
def mpstopmf(infile, outfile, duration):
    with common.Stream(infile, "rb", False) as fin:
        # Check header
        check1 = fin.readUInt()
        check2 = fin.readByte()
        if check1 != 0x1ba or check2 != 0x44:
            common.logError("Input header is wrong", common.toHex(check1),
                            common.toHeck(check2))
            return
        fin.seek(0)
        mpsdata = fin.read()
    # https://github.com/TeamPBCN/pmftools/blob/main/mps2pmf/mps2pmf.cpp
    with common.Stream(outfile, "wb", False) as f:
        # Magic
        f.writeString("PSMF")
        f.writeString("0012")
        # Header size
        f.writeUInt(0x800)
        # MPS size
        f.writeUInt(len(mpsdata))
        f.seek(0x50)
        # Other header values
        f.writeUInt(0x4e)
        f.writeUInt(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0)
        f.writeUInt(duration)
        f.writeUInt(0x61a8)
        f.writeUShort(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0x201)
        f.writeUShort(0)
        f.writeUShort(0x34)
        f.writeUShort(0)
        f.writeUShort(1)
        f.writeUShort(0x5f90)
        f.writeUShort(0)
        f.writeUInt(duration)
        f.writeUShort(1)
        f.writeUInt(0x22)
        f.writeUShort(0x2)
        f.writeUShort(0xe000)
        f.writeUShort(0x21ef)
        f.writeUShort(0)
        f.writeUInt(0x0)
        f.writeUInt(0x1e11)
        f.writeUInt(0xbd00)
        f.writeUShort(0x2004)
        f.seek(0xa0)
        f.writeUShort(0x202)
        # Everything else is 0, write the MPS data
        f.seek(0x800)
        f.write(mpsdata)
Пример #6
0
def run(file, addframes):
    infile = "data/extract_NFP/NFP2D.NFP/" + file
    outfile = "data/work_YCE/" + file

    common.logMessage("Expanding", infile, "to", outfile, "...")
    with common.Stream(outfile, "wb") as f:
        with common.Stream(infile, "rb") as fin:
            # Copy header
            f.write(fin.read(28))
            # Image number
            num = fin.readUInt()
            fin.seek(num * 4, 1)
            f.writeUInt(num + addframes)
            # Make room for the positions
            offsetpos = f.tell()
            for i in range(num + addframes):
                f.writeUInt(0)
            # Copy the existing images
            for i in range(num):
                newpos = f.tell()
                f.seek(offsetpos + i * 4)
                f.writeUInt(newpos - 24)
                f.seek(newpos)
                size = fin.readUInt()
                fin.seek(-4, 1)
                data = fin.read(size)
                f.write(data)
            # Add the new frames
            for i in range(num, num + addframes):
                newpos = f.tell()
                f.seek(offsetpos + i * 4)
                f.writeUInt(newpos - 24)
                f.seek(newpos)
                f.write(data)
        # Read the animation frames from another file
        animoffset = f.tell()
        with common.Stream(animfiles[num + addframes], "rb") as fin:
            fin.seek(20)
            animoffset2 = fin.readUInt()
            fin.seek(animoffset2)
            animsize = fin.readUInt()
            fin.seek(-4, 1)
            f.write(fin.read(animsize))
        totsize = f.tell()
        # Pad with 0s
        f.writeZero(16 - (f.tell() % 16))
        # Write new sizes and offsets
        f.seek(8)
        f.writeUInt(totsize)
        f.seek(20)
        f.writeUInt(animoffset)
        f.writeUInt(animoffset - 32)
    common.logMessage("Done!")
Пример #7
0
def compressBinary(infile, outfile):
    with common.Stream(infile, "rb") as fin:
        data = bytearray(fin.read())
    compdata = bytearray(codeCompression.compress(data, True))
    codeoffset = 0
    for i in range(0, 0x8000, 4):
        if compdata[i:i+8] == b'\x21\x06\xC0\xDE\xDE\xC0\x06\x21':
            codeoffset = i - 0x1C
            break
    if codeoffset > 0:
        struct.pack_into("<I", compdata, codeoffset + 0x14, 0x02000000 + len(compdata))
    with common.Stream(outfile, "wb") as f:
        f.write(compdata)
Пример #8
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!")
Пример #9
0
def readELF(infile):
    elf = ELF()
    with common.Stream(infile, "rb") as f:
        f.seek(0x20)
        sectionsoff = f.readUInt()
        f.seek(0x2E)
        sectionsize = f.readUShort()
        sectionnum = f.readUShort()
        shstrndx = f.readUShort()
        common.logDebug("sectionsoff:", sectionsoff, "sectionsize:",
                        sectionsize, "sectionnum", sectionnum, "shstrndx",
                        shstrndx)
        # Read section headers
        f.seek(sectionsoff)
        for i in range(sectionnum):
            section = ELFSection()
            section.nameoff = f.readUInt()
            section.type = f.readUInt()
            section.flags = f.readUInt()
            section.addr = f.readUInt()
            section.offset = f.readUInt()
            section.size = f.readUInt()
            section.link = f.readUInt()
            section.info = f.readUInt()
            section.addralign = f.readUInt()
            section.entsize = f.readUInt()
            elf.sections.append(section)
        # Read section names
        for section in elf.sections:
            f.seek(elf.sections[shstrndx].offset + section.nameoff)
            section.name = f.readNullString()
            elf.sectionsdict[section.name] = section
        for i in range(sectionnum):
            common.logDebug(i, vars(elf.sections[i]))
    return elf
Пример #10
0
def extractPGFData(file, outfile, bitmapout="", justadvance=False):
    pgf = readPGFData(file)
    with common.Stream(file, "rb") as fin:
        with codecs.open(outfile, "w", "utf-8") as f:
            for glyph in pgf.glyphs:
                char = glyph.char.replace("=", "<3D>")
                if justadvance:
                    f.write(char + "=" + str(glyph.advance["x"]) + "\n")
                else:
                    data = json.dumps({
                        "width": glyph.width,
                        "height": glyph.height,
                        "left": glyph.left,
                        "top": glyph.top,
                        "dimension": glyph.dimension,
                        "bearingx": glyph.bearingx,
                        "bearingy": glyph.bearingy,
                        "advance": glyph.advance
                    })
                    f.write(char + "=" + data + "\n")
                if bitmapout != "" and glyph.width > 0 and glyph.height > 0:
                    fin.seek(pgf.glyphpos + pgf.charptr[glyph.index] +
                             glyph.totlen // 8)
                    buf = fin.read(1024)
                    extractPGFBitmap(
                        buf, glyph,
                        bitmapout + str(glyph.index).zfill(4) + ".png")
Пример #11
0
def readGIM(file, start=0):
    gim = GIM()
    with common.Stream(file, "rb") as f:
        f.seek(start)
        if f.readString(3) == 'MIG':
            f.seek(start + 16)
            gim.rootoff = f.tell()
            id = f.readUShort()
            if id != 0x02:
                common.logError("Unexpected id in block 0:", common.toHex(id),
                                common.toHex(f.tell() - 2))
                return None
            f.seek(2, 1)
            gim.rootsize = f.readUInt()
            nextblock = gim.rootoff + f.readUInt()
            image = None
            while nextblock > 0 and nextblock < start + gim.rootsize + 16:
                f.seek(nextblock)
                nextblock, image = readGIMBlock(f, gim, image)
        else:
            # This is a TGA file, assuming 32bit RGBA
            image = TGAImage()
            image.rootoff = f.tell()
            f.seek(start + 2)
            image.format = f.readByte()
            f.seek(9, 1)
            image.width = f.readUShort()
            image.height = f.readUShort()
            f.seek(2, 1)
            image.imgoff = f.tell()
            for i in range(image.height):
                for j in range(image.width):
                    image.colors.append(readColor(f, 0x03))
            gim = image
    return gim
Пример #12
0
def repack(fin, f, archive, infolder):
    # Copy everything up to dataoff
    fin.seek(0)
    f.seek(0)
    f.write(fin.read(archive.dataoff))
    # Loop the files
    dataoff = 0
    for i in range(archive.filenum):
        subfile = archive.files[i]
        filepath = infolder + subfile.name
        if not os.path.isfile(filepath):
            # Just update the offset and copy the file
            f.seek(archive.fatoff + i * 16)
            f.seek(8, 1)
            f.writeUInt(dataoff)
            fin.seek(archive.dataoff + subfile.offset)
            f.seek(archive.dataoff + dataoff)
            f.write(fin.read(subfile.length))
        else:
            # Set the file as not encoded and copy it
            size = os.path.getsize(filepath)
            size += size % 16
            f.seek(archive.fatoff + i * 16)
            f.writeUInt(size)
            f.writeUInt(size)
            f.writeUInt(dataoff)
            f.seek(2, 1)
            f.writeUShort(0)
            f.seek(archive.dataoff + dataoff)
            with common.Stream(filepath, "rb") as subf:
                f.write(subf.read())
        # Align with 0s
        if f.tell() % 16 > 0:
            f.writeZero(16 - (f.tell() % 16))
        dataoff = f.tell() - archive.dataoff
Пример #13
0
def repack(no_rom, bin, cnut, ncgr):
    all = not bin and not cnut and not ncgr
    if all or bin:
        nds.repackBIN(game.binrange, game.freeranges, game.detectShiftJIS,
                      game.writeBINShiftJIS, "shift_jis", "//")
        common.logMessage("Patching BIN ...")
        with common.Stream(binfile, "r+b") as fo:
            # Patch the text rendering function to allow more than 15 characters per line (Thanks StorMyu!)
            fo.seek(0x6680C)
            fo.writeByte(0xFF)
        common.logMessage("Done!")
    if all or cnut:
        import repack_cnut
        repack_cnut.run()
    if all or ncgr:
        nitro.repackIMG("data/work_NCGR/", "data/extract/data/Rom/",
                        "data/repack/data/Rom/", [".NCGR", ".NCBR"],
                        game.readImage)

    if not no_rom:
        if os.path.isdir(replacefolder):
            common.mergeFolder(replacefolder, outfolder)
        nds.editBannerTitle(bannerfile,
                            "Soul Eater\nMedusa's Plot\nBandai Namco Games")
        nds.repackRom(romfile, rompatch, outfolder, patchfile)
Пример #14
0
def run():
    infile = "data/extract/arm9.bin"
    outfile = "data/bin_output.txt"
    # Set to False to analyze the whole file
    limit = True

    common.logMessage("Extracting BIN to", outfile, "...")
    with codecs.open(outfile, "w", "utf-8") as out:
        with common.Stream(infile, "rb") as f:
            # Skip the beginning and end of the file to avoid false-positives
            f.seek(992000 if limit else 900000)
            foundstrings = []
            while f.tell() < 1180000:
                pos = f.tell()
                if not limit or pos < 1010000 or pos > 1107700:
                    check = game.detectShiftJIS(f)
                    # Save the string if we detected one
                    if check != "":
                        if check not in foundstrings:
                            common.logDebug("Found string at", pos)
                            foundstrings.append(check)
                            out.write(check + "=\n")
                        pos = f.tell() - 1
                f.seek(pos + 1)
    common.logMessage("Done! Extracted", len(foundstrings), "lines")
Пример #15
0
def repack(font, bin, script, img, credits, debug, angel, no_rom):
    all = not font and not bin and not script and not img and not credits
    if all or font:
        import repack_font
        repack_font.run(data)
    if all or bin:
        import repack_bin
        repack_bin.run(data)
    if all or script or bin:
        import repack_script
        repack_script.run(data)
    if all or img:
        import repack_img
        repack_img.run(data)
    if all or credits:
        import repack_credits
        repack_credits.run(data)
    # https://tcrf.net/Neon_Genesis_Evangelion:_Shito_Ikusei
    with common.Stream(outfolder + "bank_14.bin", "rb+") as f:
        if debug or angel:
            if debug:
                f.seek(0x97)
                f.writeUInt(0x4000cc6e)
            f.seek(0xa6b9)
            f.writeByte(0x0e if not angel else 0x0d)
        else:
            f.seek(0x97)
            f.writeUInt(0x0)
            f.seek(0xa6b9)
            f.writeByte(0x3)
    if not no_rom:
        if os.path.isdir(replacefolder):
            common.mergeFolder(replacefolder, outfolder)
        ws.repackRom(romfile, rompatch, outfolder, patchfile)
Пример #16
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!")
Пример #17
0
def asmPatch(file, workfolder, banks=[0x0], banksize=0x4000):
    common.logMessage("Applying ASM patch ...")
    wlagb = common.bundledExecutable("wla-gb.exe")
    if not os.path.isfile(wlagb):
        common.logError("wla-gb not found")
        return
    wlalink = common.bundledExecutable("wlalink.exe")
    if not os.path.isfile(wlalink):
        common.logError("wlalink not found")
        return
    # Create the output file
    ofile = file.replace(".asm", ".o")
    if os.path.isfile(ofile):
        os.remove(ofile)
    common.execute(
        wlagb + " -o {ofile} {binpatch}".format(binpatch=file, ofile=ofile),
        False)
    if not os.path.isfile(ofile):
        return
    # Run the linker and create a temporary patched ROM
    tempfile = file.replace(".asm", ".txt")
    deletetemp = False
    if not os.path.isfile(tempfile):
        deletetemp = True
        with open(tempfile, "w") as f:
            f.write("[objects]\n")
            f.write(ofile + "\n")
    temprom = "temprom.gb"
    common.execute(
        wlalink +
        " -r {tempfile} {temprom}".format(tempfile=tempfile, temprom=temprom),
        False)
    if deletetemp:
        os.remove(tempfile)
    os.remove(ofile)
    # Extract the banks we're interested in from the temp ROM
    with common.Stream(temprom, "rb") as f:
        for i in banks:
            bankname = "bank_"
            if i < 0x10:
                bankname += "0"
            bankname += format(i, 'x')
            f.seek(i * banksize)
            with common.Stream(workfolder + bankname + ".bin", "wb") as fout:
                fout.write(f.read(banksize))
    os.remove(temprom)
    common.logMessage("Done!")
Пример #18
0
def shiftPointers(file, ptrs, pointerdiff):
    with common.Stream(file, "rb+") as f:
        for binptr in ptrs:
            f.seek(binptr[0])
            newpointer = common.shiftPointer(
                binptr[1], pointerdiff["bank_11.bin" if binptr[2] ==
                                       0xf1 else "bank_12.bin"])
            f.writeUShort(newpointer)
Пример #19
0
def decompressCRILAYLA(f, fileoffset):
    def deflatelevels():
        for v in [2, 3, 5, 8]:
            yield v
        while True:
            yield 8

    uncsize = f.readUInt()
    uncheaderoffset = f.readUInt()
    # common.logDebug("decompressCRILAYLA uncsize", uncsize, "uncheaderoffset", uncheaderoffset)
    with common.Stream() as decmp:
        cmp = CompressedBitInput(f.read(uncheaderoffset))
        while True:
            bit = cmp.read01(1)
            if bit == '':
                break
            if int(bit, 2):
                offset = cmp.readnum(13) + 3
                refc = 3

                for lv in deflatelevels():
                    bits = cmp.read(lv)
                    refc += int(bits.to01(), 2)
                    if not bits.all():
                        break

                while refc > 0:
                    decmp.seek(-offset, 1)
                    ref = decmp.read(refc)
                    decmp.seek(0, 2)
                    decmp.write(ref)
                    refc -= len(ref)
            else:
                b = cmp.readbyte()
                decmp.write(b)
        cmp.close()
        with common.Stream() as result:
            # Copy the uncompressed 0x100 header
            f.seek(fileoffset + 0x10 + uncheaderoffset)
            result.write(f.read(0x100))
            # Copy the uncompressed data, reversed
            decmp.seek(0)
            result.write(decmp.read()[:uncsize][::-1])
            result.seek(0)
            return result.read()
Пример #20
0
def extractRom(romfile, extractfolder, workfolder="", banksize=0x4000):
    common.logMessage("Extracting ROM", romfile, "...")
    common.makeFolder(extractfolder)
    filesize = os.path.getsize(romfile)
    banknum = filesize // banksize
    common.logMessage("Extracting", banknum, "banks ...")
    with common.Stream(romfile, "rb") as f:
        for i in range(banknum):
            bankname = "bank_"
            if i < 0x10:
                bankname += "0"
            bankname += format(i, 'x')
            with common.Stream(extractfolder + bankname + ".bin",
                               "wb") as fout:
                fout.write(f.read(banksize))
    if workfolder != "":
        common.copyFolder(extractfolder, workfolder)
    common.logMessage("Done!")
Пример #21
0
def getFontGlyphs(file):
    glyphs = {}
    with common.Stream(file, "rb", False) as f:
        # Header
        f.seek(36)
        hdwcoffset = f.readUInt()
        pamcoffset = f.readUInt()
        common.logDebug("hdwcoffset:", hdwcoffset, "pamcoffset:", pamcoffset)
        # HDWC
        f.seek(hdwcoffset - 4)
        hdwclen = f.readUInt()
        tilenum = (hdwclen - 16) // 3
        firstcode = f.readUShort()
        lastcode = f.readUShort()
        f.seek(4, 1)
        common.logDebug("firstcode:", firstcode, "lastcode:", lastcode,
                        "tilenum", tilenum)
        hdwc = []
        for i in range(tilenum):
            hdwcstart = f.readSByte()
            hdwcwidth = f.readByte()
            hdwclength = f.readByte()
            hdwc.append((hdwcstart, hdwcwidth, hdwclength))
        # PAMC
        nextoffset = pamcoffset
        while nextoffset != 0x00:
            f.seek(nextoffset)
            firstchar = f.readUShort()
            lastchar = f.readUShort()
            sectiontype = f.readUShort()
            f.seek(2, 1)
            nextoffset = f.readUInt()
            common.logDebug("firstchar:", common.toHex(firstchar), "lastchar:",
                            common.toHex(lastchar), "sectiontype:",
                            sectiontype, "nextoffset:", nextoffset)
            if sectiontype == 0:
                firstcode = f.readUShort()
                for i in range(lastchar - firstchar + 1):
                    c = common.codeToChar(firstchar + i)
                    glyphs[c] = common.FontGlyph(hdwc[firstcode + i][0],
                                                 hdwc[firstcode + i][1],
                                                 hdwc[firstcode + i][2], c,
                                                 firstchar + i, firstcode + i)
            elif sectiontype == 1:
                for i in range(lastchar - firstchar + 1):
                    charcode = f.readUShort()
                    if charcode == 0xFFFF or charcode >= len(hdwc):
                        continue
                    c = common.codeToChar(firstchar + i)
                    glyphs[c] = common.FontGlyph(hdwc[charcode][0],
                                                 hdwc[charcode][1],
                                                 hdwc[charcode][2], c,
                                                 firstchar + i, charcode)
            else:
                common.logWarning("Unknown section type", sectiontype)
    return glyphs
Пример #22
0
def run():
    infolder = "data/extract/data/graphics/"
    outfolder = "data/repack/data/graphics/"
    workfolder = "data/work_IMG/"

    common.logMessage("Repacking KBG from", workfolder, "...")
    files = common.getFiles(infolder, ".kbg")
    for file in common.showProgress(files):
        pngfile = workfolder + file.replace(".kbg", ".png")
        if not os.path.isfile(pngfile):
            continue
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as fin:
            with common.Stream(outfolder + file, "wb") as f:
                palettes, ncgr = game.readKBG(fin)
                fin.seek(0)
                f.write(fin.read(ncgr.tileoffset))
        nitro.writeNCGR(outfolder + file, ncgr, pngfile, palettes)
    common.logMessage("Done!")
Пример #23
0
def extract(f, archive, outfolder):
    for subfile in archive.files:
        with common.Stream(outfolder + subfile.name, "wb") as fout:
            f.seek(archive.dataoff + subfile.offset)
            if not subfile.encoded:
                fout.write(f.read(subfile.length))
            else:
                # Based on Tinke's ARCH implementation
                startpos = f.tell()
                buffer1 = []
                buffer2 = []
                for i in range(0x100):
                    buffer1.append(0)
                    buffer2.append(0)
                while f.tell() - startpos < subfile.length:
                    # InitBuffer
                    for i in range(0x100):
                        buffer2[i] = i
                    # FillBuffer
                    index = 0
                    while index != 0x100:
                        id = f.readByte()
                        numloops = id
                        if id > 0x7F:
                            numloops = 0
                            index += id - 0x7F
                        if index == 0x100:
                            break
                        if numloops < 0:
                            continue
                        for i in range(numloops + 1):
                            byte = f.readByte()
                            buffer2[index] = byte
                            if byte != index:
                                buffer1[index] = f.readByte()
                            index += 1
                    # Process
                    numloops = (f.readByte() << 8) + f.readByte()
                    nextsamples = []
                    while True:
                        if len(nextsamples) == 0:
                            if numloops == 0:
                                break
                            numloops -= 1
                            index = f.readByte()
                        else:
                            index = nextsamples.pop()
                        if buffer2[index] == index:
                            fout.writeByte(index)
                        else:
                            nextsamples.append(buffer1[index])
                            nextsamples.append(buffer2[index])
                            index = len(nextsamples)
Пример #24
0
def repack(no_rom, dat, bin, img, wsb, sub, no_redirect, force):
    all = not sub and not dat and not bin and not img and not wsb
    firstgame = nds.getHeaderID(headerfile) == "YU5J2J"
    if all or dat:
        import repack_dat
        repack_dat.run(firstgame, no_redirect)
    if all or dat or bin:
        import repack_bin
        repack_bin.run(firstgame)
    if all or wsb:
        import repack_wsb
        repack_wsb.run(firstgame)
    if all or dat or sub:
        import repack_sub
        repack_sub.run(firstgame)
    if all or img:
        ncgrfolder = "data/repack/data/graphic/" if firstgame else "data/repack/data/graphics/"
        ncgrfolderin = ncgrfolder.replace("repack", "extract")
        common.copyFolder(ncgrfolderin, ncgrfolder)
        nitro.repackIMG("data/work_IMG/", ncgrfolderin, ncgrfolder, ".NCGR",
                        game.readImage)
        if not firstgame:
            import repack_kbg
            repack_kbg.run()
            # Part of the AP patch
            with common.Stream(ncgrfolder + "doubleinfo/SDLawrence_01.NCGR",
                               "rb+") as f:
                f.seek(0x26f1)
                f.writeByte(0x17)

    if not no_rom:
        if os.path.isdir(replacefolder):
            common.mergeFolder(replacefolder, outfolder)
        if force != "":
            if not force.endswith(".wsb"):
                force += ".wsb"
            if firstgame:
                common.copyFile(
                    outfolder + "data/script/" + force,
                    outfolder + "data/script/event/ev_act/act_010_opening.wsb")
            else:
                common.copyFile(
                    outfolder + "data/script/" + force, outfolder +
                    "data/script/event/ev_main/main_010_prologue.wsb")
        subtitle = "My Year with Holo" if firstgame else "The Wind that Spans the Sea"
        nds.editBannerTitle(
            bannerfile, "Spice & Wolf\n" + subtitle + "\nASCII MEDIA WORKS")
        romf = romfile if os.path.isfile(romfile) else romfile.replace(
            "holo", "holo2")
        romp = rompatch if os.path.isfile(romfile) else rompatch.replace(
            "holo", "holo2")
        nds.repackRom(romf, romp, outfolder, patchfile)
Пример #25
0
def compressLZ10(indata, mindisp=1):
    with common.Stream() as out:
        inlength = len(indata)
        compressedlength = 0
        instart = 0
        # we do need to buffer the output, as the first byte indicates which blocks are compressed.
        # this version does not use a look-ahead, so we do not need to buffer more than 8 blocks at a time.
        outbuffer = bytearray(8 * 2 + 1)
        outbuffer[0] = 0
        bufferlength = 1
        bufferedblocks = 0
        readbytes = 0
        while readbytes < inlength:
            # If 8 blocks are buffered, write them and reset the buffer
            # we can only buffer 8 blocks at a time.
            if bufferedblocks == 8:
                out.write(outbuffer[:bufferlength])
                compressedlength += bufferlength
                # reset the buffer
                outbuffer[0] = 0
                bufferlength = 1
                bufferedblocks = 0
            # determine if we're dealing with a compressed or raw block.
            # it is a compressed block when the next 3 or more bytes can be copied from
            # somewhere in the set of already compressed bytes.
            oldlength = min(readbytes, 0x1000)
            length, disp = getOccurrenceLength(indata, instart + readbytes,
                                               min(inlength - readbytes, 0x12),
                                               instart + readbytes - oldlength,
                                               oldlength, mindisp)
            # length not 3 or more? next byte is raw data
            if length < 3:
                outbuffer[bufferlength] = indata[instart + readbytes]
                bufferlength += 1
                readbytes += 1
            else:
                # 3 or more bytes can be copied? next (length) bytes will be compressed into 2 bytes
                readbytes += length
                # mark the next block as compressed
                outbuffer[0] |= (1 << (7 - bufferedblocks))
                outbuffer[bufferlength] = ((length - 3) << 4) & 0xF0
                outbuffer[bufferlength] |= ((disp - 1) >> 8) & 0x0F
                bufferlength += 1
                outbuffer[bufferlength] = (disp - 1) & 0xFF
                bufferlength += 1
            bufferedblocks += 1
        # copy the remaining blocks to the output
        if bufferedblocks > 0:
            out.write(outbuffer[:bufferlength])
            compressedlength += bufferlength
        out.seek(0)
        return out.read()
Пример #26
0
def editBannerTitle(file, title):
    with common.Stream(file, "r+b") as f:
        for i in range(6):
            # Write new text for all languages
            f.seek(576 + 256 * i)
            for char in title:
                f.writeByte(ord(char))
                f.writeByte(0x00)
            # Compute CRC
            f.seek(32)
            crc = crcmod.predefined.mkCrcFun("modbus")(f.read(2080))
            f.seek(2)
            f.writeUShort(crc)
Пример #27
0
def readGMO(file):
    gmo = GMO()
    with common.Stream(file, "rb") as f:
        f.seek(16 + 4)
        gmo.size = f.readUInt()
        f.seek(8, 1)
        while f.tell() < gmo.size + 16:
            readGMOChunk(f, gmo, gmo.size + 16)
    for gimoffset in gmo.offsets:
        common.logDebug("Reading GIM at", common.toHex(gimoffset))
        gim = readGIM(file, gimoffset)
        gmo.gims.append(gim)
    return gmo
Пример #28
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")
Пример #29
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")
Пример #30
0
def readUTFData(f):
    f.setEndian(True)
    unk1 = f.readInt()
    utfsize = f.readLong()
    # common.logDebug("readUTFData unk1", common.toHex(unk1), "size", common.toHex(utfsize))
    utfpacket = f.read(utfsize)
    encrypted = False
    if utfpacket[:4].decode("ascii", "ignore") != "@UTF":
        utfpacket = decryptUTF(utfpacket)
        encrypted = True
    f.setEndian(False)
    packetstream = common.Stream(little=False).__enter__()
    packetstream.write(utfpacket)
    packetstream.seek(0)
    return packetstream, utfsize, encrypted