./pycrc-0.10.0/0000755000175000017500000000000014331517447010706 5ustar tptp./pycrc-0.10.0/test/0000755000175000017500000000000014331517447011665 5ustar tptp./pycrc-0.10.0/test/test_codegen.py0000644000175000017500000001651114331517447014706 0ustar tptp#!/usr/bin/env python3 import logging import os import tempfile import subprocess import itertools import pytest from src.pycrc.models import CrcModels from src.pycrc.algorithms import Crc LOGGER = logging.getLogger(__name__) use_algo_bit_by_bit = True use_algo_bit_by_bit_fast = True use_algo_table_driven = True use_algo_table_slice = True use_c89 = True class TestCodeGen: @pytest.mark.skipif(not use_algo_bit_by_bit, reason='bbb tests disabled') def test_models_bbb_c99(self): compile_and_test_models('bbb', 'c99') @pytest.mark.skipif(not use_c89, reason='c89 tests disabled') @pytest.mark.skipif(not use_algo_bit_by_bit, reason='bbb tests disabled') def test_models_bbb_c89(self): compile_and_test_models('bbb', 'c89') @pytest.mark.skipif(not use_algo_bit_by_bit_fast, reason='bbf tests disabled') def test_models_bbf_c99(self): compile_and_test_models('bbf', 'c99') @pytest.mark.skipif(not use_c89, reason='c89 tests disabled') @pytest.mark.skipif(not use_algo_bit_by_bit_fast, reason='bbf tests disabled') def test_models_bbf_c89(self): compile_and_test_models('bbf', 'c89') @pytest.mark.skipif(not use_algo_table_driven, reason='tbl tests disabled') def test_models_tbl_c99(self): compile_and_test_models('tbl', 'c99') @pytest.mark.skipif(not use_c89, reason='c89 tests disabled') @pytest.mark.skipif(not use_algo_table_driven, reason='tbl tests disabled') def test_models_tbl_c89(self): compile_and_test_models('tbl', 'c89') @pytest.mark.skipif(not use_algo_table_driven, reason='tbl tests disabled') @pytest.mark.skipif(not use_algo_table_slice, reason='tbl slice tests disabled') def test_models_tbl_sb_c99(self): compile_and_test_models('tbl', 'c99', ['--slice-by', '4']) compile_and_test_models('tbl', 'c99', ['--slice-by', '8']) compile_and_test_models('tbl', 'c99', ['--slice-by', '16']) # --slice-by not supported with C89 @pytest.mark.skipif(not use_algo_table_driven, reason="tbl tests disabled") def test_incomplete_models_tbl_c99(self): params = ['width', 'poly', 'xor_in', 'reflect_in', 'xor_out', 'reflect_out'] for n in range(len(params)): for c in itertools.combinations(params, n): compile_and_test_incomplete_models('tbl', 'c99', c) def test_special_cases(self): compile_and_run_special_cases() def test_variable_width(self): compile_and_run_variable_width('bbb', 'c99') compile_and_run_variable_width('bbf', 'c99') compile_and_run_variable_width('tbl', 'c99') def run_cmd(cmd): LOGGER.info(' '.join(cmd)) ret = subprocess.run(cmd, check=True, capture_output=True) return ret def run_pycrc(args): ret = run_cmd(['python3', 'src/pycrc.py'] + args) return ret.stdout.decode('utf-8').rstrip() def gen_src(tmpdir, args, name): src_h = os.path.join(tmpdir, f'{name}.h') gen = ['--generate', 'h', '-o', src_h] run_pycrc(gen + args) src_c = os.path.join(tmpdir, f'{name}.c') gen = ['--generate', 'c-main', '-o', src_c] run_pycrc(gen + args) def compile_and_run(tmpdir, compile_args, run_args, name, check): gen_src(tmpdir, compile_args, name) binary = os.path.join(tmpdir, 'a.out') compile_src(binary, os.path.join(tmpdir, name + '.c')) run_and_check_res([binary] + run_args, check) def compile_and_test_models(algo, cstd, opt_args=[]): with tempfile.TemporaryDirectory(prefix='pycrc-test.') as tmpdir: for m in CrcModels().models: # Don't test width > 32 for C89, as I don't know how to ask for an data type > 32 bits. if cstd == 'c89' and m['width'] > 32: continue args = args_from_model(m) args += ['--algorithm', algo, '--std', cstd] args += opt_args compile_and_run(tmpdir, args, [], m['name'], m['check']) def compile_and_test_incomplete_models(algo, cstd, erase_params=[]): if cstd == 'c89': pytest.skip('C89 not supported') model = CrcModels().get_params('crc-32') with tempfile.TemporaryDirectory(prefix='pycrc-test.') as tmpdir: for algo in ['bbb', 'bbf', 'tbl']: m = dict(model) for param in erase_params: del m[param] args = args_from_model(m) args += ['--algorithm', algo, '--std', cstd] run_args = args_from_model({param: model[param] for param in erase_params}) compile_and_run(tmpdir, args, run_args, f'{m["name"]}_incomplete', m['check']) def compile_and_run_special_cases(): with tempfile.TemporaryDirectory(prefix='pycrc-test.') as tmpdir: crc_5_args = ['--model=crc-5', '--reflect-in=0', '--algorithm', 'table-driven'] compile_and_run(tmpdir, crc_5_args + ['--table-idx-width=8'], [], 'special', 0x01) compile_and_run(tmpdir, crc_5_args + ['--table-idx-width=4'], [], 'special', 0x01) compile_and_run(tmpdir, crc_5_args + ['--table-idx-width=2'], [], 'special', 0x01) def compile_and_run_variable_width(algo, cstd): check_str = "123456789" models = CrcModels() m = models.get_params('crc-64-jones') with tempfile.TemporaryDirectory(prefix='pycrc-test.') as tmpdir: for width in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64]: mask = (1 << width) - 1 mw = { 'width': width, 'poly': m['poly'] & mask, 'reflect_in': m['reflect_in'], 'xor_in': m['xor_in'] & mask, 'reflect_out': m['reflect_out'], 'xor_out': m['xor_out'] & mask, } args = [ '--width', '{:d}'.format(mw['width']), '--poly', '{:#x}'.format(mw['poly']), '--xor-in', '{:#x}'.format(mw['xor_in']), '--reflect-in', '{:d}'.format(mw['reflect_in']), '--xor-out', '{:#x}'.format(mw['xor_out']), '--reflect-out', '{:d}'.format(mw['reflect_out']), ] reference = Crc(width=mw['width'], poly=mw['poly'], reflect_in=mw['reflect_in'], xor_in=mw['xor_in'], reflect_out=mw['reflect_out'], xor_out=mw['xor_out']) check = reference.bit_by_bit_fast(check_str) compile_and_run(tmpdir, ['--algorithm', algo, '--std', cstd] + args, [], 'var_width', check) def run_and_check_res(cmd, expected_crc): res = run_cmd(cmd).stdout.decode('utf-8').rstrip() assert res[:2] == '0x' assert int(res, 16) == expected_crc def compile_src(out_file, src_file, cstd='c99'): run_cmd(['cc', '-W', '-Wall', '-pedantic', '-Werror', f'-std={cstd}', '-o', out_file, src_file]) def args_from_model(m): args = [] if 'width' in m: args += ['--width', f'{m["width"]:d}'] if 'poly' in m: args += ['--poly', f'{m["poly"]:#x}'] if 'xor_in' in m: args += ['--xor-in', f'{m["xor_in"]:#x}'] if 'reflect_in' in m: args += ['--reflect-in', f'{m["reflect_in"]}'] if 'xor_out' in m: args += ['--xor-out', f'{m["xor_out"]:#x}'] if 'reflect_out' in m: args += ['--reflect-out', f'{m["reflect_out"]}'] return args ./pycrc-0.10.0/test/test_algorithms.py0000644000175000017500000000465314331517447015457 0ustar tptp#!/usr/bin/env python3 import logging from src.pycrc.models import CrcModels from src.pycrc.algorithms import Crc LOGGER = logging.getLogger(__name__) def check_crc(algo, check_str, expected_crc=None): res_bbb = algo.bit_by_bit(check_str) res_bbf = algo.bit_by_bit_fast(check_str) res_tbl = algo.table_driven(check_str) LOGGER.info(f"Crc(width={algo.width:#x}, poly={algo.poly:#x}, " f"reflect_in={algo.reflect_in:#x}, xor_in={algo.xor_in:#x}, " f"reflect_out={algo.reflect_out:#x}, xor_out={algo.xor_out:#x}), " f"expected_crc={expected_crc}, " f"bbb={res_bbb:#x}, bbf={res_bbf:#x}, tbl={res_tbl:#x}") if expected_crc is not None: assert res_bbb == res_bbf == res_tbl == expected_crc assert res_bbb == res_bbf == res_tbl def test_all_models_with_check_input(): """ Test all models using the basic check sequence. """ check_str = '123456789' for m in CrcModels().models: algo = Crc(width=m['width'], poly=m['poly'], reflect_in=m['reflect_in'], xor_in=m['xor_in'], reflect_out=m['reflect_out'], xor_out=m['xor_out']) check_crc(algo, check_str, m['check']) def test_all_models_with_cornercase_input(): """ Use corner case input strings """ for m in CrcModels().models: algo = Crc(width=m['width'], poly=m['poly'], reflect_in=m['reflect_in'], xor_in=m['xor_in'], reflect_out=m['reflect_out'], xor_out=m['xor_out']) for check_str in "", b"", b"\0", b"\1", b"\0\0\0\0", b"\xff": check_crc(algo, check_str) def test_other_models(): """ Test random parameters. """ check_str = '123456789' for width in [5, 8, 16, 32, 65, 513]: mask = ((1 << width) - 1) for poly in [0x8005, 0x4c11db7, 0xa5a5a5a5]: poly &= mask for reflect_in in [0, 1]: for reflect_out in [0, 1]: for xor_in in [0x0, 0x1, 0x5a5a5a5a]: xor_in &= mask for xor_out in [0x0, 0x1, 0x5a5a5a5a]: xor_out &= mask algo = Crc(width=width, poly=poly, reflect_in=reflect_in, xor_in=xor_in, reflect_out=reflect_out, xor_out=xor_out) check_crc(algo, check_str) ./pycrc-0.10.0/test/__init__.py0000644000175000017500000000000014331517447013764 0ustar tptp./pycrc-0.10.0/test/main.c0000644000175000017500000002042414331517447012757 0ustar tptp// Copyright (c) 2006-2013 Thomas Pircher // // 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. #include "crc.h" #include #include #include #include #include #include static bool atob(const char *str); static crc_t xtoi(const char *str); static int get_config(int argc, char *argv[], crc_cfg_t *cfg); #if CRC_ALGO_BIT_BY_BIT static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc); static crc_t crc_reflect(crc_t data, size_t data_len); #endif static bool verbose = false; static unsigned char str[256] = "123456789"; bool atob(const char *str) { if (!str) { return 0; } if (isdigit(str[0])) { return (bool)atoi(str); } if (tolower(str[0]) == 't') { return true; } return false; } crc_t xtoi(const char *str) { crc_t ret = 0; if (!str) { return 0; } if (str[0] == '0' && tolower(str[1]) == 'x') { str += 2; while (*str) { if (isdigit(*str)) ret = 16 * ret + *str - '0'; else if (isxdigit(*str)) ret = 16 * ret + tolower(*str) - 'a' + 10; else return ret; str++; } } else if (isdigit(*str)) { while (*str) { if (isdigit(*str)) ret = 10 * ret + *str - '0'; else return ret; str++; } } return ret; } int get_config(int argc, char *argv[], crc_cfg_t *cfg) { int c; int option_index; static struct option long_options[] = { {"width", 1, 0, 'w'}, {"poly", 1, 0, 'p'}, {"reflect-in", 1, 0, 'n'}, {"xor-in", 1, 0, 'i'}, {"reflect-out", 1, 0, 'u'}, {"xor-out", 1, 0, 'o'}, {"verbose", 0, 0, 'v'}, {"check-string", 1, 0, 's'}, {"table-idx-with", 1, 0, 't'}, {0, 0, 0, 0} }; while (1) { option_index = 0; c = getopt_long(argc, argv, "w:p:ni:uo:v", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf ("\n"); case 'w': cfg->width = atoi(optarg); break; case 'p': cfg->poly = xtoi(optarg); break; case 'n': cfg->reflect_in = atob(optarg); break; case 'i': cfg->xor_in = xtoi(optarg); break; case 'u': cfg->reflect_out = atob(optarg); break; case 'o': cfg->xor_out = xtoi(optarg); break; case 's': memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str)); str[sizeof(str) - 1] = '\0'; break; case 'v': verbose = true; break; case 't': // ignore --table_idx_width option break; case '?': return -1; case ':': fprintf(stderr, "missing argument to option %c\n", c); return -1; default: fprintf(stderr, "unhandled option %c\n", c); return -1; } } 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; cfg->poly &= cfg->crc_mask; cfg->xor_in &= cfg->crc_mask; cfg->xor_out &= cfg->crc_mask; return 0; } #if CRC_ALGO_BIT_BY_BIT crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc) { crc_t result; unsigned char data; unsigned int i; // don't verify if the width is not a multiple of 8 if (cfg->width % 8) { return 0; } if (cfg->xor_out) { crc ^= cfg->xor_out; } if (cfg->reflect_out) { crc = crc_reflect(crc, cfg->width); } result = crc_pre_final; for (i = 0; i < cfg->width / 8; i++) { data = (crc >> (cfg->width - 8 * i - 8)) & 0xff; if (cfg->reflect_in) { data = crc_reflect(data, 8); } result = crc_update(cfg, result, &data, 1); } // no crc_finalize, because if the CRC calculation is correct, result == 0. // A crc_finalize would XOR-in again some ones into the solution. // In theory the finalize function of the bit-by-bit algorithm // would also loop over cfg->width zero bits, but since // a) result == 0, and // b) input data == 0 // the output would always be zero return result; } crc_t crc_reflect(crc_t data, size_t data_len) { unsigned int i; crc_t ret; ret = 0; for (i = 0; i < data_len; i++) { if (data & 0x01) { ret = (ret << 1) | 1; } else { ret = ret << 1; } data >>= 1; } return ret; } #endif // CRC_ALGO_BIT_BY_BIT int main(int argc, char *argv[]) { crc_cfg_t cfg = { 0, // width 0, // poly 0, // xor_in 0, // reflect_in 0, // xor_out 0, // reflect_out 0, // crc_mask 0, // msb_mask 0, // crc_shift }; crc_t crc; crc_t crc_test, crc_pre_final; char format[20]; int ret, i; ret = get_config(argc, argv, &cfg); if (ret == 0) { # if CRC_ALGO_TABLE_DRIVEN crc_table_gen(&cfg); # endif // CRC_ALGO_TABLE_DRIVEN crc = crc_init(&cfg); crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str)); crc = crc_finalize(&cfg, crc); # if CRC_ALGO_BIT_BY_BIT if (crc_verify(&cfg, crc_pre_final, crc) != 0) { fprintf(stderr, "error: crc verification failed\n"); return 1; } # endif // calculate the checksum again, but this time loop over the input // bytes one-by-one. crc_test = crc_init(&cfg); for (i = 0; str[i]; i++) { crc_test = crc_update(&cfg, crc_test, str + i, 1); } crc_test = crc_finalize(&cfg, crc_test); if (crc_test != crc) { fprintf(stderr, "error: crc loop verification failed\n"); return 1; } if (verbose) { snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4); printf("%-16s = %d\n", "width", (unsigned int)cfg.width); printf(format, "poly", (unsigned int)cfg.poly); printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false"); printf(format, "xor_in", cfg.xor_in); printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false"); printf(format, "xor_out", (unsigned int)cfg.xor_out); printf(format, "crc_mask", (unsigned int)cfg.crc_mask); printf(format, "msb_mask", (unsigned int)cfg.msb_mask); } printf("0x%llx\n", (unsigned long long int)crc); } return !ret; } ./pycrc-0.10.0/test/check_files.sh0000755000175000017500000000605714331517447014473 0ustar tptp#!/bin/sh set -e PYCRC=`dirname $0`/../src/pycrc.py outdir_old="/tmp/pycrc_out" outdir_new="/tmp/pycrc_new" tarfile="pycrc_files.tar.gz" usage() { echo >&2 "usage: $0 [OPTIONS]" echo >&2 "" echo >&2 "with OPTIONS in" echo >&2 " -c check the generated output" echo >&2 " -g generate the database" echo >&2 " -n no cleanup: don't delete the directories with the generated code" echo >&2 " -h this help message" } opt_check=off opt_no_cleanup=off opt_generate=off while getopts cgnh opt; do case "$opt" in c) opt_check=on;; g) opt_generate=on;; n) opt_no_cleanup=on;; h) usage exit 0 ;; \?) usage # unknown flag exit 1 ;; esac done shift `expr $OPTIND - 1` if [ -e "$outdir_old" ]; then echo >&2 "Output directory $outdir_old exists!" exit 1 fi if [ -e "$outdir_new" ]; then echo >&2 "Output directory $outdir_new exists!" exit 1 fi cleanup() { if [ "$opt_no_cleanup" = "on" ]; then echo "No cleanup. Please delete $outdir_old and $outdir_new when you're done" else rm -rf "$outdir_old" "$outdir_new" fi } trap cleanup 0 1 2 3 15 generate() { outfile="$1" shift $PYCRC "$@" -o "${outfile}" sed -i -e 's/Generated on ... ... .. ..:..:.. ..../Generated on XXX XXX XX XX:XX:XX XXXX/; s/by pycrc v[0-9.]*/by pycrc vXXX/;' "${outfile}" } populate() { outdir=$1 mkdir -p "$outdir" models=`PYTHONPATH=.. python3 -c 'import src.pycrc.models as m; print(" ".join(m.CrcModels().names()))'` for model in "undefined" $models; do for algo in "bbb" "bbf" "tbl"; do for cstd in c98 c99; do if [ "$model" = "undefined" ]; then mod_opt= else mod_opt="--model=${model}" fi generate "${outdir}/${model}_${algo}_${cstd}.h" --generate=h --algorithm=${algo} $mod_opt generate "${outdir}/${model}_${algo}_${cstd}.c" --generate=c --algorithm=${algo} $mod_opt done done done algo=tbl for model in crc-32; do for slice in 4 8 16; do for cstd in c98 c99; do generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.h" --generate=h --algorithm=${algo} --model=${model} --slice-by ${slice} generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.c" --generate=c --algorithm=${algo} --model=${model} --slice-by ${slice} done done done } do_check() { tar xzf "$tarfile" -C "`dirname $outdir_new`" populate "$outdir_new" diff -ru "$outdir_old" "$outdir_new" } if [ "$opt_check" = "on" ]; then if [ ! -f "$tarfile" ]; then echo >&2 "Can't find tarfile $tarfile" exit 1 fi do_check fi if [ "$opt_generate" = "on" ]; then populate "$outdir_old" dirname="`dirname $outdir_old`" basename="`basename $outdir_old`" tar czf "$tarfile" -C "$dirname" "$basename" fi ./pycrc-0.10.0/test/performance.sh0000755000175000017500000001112414331517447014524 0ustar tptp#!/bin/sh set -e PYCRC=`dirname $0`/../src/pycrc.py cleanup() { rm -f a.out performance.c crc_bbb.[ch] crc_bbf.[ch] crc_tb[l4].[ch] crc_sb4.[ch] } trap cleanup 0 1 2 3 15 model=crc-32 prefix=bbb $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit prefix=bbf $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit-fast $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit-fast prefix=tbl $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven prefix=tb4 $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --table-idx-width 4 $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --table-idx-width 4 prefix=sb4 $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --slice-by 4 $PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --slice-by 4 print_main() { cat < #include #include #include #include #include #define NUM_RUNS (128*256*256) unsigned char buf[1024]; void test_bbb(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); void test_bbf(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); void test_tbl(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); void test_tb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); void test_sb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec); /** * Print results. * * \param dsc Description of the test * \param buflen Length of one buffer * \param num_runs Number of runs over that buffer * \param t_user user time * \param t_sys system time * \return void *****************************************************************************/ void show_times(const char *dsc, size_t buflen, size_t num_runs, double t_user) { double mbps = (((double)buflen) * num_runs)/(1024*1024*t_user); printf("%s of %ld bytes (%ld * %ld)\n", dsc, (long)buflen*num_runs, (long)buflen, (long)num_runs); printf("%13s: %7.3f s %13s: %7.3f MiB/s\n", "user time", t_user, "throughput", mbps); printf("\n"); } /** * C main function. * * \retval 0 on success * \retval 1 on failure *****************************************************************************/ int main(void) { unsigned int i; long int clock_per_sec; for (i = 0; i < sizeof(buf); i++) { buf[i] = (unsigned char)rand(); } clock_per_sec = sysconf(_SC_CLK_TCK); // bit-by-bit test_bbb(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec); // bit-by-bit-fast test_bbf(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec); // table-driven test_tbl(buf, sizeof(buf), NUM_RUNS, clock_per_sec); // table-driven idx4 test_tb4(buf, sizeof(buf), NUM_RUNS / 2, clock_per_sec); // table-driven slice-by 4 test_sb4(buf, sizeof(buf), NUM_RUNS, clock_per_sec); return 0; } EOF } print_routine() { algo=$1 prefix=$2 cat < performance.c print_routine "bit-by-bit" bbb >> performance.c print_routine "bit-by-bit-fast" bbf >> performance.c print_routine "table-driven" tbl >> performance.c print_routine "table-driven idx4" tb4 >> performance.c print_routine "table-driven sb4" sb4 >> performance.c cc -W -Wall -O3 crc_bbb.c crc_bbf.c crc_tbl.c crc_tb4.c crc_sb4.c performance.c ./a.out ./pycrc-0.10.0/test/test_cli.py0000644000175000017500000000325414331517447014051 0ustar tptp#!/usr/bin/env python3 import logging import tempfile import subprocess from src.pycrc.models import CrcModels LOGGER = logging.getLogger(__name__) class TestCli: def test_cli(self): check_bytes = b"123456789" with tempfile.NamedTemporaryFile(prefix="pycrc-test.") as f: f.write(check_bytes) f.seek(0) for m in CrcModels().models: expected_crc = m["check"] args = args_from_model(m) check_crc(["--model", m["name"]], expected_crc) check_crc(args + ["--check-string", check_bytes.decode("utf-8")], expected_crc) check_crc(args + ["--check-hexstring", ''.join([f"{i:02x}" for i in check_bytes])], expected_crc) check_crc(args + ["--check-file", f.name], expected_crc) def run_cmd(cmd): LOGGER.info(' '.join(cmd)) ret = subprocess.run(cmd, check=True, capture_output=True) return ret def run_pycrc(args): ret = run_cmd(['python3', 'src/pycrc.py'] + args) return ret.stdout.decode('utf-8').rstrip() def check_crc(args, expected_crc): res = run_pycrc(args) assert res[:2] == "0x" assert int(res, 16) == expected_crc def args_from_model(m): args = [] if 'width' in m: args += ["--width", f"{m['width']:d}"] if 'poly' in m: args += ["--poly", f"{m['poly']:#x}"] if 'xor_in' in m: args += ["--xor-in", f"{m['xor_in']:#x}"] if 'reflect_in' in m: args += ["--reflect-in", f"{m['reflect_in']}"] if 'xor_out' in m: args += ["--xor-out", f"{m['xor_out']:#x}"] if 'reflect_out' in m: args += ["--reflect-out", f"{m['reflect_out']}"] return args ./pycrc-0.10.0/doc/0000755000175000017500000000000014331525406011445 5ustar tptp./pycrc-0.10.0/doc/style-html.xsl0000644000175000017500000000107014331517447014303 0ustar tptp ./pycrc-0.10.0/doc/pycrc.xml0000644000175000017500000010047014331517447013317 0ustar tptp ]> pycrc pycrc &project_version; &author_firstname; &author_surname; Author of pycrc and this manual page. &author_email; &date; pycrc 1 pycrc a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator. python pycrc.py OPTIONS Description pycrc is a CRC reference implementation in Python and a C source code generator for parametrised CRC models. The generated C source code can be optimised for simplicity, speed or small memory footprint, as required on small embedded systems. The following operations are implemented: calculate the checksum of a string (ASCII or hex) calculate the checksum of a file generate the header and source files for a C implementation. pycrc supports the following variants of the CRC algorithm: &bit-by-bit; or &bbb;: the basic algorithm which operates individually on every bit of the augmented message (i.e. the input data with &width; zero bits added at the end). This algorithm is a straightforward implementation of the basic polynomial division and is the easiest one to understand, but it is also the slowest one among all possible variants. &bit-by-bit-fast; or &bbf;: a variation of the simple &bit-by-bit; algorithm. This algorithm still iterates over every bit of the message, but does not augment it (does not add &width; zero bits at the end). It gives the same result as the &bit-by-bit; method by carefully choosing the initial value of the algorithm. This method might be a good choice for embedded platforms, where code space is more important than execution speed. &table-driven; or &tbl;: the standard table driven algorithm. This is the fastest variant because it operates on one byte at a time, as opposed to one bit at the time. This method uses a look-up table (usually of 256 elements), which might not be acceptable for small embedded systems. The number of elements in the look-up table can be reduced with the command line switch. The value of 4 bits for the table index (16 elements in the look-up table) can be a good compromise between execution speed and code size. The option enables a variant of the &table-driven; algorithm that operates on 32 bits of data or more at a time rather than 8 bits. This can dramatically speed-up the calculation of the CRC, at the cost of increased code and data size. Note: this option is experimental and not well-tested. Check your results and please raise bugs if you find problems. Options show the program version number and exit. show this help message and exit. be more verbose; in particular, print the value of the parameters and the chosen model to stdout. STRING calculate the checksum of a string (default: 123456789). If the string contains non-ASCII characters then it will be UTF-8 decoded. STRING calculate the checksum of a hexadecimal number string. FILE calculate the checksum of a file. If the file contains non-ASCII characters then it will be UTF-8 decoded. CODE generate C source code; choose the type from {h, c, c-main, table}. STD specify the C dialect of the generated code from {C89, ANSI, C99}. ALGO choose an algorithm from {bit-by-bit, bbb, bit-by-bit-fast, bbf, table-driven, tbl, all}. MODEL choose a parameter set from {crc-5, crc-8, dallas-1-wire, crc-12-3gpp, crc-15, crc-16, crc-16-usb, crc-16-modbus, crc-16-genibus, crc-16-ccitt, r-crc-16, kermit, x-25, xmodem, zmodem, crc-24, crc-32, crc-32c, crc-32-mpeg, crc-32-bzip2, posix, jam, xfer, crc-64, crc-64-jones, crc-64-xz}. NUM use NUM bits in the &poly;. HEX use HEX as &poly;. BOOL reflect the octets in the input message. HEX use HEX as initial value. BOOL reflect the resulting checksum before applying the &xor_out; value. HEX xor the final CRC value with HEX. NUM speed-up the &table-driven; calculation by operating on NUM octets of data rather than a single octet at a time. NUM must be one of the values {4, 8, 16}. NUM use NUM bits to index the CRC table; NUM must be one of the values {1, 2, 4, 8}. override any errors about possibly unsuitable polynoms. pycrc does not allow even polynoms or polynoms that are wider than &width;. Use this option to override the error, if you know what you are doing. STRING when generating source code, use STRING as prefix to the exported C symbols. STRING when generating source code, use STRING as crc_t type. FILE when generating source code, include also FILE as header file. This option can be specified multiple times. FILE FILE write the generated code to FILE instead of stdout. The CRC Parametric Model The parametric model follows Ross N. Williams' convention described in A Painless Guide to CRC Error Detection Algorithms, often called the Rocksoft Model. Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows: &width; The number of significant bits in the CRC &poly;, excluding the most significant 1. This will also be the number of bits in the final CRC result. In previous versions of pycrc only multiples of 8 could be used as &width; for the &table-driven; algorithm. As of version 0.7.5 any value is accepted for &width; for all algorithms. &poly; The unreflected polynomial of the CRC algorithm. The &poly; may be specified in its standard form, i.e. with bit &width;+1 set to 1, but the most significant bit may also be omitted. For example, both numbers 0x18005 and 0x8005 are accepted for a 16-bit &poly;. Most polynomials used in real world applications are odd (the least significant bit is 1), but there are some good even ones. pycrc allows the use of even polynomials with the option. Some even polynomials may yield incorrect checksums depending on the used algorithm. Use at your own risk and if at all possible use a well-known MODEL above. &reflect_in; Reflect the octets of the message before processing them. A word is reflected or reversed by flipping its bits around the mid-point of the word. The most significant bit of the word is moved to the least significant position, the second-most significant bit is moved to the second-least significant position and so on. The reflected value of 0xa2 (10100010b) is 0x45 (01000101b), for example. Some CRC algorithms can be implemented more efficiently in a bit reversed version, that's why many of the standard CRC models use reflected input octets. &xor_in; The initial value (usually all 0 or all 1) for algorithms which operate on the non-augmented message, that is, any algorithm other than the &bit-by-bit; one. This value can be interpreted as a value which will be XOR-ed into the CRC register after &width; iterations of the &bit-by-bit; algorithm. This implies that the simple &bit-by-bit; algorithm must calculate the initial value using some sort of reverse CRC algorithm on the &xor_in; value. &reflect_out; Reflect the final CRC result. This operation takes place before XOR-ing the final CRC value with the &xor_out; parameter. &xor_out; A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value. This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters. It is the CRC value of the parametrised model over the string 123456789 and can be used as a sanity check for a particular CRC implementation. Code generation In the default configuration, the generated code is strict ISO C99. A minimal set of three functions are defined for each algorithm: crc_init(), crc_update() and crc_finalize(). Depending on the number of parameters given to pycrc, a different interface will be defined. A fully parametrised model has a simpler API, while the generated code for a runtime-specified implementation requires a pointer to a configuration structure as first parameter to all functions. The generated source code uses the type crc_t, which is used throughout the code to hold intermediate results and also the final CRC value. It is defined in the generated header file and its type may be overridden with the option. Fully parametrised models The prototypes of the CRC functions are normally generated by pycrc using the --generate h option. The CRC functions for a fully parametrised model will look like: #include <stdlib.h> typedef uint16_t crc_t; /* pycrc will use an appropriate size here */ crc_t crc_init crc_t crc_update crc_t crc const unsigned char *data size_t data_len crc_t crc_finalize crc_t crc The code snippet below shows how to use the generated functions. #include "pycrc_generated_crc.h" #include <stdio.h> int main(void) { static const unsigned char str1[] = "1234"; static const unsigned char str2[] = "56789"; crc_t crc; crc = crc_init(); crc = crc_update(crc, str1, sizeof(str1) - 1); crc = crc_update(crc, str2, sizeof(str2) - 1); /* more calls to crc_update... */ crc = crc_finalize(crc); printf("0x%lx\n", (long)crc); return 0; } Models with runtime-configurable parameters When the model is not fully defined then the missing parameters are stored in a structure of type crc_cfg_t. If a CRC function requires a value from the crc_cfg_t structure, then the first function argument is always a pointer to that structure. All fields of the configuration structure must be properly initialised before the first call to any CRC function. If the &width; was not specified when the code was generated, then the crc_cfg_t structure will contain three more fields: msb_mask, crc_mask and crc_shift. They are defined for performance reasons and must be initialised to the value given next to the field definition. For example, a completely undefined CRC implementation will generate a crc_cfg_t structure as below: typedef struct { unsigned int width; crc_t poly; bool reflect_in; crc_t xor_in; bool reflect_out; crc_t xor_out; // internal parameters crc_t msb_mask; // initialise as (crc_t)1u << (cfg->width - 1) crc_t crc_mask; // initialise as (cfg->msb_mask - 1) | cfg->msb_mask unsigned int crc_shift; // initialise as cfg->width < 8 ? 8 - cfg->width : 0 } crc_cfg_t; msb_mask is a bitmask with the most significant bit of a &width; bits wide data type set to 1. crc_mask is a bitmask with all bits of a &width; bits wide data type set to 1. crc_shift is a shift counter that is used when &width; is less than 8. It is the number of bits to shift the CRC register to align its top bit to a byte boundary. The file test/main.c in the source package of pycrc contains a fully featured example of how to use the generated source code. A shorter, more compact main() function can be generated with the --generate c-main option. This second variant is the better option as it will always output valid code when some of the CRC parameters are known and some are unknown during code generation. Examples Calculate the CRC-32 checksum of the string 123456789: python pycrc.py --model crc-32 --check-string 123456789 Generate the source code of the table-driven algorithm for an embedded application. The table index width of 4 bits ensures a moderate memory usage. To be precise, the size of the resulting table will be 16 * sizeof(crc_t). python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c A variant of the c target is c-main: this target will generate a simple main() function in addition to the CRC functions: python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c Generate the CRC table only: python pycrc.py --model kermit --generate table -o crc-table.txt See Also The homepage of pycrc is &project_homepage;. A list of common CRC models is at &project_models;. For a long list of known CRC models, see Greg Cook's Catalogue of Parameterised CRC Algorithms. Copyright This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International. ./pycrc-0.10.0/doc/pycrc.html0000644000175000017500000007171614331525404013465 0ustar tptppycrc

