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