def ls(isoFile, directory=b"/", columns=None, size=False): with gciso.IsoFile(isoFile) as iso: files = list(iso.listDir(directory)) if directory[-1] != b"/": directory += b"/" maxNameLen = 0 for file in files: nameLen = len(file) if size: nameLen += len(" ({})".format(iso.fileSize(directory + file))) maxNameLen = max(maxNameLen, nameLen) colWidth = maxNameLen + 5 # 3 spaces and b'' if columns == None: columns = int(100 / colWidth) # assume 100 characters width colFmt = "{{!s:<{}}}".format(colWidth) for i in range(0, len(files), columns): printCols = min(columns, len(files) - i) fmt = colFmt * printCols params = files[i:i + printCols] if size: params = map( lambda x: "{!s} ({})".format(x, iso.fileSize(directory + x) ), params) print(fmt.format(*params))
def read(isoFile, internalFile, dstFile, offset=0, length=None, banner=False): with gciso.IsoFile(isoFile) as iso: if banner: banner = iso.getBannerFile(internalFile) banner.getPILImage().save(dstFile) else: with open(dstFile, "wb") as dst: dst.write(iso.readFile(internalFile, offset, length))
def isoInfo(isoFile): with gciso.IsoFile(isoFile) as iso: print("Game Code:", iso.gameCode) print("Maker Code:", iso.makerCode) print("Disk Id:", iso.diskId) print("Version:", iso.version) print("Game Name:", iso.gameName) print() print("DOL offset:", _h(iso.dolOffset)) print("DOL size:", _h(iso.dolSize)) print("FST offset:", _h(iso.fstOffset)) print("FST Size:", _h(iso.fstSize)) print("Max FST Size:", _h(iso.maxFstSize)) print("FST Entries:", _h(iso.numFstEntries)) print() print("Apploader Date:", iso.apploaderDate) print("Apploader Entry Point:", _h(iso.apploaderEntryPoint)) print("Apploader Code Size:", _h(iso.apploaderCodeSize)) print("Apploader Trailer Size:", _h(iso.apploaderTrailerSize))
def bannerInfo(file, fileName=b"opening.bnr"): if file.endswith(".iso"): with gciso.IsoFile(file) as iso: banner = iso.getBannerFile(fileName) elif file.endswith(".bnr"): with open(file, "rb") as bannerFile: banner = gciso.BannerFile(bannerFile.read()) else: quit("File extension must be .bnr or .iso!") print("Magic Bytes:", banner.magicBytes) metas = banner.meta if isinstance(metas, gciso.BannerFile.MetaData): metas = [metas] for i, meta in enumerate(metas): print("\nMetadata {}:".format(i)) print("Game Name:", meta.gameName) print("Developer Name:", meta.developerName) print("Full Game Title:", meta.fullGameTitle) print("Full Developer Name:", meta.fullDeveloperName) print("Game Description:", meta.gameDescription)
def dolInfo(file, fileName=b"start.dol", order=None): if file.endswith(".iso"): with gciso.IsoFile(file) as iso: dol = iso.getDolFile(fileName) elif file.endswith(".dol"): with open(file, "rb") as dolFile: dol = gciso.DolFile(dolFile.read()) else: quit("File extension must be .bnr or .iso!") print("BSS Memory Address: 0x{:x}".format(dol.bssMemAddress)) print("BSS Size: 0x{:x}".format(dol.bssSize)) print("Entry Point: 0x{:x}".format(dol.entryPoint)) if order == None: order = SectionOrder.FILE assert isinstance(order, SectionOrder) if order == SectionOrder.FILE: sections = dol.sections elif order == SectionOrder.DOL_OFFSET: sections = dol.sectionsDolOrder elif order == SectionOrder.MEM_ADDRESS: sections = dol.sectionsMemOrder print("\nSections:") for i, section in enumerate(sections): print( "{} {} - DOL: {:>8} to {:>8}, Memory: 0x{:x} to 0x{:x} (size: 0x{:x})" .format(section.type.value, section.index, _h(section.dolOffset), _h(section.endDolOffset), section.memAddress, section.endMemAddress, section.size)) if i + 1 < len(sections): if order == SectionOrder.DOL_OFFSET: gap = sections[i + 1].dolOffset - section.endDolOffset if gap > 0: print("Gap (DOL): 0x{:x}".format(gap)) if order == SectionOrder.MEM_ADDRESS: gap = sections[i + 1].memAddress - section.endMemAddress if gap > 0: print("Gap (memory): 0x{:x}".format(gap))
gciso = None parser = argparse.ArgumentParser( description="Apply patch data to .dat file or .iso file.") parser.add_argument("patchfile", help="The patch json file.") parser.add_argument("targetfile", help="The .dat/.iso file to apply the patch to.") args = parser.parse_args() with open(args.patchfile) as f: patchData = json.load(f) if args.targetfile.lower().endswith(".iso"): if not gciso: quit("The gciso module must be installed to patch .iso files!") with gciso.IsoFile(args.targetfile) as isoFile: for file in patchData: filePatch = patchData[file] for i in range(0, len(filePatch), 2): offset, data = filePatch[i + 0], filePatch[i + 1] data = bytes.fromhex(data) isoFile.writeFile(file.encode("ascii"), offset, data) elif args.targetfile.lower().endswith(".dat"): fileBase = os.path.basename(args.targetfile) if fileBase not in patchData: quit("No patch data for '{}'!".format(fileBase)) filePatch = patchData[fileBase] with open(args.targetfile, "r+b") as f: for i in range(0, len(filePatch), 2): offset, data = filePatch[i + 0], filePatch[i + 1] data = bytes.fromhex(data)
def write(isoFile, internalFile, srcFile, offset=0, banner=False): if banner: raise NotImplementedError("Writing banners is not implemented yet!") with gciso.IsoFile(isoFile) as iso, open(srcFile, "rb") as src: iso.writeFile(internalFile, offset, srcFile.read())
def setUp(self): self.isoFile = gciso.IsoFile(ISO_PATH)