Home | History | Annotate | Download | only in src
      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*
     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*
    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*
    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*
    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*
    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*
    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*
    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*
    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*
    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*
    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 //-----------------------------------------------------------------------------
    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