From dfb7115b281cf0f691b623ed6fbc8b3e7d924fe2 Mon Sep 17 00:00:00 2001 From: JoshuaMKW <60854312+JoshuaMKW@users.noreply.github.com> Date: Wed, 22 Jul 2020 00:32:25 -0500 Subject: [PATCH] Added dolphin style txt compatibility, improved tmp folder logic --- GeckoLoader.py | 94 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/GeckoLoader.py b/GeckoLoader.py index 6dacb59..913481b 100644 --- a/GeckoLoader.py +++ b/GeckoLoader.py @@ -5,8 +5,8 @@ import os import time import re import shutil -import glob import dolreader +import random from io import BytesIO, RawIOBase @@ -118,28 +118,41 @@ class CodeHandler(object): encodeType = result['encoding'] with open(r'{}'.format(geckoText), 'r', encoding=encodeType) as gecko: - data = gecko.readlines() geckoCodes = '' + state = None - for line in data: - if parseAll.lower() == 'all': - geckoLine = re.findall(r'[A-F0-9]{8}\s[A-F0-9]{8}', line, re.IGNORECASE) - elif parseAll.lower() == 'active': - geckoLine = re.findall(r'\*\s[A-F0-9]{8}\s[A-F0-9]{8}', line, re.IGNORECASE) - else: - geckoLine = re.findall(r'\*\s[A-F0-9]{8}\s[A-F0-9]{8}', line, re.IGNORECASE) + for line in gecko.readlines(): + if line in ('', '\n'): + continue - geckoLine = ''.join(geckoLine) - geckoLine = re.sub(r'\s+', '', geckoLine) - geckoCodes = geckoCodes + geckoLine.replace('*', '') + if state is None: + if line.startswith('$'): + state = 'Dolphin' + else: + state = 'OcarinaM' + + try: + if state == 'OcarinaM': + if parseAll.lower() == 'all': + geckoLine = re.findall(r'[A-F0-9]{8}[\t\f ][A-F0-9]{8}', line, re.IGNORECASE)[0] + elif parseAll.lower() == 'active': + geckoLine = re.findall(r'(?:\*\s*)([A-F0-9]{8}[\t\f ][A-F0-9]{8})', line, re.IGNORECASE)[0] + else: + geckoLine = re.findall(r'(?:\*\s*)([A-F0-9]{8}[\t\f ][A-F0-9]{8})', line, re.IGNORECASE)[0] + else: + geckoLine = re.findall(r'(? 0x80002FFF: - patchGeckoLoader(code, codehandler, tmp, dolfile, dump_address) + status = patchGeckoLoader(code, codehandler, tmp, dolfile, dump_address) legacy = False else: codehandler.allocation = 0x80003000 - (codehandler.initaddress + codehandler.handlerlength) - patchLegacyHandler(codehandler, tmp, dolfile) + status = patchLegacyHandler(codehandler, tmp, dolfile) legacy = True + if status is False: + shutil.rmtree(tmpdir) + parser.error(TREDLIT + 'Not enough text sections to patch the DOL file! Potentially due to previous mods?\n' + TRESET) + dolfile.save(final) if codehandler.allocation < codehandler.geckocodes.size: @@ -274,7 +293,6 @@ def build(gctFile, dolFile, codehandlerFile, allocation: int, codehook: int): for bit in info: print(bit) - return def determineCodeLength(codetype, info): if codetype.startswith(b'\x06'): @@ -429,11 +447,16 @@ def patchGeckoLoader(fLoader, codehandler: CodeHandler, tmp, dolfile: dolreader. dolfile._rawdata.write(tmp.read()) dolfile.align(256) - assertTextSections(dolfile, 6, [[int(entrypoint, 16), geckoloader_offset]]) + status = assertTextSections(dolfile, 6, [[int(entrypoint, 16), geckoloader_offset]]) + + if status is False: + return False '''Write game entry in DOL file header''' dolfile.setInitPoint(int(entrypoint, 16)) + return True + def patchLegacyHandler(codehandler: CodeHandler, tmp, dolfile: dolreader.DolFile): handler_offset = dolfile.getsize() @@ -444,9 +467,15 @@ def patchLegacyHandler(codehandler: CodeHandler, tmp, dolfile: dolreader.DolFile dolfile._rawdata.write(codehandler.codehandler.read() + codehandler.geckocodes.codelist.read()) dolfile.align(256) - assertTextSections(dolfile, 6, [[codehandler.initaddress, handler_offset]]) + status = assertTextSections(dolfile, 6, [[codehandler.initaddress, handler_offset]]) + + if status is False: + return False + determineCodeHook(dolfile, codehandler) + return True + def assertTextSections(dolfile: dolreader.DolFile, textsections: int, sections_list: list): offset = len(dolfile._text) << 2 if len(sections_list) + len(dolfile._text) <= 7: @@ -473,9 +502,10 @@ def assertTextSections(dolfile: dolreader.DolFile, textsections: int, sections_l dolfile._rawdata.seek(0x90 + offset) for size in size_list: dolfile._rawdata.write(bytes.fromhex('{:08X}'.format(size))) + + return True else: - shutil.rmtree('tmp') - parser.error(TREDLIT + 'Not enough text sections to patch the DOL file! Potentially due to previous mods?\n' + TRESET) + return False def figureLoaderData(tmp, fLoader, codehandler: CodeHandler, dolfile: dolreader.DolFile, entrypoint: str, initpoint: list): upperAddr, lowerAddr = entrypoint[:int(len(entrypoint)/2)], entrypoint[int(len(entrypoint)/2):] @@ -612,9 +642,6 @@ def sortArgFiles(fileA, fileB): return dolFile, gctFile if __name__ == "__main__": - if not os.path.isdir('tmp'): - os.mkdir('tmp') - parser = argparse.ArgumentParser(prog='GeckoLoader', description='Process files and allocations for GeckoLoader', allow_abbrev=False) @@ -707,10 +734,15 @@ if __name__ == "__main__": parser.error('File/folder "' + gctFile + '" does not exist') time1 = time.time() + + tmpdir = ''.join(random.choice('1234567890-_abcdefghijklomnpqrstuvwxyz') for i in range(6)) + '-GeckoLoader' + + if not os.path.isdir(tmpdir): + os.mkdir(tmpdir) - build(gctFile, dolFile, codehandlerFile, _allocation, _codehook) + build(gctFile, dolFile, codehandlerFile, tmpdir, _allocation, _codehook) - shutil.rmtree('tmp') + shutil.rmtree(tmpdir) if not args.quiet: print(TGREENLIT + '\n :: Compiled in {:0.4f} seconds!\n'.format(time.time() - time1) + TRESET)