blob: 381c7a95a7707d7e0ad3a57a8fe30a79cf26eec2 [file] [log] [blame]
developer6f1fc752022-02-10 17:24:44 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 */
7#include <stdio.h>
8#include <stdarg.h>
9#include <stdint.h>
10#include <stdlib.h>
11#include <stdbool.h>
12#include <string.h>
13#include <ctype.h>
14#include <errno.h>
15#include <getopt.h>
16
17#ifdef _WIN32
18#include <io.h>
19#include <fcntl.h>
20#define SET_BINARY_MODE(_f) _setmode(_fileno(_f, O_BINARY)
21#else
22#define SET_BINARY_MODE(_f) ((void)0)
23#endif
24
25#define CRC32_LE_POLY_DEFAULT 0xedb88320
26#define CRC32_BE_POLY_DEFAULT 0x04c11db7
27#define CRC32_TABLE_ITEMS 256
28
29static uint32_t crc32_le_calc(uint32_t crc, const uint8_t *data, size_t length,
30 const uint32_t *crc_table)
31{
32 while (length--)
33 crc = crc_table[(uint8_t)(crc ^ *data++)] ^ (crc >> 8);
34
35 return crc;
36}
37
38static void crc32_le_init(uint32_t *crc_table, uint32_t poly)
39{
40 uint32_t i, j, v;
41
42 for (i = 0; i < CRC32_TABLE_ITEMS; i++) {
43 v = i;
44
45 for (j = 0; j < 8; j++)
46 v = (v >> 1) ^ ((v & 1) ? poly : 0);
47
48 crc_table[i] = v;
49 }
50}
51
52static uint32_t crc32_be_calc(uint32_t crc, const uint8_t *data, size_t length,
53 const uint32_t *crc_table)
54{
55 while (length--)
56 crc = crc_table[(uint8_t)((crc >> 24) ^ *data++)] ^ (crc << 8);
57
58 return crc;
59}
60
61static void crc32_be_init(uint32_t *crc_table, uint32_t poly)
62{
63 uint32_t i, j, v;
64
65 for (i = 0; i < CRC32_TABLE_ITEMS; i++) {
66 v = i << 24;
67
68 for (j = 0; j < 8; j++)
69 v = (v << 1) ^ ((v & (1 << 31)) ? poly : 0);
70
71 crc_table[i] = v;
72 }
73}
74
75struct crc_funcs {
76 uint32_t poly;
77
78 void (*init)(uint32_t *crc_table, uint32_t poly);
79 uint32_t (*calc)(uint32_t crc, const uint8_t *data, size_t length,
80 const uint32_t *crc_table);
81};
82
83static const struct crc_funcs crc32_le = {
84 .poly = CRC32_LE_POLY_DEFAULT,
85 .init = crc32_le_init,
86 .calc = crc32_le_calc,
87};
88
89static const struct crc_funcs crc32_be = {
90 .poly = CRC32_BE_POLY_DEFAULT,
91 .init = crc32_be_init,
92 .calc = crc32_be_calc,
93};
94
95static const struct crc_funcs *crc32_algo = &crc32_le;
96static uint32_t crc32_poly;
97static uint32_t crc32_val;
98static const char *input_file;
99static bool output_decimal;
100static bool no_comp;
101
102static void err(const char *fmt, ...)
103{
104 va_list ap;
105
106 va_start(ap, fmt);
107 fprintf(stderr, "Error: ");
108 vfprintf(stderr, fmt, ap);
109 va_end(ap);
110}
111
112static void usage(FILE *con, const char *progname, int exitcode)
113{
114 const char *prog;
115 size_t len;
116
117 len = strlen(progname);
118 prog = progname + len - 1;
119
120 while (prog > progname) {
121 if (*prog == '\\' || *prog == '/') {
122 prog++;
123 break;
124 }
125
126 prog--;
127 }
128
129 fprintf(con, "CRC32 checksum tool\n");
130 fprintf(con, "\n");
131 fprintf(con, "Usage: %s [options] <input_file>\n", prog);
132 fprintf(con, "\n");
133 fprintf(con, "Options:\n");
134 fprintf(con, "\t-h display help message\n");
135 fprintf(con, "\t-i <val> crc value for incremental calculation\n");
136 fprintf(con, "\t (default is 0)\n");
137 fprintf(con, "\t-p <val> polynomial for calculation\n");
138 fprintf(con, "\t (default is 0x%08x for LE, 0x%08x for BE)\n",
139 crc32_le.poly, crc32_be.poly);
140 fprintf(con, "\t-b use big-endian mode\n");
141 fprintf(con, "\t-n do not use one's complement\n");
142 fprintf(con, "\t-d use decimal output\n");
143 fprintf(con, "\n");
144
145 exit(exitcode);
146}
147
148static int parse_args(int argc, char *argv[])
149{
150 int opt;
151
152 static const char *optstring = "i:p:bndh";
153
154 opterr = 0;
155
156 while ((opt = getopt(argc, argv, optstring)) >= 0) {
157 switch (opt) {
158 case 'i':
159 if (!isxdigit(optarg[0])) {
160 err("Invalid crc value - %s\n", optarg);
161 return -EINVAL;
162 }
163
164 crc32_val = strtoul(optarg, NULL, 0);
165 break;
166
167 case 'p':
168 if (!isxdigit(optarg[0])) {
169 err("Invalid polynomial value - %s\n", optarg);
170 return -EINVAL;
171 }
172
173 crc32_poly = strtoul(optarg, NULL, 0);
174 break;
175
176 case 'b':
177 crc32_algo = &crc32_be;
178 break;
179
180 case 'n':
181 no_comp = true;
182 break;
183
184 case 'd':
185 output_decimal = true;
186 break;
187
188 case 'h':
189 usage(stdout, argv[0], 0);
190 break;
191
192 default:
193 usage(stderr, argv[0], EXIT_FAILURE);
194 }
195 }
196
197 if (!crc32_poly)
198 crc32_poly = crc32_algo->poly;
199
200 if (optind >= argc)
201 input_file = "-";
202 else
203 input_file = argv[optind];
204
205 if (!input_file[0]) {
206 err("Input file must not be empty\n");
207 return -EINVAL;
208 }
209
210 return 0;
211}
212
213static int crc32_calc(void)
214{
215 uint32_t crc_table[CRC32_TABLE_ITEMS];
216 bool using_stdin = false;
217 uint8_t buf[4096];
218 size_t size;
219 int ret, i;
220 FILE *f;
221
222 if (!strcmp(input_file, "-")) {
223 SET_BINARY_MODE(stdin);
224 using_stdin = true;
225 f = stdin;
226 } else {
227 f = fopen(input_file, "rb");
228 }
229
230 if (!f) {
231 err("Failed to open file '%s'\n", input_file);
232 return -EINVAL;
233 }
234
235 crc32_algo->init(crc_table, crc32_poly);
236
237 if (!no_comp)
238 crc32_val ^= 0xffffffff;
239
240 do {
241 size = fread(buf, 1, sizeof(buf), f);
242
243 if (size) {
244 crc32_val = crc32_algo->calc(crc32_val, buf, size,
245 crc_table);
246 }
247
248 if (size < sizeof(buf)) {
249 ret = ferror(f);
250
251 if (!ret && feof(f))
252 break;
253
254 err("Error while reading file: %d\n", ret);
255 break;
256 }
257 } while (true);
258
259 if (!using_stdin)
260 fclose(f);
261
262 if (ret)
263 return ret;
264
265 if (!no_comp)
266 crc32_val ^= 0xffffffff;
267
268 if (output_decimal)
269 printf("%u\n", crc32_val);
270 else
271 printf("%08x\n", crc32_val);
272
273 return 0;
274}
275
276int main(int argc, char *argv[])
277{
278 if (parse_args(argc, argv))
279 return 1;
280
281 return crc32_calc();
282}