blob: 252d4fda3d4c3e1606057359347bf50978709305 [file] [log] [blame]
Brian Silverman84b22232019-01-25 20:29:29 -08001// Copyright (c) 2006-2013 Thomas Pircher <tehpeh-web@tty1.net>
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21#include "crc.h"
22#include <getopt.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <ctype.h>
26#include <stdbool.h>
27#include <string.h>
28
29static bool atob(const char *str);
30static crc_t xtoi(const char *str);
31static int get_config(int argc, char *argv[], crc_cfg_t *cfg);
32#if CRC_ALGO_BIT_BY_BIT
33static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc);
34static crc_t crc_reflect(crc_t data, size_t data_len);
35#endif
36
37
38
39static bool verbose = false;
40static unsigned char str[256] = "123456789";
41
42bool atob(const char *str)
43{
44 if (!str) {
45 return 0;
46 }
47 if (isdigit(str[0])) {
48 return (bool)atoi(str);
49 }
50 if (tolower(str[0]) == 't') {
51 return true;
52 }
53 return false;
54}
55
56crc_t xtoi(const char *str)
57{
58 crc_t ret = 0;
59
60 if (!str) {
61 return 0;
62 }
63 if (str[0] == '0' && tolower(str[1]) == 'x') {
64 str += 2;
65 while (*str) {
66 if (isdigit(*str))
67 ret = 16 * ret + *str - '0';
68 else if (isxdigit(*str))
69 ret = 16 * ret + tolower(*str) - 'a' + 10;
70 else
71 return ret;
72 str++;
73 }
74 } else if (isdigit(*str)) {
75 while (*str) {
76 if (isdigit(*str))
77 ret = 10 * ret + *str - '0';
78 else
79 return ret;
80 str++;
81 }
82 }
83 return ret;
84}
85
86
87int get_config(int argc, char *argv[], crc_cfg_t *cfg)
88{
89 int c;
90 int option_index;
91 static struct option long_options[] = {
92 {"width", 1, 0, 'w'},
93 {"poly", 1, 0, 'p'},
94 {"reflect-in", 1, 0, 'n'},
95 {"xor-in", 1, 0, 'i'},
96 {"reflect-out", 1, 0, 'u'},
97 {"xor-out", 1, 0, 'o'},
98 {"verbose", 0, 0, 'v'},
99 {"check-string", 1, 0, 's'},
100 {"table-idx-with", 1, 0, 't'},
101 {0, 0, 0, 0}
102 };
103
104 while (1) {
105 option_index = 0;
106
107 c = getopt_long(argc, argv, "w:p:ni:uo:v", long_options, &option_index);
108 if (c == -1)
109 break;
110
111 switch (c) {
112 case 0:
113 printf("option %s", long_options[option_index].name);
114 if (optarg)
115 printf(" with arg %s", optarg);
116 printf ("\n");
117 case 'w':
118 cfg->width = atoi(optarg);
119 break;
120 case 'p':
121 cfg->poly = xtoi(optarg);
122 break;
123 case 'n':
124 cfg->reflect_in = atob(optarg);
125 break;
126 case 'i':
127 cfg->xor_in = xtoi(optarg);
128 break;
129 case 'u':
130 cfg->reflect_out = atob(optarg);
131 break;
132 case 'o':
133 cfg->xor_out = xtoi(optarg);
134 break;
135 case 's':
136 memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));
137 str[sizeof(str) - 1] = '\0';
138 break;
139 case 'v':
140 verbose = true;
141 break;
142 case 't':
143 // ignore --table_idx_width option
144 break;
145 case '?':
146 return -1;
147 case ':':
148 fprintf(stderr, "missing argument to option %c\n", c);
149 return -1;
150 default:
151 fprintf(stderr, "unhandled option %c\n", c);
152 return -1;
153 }
154 }
155 cfg->msb_mask = (crc_t)1u << (cfg->width - 1);
156 cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;
157 cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;
158
159 cfg->poly &= cfg->crc_mask;
160 cfg->xor_in &= cfg->crc_mask;
161 cfg->xor_out &= cfg->crc_mask;
162 return 0;
163}
164
165
166#if CRC_ALGO_BIT_BY_BIT
167crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc)
168{
169 crc_t result;
170 unsigned char data;
171 unsigned int i;
172
173 // don't verify if the width is not a multiple of 8
174 if (cfg->width % 8) {
175 return 0;
176 }
177 if (cfg->xor_out) {
178 crc ^= cfg->xor_out;
179 }
180 if (cfg->reflect_out) {
181 crc = crc_reflect(crc, cfg->width);
182 }
183 result = crc_pre_final;
184 for (i = 0; i < cfg->width / 8; i++) {
185 data = (crc >> (cfg->width - 8 * i - 8)) & 0xff;
186 if (cfg->reflect_in) {
187 data = crc_reflect(data, 8);
188 }
189 result = crc_update(cfg, result, &data, 1);
190 }
191 // no crc_finalize, because if the CRC calculation is correct, result == 0.
192 // A crc_finalize would XOR-in again some ones into the solution.
193 // In theory the finalize function of the bit-by-bit algorithm
194 // would also loop over cfg->width zero bits, but since
195 // a) result == 0, and
196 // b) input data == 0
197 // the output would always be zero
198 return result;
199}
200
201crc_t crc_reflect(crc_t data, size_t data_len)
202{
203 unsigned int i;
204 crc_t ret;
205
206 ret = 0;
207 for (i = 0; i < data_len; i++)
208 {
209 if (data & 0x01) {
210 ret = (ret << 1) | 1;
211 } else {
212 ret = ret << 1;
213 }
214 data >>= 1;
215 }
216 return ret;
217}
218#endif // CRC_ALGO_BIT_BY_BIT
219
220
221int main(int argc, char *argv[])
222{
223 crc_cfg_t cfg = {
224 0, // width
225 0, // poly
226 0, // xor_in
227 0, // reflect_in
228 0, // xor_out
229 0, // reflect_out
230
231 0, // crc_mask
232 0, // msb_mask
233 0, // crc_shift
234 };
235 crc_t crc;
236 crc_t crc_test, crc_pre_final;
237 char format[20];
238 int ret, i;
239
240 ret = get_config(argc, argv, &cfg);
241 if (ret == 0) {
242# if CRC_ALGO_TABLE_DRIVEN
243 crc_table_gen(&cfg);
244# endif // CRC_ALGO_TABLE_DRIVEN
245 crc = crc_init(&cfg);
246 crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str));
247 crc = crc_finalize(&cfg, crc);
248
249# if CRC_ALGO_BIT_BY_BIT
250 if (crc_verify(&cfg, crc_pre_final, crc) != 0) {
251 fprintf(stderr, "error: crc verification failed\n");
252 return 1;
253 }
254# endif
255
256 // calculate the checksum again, but this time loop over the input
257 // bytes one-by-one.
258 crc_test = crc_init(&cfg);
259 for (i = 0; str[i]; i++)
260 {
261 crc_test = crc_update(&cfg, crc_test, str + i, 1);
262 }
263 crc_test = crc_finalize(&cfg, crc_test);
264 if (crc_test != crc) {
265 fprintf(stderr, "error: crc loop verification failed\n");
266 return 1;
267 }
268
269 if (verbose) {
270 snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4);
271 printf("%-16s = %d\n", "width", (unsigned int)cfg.width);
272 printf(format, "poly", (unsigned int)cfg.poly);
273 printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false");
274 printf(format, "xor_in", cfg.xor_in);
275 printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false");
276 printf(format, "xor_out", (unsigned int)cfg.xor_out);
277 printf(format, "crc_mask", (unsigned int)cfg.crc_mask);
278 printf(format, "msb_mask", (unsigned int)cfg.msb_mask);
279 }
280 printf("0x%llx\n", (unsigned long long int)crc);
281 }
282 return !ret;
283}