1 //-----------------------------------------------------------------------------
2 // Low level CRC functions for use by crcmod. This version is the C
3 // implementation that corresponds to the Python module _crcfunpy. This module
4 // will be used by crcmod if it is built for the target platform. Otherwise,
5 // the Python module is used.
6 //
7 // Copyright (c) 2004 Raymond L. Buvel
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to
11 // deal in the Software without restriction, including without limitation the
12 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 // sell copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 // IN THE SOFTWARE.
26 //-----------------------------------------------------------------------------
27
28 // Force Py_ssize_t to be used for s# conversions.
29 #define PY_SSIZE_T_CLEAN
30 #include <Python.h>
31
32 // Make compatible with previous Python versions
33 #if PY_VERSION_HEX < 0x02050000
34 typedef int Py_ssize_t;
35 #define PY_SSIZE_T_MAX INT_MAX
36 #define PY_SSIZE_T_MIN INT_MIN
37 #endif
38
39 // Note: the type declarations are set up to work on 32-bit platforms using the
40 // GNU C compiler. They will need to be adjusted for other platforms. In
41 // particular, the Microsoft Windows compiler uses _int64 instead of long long.
42
43 // Define a few types to make it easier to port to other platforms.
44 typedef unsigned char UINT8;
45 typedef unsigned short UINT16;
46 typedef unsigned int UINT32;
47 typedef unsigned long long UINT64;
48
49 // Define some macros for the data format strings. The INPUT strings are for
50 // decoding the input parameters to the function which are (data, crc, table).
51
52 // Note: these format strings use codes that are new in Python 2.3 so it would
53 // be necessary to rewrite the code for versions earlier than 2.3.
54
55 #define INPUT8 "s#Bs#"
56 #define INPUT16 "s#Hs#"
57 #define INPUT32 "s#Is#"
58 #define INPUT64 "s#Ks#"
59
60 // Define some macros that extract the specified byte from an integral value in
61 // what should be a platform independent manner.
62 #define BYTE0(x) ((UINT8)(x))
63 #define BYTE1(x) ((UINT8)((x) >> 8))
64 #define BYTE2(x) ((UINT8)((x) >> 16))
65 #define BYTE3(x) ((UINT8)((x) >> 24))
66 #define BYTE7(x) ((UINT8)((x) >> 56))
67
68 //-----------------------------------------------------------------------------
69 // Compute a 8-bit crc over the input data.
70 // Inputs:
71 // data - string containing the data
72 // crc - unsigned integer containing the initial crc
73 // table - string containing the 8-bit table corresponding to the generator
74 // polynomial.
75 // Returns:
76 // crc - unsigned integer containing the resulting crc
77
78 static PyObject*
_crc8(PyObject * self,PyObject * args)79 _crc8(PyObject* self, PyObject* args)
80 {
81 UINT8 crc;
82 UINT8* data;
83 Py_ssize_t dataLen;
84 UINT8* table;
85 Py_ssize_t tableLen;
86
87 if (!PyArg_ParseTuple(args, INPUT8, &data, &dataLen, &crc,
88 &table, &tableLen))
89 {
90 return NULL;
91 }
92
93 if (tableLen != 256)
94 {
95 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
96 return NULL;
97 }
98
99 while (dataLen--)
100 {
101 crc = table[*data ^ crc];
102 data++;
103 }
104
105 return PyInt_FromLong((long)crc);
106 }
107
108 //-----------------------------------------------------------------------------
109 // Compute a 8-bit crc over the input data. The data stream is bit reversed
110 // during the computation.
111 // Inputs:
112 // data - string containing the data
113 // crc - unsigned integer containing the initial crc
114 // table - string containing the 8-bit table corresponding to the generator
115 // polynomial.
116 // Returns:
117 // crc - unsigned integer containing the resulting crc
118
119 static PyObject*
_crc8r(PyObject * self,PyObject * args)120 _crc8r(PyObject* self, PyObject* args)
121 {
122 UINT8 crc;
123 UINT8* data;
124 Py_ssize_t dataLen;
125 UINT8* table;
126 Py_ssize_t tableLen;
127
128 if (!PyArg_ParseTuple(args, INPUT8, &data, &dataLen, &crc,
129 &table, &tableLen))
130 {
131 return NULL;
132 }
133
134 if (tableLen != 256)
135 {
136 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
137 return NULL;
138 }
139
140 while (dataLen--)
141 {
142 crc = table[*data ^ crc];
143 data++;
144 }
145
146 return PyInt_FromLong((long)crc);
147 }
148
149 //-----------------------------------------------------------------------------
150 // Compute a 16-bit crc over the input data.
151 // Inputs:
152 // data - string containing the data
153 // crc - unsigned integer containing the initial crc
154 // table - string containing the 16-bit table corresponding to the generator
155 // polynomial.
156 // Returns:
157 // crc - unsigned integer containing the resulting crc
158
159 static PyObject*
_crc16(PyObject * self,PyObject * args)160 _crc16(PyObject* self, PyObject* args)
161 {
162 UINT16 crc;
163 UINT8* data;
164 Py_ssize_t dataLen;
165 UINT16* table;
166 Py_ssize_t tableLen;
167
168 if (!PyArg_ParseTuple(args, INPUT16, &data, &dataLen, &crc,
169 &table, &tableLen))
170 {
171 return NULL;
172 }
173
174 if (tableLen != 256*2)
175 {
176 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
177 return NULL;
178 }
179
180 while (dataLen--)
181 {
182 crc = table[*data ^ BYTE1(crc)] ^ (crc << 8);
183 data++;
184 }
185
186 return PyInt_FromLong((long)crc);
187 }
188
189 //-----------------------------------------------------------------------------
190 // Compute a 16-bit crc over the input data. The data stream is bit reversed
191 // during the computation.
192 // Inputs:
193 // data - string containing the data
194 // crc - unsigned integer containing the initial crc
195 // table - string containing the 16-bit table corresponding to the generator
196 // polynomial.
197 // Returns:
198 // crc - unsigned integer containing the resulting crc
199
200 static PyObject*
_crc16r(PyObject * self,PyObject * args)201 _crc16r(PyObject* self, PyObject* args)
202 {
203 UINT16 crc;
204 UINT8* data;
205 Py_ssize_t dataLen;
206 UINT16* table;
207 Py_ssize_t tableLen;
208
209 if (!PyArg_ParseTuple(args, INPUT16, &data, &dataLen, &crc,
210 &table, &tableLen))
211 {
212 return NULL;
213 }
214
215 if (tableLen != 256*2)
216 {
217 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
218 return NULL;
219 }
220
221 while (dataLen--)
222 {
223 crc = table[*data ^ BYTE0(crc)] ^ (crc >> 8);
224 data++;
225 }
226
227 return PyInt_FromLong((long)crc);
228 }
229
230 //-----------------------------------------------------------------------------
231 // Compute a 24-bit crc over the input data.
232 // Inputs:
233 // data - string containing the data
234 // crc - unsigned integer containing the initial crc
235 // table - string containing the 24-bit table corresponding to the generator
236 // polynomial.
237 // Returns:
238 // crc - unsigned integer containing the resulting crc
239
240 static PyObject*
_crc24(PyObject * self,PyObject * args)241 _crc24(PyObject* self, PyObject* args)
242 {
243 UINT32 crc;
244 UINT8* data;
245 Py_ssize_t dataLen;
246 UINT32* table;
247 Py_ssize_t tableLen;
248
249 if (!PyArg_ParseTuple(args, INPUT32, &data, &dataLen, &crc,
250 &table, &tableLen))
251 {
252 return NULL;
253 }
254
255 if (tableLen != 256*4)
256 {
257 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
258 return NULL;
259 }
260
261 while (dataLen--)
262 {
263 crc = table[*data ^ BYTE2(crc)] ^ (crc << 8);
264 data++;
265 }
266
267 return PyInt_FromLong((long)(crc & 0xFFFFFFU));
268 }
269
270 //-----------------------------------------------------------------------------
271 // Compute a 24-bit crc over the input data. The data stream is bit reversed
272 // during the computation.
273 // Inputs:
274 // data - string containing the data
275 // crc - unsigned integer containing the initial crc
276 // table - string containing the 24-bit table corresponding to the generator
277 // polynomial.
278 // Returns:
279 // crc - unsigned integer containing the resulting crc
280
281 static PyObject*
_crc24r(PyObject * self,PyObject * args)282 _crc24r(PyObject* self, PyObject* args)
283 {
284 UINT32 crc;
285 UINT8* data;
286 Py_ssize_t dataLen;
287 UINT32* table;
288 Py_ssize_t tableLen;
289
290 if (!PyArg_ParseTuple(args, INPUT32, &data, &dataLen, &crc,
291 &table, &tableLen))
292 {
293 return NULL;
294 }
295
296 if (tableLen != 256*4)
297 {
298 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
299 return NULL;
300 }
301
302 crc = crc & 0xFFFFFFU;
303 while (dataLen--)
304 {
305 crc = table[*data ^ BYTE0(crc)] ^ (crc >> 8);
306 data++;
307 }
308
309 return PyInt_FromLong((long)crc);
310 }
311
312 //-----------------------------------------------------------------------------
313 // Compute a 32-bit crc over the input data.
314 // Inputs:
315 // data - string containing the data
316 // crc - unsigned integer containing the initial crc
317 // table - string containing the 32-bit table corresponding to the generator
318 // polynomial.
319 // Returns:
320 // crc - unsigned integer containing the resulting crc
321
322 static PyObject*
_crc32(PyObject * self,PyObject * args)323 _crc32(PyObject* self, PyObject* args)
324 {
325 UINT32 crc;
326 UINT8* data;
327 Py_ssize_t dataLen;
328 UINT32* table;
329 Py_ssize_t tableLen;
330
331 if (!PyArg_ParseTuple(args, INPUT32, &data, &dataLen, &crc,
332 &table, &tableLen))
333 {
334 return NULL;
335 }
336
337 if (tableLen != 256*4)
338 {
339 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
340 return NULL;
341 }
342
343 while (dataLen--)
344 {
345 crc = table[*data ^ BYTE3(crc)] ^ (crc << 8);
346 data++;
347 }
348
349 return PyLong_FromUnsignedLong(crc);
350 }
351
352 //-----------------------------------------------------------------------------
353 // Compute a 32-bit crc over the input data. The data stream is bit reversed
354 // during the computation.
355 // Inputs:
356 // data - string containing the data
357 // crc - unsigned integer containing the initial crc
358 // table - string containing the 32-bit table corresponding to the generator
359 // polynomial.
360 // Returns:
361 // crc - unsigned integer containing the resulting crc
362
363 static PyObject*
_crc32r(PyObject * self,PyObject * args)364 _crc32r(PyObject* self, PyObject* args)
365 {
366 UINT32 crc;
367 UINT8* data;
368 Py_ssize_t dataLen;
369 UINT32* table;
370 Py_ssize_t tableLen;
371
372 if (!PyArg_ParseTuple(args, INPUT32, &data, &dataLen, &crc,
373 &table, &tableLen))
374 {
375 return NULL;
376 }
377
378 if (tableLen != 256*4)
379 {
380 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
381 return NULL;
382 }
383
384 while (dataLen--)
385 {
386 crc = table[*data ^ BYTE0(crc)] ^ (crc >> 8);
387 data++;
388 }
389
390 return PyLong_FromUnsignedLong(crc);
391 }
392
393 //-----------------------------------------------------------------------------
394 // Compute a 64-bit crc over the input data.
395 // Inputs:
396 // data - string containing the data
397 // crc - unsigned integer containing the initial crc
398 // table - string containing the 64-bit table corresponding to the generator
399 // polynomial.
400 // Returns:
401 // crc - unsigned integer containing the resulting crc
402
403 static PyObject*
_crc64(PyObject * self,PyObject * args)404 _crc64(PyObject* self, PyObject* args)
405 {
406 UINT64 crc;
407 UINT8* data;
408 Py_ssize_t dataLen;
409 UINT64* table;
410 Py_ssize_t tableLen;
411
412 if (!PyArg_ParseTuple(args, INPUT64, &data, &dataLen, &crc,
413 &table, &tableLen))
414 {
415 return NULL;
416 }
417
418 if (tableLen != 256*8)
419 {
420 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
421 return NULL;
422 }
423
424 while (dataLen--)
425 {
426 crc = table[*data ^ BYTE7(crc)] ^ (crc << 8);
427 data++;
428 }
429
430 return PyLong_FromUnsignedLongLong(crc);
431 }
432
433 //-----------------------------------------------------------------------------
434 // Compute a 64-bit crc over the input data. The data stream is bit reversed
435 // during the computation.
436 // Inputs:
437 // data - string containing the data
438 // crc - unsigned integer containing the initial crc
439 // table - string containing the 64-bit table corresponding to the generator
440 // polynomial.
441 // Returns:
442 // crc - unsigned integer containing the resulting crc
443
444 static PyObject*
_crc64r(PyObject * self,PyObject * args)445 _crc64r(PyObject* self, PyObject* args)
446 {
447 UINT64 crc;
448 UINT8* data;
449 Py_ssize_t dataLen;
450 UINT64* table;
451 Py_ssize_t tableLen;
452
453 if (!PyArg_ParseTuple(args, INPUT64, &data, &dataLen, &crc,
454 &table, &tableLen))
455 {
456 return NULL;
457 }
458
459 if (tableLen != 256*8)
460 {
461 PyErr_SetString(PyExc_ValueError, "invalid CRC table");
462 return NULL;
463 }
464
465 while (dataLen--)
466 {
467 crc = table[*data ^ BYTE0(crc)] ^ (crc >> 8);
468 data++;
469 }
470
471 return PyLong_FromUnsignedLongLong(crc);
472 }
473
474 //-----------------------------------------------------------------------------
475 static PyMethodDef methodTable[] = {
476 {"_crc8", _crc8, METH_VARARGS},
477 {"_crc8r", _crc8r, METH_VARARGS},
478 {"_crc16", _crc16, METH_VARARGS},
479 {"_crc16r", _crc16r, METH_VARARGS},
480 {"_crc24", _crc24, METH_VARARGS},
481 {"_crc24r", _crc24r, METH_VARARGS},
482 {"_crc32", _crc32, METH_VARARGS},
483 {"_crc32r", _crc32r, METH_VARARGS},
484 {"_crc64", _crc64, METH_VARARGS},
485 {"_crc64r", _crc64r, METH_VARARGS},
486 {NULL, NULL}
487 };
488
489 //-----------------------------------------------------------------------------
init_crcfunext(void)490 void init_crcfunext(void)
491 {
492 PyObject *m;
493
494 if ((sizeof(UINT8) != 1) || (sizeof(UINT16) != 2) ||
495 (sizeof(UINT32) != 4) || (sizeof(UINT64) != 8))
496 {
497 Py_FatalError("crcfunext: One of the data types is invalid");
498 }
499 m = Py_InitModule("_crcfunext", methodTable);
500 }
501
502