Name

pycrc — a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator.

Synopsis

python pycrc.py [OPTIONS]

Description

pycrc is a CRC reference implementation in Python and a C source code generator for parametrised CRC models. The generated C source code can be optimised for simplicity, speed or small memory footprint, as required on small embedded systems. The following operations are implemented:

  • calculate the checksum of a string (ASCII or hex)

  • calculate the checksum of a file

  • generate the header and source files for a C implementation.

pycrc supports the following variants of the CRC algorithm:

  • bit-by-bit or bbb: the basic algorithm which operates individually on every bit of the augmented message (i.e. the input data with Width zero bits added at the end). This algorithm is a straightforward implementation of the basic polynomial division and is the easiest one to understand, but it is also the slowest one among all possible variants.

  • bit-by-bit-fast or bbf: a variation of the simple bit-by-bit algorithm. This algorithm still iterates over every bit of the message, but does not augment it (does not add Width zero bits at the end). It gives the same result as the bit-by-bit method by carefully choosing the initial value of the algorithm. This method might be a good choice for embedded platforms, where code space is more important than execution speed.

  • table-driven or tbl: the standard table driven algorithm. This is the fastest variant because it operates on one byte at a time, as opposed to one bit at the time. This method uses a look-up table (usually of 256 elements), which might not be acceptable for small embedded systems. The number of elements in the look-up table can be reduced with the --table-idx-width command line switch. The value of 4 bits for the table index (16 elements in the look-up table) can be a good compromise between execution speed and code size.

    The --slice-by option enables a variant of the table-driven algorithm that operates on 32 bits of data or more at a time rather than 8 bits. This can dramatically speed-up the calculation of the CRC, at the cost of increased code and data size. Note: this option is experimental and not well-tested. Check your results and please raise bugs if you find problems.

