import sys import os from pathlib import Path import struct def addPaddingToFile(file, padding): file.write(bytearray(padding - (file.tell() % padding))) def sortFileList(x): l = [] for c in x: c = ord(c.lower()) if c == ord("_"): l.append(255) else: l.append(c) return l def parseDir(dir, stringTable, currentEntryNum, parent): os.chdir(dir) entries = sorted(os.listdir("./"), key=sortFileList) table = [] for entry in entries: currentEntryNum = currentEntryNum + 1 tableEntry = { "name": entry, "children": None, "size": None, "stringTableOffset": len(stringTable), "entryNum": currentEntryNum, "parent": parent, "path": None, } stringTable = stringTable + entry + "\0" if os.path.isdir(entry): tableEntry["children"], stringTable, currentEntryNum = parseDir( entry, stringTable, currentEntryNum, tableEntry ) else: tableEntry["size"] = os.path.getsize(entry) tableEntry["path"] = os.path.abspath(entry) table.append(tableEntry) os.chdir("..") return table, stringTable, currentEntryNum def recurseWriteFst(files, fstBin, isoFile): for currentFile in files: if currentFile["children"]: # is a directory nextDirEntryNum = 0 testLastEntryFile = currentFile["children"][-1] parentEntryNum = 0 while True: if testLastEntryFile["children"]: testLastEntryFile = testLastEntryFile["children"][-1] else: nextDirEntryNum = testLastEntryFile["entryNum"] + 1 break if currentFile["parent"]: parentEntryNum = currentFile["parent"]["entryNum"] fstBin.append( struct.pack( ">BBHII", 1, (currentFile["stringTableOffset"] >> 16) & 0xFF, currentFile["stringTableOffset"] & 0xFFFF, parentEntryNum, nextDirEntryNum, ) ) recurseWriteFst(currentFile["children"], fstBin, isoFile) else: # is a file fstBin.append( struct.pack( ">BBHII", 0, (currentFile["stringTableOffset"] >> 16) & 0xFF, currentFile["stringTableOffset"] & 0xFFFF, isoFile.tell(), currentFile["size"], ) ) isoFile.write(open(currentFile["path"], "rb").read()) addPaddingToFile(isoFile, 0x100) def packageISO(sourcePath, destPath): print("Converting filesystem into ISO") ISOfile = open(destPath, "wb") # write sys files ISOfile.write(open(sourcePath / "sys/boot.bin", "rb").read()) ISOfile.write(open(sourcePath / "sys/bi2.bin", "rb").read()) ISOfile.write(open(sourcePath / "sys/apploader.img", "rb").read()) addPaddingToFile(ISOfile, 0x100) dolStartPos = ISOfile.tell() ISOfile.seek(0x420) ISOfile.write(struct.pack(">I", dolStartPos)) ISOfile.seek(dolStartPos) ISOfile.write(open(sourcePath / "sys/main.dol", "rb").read()) addPaddingToFile(ISOfile, 0x100) fstStartPos = ISOfile.tell() files, stringTable, entryLength = parseDir(sourcePath / "files", "", 0, None) entryLength = entryLength + 1 ISOfile.seek(0x424) ISOfile.write( struct.pack(">II", fstStartPos, (entryLength * 12) + len(stringTable)) ) # print(stringTable) # print(files) # print(hex(entryLength)) # print(files[0]["entryNum"]) fstBin = [] fstBin.append(struct.pack(">BBHII", 1, 0, 0, 0, entryLength)) ISOfile.seek(fstStartPos + (entryLength * 12) + len(stringTable)) addPaddingToFile(ISOfile, 0x100) recurseWriteFst(files, fstBin, ISOfile) ISOfile.write(bytearray(1459978240 - (ISOfile.tell()))) ISOfile.seek(fstStartPos) for fileEntry in fstBin: ISOfile.write(fileEntry) ISOfile.seek((entryLength * 12) + fstStartPos) ISOfile.write(bytearray(stringTable, "utf8")) if __name__ == "__main__": packageISO(Path(sys.argv[1]), Path(sys.argv[2]))