#!/usr/bin/env python3 import os import argparse AudioFunctions = {} Verbose = False Verbose2 = False def set_verbose(v): global Verbose global Verbose2 Verbose = v Verbose2 = v return 1 def make_audio_dict(AudioFunctions, repo): with open(repo + os.sep + 'include' + os.sep + 'functions.h','r') as funcfile: funcdata = funcfile.readlines() for i, line in enumerate(funcdata): if(line.count('sfxId')): funcname, argnum = get_func_data(funcdata,i) if(funcname != None): AudioFunctions[funcname] = argnum return 1 def get_func_data(funcdata,i): j = i while(funcdata[j - 1].count(';') == 0): j -= 1 k = i + 1 while(funcdata[k - 1].count(';') == 0): k += 1 prototype = "".join(funcdata[j:k]) argdata = prototype.replace('(',',').replace(')',',').split(',') funcname = argdata[0].split(' ')[1] for x in range(len(argdata)): if(argdata[x].count('sfxId')): break; if(x == len(argdata) - 1): print('sfxId not found in ', funcname) return None,-1 return funcname, x - 1 def lookup_sfx(idnum, repo): if(type(idnum) is int): id = '0x' + format(idnum,'X') elif(idnum.isnumeric()): id = '0x' + format(int(idnum),'X') else: id = idnum idfix,sfxFlag = fix_sfx_flag(id) with open(repo + os.sep + 'include' + os.sep + 'sfx.h','r') as sfxfile: for line in sfxfile: if(line.count(idfix)): return line.split(' ')[1] + sfxFlag return 'INVALID_ID' def fix_sfx_flag(id): if(id.endswith(' - SFX_FLAG')): splitdata = id.split('-') return splitdata[0].strip(), ' -' + splitdata[1] if not(int(id,16) & 0x800): newid = '0x' + format(int(id,16) + 0x800,'X') sfxFlag = ' - SFX_FLAG' else : newid = id sfxFlag = '' return newid,sfxFlag def fix_sfx_func(sourcedata, i, j, repo): data = ''.join(sourcedata[i:j]) func = data.split('(')[0].strip() index = data.find(func) argnum = AudioFunctions.get(func,-1) if(argnum == -1 or index == -1): print('Function lookup error at line', i, 'in', func) return -1 args = data[index:].replace('(',',').replace(')',',').split(',') sfxId = args[argnum + 1].strip() if(sfxId.count('NA_SE') != 0): return 0 newId = lookup_sfx(sfxId, repo) if(newId == 'INVALID_ID'): print('ID parse error at line', i, 'in', func) return -2 for k in range(i, j): sourcedata[k] = sourcedata[k].replace(sfxId,newId) if Verbose: print('Replaced', sfxId, 'with', newId, 'in', func, 'at line', i + 1) return 1 def find_audio_func(line): audiofuncs = list(AudioFunctions.keys()) funcname = line.split('(')[0].strip() for func in audiofuncs: if(line.count(func)): return func return False def fix_sfx_all(repo): global Verbose2 tv = Verbose2 Verbose2 = False for subdir, dirs, files in os.walk(repo + os.sep + 'src'): for filename in files: if(filename.endswith('.c')): file = subdir + os.sep + filename fix_sfx(file, repo) Verbose2 = tv return 1 def fix_sfx(file, repo, outfile = None): if(outfile == None): outfile = file make_audio_dict(AudioFunctions, repo) with open(file,'r',encoding='utf-8') as sourcefile: sourcedata = sourcefile.readlines() replacements = set() j = 0 lookuperrors = 0 funcerrors = 0 iderrors = 0 fixes = 0 for i, line in enumerate(sourcedata): if(i < j): continue if(find_audio_func(line)): j = i while(sourcedata[j].count(';') == 0): j += 1 status = fix_sfx_func(sourcedata, i, j + 1, repo) if(status == -2): iderrors += 1 elif(status == -1): lookuperrors += 1 elif(status > 0): fixes += 1 if(fixes > 0): with open(outfile,'w',encoding ='utf-8',newline='\n') as outfile: outfile.writelines(sourcedata) if Verbose: print(file, 'updated') elif Verbose2: print('No changes made to', file) if(lookuperrors > 0): print('Problem with function lookup. Try formatting functions.h') if(iderrors > 0): print('Problem with id parsing. Make sure your SFX ids are in hex.') return 1 parser = argparse.ArgumentParser(description='Convert hex SFX ids to macros') parser.add_argument('file', help="source file to be processed") parser.add_argument('repo', help="directory of the decomp repo") parser.add_argument('-o', metavar='outfile',dest='outfile',help='file to write to instead of original') parser.add_argument('-v', action='store_true',help='show what changes are made') if __name__ == "__main__": args = parser.parse_args() set_verbose(args.v) fix_sfx(args.file, args.repo, outfile=args.outfile)