Merge branch 'master' of https://github.com/JoshuaMKW/GeckoLoader
This commit is contained in:
commit
4a8986232d
3 changed files with 0 additions and 590 deletions
BIN
codehandler.bin
BIN
codehandler.bin
Binary file not shown.
215
loader.c
215
loader.c
|
@ -1,215 +0,0 @@
|
|||
/*Credits to riidefi for hook code, cache asm, and teaching me C*/
|
||||
|
||||
#define dcbst(_val) asm volatile("dcbst 0, %0" \
|
||||
: \
|
||||
: "r"(_val))
|
||||
#define dcbf(_val) asm volatile("dcbf 0, %0" \
|
||||
: \
|
||||
: "r"(_val))
|
||||
#define icbi(_val) asm volatile("icbi 0, %0" \
|
||||
: \
|
||||
: "r"(_val))
|
||||
|
||||
#define callFunction(addr) ((void (*)())addr)()
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define NULL 0
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
typedef int s32;
|
||||
typedef short s16;
|
||||
typedef char s8;
|
||||
typedef u32 BOOL;
|
||||
typedef u32 unk32;
|
||||
|
||||
__attribute__((noreturn)) int main();
|
||||
|
||||
enum {
|
||||
MEM1_START = 0x80000000,
|
||||
MEM1_END = 0x81800000,
|
||||
CODEHANDLER_ENTRY = 0x800018A8,
|
||||
GAME_ENTRY = 0xDEADBEEF,
|
||||
GCT_MAGIC = 0x00D0C0DE
|
||||
};
|
||||
|
||||
struct Info {
|
||||
const u32 allocsize;
|
||||
const u32 _loaderSize;
|
||||
const u32 _loaderFullSize;
|
||||
struct CodeList* _codelistPointer;
|
||||
const u32 _wiiVIHook[4];
|
||||
const u32 _gcnVIHook[8];
|
||||
const u32 otherModPointer[4];
|
||||
};
|
||||
|
||||
struct CodeList {
|
||||
u16 mBaseASM;
|
||||
u16 mUpperBase;
|
||||
u16 mOffsetASM;
|
||||
u16 mLowerOffset;
|
||||
};
|
||||
|
||||
struct DiscInfo {
|
||||
const u8 mDiscID;
|
||||
const u16 mGameCode;
|
||||
const u8 mRegionCode;
|
||||
const u16 mMakerCode;
|
||||
const u8 mDiscNumber;
|
||||
const u8 mDiscVersion;
|
||||
const u8 mAudioStreaming;
|
||||
const u8 mStreamBufferSize;
|
||||
const u8 mUnknown[12];
|
||||
const u32 mWiiMagic;
|
||||
const u32 mGCNMagic;
|
||||
const u32 mUnknown2[2];
|
||||
u32 mRAMSize;
|
||||
const u32 mUnknown3[2];
|
||||
u32* mHeapPointer;
|
||||
u32 mHeapMirror;
|
||||
u32 mFstSize;
|
||||
u32 mData[(0x3110 - 0x40) / 4];
|
||||
u32 mWiiHeap;
|
||||
};
|
||||
|
||||
struct Info gInfo = {
|
||||
.allocsize = 0, /*This is the code allocation*/
|
||||
._loaderSize = 0, /*This is the size of the GeckoLoader*/
|
||||
._loaderFullSize = 0, /*This is the size of the GeckoLoader + the codelist*/
|
||||
._codelistPointer = (struct CodeList*)0x800018F8, /*This points to where the codelist address is set in the codehandler*/
|
||||
._wiiVIHook = { 0x7CE33B78, 0x38870034, 0x38A70038, 0x38C7004C },
|
||||
._gcnVIHook = { 0x7C030034, 0x38830020, 0x5485083C, 0x7C7F2A14, 0xA0030000, 0x7C7D2A14, 0x20A4003F, 0xB0030000 },
|
||||
};
|
||||
|
||||
//struct Info* infoPointer = &gInfo;
|
||||
|
||||
static inline void flushAddr(void* addr)
|
||||
{
|
||||
dcbf(addr);
|
||||
icbi(addr);
|
||||
}
|
||||
|
||||
static inline void directWrite(u32* addr, u32 value)
|
||||
{
|
||||
*addr = value;
|
||||
flushAddr(addr);
|
||||
}
|
||||
|
||||
/*This constructs a branch instruction. &TO = ((TO - FROM) & MAX_OFFSET) | BRANCH_TYPE | !!isLink*/
|
||||
static inline void directBranchEx(void* addr, void* ptr, BOOL lk)
|
||||
{
|
||||
directWrite((u32*)(addr), ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!lk));
|
||||
}
|
||||
|
||||
static inline u32* findArrayInstance(u32* start, const u32 end, const u32 arrayLength, const u32* hookData)
|
||||
{
|
||||
u32 index = 0;
|
||||
|
||||
/*Loop through the games RAM, make sure we don't find our own hook data by accident*/
|
||||
for (u32 i = 0; (u32)&start[i] < end; ++i) {
|
||||
/*If the data matches, increase the index counter and continue search,
|
||||
else set index to 0 and continue searching*/
|
||||
if (start[i] == hookData[index])
|
||||
++index;
|
||||
else
|
||||
index = 0;
|
||||
|
||||
/*If the data has matched the whole array, return the address of the match*/
|
||||
if (index >= (arrayLength) && ((u32)&start[i] < (u32)&gInfo || (u32)&start[i] > (u32)&gInfo + sizeof(gInfo))) {
|
||||
return &start[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline u32* findU32Instance(u32* start, u32 end, u32 hookData)
|
||||
{
|
||||
for (u32 i = 0; (u32)&start[i] < end; ++i) {
|
||||
if (start[i] == hookData) {
|
||||
return &start[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Find VI hook for Game*/
|
||||
static inline u32* findVIHook(struct DiscInfo* discResources, struct Info* infoPointer, u32* start, const u32 end)
|
||||
{
|
||||
volatile const u32* hookData;
|
||||
volatile u32 arrayLength;
|
||||
|
||||
/*If the game is built for the Wii, set the hookdata to be the Wii variant*/
|
||||
if (discResources->mWiiMagic) {
|
||||
hookData = (const u32*)infoPointer->_wiiVIHook;
|
||||
arrayLength = sizeof(infoPointer->_wiiVIHook) / sizeof(u32);
|
||||
} else /*The game is built for the GCN, set the hookdata to be the GCN variant*/
|
||||
{
|
||||
hookData = (const u32*)infoPointer->_gcnVIHook;
|
||||
arrayLength = sizeof(infoPointer->_gcnVIHook) / sizeof(u32);
|
||||
}
|
||||
return findArrayInstance(start, end, (const u32)arrayLength, hookData);
|
||||
}
|
||||
|
||||
/*Call this after findFunction, finds the address of the first instance
|
||||
of value hookInstruction, and hooks it to the pointer hookTo*/
|
||||
static inline void hookFunction(volatile u32* start, u32 hookInstruction, u32 hookTo, BOOL isLink)
|
||||
{
|
||||
int i = 0;
|
||||
while (start[i] != hookInstruction) {
|
||||
++i;
|
||||
}
|
||||
directBranchEx((u32*)(&start[i]), (void*)(hookTo), isLink);
|
||||
}
|
||||
|
||||
/*Reallocate the games internal memory heap based on the console
|
||||
the game is for, to make space for our codes*/
|
||||
static inline void setHeap(struct DiscInfo* discResources, u32 alloc)
|
||||
{
|
||||
if (discResources->mWiiMagic) {
|
||||
discResources->mHeapPointer = (u32*)((u32)discResources->mWiiHeap - alloc);
|
||||
discResources->mWiiHeap = (u32)discResources->mHeapPointer;
|
||||
} else {
|
||||
discResources->mHeapPointer = (u32*)((u32)discResources->mHeapPointer - alloc);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memCopy(u32* to, u32* from, s32 size)
|
||||
{
|
||||
for (s32 i = 0; i < size; ++i) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline BOOL initMods(struct DiscInfo* discResources)
|
||||
{
|
||||
setHeap(discResources, gInfo.allocsize); /*Reallocate the internal heap*/
|
||||
s32 sizeDiff = (gInfo._loaderFullSize - gInfo._loaderSize) / 4; /*Calculate size of codelist*/
|
||||
|
||||
/*Copy codelist to the new allocation*/
|
||||
memCopy(discResources->mHeapPointer, findU32Instance((u32*)&gInfo, MEM1_END, GCT_MAGIC), sizeDiff);
|
||||
|
||||
/*Change codelist pointer to the new address in the allocation*/
|
||||
gInfo._codelistPointer->mUpperBase = ((u32)discResources->mHeapPointer >> 16) & 0xFFFF;
|
||||
gInfo._codelistPointer->mLowerOffset = (u32)(discResources->mHeapPointer) & 0xFFFF;
|
||||
|
||||
/*Update the cache, so that the instructions fully update*/
|
||||
flushAddr(&gInfo._codelistPointer->mBaseASM);
|
||||
|
||||
u32* functionAddr = findVIHook(discResources, &gInfo, (u32*)MEM1_START, MEM1_END);
|
||||
if (functionAddr == NULL) return FALSE;
|
||||
hookFunction(functionAddr, 0x4E800020, CODEHANDLER_ENTRY, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct DiscInfo* discResources = (struct DiscInfo*)MEM1_START;
|
||||
if (discResources->mWiiMagic || discResources->mGCNMagic) {
|
||||
if (initMods(discResources) == TRUE) {
|
||||
callFunction(CODEHANDLER_ENTRY); /*Call the codehandler if successful*/
|
||||
}
|
||||
}
|
||||
callFunction(GAME_ENTRY); /*Call the game start*/
|
||||
}
|
375
main.py
375
main.py
|
@ -1,375 +0,0 @@
|
|||
#Written by JoshuaMK 2020
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
try:
|
||||
import argparse
|
||||
import chardet
|
||||
except ImportError as IE:
|
||||
print(IE)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import colorama
|
||||
from colorama import Fore, Style
|
||||
colorama.init()
|
||||
TRESET = Style.RESET_ALL
|
||||
TGREEN = Fore.GREEN
|
||||
TGREENLIT = Style.BRIGHT + Fore.GREEN
|
||||
TYELLOW = Fore.YELLOW
|
||||
TYELLOWLIT = Style.BRIGHT + Fore.YELLOW
|
||||
TRED = Fore.RED
|
||||
TREDLIT = Style.BRIGHT + Fore.RED
|
||||
|
||||
except ImportError:
|
||||
TRESET = ''
|
||||
TGREEN = ''
|
||||
TGREENLIT = ''
|
||||
TYELLOW = ''
|
||||
TYELLOWLIT = ''
|
||||
TRED = ''
|
||||
TREDLIT = ''
|
||||
|
||||
|
||||
|
||||
def resource_path(relative_path):
|
||||
""" Get absolute path to resource, works for dev and for PyInstaller """
|
||||
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
|
||||
return os.path.join(base_path, relative_path)
|
||||
|
||||
def geckoParser(geckoText, parseAll):
|
||||
|
||||
geckoMagic = '00D0C0DE00D0C0DE'
|
||||
geckoTerminate = 'F000000000000000'
|
||||
with open(geckoText, 'rb') as gecko:
|
||||
result = chardet.detect(gecko.read())
|
||||
encodeType = result['encoding']
|
||||
|
||||
with open(geckoText, 'r', encoding=encodeType) as gecko:
|
||||
data = gecko.readlines()
|
||||
geckoCodes = ''
|
||||
|
||||
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)
|
||||
|
||||
geckoLine = ''.join(geckoLine)
|
||||
geckoLine = re.sub(r'\s+', '', geckoLine)
|
||||
geckoCodes = geckoCodes + geckoLine.replace('*', '')
|
||||
|
||||
geckoCodes = geckoMagic + geckoCodes + geckoTerminate
|
||||
geckoSize = '{:08X}'.format(len(bytes.fromhex(geckoCodes))).lstrip('0')
|
||||
|
||||
return [bytes.fromhex(geckoCodes), geckoSize]
|
||||
|
||||
def build(gctFile, dolFile, size, isText):
|
||||
with open(resource_path('geckoloader.bin'), 'rb') as code, open(r'{}'.format(dolFile), 'rb') as dol, open(r'{}'.format(gctFile), 'rb') as gecko, open(resource_path('codehandler.bin'), 'rb') as handler, open('tmp.bin', 'wb+') as tmp, open(os.path.join('BUILD', os.path.basename(dolFile)), 'wb+') as final:
|
||||
|
||||
if int(get_size(dol).hex(), 16) < int('0x100', 16):
|
||||
os.remove('tmp.bin')
|
||||
parser.error('DOL header is corrupted. Please provide a clean file')
|
||||
|
||||
dol.seek(0)
|
||||
|
||||
'''Initialize the new DOL file'''
|
||||
|
||||
final.write(dol.read())
|
||||
|
||||
'''Initialize the sme-code loader'''
|
||||
|
||||
tmp.write(code.read())
|
||||
code.seek(0, 0)
|
||||
tmp.seek(0, 0)
|
||||
|
||||
'''Search for main entry of loader'''
|
||||
|
||||
entryIndex = 0
|
||||
sample = tmp.read(4)
|
||||
while sample:
|
||||
if sample == ENTRY:
|
||||
tmp.seek(-4, 1)
|
||||
tmp.write(bytes.fromhex('7C0802A6'))
|
||||
break
|
||||
entryIndex += 4
|
||||
sample = tmp.read(4)
|
||||
tmp.seek(0)
|
||||
|
||||
'''Get BSS section for insert'''
|
||||
|
||||
final.seek(int('D8', 16))
|
||||
BSS = int(final.read(4).hex(), 16)
|
||||
BSS_length = int(final.read(4).hex(), 16)
|
||||
dump_address = '{:08X}'.format(int(BSS + (BSS_length / 2)))[:-2] + '00'
|
||||
_START = bytes.fromhex('{:08X}'.format(int(dump_address, 16) + entryIndex))
|
||||
cLoader = bytes.fromhex(dump_address)
|
||||
|
||||
'''Get address split for later'''
|
||||
|
||||
upperAddr, lowerAddr = dump_address[:int(len(dump_address)/2)], dump_address[int(len(dump_address)/2):]
|
||||
|
||||
'''Get code initialize address'''
|
||||
|
||||
final.seek(int('E0', 16))
|
||||
_init = [final.read(2), final.read(2)]
|
||||
|
||||
'''Patch the values for the addresses and such'''
|
||||
|
||||
heaped = False
|
||||
sized = False
|
||||
fsized = False
|
||||
|
||||
gUpperAddr = bytes.fromhex(upperAddr)
|
||||
|
||||
if isText == True:
|
||||
geckoCheats = geckoParser(gctFile, args.txtcodes)
|
||||
|
||||
while heaped == False or sized == False or fsized == False:
|
||||
try:
|
||||
sample = tmp.read(4)
|
||||
if sample == HEAP: #Found keyword "HEAP". Goes with the resize of the heap
|
||||
if not heaped:
|
||||
tmp.seek(-4, 1)
|
||||
gInfo = tmp.tell()
|
||||
if int(lowerAddr, 16) + gInfo > int('7FFF', 16): #Absolute addressing
|
||||
gUpperAddr = bytes.fromhex('{:04X}'.format(int(upperAddr, 16) + 1))
|
||||
if size == '0' or size == '':
|
||||
if isText == False:
|
||||
size = get_size(gecko).hex().upper()
|
||||
else:
|
||||
size = geckoCheats[1]
|
||||
tmp.write(bytes.fromhex('{:08X}'.format(int(size, 16))))
|
||||
heaped = True
|
||||
|
||||
elif sample == LOADERSIZE: #Found keyword "LSIZ". Goes with the size of the loader
|
||||
if not sized:
|
||||
tmp.seek(-4, 1)
|
||||
tmp.write(get_size(code))
|
||||
sized = True
|
||||
|
||||
elif sample == FULLSIZE: #Found keyword "FSIZ". Goes with the size of the loader + codes
|
||||
if not fsized:
|
||||
tmp.seek(-4, 1)
|
||||
code.seek(0, 2)
|
||||
gecko.seek(0, 2)
|
||||
if isText == True:
|
||||
tmp.write(get_size(code, int(geckoCheats[1], 16)))
|
||||
else:
|
||||
tmp.write(get_size(code, gecko.tell()))
|
||||
fsized = True
|
||||
except Exception as err:
|
||||
print(err)
|
||||
sys.exit(1)
|
||||
|
||||
'''Patch all load/store offsets to data'''
|
||||
|
||||
tmp.seek(0)
|
||||
sample = tmp.read(2)
|
||||
while sample:
|
||||
if sample == GH:
|
||||
tmp.seek(-2, 1)
|
||||
tmp.write(gUpperAddr)
|
||||
elif sample == GL:
|
||||
tmp.seek(-2, 1)
|
||||
tmp.write(bytes.fromhex('{:04X}'.format(int(lowerAddr, 16) + gInfo)))
|
||||
elif sample == IH:
|
||||
tmp.seek(-2, 1)
|
||||
tmp.write(_init[0])
|
||||
elif sample == IL:
|
||||
tmp.seek(-2, 1)
|
||||
tmp.write(_init[1])
|
||||
sample = tmp.read(2)
|
||||
|
||||
final.seek(0, 2)
|
||||
tmp.seek(0)
|
||||
gecko.seek(0)
|
||||
|
||||
dol_handler_offset = get_size(final)
|
||||
final.write(handler.read())
|
||||
time.sleep(0.01)
|
||||
dol_sme_offset = get_size(final)
|
||||
|
||||
final.write(tmp.read())
|
||||
time.sleep(0.01)
|
||||
|
||||
if isText == False:
|
||||
final.write(gecko.read())
|
||||
else:
|
||||
final.write(geckoCheats[0])
|
||||
final.seek(0, 0)
|
||||
|
||||
status = False
|
||||
i = 0
|
||||
|
||||
while i < 6:
|
||||
textOffset = int(final.read(4).hex(), 16)
|
||||
if textOffset == 0:
|
||||
status = True
|
||||
offset = i * 4
|
||||
|
||||
'''Write offset to each section in DOL file header'''
|
||||
final.seek(-4, 1)
|
||||
final.write(dol_handler_offset)
|
||||
final.write(dol_sme_offset)
|
||||
|
||||
final.seek(int('48', 16) + offset)
|
||||
|
||||
'''Write in game memory addresses for each section in DOL file header'''
|
||||
final.write(bytes.fromhex('80001800'))
|
||||
final.write(cLoader)
|
||||
final.seek(int('E0', 16))
|
||||
|
||||
'''Write game entry in DOL file header'''
|
||||
final.write(_START)
|
||||
|
||||
'''Get size of GeckoLoader + gecko codes, and the codehandler'''
|
||||
handler_size = get_size(handler)
|
||||
|
||||
tmp.seek(0, 2)
|
||||
gecko.seek(0, 2)
|
||||
|
||||
if isText == True:
|
||||
sme_code_size = get_size(tmp, int(geckoCheats[1], 16))
|
||||
else:
|
||||
sme_code_size = get_size(tmp, gecko.tell())
|
||||
|
||||
'''Write size of each section into DOL file header'''
|
||||
final.seek(int('90', 16) + offset)
|
||||
final.write(handler_size)
|
||||
final.write(sme_code_size)
|
||||
break
|
||||
else:
|
||||
i += 1
|
||||
|
||||
if status == False:
|
||||
os.remove('tmp.bin')
|
||||
parser.error(TREDLIT + 'Not enough text sections to patch the DOL file! Potentially due to previous mods?\n' + TRESET)
|
||||
|
||||
if isText == False:
|
||||
if int(size, 16) < int(get_size(gecko).hex(), 16):
|
||||
print(TYELLOW + '\n :: WARNING: Allocated codespace was smaller than the given codelist. The game will crash if run' + TRESET)
|
||||
else:
|
||||
if int(size, 16) < int(geckoCheats[1], 16):
|
||||
print(TYELLOW + '\n :: WARNING: Allocated codespace was smaller than the given codelist. The game will crash if run' + TRESET)
|
||||
|
||||
if args.quiet:
|
||||
return
|
||||
|
||||
if int(size, 16) > int('70000', 16):
|
||||
print(TYELLOW + '\n :: WARNING: Allocations beyond 70000 will crash certain games. You allocated 0x{}'.format(size) + TRESET)
|
||||
|
||||
elif int(size, 16) > int('40000', 16):
|
||||
print(TYELLOWLIT + '\n :: HINT: Recommended allocation limit is 0x40000. You allocated 0x{}'.format(size) + TRESET)
|
||||
|
||||
if isText == False:
|
||||
codelistSize = get_size(gecko).hex().upper().lstrip('0')
|
||||
else:
|
||||
codelistSize = geckoCheats[1]
|
||||
|
||||
if args.verbose >= 2:
|
||||
print('')
|
||||
info = [TGREENLIT + ' :: GeckoLoader set at address 0x{}, start of game modified to address 0x{}'.format(dump_address.upper(), _START.hex().upper()),
|
||||
' :: Game function "_init_registers" located at address 0x{}{}'.format(_init[0].hex(), _init[1].hex().upper()),
|
||||
' :: Code allocation is 0x{}; codelist size is 0x{}'.format(size.upper().lstrip('0'), codelistSize),
|
||||
' :: Of the 7 text sections in this DOL file, {} were already used'.format(i) + TRESET]
|
||||
|
||||
for bit in info:
|
||||
print(bit)
|
||||
|
||||
elif args.verbose >= 1:
|
||||
print('')
|
||||
info = [TGREENLIT + ' :: GeckoLoader set at address 0x{}'.format(dump_address.upper()),
|
||||
' :: Code allocation is 0x{} in hex; codelist size is 0x{}'.format(size.upper().lstrip('0'), codelistSize) + TRESET]
|
||||
|
||||
for bit in info:
|
||||
print(bit)
|
||||
return
|
||||
|
||||
def get_size(file, offset=0):
|
||||
""" Return a file's size in bytes """
|
||||
file.seek(0, 2)
|
||||
return(bytes.fromhex('{:08X}'.format(file.tell() + offset)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
isText = False
|
||||
|
||||
parser = argparse.ArgumentParser(description='Process files and allocations for GeckoLoader')
|
||||
parser.add_argument('file', help='First file')
|
||||
parser.add_argument('file2', help='Second file')
|
||||
parser.add_argument('--alloc', help='Define the size of the code allocation: --alloc hex')
|
||||
parser.add_argument('-tc', '--txtcodes', help='What codes get parsed when a txt file is used.\n"ALL" makes all codes get parsed,\n"ACTIVE" makes only activated codes get parsed.', default='active')
|
||||
parser.add_argument('-q', '--quiet', help='Print nothing to the console', action='store_true')
|
||||
parser.add_argument('-v', '--verbose', help='Print extra info to the console', default=0, action='count')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.alloc:
|
||||
size = args.alloc.lstrip('0x')
|
||||
try:
|
||||
int(size, 16)
|
||||
except:
|
||||
parser.error('The allocation was invalid\n')
|
||||
else:
|
||||
size = '0'
|
||||
|
||||
if os.path.splitext(args.file)[1].lower() == '.dol':
|
||||
dolFile = args.file
|
||||
elif os.path.splitext(args.file2)[1].lower() == '.dol':
|
||||
dolFile = args.file2
|
||||
else:
|
||||
parser.error('No dol file was passed\n')
|
||||
|
||||
if os.path.splitext(args.file)[1].lower() == '.gct':
|
||||
gctFile = args.file
|
||||
isText = False
|
||||
elif os.path.splitext(args.file)[1].lower() == '.txt':
|
||||
gctFile = args.file
|
||||
isText = True
|
||||
elif os.path.splitext(args.file2)[1].lower() == '.gct':
|
||||
gctFile = args.file2
|
||||
isText = False
|
||||
elif os.path.splitext(args.file2)[1].lower() == '.txt':
|
||||
gctFile = args.file2
|
||||
isText = True
|
||||
else:
|
||||
parser.error('Neither a gct or gecko text file was passed\n')
|
||||
|
||||
time1 = time.time()
|
||||
|
||||
HEAP = bytes.fromhex('48454150')
|
||||
LOADERSIZE = bytes.fromhex('4C53495A')
|
||||
FULLSIZE = bytes.fromhex('4653495A')
|
||||
ENTRY = bytes.fromhex('454E5452')
|
||||
GH = bytes.fromhex('4748')
|
||||
GL = bytes.fromhex('474C')
|
||||
IH = bytes.fromhex('4948')
|
||||
IL = bytes.fromhex('494C')
|
||||
MODFIELD = [bytes.fromhex('BBBBBBBB'), bytes.fromhex('CCCCCCCC'), bytes.fromhex('DDDDDDDD'), bytes.fromhex('EEEEEEEE')]
|
||||
|
||||
try:
|
||||
if not os.path.isdir('BUILD'):
|
||||
os.mkdir('BUILD')
|
||||
|
||||
if not os.path.isfile(dolFile):
|
||||
parser.error(dolFile + ' Does not exist')
|
||||
|
||||
if not os.path.isfile(gctFile):
|
||||
parser.error(gctFile + ' Does not exist')
|
||||
|
||||
build(gctFile, dolFile, size, isText)
|
||||
|
||||
os.remove('tmp.bin')
|
||||
if not args.quiet:
|
||||
print('\n :: Compiled in {:0.4f} seconds!\n'.format(time.time() - time1))
|
||||
|
||||
except FileNotFoundError as err:
|
||||
parser.error(err)
|
||||
sys.exit(1)
|
Reference in a new issue