commit 133ed9188aec054c4c9543e489e02d4a26ade045 Author: Connor Olding Date: Fri Apr 13 02:43:39 2012 -0700 init diff --git a/args.h b/args.h new file mode 100644 index 0000000..b181d83 --- /dev/null +++ b/args.h @@ -0,0 +1,131 @@ +/* args.h - argument handling + Copyright (C) 2012 Connor Olding + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef ARGS_H_ +#define ARGS_H_ + +#include +#include + +/* interface */ + +extern char args_info[]; +extern char args_usage[]; +extern char args_help_suffix[]; + +extern const int args_count; +extern char* args_args[]; +extern void (*args_functions[])(); + +void args_handle(int argc, char* argv[]); +char* args_poll(); +void args_print_help(); + +/* implemenation */ + +static const int args_columns = 3; + +static char* args_program_name = NULL; + +static int args_argc = 0; +static char** args_argv = NULL; + +static int args_current = 0; +static int args_previous = 0; + +static void args_print_info() +{ + printf(args_info); +} + +static void args_print_usage() +{ + printf(args_usage, args_program_name); +} + +static void args_print_args() +{ + int i; + for (i = 0; i < args_count * args_columns; i += args_columns) { + printf(" %s, %s %s\n", + args_args[i], args_args[i + 1], args_args[i + 2]); + } + printf(args_help_suffix); +} + +void args_print_help() +{ + args_print_info(); + puts(""); + args_print_args(); + exit(0); +} + +static int args_get_index(char* name) +{ + int i; + for (i = 0; i < args_count * args_columns; i++) { + if (i % args_columns == args_columns - 1) + continue; /* skip checking the description column */ + if (!strcmp(args_args[i], name)) { + return i / args_columns; + } + } + return -1; +} + +char* args_poll() +{ + if (args_current >= args_argc) { + if (args_current - 1 == args_previous) + fprintf(stderr, "%s requires an argument.\n", + args_argv[args_previous]); + else + fprintf(stderr, "%s requires another argument.\n", + args_argv[args_previous]); + args_print_usage(); + exit(1); + } + args_current++; + return args_argv[args_current - 1]; +} + +void args_handle(int argc, char** argv) +{ + args_argc = argc; + args_argv = argv; + + args_current = 0; + args_program_name = args_poll(); + + while (args_current < args_argc) { + char* name; + int index; + + args_previous = args_current; + name = args_poll(); + index = args_get_index(name); + if (index < 0) { + fprintf(stderr, "Unknown option: %s\n", name); + args_print_usage(); + exit(1); + } + args_functions[index](); + } +} + +#endif diff --git a/crc32.h b/crc32.h new file mode 100644 index 0000000..0ebf912 --- /dev/null +++ b/crc32.h @@ -0,0 +1,161 @@ +/* crc32.h - 32-bit cyclic redundancy check calcuations + Copyright (C) 2012 Connor Olding + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef CRC32_H_ +#define CRC32_H_ + +#include + +/* interface */ + +typedef unsigned long uint32; + +void crc_cycle(uint32 *remainder, char c); +uint32 crc_reflect(uint32 input); + +void crc_set_big_endian(); +void crc_set_little_endian(); +void crc_set_polynomial(uint32 p); + +/* implementation */ + +static char crc_big_endian = 0; +static const int crc_table_size = 0x100; +static uint32* crc_be_table = NULL; /* big endian */ +static uint32* crc_le_table = NULL; /* little endian */ +static uint32 crc_polynomial = 0x04C11DB7; + +uint32 crc_reflect(uint32 input) +{ + uint32 reflected = 0; + unsigned int i; + for (i = 0; i < sizeof(uint32) * 8; i++) { + reflected <<= 1; + reflected |= input & 1; + input >>= 1; + } + return reflected; +} + +static uint32* crc_alloc(size_t size) +{ + uint32* p = (uint32*) malloc(size * sizeof(uint32)); + if (p == NULL) + exit(1); + return p; +} + +static void crc_allocate_tables_once() +{ + static char allocated = 0; + if (crc_big_endian && !(allocated & 1)) { + crc_be_table = crc_alloc(crc_table_size); + allocated |= 1; + } else if (!crc_big_endian && !(allocated & 2)) { + crc_le_table = crc_alloc(crc_table_size); + allocated |= 2; + } +} + +static void crc_fill_big_endian_table() +{ + const uint32 least_significant_bit = 1 << 31; + int c, i; + + crc_allocate_tables_once(); + + for (c = 0; c < crc_table_size; c++) { + crc_be_table[c] = c << 24; + for (i = 0; i < 8; i++) { + if (crc_be_table[c] & least_significant_bit) { + crc_be_table[c] <<= 1; + crc_be_table[c] ^= crc_polynomial; + } else { + crc_be_table[c] <<= 1; + } + } + } +} + +static void crc_fill_little_endian_table() +{ + const uint32 least_significant_bit = 1; + const uint32 reflected_polynomial = crc_reflect(crc_polynomial); + int c, i; + + crc_allocate_tables_once(); + /* printf("p: %08X\n", (int)reflected_polynomial); */ + + for (c = 0; c < crc_table_size; c++) { + crc_le_table[c] = c; + for (i = 0; i < 8; i++) { + if (crc_le_table[c] & least_significant_bit) { + crc_le_table[c] >>= 1; + crc_le_table[c] ^= reflected_polynomial; + } else { + crc_le_table[c] >>= 1; + } + } + } +} + +static void crc_fill_tables_once() +{ + static char filled = 0; + if (crc_big_endian && !(filled & 1)) { + crc_fill_big_endian_table(); + filled |= 1; + } else if (!crc_big_endian && !(filled & 2)) { + crc_fill_little_endian_table(); + filled |= 2; + } +} + +void crc_set_big_endian() +{ + crc_big_endian = 1; +} + +void crc_set_little_endian() +{ + crc_big_endian = 0; +} + +void crc_set_polynomial(uint32 p) +{ + crc_polynomial = p; +} + +void crc_cycle(uint32 *remainder, char c) +{ + crc_fill_tables_once(); + if (crc_big_endian) { + const uint32 newByte = crc_be_table[ + ((*remainder) >> 24) ^ c]; + /* printf("%08X00 ^ %08X =\n", + (int)(*remainder), (int)newByte); */ + *remainder = ((*remainder) << 8) ^ newByte; + } else { + const uint32 newByte = crc_le_table[ + ((*remainder) ^ c) & 0xFF]; + /* printf(" %08X ^ %08X =\n", + (int)((*remainder) >> 8), (int)newByte); */ + *remainder = ((*remainder) >> 8) ^ newByte; + } +} + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..62f8ad2 --- /dev/null +++ b/main.c @@ -0,0 +1,151 @@ +/* crc32 - 32-bit cyclic redundancy check calculator + Copyright (C) 2012 Connor Olding + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include + +#include "crc32.h" +#include "args.h" + +#ifdef _MSC_VER + #define FREOPEN_BLANK ("") +#else + #define FREOPEN_BLANK (NULL) +#endif + +static uint32 remainder = 0xFFFFFFFF; + +static FILE* input_stream = NULL; +static char* input_name = "-"; +static char print_binary = 0; +static char xor_output = 1; +static char reflect_output = 0; + +char args_info[] = "crc32 - 32-bit cyclic redundancy check calculator\n"; +char args_usage[] = "Usage: %s [-i f] [-s n] [-p n] [-e] [-x] [-r] [-b]\n"; +char args_help_suffix[] = "\n\ +numbers (n) can be entered as hexadecimal or octal with prefixes\n"; + +const int args_count = 8; + +char* args_args[] = { +"-h","--help"," display this text", +"-i","--input","f open file f for reading (default: stdin)", +"-s","--start-at","n start cycle with n (default: 0xFFFFFFFF)", +"-p","--polynomial","n use n for crc calculations (default: 0x04C11DB7)", +"-e","--big-endian"," use big endian calculations (default: little)", +"-b","--binary"," output as binary (default: hex with newline)", +"-x","--xor"," xor the output by 0xFFFFFFFF", +"-r","--reflect"," reverse the bits of the output", +}; + +void start_at() +{ + remainder = strtoul(args_poll(), NULL, 0); +} + +void set_input() +{ + input_name = args_poll(); +} + +void set_polynomial() +{ + const int p = strtoul(args_poll(), NULL, 0); + crc_set_polynomial(p); +} + +void set_big_endian() +{ + crc_set_big_endian(); +} + +void set_binary() +{ + print_binary = 1; +} + +void set_xor() +{ + xor_output = 0; +} + +void set_reflect() +{ + reflect_output = 1; +} + +void (*args_functions[])() = + {args_print_help, set_input, start_at, set_polynomial, + set_big_endian, set_binary, set_xor, set_reflect}; + +static void open_stream() +{ + const char mode[] = "rb"; + if (!strcmp(input_name, "-")) { + freopen(FREOPEN_BLANK, mode, stdin); + input_stream = stdin; + } else { + input_stream = fopen(input_name, mode); + } + if (input_stream == NULL) { + fprintf(stderr, "Could not open file for reading: %s\n", + input_name); + exit(1); + } +} + +static void close_stream() +{ + fclose(input_stream); +} + +static void cycle_input() +{ + int c; + open_stream(); + while ((c = getc(input_stream)) != EOF) { + crc_cycle(&remainder, c); + } + close_stream(); + + if (xor_output) + remainder ^= 0xFFFFFFFF; + if (reflect_output) + remainder = crc_reflect(remainder); + /* if remainder has unnecessary bits from + left shifting, remove them + remainder &= 0xFFFFFFFF; + */ +} + +static void print_crc() +{ + if (print_binary) + fwrite(&remainder, sizeof(remainder), 1, stdout); + else + printf("%08X\n", (int) remainder); +} + +int main(int argc, char** argv) +{ + crc_set_little_endian(); + args_handle(argc, argv); + cycle_input(); + print_crc(); + return 0; +}