small crc32 calculator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
3.4 KiB

11 years ago
#include <stdio.h>
#include <stdlib.h>
8 years ago
#include <stdint.h>
#include "crc32.c"
#include "args.c"
11 years ago
8 years ago
typedef int bool;
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 4096
#endif
char buff[BUFFER_SIZE];
#define MAX_INPUTS 256
11 years ago
static char *inputs[MAX_INPUTS];
static int input_n = 0;
8 years ago
static uint32_t starting = 0xFFFFFFFF;
8 years ago
static bool big_endian = 0;
8 years ago
static uint32_t polynomial = 0x04C11DB7;
8 years ago
static bool print_binary = 0;
static bool xor_output = 1;
static bool reflect_output = 0;
11 years ago
8 years ago
static const char help[] = "\
crc32 - a 32-bit cyclic rendundancy check calculator\n\
\n\
<files...> open files as inputs\n\
-h display this text\n\
-s <n> start cycle with n (default: 0xFFFFFFFF)\n\
-p <n> use n as the crc divisor (default: 0x04C11DB7)\n\
-e use big endian calculations\n\
-b output as binary\n\
-x NOT the output\n\
-r reverse output's bits\n\
\n\
8 years ago
numbers <n> may be in hexadecimal or octal using proper prefixes\n\
";
static char
*check_next(char flag, char *next) {
if (!next) {
fprintf(stderr, "-%c requires another argument\n", flag);
exit(1);
}
return next;
}
static void
handle_flag(char flag, char *(*nextarg)())
{
char *next;
switch (flag) {
case 'h': {
8 years ago
printf(help);
} exit(0);
case 'e': {
big_endian = 1;
} break;
case 'b': {
print_binary = 1;
} break;
case 'x': {
xor_output = 0;
} break;
case 'r': {
reflect_output = 1;
} break;
case 's': {
next = check_next(flag, nextarg());
starting = strtoul(next, NULL, 0);
} break;
case 'p': {
next = check_next(flag, nextarg());
polynomial = strtoul(next, NULL, 0);
} break;
default: {
fprintf(stderr, "Unknown flag: -%c\n", flag);
} exit(1);
}
11 years ago
}
static void
add_input(char *arg)
11 years ago
{
if (input_n >= MAX_INPUTS) {
fprintf(stderr, "Too many inputs specified\n");
11 years ago
exit(1);
}
inputs[input_n++] = arg;
11 years ago
}
static FILE *
open_stream(char *filename)
11 years ago
{
FILE *stream = NULL;
stream = fopen(filename, "rb");
if (stream == NULL) {
perror(filename);
exit(1);
}
return stream;
11 years ago
}
static inline size_t
buff_read(FILE *stream)
{
size_t len = fread(buff, 1, BUFFER_SIZE, stream);
if (ferror(stream)) {
perror(NULL);
exit(1);
}
return len;
}
8 years ago
static uint32_t
cycle_file(FILE *stream)
11 years ago
{
8 years ago
uint32_t remainder = starting;
uint32_t table[CRC_TABLE_SIZE];
if (big_endian)
crc_be_fill_table(table, polynomial);
else
crc_le_fill_table(table, polynomial);
// cast len to int to enable potential signedness optimizations.
// this is safe so long as BUFFER_SIZE can fit in an int.
if (big_endian) do {
int len = (int) buff_read(stream);
for (int i = 0; i < len; i++)
crc_be_cycle(table, &remainder, buff[i]);
} while (!feof(stream)); else do {
int len = (int) buff_read(stream);
for (int i = 0; i < len; i++)
crc_le_cycle(table, &remainder, buff[i]);
} while (!feof(stream));
11 years ago
if (xor_output)
remainder ^= 0xFFFFFFFF;
if (reflect_output)
remainder = crc_reflect(remainder);
return remainder;
11 years ago
}
static void
8 years ago
print_crc(uint32_t remainder)
11 years ago
{
if (print_binary)
fwrite(&remainder, sizeof(remainder), 1, stdout);
else
printf("%08X\n", (int) remainder);
}
int
main(int argc, char **argv)
11 years ago
{
args_parse(argc, argv, handle_flag, add_input);
if (!input_n) {
freopen(NULL, "rb", stdin);
print_crc(cycle_file(stdin));
}
for (int i = 0; i < input_n; i++) {
FILE *stream = open_stream(inputs[i]);
print_crc(cycle_file(stream));
fclose(stream);
}
11 years ago
return 0;
}