Create a gist now

Instantly share code, notes, and snippets.

@nutbread /crc.py Secret
Created Nov 10, 2014

Embed
What would you like to do?
CRC checker in python, with some options for renaming files
#!/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