Squashed 'third_party/pycrc/' content from commit cb91196b9
Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/pycrc/__init__.py b/pycrc/__init__.py
new file mode 100644
index 0000000..e0749e4
--- /dev/null
+++ b/pycrc/__init__.py
@@ -0,0 +1,3 @@
+progname = "pycrc"
+version = "0.9.1"
+url = 'https://pycrc.org'
diff --git a/pycrc/__main__.py b/pycrc/__main__.py
new file mode 100644
index 0000000..cefc3bb
--- /dev/null
+++ b/pycrc/__main__.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+from pycrc.main import main
+import sys
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/pycrc/algorithms.py b/pycrc/algorithms.py
new file mode 100644
index 0000000..3ebcebd
--- /dev/null
+++ b/pycrc/algorithms.py
@@ -0,0 +1,235 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+CRC algorithms implemented in Python.
+If you want to study the Python implementation of the CRC routines, then this
+is a good place to start from.
+
+The algorithms Bit by Bit, Bit by Bit Fast and Table-Driven are implemented.
+
+This module can also be used as a library from within Python.
+
+Examples
+========
+
+This is an example use of the different algorithms:
+
+ from pycrc.algorithms import Crc
+
+ crc = Crc(width = 16, poly = 0x8005,
+ reflect_in = True, xor_in = 0x0000,
+ reflect_out = True, xor_out = 0x0000)
+ print("{0:#x}".format(crc.bit_by_bit("123456789")))
+ print("{0:#x}".format(crc.bit_by_bit_fast("123456789")))
+ print("{0:#x}".format(crc.table_driven("123456789")))
+"""
+
+class Crc(object):
+ """
+ A base class for CRC routines.
+ """
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self, width, poly, reflect_in, xor_in, reflect_out, xor_out, table_idx_width=None, slice_by=1):
+ """The Crc constructor.
+
+ The parameters are as follows:
+ width
+ poly
+ reflect_in
+ xor_in
+ reflect_out
+ xor_out
+ """
+ # pylint: disable=too-many-arguments
+
+ self.width = width
+ self.poly = poly
+ self.reflect_in = reflect_in
+ self.xor_in = xor_in
+ self.reflect_out = reflect_out
+ self.xor_out = xor_out
+ self.tbl_idx_width = table_idx_width
+ self.slice_by = slice_by
+
+ self.msb_mask = 0x1 << (self.width - 1)
+ self.mask = ((self.msb_mask - 1) << 1) | 1
+ if self.tbl_idx_width != None:
+ self.tbl_width = 1 << self.tbl_idx_width
+ else:
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << self.tbl_idx_width
+
+ self.direct_init = self.xor_in
+ self.nondirect_init = self.__get_nondirect_init(self.xor_in)
+ if self.width < 8:
+ self.crc_shift = 8 - self.width
+ else:
+ self.crc_shift = 0
+
+
+ def __get_nondirect_init(self, init):
+ """
+ return the non-direct init if the direct algorithm has been selected.
+ """
+ crc = init
+ for dummy_i in range(self.width):
+ bit = crc & 0x01
+ if bit:
+ crc ^= self.poly
+ crc >>= 1
+ if bit:
+ crc |= self.msb_mask
+ return crc & self.mask
+
+
+ def reflect(self, data, width):
+ """
+ reflect a data word, i.e. reverts the bit order.
+ """
+ # pylint: disable=no-self-use
+
+ res = data & 0x01
+ for dummy_i in range(width - 1):
+ data >>= 1
+ res = (res << 1) | (data & 0x01)
+ return res
+
+
+ def bit_by_bit(self, in_data):
+ """
+ Classic simple and slow CRC implementation. This function iterates bit
+ by bit over the augmented input message and returns the calculated CRC
+ value at the end.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ reg = self.nondirect_init
+ for octet in in_data:
+ if self.reflect_in:
+ octet = self.reflect(octet, 8)
+ for i in range(8):
+ topbit = reg & self.msb_mask
+ reg = ((reg << 1) & self.mask) | ((octet >> (7 - i)) & 0x01)
+ if topbit:
+ reg ^= self.poly
+
+ for i in range(self.width):
+ topbit = reg & self.msb_mask
+ reg = ((reg << 1) & self.mask)
+ if topbit:
+ reg ^= self.poly
+
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return (reg ^ self.xor_out) & self.mask
+
+
+ def bit_by_bit_fast(self, in_data):
+ """
+ This is a slightly modified version of the bit-by-bit algorithm: it
+ does not need to loop over the augmented bits, i.e. the Width 0-bits
+ wich are appended to the input message in the bit-by-bit algorithm.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ reg = self.direct_init
+ for octet in in_data:
+ if self.reflect_in:
+ octet = self.reflect(octet, 8)
+ for i in range(8):
+ topbit = reg & self.msb_mask
+ if octet & (0x80 >> i):
+ topbit ^= self.msb_mask
+ reg <<= 1
+ if topbit:
+ reg ^= self.poly
+ reg &= self.mask
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return reg ^ self.xor_out
+
+
+ def gen_table(self):
+ """
+ This function generates the CRC table used for the table_driven CRC
+ algorithm. The Python version cannot handle tables of an index width
+ other than 8. See the generated C code for tables with different sizes
+ instead.
+ """
+ table_length = 1 << self.tbl_idx_width
+ tbl = [[0 for i in range(table_length)] for j in range(self.slice_by)]
+ for i in range(table_length):
+ reg = i
+ if self.reflect_in:
+ reg = self.reflect(reg, self.tbl_idx_width)
+ reg = reg << (self.width - self.tbl_idx_width + self.crc_shift)
+ for dummy_j in range(self.tbl_idx_width):
+ if reg & (self.msb_mask << self.crc_shift) != 0:
+ reg = (reg << 1) ^ (self.poly << self.crc_shift)
+ else:
+ reg = (reg << 1)
+ if self.reflect_in:
+ reg = self.reflect(reg >> self.crc_shift, self.width) << self.crc_shift
+ tbl[0][i] = (reg >> self.crc_shift) & self.mask
+
+ for j in range(1, self.slice_by):
+ for i in range(table_length):
+ tbl[j][i] = (tbl[j - 1][i] >> 8) ^ tbl[0][tbl[j - 1][i] & 0xff]
+ return tbl
+
+
+ def table_driven(self, in_data):
+ """
+ The Standard table_driven CRC algorithm.
+ """
+ # pylint: disable = line-too-long
+
+ # If the input data is a string, convert to bytes.
+ if isinstance(in_data, str):
+ in_data = bytearray(in_data, 'utf-8')
+
+ tbl = self.gen_table()
+
+ if not self.reflect_in:
+ reg = self.direct_init << self.crc_shift
+ for octet in in_data:
+ tblidx = ((reg >> (self.width - self.tbl_idx_width + self.crc_shift)) ^ octet) & 0xff
+ reg = ((reg << (self.tbl_idx_width - self.crc_shift)) ^ (tbl[0][tblidx] << self.crc_shift)) & (self.mask << self.crc_shift)
+ reg = reg >> self.crc_shift
+ else:
+ reg = self.reflect(self.direct_init, self.width)
+ for octet in in_data:
+ tblidx = (reg ^ octet) & 0xff
+ reg = ((reg >> self.tbl_idx_width) ^ tbl[0][tblidx]) & self.mask
+ reg = self.reflect(reg, self.width) & self.mask
+
+ if self.reflect_out:
+ reg = self.reflect(reg, self.width)
+ return reg ^ self.xor_out
+
diff --git a/pycrc/codegen.py b/pycrc/codegen.py
new file mode 100644
index 0000000..4079cc0
--- /dev/null
+++ b/pycrc/codegen.py
@@ -0,0 +1,1559 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+use as follows:
+
+ import pycrc.codegen as cg
+ import pycrc.opt as opt
+ opt = opt.Options()
+ print(cg.CodeGen(opt, '', [
+ 'if (a == b) {',
+ cg.CodeGen(opt, 4*' ', ['print("a equals b\\n");']),
+ '}',
+ ]))
+"""
+
+import pycrc.symtable
+import pycrc.expr as expr
+
+
+class CodeGen(object):
+ """
+ The symbol table class.
+ """
+ def __init__(self, opt, indent, content = []):
+ """
+ The class constructor.
+ """
+ self.opt = opt
+ self.sym = pycrc.symtable.SymbolTable(opt)
+ self.indent = indent
+ self.content = content
+
+ def gen(self, indent = ''):
+ """
+ Return an array of strings.
+ """
+ out = []
+ if self.indent is None:
+ indent = ''
+ else:
+ indent += self.indent
+ for item in self.content:
+ if isinstance(item, str):
+ out.append(indent + item)
+ else:
+ out += item.gen(indent)
+ return out
+
+ def __str__(self):
+ """
+ Stringify the object.
+ """
+ return '\n'.join([l.rstrip() for l in self.gen()])
+
+
+class Conditional(CodeGen):
+ """
+ A conditional block of code.
+ """
+ def __init__(self, opt, indent, condition, content):
+ """
+ The class constructor.
+ """
+ super(Conditional, self).__init__(opt, indent)
+ if condition:
+ self.content = content
+
+
+class Conditional2(CodeGen):
+ """
+ A conditional block of code with an else block.
+ """
+ def __init__(self, opt, indent, condition, content_true, content_false):
+ """
+ The class constructor.
+ """
+ super(Conditional2, self).__init__(opt, indent)
+ if condition:
+ self.content = content_true
+ else:
+ self.content = content_false
+
+
+class Comment(CodeGen):
+ """
+ A comment wrapper.
+ """
+ def __init__(self, opt, indent, content):
+ """
+ The class constructor.
+ """
+ super(Comment, self).__init__(opt, indent)
+ self.content = [
+ '/**',
+ CodeGen(opt, indent + ' * ', content),
+ ' */'
+ ]
+
+
+class ParamBlock(CodeGen):
+ """
+ Print the parameters of the model.
+ """
+ def __init__(self, opt, indent, algorithm = False):
+ """
+ The class constructor.
+ """
+ super(ParamBlock, self).__init__(opt, indent)
+ self.content = [
+ '- {0:13s} = {1}'.format('Width', self.sym['crc_width']),
+ '- {0:13s} = {1}'.format('Poly', self.sym['crc_poly']),
+ '- {0:13s} = {1}'.format('XorIn', self.sym['crc_xor_in']),
+ '- {0:13s} = {1}'.format('ReflectIn', self.sym['crc_reflect_in']),
+ '- {0:13s} = {1}'.format('XorOut', self.sym['crc_xor_out']),
+ '- {0:13s} = {1}'.format('ReflectOut', self.sym['crc_reflect_out']),
+ Conditional(opt, '', algorithm,
+ ['- {0:13s} = {1}'.format('Algorithm', self.sym['crc_algorithm'])]),
+ Conditional(opt, '', opt.slice_by > 1,
+ ['- {0:13s} = {1}'.format('SliceBy', opt.slice_by)]),
+ ]
+
+
+
+class File(CodeGen):
+ """
+ Generate the file output.
+ """
+ def __init__(self, opt, indent):
+ """
+ The class constructor.
+ """
+ super(File, self).__init__(opt, indent)
+ self.content = [
+ Comment(opt, '', [
+ '\\file',
+ 'Functions and types for CRC checks.',
+ '',
+ 'Generated on {datetime}'.format(**self.sym),
+ 'by {program_version}, {program_url}'.format(**self.sym),
+ 'using the configuration:',
+ ParamBlock(opt, ' ', algorithm = True),
+ Conditional(opt, '', opt.action == opt.action_generate_h, [
+ '',
+ 'This file defines the functions {crc_init_function}(), ' \
+ '{crc_update_function}() and {crc_finalize_function}().'.format(**self.sym),
+ '',
+ 'The {crc_init_function}() function returns the inital \c crc value and must be called'.format(**self.sym),
+ 'before the first call to {crc_update_function}().'.format(**self.sym),
+ 'Similarly, the {crc_finalize_function}() function must be called after the last call'.format(**self.sym),
+ 'to {crc_update_function}(), before the \c crc is being used.'.format(**self.sym),
+ 'is being used.',
+ '',
+ 'The {crc_update_function}() function can be called any number of times (including zero'.format(**self.sym),
+ 'times) in between the {crc_init_function}() and {crc_finalize_function}() calls.'.format(**self.sym),
+ '',
+ 'This pseudo-code shows an example usage of the API:',
+ '\code{.c}',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '{cfg_t} cfg = '.format(**self.sym) + '{',
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '0, // width',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None, [
+ '0, // poly',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+ '0, // reflect_in',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+ '0, // xor_in',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+ '0, // reflect_out',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+ '0, // xor_out',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '0, // crc_mask',
+ '0, // msb_mask',
+ '0, // crc_shift',
+ ]),
+ '};',
+ ]),
+ '{crc_t} crc;'.format(**self.sym),
+ 'unsigned char data[MAX_DATA_LEN];',
+ 'size_t data_len;',
+ '',
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+ ]),
+ 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+ 'while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {',
+ CodeGen(self.opt, 4*' ', [
+ 'crc = {0}({1}crc, data, data_len);'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+ ]),
+ '}',
+ 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+ '\endcode',
+ ]),
+ ]),
+ ]
+ if opt.action == opt.action_generate_h:
+ self.content += self._header_file()
+ elif opt.action == opt.action_generate_c:
+ self.content += self._c_file()
+ elif opt.action == opt.action_generate_c_main:
+ self.content += self._c_file() + self._main_file()
+
+ def _header_file(self):
+ """
+ Add header content.
+ """
+ out = [
+ '#ifndef {header_protection}'.format(**self.sym),
+ '#define {header_protection}'.format(**self.sym),
+ '',
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include <stdlib.h>',
+ Conditional(self.opt, '', self.opt.c_std != 'C89',
+ ['#include <stdint.h>']),
+ Conditional(self.opt, '', _use_cfg(self.opt) and self.opt.c_std != 'C89',
+ ['#include <stdbool.h>']),
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ '', '',
+ Comment(self.opt, '', [
+ 'The definition of the used algorithm.',
+ '',
+ 'This is not used anywhere in the generated code, but it may be used by the',
+ 'application code to call algorithm-specific code, if desired.',
+ ]),
+ '#define {0} 1'.format(_crc_algo_define(self.opt, self.sym)),
+ '', '',
+ Comment(self.opt, self.indent, [
+ 'The type of the CRC values.',
+ '',
+ 'This type must be big enough to contain at least {cfg_width} bits.'.format(**self.sym),
+ ]),
+ 'typedef {underlying_crc_t} {crc_t};'.format(**self.sym),
+ Conditional(self.opt, '', _use_cfg(self.opt), [
+ '', '',
+ Comment(self.opt, self.indent, ['The configuration type of the CRC algorithm.']),
+ 'typedef struct {',
+ Conditional(self.opt, 4*' ', self.opt.width is None,
+ ['{0:24s} {1}'.format('unsigned int width;',
+ '/*!< The width of the polynomial */')]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' poly;',
+ '/*!< The CRC polynomial */')]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None,
+ ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_in;',
+ '/*!< Whether the input shall be reflected or not */')]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_in;',
+ '/*!< The initial value of the register */')]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None,
+ ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_out;',
+ '/*!< Whether the output shall be reflected or not */')]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None,
+ ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_out;',
+ '/*!< The value which shall be XOR-ed to the final CRC value */')]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '/* internal parameters */',
+ '{0:24s} {1}'.format(self.sym['crc_t'] + ' msb_mask;', '/*!< a bitmask with the Most Significant Bit set to 1'),
+ 33*' ' + 'initialise as (crc_t)1u << (width - 1) */',
+ '{0:24s} {1}'.format(self.sym['crc_t'] + ' crc_mask;', '/*!< a bitmask with all width bits set to 1'),
+ 33*' ' + 'initialise as (cfg->msb_mask - 1) | cfg->msb_mask */',
+ '{0:24s} {1}'.format('unsigned int crc_shift;', '/*!< a shift count that is used when width < 8'),
+ 33*' ' + 'initialise as cfg->width < 8 ? 8 - cfg->width : 0 */',
+ ]),
+ '}} {cfg_t};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', _use_reflect_func(self.opt) and not _use_static_reflect_func(self.opt), [
+ '', '',
+ Comment(self.opt, '', [
+ 'Reflect all bits of a \\a data word of \\a data_len bytes.',
+ '',
+ '\\param[in] data The data word to be reflected.',
+ '\\param[in] data_len The width of \\a data expressed in number of bits.',
+ '\\return The reflected data.'
+ ]),
+ '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '', '',
+ Comment(self.opt, '', [
+ 'Populate the private static crc table.',
+ '',
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ 'void {crc_table_gen_function}(const {cfg_t} *cfg);'.format(**self.sym),
+ ]),
+ '', '',
+ Comment(self.opt, '', [
+ 'Calculate the initial crc value.',
+ '',
+ Conditional(self.opt, '', _use_cfg(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\return The initial crc value.',
+ ]),
+ Conditional2(self.opt, '', _use_constant_crc_init(self.sym), [
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ '#define {crc_init_function}() ({crc_init_value})'.format(**self.sym),
+ ], [
+ 'static inline {0}'.format(_crc_init_function_def(self.opt, self.sym)),
+ '{',
+ ' return {crc_init_value};'.format(**self.sym),
+ '}',
+ ]),
+ ], [
+ '{0};'.format(_crc_init_function_def(self.opt, self.sym)),
+ ]),
+ '', '',
+ Comment(self.opt, '', [
+ 'Update the crc value with new data.',
+ '',
+ '\\param[in] crc The current crc value.',
+ Conditional(self.opt, '', not _use_cfg_in_crc_update(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\param[in] data Pointer to a buffer of \\a data_len bytes.',
+ '\\param[in] data_len Number of bytes in the \\a data buffer.',
+ '\\return The updated crc value.',
+ ]),
+ '{0};'.format(_crc_update_function_def(self.opt, self.sym)),
+ '', '',
+ Comment(self.opt, '', [
+ 'Calculate the final crc value.',
+ '',
+ Conditional(self.opt, '', not _use_cfg_in_finalize(self.opt), [
+ '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
+ ]),
+ '\\param[in] crc The current crc value.',
+ '\\return The final crc value.',
+ ]),
+ Conditional2(self.opt, '', _use_inline_crc_finalize(self.opt), [
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ '#define {0}(crc) ({1})'.format(self.sym['crc_finalize_function'], _crc_final_value(self.opt, self.sym)),
+ ], [
+ 'static inline {0}'.format(_crc_finalize_function_def(self.opt, self.sym)),
+ '{',
+ ' return {0};'.format(_crc_final_value(self.opt, self.sym)),
+ '}',
+ ]),
+ ], [
+ '{0};'.format(_crc_finalize_function_def(self.opt, self.sym)),
+ ]),
+ '', '',
+ '#ifdef __cplusplus',
+ '} /* closing brace for extern "C" */',
+ '#endif',
+ '',
+ '#endif /* {header_protection} */'.format(**self.sym),
+ '',
+ ]
+ return out
+
+ def _c_file(self):
+ """
+ Add C file content.
+ """
+ out = [
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include "{header_filename}" /* include the header file generated with pycrc */'.format(**self.sym),
+ '#include <stdlib.h>',
+ Conditional(self.opt, '', self.opt.c_std != 'C89', [
+ '#include <stdint.h>',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters or \
+ self.opt.algorithm == self.opt.algo_bit_by_bit or \
+ self.opt.algorithm == self.opt.algo_bit_by_bit_fast, [
+ '#include <stdbool.h>',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.slice_by > 1, [
+ '#include <endian.h>',
+ ]),
+ Conditional(self.opt, '', _use_reflect_func(self.opt) and _use_static_reflect_func(self.opt), [
+ '',
+ 'static {crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
+ ]),
+ '',
+ CodeGen(self.opt, '', _crc_table(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_reflect_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_init_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_table_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_update_function_gen(self.opt, self.sym)),
+ CodeGen(self.opt, '', _crc_finalize_function_gen(self.opt, self.sym)),
+ '',
+ ]
+ return out
+
+ def _main_file(self):
+ """
+ Add main file content.
+ """
+ out = [
+ '',
+ '',
+ CodeGen(self.opt, '', _includes(self.opt)),
+ '#include <stdio.h>',
+ '#include <getopt.h>',
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '#include <stdlib.h>',
+ '#include <stdio.h>',
+ '#include <ctype.h>',
+ ]),
+ Conditional(self.opt, '', self.opt.c_std != 'C89', [
+ '#include <stdbool.h>',
+ ]),
+ '#include <string.h>',
+ '',
+ 'static char str[256] = "123456789";',
+ 'static {c_bool} verbose = {c_false};'.format(**self.sym),
+ self._getopt_template(),
+ '',
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'static void print_params(const {cfg_t} *cfg)'.format(**self.sym),
+ ], [
+ 'static void print_params(void)',
+ ]),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'char format[20];',
+ '',
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ 'sprintf(format, "%%-16s = 0x%%0%dlx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+ 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+ 'printf(format, "poly", (unsigned long int){cfg_poly});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+ 'printf(format, "xor_in", (unsigned long int){cfg_xor_in});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+ 'printf(format, "xor_out", (unsigned long int){cfg_xor_out});'.format(**self.sym),
+ 'printf(format, "crc_mask", (unsigned long int){cfg_mask});'.format(**self.sym),
+ 'printf(format, "msb_mask", (unsigned long int){cfg_msb_mask});'.format(**self.sym),
+ ], [
+ 'snprintf(format, sizeof(format), "%%-16s = 0x%%0%dllx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
+ 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
+ 'printf(format, "poly", (unsigned long long int){cfg_poly});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
+ 'printf(format, "xor_in", (unsigned long long int){cfg_xor_in});'.format(**self.sym),
+ 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
+ 'printf(format, "xor_out", (unsigned long long int){cfg_xor_out});'.format(**self.sym),
+ 'printf(format, "crc_mask", (unsigned long long int){cfg_mask});'.format(**self.sym),
+ 'printf(format, "msb_mask", (unsigned long long int){cfg_msb_mask});'.format(**self.sym),
+ ]),
+ ]),
+ '}',
+ '',
+ '',
+ Comment(self.opt, '', [
+ 'C main function.',
+ '\\param[in] argc the number of arguments in \\a argv.',
+ '\\param[in] argv a NULL-terminated array of pointers to the argument strings.',
+ '\\retval 0 on success.',
+ '\\retval >0 on error.',
+ ]),
+ 'int main(int argc, char *argv[])',
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
+ '{cfg_t} cfg = '.format(**self.sym) + '{',
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '0, /* width */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.poly is None, [
+ '0, /* poly */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
+ '0, /* reflect_in */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
+ '0, /* xor_in */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
+ '0, /* reflect_out */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
+ '0, /* xor_out */',
+ ]),
+ Conditional(self.opt, 4*' ', self.opt.width is None, [
+ '',
+ '0, /* crc_mask */',
+ '0, /* msb_mask */',
+ '0, /* crc_shift */',
+ ]),
+ '};',
+ ]),
+ '{crc_t} crc;'.format(**self.sym),
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'get_config(argc, argv, &cfg);',
+ ], [
+ 'get_config(argc, argv);',
+ ]),
+ Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
+ '{crc_table_gen_function}(&cfg);'.format(**self.sym),
+ ]),
+ 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
+ 'crc = {0}({1}crc, (void *)str, strlen(str));'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
+ 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
+ '',
+ 'if (verbose) {',
+ CodeGen(self.opt, 4*' ', [
+ 'print_params({0});'.format('&cfg' if self.opt.undefined_crc_parameters else ''),
+ ]),
+ '}',
+ Conditional2(self.opt, '', self.opt.c_std == 'C89', [
+ 'printf("0x%lx\\n", (unsigned long int)crc);',
+ ], [
+ 'printf("0x%llx\\n", (unsigned long long int)crc);',
+ ]),
+ 'return 0;',
+ ]),
+ '}',
+ ]
+ return out
+
+ def _getopt_template(self):
+ """
+ Add getopt functions.
+ """
+ out = [
+ Conditional(self.opt, '', self.opt.reflect_in is None or self.opt.reflect_out is None, [
+ '',
+ '',
+ 'static {c_bool} atob(const char *str)'.format(**self.sym),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'if (!str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return 0;',
+ ]),
+ '}',
+ 'if (isdigit(str[0])) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return ({c_bool})atoi(str);'.format(**self.sym),
+ ]),
+ '}',
+ 'if (tolower(str[0]) == \'t\') {',
+ CodeGen(self.opt, 4*' ', [
+ 'return {c_true};'.format(**self.sym),
+ ]),
+ '}',
+ 'return {c_false};'.format(**self.sym),
+ ]),
+ '}',
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None or self.opt.xor_in is None or self.opt.xor_out is None, [
+ '',
+ '',
+ 'static crc_t xtoi(const char *str)',
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'crc_t ret = 0;',
+ '',
+ 'if (!str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'return 0;',
+ ]),
+ '}',
+ 'if (str[0] == \'0\' && tolower(str[1]) == \'x\') {',
+ CodeGen(self.opt, 4*' ', [
+ 'str += 2;',
+ 'while (*str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'if (isdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 16 * ret + *str - \'0\';',
+ ]),
+ 'else if (isxdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 16 * ret + tolower(*str) - \'a\' + 10;',
+ ]),
+ 'else',
+ CodeGen(self.opt, 4*' ', [
+ 'return ret;',
+ ]),
+ 'str++;',
+ ]),
+ '}',
+ ]),
+ '} else if (isdigit(*str)) {',
+ CodeGen(self.opt, 4*' ', [
+ 'while (*str) {',
+ CodeGen(self.opt, 4*' ', [
+ 'if (isdigit(*str))',
+ CodeGen(self.opt, 4*' ', [
+ 'ret = 10 * ret + *str - \'0\';',
+ ]),
+ 'else',
+ CodeGen(self.opt, 4*' ', [
+ 'return ret;',
+ ]),
+ 'str++;',
+ ]),
+ '}',
+ ]),
+ '}',
+ 'return ret;',
+ ]),
+ '}',
+ ]),
+ '',
+ '',
+ Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
+ 'static int get_config(int argc, char *argv[], {cfg_t} *cfg)'.format(**self.sym),
+ ], [
+ 'static int get_config(int argc, char *argv[])',
+ ]),
+ '{',
+ CodeGen(self.opt, 4*' ', [
+ 'int c;',
+ 'int option_index;',
+ 'static struct option long_options[] = {',
+ CodeGen(self.opt, 4*' ', [
+ Conditional(self.opt, '', self.opt.width is None, [
+ '{"width", 1, 0, \'w\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None, [
+ '{"poly", 1, 0, \'p\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_in is None, [
+ '{"reflect-in", 1, 0, \'n\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ '{"xor-in", 1, 0, \'i\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_out is None, [
+ '{"reflect-out", 1, 0, \'u\'},',
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ '{"xor-out", 1, 0, \'o\'},',
+ ]),
+ '{"verbose", 0, 0, \'v\'},',
+ '{"check-string", 1, 0, \'s\'},',
+ Conditional(self.opt, '', self.opt.width is None, [
+ '{"table-idx-with", 1, 0, \'t\'},',
+ ]),
+ '{0, 0, 0, 0}',
+ ]),
+ '};',
+ '',
+ 'while (1) {',
+ CodeGen(self.opt, 4*' ', [
+ 'option_index = 0;',
+ '',
+ 'c = getopt_long(argc, argv, "w:p:n:i:u:o:s:vt", long_options, &option_index);',
+ 'if (c == -1)',
+ CodeGen(self.opt, 4*' ', [
+ 'break;',
+ ]),
+ '',
+ 'switch (c) {',
+ CodeGen(self.opt, 4*' ', [
+ 'case 0:',
+ CodeGen(self.opt, 4*' ', [
+ 'printf("option %s", long_options[option_index].name);',
+ 'if (optarg)',
+ CodeGen(self.opt, 4*' ', [
+ 'printf(" with arg %s", optarg);',
+ ]),
+ 'printf("\\n");',
+ 'break;',
+ ]),
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'case \'w\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->width = atoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.poly is None, [
+ 'case \'p\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->poly = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_in is None, [
+ 'case \'n\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->reflect_in = atob(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ 'case \'i\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->xor_in = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.reflect_out is None, [
+ 'case \'u\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->reflect_out = atob(optarg);',
+ 'break;',
+ ]),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ 'case \'o\':',
+ CodeGen(self.opt, 4*' ', [
+ 'cfg->xor_out = xtoi(optarg);',
+ 'break;',
+ ]),
+ ]),
+ 'case \'s\':',
+ CodeGen(self.opt, 4*' ', [
+ 'memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));',
+ 'str[sizeof(str) - 1] = \'\\0\';',
+ 'break;',
+ ]),
+ 'case \'v\':',
+ CodeGen(self.opt, 4*' ', [
+ 'verbose = {c_true};'.format(**self.sym),
+ 'break;',
+ ]),
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'case \'t\':',
+ CodeGen(self.opt, 4*' ', [
+ '/* ignore --table_idx_width option */',
+ 'break;',
+ ]),
+ ]),
+ 'case \'?\':',
+ CodeGen(self.opt, 4*' ', [
+ 'return -1;',
+ ]),
+ 'case \':\':',
+ CodeGen(self.opt, 4*' ', [
+ 'fprintf(stderr, "missing argument to option %c\\n", c);',
+ 'return -1;',
+ ]),
+ 'default:',
+ CodeGen(self.opt, 4*' ', [
+ 'fprintf(stderr, "unhandled option %c\\n", c);',
+ 'return -1;',
+ ]),
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(self.opt, '', self.opt.width is None, [
+ 'cfg->msb_mask = (crc_t)1u << (cfg->width - 1);',
+ 'cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;',
+ 'cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;',
+ ]),
+ '',
+ Conditional(self.opt, '', self.opt.poly is None, [
+ 'cfg->poly &= {cfg_mask};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_in is None, [
+ 'cfg->xor_in &= {cfg_mask};'.format(**self.sym),
+ ]),
+ Conditional(self.opt, '', self.opt.xor_out is None, [
+ 'cfg->xor_out &= {cfg_mask};'.format(**self.sym),
+ ]),
+ 'return 0;',
+ ]),
+ '}',
+ ]
+ return CodeGen(self.opt, '', out)
+
+
+def _includes(opt):
+ """
+ Return the #include directives for the user-defined list of include files.
+ """
+ includes = []
+ if opt.include_files is not None and len(opt.include_files) > 0:
+ for include_file in opt.include_files:
+ if include_file[0] == '"' or include_file[0] == '<':
+ includes.append('#include {0}'.format(include_file))
+ else:
+ includes.append('#include "{0}"'.format(include_file))
+ return includes
+
+
+def _crc_algo_define(opt, sym):
+ """
+ Get the the identifier for header files.
+ """
+ name = sym['crc_algorithm'].upper().replace('-', '_')
+ return 'CRC_ALGO_' + name
+
+
+def _use_cfg(opt):
+ """
+ Return True if a cfg_t structure is to be used.
+ """
+ return opt.undefined_crc_parameters
+
+
+def _use_constant_crc_init(sym):
+ """
+ Return True if the inintial value is constant.
+ """
+ return sym['crc_init_value'] is not None
+
+
+def _use_reflect_func(opt):
+ """
+ Return True if the reflect function is to be used.
+ """
+ if opt.reflect_out == None or opt.reflect_in == None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in != opt.reflect_out:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit:
+ if opt.reflect_in:
+ return True
+ if opt.reflect_out:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.reflect_in:
+ return True
+ if opt.reflect_out:
+ return True
+ return False
+
+
+def _use_static_reflect_func(opt):
+ """
+ Whether a static reflect function is to be used.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ return False
+ elif opt.reflect_out is not None and opt.algorithm == opt.algo_bit_by_bit_fast:
+ return False
+ else:
+ return True
+
+
+def _use_crc_table_gen(opt):
+ """
+ Return True if the table generator function is to be generated.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ return opt.width is None or opt.poly is None or opt.reflect_in is None
+ else:
+ return False
+
+
+def _crc_init_function_def(opt, sym):
+ """
+ The definition for the init function.
+ """
+ if _use_constant_crc_init(sym):
+ return '{crc_t} {crc_init_function}(void)'.format(**sym)
+ else:
+ return '{crc_t} {crc_init_function}(const {cfg_t} *cfg)'.format(**sym)
+
+
+def _use_cfg_in_crc_update(opt):
+ """
+ Return True if the update function uses the cfg_t parameter.
+ """
+ if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+ if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.width is not None and opt.reflect_in is not None:
+ return True
+ return False
+
+
+def _crc_update_function_def(opt, sym):
+ """
+ The definition of the update function.
+ """
+ if _use_cfg_in_crc_update(opt):
+ return '{crc_t} {crc_update_function}({crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+ else:
+ return '{crc_t} {crc_update_function}(const {cfg_t} *cfg, {crc_t} crc, const void *data, size_t data_len)'.format(**sym)
+
+
+def _use_cfg_in_finalize(opt):
+ """
+ Return True if the cfg_t parameter is used in the finalize function.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ if opt.width is not None and opt.poly is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.width is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None:
+ return True
+ return False
+
+
+def _use_inline_crc_finalize(opt):
+ """
+ Return True if the init function can be inlined.
+ """
+ if opt.algorithm in set([opt.algo_bit_by_bit_fast, opt.algo_table_driven]) and \
+ (opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None):
+ return True
+ else:
+ return False
+
+
+def _use_constant_crc_table(opt):
+ """
+ Return True is the CRC table is constant.
+ """
+ if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
+ return True
+ else:
+ return False
+
+
+def _crc_finalize_function_def(opt, sym):
+ """
+ The definition of the finalize function.
+ """
+ if _use_cfg_in_finalize(opt):
+ return '{crc_t} {crc_finalize_function}({crc_t} crc)'.format(**sym)
+ else:
+ return '{crc_t} {crc_finalize_function}(const {cfg_t} *cfg, {crc_t} crc)'.format(**sym)
+
+
+def _crc_final_value(opt, sym):
+ """
+ The return value for the finalize function.
+ """
+ if opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in == opt.reflect_out:
+ return expr.Xor('crc', sym['crc_xor_out']).simplify()
+ else:
+ reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+ return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+ elif opt.reflect_out:
+ reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
+ return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
+ else:
+ return expr.Xor('crc', sym['crc_xor_out']).simplify()
+
+
+def _crc_table(opt, sym):
+ """
+ Return the code for the CRC table or the generator function.
+ """
+ if opt.algorithm != opt.algo_table_driven:
+ return []
+ return [
+ '', '',
+ Comment(opt, '', [
+ 'Static table used for the table_driven implementation.',
+ Conditional(opt, '', opt.undefined_crc_parameters, [
+ 'Must be initialised with the {crc_table_gen_function} function.'.format(**sym),
+ ]),
+ ]),
+ Conditional2(opt, '', _use_constant_crc_table(opt), [
+ Conditional2(opt, '', opt.slice_by > 1, [
+ 'static const {crc_t} crc_table[{crc_slice_by}][{crc_table_width}] = {crc_table_init};'.format(**sym),
+ ], [
+ 'static const {crc_t} crc_table[{crc_table_width}] = {crc_table_init};'.format(**sym),
+ ]),
+ ], [
+ 'static {crc_t} crc_table[{crc_table_width}];'.format(**sym),
+ ]),
+ ]
+
+
+def _crc_table_gen(opt, sym):
+ """
+ Return the code for the CRC table or the generator function.
+ """
+ if opt.algorithm != opt.algo_table_driven or _use_constant_crc_table(opt):
+ return []
+ return [
+ '', '',
+ 'void {crc_table_gen_function}(const {cfg_t} *cfg)'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ '{crc_t} crc;'.format(**sym),
+ 'unsigned int i, j;',
+ '',
+ 'for (i = 0; i < {cfg_table_width}; i++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.reflect_in is None, [
+ 'if (cfg->reflect_in) {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc = i;',
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.reflect_in, [
+ 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
+ ], [
+ 'crc = i;',
+ ]),
+ ]),
+ 'crc <<= {0};'.format(expr.Parenthesis(expr.Add(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width']), sym['cfg_shift'])).simplify()),
+ 'for (j = 0; j < {cfg_table_idx_width}; j++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'if (crc & {cfg_msb_mask_shifted}) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'crc = {0};'.format(expr.Xor(expr.Parenthesis(expr.Shl('crc', 1)), sym['cfg_poly_shifted']).simplify()),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc = crc << 1;',
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(opt, '', opt.reflect_in is None, [
+ 'if (cfg->reflect_in) {',
+ Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+ 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+ ], [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_in, [
+ Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
+ 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
+ ], [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+ 'crc_table[i] = {0};'.format(expr.Shr(expr.Parenthesis(expr.And('crc', sym['cfg_mask_shifted'])), sym['cfg_shift'])),
+ ]),
+ '}',
+ ]),
+ '}',
+ ]
+
+
+def _crc_reflect_function_gen(opt, sym):
+ """
+ Return the code for the reflect functon.
+ """
+ if not _use_reflect_func(opt):
+ return []
+ if not (opt.reflect_in is None or opt.reflect_in or \
+ opt.reflect_out is None or opt.reflect_out):
+ return []
+ return [
+ '', '',
+ '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len)'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{crc_t} ret;'.format(**sym),
+ '',
+ 'ret = data & 0x01;',
+ 'for (i = 1; i < data_len; i++) {',
+ CodeGen(opt, 4*' ', [
+ 'data >>= 1;',
+ 'ret = (ret << 1) | (data & 0x01);',
+ ]),
+ '}',
+ 'return ret;',
+ ]),
+ '}',
+ ]
+
+
+def _crc_init_function_gen(opt, sym):
+ """
+ Return the code for the init function.
+ """
+ if _use_constant_crc_init(sym):
+ return []
+ out = [
+ '', '',
+ _crc_init_function_def(opt, sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit, [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ '{crc_t} crc = {cfg_xor_in};'.format(**sym),
+ 'for (i = 0; i < {cfg_width}; i++) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'bit = crc & 0x01;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc = ((crc ^ {cfg_poly}) >> 1) | {cfg_msb_mask};'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'crc >>= 1;',
+ ]),
+ '}',
+ ]),
+ '}',
+ 'return crc & {cfg_mask};'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit_fast, [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.algorithm == opt.algo_table_driven, [
+ Conditional2(opt, '', opt.reflect_in is None, [
+ 'if ({cfg_reflect_in}) '.format(**sym) + '{',
+ CodeGen(opt, 4*' ', [
+ 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.algorithm == opt.reflect_in, [
+ 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
+ ], [
+ 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
+ ]),
+ ]),
+ ]),
+ ]),
+ '}',
+ ]
+ return out
+
+
+def _crc_update_function_gen(opt, sym):
+ """
+ Return the code for the update function.
+ """
+ out = [
+ '', '',
+ _crc_update_function_def(opt, sym),
+ '{',
+ CodeGen(opt, 4*' ', [ 'const unsigned char *d = (const unsigned char *)data;' ]),
+ ]
+ if opt.algorithm == opt.algo_bit_by_bit:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ 'unsigned char c;',
+ '',
+ 'while (data_len--) {',
+ Conditional2(opt, 4*' ', opt.reflect_in is None, [
+ 'if (' + sym['cfg_reflect_in'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'c = *d++;',
+ ]),
+ '}',
+ ], [
+ Conditional2(opt, '', opt.reflect_in, [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ], [
+ 'c = *d++;',
+ ]),
+ ]),
+
+ CodeGen(opt, 4*' ', [
+ 'for (i = 0; i < 8; i++) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!(crc & {cfg_msb_mask});'.format(**sym),
+ ], [
+ 'bit = crc & {cfg_msb_mask};'.format(**sym),
+ ]),
+ 'crc = (crc << 1) | ((c >> (7 - i)) & 0x01);',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ 'crc &= {cfg_mask};'.format(**sym),
+ ]),
+ '}',
+ 'return crc & {cfg_mask};'.format(**sym),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_bit_by_bit_fast:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ 'unsigned char c;',
+ '',
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.reflect_in == None, [
+ 'if (' + sym['cfg_reflect_in'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'c = *d++;',
+ ]),
+ '}',
+ ], [
+ 'c = *d++;',
+ ]),
+ Conditional2(opt, '', opt.reflect_in, [
+ 'for (i = 0x01; i & 0xff; i <<= 1) {',
+ ], [
+ 'for (i = 0x80; i > 0; i >>= 1) {',
+ ]),
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!({0});'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+ ], [
+ 'bit = {0};'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
+ ]),
+ 'if (c & i) {',
+ CodeGen(opt, 4*' ', [
+ 'bit = !bit;',
+ ]),
+ '}',
+ 'crc <<= 1;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ 'crc &= {cfg_mask};'.format(**sym)
+ ]),
+ '}',
+ 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_table_driven:
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'unsigned int tbl_idx;',
+ '',
+ Conditional2(opt, '', opt.reflect_in == None, [
+ 'if (cfg->reflect_in) {',
+ CodeGen(opt, 4*' ', [
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm_reflected(opt, sym),
+ 'd++;',
+ ]),
+ '}',
+ ]),
+ '} else {',
+ CodeGen(opt, 4*' ', [
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm_nonreflected(opt, sym),
+ 'd++;',
+ ]),
+ '}',
+ ]),
+ '}',
+ ], [
+ Conditional(opt, '', opt.slice_by > 1, [
+ '/* Align to a multiple of {crc_slice_by} bytes */'.format(**sym),
+ 'while (data_len && (((uintptr_t)(const void *)d) % {crc_slice_by} != 0))'.format(**sym) + ' {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm(opt, sym),
+ 'data_len--;',
+ ]),
+ '}',
+ '',
+ _crc_table_slice_by_algorithm(opt, sym),
+ '/* Remaining bytes with the standard algorithm */',
+ 'd = (const unsigned char *)d32;',
+ ]),
+ 'while (data_len--) {',
+ CodeGen(opt, 4*' ', [
+ _crc_table_core_algorithm(opt, sym),
+ ]),
+ '}',
+ ]),
+ 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
+ ]),
+ ]
+ out += [
+ '}',
+ ]
+ return out
+
+
+
+def _crc_finalize_function_gen(opt, sym):
+ """
+ Return the code for the finalize function.
+ """
+ if _use_inline_crc_finalize(opt):
+ return []
+ out = [
+ '', '',
+ _crc_finalize_function_def(opt, sym),
+ '{',
+ ]
+ if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
+ out += [
+ Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit, [
+ 'unsigned int i;',
+ '{c_bool} bit;'.format(**sym),
+ '',
+ 'for (i = 0; i < ' + sym['cfg_width'] + '; i++) {',
+ CodeGen(opt, 4*' ', [
+ Conditional2(opt, '', opt.c_std == 'C89', [
+ 'bit = !!(crc & {cfg_msb_mask});'.format(**sym)
+ ], [
+ 'bit = crc & {cfg_msb_mask};'.format(**sym),
+ ]),
+ 'crc <<= 1;',
+ 'if (bit) {',
+ CodeGen(opt, 4*' ', [
+ 'crc ^= {cfg_poly};'.format(**sym),
+ ]),
+ '}',
+ ]),
+ '}',
+ Conditional(opt, '', opt.reflect_out is None, [
+ 'if (' + sym['cfg_reflect_out'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_out, [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+
+ Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit_fast, [
+ Conditional(opt, '', opt.reflect_out is None, [
+ 'if (' + sym['cfg_reflect_out'] + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ Conditional(opt, '', opt.reflect_out, [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ ]),
+ ]
+
+ if opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in is None or opt.reflect_out is None:
+ if opt.reflect_in is None and opt.reflect_out is None:
+ cond = 'cfg->reflect_in != cfg->reflect_out'
+ elif opt.reflect_out is None:
+ cond = '!' if opt.reflect_in else '' + 'cfg->reflect_out'
+ else:
+ cond = '!' if opt.reflect_out else '' + 'cfg->reflect_in'
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'if (' + cond + ') {',
+ CodeGen(opt, 4*' ', [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]),
+ '}',
+ ]),
+ ]
+ elif opt.reflect_in != opt.reflect_out:
+ out += [
+ 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
+ ]
+ out += [
+ CodeGen(opt, 4*' ', [
+ 'return {0};'.format(expr.And(expr.Parenthesis(expr.Xor('crc', sym['cfg_xor_out'])), sym['cfg_mask']).simplify()),
+ ]),
+ '}',
+ ]
+ return out
+
+def _crc_table_core_algorithm(opt, sym):
+ """
+ Return the core of the table-driven algorithm.
+ """
+ out = []
+ out += [
+ Conditional2(opt, '', opt.reflect_in, [
+ _crc_table_core_algorithm_reflected(opt, sym),
+ ], [
+ _crc_table_core_algorithm_nonreflected(opt, sym),
+ ]),
+ 'd++;',
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_reflected(opt, sym):
+ """
+ Return the core loop of the table-driven algorithm, reflected variant.
+ """
+ out = []
+ if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+ crc_xor_expr = '0'
+ else:
+ crc_xor_expr = '(crc >> {cfg_table_idx_width})'.format(**sym)
+
+ if opt.tbl_idx_width == 8:
+ if opt.slice_by > 1:
+ crc_lookup = 'crc_table[0][tbl_idx]'
+ else:
+ crc_lookup = 'crc_table[tbl_idx]'
+ out += [
+ Conditional2(opt, '', opt.width is None or opt.width > 8, [
+ 'tbl_idx = (crc ^ *d) & {crc_table_mask};'.format(**sym),
+ ], [
+ 'tbl_idx = crc ^ *d;',
+ ]),
+ 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, expr.Parenthesis(expr.Shr('crc', sym['cfg_table_idx_width'])))), sym['cfg_mask']).simplify()),
+ ]
+ else:
+ crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+ for i in range(8 // opt.tbl_idx_width):
+ out += [
+ 'tbl_idx = {0};'.format(expr.Xor('crc', expr.Parenthesis(expr.Shr('*d', expr.Parenthesis(expr.Mul(i, sym['cfg_table_idx_width']))))).simplify()),
+ 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify())
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_core_algorithm_nonreflected(opt, sym):
+ """
+ Return the core loop of the table-driven algorithm, non-reflected variant.
+ """
+ out = []
+ if opt.width == None:
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', expr.Parenthesis(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width'])))).simplify()
+ elif opt.width < 8:
+ shift_val = opt.width - opt.tbl_idx_width
+ if shift_val < 0:
+ crc_shifted_right = expr.Parenthesis(expr.Shl('crc', -shift_val)).simplify()
+ else:
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+ else:
+ shift_val = opt.width - opt.tbl_idx_width
+ crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
+
+ if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
+ crc_xor_expr = '0'
+ else:
+ crc_xor_expr = '(crc << {cfg_table_idx_width})'.format(**sym)
+
+ if opt.tbl_idx_width == 8:
+ if opt.slice_by > 1:
+ crc_lookup = 'crc_table[0][tbl_idx]'
+ else:
+ crc_lookup = 'crc_table[tbl_idx]'
+ out += [
+ Conditional2(opt, '', opt.width is None or opt.width > 8, [
+ 'tbl_idx = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_shifted_right, '*d')), sym['crc_table_mask']).simplify())
+ ], [
+ 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, '*d').simplify())
+ ]),
+ 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, crc_xor_expr)), sym['cfg_mask']).simplify())
+ ]
+ else:
+ crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
+ for i in range(8 // opt.tbl_idx_width):
+ str_idx = '{0:d}'.format(8 - (i + 1) * opt.tbl_idx_width)
+ out += [
+ 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, expr.Parenthesis(expr.Shr('*d', str_idx)))),
+ 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify()),
+ ]
+ return CodeGen(opt, '', out)
+
+def _crc_table_slice_by_algorithm(opt, sym):
+ update_be = []
+ for i in range(opt.slice_by // 4):
+ vard = 'd{0}'.format(opt.slice_by // 4 - i)
+ for j in range(4):
+ idx1 = i * 4 + j
+ idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, j*8)), expr.Terminal(255, '0xffu')).simplify()
+ update_be.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+ update_le = []
+ for i in range(opt.slice_by // 4):
+ vard = 'd{0}'.format(opt.slice_by // 4 - i)
+ for j in range(4):
+ idx1 = i * 4 + j
+ idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, 24 - j*8)), expr.Terminal(255, '0xffu')).simplify()
+ update_le.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
+
+ out = [
+ 'const uint32_t *d32 = (const uint32_t *)d;',
+ 'while (data_len >= {crc_slice_by})'.format(**sym),
+ '{',
+ CodeGen(opt, 4*' ', [
+ CodeGen(opt, None, [
+ '#if __BYTE_ORDER == __BIG_ENDIAN',
+ ]),
+ '{crc_t} d1 = *d32++ ^ le16toh(crc);'.format(**sym),
+ Conditional(opt, '', opt.slice_by >= 8, [
+ '{crc_t} d2 = *d32++;'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.slice_by >= 16, [
+ '{crc_t} d3 = *d32++;'.format(**sym),
+ '{crc_t} d4 = *d32++;'.format(**sym),
+ ]),
+ 'crc =',
+ CodeGen(opt, 4*' ', update_be),
+ CodeGen(opt, None, [
+ '#else',
+ ]),
+ '{crc_t} d1 = *d32++ ^ crc;'.format(**sym),
+ Conditional(opt, '', opt.slice_by >= 8, [
+ '{crc_t} d2 = *d32++;'.format(**sym),
+ ]),
+ Conditional(opt, '', opt.slice_by >= 16, [
+ '{crc_t} d3 = *d32++;'.format(**sym),
+ '{crc_t} d4 = *d32++;'.format(**sym),
+ ]),
+ 'crc =',
+ CodeGen(opt, 4*' ', update_le),
+ CodeGen(opt, None, [
+ '#endif',
+ ]),
+ '',
+ 'data_len -= {crc_slice_by};'.format(**sym),
+ ]),
+ '}',
+ '',
+ ]
+ return CodeGen(opt, '', out)
diff --git a/pycrc/expr.py b/pycrc/expr.py
new file mode 100644
index 0000000..a15742c
--- /dev/null
+++ b/pycrc/expr.py
@@ -0,0 +1,398 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+This modules simplifies an expression.
+
+ import pycrc.expr as exp
+
+ my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
+ print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
+"""
+
+
+def _classify(val):
+ """
+ Creates a Terminal object if the parameter is a string or an integer.
+ """
+ if type(val) is int:
+ return Terminal(val)
+ if type(val) is str:
+ if val.isdigit():
+ return Terminal(int(val), val)
+ if val[:2].lower() == '0x':
+ return Terminal(int(val, 16), val)
+ return Terminal(val)
+ return val
+
+
+class Expression(object):
+ """
+ Base class for all expressions.
+ """
+ def is_int(self, val = None):
+ return False
+
+
+class Terminal(Expression):
+ """
+ A terminal object.
+ """
+ def __init__(self, val, pretty = None):
+ """
+ Construct a Terminal.
+ The val variable is usually a string or an integer. Integers may also
+ be passed as strings. The pretty-printer will use the string when
+ formatting the expression.
+ """
+ self.val = val
+ self.pretty = pretty
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ if self.pretty is None:
+ return str(self.val)
+ return self.pretty
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ return self
+
+ def is_int(self, val = None):
+ """
+ Return True if the value of this Terminal is an integer.
+ """
+ if type(self.val) is int:
+ return val is None or self.val == val
+ return False
+
+
+class FunctionCall(Expression):
+ """
+ Represent a function call
+ """
+ def __init__(self, name, args):
+ """
+ Construct a function call object.
+ """
+ self.name = _classify(name)
+ self.args = [_classify(arg) for arg in args]
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ args = [arg.simplify() for arg in self.args]
+ return FunctionCall(self.name, args)
+
+
+class Parenthesis(Expression):
+ """
+ Represent a pair of round brackets.
+ """
+ def __init__(self, val):
+ """
+ Construct a parenthesis object.
+ """
+ self.val = _classify(val)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ val = self.val.simplify()
+ if type(val) is Terminal:
+ return val
+ return Parenthesis(val)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return '(' + str(self.val) + ')'
+
+
+class Add(Expression):
+ """
+ Represent an addition of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct an addition object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val + rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Add(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' + ' + str(self.rhs)
+
+
+class Sub(Expression):
+ """
+ Represent a subtraction of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct subtraction object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val - rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Sub(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' - ' + str(self.rhs)
+
+
+class Mul(Expression):
+ """
+ Represent the multiplication of operands.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a multiplication object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val * rhs.val)
+ if lhs.is_int(0) or rhs.is_int(0):
+ return Terminal(0)
+ if lhs.is_int(1):
+ return rhs
+ if rhs.is_int(1):
+ return lhs
+ return Mul(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' * ' + str(self.rhs)
+
+
+class Shl(Expression):
+ """
+ Shift left operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a shift left object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val << rhs.val)
+ if lhs.is_int(0):
+ return Terminal(0)
+ if rhs.is_int(0):
+ return lhs
+ return Shl(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' << ' + str(self.rhs)
+
+
+class Shr(Expression):
+ """
+ Shift right operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a shift right object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val >> rhs.val)
+ if lhs.is_int(0):
+ return Terminal(0)
+ if rhs.is_int(0):
+ return lhs
+ return Shr(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' >> ' + str(self.rhs)
+
+
+class Or(Expression):
+ """
+ Logical or operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical and object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val | rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Or(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' | ' + str(self.rhs)
+
+
+class And(Expression):
+ """
+ Logical and operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical and object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val & rhs.val)
+ if lhs.is_int(0) or rhs.is_int(0):
+ return Terminal(0)
+ return And(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' & ' + str(self.rhs)
+
+
+class Xor(Expression):
+ """
+ Logical xor operation.
+ """
+ def __init__(self, lhs, rhs):
+ """
+ Construct a logical xor object.
+ """
+ self.lhs = _classify(lhs)
+ self.rhs = _classify(rhs)
+
+ def simplify(self):
+ """
+ Return a simplified version of this sub-expression.
+ """
+ lhs = self.lhs.simplify()
+ rhs = self.rhs.simplify()
+ if lhs.is_int() and rhs.is_int():
+ return Terminal(lhs.val ^ rhs.val)
+ if lhs.is_int(0):
+ return rhs
+ if rhs.is_int(0):
+ return lhs
+ return Xor(lhs, rhs)
+
+ def __str__(self):
+ """
+ Return the string expression of this object.
+ """
+ return str(self.lhs) + ' ^ ' + str(self.rhs)
diff --git a/pycrc/main.py b/pycrc/main.py
new file mode 100644
index 0000000..d446362
--- /dev/null
+++ b/pycrc/main.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+pycrc is a fully parameterisable Cyclic Redundancy Check (CRC) calculation
+utility and C source code generator written in Python.
+
+It can:
+ - generate the checksum of a string
+ - generate the checksum of a file
+ - generate the C header file and source of any of the algorithms below
+
+It supports the following CRC algorithms:
+ - bit-by-bit the basic algorithm which operates bit by bit on the
+ augmented message
+ - bit-by-bit-fast a variation of the simple bit-by-bit algorithm
+ - table-driven the standard table driven algorithm
+"""
+
+from __future__ import print_function
+from pycrc import progname, version, url
+from pycrc.opt import Options
+from pycrc.algorithms import Crc
+import pycrc.codegen as cg
+import binascii
+import sys
+
+
+
+def print_parameters(opt):
+ """
+ Generate a string with the options pretty-printed (used in the --verbose mode).
+ """
+ return str(cg.ParamBlock(opt, ''))
+
+
+def check_string(opt):
+ """
+ Return the calculated CRC sum of a string.
+ """
+ error = False
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ if opt.algorithm == 0:
+ opt.algorithm = opt.algo_bit_by_bit | opt.algo_bit_by_bit_fast | opt.algo_table_driven
+
+ alg = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+
+ crc = None
+ if opt.algorithm & opt.algo_bit_by_bit:
+ bbb_crc = alg.bit_by_bit(opt.check_string)
+ if crc != None and bbb_crc != crc:
+ error = True
+ crc = bbb_crc
+ if opt.algorithm & opt.algo_bit_by_bit_fast:
+ bbf_crc = alg.bit_by_bit_fast(opt.check_string)
+ if crc != None and bbf_crc != crc:
+ error = True
+ crc = bbf_crc
+ if opt.algorithm & opt.algo_table_driven:
+ # no point making the python implementation slower by using less than 8 bits as index.
+ opt.tbl_idx_width = 8
+ tbl_crc = alg.table_driven(opt.check_string)
+ if crc != None and tbl_crc != crc:
+ error = True
+ crc = tbl_crc
+
+ if error:
+ sys.stderr.write("{0:s}: error: different checksums!\n".format(progname))
+ if opt.algorithm & opt.algo_bit_by_bit:
+ sys.stderr.write(" bit-by-bit: {0:#x}\n".format(bbb_crc))
+ if opt.algorithm & opt.algo_bit_by_bit_fast:
+ sys.stderr.write(" bit-by-bit-fast: {0:#x}\n".format(bbf_crc))
+ if opt.algorithm & opt.algo_table_driven:
+ sys.stderr.write(" table_driven: {0:#x}\n".format(tbl_crc))
+ sys.exit(1)
+ return crc
+
+
+def check_hexstring(opt):
+ """
+ Return the calculated CRC sum of a hex string.
+ """
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ if len(opt.check_string) % 2 != 0:
+ opt.check_string = "0" + opt.check_string
+ if sys.version_info >= (3, 0):
+ opt.check_string = bytes(opt.check_string, 'utf_8')
+ try:
+ check_str = bytearray(binascii.unhexlify(opt.check_string))
+ except TypeError:
+ sys.stderr.write(
+ "{0:s}: error: invalid hex string {1:s}\n".format(progname, opt.check_string))
+ sys.exit(1)
+
+ opt.check_string = check_str
+ return check_string(opt)
+
+
+def crc_file_update(alg, register, check_bytes):
+ """
+ Update the CRC using the bit-by-bit-fast CRC algorithm.
+ """
+ # If the input data is a string, convert to bytes.
+ if isinstance(check_bytes, str):
+ check_bytes = bytearray(check_bytes, 'utf_8')
+
+ for octet in check_bytes:
+ if alg.reflect_in:
+ octet = alg.reflect(octet, 8)
+ for j in range(8):
+ bit = register & alg.msb_mask
+ register <<= 1
+ if octet & (0x80 >> j):
+ bit ^= alg.msb_mask
+ if bit:
+ register ^= alg.poly
+ register &= alg.mask
+ return register
+
+
+def check_file(opt):
+ """
+ Calculate the CRC of a file.
+ This algorithm uses the table_driven CRC algorithm.
+ """
+ if opt.undefined_crc_parameters:
+ sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
+ sys.exit(1)
+ alg = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+
+ if not opt.reflect_in:
+ register = opt.xor_in
+ else:
+ register = alg.reflect(opt.xor_in, opt.width)
+
+ try:
+ with open(opt.check_file, 'rb') as f:
+ check_bytes = bytearray(f.read(1024))
+ while check_bytes != b"":
+ register = crc_file_update(alg, register, check_bytes)
+ check_bytes = bytearray(f.read(1024))
+ except IOError:
+ sys.stderr.write(
+ "{0:s}: error: can't open file {1:s}\n".format(progname, opt.check_file))
+ sys.exit(1)
+
+ if opt.reflect_out:
+ register = alg.reflect(register, opt.width)
+ register = register ^ opt.xor_out
+ return register
+
+
+def write_file(filename, out_str):
+ """
+ Write the content of out_str to filename.
+ """
+ try:
+ out_file = open(filename, "w")
+ out_file.write(out_str)
+ out_file.close()
+ except IOError:
+ sys.stderr.write("{0:s}: error: cannot write to file {1:s}\n".format(progname, filename))
+ sys.exit(1)
+
+
+def main():
+ """
+ Main function.
+ """
+ opt = Options(progname, version, url)
+ opt.parse(sys.argv[1:])
+ if opt.verbose:
+ print(print_parameters(opt))
+ if opt.action == opt.action_check_str:
+ crc = check_string(opt)
+ print("{0:#x}".format(crc))
+ if opt.action == opt.action_check_hex_str:
+ crc = check_hexstring(opt)
+ print("{0:#x}".format(crc))
+ if opt.action == opt.action_check_file:
+ crc = check_file(opt)
+ print("{0:#x}".format(crc))
+ if opt.action in set([
+ opt.action_generate_h, opt.action_generate_c, opt.action_generate_c_main,
+ opt.action_generate_table]):
+ if opt.action == opt.action_generate_h:
+ in_str = "$h_template"
+ elif opt.action == opt.action_generate_c:
+ in_str = "$c_template"
+ elif opt.action == opt.action_generate_c_main:
+ in_str = "$c_template\n\n$main_template"
+ elif opt.action == opt.action_generate_table:
+ in_str = "$crc_table_init"
+ else:
+ sys.stderr.write(
+ "{0:s}: error: unknown action. Please file a bug report!\n".format(progname))
+ sys.exit(1)
+ out = str(cg.File(opt, ''))
+ if opt.output_file == None:
+ print(out)
+ else:
+ write_file(opt.output_file, out)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/pycrc/models.py b/pycrc/models.py
new file mode 100644
index 0000000..d12c91c
--- /dev/null
+++ b/pycrc/models.py
@@ -0,0 +1,334 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Collection of CRC models. This module contains the CRC models known to pycrc.
+
+To print the parameters of a particular model:
+
+ from pycrc.models import CrcModels
+
+ models = CrcModels()
+ print(", ".join(models.names()))
+ m = models.get_params("crc-32")
+ if m != None:
+ print("Width: {width:d}".format(**m))
+ print("Poly: {poly:#x}".format(**m))
+ print("ReflectIn: {reflect_in}".format(**m))
+ print("XorIn: {xor_in:#x}".format(**m))
+ print("ReflectOut: {reflect_out}".format(**m))
+ print("XorOut: {xor_out:#x}".format(**m))
+ print("Check: {check:#x}".format(**m))
+ else:
+ print("model not found.")
+"""
+
+
+
+class CrcModels(object):
+ """
+ CRC Models.
+
+ All models are defined as constant class variables.
+ """
+
+ models = []
+
+ models.append({
+ 'name': 'crc-5',
+ 'width': 5,
+ 'poly': 0x05,
+ 'reflect_in': True,
+ 'xor_in': 0x1f,
+ 'reflect_out': True,
+ 'xor_out': 0x1f,
+ 'check': 0x19,
+ })
+ models.append({
+ 'name': 'crc-8',
+ 'width': 8,
+ 'poly': 0x07,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xf4,
+ })
+ models.append({
+ 'name': 'dallas-1-wire',
+ 'width': 8,
+ 'poly': 0x31,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xa1,
+ })
+ models.append({
+ 'name': 'crc-12-3gpp',
+ 'width': 12,
+ 'poly': 0x80f,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xdaf,
+ })
+ models.append({
+ 'name': 'crc-15',
+ 'width': 15,
+ 'poly': 0x4599,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x59e,
+ })
+ models.append({
+ 'name': 'crc-16',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xbb3d,
+ })
+ models.append({
+ 'name': 'crc-16-usb',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffff,
+ 'check': 0xb4c8,
+ })
+ models.append({
+ 'name': 'crc-16-modbus',
+ 'width': 16,
+ 'poly': 0x8005,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x4b37,
+ })
+ models.append({
+ 'name': 'crc-16-genibus',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0xffff,
+ 'reflect_out': False,
+ 'xor_out': 0xffff,
+ 'check': 0xd64e,
+ })
+ models.append({
+ 'name': 'crc-16-ccitt',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x1d0f,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xe5cc,
+ })
+ models.append({
+ 'name': 'r-crc-16',
+ 'width': 16,
+ 'poly': 0x0589,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0001,
+ 'check': 0x007e,
+ })
+ models.append({
+ 'name': 'kermit',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x2189,
+ })
+ models.append({
+ 'name': 'x-25',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': True,
+ 'xor_in': 0xffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffff,
+ 'check': 0x906e,
+ })
+ models.append({
+ 'name': 'xmodem',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x31c3,
+ })
+ models.append({
+ 'name': 'zmodem',
+ 'width': 16,
+ 'poly': 0x1021,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x31c3,
+ })
+ models.append({
+ 'name': 'crc-24',
+ 'width': 24,
+ 'poly': 0x864cfb,
+ 'reflect_in': False,
+ 'xor_in': 0xb704ce,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x21cf02,
+ })
+ models.append({
+ 'name': 'crc-32',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffff,
+ 'check': 0xcbf43926,
+ })
+ models.append({
+ 'name': 'crc-32c',
+ 'width': 32,
+ 'poly': 0x1edc6f41,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffff,
+ 'check': 0xe3069283,
+ })
+ models.append({
+ 'name': 'crc-32-mpeg',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0x0376e6e7,
+ })
+ models.append({
+ 'name': 'crc-32-bzip2',
+ 'width': 32,
+ 'poly': 0x04c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': False,
+ 'xor_out': 0xffffffff,
+ 'check': 0xfc891918,
+ })
+ models.append({
+ 'name': 'posix',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0xffffffff,
+ 'check': 0x765e7680,
+ })
+ models.append({
+ 'name': 'jam',
+ 'width': 32,
+ 'poly': 0x4c11db7,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x340bc6d9,
+ })
+ models.append({
+ 'name': 'xfer',
+ 'width': 32,
+ 'poly': 0x000000af,
+ 'reflect_in': False,
+ 'xor_in': 0x0,
+ 'reflect_out': False,
+ 'xor_out': 0x0,
+ 'check': 0xbd0be338,
+ })
+ models.append({
+ 'name': 'crc-64',
+ 'width': 64,
+ 'poly': 0x000000000000001b,
+ 'reflect_in': True,
+ 'xor_in': 0x0,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0x46a5a9388a5beffe,
+ })
+ models.append({
+ 'name': 'crc-64-jones',
+ 'width': 64,
+ 'poly': 0xad93d23594c935a9,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffffffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0x0,
+ 'check': 0xcaa717168609f281,
+ })
+ models.append({
+ 'name': 'crc-64-xz',
+ 'width': 64,
+ 'poly': 0x42f0e1eba9ea3693,
+ 'reflect_in': True,
+ 'xor_in': 0xffffffffffffffff,
+ 'reflect_out': True,
+ 'xor_out': 0xffffffffffffffff,
+ 'check': 0x995dc9bbdf1939fa,
+ })
+
+
+ def names(self):
+ """
+ This function returns the list of supported CRC models.
+ """
+ return [model['name'] for model in self.models]
+
+
+ def get_params(self, model):
+ """
+ This function returns the parameters of a given model.
+ """
+ model = model.lower()
+ for i in self.models:
+ if i['name'] == model:
+ return i
+ return None
diff --git a/pycrc/opt.py b/pycrc/opt.py
new file mode 100644
index 0000000..7868b2e
--- /dev/null
+++ b/pycrc/opt.py
@@ -0,0 +1,484 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Option parsing library for pycrc.
+use as follows:
+
+ from pycrc.opt import Options
+
+ opt = Options()
+ opt.parse(sys.argv[1:])
+"""
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import sys
+from pycrc.models import CrcModels
+
+
+class Options(object):
+ """
+ The options parsing and validating class.
+ """
+ # pylint: disable=too-many-instance-attributes, too-few-public-methods
+
+ # Bitmap of the algorithms
+ algo_none = 0x00
+ algo_bit_by_bit = 0x01
+ algo_bit_by_bit_fast = 0x02
+ algo_table_driven = 0x08
+
+ action_check_str = 0x01
+ action_check_hex_str = 0x02
+ action_check_file = 0x03
+ action_generate_h = 0x04
+ action_generate_c = 0x05
+ action_generate_c_main = 0x06
+ action_generate_table = 0x07
+
+
+ def __init__(self, progname='pycrc', version=None, url=None):
+ self.program_name = progname
+ self.version = version
+ self.version_str = "{0:s} v{1:s}".format(progname, version)
+ self.web_address = url
+
+ self.width = None
+ self.poly = None
+ self.reflect_in = None
+ self.xor_in = None
+ self.reflect_out = None
+ self.xor_out = None
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << self.tbl_idx_width
+ self.slice_by = 1
+ self.verbose = False
+ self.check_string = "123456789"
+ self.msb_mask = None
+ self.mask = None
+
+ self.algorithm = self.algo_none
+ self.symbol_prefix = "crc_"
+ self.crc_type = None
+ self.include_files = []
+ self.output_file = None
+ self.action = self.action_check_str
+ self.check_file = None
+ self.c_std = None
+ self.undefined_crc_parameters = False
+
+
+ def parse(self, argv=None):
+ """
+ Parses and validates the options given as arguments
+ """
+ # pylint: disable=too-many-branches, too-many-statements
+
+ usage = """python %prog [OPTIONS]
+
+To calculate the checksum of a string or hexadecimal data:
+ python %prog [model] --check-string "123456789"
+ python %prog [model] --check-hexstring "313233343536373839"
+
+To calculate the checksum of a file:
+ python %prog [model] --check-file filename
+
+To generate the C source code and write it to filename:
+ python %prog [model] --generate c -o filename
+
+The model can be defined either with the --model switch or by specifying each
+of the following parameters:
+ --width --poly --reflect-in --xor-in --reflect-out --xor-out"""
+
+ models = CrcModels()
+ model_list = ", ".join(models.names())
+ parser = OptionParser(option_class=MyOption, usage=usage, version=self.version_str)
+ parser.add_option(
+ "-v", "--verbose",
+ action="store_true", dest="verbose", default=False,
+ help="be more verbose; print the value of the parameters "
+ "and the chosen model to stdout")
+ parser.add_option(
+ "--check-string",
+ action="store", type="string", dest="check_string",
+ help="calculate the checksum of a string (default: '123456789')",
+ metavar="STRING")
+ parser.add_option(
+ "--check-hexstring",
+ action="store", type="string", dest="check_hexstring",
+ help="calculate the checksum of a hexadecimal number string",
+ metavar="STRING")
+ parser.add_option(
+ "--check-file",
+ action="store", type="string", dest="check_file",
+ help="calculate the checksum of a file",
+ metavar="FILE")
+ parser.add_option(
+ "--generate",
+ action="store", type="string", dest="generate", default=None,
+ help="generate C source code; choose the type from {h, c, c-main, table}",
+ metavar="CODE")
+ parser.add_option(
+ "--std",
+ action="store", type="string", dest="c_std", default="C99",
+ help="choose the C dialect of the generated code from {C89, ANSI, C99}",
+ metavar="STD")
+ parser.add_option(
+ "--algorithm",
+ action="store", type="string", dest="algorithm", default="all",
+ help="choose an algorithm from "
+ "{bit-by-bit, bbb, bit-by-bit-fast, bbf, table-driven, tbl, all}",
+ metavar="ALGO")
+ parser.add_option(
+ "--model",
+ action="callback", callback=_model_cb, type="string", dest="model", default=None,
+ help="choose a parameter set from {{{0:s}}}".format(model_list),
+ metavar="MODEL")
+ parser.add_option(
+ "--width",
+ action="store", type="hex", dest="width",
+ help="use NUM bits in the polynomial",
+ metavar="NUM")
+ parser.add_option(
+ "--poly",
+ action="store", type="hex", dest="poly",
+ help="use HEX as polynomial",
+ metavar="HEX")
+ parser.add_option(
+ "--reflect-in",
+ action="store", type="bool", dest="reflect_in",
+ help="reflect the octets in the input message",
+ metavar="BOOL")
+ parser.add_option(
+ "--xor-in",
+ action="store", type="hex", dest="xor_in",
+ help="use HEX as initial value",
+ metavar="HEX")
+ parser.add_option(
+ "--reflect-out",
+ action="store", type="bool", dest="reflect_out",
+ help="reflect the resulting checksum before applying the --xor-out value",
+ metavar="BOOL")
+ parser.add_option(
+ "--xor-out",
+ action="store", type="hex", dest="xor_out",
+ help="xor the final CRC value with HEX",
+ metavar="HEX")
+ parser.add_option(
+ "--slice-by",
+ action="store", type="int", dest="slice_by",
+ help="read NUM bytes at a time from the input. NUM must be one of the values {4, 8, 16}",
+ metavar="NUM")
+ parser.add_option(
+ "--table-idx-width",
+ action="store", type="int", dest="table_idx_width",
+ help="use NUM bits to index the CRC table; NUM must be one of the values {1, 2, 4, 8}",
+ metavar="NUM")
+ parser.add_option(
+ "--force-poly",
+ action="store_true", dest="force_poly", default=False,
+ help="override any errors about possibly unsuitable polynoms")
+ parser.add_option(
+ "--symbol-prefix",
+ action="store", type="string", dest="symbol_prefix",
+ help="when generating source code, use STRING as prefix to the exported C symbols",
+ metavar="STRING")
+ parser.add_option(
+ "--crc-type",
+ action="store", type="string", dest="crc_type",
+ help="when generating source code, use STRING as crc_t type",
+ metavar="STRING")
+ parser.add_option(
+ "--include-file",
+ action="append", type="string", dest="include_files",
+ help="when generating source code, include also FILE as header file; "
+ "can be specified multiple times",
+ metavar="FILE")
+ parser.add_option(
+ "-o", "--output",
+ action="store", type="string", dest="output_file",
+ help="write the generated code to file instead to stdout",
+ metavar="FILE")
+
+ (options, args) = parser.parse_args(argv)
+
+ if options.c_std != None:
+ std = options.c_std.upper()
+ if std == "ANSI" or std == "C89":
+ self.c_std = "C89"
+ elif std == "C99":
+ self.c_std = std
+ else:
+ self.__error("unknown C standard {0:s}".format(options.c_std))
+
+ undefined_params = []
+ if options.width != None:
+ self.width = options.width
+ else:
+ undefined_params.append("--width")
+ if options.poly != None:
+ self.poly = options.poly
+ else:
+ undefined_params.append("--poly")
+ if options.reflect_in != None:
+ self.reflect_in = options.reflect_in
+ else:
+ undefined_params.append("--reflect-in")
+ if options.xor_in != None:
+ self.xor_in = options.xor_in
+ else:
+ undefined_params.append("--xor-in")
+ if options.reflect_out != None:
+ self.reflect_out = options.reflect_out
+ else:
+ undefined_params.append("--reflect-out")
+ if options.xor_out != None:
+ self.xor_out = options.xor_out
+ else:
+ undefined_params.append("--xor-out")
+
+ if options.table_idx_width != None:
+ if options.table_idx_width in set((1, 2, 4, 8)):
+ self.tbl_idx_width = options.table_idx_width
+ self.tbl_width = 1 << options.table_idx_width
+ else:
+ self.__error("unsupported table-idx-width {0:d}".format(options.table_idx_width))
+
+ if self.poly != None and self.poly % 2 == 0 and not options.force_poly:
+ self.__error("even polinomials are not allowed by default. Use --force-poly to override this.")
+
+ if self.width != None:
+ if self.width <= 0:
+ self.__error("Width must be strictly positive")
+ self.msb_mask = 0x1 << (self.width - 1)
+ self.mask = ((self.msb_mask - 1) << 1) | 1
+ if self.poly != None and self.poly >> (self.width + 1) != 0 and not options.force_poly:
+ self.__error("the polynomial is wider than the supplied Width. Use --force-poly to override this.")
+ if self.poly != None:
+ self.poly = self.poly & self.mask
+ if self.xor_in != None:
+ self.xor_in = self.xor_in & self.mask
+ if self.xor_out != None:
+ self.xor_out = self.xor_out & self.mask
+ else:
+ self.msb_mask = None
+ self.mask = None
+
+ if self.width == None or \
+ self.poly == None or \
+ self.reflect_in == None or \
+ self.xor_in == None or \
+ self.reflect_out == None or \
+ self.xor_out == None:
+ self.undefined_crc_parameters = True
+ else:
+ self.undefined_crc_parameters = False
+
+ if options.slice_by != None:
+ if options.slice_by in set((4, 8, 16)):
+ self.slice_by = options.slice_by
+ else:
+ self.__error("unsupported slice-by {0:d}".format(options.slice_by))
+ if self.undefined_crc_parameters:
+ self.__error("slice-by is only implemented for fully defined models")
+ if self.tbl_idx_width != 8:
+ self.__error("slice-by is only implemented for table-idx-width=8")
+ # FIXME tp: Fix corner cases and disable the following tests
+ if self.width < 8:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if self.width < 16:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if self.width > 32:
+ self.__warning("disabling slice-by for width {0}".format(self.width))
+ self.slice_by = 1
+ if not self.reflect_in:
+ self.__warning("disabling slice-by for non-reflected algorithm")
+ self.slice_by = 1
+# FIXME tp: reintroduce this?
+# if self.width % 8 != 0:
+# self.__error("slice-by is only implemented for width multiples of 8")
+# if options.slice_by < self.width / 8:
+# self.__error("slice-by must be greater or equal width / 8")
+ if self.c_std == "C89":
+ self.__error("--slice-by not supported for C89")
+
+ if options.algorithm != None:
+ alg = options.algorithm.lower()
+ if alg in set(["bit-by-bit", "bbb", "all"]):
+ self.algorithm |= self.algo_bit_by_bit
+ if alg in set(["bit-by-bit-fast", "bbf", "all"]):
+ self.algorithm |= self.algo_bit_by_bit_fast
+ if alg in set(["table-driven", "tbl", "all"]):
+ self.algorithm |= self.algo_table_driven
+ if self.algorithm == 0:
+ self.__error("unknown algorithm {0:s}".format(options.algorithm))
+
+ if options.symbol_prefix != None:
+ self.symbol_prefix = options.symbol_prefix
+ if options.include_files != None:
+ self.include_files = options.include_files
+ if options.crc_type != None:
+ self.crc_type = options.crc_type
+ if options.output_file != None:
+ self.output_file = options.output_file
+ op_count = 0
+ if options.check_string != None:
+ self.action = self.action_check_str
+ self.check_string = options.check_string
+ op_count += 1
+ if options.check_hexstring != None:
+ self.action = self.action_check_hex_str
+ self.check_string = options.check_hexstring
+ op_count += 1
+ if options.check_file != None:
+ self.action = self.action_check_file
+ self.check_file = options.check_file
+ op_count += 1
+ if options.generate != None:
+ arg = options.generate.lower()
+ if arg == 'h':
+ self.action = self.action_generate_h
+ elif arg == 'c':
+ self.action = self.action_generate_c
+ elif arg == 'c-main':
+ self.action = self.action_generate_c_main
+ elif arg == 'table':
+ self.action = self.action_generate_table
+ else:
+ self.__error("don't know how to generate {0:s}".format(options.generate))
+ op_count += 1
+
+ if self.action == self.action_generate_table:
+ if self.algorithm & self.algo_table_driven == 0:
+ self.__error("the --generate table option is incompatible "
+ "with the --algorithm option")
+ self.algorithm = self.algo_table_driven
+ elif self.algorithm not in set(
+ [self.algo_bit_by_bit, self.algo_bit_by_bit_fast, self.algo_table_driven]):
+ self.__error("select an algorithm to be used in the generated file")
+ else:
+ if self.tbl_idx_width != 8:
+ self.__warning("reverting to Table Index Width = 8 "
+ "for internal CRC calculation")
+ self.tbl_idx_width = 8
+ self.tbl_width = 1 << options.table_idx_width
+ if op_count == 0:
+ self.action = self.action_check_str
+ if op_count > 1:
+ self.__error("too many actions specified")
+
+ if len(args) != 0:
+ self.__error("unrecognized argument(s): {0:s}".format(" ".join(args)))
+
+ def_params_acts = (self.action_check_str, self.action_check_hex_str,
+ self.action_check_file, self.action_generate_table)
+ if self.undefined_crc_parameters and self.action in set(def_params_acts):
+ self.__error("undefined parameters: Add {0:s} or use --model"
+ .format(", ".join(undefined_params)))
+ self.verbose = options.verbose
+
+
+
+ def __warning(self, message):
+ """
+ Print a warning message to stderr.
+ """
+ sys.stderr.write(
+ "{0:s}: warning: {1:s}\n".format(self.program_name, message))
+
+
+
+ def __error(self, message):
+ """
+ Print a error message to stderr and terminate the program.
+ """
+ sys.stderr.write(
+ "{0:s}: error: {1:s}\n".format(self.program_name, message))
+ sys.exit(1)
+
+
+def _model_cb(option, opt_str, value, parser):
+ """
+ This function sets up the single parameters if the 'model' option has been selected
+ by the user.
+ """
+ model_name = value.lower()
+ models = CrcModels()
+ model = models.get_params(model_name)
+ if model != None:
+ setattr(parser.values, 'width', model['width'])
+ setattr(parser.values, 'poly', model['poly'])
+ setattr(parser.values, 'reflect_in', model['reflect_in'])
+ setattr(parser.values, 'xor_in', model['xor_in'])
+ setattr(parser.values, 'reflect_out', model['reflect_out'])
+ setattr(parser.values, 'xor_out', model['xor_out'])
+ else:
+ models = CrcModels()
+ model_list = ", ".join(models.names())
+ raise OptionValueError(
+ "unsupported model {0:s}. Supported models are: {1:s}."
+ .format(value, model_list))
+
+
+def _check_hex(dummy_option, opt, value):
+ """
+ Checks if a value is given in a decimal integer of hexadecimal reppresentation.
+ Returns the converted value or rises an exception on error.
+ """
+ try:
+ if value.lower().startswith("0x"):
+ return int(value, 16)
+ else:
+ return int(value)
+ except ValueError:
+ raise OptionValueError(
+ "option {0:s}: invalid integer or hexadecimal value: {1:s}.".format(opt, value))
+
+
+def _check_bool(dummy_option, opt, value):
+ """
+ Checks if a value is given as a boolean value (either 0 or 1 or "true" or "false")
+ Returns the converted value or rises an exception on error.
+ """
+ if value.isdigit():
+ return int(value, 10) != 0
+ elif value.lower() == "false":
+ return False
+ elif value.lower() == "true":
+ return True
+ else:
+ raise OptionValueError("option {0:s}: invalid boolean value: {1:s}.".format(opt, value))
+
+
+class MyOption(Option):
+ """
+ New option parsing class extends the Option class
+ """
+ TYPES = Option.TYPES + ("hex", "bool")
+ TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+ TYPE_CHECKER["hex"] = _check_hex
+ TYPE_CHECKER["bool"] = _check_bool
+
diff --git a/pycrc/symtable.py b/pycrc/symtable.py
new file mode 100644
index 0000000..e46ab9c
--- /dev/null
+++ b/pycrc/symtable.py
@@ -0,0 +1,352 @@
+# pycrc -- parameterisable CRC calculation utility and C source code generator
+#
+# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+"""
+Symbol table for the macro processor used by pycrc.
+use as follows:
+
+ import pycrc.opt as opt
+ import pycrc.symtable as sym
+
+ opt = opt.Options()
+ sym = sym.SymbolTable(opt)
+
+ print(sym['crc_width'])
+ print('width: {crc_width}, poly: {crc_poly}'.format(**sym))
+"""
+
+from pycrc.algorithms import Crc
+import collections
+import time
+import os
+
+
+class SymbolTable(object):
+ def __init__(self, opt):
+ self.opt = opt
+
+
+class SymbolTable(collections.MutableMapping):
+ """A dictionary that applies an arbitrary key-altering
+ function before accessing the keys"""
+
+ def __init__(self, opt):
+ self.opt = opt
+ self.tbl_shift = _tbl_shift(opt)
+ self.cache = dict()
+ self.generator = dict({
+ 'datetime': lambda: time.asctime(),
+ 'program_version': lambda: self.opt.version_str,
+ 'program_url': lambda: self.opt.web_address,
+ 'filename': lambda: 'pycrc_stdout' if self.opt.output_file is None else os.path.basename(self.opt.output_file),
+ 'header_filename': lambda: _pretty_header_filename(self.opt.output_file),
+ 'header_protection': lambda: _pretty_hdrprotection(self.opt),
+
+ 'crc_algorithm': lambda: _pretty_algorithm(self.opt),
+ 'crc_width': lambda: _pretty_str(self.opt.width),
+ 'crc_poly': lambda: _pretty_hex(self.opt.poly, self.opt.width),
+ 'crc_reflect_in': lambda: _pretty_bool(self.opt.reflect_in),
+ 'crc_xor_in': lambda: _pretty_hex(self.opt.xor_in, self.opt.width),
+ 'crc_reflect_out': lambda: _pretty_bool(self.opt.reflect_out),
+ 'crc_xor_out': lambda: _pretty_hex(self.opt.xor_out, self.opt.width),
+ 'crc_slice_by': lambda: _pretty_str(self.opt.slice_by),
+ 'crc_table_idx_width': lambda: str(self.opt.tbl_idx_width),
+ 'crc_table_width': lambda: _pretty_str(1 << self.opt.tbl_idx_width),
+ 'crc_table_mask': lambda: _pretty_hex(self.opt.tbl_width - 1, 8),
+ 'crc_mask': lambda: _pretty_hex(self.opt.mask, self.opt.width),
+ 'crc_msb_mask': lambda: _pretty_hex(self.opt.msb_mask, self.opt.width),
+ 'crc_shift': lambda: _pretty_str(self.tbl_shift),
+
+ 'cfg_width': lambda: self.__getitem__('crc_width') if self.opt.width is not None else 'cfg->width',
+ 'cfg_poly': lambda: self.__getitem__('crc_poly') if self.opt.poly is not None else 'cfg->poly',
+ 'cfg_reflect_in': lambda: self.__getitem__('crc_reflect_in') if self.opt.reflect_in is not None else 'cfg->reflect_in',
+ 'cfg_xor_in': lambda: self.__getitem__('crc_xor_in') if self.opt.xor_in is not None else 'cfg->xor_in',
+ 'cfg_reflect_out': lambda: self.__getitem__('crc_reflect_out') if self.opt.reflect_out is not None else 'cfg->reflect_out',
+ 'cfg_xor_out': lambda: self.__getitem__('crc_xor_out') if self.opt.xor_out is not None else 'cfg->xor_out',
+ 'cfg_table_idx_width': lambda: self.__getitem__('crc_table_idx_width') if self.opt.tbl_idx_width is not None else 'cfg->table_idx_width',
+ 'cfg_table_width': lambda: self.__getitem__('crc_table_width') if self.opt.tbl_width is not None else 'cfg->table_width',
+ 'cfg_mask': lambda: self.__getitem__('crc_mask') if self.opt.mask is not None else 'cfg->crc_mask',
+ 'cfg_msb_mask': lambda: self.__getitem__('crc_msb_mask') if self.opt.msb_mask is not None else 'cfg->msb_mask',
+ 'cfg_shift': lambda: self.__getitem__('crc_shift') if self.tbl_shift is not None else 'cfg->crc_shift',
+ 'cfg_poly_shifted': lambda: '('+self.__getitem__('cfg_poly')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_poly'),
+ 'cfg_mask_shifted': lambda: '('+self.__getitem__('cfg_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_mask'),
+ 'cfg_msb_mask_shifted': lambda: '('+self.__getitem__('cfg_msb_mask')+' << '+self.__getitem__('cfg_shift')+')' if self.tbl_shift is None or self.tbl_shift > 0 else self.__getitem__('cfg_msb_mask'),
+
+ 'c_bool': lambda: 'int' if self.opt.c_std == 'C89' else 'bool',
+ 'c_true': lambda: '1' if self.opt.c_std == 'C89' else 'true',
+ 'c_false': lambda: '0' if self.opt.c_std == 'C89' else 'false',
+
+ 'underlying_crc_t': lambda: _get_underlying_crc_t(self.opt),
+ 'crc_t': lambda: self.opt.symbol_prefix + 't',
+ 'cfg_t': lambda: self.opt.symbol_prefix + 'cfg_t',
+ 'crc_reflect_function': lambda: self.opt.symbol_prefix + 'reflect',
+ 'crc_table_gen_function': lambda: self.opt.symbol_prefix + 'table_gen',
+ 'crc_init_function': lambda: self.opt.symbol_prefix + 'init',
+ 'crc_update_function': lambda: self.opt.symbol_prefix + 'update',
+ 'crc_finalize_function': lambda: self.opt.symbol_prefix + 'finalize',
+
+ 'crc_init_value': lambda: _get_init_value(self.opt),
+ 'crc_table_init': lambda: _get_table_init(self.opt),
+ })
+
+ def __getitem__(self, key):
+ """
+ Return the value for the requested key
+ """
+ if key in self.cache:
+ return self.cache[key]
+ if key not in self.generator:
+ raise KeyError(key)
+ generator = self.generator[key]
+ val = self.generator[key]()
+ self.cache[key] = val
+ return val
+
+ def __setitem__(self, key, value):
+ self.generator[key] = value
+
+ def __delitem__(self, key):
+ del self.generator[key]
+
+ def __iter__(self):
+ return iter(self.generator)
+
+ def __len__(self):
+ return len(self.generator)
+
+
+
+def _pretty_str(value):
+ """
+ Return a value of width bits as a pretty string.
+ """
+ if value is None:
+ return 'Undefined'
+ return str(value)
+
+
+def _pretty_hex(value, width=None):
+ """
+ Return a value of width bits as a pretty hexadecimal formatted string.
+ """
+ if value is None:
+ return 'Undefined'
+ if width is None:
+ return '{0:#x}'.format(value)
+ width = (width + 3) // 4
+ hex_str = "{{0:#0{0:d}x}}".format(width + 2)
+ return hex_str.format(value)
+
+
+def _pretty_bool(value):
+ """
+ Return a boolen value of width bits as a pretty formatted string.
+ """
+ if value is None:
+ return 'Undefined'
+ return 'True' if value else 'False'
+
+
+def _pretty_algorithm(opt):
+ """
+ Return the algorithm name.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ return 'bit-by-bit'
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ return 'bit-by-bit-fast'
+ elif opt.algorithm == opt.algo_table_driven:
+ return 'table-driven'
+ else:
+ return 'UNDEFINED'
+
+def _pretty_header_filename(filename):
+ """
+ Return the sanitized filename of a header file.
+ """
+ if filename is None:
+ return 'pycrc_stdout.h'
+ filename = os.path.basename(filename)
+ if filename[-2:] == '.c':
+ return filename[0:-1] + 'h'
+ else:
+ return filename + '.h'
+
+
+def _pretty_hdrprotection(opt):
+ """
+ Return the name of a C header protection (e.g. CRC_IMPLEMENTATION_H).
+ """
+ if opt.output_file is None:
+ filename = 'pycrc_stdout'
+ else:
+ filename = os.path.basename(opt.output_file)
+ out_str = ''.join([s.upper() if s.isalnum() else '_' for s in filename])
+ return out_str
+
+
+def _get_underlying_crc_t(opt):
+ """
+ Return the C type of the crc_t typedef.
+ """
+ # pylint: disable=too-many-return-statements, too-many-branches
+
+ if opt.crc_type is not None:
+ return opt.crc_type
+ if opt.c_std == 'C89':
+ if opt.width is None:
+ return 'unsigned long int'
+ if opt.width <= 8:
+ return 'unsigned char'
+ elif opt.width <= 16:
+ return 'unsigned int'
+ else:
+ return 'unsigned long int'
+ else: # C99
+ if opt.width is None:
+ return 'unsigned long long int'
+ if opt.width <= 8:
+ return 'uint_fast8_t'
+ elif opt.width <= 16:
+ return 'uint_fast16_t'
+ elif opt.width <= 32:
+ return 'uint_fast32_t'
+ elif opt.width <= 64:
+ return 'uint_fast64_t'
+ elif opt.width <= 128:
+ return 'uint_fast128_t'
+ else:
+ return 'uintmax_t'
+
+
+def _get_init_value(opt):
+ """
+ Return the init value of a C implementation, according to the selected
+ algorithm and to the given options.
+ If no default option is given for a given parameter, value in the cfg_t
+ structure must be used.
+ """
+ if opt.algorithm == opt.algo_bit_by_bit:
+ if opt.xor_in is None or opt.width is None or opt.poly is None:
+ return None
+ crc = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+ init = crc.nondirect_init
+ elif opt.algorithm == opt.algo_bit_by_bit_fast:
+ if opt.xor_in is None:
+ return None
+ init = opt.xor_in
+ elif opt.algorithm == opt.algo_table_driven:
+ if opt.reflect_in is None or opt.xor_in is None or opt.width is None:
+ return None
+ if opt.poly is None:
+ poly = 0
+ else:
+ poly = opt.poly
+ crc = Crc(
+ width=opt.width, poly=poly,
+ reflect_in=opt.reflect_in, xor_in=opt.xor_in,
+ reflect_out=opt.reflect_out, xor_out=opt.xor_out,
+ table_idx_width=opt.tbl_idx_width)
+ if opt.reflect_in:
+ init = crc.reflect(crc.direct_init, opt.width)
+ else:
+ init = crc.direct_init
+ else:
+ init = 0
+ return _pretty_hex(init, opt.width)
+
+
+def _get_simple_table(opt, crc_tbl, values_per_line, format_width, indent):
+ """
+ Get one CRC table, formatted as string with appropriate indenting and
+ line breaks.
+ """
+ out = ""
+ for i in range(opt.tbl_width):
+ if i % values_per_line == 0:
+ out += " " * indent
+ tbl_val = _pretty_hex(crc_tbl[i], format_width)
+ if i == (opt.tbl_width - 1):
+ out += "{0:s}".format(tbl_val)
+ elif i % values_per_line == (values_per_line - 1):
+ out += "{0:s},\n".format(tbl_val)
+ else:
+ out += "{0:s}, ".format(tbl_val)
+ return out
+
+
+def _get_table_init(opt): # TODO: change to return a list
+ """
+ Return the precalculated CRC table for the table_driven implementation.
+ """
+ if opt.algorithm != opt.algo_table_driven:
+ return "0"
+ if opt.width is None or opt.poly is None or opt.reflect_in is None:
+ return "0"
+ crc = Crc(
+ width=opt.width, poly=opt.poly,
+ reflect_in=opt.reflect_in,
+ xor_in=0, reflect_out=False, xor_out=0, # set unimportant variables to known values
+ table_idx_width=opt.tbl_idx_width,
+ slice_by=opt.slice_by)
+ crc_tbl = crc.gen_table()
+ if opt.width > 32:
+ values_per_line = 4
+ elif opt.width >= 16:
+ values_per_line = 8
+ else:
+ values_per_line = 16
+ format_width = max(opt.width, 8)
+ if opt.slice_by == 1:
+ indent = 4
+ else:
+ indent = 8
+
+ out = [''] * opt.slice_by
+ for i in range(opt.slice_by):
+ out[i] = _get_simple_table(opt, crc_tbl[i], values_per_line, format_width, indent)
+ fixed_indent = ' ' * (indent - 4)
+ out = '{0:s}{{\n'.format(fixed_indent) + \
+ '\n{0:s}}},\n{0:s}{{\n'.format(fixed_indent).join(out) + \
+ '\n{0:s}}}'.format(fixed_indent)
+ if opt.slice_by == 1:
+ return out
+ return '{\n' + out + '\n}'
+
+
+def _tbl_shift(opt):
+ """
+ Return the table shift value
+ """
+ if opt.algorithm == opt.algo_table_driven and (opt.width is None or opt.width < 8):
+ if opt.width is None:
+ return None
+ else:
+ return 8 - opt.width
+ else:
+ return 0
+