Options

--version

show the program version number and exit.

-h , --help

show this help message and exit.

--verbose

be more verbose; in particular, print the value of the parameters and the chosen model to stdout.

--check-string=STRING

calculate the checksum of a string (default: 123456789). If the string contains non-ASCII characters then it will be UTF-8 decoded.

--check-hexstring=STRING

calculate the checksum of a hexadecimal number string.

--check-file=FILE

calculate the checksum of a file. If the file contains non-ASCII characters then it will be UTF-8 decoded.

--generate=CODE

generate C source code; choose the type from {h, c, c-main, table}.

--std=STD

specify the C dialect of the generated code from {C89, ANSI, C99}.

--algorithm=ALGO

choose an algorithm from {bit-by-bit, bbb, bit-by-bit-fast, bbf, table-driven, tbl, all}.

--model=MODEL

choose a parameter set from {crc-5, crc-8, dallas-1-wire, crc-12-3gpp, crc-15, crc-16, crc-16-usb, crc-16-modbus, crc-16-genibus, crc-16-ccitt, r-crc-16, kermit, x-25, xmodem, zmodem, crc-24, crc-32, crc-32c, crc-32-mpeg, crc-32-bzip2, posix, jam, xfer, crc-64, crc-64-jones, crc-64-xz}.

--width=NUM

use NUM bits in the Polynomial.

--poly=HEX

use HEX as Polynomial.

--reflect-in=BOOL

reflect the octets in the input message.

--xor-in=HEX

use HEX as initial value.

--reflect-out=BOOL

reflect the resulting checksum before applying the XorOut value.

--xor-out=HEX

xor the final CRC value with HEX.

--slice-by=NUM

speed-up the table-driven calculation by operating on NUM octets of data rather than a single octet at a time. NUM must be one of the values {4, 8, 16}.

--table-idx-width=NUM

use NUM bits to index the CRC table; NUM must be one of the values {1, 2, 4, 8}.

--force-poly

override any errors about possibly unsuitable polynoms. pycrc does not allow even polynoms or polynoms that are wider than Width. Use this option to override the error, if you know what you are doing.

--symbol-prefix=STRING

when generating source code, use STRING as prefix to the exported C symbols.

--crc-type=STRING

when generating source code, use STRING as crc_t type.

--include-file=FILE

when generating source code, include also FILE as header file. This option can be specified multiple times.

-oFILE , --output=FILE

write the generated code to FILE instead of stdout.

The CRC Parametric Model

The parametric model follows Ross N. Williams' convention described in A Painless Guide to CRC Error Detection Algorithms, often called the Rocksoft Model. Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows:

Width

The number of significant bits in the CRC Polynomial, excluding the most significant 1. This will also be the number of bits in the final CRC result. In previous versions of pycrc only multiples of 8 could be used as Width for the table-driven algorithm. As of version 0.7.5 any value is accepted for Width for all algorithms.

Polynomial

The unreflected polynomial of the CRC algorithm.

The Polynomial may be specified in its standard form, i.e. with bit Width+1 set to 1, but the most significant bit may also be omitted. For example, both numbers 0x18005 and 0x8005 are accepted for a 16-bit Polynomial.

Most polynomials used in real world applications are odd (the least significant bit is 1), but there are some good even ones. pycrc allows the use of even polynomials with the --force-poly option. Some even polynomials may yield incorrect checksums depending on the used algorithm. Use at your own risk and if at all possible use a well-known MODEL above.

ReflectIn

Reflect the octets of the message before processing them.

A word is reflected or reversed by flipping its bits around the mid-point of the word. The most significant bit of the word is moved to the least significant position, the second-most significant bit is moved to the second-least significant position and so on. The reflected value of 0xa2 (10100010b) is 0x45 (01000101b), for example.

Some CRC algorithms can be implemented more efficiently in a bit reversed version, that's why many of the standard CRC models use reflected input octets.

XorIn

The initial value (usually all 0 or all 1) for algorithms which operate on the non-augmented message, that is, any algorithm other than the bit-by-bit one. This value can be interpreted as a value which will be XOR-ed into the CRC register after Width iterations of the bit-by-bit algorithm. This implies that the simple bit-by-bit algorithm must calculate the initial value using some sort of reverse CRC algorithm on the XorIn value.

ReflectOut

Reflect the final CRC result. This operation takes place before XOR-ing the final CRC value with the XorOut parameter.

XorOut

A value (usually all bits 0 or all 1) which will be XOR-ed to the final CRC value.

Check

This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters. It is the CRC value of the parametrised model over the string 123456789 and can be used as a sanity check for a particular CRC implementation.

Code generation

In the default configuration, the generated code is strict ISO C99. A minimal set of three functions are defined for each algorithm: crc_init(), crc_update() and crc_finalize(). Depending on the number of parameters given to pycrc, a different interface will be defined. A fully parametrised model has a simpler API, while the generated code for a runtime-specified implementation requires a pointer to a configuration structure as first parameter to all functions.

The generated source code uses the type crc_t, which is used throughout the code to hold intermediate results and also the final CRC value. It is defined in the generated header file and its type may be overridden with the --crc-type option.

Fully parametrised models

The prototypes of the CRC functions are normally generated by pycrc using the --generate h option. The CRC functions for a fully parametrised model will look like:

#include <stdlib.h>
typedef uint16_t crc_t;         /* pycrc will use an appropriate size here */
                
crc_t crc_init(void); 
 
crc_t crc_update(crc_t crc,
 const unsigned char *data,
 size_t data_len);
 
crc_t crc_finalize(crc_t crc);
 

The code snippet below shows how to use the generated functions.

#include "pycrc_generated_crc.h"
#include <stdio.h>

int main(void)
{
    static const unsigned char str1[] = "1234";
    static const unsigned char str2[] = "56789";
    crc_t crc;

    crc = crc_init();
    crc = crc_update(crc, str1, sizeof(str1) - 1);
    crc = crc_update(crc, str2, sizeof(str2) - 1);
    /* more calls to crc_update... */
    crc = crc_finalize(crc);

    printf("0x%lx\n", (long)crc);
    return 0;
}
            

Models with runtime-configurable parameters

When the model is not fully defined then the missing parameters are stored in a structure of type crc_cfg_t. If a CRC function requires a value from the crc_cfg_t structure, then the first function argument is always a pointer to that structure. All fields of the configuration structure must be properly initialised before the first call to any CRC function.

If the Width was not specified when the code was generated, then the crc_cfg_t structure will contain three more fields: msb_mask, crc_mask and crc_shift. They are defined for performance reasons and must be initialised to the value given next to the field definition.

For example, a completely undefined CRC implementation will generate a crc_cfg_t structure as below:

typedef struct {
    unsigned int width;
    crc_t poly;
    bool reflect_in;
    crc_t xor_in;
    bool reflect_out;
    crc_t xor_out;

    // internal parameters
    crc_t msb_mask;             // initialise as (crc_t)1u << (cfg->width - 1)
    crc_t crc_mask;             // initialise as (cfg->msb_mask - 1) | cfg->msb_mask
    unsigned int crc_shift;     // initialise as cfg->width < 8 ? 8 - cfg->width : 0
} crc_cfg_t;
            

msb_mask is a bitmask with the most significant bit of a Width bits wide data type set to 1. crc_mask is a bitmask with all bits of a Width bits wide data type set to 1. crc_shift is a shift counter that is used when Width is less than 8. It is the number of bits to shift the CRC register to align its top bit to a byte boundary.

The file test/main.c in the source package of pycrc contains a fully featured example of how to use the generated source code. A shorter, more compact main() function can be generated with the --generate c-main option. This second variant is the better option as it will always output valid code when some of the CRC parameters are known and some are unknown during code generation.

Examples

Calculate the CRC-32 checksum of the string 123456789:

python pycrc.py --model crc-32 --check-string 123456789

Generate the source code of the table-driven algorithm for an embedded application.

The table index width of 4 bits ensures a moderate memory usage. To be precise, the size of the resulting table will be 16 * sizeof(crc_t).

python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate h -o crc.h

python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c -o crc.c

A variant of the c target is c-main: this target will generate a simple main() function in addition to the CRC functions:

python pycrc.py --model crc-16 --algorithm table-driven --table-idx-width 4 --generate c-main -o crc.c

Generate the CRC table only:

python pycrc.py --model kermit --generate table -o crc-table.txt

See Also

The homepage of pycrc is https://pycrc.org.

A list of common CRC models is at https://pycrc.org/models.html. For a long list of known CRC models, see Greg Cook's Catalogue of Parameterised CRC Algorithms.

Copyright

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International.

./pycrc-0.10.0/doc/pycrc.10000644000175000017500000004113414331525406012652 0ustar tptp'\" t .\" Title: pycrc .\" Author: Thomas Pircher .\" Generator: DocBook XSL Stylesheets v1.79.2 .\" Date: 2017-08-11 .\" Manual: pycrc .\" Source: pycrc 0.9.1 .\" Language: English .\" .TH "PYCRC" "1" "2017\-08\-11" "pycrc 0.9.1" "pycrc" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" pycrc \- a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator\&. .SH "SYNOPSIS" .HP \w'\fBpython\ pycrc\&.py\fR\ 'u \fBpython pycrc\&.py\fR [OPTIONS] .SH "DESCRIPTION" .PP \m[blue]\fBpycrc\fR\m[]\&\s-2\u[1]\d\s+2 is a CRC reference implementation in Python and a C source code generator for parametrised CRC models\&. The generated C source code can be optimised for simplicity, speed or small memory footprint, as required on small embedded systems\&. The following operations are implemented: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} calculate the checksum of a string (ASCII or hex) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} calculate the checksum of a file .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} generate the header and source files for a C implementation\&. .RE .PP pycrc supports the following variants of the CRC algorithm: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIbit\-by\-bit\fR or \fIbbb\fR: the basic algorithm which operates individually on every bit of the augmented message (i\&.e\&. the input data with \fIWidth\fR zero bits added at the end)\&. This algorithm is a straightforward implementation of the basic polynomial division and is the easiest one to understand, but it is also the slowest one among all possible variants\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIbit\-by\-bit\-fast\fR or \fIbbf\fR: a variation of the simple \fIbit\-by\-bit\fR algorithm\&. This algorithm still iterates over every bit of the message, but does not augment it (does not add \fIWidth\fR zero bits at the end)\&. It gives the same result as the \fIbit\-by\-bit\fR method by carefully choosing the initial value of the algorithm\&. This method might be a good choice for embedded platforms, where code space is more important than execution speed\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fItable\-driven\fR or \fItbl\fR: the standard table driven algorithm\&. This is the fastest variant because it operates on one byte at a time, as opposed to one bit at the time\&. This method uses a look\-up table (usually of 256 elements), which might not be acceptable for small embedded systems\&. The number of elements in the look\-up table can be reduced with the \fB\-\-table\-idx\-width\fR command line switch\&. The value of 4 bits for the table index (16 elements in the look\-up table) can be a good compromise between execution speed and code size\&. .sp The \fB\-\-slice\-by\fR option enables a variant of the \fItable\-driven\fR algorithm that operates on 32 bits of data or more at a time rather than 8 bits\&. This can dramatically speed\-up the calculation of the CRC, at the cost of increased code and data size\&. \fINote\fR: this option is experimental and not well\-tested\&. Check your results and please raise bugs if you find problems\&. .RE .sp .SH "OPTIONS" .PP \fB\-\-version\fR .RS 4 show the program version number and exit\&. .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 show this help message and exit\&. .RE .PP \fB\-\-verbose\fR .RS 4 be more verbose; in particular, print the value of the parameters and the chosen model to stdout\&. .RE .PP \fB\-\-check\-string=\fR\fISTRING\fR .RS 4 calculate the checksum of a string (default: \(lq\fI123456789\fR\(rq)\&. If the string contains non\-ASCII characters then it will be UTF\-8 decoded\&. .RE .PP \fB\-\-check\-hexstring=\fR\fISTRING\fR .RS 4 calculate the checksum of a hexadecimal number string\&. .RE .PP \fB\-\-check\-file=\fR\fIFILE\fR .RS 4 calculate the checksum of a file\&. If the file contains non\-ASCII characters then it will be UTF\-8 decoded\&. .RE .PP \fB\-\-generate=\fR\fICODE\fR .RS 4 generate C source code; choose the type from {\fIh\fR, \fIc\fR, \fIc\-main\fR, \fItable\fR}\&. .RE .PP \fB\-\-std=\fR\fISTD\fR .RS 4 specify the C dialect of the generated code from {C89, ANSI, C99}\&. .RE .PP \fB\-\-algorithm=\fR\fIALGO\fR .RS 4 choose an algorithm from {\fIbit\-by\-bit\fR, \fIbbb\fR, \fIbit\-by\-bit\-fast\fR, \fIbbf\fR, \fItable\-driven\fR, \fItbl\fR, \fIall\fR}\&. .RE .PP \fB\-\-model=\fR\fIMODEL\fR .RS 4 choose a parameter set from {\fIcrc\-5\fR, \fIcrc\-8\fR, \fIdallas\-1\-wire\fR, \fIcrc\-12\-3gpp\fR, \fIcrc\-15\fR, \fIcrc\-16\fR, \fIcrc\-16\-usb\fR, \fIcrc\-16\-modbus\fR, \fIcrc\-16\-genibus\fR, \fIcrc\-16\-ccitt\fR, \fIr\-crc\-16\fR, \fIkermit\fR, \fIx\-25\fR, \fIxmodem\fR, \fIzmodem\fR, \fIcrc\-24\fR, \fIcrc\-32\fR, \fIcrc\-32c\fR, \fIcrc\-32\-mpeg\fR, \fIcrc\-32\-bzip2\fR, \fIposix\fR, \fIjam\fR, \fIxfer\fR, \fIcrc\-64\fR, \fIcrc\-64\-jones\fR, \fIcrc\-64\-xz\fR}\&. .RE .PP \fB\-\-width=\fR\fINUM\fR .RS 4 use \fINUM\fR bits in the \fIPolynomial\fR\&. .RE .PP \fB\-\-poly=\fR\fIHEX\fR .RS 4 use \fIHEX\fR as \fIPolynomial\fR\&. .RE .PP \fB\-\-reflect\-in=\fR\fIBOOL\fR .RS 4 reflect the octets in the input message\&. .RE .PP \fB\-\-xor\-in=\fR\fIHEX\fR .RS 4 use \fIHEX\fR as initial value\&. .RE .PP \fB\-\-reflect\-out=\fR\fIBOOL\fR .RS 4 reflect the resulting checksum before applying the XorOut value\&. .RE .PP \fB\-\-xor\-out=\fR\fIHEX\fR .RS 4 xor the final CRC value with \fIHEX\fR\&. .RE .PP \fB\-\-slice\-by=\fR\fINUM\fR .RS 4 speed\-up the table\-driven calculation by operating on \fINUM\fR octets of data rather than a single octet at a time\&. \fINUM\fR must be one of the values {\fI4\fR, \fI8\fR, \fI16\fR}\&. .RE .PP \fB\-\-table\-idx\-width=\fR\fINUM\fR .RS 4 use \fINUM\fR bits to index the CRC table; \fINUM\fR must be one of the values {\fI1\fR, \fI2\fR, \fI4\fR, \fI8\fR}\&. .RE .PP \fB\-\-force\-poly\fR .RS 4 override any errors about possibly unsuitable polynoms\&. pycrc does not allow even polynoms or polynoms that are wider than Width\&. Use this option to override the error, if you know what you are doing\&. .RE .PP \fB\-\-symbol\-prefix=\fR\fISTRING\fR .RS 4 when generating source code, use \fISTRING\fR as prefix to the exported C symbols\&. .RE .PP \fB\-\-crc\-type=\fR\fISTRING\fR .RS 4 when generating source code, use \fISTRING\fR as crc_t type\&. .RE .PP \fB\-\-include\-file=\fR\fIFILE\fR .RS 4 when generating source code, include also \fIFILE\fR as header file\&. This option can be specified multiple times\&. .RE .PP \fB\-o\fR\fIFILE\fR, \fB\-\-output=\fR\fIFILE\fR .RS 4 write the generated code to \fIFILE\fR instead of stdout\&. .RE .SH "THE CRC PARAMETRIC MODEL" .PP The parametric model follows Ross N\&. Williams\*(Aq convention described in \m[blue]\fBA Painless Guide to CRC Error Detection Algorithms\fR\m[]\&\s-2\u[2]\d\s+2, often called the Rocksoft Model\&. Since most people are familiar with this kind of parameters, pycrc follows this convention, described as follows: .PP \fIWidth\fR .RS 4 The number of significant bits in the CRC \fIPolynomial\fR, excluding the most significant 1\&. This will also be the number of bits in the final CRC result\&. In previous versions of pycrc only multiples of 8 could be used as \fIWidth\fR for the \fItable\-driven\fR algorithm\&. As of version 0\&.7\&.5 any value is accepted for \fIWidth\fR for all algorithms\&. .RE .PP \fIPolynomial\fR .RS 4 The unreflected polynomial of the CRC algorithm\&. .sp The \fIPolynomial\fR may be specified in its standard form, i\&.e\&. with bit \fIWidth\fR+1 set to 1, but the most significant bit may also be omitted\&. For example, both numbers 0x18005 and 0x8005 are accepted for a 16\-bit \fIPolynomial\fR\&. .sp Most polynomials used in real world applications are odd (the least significant bit is 1), but there are some good even ones\&. pycrc allows the use of even polynomials with the \fB\-\-force\-poly\fR option\&. Some even polynomials may yield incorrect checksums depending on the used algorithm\&. Use at your own risk and if at all possible use a well\-known \fIMODEL\fR above\&. .RE .PP \fIReflectIn\fR .RS 4 Reflect the octets of the message before processing them\&. .sp A word is reflected or reversed by \(lqflipping\(rq its bits around the mid\-point of the word\&. The most significant bit of the word is moved to the least significant position, the second\-most significant bit is moved to the second\-least significant position and so on\&. The reflected value of 0xa2 (10100010b) is 0x45 (01000101b), for example\&. .sp Some CRC algorithms can be implemented more efficiently in a bit reversed version, that\*(Aqs why many of the standard CRC models use reflected input octets\&. .RE .PP \fIXorIn\fR .RS 4 The initial value (usually all 0 or all 1) for algorithms which operate on the non\-augmented message, that is, any algorithm other than the \fIbit\-by\-bit\fR one\&. This value can be interpreted as a value which will be XOR\-ed into the CRC register after \fIWidth\fR iterations of the \fIbit\-by\-bit\fR algorithm\&. This implies that the simple \fIbit\-by\-bit\fR algorithm must calculate the initial value using some sort of reverse CRC algorithm on the \fIXorIn\fR value\&. .RE .PP \fIReflectOut\fR .RS 4 Reflect the final CRC result\&. This operation takes place before XOR\-ing the final CRC value with the \fIXorOut\fR parameter\&. .RE .PP \fIXorOut\fR .RS 4 A value (usually all bits 0 or all 1) which will be XOR\-ed to the final CRC value\&. .RE .PP \fICheck\fR .RS 4 This value is not exactly a parameter of a model but it is sometimes given together with the Rocksoft Model parameters\&. It is the CRC value of the parametrised model over the string \(lq\fI123456789\fR\(rq and can be used as a sanity check for a particular CRC implementation\&. .RE .SH "CODE GENERATION" .PP In the default configuration, the generated code is strict ISO C99\&. A minimal set of three functions are defined for each algorithm: \fBcrc_init()\fR, \fBcrc_update()\fR and \fBcrc_finalize()\fR\&. Depending on the number of parameters given to pycrc, a different interface will be defined\&. A fully parametrised model has a simpler API, while the generated code for a runtime\-specified implementation requires a pointer to a configuration structure as first parameter to all functions\&. .PP The generated source code uses the type \fBcrc_t\fR, which is used throughout the code to hold intermediate results and also the final CRC value\&. It is defined in the generated header file and its type may be overridden with the \fB\-\-crc\-type\fR option\&. .SS "Fully parametrised models" .PP The prototypes of the CRC functions are normally generated by pycrc using the \fI\-\-generate h\fR option\&. The CRC functions for a fully parametrised model will look like: .sp .ft B .nf #include typedef uint16_t crc_t; /* pycrc will use an appropriate size here */ .fi .ft .HP \w'crc_t\ crc_init('u .BI "crc_t crc_init(void);" .HP \w'crc_t\ crc_update('u .BI "crc_t crc_update(crc_t\ " "crc" ", const\ unsigned\ char\ *" "data" ", size_t\ " "data_len" ");" .HP \w'crc_t\ crc_finalize('u .BI "crc_t crc_finalize(crc_t\ " "crc" ");" .PP The code snippet below shows how to use the generated functions\&. .sp .if n \{\ .RS 4 .\} .nf #include "pycrc_generated_crc\&.h" #include int main(void) { static const unsigned char str1[] = "1234"; static const unsigned char str2[] = "56789"; crc_t crc; crc = crc_init(); crc = crc_update(crc, str1, sizeof(str1) \- 1); crc = crc_update(crc, str2, sizeof(str2) \- 1); /* more calls to crc_update\&.\&.\&. */ crc = crc_finalize(crc); printf("0x%lx\en", (long)crc); return 0; } .fi .if n \{\ .RE .\} .sp .SS "Models with runtime\-configurable parameters" .PP When the model is not fully defined then the missing parameters are stored in a structure of type \fBcrc_cfg_t\fR\&. If a CRC function requires a value from the \fBcrc_cfg_t\fR structure, then the first function argument is always a pointer to that structure\&. All fields of the configuration structure must be properly initialised before the first call to any CRC function\&. .PP If the \fIWidth\fR was not specified when the code was generated, then the \fBcrc_cfg_t\fR structure will contain three more fields: \fImsb_mask\fR, \fIcrc_mask\fR and \fIcrc_shift\fR\&. They are defined for performance reasons and must be initialised to the value given next to the field definition\&. .PP For example, a completely undefined CRC implementation will generate a \fBcrc_cfg_t\fR structure as below: .sp .if n \{\ .RS 4 .\} .nf typedef struct { unsigned int width; crc_t poly; bool reflect_in; crc_t xor_in; bool reflect_out; crc_t xor_out; // internal parameters crc_t msb_mask; // initialise as (crc_t)1u << (cfg\->width \- 1) crc_t crc_mask; // initialise as (cfg\->msb_mask \- 1) | cfg\->msb_mask unsigned int crc_shift; // initialise as cfg\->width < 8 ? 8 \- cfg\->width : 0 } crc_cfg_t; .fi .if n \{\ .RE .\} .PP \fImsb_mask\fR is a bitmask with the most significant bit of a \fIWidth\fR bits wide data type set to 1\&. \fIcrc_mask\fR is a bitmask with all bits of a \fIWidth\fR bits wide data type set to 1\&. \fIcrc_shift\fR is a shift counter that is used when \fIWidth\fR is less than 8\&. It is the number of bits to shift the CRC register to align its top bit to a byte boundary\&. .PP The file test/main\&.c in the source package of pycrc contains a fully featured example of how to use the generated source code\&. A shorter, more compact main() function can be generated with the \fI\-\-generate c\-main\fR option\&. This second variant is the better option as it will always output valid code when some of the CRC parameters are known and some are unknown during code generation\&. .SH "EXAMPLES" .PP .PP Calculate the CRC\-32 checksum of the string \(lq123456789\(rq: .RS 4 \fBpython pycrc\&.py \-\-model crc\-32 \-\-check\-string 123456789\fR .RE .PP Generate the source code of the table\-driven algorithm for an embedded application\&. .RS 4 The table index width of 4 bits ensures a moderate memory usage\&. To be precise, the size of the resulting table will be 16 * sizeof(crc_t)\&. .sp \fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate h \-o crc\&.h\fR .sp \fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate c \-o crc\&.c\fR .sp A variant of the \fIc\fR target is \fIc\-main\fR: this target will generate a simple \fImain()\fR function in addition to the CRC functions: .sp \fBpython pycrc\&.py \-\-model crc\-16 \-\-algorithm table\-driven \-\-table\-idx\-width 4 \-\-generate c\-main \-o crc\&.c\fR .RE .PP Generate the CRC table only: .RS 4 \fBpython pycrc\&.py \-\-model kermit \-\-generate table \-o crc\-table\&.txt\fR .RE .SH "SEE ALSO" .PP The homepage of pycrc is \m[blue]\fBhttps://pycrc\&.org\fR\m[]\&. .PP A list of common CRC models is at \m[blue]\fBhttps://pycrc\&.org/models\&.html\fR\m[]\&. For a long list of known CRC models, see Greg Cook\*(Aqs \m[blue]\fBCatalogue of Parameterised CRC Algorithms\fR\m[]\&\s-2\u[3]\d\s+2\&. .SH "COPYRIGHT" .PP This work is licensed under a \m[blue]\fBCreative Commons Attribution\-ShareAlike 4\&.0 International\fR\m[]\&\s-2\u[4]\d\s+2\&. .SH "AUTHOR" .PP \fBThomas Pircher\fR <\&tehpeh\-web@tty1\&.net\&> .RS 4 Author of pycrc and this manual page\&. .RE .SH "NOTES" .IP " 1." 4 pycrc .RS 4 \%https://pycrc.org .RE .IP " 2." 4 A Painless Guide to CRC Error Detection Algorithms .RS 4 \%http://www.ross.net/crc/crcpaper.html .RE .IP " 3." 4 Catalogue of Parameterised CRC Algorithms .RS 4 \%http://reveng.sourceforge.net/crc-catalogue/ .RE .IP " 4." 4 Creative Commons Attribution-ShareAlike 4.0 International .RS 4 \%https://creativecommons.org/licenses/by-sa/4.0/ .RE ./pycrc-0.10.0/doc/docbook.css0000644000175000017500000000306114331525404013575 0ustar tptp /********************************/ /* start of styles in block.xsl */ .formalpara-title { font-weight: bold; } div.blockquote-title { font-weight: bold; margin-top: 1em; margin-bottom: 1em; } span.msgmain-title { font-weight: bold; } span.msgsub-title { font-weight: bold; } span.msgrel-title { font-weight: bold; } div.msglevel, div.msgorig, div.msgaud { margin-top: 1em; margin-bottom: 1em; } span.msglevel-title, span.msgorig-title, span.msgaud-title { font-weight: bold; } div.msgexplan { margin-top: 1em; margin-bottom: 1em; } span.msgexplan-title { font-weight: bold; } /* end of styles in block.xsl */ /********************************/ /********************************/ /* start of styles in autotoc.xsl */ /* end of styles in autotoc.xsl */ /********************************/ /********************************/ /* start of styles in formal.xsl */ div.figure-title { font-weight: bold; } div.example-title { font-weight: bold; } div.equation-title { font-weight: bold; } div.table-title { font-weight: bold; } div.sidebar-title { font-weight: bold; } /* end of styles in formal.xsl */ /********************************/ /********************************/ /* start of styles in verbatim.xsl */ div.programlisting { white-space: pre; font-family: monospace; } div.screen { white-space: pre; font-family: monospace; } div.synopsis { white-space: pre; font-family: monospace; } /* end of styles in verbatim.xsl */ /********************************/ /* footnote rule */ hr.footnote-hr { width: 100; } ./pycrc-0.10.0/doc/Makefile0000644000175000017500000000062414331517447013115 0ustar tptpHTML_PARAMS = style-html.xsl MAN_PARAMS = style-man.xsl source = pycrc.xml targets = $(source:.xml=.html) $(source:.xml=.1) all: $(targets) .PHONY: clean clean: $(RM) $(targets) .PHONY: check check: xmllint --valid --noout $(source) %.html: %.xml $(HTML_PARAMS) saxon-xslt -o $@ $^ %.1: %.xml $(MAN_PARAMS) saxon-xslt -o $@ $^ %.txt: %.html links -dump -no-numbering -no-references $< > $@ ./pycrc-0.10.0/doc/style-man.xsl0000644000175000017500000000033414331517447014114 0ustar tptp ./pycrc-0.10.0/src/0000755000175000017500000000000014331517447011475 5ustar tptp./pycrc-0.10.0/src/__init__.py0000644000175000017500000000000014331517447013574 0ustar tptp./pycrc-0.10.0/src/pycrc.py0000755000175000017500000000257014331517447013176 0ustar tptp#!/usr/bin/env python3 # pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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 is a simple wrapper/executable for the pycrc library.""" import sys from pycrc.main import main if __name__ == "__main__": sys.exit(main()) ./pycrc-0.10.0/src/pycrc/0000755000175000017500000000000014331517447012615 5ustar tptp./pycrc-0.10.0/src/pycrc/__main__.py0000644000175000017500000000246514331517447014716 0ustar tptp#!/usr/bin/env python # pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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()) ./pycrc-0.10.0/src/pycrc/opt.py0000644000175000017500000004566114331517447014005 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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='unknown', url='unknown'): self.program_name = progname self.version = version self.version_str = f"{progname} v{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): # noqa: C901 """ 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=f"choose a parameter set from {{{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 is not 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(f"unknown C standard {options.c_std}") undefined_params = [] if options.width is not None: self.width = options.width else: undefined_params.append("--width") if options.poly is not None: self.poly = options.poly else: undefined_params.append("--poly") if options.reflect_in is not None: self.reflect_in = options.reflect_in else: undefined_params.append("--reflect-in") if options.xor_in is not None: self.xor_in = options.xor_in else: undefined_params.append("--xor-in") if options.reflect_out is not None: self.reflect_out = options.reflect_out else: undefined_params.append("--reflect-out") if options.xor_out is not None: self.xor_out = options.xor_out else: undefined_params.append("--xor-out") if options.table_idx_width is not 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(f"unsupported table-idx-width {options.table_idx_width}") if self.poly is not 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 is not 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 is not 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 is not None: self.poly = self.poly & self.mask if self.xor_in is not None: self.xor_in = self.xor_in & self.mask if self.xor_out is not None: self.xor_out = self.xor_out & self.mask else: self.msb_mask = None self.mask = None if self.width is None or \ self.poly is None or \ self.reflect_in is None or \ self.xor_in is None or \ self.reflect_out is None or \ self.xor_out is None: self.undefined_crc_parameters = True else: self.undefined_crc_parameters = False if options.slice_by is not None: if options.slice_by in set((4, 8, 16)): self.slice_by = options.slice_by else: self.__error(f"unsupported slice-by {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(f"disabling slice-by for width {self.width}") self.slice_by = 1 if self.width < 16: self.__warning(f"disabling slice-by for width {self.width}") self.slice_by = 1 if self.width > 32: self.__warning(f"disabling slice-by for width {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 is not 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(f"unknown algorithm {options.algorithm}") if options.symbol_prefix is not None: self.symbol_prefix = options.symbol_prefix if options.include_files is not None: self.include_files = options.include_files if options.crc_type is not None: self.crc_type = options.crc_type if options.output_file is not None: self.output_file = options.output_file op_count = 0 if options.check_string is not None: self.action = self.action_check_str self.check_string = options.check_string op_count += 1 if options.check_hexstring is not None: self.action = self.action_check_hex_str self.check_string = options.check_hexstring op_count += 1 if options.check_file is not None: self.action = self.action_check_file self.check_file = options.check_file op_count += 1 if options.generate is not 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(f"don't know how to generate {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): undefined_params_str = ", ".join(undefined_params) self.__error(f"undefined parameters: Add {undefined_params_str} or use --model") self.verbose = options.verbose def __warning(self, message): """ Print a warning message to stderr. """ sys.stderr.write(f"{self.program_name}: warning: {message}\n") def __error(self, message): """ Print a error message to stderr and terminate the program. """ self.__warning(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 is not 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(f"unsupported model {value}. Supported models are: {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(f"option {opt}: invalid integer or hexadecimal value: {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(f"option {opt}: invalid boolean value: {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 ./pycrc-0.10.0/src/pycrc/models.py0000644000175000017500000002364514331517447014464 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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: import pycrc.models as cm models = cm.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(): """ 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 ./pycrc-0.10.0/src/pycrc/expr.py0000644000175000017500000002456414331517447014160 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2017 Thomas Pircher # # 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 isinstance(val, int): return Terminal(val) if isinstance(val, 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(): """ Base class for all expressions. """ def is_int(self, val=None): """Dummy function, always returns False. This is overwritten bu derived classes.""" 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 isinstance(self.val, 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 isinstance(val, 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) ./pycrc-0.10.0/src/pycrc/codegen.py0000644000175000017500000021076114331517447014602 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2017 Thomas Pircher # # 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([i.rstrip() for i 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 = [] if opt.action == opt.action_generate_h: self.content = self._code_file() + self._header_file() if opt.action == opt.action_generate_c: self.content = self._code_file() + self._c_file() if opt.action == opt.action_generate_c_main: self.content = self._code_file() + self._c_file() + self._main_file() if opt.action == opt.action_generate_table: self.content = [f'{self.sym.crc_table_init}'] def _code_file(self): """ Add code file """ out = [ Comment(self.opt, '', [ '\\file', 'Functions and types for CRC checks.', '', f'Generated on {self.sym.datetime}', f'by {self.sym.program_version}, {self.sym.program_url}', 'using the configuration:', ParamBlock(self.opt, ' ', algorithm=True), Conditional(self.opt, '', self.opt.action == self.opt.action_generate_h, [ '', f'This file defines the functions {self.sym.crc_init_function}(), {self.sym.crc_update_function}() and {self.sym.crc_finalize_function}().', '', f'The {self.sym.crc_init_function}() function returns the initial \\c crc value and must be called', f'before the first call to {self.sym.crc_update_function}().', f'Similarly, the {self.sym.crc_finalize_function}() function must be called after the last call', f'to {self.sym.crc_update_function}(), before the \\c crc is being used.', 'is being used.', '', f'The {self.sym.crc_update_function}() function can be called any number of times (including zero', f'times) in between the {self.sym.crc_init_function}() and {self.sym.crc_finalize_function}() calls.', '', 'This pseudo-code shows an example usage of the API:', '\\code{.c}', Conditional(self.opt, '', self.opt.undefined_crc_parameters, [ f'{self.sym.cfg_t} cfg = ' + '{', 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', ]), '};', ]), f'{self.sym.crc_t} crc;', 'unsigned char data[MAX_DATA_LEN];', 'size_t data_len;', '', Conditional(self.opt, '', _use_crc_table_gen(self.opt), [ f'{self.sym.crc_table_gen_function}(&cfg);', ]), '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', ]), ]), ] return out def _header_file(self): """ Add header content. """ out = [ f'#ifndef {self.sym.header_protection}', f'#define {self.sym.header_protection}', '', CodeGen(self.opt, '', _includes(self.opt)), '#include ', Conditional(self.opt, '', self.opt.c_std != 'C89', ['#include ']), Conditional(self.opt, '', _use_cfg(self.opt) and self.opt.c_std != 'C89', ['#include ']), '', '#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.', '', f'This type must be big enough to contain at least {self.sym.cfg_width} bits.', ]), f'typedef {self.sym.underlying_crc_t} {self.sym.crc_t};', 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 */', ]), f'}} {self.sym.cfg_t};', ]), 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.' ]), f'{self.sym.crc_t} {self.sym.crc_reflect_function}({self.sym.crc_t} data, size_t data_len);', ]), Conditional(self.opt, '', _use_crc_table_gen(self.opt), [ '', '', Comment(self.opt, '', [ 'Populate the private static crc table.', '', f'\\param[in] cfg A pointer to an initialised {self.sym.cfg_t} structure.', ]), f'void {self.sym.crc_table_gen_function}(const {self.sym.cfg_t} *cfg);', ]), '', '', Comment(self.opt, '', [ 'Calculate the initial crc value.', '', Conditional(self.opt, '', _use_cfg(self.opt), [ f'\\param[in] cfg A pointer to an initialised {self.sym.cfg_t} structure.', ]), '\\return The initial crc value.', ]), Conditional2(self.opt, '', _use_constant_crc_init(self.sym), [ Conditional2(self.opt, '', self.opt.c_std == 'C89', [ f'#define {self.sym.crc_init_function}() ({self.sym.crc_init_value})', ], [ 'static inline {0}'.format(_crc_init_function_def(self.opt, self.sym)), '{', f' return {self.sym.crc_init_value};', '}', ]), ], [ '{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), [ f'\\param[in] cfg A pointer to an initialised {self.sym.cfg_t} structure.', ]), '\\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), [ f'\\param[in] cfg A pointer to an initialised {self.sym.cfg_t} structure.', ]), '\\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', '', f'#endif /* {self.sym.header_protection} */', '', ] return out def _c_file(self): """ Add C file content. """ out = [ CodeGen(self.opt, '', _includes(self.opt)), f'#include "{self.sym.header_filename}" /* include the header file generated with pycrc */', '#include ', Conditional(self.opt, '', self.opt.c_std != 'C89', [ '#include ', 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 ', ]), ]), Conditional(self.opt, '', self.opt.slice_by > 1, [ '#include ', ]), Conditional(self.opt, '', _use_reflect_func(self.opt) and _use_static_reflect_func(self.opt), [ '', f'static {self.sym.crc_t} {self.sym.crc_reflect_function}({self.sym.crc_t} data, size_t data_len);', ]), '', 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 ', '#include ', Conditional(self.opt, '', self.opt.undefined_crc_parameters, [ '#include ', '#include ', ]), Conditional(self.opt, '', self.opt.c_std != 'C89', [ '#include ', ]), '#include ', '', 'static char str[256] = "123456789";', f'static {self.sym.c_bool} verbose = {self.sym.c_false};', self._getopt_template(), '', '', Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [ f'static void print_params(const {self.sym.cfg_t} *cfg)', ], [ 'static void print_params(void)', ]), '{', CodeGen(self.opt, 4*' ', [ 'char format[32];', '', Conditional2(self.opt, '', self.opt.c_std == 'C89', [ f'sprintf(format, "%%-16s = 0x%%0%dlx\\n", (unsigned int)({self.sym.cfg_width} + 3) / 4);', f'printf("%-16s = %d\\n", "width", (unsigned int){self.sym.cfg_width});', f'printf(format, "poly", (unsigned long int){self.sym.cfg_poly});', '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"')), f'printf(format, "xor_in", (unsigned long int){self.sym.cfg_xor_in});', '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"')), f'printf(format, "xor_out", (unsigned long int){self.sym.cfg_xor_out});', f'printf(format, "crc_mask", (unsigned long int){self.sym.cfg_mask});', f'printf(format, "msb_mask", (unsigned long int){self.sym.cfg_msb_mask});', ], [ f'snprintf(format, sizeof(format), "%%-16s = 0x%%0%dllx\\n", (unsigned int)({self.sym.cfg_width} + 3) / 4);', f'printf("%-16s = %d\\n", "width", (unsigned int){self.sym.cfg_width});', f'printf(format, "poly", (unsigned long long int){self.sym.cfg_poly});', '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"')), f'printf(format, "xor_in", (unsigned long long int){self.sym.cfg_xor_in});', '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"')), f'printf(format, "xor_out", (unsigned long long int){self.sym.cfg_xor_out});', f'printf(format, "crc_mask", (unsigned long long int){self.sym.cfg_mask});', f'printf(format, "msb_mask", (unsigned long long int){self.sym.cfg_msb_mask});', ]), ]), '}', '', '', 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, [ f'{self.sym.cfg_t} cfg = ' + '{', 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 */', ]), '};', ]), f'{self.sym.crc_t} crc;', '', 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), [ f'{self.sym.crc_table_gen_function}(&cfg);', ]), '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, [ '', '', f'static {self.sym.c_bool} atob(const char *str)', '{', CodeGen(self.opt, 4*' ', [ 'if (!str) {', CodeGen(self.opt, 4*' ', [ 'return 0;', ]), '}', 'if (isdigit(str[0])) {', CodeGen(self.opt, 4*' ', [ f'return ({self.sym.c_bool})atoi(str);', ]), '}', 'if (tolower(str[0]) == \'t\') {', CodeGen(self.opt, 4*' ', [ f'return {self.sym.c_true};', ]), '}', f'return {self.sym.c_false};', ]), '}', ]), 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, [ f'static int get_config(int argc, char *argv[], {self.sym.cfg_t} *cfg)', ], [ '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*' ', [ f'verbose = {self.sym.c_true};', '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, [ f'cfg->poly &= {self.sym.cfg_mask};', ]), Conditional(self.opt, '', self.opt.xor_in is None, [ f'cfg->xor_in &= {self.sym.cfg_mask};', ]), Conditional(self.opt, '', self.opt.xor_out is None, [ f'cfg->xor_out &= {self.sym.cfg_mask};', ]), '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 is None or opt.reflect_in is None: return True if opt.algorithm == opt.algo_table_driven: if opt.reflect_in and opt.reflect_out: return True if opt.reflect_in != opt.reflect_out: return True if opt.algorithm == opt.algo_bit_by_bit: if opt.reflect_in: return True if opt.reflect_out: return True if 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 if opt.reflect_out is not None and opt.algorithm == opt.algo_bit_by_bit_fast: return False 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 f'{sym.crc_t} {sym.crc_init_function}(void)' else: return f'{sym.crc_t} {sym.crc_init_function}(const {sym.cfg_t} *cfg)' 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 if 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 f'{sym.crc_t} {sym.crc_update_function}({sym.crc_t} crc, const void *data, size_t data_len)' else: return f'{sym.crc_t} {sym.crc_update_function}(const {sym.cfg_t} *cfg, {sym.crc_t} crc, const void *data, size_t data_len)' 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 if 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 if 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 f'{sym.crc_t} {sym.crc_finalize_function}({sym.crc_t} crc)' else: return f'{sym.crc_t} {sym.crc_finalize_function}(const {sym.cfg_t} *cfg, {sym.crc_t} crc)' 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() if 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() 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, [ f'Must be initialised with the {sym.crc_table_gen_function} function.', ]), ]), Conditional2(opt, '', _use_constant_crc_table(opt), [ Conditional2(opt, '', opt.slice_by > 1, [ f'static const {sym.crc_t} crc_table[{sym.crc_slice_by}][{sym.crc_table_width}] = {sym.crc_table_init};', ], [ f'static const {sym.crc_t} crc_table[{sym.crc_table_width}] = {sym.crc_table_init};', ]), ], [ f'static {sym.crc_t} crc_table[{sym.crc_table_width}];', ]), ] 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 [ '', '', f'void {sym.crc_table_gen_function}(const {sym.cfg_t} *cfg)', '{', CodeGen(opt, 4*' ', [ f'{sym.crc_t} crc;', 'unsigned int i, j;', '', f'for (i = 0; i < {sym.cfg_table_width}; i++) ' + '{', CodeGen(opt, 4*' ', [ Conditional2(opt, '', opt.reflect_in is None, [ 'if (cfg->reflect_in) {', CodeGen(opt, 4*' ', [ f'crc = {sym.crc_reflect_function}(i, {sym.cfg_table_idx_width});', ]), '} else {', CodeGen(opt, 4*' ', [ 'crc = i;', ]), '}', ], [ Conditional2(opt, '', opt.reflect_in, [ f'crc = {sym.crc_reflect_function}(i, {sym.cfg_table_idx_width});', ], [ 'crc = i;', ]), ]), 'crc <<= {0};'.format(expr.Parenthesis(expr.Add(expr.Sub(sym.cfg_width, sym.cfg_table_idx_width), sym.cfg_shift)).simplify()), f'for (j = 0; j < {sym.cfg_table_idx_width}; j++) ' + '{', CodeGen(opt, 4*' ', [ f'if (crc & {sym.cfg_msb_mask_shifted}) ' + '{', 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()), ], [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), '}', ]), Conditional(opt, '', opt.reflect_in, [ Conditional2(opt, '', 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()), ], [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), ]), '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 [ '', '', f'{sym.crc_t} {sym.crc_reflect_function}({sym.crc_t} data, size_t data_len)', '{', CodeGen(opt, 4*' ', [ 'unsigned int i;', f'{sym.crc_t} ret;', '', '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;', f'{sym.c_bool} bit;' f'{sym.crc_t} crc = {sym.cfg_xor_in};', f'for (i = 0; i < {sym.cfg_width}; i++) ' + '{', CodeGen(opt, 4*' ', [ 'bit = crc & 0x01;', 'if (bit) {', CodeGen(opt, 4*' ', [ f'crc = ((crc ^ {sym.cfg_poly}) >> 1) | {sym.cfg_msb_mask};', ]), '} else {', CodeGen(opt, 4*' ', [ 'crc >>= 1;', ]), '}', ]), '}', f'return crc & {sym.cfg_mask};', ]), Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit_fast, [ f'return {sym.cfg_xor_in} & {sym.cfg_mask};', ]), Conditional(opt, '', opt.algorithm == opt.algo_table_driven, [ Conditional2(opt, '', opt.reflect_in is None, [ f'if ({sym.cfg_reflect_in}) ' + '{', CodeGen(opt, 4*' ', [ f'return {sym.crc_reflect_function}({sym.cfg_xor_in} & {sym.cfg_mask}, {sym.cfg_width});', ]), '} else {', CodeGen(opt, 4*' ', [ f'return {sym.cfg_xor_in} & {sym.cfg_mask};', ]), '}', ], [ Conditional2(opt, '', opt.algorithm == opt.reflect_in, [ f'return {sym.crc_reflect_function}({sym.cfg_xor_in} & {sym.cfg_mask}, {sym.cfg_width});', ], [ f'return {sym.cfg_xor_in} & {sym.cfg_mask};', ]), ]), ]), ]), '}', ] 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;', f'{sym.c_bool} bit;', 'unsigned char c;', '', 'while (data_len--) {', Conditional2(opt, 4*' ', opt.reflect_in is None, [ 'if (' + sym.cfg_reflect_in + ') {', CodeGen(opt, 4*' ', [ f'c = {sym.crc_reflect_function}(*d++, 8);', ]), '} else {', CodeGen(opt, 4*' ', [ 'c = *d++;', ]), '}', ], [ Conditional2(opt, '', opt.reflect_in, [ f'c = {sym.crc_reflect_function}(*d++, 8);', ], [ 'c = *d++;', ]), ]), CodeGen(opt, 4*' ', [ 'for (i = 0; i < 8; i++) {', CodeGen(opt, 4*' ', [ Conditional2(opt, '', opt.c_std == 'C89', [ f'bit = !!(crc & {sym.cfg_msb_mask});', ], [ f'bit = crc & {sym.cfg_msb_mask};', ]), 'crc = (crc << 1) | ((c >> (7 - i)) & 0x01);', 'if (bit) {', CodeGen(opt, 4*' ', [ f'crc ^= {sym.cfg_poly};', ]), '}', ]), '}', f'crc &= {sym.cfg_mask};', ]), '}', f'return crc & {sym.cfg_mask};', ]), ] if opt.algorithm == opt.algo_bit_by_bit_fast: out += [ CodeGen(opt, 4*' ', [ 'unsigned int i;', f'{sym.crc_t} bit;', 'unsigned char c;', '', 'while (data_len--) {', CodeGen(opt, 4*' ', [ Conditional2(opt, '', opt.reflect_in is None, [ 'if (' + sym.cfg_reflect_in + ') {', CodeGen(opt, 4*' ', [ f'c = {sym.crc_reflect_function}(*d++, 8);', ]), '} 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*' ', [ 'bit = ({0}) ^ ({1});'.format(expr.And('crc', sym.cfg_msb_mask).simplify(), '(c & i) ? {0} : 0'.format(sym.cfg_msb_mask)), 'crc <<= 1;', 'if (bit) {', CodeGen(opt, 4*' ', [ f'crc ^= {sym.cfg_poly};', ]), '}', ]), '}', f'crc &= {sym.cfg_mask};' ]), '}', '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 is 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, [ f'/* Align to a multiple of {sym.crc_slice_by} bytes */', f'while (data_len && (((uintptr_t)(const void *)d) % {sym.crc_slice_by} != 0))' + ' {', 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;', f'{sym.c_bool} bit;', '', 'for (i = 0; i < ' + sym.cfg_width + '; i++) {', CodeGen(opt, 4*' ', [ Conditional2(opt, '', opt.c_std == 'C89', [ f'bit = !!(crc & {sym.cfg_msb_mask});' ], [ f'bit = crc & {sym.cfg_msb_mask};', ]), 'crc <<= 1;', 'if (bit) {', CodeGen(opt, 4*' ', [ f'crc ^= {sym.cfg_poly};', ]), '}', ]), '}', Conditional(opt, '', opt.reflect_out is None, [ 'if (' + sym.cfg_reflect_out + ') {', CodeGen(opt, 4*' ', [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), '}', ]), Conditional(opt, '', opt.reflect_out, [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), ]), 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*' ', [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), '}', ]), Conditional(opt, '', opt.reflect_out, [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), ]), ] 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*' ', [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ]), '}', ]), ] elif opt.reflect_in != opt.reflect_out: out += [ f'crc = {sym.crc_reflect_function}(crc, {sym.cfg_width});', ] 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 = f'(crc >> {sym.cfg_table_idx_width})' 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]' crc_exp = expr.And(expr.Parenthesis(expr.Xor(crc_lookup, expr.Parenthesis(expr.Shr('crc', sym.cfg_table_idx_width)))), sym.cfg_mask).simplify() out += [ Conditional2(opt, '', opt.width is None or opt.width > 8, [ f'tbl_idx = (crc ^ *d) & {sym.crc_table_mask};', ], [ 'tbl_idx = crc ^ *d;', ]), f'crc = {crc_exp};', ] else: crc_lookup = f'crc_table[tbl_idx & {sym.crc_table_mask}]' for i in range(8 // opt.tbl_idx_width): idx = expr.Xor('crc', expr.Parenthesis(expr.Shr('*d', expr.Parenthesis(expr.Mul(i, sym.cfg_table_idx_width))))).simplify() out += [ f'tbl_idx = {idx};', '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 is 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 = f'(crc << {sym.cfg_table_idx_width})' 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 = f'crc_table[tbl_idx & {sym.crc_table_mask}]' 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;', f'while (data_len >= {sym.crc_slice_by})', '{', CodeGen(opt, 4*' ', [ CodeGen(opt, None, [ '#if __BYTE_ORDER == __BIG_ENDIAN', ]), f'{sym.crc_t} d1 = *d32++ ^ le16toh(crc);', Conditional(opt, '', opt.slice_by >= 8, [ f'{sym.crc_t} d2 = *d32++;', ]), Conditional(opt, '', opt.slice_by >= 16, [ f'{sym.crc_t} d3 = *d32++;', f'{sym.crc_t} d4 = *d32++;', ]), 'crc =', CodeGen(opt, 4*' ', update_be), CodeGen(opt, None, [ '#else', ]), f'{sym.crc_t} d1 = *d32++ ^ crc;', Conditional(opt, '', opt.slice_by >= 8, [ f'{sym.crc_t} d2 = *d32++;', ]), Conditional(opt, '', opt.slice_by >= 16, [ f'{sym.crc_t} d3 = *d32++;', f'{sym.crc_t} d4 = *d32++;', ]), 'crc =', CodeGen(opt, 4*' ', update_le), CodeGen(opt, None, [ '#endif', ]), '', f'data_len -= {sym.crc_slice_by};', ]), '}', '', ] return CodeGen(opt, '', out) ./pycrc-0.10.0/src/pycrc/main.py0000644000175000017500000001700114331517447014112 0ustar tptp#!/usr/bin/env python # pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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 __version__ from pycrc.opt import Options from pycrc.algorithms import Crc import pycrc.codegen as cg import binascii import sys progname = "pycrc" url = 'https://pycrc.org' 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(f"{progname:s}: error: undefined parameters\n") 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) error |= crc is not None and bbb_crc != crc crc = bbb_crc if opt.algorithm & opt.algo_bit_by_bit_fast: bbf_crc = alg.bit_by_bit_fast(opt.check_string) error |= crc is not None and bbf_crc != crc 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) error |= crc is not None and tbl_crc != crc crc = tbl_crc if error: sys.stderr.write(f"{progname:s}: error: different checksums!\n") if opt.algorithm & opt.algo_bit_by_bit: sys.stderr.write(f" bit-by-bit: {bbb_crc:#x}\n") if opt.algorithm & opt.algo_bit_by_bit_fast: sys.stderr.write(f" bit-by-bit-fast: {bbf_crc:#x}\n") if opt.algorithm & opt.algo_table_driven: sys.stderr.write(f" table_driven: {tbl_crc:#x}\n") 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 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) # Always use the xor_in value unreflected # As in the rocksoft reference implementation register = opt.xor_in try: with open(opt.check_file, 'rb') as f: check_bytes = bytearray(f.read(4096)) while check_bytes != b"": register = crc_file_update(alg, register, check_bytes) check_bytes = bytearray(f.read(4096)) 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]): out = str(cg.File(opt, '')) if opt.output_file is None: print(out) else: write_file(opt.output_file, out) return 0 if __name__ == "__main__": sys.exit(main()) ./pycrc-0.10.0/src/pycrc/__init__.py0000644000175000017500000000111414331517447014723 0ustar tptpdef get_version(): try: import importlib.metadata return importlib.metadata.version("pycrc") except: # noqa: E722 pass try: import re import os with open(os.path.join('..', '..', 'pyproject.toml'), 'r') as file: text = file.read() pattern = re.compile(r"""^version *= *["']([^'"]*)['"]""", re.MULTILINE) m = re.search(pattern, text) if m: return m[1] except FileNotFoundError: pass return 'unknown' __version__ = get_version() __author__ = "Thomas Pircher" ./pycrc-0.10.0/src/pycrc/symtable.py0000644000175000017500000002724614331517447015022 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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(f'width: {sym.crc_width}, poly: {sym.crc_poly}') """ from pycrc.algorithms import Crc import time import os class SymbolTable: """ A class with the symbols as public members. """ def __init__(self, opt): self._opt = opt self.tbl_shift = _tbl_shift(opt) self.datetime = time.asctime() self.program_version = self._opt.version_str self.program_url = self._opt.web_address self.filename = 'pycrc_stdout' if self._opt.output_file is None else os.path.basename(self._opt.output_file) self.header_filename = _pretty_header_filename(self._opt.output_file) self.header_protection = _pretty_hdrprotection(self._opt) self.crc_algorithm = _pretty_algorithm(self._opt) self.crc_width = _pretty_str(self._opt.width) self.crc_poly = _pretty_hex(self._opt.poly, self._opt.width) self.crc_reflect_in = _pretty_bool(self._opt.reflect_in) self.crc_xor_in = _pretty_hex(self._opt.xor_in, self._opt.width) self.crc_reflect_out = _pretty_bool(self._opt.reflect_out) self.crc_xor_out = _pretty_hex(self._opt.xor_out, self._opt.width) self.crc_slice_by = _pretty_str(self._opt.slice_by) self.crc_table_idx_width = str(self._opt.tbl_idx_width) self.crc_table_width = _pretty_str(1 << self._opt.tbl_idx_width) self.crc_table_mask = _pretty_hex(self._opt.tbl_width - 1, 8) self.crc_mask = _pretty_hex(self._opt.mask, self._opt.width) self.crc_msb_mask = _pretty_hex(self._opt.msb_mask, self._opt.width) self.crc_shift = _pretty_str(self.tbl_shift) self.cfg_width = self.crc_width if self._opt.width is not None else 'cfg->width' self.cfg_poly = self.crc_poly if self._opt.poly is not None else 'cfg->poly' self.cfg_reflect_in = self.crc_reflect_in if self._opt.reflect_in is not None else 'cfg->reflect_in' self.cfg_xor_in = self.crc_xor_in if self._opt.xor_in is not None else 'cfg->xor_in' self.cfg_reflect_out = self.crc_reflect_out if self._opt.reflect_out is not None else 'cfg->reflect_out' self.cfg_xor_out = self.crc_xor_out if self._opt.xor_out is not None else 'cfg->xor_out' self.cfg_table_idx_width = self.crc_table_idx_width if self._opt.tbl_idx_width is not None else 'cfg->table_idx_width' self.cfg_table_width = self.crc_table_width if self._opt.tbl_width is not None else 'cfg->table_width' self.cfg_mask = self.crc_mask if self._opt.mask is not None else 'cfg->crc_mask' self.cfg_msb_mask = self.crc_msb_mask if self._opt.msb_mask is not None else 'cfg->msb_mask' self.cfg_shift = self.crc_shift if self.tbl_shift is not None else 'cfg->crc_shift' self.cfg_poly_shifted = f'({self.cfg_poly} << {self.cfg_shift})' if self.tbl_shift is None or self.tbl_shift > 0 else self.cfg_poly self.cfg_mask_shifted = f'({self.cfg_mask} << {self.cfg_shift})' if self.tbl_shift is None or self.tbl_shift > 0 else self.cfg_mask self.cfg_msb_mask_shifted = f'({self.cfg_msb_mask} << {self.cfg_shift})' if self.tbl_shift is None or self.tbl_shift > 0 else self.cfg_msb_mask self.c_bool = 'int' if self._opt.c_std == 'C89' else 'bool' self.c_true = '1' if self._opt.c_std == 'C89' else 'true' self.c_false = '0' if self._opt.c_std == 'C89' else 'false' self.underlying_crc_t = _get_underlying_crc_t(self._opt) self.crc_t = self._opt.symbol_prefix + 't' self.cfg_t = self._opt.symbol_prefix + 'cfg_t' self.crc_reflect_function = self._opt.symbol_prefix + 'reflect' self.crc_table_gen_function = self._opt.symbol_prefix + 'table_gen' self.crc_init_function = self._opt.symbol_prefix + 'init' self.crc_update_function = self._opt.symbol_prefix + 'update' self.crc_finalize_function = self._opt.symbol_prefix + 'finalize' self.crc_init_value = _get_init_value(self._opt) self._crc_table_init = None @property def crc_table_init(self): if self._crc_table_init is None: self._crc_table_init = _get_table_init(self._opt) return self._crc_table_init 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): # noqa: C901 # pylint: disable=too-many-return-statements, too-many-branches """ Return the C type of the crc_t typedef. """ 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' if opt.width <= 16: return 'unsigned int' return 'unsigned long int' else: # C99 if opt.width is None: return 'unsigned long long int' if opt.width <= 8: return 'uint_fast8_t' if opt.width <= 16: return 'uint_fast16_t' if opt.width <= 32: return 'uint_fast32_t' if opt.width <= 64: return 'uint_fast64_t' if opt.width <= 128: return 'uint_fast128_t' 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 ./pycrc-0.10.0/src/pycrc/algorithms.py0000644000175000017500000002035614331517447015346 0ustar tptp# pycrc -- parameterisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2017 Thomas Pircher # # 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(): """ 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): """ Create a CRC object, using the Rocksoft model. 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 is not 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 ./pycrc-0.10.0/.github/0000755000175000017500000000000014331517447012246 5ustar tptp./pycrc-0.10.0/.github/workflows/0000755000175000017500000000000014331517447014303 5ustar tptp./pycrc-0.10.0/.github/workflows/github-actions.yml0000644000175000017500000000200414331517447017742 0ustar tptpname: Test and Lint on: [push] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 pytest if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 200 chars wide flake8 . --count --exit-zero --max-complexity=11 --max-line-length=127 --statistics - name: Test with pytest run: | pytest ./pycrc-0.10.0/pyproject.toml0000644000175000017500000000120514331517447013620 0ustar tptp[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "pycrc" version = "0.10.0" authors = [ { name="Thomas Pircher", email="tehpeh-web@tty1.net" }, ] description = "A free, easy to use Cyclic Redundancy Check source code generator for C/C++" readme = "README.md" requires-python = ">=3.0" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] [project.urls] "Homepage" = "https://pycrc.org" "Bug Tracker" = "https://github.com/tpircher/pycrc/issues" [project.scripts] pycrc = "pycrc.main:main" ./pycrc-0.10.0/.gitignore0000644000175000017500000000021414331517447012673 0ustar tptp.svn .*.swp *.pyc *.pyo __pycache__ /src/pycrc.egg-info /dist /build /doc/pycrc.1 /doc/pycrc.html /doc/docbook.css /test/pycrc_files.tar.gz ./pycrc-0.10.0/README.md0000644000175000017500000000413414331517447012167 0ustar tptp _ __ _ _ ___ _ __ ___ | '_ \| | | |/ __| '__/ __| | |_) | |_| | (__| | | (__ | .__/ \__, |\___|_| \___| |_| |___/ https://pycrc.org pycrc is a free, easy to use Cyclic Redundancy Check (CRC) calculator and C source code generator. System Requirements =================== Python3 is required to run pycrc. The last version compatible with Python 2 is v0.9.x. Running pycrc ============= This program doesn't need to be installed to be run. The script can be executed from the source directory. Simply call the python interpreter with the script as parameter: python3 src/pycrc.py [options] Installation ============ Install pycrc (if required) using pip: python3 -m pip install pycrc This will install a `pycrc` binary in the path. Getting help ============ If you are new to pycrc and want to generate C code, start with [the tutorial](https://pycrc.org/tutorial.html). The [pycrc manual page](https://pycrc.org/pycrc.html) explains the command line options in some detail and also gives some more examples how to use pycrc. If you have found a bug in pycrc or want to request a feature please take the time and submit it to the [issue tracker](https://github.com/tpircher/pycrc/issues). Thanks for your help. Also see the [frequently asked questions](https://pycrc.org/faq.html). Feedback ======== If you like pycrc, let me know and drop me a note. If you don't like pycrc let me know what you don't like and why. In both cases, I would really appreciate some [feed back](https://sourceforge.net/projects/pycrc/reviews/). If you want some idea how to say thanks for this software, please have a look [here](https://www.tty1.net/say-thanks_en.html). Copyright of the generated source code ====================================== The code generated by pycrc is not considered a substantial portion of the software, therefore the licence does not cover the generated code, and the author of pycrc will not claim any copyright on the generated code. ./pycrc-0.10.0/AUTHORS0000644000175000017500000000105414331517447011756 0ustar tptpThomas Pircher: main developer. Matthias Urlichs: removed the unused 'direct' parameter and added a fix not to recurse into main() when an unknown algorithm is selected. Marti Raudsepp: improved spacing for the table-driven algorithm. Stephan Brumme: his implementation of the slice-by-x algorithm was used as a basis for the implementation in pycrc. Danjel McGougan: whose Universal Crc project was highly influential in the implementation of widths < 8 in the table-driven algorithm. André Hartmann, ashelly and others for minor fixes. ./pycrc-0.10.0/LICENSE0000644000175000017500000000207614331517447011720 0ustar tptpCopyright (c) 2006-2015, Thomas Pircher 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-0.10.0/CHANGELOG.md0000644000175000017500000004460114331517447012524 0ustar tptp# Change Log All notable changes to this project will be documented in this file. For a detailed list of changes see the [pycrc GitHub][pycrc github] page. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added - Add support for GitHub CI ### Fixed - Make flake8 happy ## [v0.10.0] - 2022-11-01 ### Added - Use pytest for regression tests - Update to pyproject.toml for packaging ### Removed - Removed Python 2 compatibility. Use pycrc v0.9.x if Python 2 is required. ### Fixed - The xor-in value is never reflected Thanks to Ralf Schlatterbeck ## [v0.9.3] - 2022-11-01 ### Fixed - Fix compatibility with Python 3.10. Fixes #46. - Slightly improved the performance of the bit-by-bit-fast algorithm. ## [v0.9.2] - 2019-02-06 ### Fixed - Fix code generator to output the table correctly. Fixes #28. - Ensure the data is aligned when using slice-by. Fixes #24. ## [v0.9.1] - 2017-09-09 ### Added - Added setup.py script to install pycrc on the system, if desired. - Added checks about possibly unsuitable polynomials. Use the --force-poly option to override the error message. ### Changed - Completely rewritten the code generator back-end. The new back-end is more flexible and allows for a better optimisation of the generated expressions. - Moved the python code under the `pycrc` directory and changed how the pycrc sub-modules are included. Before one would write `import crc_xxx`, now one would write `import pycrc.xxx`. - New license for the documentation: [Creative Commons Attribution-Share Alike 4.0 Unported License][CC-BY-SA-4.0]. ### Fixed - Fixed binary files handling with Python 2.7. Fixes #11. Thanks to James Bowman. - Fixed some spelling. Thanks to Frank (ftheile) and ashelly. - Fixed Header Guard generation. Don't use underscores to start the header guard name. Thanks to Andre Hartmann. ## [v0.9] - 2016-01-06 ### Added - Added Stephan Brumme to the `AUTHORS` file as his implementation of the slice-by algorithm is the basis for pycrc's implementation. - Added a new option `--slice-by`. This option is still experimental and limited in its use. ### Changed - Documented the experimental `--slice-by option`. - Simplified the implementation where Width is less than 8 bits. - Run the code through `pylint`. - __API change__: changed the names of the member variables from `CamelCase` to the format suggested in `PEP 0008` (lowercase letters and words separated by underscore). ### Fixed - Suppressed the `crc_reflect` function where not needed. Addresses part of #8. Thanks to Craig McQueen. - Allow strings with values greater than 0x80 in `--check-hexstring`. - When the CRC width is less than 8 then the `bit-by-bit` algorithm needs to apply the CRC mask to the final value. Fixes #10. Thanks to Steve Geo. - Fixed the initial value of the 16-bit `CCITT` algorithm. Renamed the model from `ccitt` to `crc-16-ccitt`. Fixes #7. Thanks to Craig McQueen. ## [v0.8.3] - 2015-08-31 ### Changed - pycrc has a new [homepage][pycrc home]. - The [issue tracker on GitHub][pycrc issues] is now advertised as the preferred issue tracker. - Applied some minor optimisations to the generated table-driven code. - Belatedly added an authors file. Should I have forgotten to mention someone please don't hesitate to send a mail. - Upgraded documentation to DocBook 5. - Removed sourceforge mailing list from `README.md` in an effort to move pycrc away from sourceforge. - Removed the experimental `--bitwise-expression` option to facilitate restructuring of the code. - The preferred format for the input data for the Python API is now a byte array. But if a string is supplied it is decoded as UTF-8 string. Alternative formats are not supported and must be passed to the functions as byte arrays. - Changed the signature of the `crc_update()` function: the data argument is now a pointer to void to improve compatibility with C++. Thanks to Kamil Szczygieł. This closes GitHub issue #4. ## [v0.8.2] - 2014-12-04 ### Changed - Smaller code cleanups. - Stated more clearly that the bitwise expression algorithm is experimental in the documentation. - Fixed a typo in the documentation. The description previously stated: "The reflected value of 0xa3 (10100010b) is 0x45 (01000101b)" but this should be: "The reflected value of 0xa2 (10100010b) is 0x45 (01000101b)" Thanks to Andreas Nebenfuehr for reporting the mistake. - Small cleanups. Added a tests for special cases. For now, added `crc-5` with non-inverted input. This test is currently failing. - Removed warning about even polynomials. As Lars Pötter rightly pointed out, polynomials may be even. Added a caveat emptor about even polinomials in the documentation. ### Fixed - The table-driven code for polynomials of width < 8 using a table index width < 8 was producing a wrong checksum. Thanks to Radosław Gancarz. - Updated the generated code to cope with big Widths (>32 bits) on 32 bit processors. Since C89 does not give a way to specify the minimum length of a data type, the test does not validate C89 code using Widths > 32. For C99, the `uint_fastN_t` data types are used or long long, if the Width is unknown. ## [v0.8.1] - 2013-05-17 ### Changed - Updated [qm.py from GitHub][qm github]. - Explicitly stated that the output of pycrc is not considered a substantial part of the code of pycrc in `README.md`. - Re-organised the symbol table: grouped the code by functionality, not by algorithm. - The input to the CRC routines can now be bytes or strings. - Minor formatting change in the manpage. - Better python3 compatibility. - Added the files generated with the `bwe` algorithm to `check_files.sh`. ### Fixed - Fixed a bug in the handling of hexstrings in Python3. Thanks to Matthias Kuehlewein. - Added `--check-hexstring` to the tests. - Remove obsolete and unused `direct` parameter. Merge pull request #2 from smurfix/master. Thanks to Matthias Urlichs. - Don't recurse into main() when an unknown algorithm is selected. Merge pull request #2 from smurfix/master. Thanks to Matthias Urlichs. ## [v0.8] - 2013-01-04 ### Added - Merged (private) bitwise-expression branch to main. This adds the highly experimental `bitwise-expression` (`bwe`) code generator target, which might one day be almost as fast as the table-driven code but much smaller. At the moment the generated code is bigger and slower than any other algorithm, so use at your own risk. ### Changed - Now it is possible to specify the `--include` option multiple times. - Completely revisited and reworked the documentation. - Updated the command line help screen with more useful command descriptions. - Removed the `-*- coding: Latin-1 -*-` string. - Updated the copyright year to 2013. - Renamed abbreviations to `bbb`, `bbf`, `tbl`. - It is possible now to abbreviate the algorithms (`bbb` for `bit-by-bit`, `bbf` for `bit-by-bit-fast` and `tbl` for `table-driven`). Added the list of supported CRC models to the error message when an unknown model parameter was supplied. - Documented the possibility to abbreviate the algorithms. Minor improvements in the documentation. - Added a note to `README.md` that version 0.7.10 of pycrc is the last one known to work with Python 2.4. - Updated a link to the list of CRC models. - Renamed i`README` to `README.md`. - Updated link to the [Catalogue of parametrised CRC algorithms][crc catalogue]. ## [v0.7.11] - 2012-10-20 ### Changed - Improved Python3 compatibility. pycrc now requires Python 2.6 or later. - Added a test for compiled standard models. ### Fixed - Fixed a wrong `check` value of the `crc-64-jones` model. - Don't use `snprintf()` with `c89` code, changed to `sprintf()`. - Deleted `test.sh` shell script and replaced it with `test.py`. ## [v0.7.10] - 2012-02-13 ### Added - Added the models `crc-12-3gpp`, `crc-16-genibus`, `crc-32-bzip2` and `crc-64-xz`. Taken from [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue]. ### Changed - Bad-looking C code generated; make sure the `bit-by-bit`(`-fast`) code does not contain two instructions on one line. Thanks to "intgr" for the fix. - Some small code clean-up: use `set()` when appropriate. ### Fixed - Fixed a mistake in the man page that still used the old model name `crc-32mpeg` instead of `crc-32-mpeg`. Thanks to Marek Erban. ## [v0.7.9] - 2011-12-08 ### Fixed - Fixed a bug in the generated C89 code that included `stdint.h`. Thanks to Frank (ftheile). Closes issue 3454356. - Fixed a bug in the generated C89 code when using a 64 bit CRC. - Using the `--verbose` option made pycrc quit without error message. ## [v0.7.8] - 2011-07-10 ### Changed - When generating C code for the C89 or ANSI standard, don't include `stdint.h`. This closes issue 3338930 - If no output file name is given while generating a C file, then pycrc will `#include` a hypothetical `pycrc.h` file instead of a `stdout.h` file. Also, added a comment on that line to make debugging easier. Closes issue 3325109. - Removed unused variable `this_option_optind` in the generated option parser. ## [v0.7.7] - 2011-02-11 ### Changed - Updated the copyright year. Fixed some coding style issues found by `pylint` and `pychecker`. ### Fixed - Substituted the deprecated function `atoi()` with `int()`. Closes issue 3136566. Thanks to Tony Smith. - Updated the documentation using Windows-style calls to the Python interpreter. ## [v0.7.6] - 2010-10-21 ### Changed - Rewritten macro parser from scratch. Simplified the macro language. - Changed a simple division (/) to a integer division (//) for Python3 compatibility. ### Fixed - Fixed a minor bug in the command line parsing of the generated main function. ## [v0.7.5] - 2010-03-28 ### Added - Python implementation of the `table-driven` algorithm can handle widths less than 8. - Suppressed warnings of unused cfg structure on partially defined models. ### Removed - Removed the half-baken and confusing `--direct` option. ### Changed - C/C++ code can now be generated for the table-driven algorithm with widths that are not byte-aligned or less than 8. This feature was heavily inspired by a similar feature in Danjel McGougan's [Universal Crc][universal crc]. - __API change__: introduced new variable `crc_shift`, member of the `crc_cfg_t` structure, which must be initialised manually when the width was undefined during C/C++ code generation. - Minor code cleanup. ## [v0.7.4] - 2010-01-24 ### Added - Added `crc-16-modbus`. Closes issue 2896611. ### Changed - Changed the `xor-in` value of the `crc-64-jones` model. - Set xmodem parameters equal to the `zmodem` parameters. - Generate more uniform error messages. - Added a warning for even polynomials. ### Fixed - Fix for unused variable argv. Closes issue 2893224. Thanks to Marko von Oppen. ## [v0.7.3] - 2009-10-25 ### Added - Added `crc-64-jones` CRC model. Thanks to Waterspirit. ### Changed - Renamed `crc-32mpeg` to `crc-32-mpeg`. ## [v0.7.2] - 2009-09-30 ### Fixed - Fixed a bug that caused the result of the Python `table-driven` code not being evaluated at all. Closes issue 2870630. Thanks to Ildar Muslukhov. ## [v0.7.1] - 2009-04-05 ### Added - Added `crc-32mpeg`. Thanks to Thomas Edwards. ## [v0.7] - 2009-02-27 ### Added - Added the `--direct` option. - Added `--check-hexstring` option. Closes issue 2545183. Thanks to Arnim Littek. - Added a check for extra arguments on the command line. Closes issue 2545185. Thanks to Arnim Littek. ### Changed - Added one more example in the documentation. ## [v0.6.7] - 2008-12-11 ### Changed - Run Python's 2to3 script on all files. Check the code on a x64 platform. - Fixed a bug that raised an exception when an unknown model was selected. ## [v0.6.6] - 2008-06-05 ### Changed - New license for the documentation: [Creative Commons Attribution-Share Alike 3.0 Unported License][CC-BY-SA-3.0]. ### Fixed - Fixed a bug in the `print_params()` function. Closes issue 1985197. Thanks to Artur Lipowski. ## [v0.6.5] - 2008-03-03 ### Added - Added dallas-1-wire 8 bit CRC. - Added `r-crc-16 model` (DECT (cordless digital standard) packets A-field according to ETSI EN 300 175-3 v2.1.1). Thanks to "raimondo". - Added `--crc-type` and `--include-file` options. - Added new file to handle CRC models. ### Changed - Added extern "C" declaration to the generated C header file. Thanks to Nathan Royer. - Changed the API to take the CRC model direct as parameter. Deleted the need for an obscure `opt` object. ### Fixed - Fixed a problem with the generated code for bit-by-bit-fast algorithms. Thanks to Hans Bacher. ## [v0.6.4] - 2007-12-05 ### Fixed - Fixed a bug in the code generator for the `table-driven` algorithm. Thanks to Tom McDermott. Closes issue 1843774 ## [v0.6.3] - 2007-10-13 ### Added - Added new models: `crc-5`, `crc-15`, `crc-16-usb`, `crc-24`, `crc-64`. The new models are taken from Ray Burr's CrcMoose. ### Fixed - Fixed some portability problems in the generated code. Thanks to Helmut Bauer. Closes issue 1812894. - The option `--check-file` works now with `--width` < 8. Closes issue 1794343. - Removed unnecessary restriction on the width when using the `bit-by-bit-fast` algorithm. Closes issue 1794344. ## [v0.6.2] - 2007-08-25 ### Changed - Simplified the table-driven code. Closes issue 1727128. - Changed the macro language syntax to a better format. - Renamed `crc_code_gen.py` to `crc_parser.py`. - Documented the usage of the `crc_*` modules. ### Fixed - The parameter to `--check-string` was ignored. Closes issue 1781637. ## [v0.6.1] - 2007-08-12 ### Added - Added test for C89 compilation. - Added a test case to loop over the input bytes one by one. ### Removed - Deleted obsolete options. ### Changed - Tidied up the documentation. Code cleanup. ### Fixed - Bugfix in the source code generator for C89: Compilation error due to mismatch of parameters in the `crc_finalize` funtion. - Changes related to 919107: Code generator includes `reflect()` function even if not needed. - Fixed a typo in the C89 source code generator. Thanks to Helmut Bauer. ## [v0.6] - 2007-05-21 ### Added - Added the `--std` option to generate C89 (ANSI) compliant code. - Added a new check to the test script which validate all possible combination of undefined parameters. - Made the generated main function cope with command line arguments. - Added the `--generate` table option. - Added a template engine for the code generation. Split up `pycrc.py` into smaller modules. - Added obsolete options again tor legacy reasons. - Added a better handling of the `--model` parameter. ### Changed - Reduced the size of the symbol table by re-arranging items. - Changed licence to the MIT licence. This makes the additional clause for generated source code obsolete. Changed all command line options with underscores to hyphen (e.g. `table_driven` becomes `table-driven`). Added the option `--generate` which obsoletes the old options `--generate_c` `--generate_h` etc. ## [v0.5] - 2007-03-25 ### Fixed - Fixed bug 1686404: unhandled exception when called with both options `--table_idx_width` and `--check_file`. - Eliminated useless declaration of `crc_reflect`, when not used. - Corrected typos in the documentation. ## [v0.4] - 2007-01-26 ### Added - Added more parameter sets (now supported: `crc-8`, `crc-16`, `citt`, `kermit`, `x-25`, `xmodem`, `zmodem`, `crc-32`, `crc-32c`, `posix`, `jam`, `xfer`) from [Greg Cook's Catalogue of parametrised CRC algorithms][crc catalogue]. - Added Doxygen documentation strings to the functions. - Added the `--symbol_prefix` option. - Added the `--check_file` option. - Added a non-regression test on the generated C source. ### Changed - Eliminated needless documentation of not generated functions. - Many corrections to the manual (thanks Francesca) Documented the new parameter sets. - Added some new tests, disabled the random loop. ### Fixed - Corrected many typos and bad phrasing (still a lot to do) Documented the `--symbol_prefix` option. ## [v0.3] - 2007-01-14 ### Added - First public release pycrc v0.3 [Unreleased]: https://github.com/tpircher/pycrc [v0.10.0]: https://github.com/tpircher/pycrc/releases/tag/v0.10.0 [v0.9.3]: https://github.com/tpircher/pycrc/releases/tag/v0.9.3 [v0.9.2]: https://github.com/tpircher/pycrc/releases/tag/v0.9.2 [v0.9.1]: https://github.com/tpircher/pycrc/releases/tag/v0.9.1 [v0.9]: https://github.com/tpircher/pycrc/releases/tag/v0.9 [v0.8.3]: https://github.com/tpircher/pycrc/releases/tag/v0.8.3 [v0.8.2]: https://github.com/tpircher/pycrc/releases/tag/v0.8.2 [v0.8.1]: https://github.com/tpircher/pycrc/releases/tag/v0.8.1 [v0.8]: https://github.com/tpircher/pycrc/releases/tag/v0.8 [v0.7.11]: https://github.com/tpircher/pycrc/releases/tag/v0.7.11 [v0.7.10]: https://github.com/tpircher/pycrc/releases/tag/v0.7.10 [v0.7.9]: https://github.com/tpircher/pycrc/releases/tag/v0.7.9 [v0.7.8]: https://github.com/tpircher/pycrc/releases/tag/v0.7.8 [v0.7.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7.7 [v0.7.6]: https://github.com/tpircher/pycrc/releases/tag/v0.7.6 [v0.7.5]: https://github.com/tpircher/pycrc/releases/tag/v0.7.5 [v0.7.4]: https://github.com/tpircher/pycrc/releases/tag/v0.7.4 [v0.7.3]: https://github.com/tpircher/pycrc/releases/tag/v0.7.3 [v0.7.2]: https://github.com/tpircher/pycrc/releases/tag/v0.7.2 [v0.7.1]: https://github.com/tpircher/pycrc/releases/tag/v0.7.1 [v0.7]: https://github.com/tpircher/pycrc/releases/tag/v0.7 [v0.6.7]: https://github.com/tpircher/pycrc/releases/tag/v0.6.7 [v0.6.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6.6 [v0.6.5]: https://github.com/tpircher/pycrc/releases/tag/v0.6.5 [v0.6.4]: https://github.com/tpircher/pycrc/releases/tag/v0.6.4 [v0.6.3]: https://github.com/tpircher/pycrc/releases/tag/v0.6.3 [v0.6.2]: https://github.com/tpircher/pycrc/releases/tag/v0.6.2 [v0.6.1]: https://github.com/tpircher/pycrc/releases/tag/v0.6.1 [v0.6]: https://github.com/tpircher/pycrc/releases/tag/v0.6 [v0.5]: https://github.com/tpircher/pycrc/releases/tag/v0.5 [v0.4]: https://github.com/tpircher/pycrc/releases/tag/v0.4 [v0.3]: https://github.com/tpircher/pycrc/releases/tag/v0.3 [pycrc home]: https://pycrc.org [pycrc github]: https://github.com/tpircher/pycrc [pycrc issues]: https://github.com/tpircher/pycrc/issues [crc catalogue]: http://regregex.bbcmicro.net/crc-catalogue.htm [universal crc]: http://mcgougan.se/universal_crc/ [qm github]: https://github.com/tpircher/quine-mccluskey [CC-BY-SA-3.0]: https://creativecommons.org/licenses/by-sa/3.0/ [CC-BY-SA-4.0]: https://creativecommons.org/licenses/by-sa/4.0/