This repository has been archived by the owner on Feb 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.c
172 lines (153 loc) · 3.43 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "crc32.c"
#include "args.c"
typedef int bool;
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 4096
#endif
char buff[BUFFER_SIZE];
#define MAX_INPUTS 256
static char *inputs[MAX_INPUTS];
static int input_n = 0;
static uint32_t starting = 0xFFFFFFFF;
static bool big_endian = 0;
static uint32_t polynomial = 0x04C11DB7;
static bool print_binary = 0;
static bool xor_output = 1;
static bool reflect_output = 0;
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\
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': {
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);
}
}
static void
add_input(char *arg)
{
if (input_n >= MAX_INPUTS) {
fprintf(stderr, "Too many inputs specified\n");
exit(1);
}
inputs[input_n++] = arg;
}
static FILE *
open_stream(char *filename)
{
FILE *stream = NULL;
stream = fopen(filename, "rb");
if (stream == NULL) {
perror(filename);
exit(1);
}
return stream;
}
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;
}
static uint32_t
cycle_file(FILE *stream)
{
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));
if (xor_output)
remainder ^= 0xFFFFFFFF;
if (reflect_output)
remainder = crc_reflect(remainder);
return remainder;
}
static void
print_crc(uint32_t remainder)
{
if (print_binary)
fwrite(&remainder, sizeof(remainder), 1, stdout);
else
printf("%08X\n", (int) remainder);
}
int
main(int argc, char **argv)
{
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);
}
return 0;
}