Skip to content

Instantly share code, notes, and snippets.

@mgrandi
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgrandi/e784f2365ac922b0e248 to your computer and use it in GitHub Desktop.
Save mgrandi/e784f2365ac922b0e248 to your computer and use it in GitHub Desktop.
ratchet_and_clank_nexus_rename_soundfiles.py
#
# script to name audio files from 'ratchet and clank into the nexus' to human readable names
#
# aka resident_sound.dat -> cha_clank_voc_tossspecialb_mdc.dat
#
# Jun 23, 2014 Mark Grandi
#
import argparse, sys, re, os.path, os, shutil
def _readCString(theFile):
''' method that will read a c string given a file and return it'''
# need to read bytes until we get null byte cause this is a null
# terminated c string
stringBuffer = bytearray()
while True:
tmp = theFile.read(1)
if tmp is not None and len(tmp) != 0:
if tmp != b'\x00':
stringBuffer += tmp
else:
# found the null terminator, we are done
return stringBuffer.decode("utf-8")
else:
# end of file?
# print("unexpected end of file.... trying to convert what we have" +
# " to utf-8\n")
return stringBuffer.decode("utf-8")
def renameFiles(args):
'''renames ratchet and clank sound files to have a human readable name
@param args - the namespace object we get from argparse.parse_args()
'''
if args.verbose:
print("Regex is: '{}'".format(args.fileToRenameRegex))
print("Searching directory: '{}'".format(args.inputFolder))
# dirpath is a string, the path to the directory.
# dirnames is a list of the names of the subdirectories in dirpath (excluding '.' and '..').
# filenames is a list of the names of the non-directory files in dirpath.
for dirpath, dirnames, filenames in os.walk(args.inputFolder):
for iterFile in filenames:
curPath = os.path.join(dirpath, iterFile)
if args.fileToRenameRegex.search(iterFile) != None:
if args.verbose:
print("file {} matched, renaming".format(curPath))
name = None
with open(curPath, "rb") as f:
# see if it matches the file we expect
header = f.read(4)
if header != "IGHW".encode("utf-8"):
print("\tFile {} matched regex but its header did not match what we expect! got {} but expected 'IGHW'".format(curPath, header))
continue
# go to byte 256 and read a C string
f.seek(256)
name = _readCString(f)
# now rename it to be the name we got from the file + file extension
outputFile = os.path.join(args.outputFolder, name + os.path.splitext(curPath)[1])
shutil.copyfile(curPath, outputFile)
print("{} renamed to {}".format(curPath, outputFile))
else:
if args.verbose:
print("file {} did not match regex, skipping".format(curPath))
print("done!")
def isDirectoryType(stringArg):
''' helper method for argparse to see if the argument is a directory
@param stringArg - the argument we get from argparse
@return the path if it is indeed a directory, or raises ArgumentTypeError if its not.'''
path = os.path.realpath(os.path.normpath(stringArg))
if not os.path.isdir(path):
raise argparse.ArgumentTypeError("{} is not a directory!".format(path))
return path
def isRegexType(stringArg):
''' helper method for argparse to see if the argument is a valid regex expression
@param stringArg - the argument we get from argparse
@return the compiled RE object if it is indeed a directory, or raises ArgumentTypeError if its not.'''
compiledRe = None
try:
compiledRe = re.compile(stringArg)
except re.error as e:
# not a valid regex expression
raise ArgumentTypeError("{} is not a valid regular expression! error: {}".format(stringArg, e))
return compiledRe
if __name__ == "__main__":
# if we are being run as a real program
parser = argparse.ArgumentParser(description="script to name audio files from 'ratchet and clank into the nexus' to human readable names",
epilog="Copyright Jun 23, 2014 Mark Grandi")
# optional arguments, if specified these are the input and output files, if not specified, it uses stdin and stdout
parser.add_argument('inputFolder', type=isDirectoryType, help="the folder that contains the files to rename")
parser.add_argument("outputFolder", type=isDirectoryType, help="Where to output the resulting files")
parser.add_argument('fileToRenameRegex', type=isRegexType, help="the regex to use to figure out what files to rename, "
"if unsure just type the entire name (like 'resident_sound.dat')")
parser.add_argument("--verbose", action="store_true", help="use this to increase verbosity")
renameFiles(parser.parse_args())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment