I needed a Python function calculating CRC of arbitrary length.
There are a few packages available, but they either calculate
only a few standard CRC, or calculate CRC of only certain
length (e.g. 8 , 16 or 24 bits).
Therefore I prepares a simple implementation based strictly
on the calculation of the CRC presented in Wikipedia.
This is a PUBLIC DOMAIN code.
Please use it on yout own risk.
With best regards,
Wojtek
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh07730
# Made on 2016-03-07 15:49 CET by <wzab@wzdell>.
# Source directory was '/home/wzab/biezace/CBM/crc_any_length'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 1567 -rw-r--r-- CRC_al.py
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= CRC_al.py ==============
if test -n "${keep_file}" && test -f 'CRC_al.py'
then
${echo} "x - SKIPPING CRC_al.py (file already exists)"
else
${echo} "x - extracting CRC_al.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'CRC_al.py' &&
"""
This module implements the CRC of arbitrary length. The implementation is not the
most efficient one, but it is intended to be as simple (from the code point
of view) as possible and follows the explanation provided in
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
"""
def crc_al(bdata,bdiv,n):
X """
X bdata - binary value of arbitrary length with either CRC bits to be checked
X or n 0 bits (if we want to calculate the CRC)
X bdiv - CRC divisor
X n - length of the CRC
X
X Output:
X dout,dcrc
X
X dout - data with last bits replaced with the result of calculation
X dcrc - value of the CRC
X
X In the implementation we heavily depend on implementation of the
X "bin" function...
X """
X #Check if bdiv is correct for the given CRC length
X div_len=len(bin(bdiv))-2 # There was '0b' at the beginning!
X if div_len != n+1:
X raise Exception("Incorrect CRC divisor for given CRC length")
X data_len=len(bin(bdata))-2
X #Create the copy of data
X sdata = bdata
X #Now we create the mask used to check if the highest bit is set
X mask = 1<<data_len
X #Create the shifted divisor
X i = data_len-div_len
X sdiv = bdiv << i
X #Now in the loop we compute CRC
X while i>0:
X if sdata & mask:
X sdata ^= sdiv
X mask >>= 1
X sdiv >>= 1
X i -= 1
X crc_mask = (1<<n)-1
X crc_val = sdata & crc_mask
X #In the line below we do the dirty trick to clear some bits
X #In the binary number with unknown length...
X bdata = ((bdata | crc_mask) ^ crc_mask) | crc_val;
X return (bdata, crc_val)
X
SHAR_EOF
(set 20 16 03 07 11 46 01 'CRC_al.py'
eval "${shar_touch}") && \
chmod 0644 'CRC_al.py'
if test $? -ne 0
then ${echo} "restore of CRC_al.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'CRC_al.py': 'MD5 check failed'
) << \SHAR_EOF
fda9f5664217e6af1695da38ce939b7d CRC_al.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'CRC_al.py'` -ne 1567 && \
${echo} "restoration warning: size of 'CRC_al.py' is not 1567"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0