-
-
Save nutbread/b8111bb93156a20d3bb4 to your computer and use it in GitHub Desktop.
CRC checker in python, with some options for renaming files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os, sys, binascii; | |
version_info = ( 1 , 0 ); | |
# Python 2/3 support | |
if (sys.version_info[0] == 3): | |
# Version 3 | |
def py_2or3_get_cwd(): | |
return os.getcwd(); | |
else: | |
# Version 2 | |
def py_2or3_get_cwd(): | |
return os.getcwdu(); | |
# Argument parser | |
class Arguments: | |
DOUBLE_DASH_STOP = 0x1; | |
STOP_AFTER_FLAGLESS = 0x2; | |
ALLOW_EXTRA_ARGUMENTS = 0x4; | |
class __Arg: | |
STRING = 0; | |
BOOL = 1; | |
ARRAY = 2; | |
def __init__(self, value, type): | |
self.value = value; | |
self.type = type; | |
@classmethod | |
def parse(cls, descriptor, arguments, flagless_order=[], flags=0): | |
# Setup data | |
argument_values = {}; | |
argument_aliases_short = {}; | |
argument_aliases_long = {}; | |
extra_arguments = []; | |
errors = []; | |
for item in descriptor: | |
k = item["name"]; | |
argument_values[k] = cls.__Arg(None, cls.__Arg.STRING); | |
if ("type" in item): | |
if (item["type"] == "bool"): | |
argument_values[k] = cls.__Arg(False, cls.__Arg.BOOL); | |
elif (item["type"] == "array"): | |
argument_values[k] = cls.__Arg([], cls.__Arg.ARRAY); | |
for flag in item["short"]: | |
argument_aliases_short[flag] = k; | |
for flag in item["long"]: | |
argument_aliases_long[flag] = k; | |
# Parse command line | |
flagless_index = 0; | |
flags_parse = True; | |
i = 0; | |
end = len(arguments); | |
arg_map = None; | |
while (i < end): | |
arg = arguments[i]; | |
arg_obj = None; | |
arg_search = None; | |
arg_value_id = i + 1; | |
if (flags_parse and len(arg) > 0 and arg[0] == "-"): | |
# Find argument name/type | |
if (len(arg) > 1 and arg[1] == "-"): | |
arg_name = arg[2 : ]; | |
arg_search = [ arg_name ]; | |
arg_map = argument_aliases_long; | |
else: | |
arg_name = arg[1 : ]; | |
arg_search = arg_name; | |
arg_map = argument_aliases_short; | |
# Blank argument | |
if (len(arg_name) == 0): | |
arg_search = None; | |
if (arg_map is argument_aliases_long and (flags & cls.DOUBLE_DASH_STOP) != 0): | |
# -- disables flag parsing | |
flags_parse = False; | |
else: | |
errors.append("Invalid flag {0:s}".format(arg)); | |
else: | |
if (flagless_index < len(flagless_order)): | |
# Flagless argument | |
arg_search = [ None ]; # Dummy data | |
arg_obj = argument_values[flagless_order[flagless_index]]; | |
arg_value_id = i; | |
if (arg_obj.type != cls.__Arg.ARRAY): flagless_index += 1; | |
else: | |
# Extra argument | |
if ((flags & cls.ALLOW_EXTRA_ARGUMENTS) == 0): | |
errors.append("Invalid argument {0:s}".format(repr(arg))); | |
else: | |
extra_arguments.push(arg); | |
if (arg_search is not None): | |
for j in range(len(arg_search)): | |
# Find object | |
if (arg_obj is None): | |
arg_name = arg_search[j]; | |
if (arg_name not in arg_map): | |
errors.append("Invalid flag {0:s}".format(arg_name)); | |
continue; | |
else: | |
arg_obj = argument_values[arg_map[arg_name]]; | |
if (arg_obj.type == cls.__Arg.BOOL): | |
# Boolean value | |
arg_obj.value = True; | |
else: | |
# Find value | |
if (j + 1 < len(arg_search)): | |
value = arg_search[j + 1 : ]; | |
elif (arg_value_id < end): | |
i = arg_value_id; | |
value = arguments[i]; | |
else: | |
errors.append("Missing value for flag {0:s}".format(arg)); | |
break; | |
# Update value | |
if (arg_obj.type == cls.__Arg.STRING): | |
arg_obj.value = value; | |
else: # if (arg_obj.type == cls.__Arg.ARRAY): | |
arg_obj.value.append(value); | |
# Done looping | |
break; | |
arg_obj = None; | |
# Next | |
i += 1; | |
# Format return | |
for k,v in argument_values.items(): | |
argument_values[k] = v.value; | |
# Return | |
return ( argument_values , errors , extra_arguments , i , flagless_index ); | |
# Usage info | |
def usage(arguments_descriptor, stream): | |
usage_info = [ | |
"Usage:", | |
" {0:s} [flags] <input-filename-1> <input-filename-2> ...".format(os.path.split(sys.argv[0])[1]), | |
"\n", | |
"Available flags:", | |
]; | |
# Flags | |
arg_count = 0; | |
for i in range(len(arguments_descriptor)): | |
arg = arguments_descriptor[i]; | |
if (len(arg["long"]) == 0 and len(arg["short"]) == 0): continue; | |
param_name = ""; | |
param_type = arg["type"] if ("type" in arg) else "string"; | |
if (param_type == "string" or param_type == "array"): | |
if ("argument" in arg): | |
param_name = " <{0:s}>".format(arg["argument"]); | |
else: | |
param_name = " <value>"; | |
if (arg_count > 0): | |
usage_info.append(""); | |
for a in arg["long"]: | |
usage_info.append(" --{0:s}{1:s}".format(a, param_name)); | |
usage_info.append(" {0:s}".format(", ".join([ "-{0:s}{1:s}".format(a, param_name) for a in arg["short"] ]))); | |
if ("description" in arg): | |
usage_info.append(" {0:s}".format(arg["description"])); | |
arg_count += 1; | |
# Output | |
stream.write("{0:s}\n".format("\n".join(usage_info))); | |
# Main | |
def main(): | |
# Command line argument settings | |
arguments_descriptor = [ | |
{ | |
"name": "version", | |
"short": [ "v" ], | |
"long": [ "version" ], | |
"type": "bool", | |
"description": "Show version info and exit", | |
}, | |
{ | |
"name": "help", | |
"short": [ "h" , "?" ], | |
"long": [ "help" , "usage" ], | |
"type": "bool", | |
"description": "Show usage info and exit", | |
}, | |
{ | |
"name": "rename", | |
"short": [ "r" ], | |
"long": [ "rename" ], | |
"type": "bool", | |
"description": "Rename files which include a tag in their name", | |
}, | |
{ | |
"name": "tag", | |
"short": [ "t" ], | |
"long": [ "tag" ], | |
"description": "Specifies the rename tag for filenames. The default is \"CRC\".", | |
}, | |
{ | |
"name": "auto", | |
"short": [ "a" ], | |
"long": [ "auto" ], | |
"type": "bool", | |
"description": "Automatically scan the current directory for any filenames which contain a tag, and apply a CRC check to all of them", | |
}, | |
{ | |
"name": "files", | |
"short": [], | |
"long": [], | |
"type": "array", | |
"description": "List of files", | |
}, | |
]; | |
# Check for special arguments | |
arguments, errors = Arguments.parse(arguments_descriptor, sys.argv[1 : ], [ "files" ])[ : 2]; | |
# Command line parsing errors? | |
if (len(errors) > 0): | |
for e in errors: | |
sys.stderr.write("{0:s}\n".format(e)); | |
return -1; | |
# Version | |
if (arguments["version"]): | |
sys.stdout.write("Version {0:s}\n".format(".".join([ str(v) for v in version_info ]))); | |
return 0; | |
if (arguments["help"]): | |
# Usage info | |
usage(arguments_descriptor, sys.stdout); | |
return 0; | |
# Usage? | |
if (len(arguments["files"]) == 0 and not arguments["auto"]): | |
usage(arguments_descriptor, sys.stderr); | |
return -2; | |
# Vars | |
replace_tag = arguments["tag"]; | |
if (replace_tag is None): replace_tag = "CRC"; | |
# Filenames | |
filenames = []; | |
for f in arguments["files"]: | |
fn_full = os.path.abspath(unicode(f)); | |
filenames.append(( | |
fn_full, # path | |
True, # manually specified | |
)); | |
if (arguments["auto"]): | |
current_path = py_2or3_get_cwd(); | |
files = os.listdir(current_path); | |
for f in files: | |
fn_full = os.path.join(current_path, f); | |
# Check if it has the tag | |
try: | |
f.index(replace_tag); | |
except ValueError: | |
# No tag, skip | |
continue; | |
# Make sure it's a file | |
if (os.path.isfile(fn_full)): | |
# Make sure it doesn't already exist | |
found = False; | |
for file_info in filenames: | |
if (fn_full == file_info[0]): | |
found = True; | |
break; | |
if (not found): | |
filenames.append(( | |
fn_full, # path | |
False, # manually specified | |
)); | |
# Perform hash check | |
ret_code = 0; | |
read_size = 51200; | |
for file_info in filenames: | |
# Open | |
e = None; | |
try: | |
f = open(file_info[0], "rb"); | |
except IOError as e: | |
f = None; | |
if (f is None): | |
# Error | |
sys.stderr.write("Could not open file {0:s}\n".format(repr(file_info[0]))); | |
sys.stdout.write("@INVALID\n"); | |
ret_code = -1; | |
else: | |
# Read | |
crc = 0; | |
while (True): | |
# Read | |
data = f.read(read_size); | |
# End | |
if (len(data) == 0): break; | |
# Continue | |
crc = binascii.crc32(data, crc); | |
# Close | |
f.close(); | |
# Output | |
crc_str = "{0:08X}".format(crc & 0xFFFFFFFF); | |
sys.stdout.write("{0:s}\n".format(crc_str)); | |
# Rename | |
if (arguments["rename"]): | |
path, fn = os.path.split(file_info[0]); | |
fn_new = fn.replace(replace_tag, crc_str); | |
if (fn_new != fn): | |
fn_new = os.path.join(path, fn_new); | |
os.rename(file_info[0], fn_new); | |
# Done | |
return ret_code; | |
# Execute | |
if (__name__ == "__main__"): sys.exit(main()); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment