import csv, glob, os, sys from pathlib import Path libraries = { } class Function: name = "" isCompleted = False funcSize = 0 def __init__(self, name, isComplete, funcSize): self.name = name self.isCompleted = isComplete self.funcSize = funcSize class Object: name = "" functions = [] totalFunctions = 0 totalCompletedFunctions = 0 def __init__(self, name): self.name = name self.functions = list() self.totalFunctions = 0 self.totalCompletedFunctions = 0 def addFunction(self, function): self.functions.append(function) if function.isCompleted: self.totalCompletedFunctions += 1 self.totalFunctions += 1 def getFunctions(self): return self.functions def calculateProgress(self): fullSize = 0 doneSize = 0 for function in self.functions: fullSize += function.funcSize if function.isCompleted: doneSize += function.funcSize return doneSize, fullSize class Library: name = "" objects = [] def __init__(self, name): self.name = name self.objects = list() def addObject(self, object): self.objects.append(object) def addFunctionToObject(self, obj, function): if self.containsObject(obj.name): self.findObject(obj.name).addFunction(function) else: self.addObject(obj) self.addFunctionToObject(obj, function) def findObject(self, objectName): for obj in self.objects: if obj.name == objectName: return obj return None def getObjects(self): return self.objects def containsObject(self, object): for obj in self.objects: if obj.name == object: return True return False def calculateProgress(self): fullSize = 0 doneSize = 0 for obj in self.objects: d, f = obj.calculateProgress() fullSize += f doneSize += d return doneSize, fullSize def generateMarkdown(self): # first we are going to generate the tables for the object files themselves in the library page = [] page.append(f"# {self.name}\n") page.append("| Object | Percentage (of Bytes) | Functions Done / Total Functions | Percentage (Functions) \n") page.append("| ------------- | ------------- | ------------- | ------------- |\n") for obj in self.objects: d, f = obj.calculateProgress() prog = (d / f) * 100.0 funcProg = (obj.totalCompletedFunctions / obj.totalFunctions) * 100.0 page.append(f"| {obj.name} | {prog}% | {obj.totalCompletedFunctions} / {obj.totalFunctions} | {funcProg}% |\n") page.append("\n\n") # now we can do it per object in the library for obj in self.objects: page.append(f"# {obj.name}\n") page.append("| Symbol | Decompiled? |\n") page.append("| ------------- | ------------- |\n") for func in obj.getFunctions(): marker = ":x:" if func.isCompleted: marker = ":white_check_mark:" funcName = func.name.replace("<", "<") funcName = funcName.replace(">", ">") page.append(f"| {funcName} | {marker} |\n") page.append("\n\n") with open(f"docs/lib/{self.name}.md", "w") as w: w.writelines(page) excludedLibraries = [ "ai.a", "aralt.a", "arc.a", "ax.a", "axfx.a", "base.a", "bte.a", "db.a", "dsp.a", "dvd.a", "esp.a", "euart.a", "exi.a", "fs.a", "gd.a", "gx.a", "ipc.a", "libnw4Fr_ut.a", "libnw4r_db.a", "libnw4r_lyt.a", "libnw4r_math.a", "libnw4r_ut.a", "MSL_C.PPCEABI.bare.H.a", "mem.a", "mtx.a", "nand.a", "net.a", "nwc24.a", "NWC24.a", "os.a", "pad.a", "rso.a", "Runtime.PPCEABI.H.a", "RVLFaceLib.a", "sc.a", "si.a", "thp.a", "tpl.a", "TRK_Hollywood_Revolution.a", "usb.a", "vf.a", "vi.a", "wenc.a", "wpad.a", "wud.a", "JAudio2.a", "JKernel.a", "JSupport.a", "JGadget.a", "JUtility.a", "J2DGraph.a", "J3DGraphBase.a", "J3DGraphAnimator.a", "J3DGraphLoader.a", "JMath.a", "JParticle.a", "NdevExi2A.a" ] func_sizes = {} # start by reading function sizes with open("data/funcSizes.txt", "r") as file: lines = file.readlines() for line in lines: spl = line.split('=') sym = spl[0] func_sizes[sym] = spl[1].split(',', 1)[1] csv_files = glob.glob("csv/*.csv") for csv_file in csv_files: lib_name = Path(csv_file).stem lib_arch_name = Path(csv_file).stem + ".a" # we are just going to ignore non-SMG libraries if lib_arch_name not in excludedLibraries: library = Library(lib_name) with open(csv_file, "r") as c: csv_reader = csv.reader(c) for row in csv_reader: symbol = row[0] symbol = symbol.replace(",", ",") if symbol == "Symbol Name": continue obj = row[1] lib = row[2] done = row[3] == "true" funcSize = int(func_sizes[symbol].strip("\n")) func = Function(symbol, done, funcSize) obj = Object(obj) library.addFunctionToObject(obj, func) libraries[lib_name] = library fullSize = 0 doneSize = 0 print("Calculating percentages...") for key in libraries: lib = libraries[key] d, f = lib.calculateProgress() fullSize += f doneSize += d progPercent = (doneSize / fullSize ) * 100.0 progNonPercent = int((doneSize / fullSize) * 120.0) print(f"Progress: {progPercent}% [{doneSize} / {fullSize}] bytes") print(f"You currently have {progNonPercent} / 120 stars.") print("Generating JSON...") # generate our JSON for the tags on the github page json = [] json.append("{\n") json.append("\t\"schemaVersion\": 1,\n") json.append("\t\"label\": \"decompiled\",\n") json.append(f"\t\"message\": \"{progPercent}%\",\n") json.append("\t\"color\": \"blue\"\n") json.append("}") with open("data/percent.json", "w") as w: w.writelines(json) print("Generating markdown pages...") # now we generate our progress page progressPage = [] progressPage.append("| Library | Percentage |\n") progressPage.append("| ------------- | ------------- |\n") for key in libraries: lib = libraries[key] d, f = lib.calculateProgress() libprog = (d / f) * 100.0 progressPage.append(f"| [{key}](https://github.com/shibbo/Petari/blob/master/docs/lib/{key}.md) | {libprog}% |\n") with open("docs/PROGRESS.md", "w") as w: w.writelines(progressPage) # now we write the progress page for each library for key in libraries: lib = libraries[key] lib.generateMarkdown() print("Done.")