CANLibrary/pycrc/pycrc.py

253 lines
9 KiB
Python

#!/usr/bin/env python
# -*- coding: Latin-1 -*-
# pycrc -- parametrisable CRC calculation utility and C source code generator
#
# Copyright (c) 2006-2012 Thomas Pircher <tehpeh@gmx.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
"""
pycrc is a fully parametrisable 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 crc_opt import Options
from crc_algorithms import Crc
from crc_parser import MacroParser
import binascii
import sys
# function print_parameters
###############################################################################
def print_parameters(opt):
"""
Generate a string with the options pretty-printed (used in the --verbose mode).
"""
in_str = ""
in_str += "Width = $crc_width\n"
in_str += "Poly = $crc_poly\n"
in_str += "ReflectIn = $crc_reflect_in\n"
in_str += "XorIn = $crc_xor_in\n"
in_str += "ReflectOut = $crc_reflect_out\n"
in_str += "XorOut = $crc_xor_out\n"
in_str += "Algorithm = $crc_algorithm\n"
mp = MacroParser(opt)
mp.parse(in_str)
return mp.out_str
# function check_string
###############################################################################
def check_string(opt):
"""
Return the calculated CRC sum of a string.
"""
error = False
if opt.UndefinedCrcParameters:
sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0])
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.ReflectIn, xor_in = opt.XorIn,
reflect_out = opt.ReflectOut, xor_out = opt.XorOut,
table_idx_width = opt.TableIdxWidth)
crc = None
if opt.Algorithm & opt.Algo_Bit_by_Bit:
bbb_crc = alg.bit_by_bit(opt.CheckString)
if crc != None and bbb_crc != crc:
error = True
crc = bbb_crc
if opt.Algorithm & opt.Algo_Bit_by_Bit_Fast:
bbf_crc = alg.bit_by_bit_fast(opt.CheckString)
if crc != None and bbf_crc != crc:
error = True
crc = bbf_crc
if opt.Algorithm & opt.Algo_Table_Driven:
opt.TableIdxWidth = 8 # no point making the python implementation slower by using less than 8 bits as index.
tbl_crc = alg.table_driven(opt.CheckString)
if crc != None and tbl_crc != crc:
error = True
crc = tbl_crc
if error:
sys.stderr.write("%s: error: different checksums!\n" % sys.argv[0])
if opt.Algorithm & opt.Algo_Bit_by_Bit:
sys.stderr.write(" bit-by-bit: 0x%x\n" % bbb_crc)
if opt.Algorithm & opt.Algo_Bit_by_Bit_Fast:
sys.stderr.write(" bit-by-bit-fast: 0x%x\n" % bbf_crc)
if opt.Algorithm & opt.Algo_Table_Driven:
sys.stderr.write(" table_driven: 0x%x\n" % tbl_crc)
sys.exit(1)
return crc
# function check_hexstring
###############################################################################
def check_hexstring(opt):
"""
Return the calculated CRC sum of a hex string.
"""
if opt.UndefinedCrcParameters:
sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0])
sys.exit(1)
if len(opt.CheckString) % 2 != 0:
opt.CheckString = "0" + opt.CheckString
try:
check_str = binascii.unhexlify(opt.CheckString)
except TypeError:
sys.stderr.write("%s: error: invalid hex string %s\n" % (sys.argv[0], opt.CheckString))
sys.exit(1)
opt.CheckString = check_str
return check_string(opt)
# function crc_file_update
###############################################################################
def crc_file_update(alg, register, check_str):
"""
Update the CRC using the bit-by-bit-fast CRC algorithm.
"""
for i in range(len(check_str)):
octet = ord(check_str[i])
if alg.ReflectIn:
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
# function check_file
###############################################################################
def check_file(opt):
"""
Calculate the CRC of a file.
This algorithm uses the table_driven CRC algorithm.
"""
if opt.UndefinedCrcParameters:
sys.stderr.write("%s: error: undefined parameters\n" % sys.argv[0])
sys.exit(1)
alg = Crc(width = opt.Width, poly = opt.Poly,
reflect_in = opt.ReflectIn, xor_in = opt.XorIn,
reflect_out = opt.ReflectOut, xor_out = opt.XorOut,
table_idx_width = opt.TableIdxWidth)
try:
in_file = open(opt.CheckFile, 'rb')
except IOError:
sys.stderr.write("%s: error: can't open file %s\n" % (sys.argv[0], opt.CheckFile))
sys.exit(1)
if not opt.ReflectIn:
register = opt.XorIn
else:
register = alg.reflect(opt.XorIn, opt.Width)
try:
check_str = in_file.read()
except IOError:
sys.stderr.write("%s: error: can't open read %s\n" % (sys.argv[0], opt.CheckFile))
sys.exit(1)
while len(check_str):
register = crc_file_update(alg, register, check_str)
try:
check_str = in_file.read()
except IOError:
sys.stderr.write("%s: error: can't open read %s\n" % (sys.argv[0], opt.CheckFile))
sys.exit(1)
in_file.close()
if opt.ReflectOut:
register = alg.reflect(register, opt.Width)
register = register ^ opt.XorOut
return register
# main function
###############################################################################
def main():
"""
Main function.
"""
opt = Options()
opt.parse(sys.argv[1:])
if opt.Verbose:
print(print_parameters(opt))
if opt.Action == opt.Action_Check_String:
crc = check_string(opt)
print("0x%x" % crc)
if opt.Action == opt.Action_Check_Hex_String:
crc = check_hexstring(opt)
print("0x%x" % crc)
if opt.Action == opt.Action_Check_File:
crc = check_file(opt)
print("0x%x" % crc)
if opt.Action == opt.Action_Generate_H or opt.Action == opt.Action_Generate_C or opt.Action == opt.Action_Generate_C_Main or opt.Action == opt.Action_Generate_Table:
mp = MacroParser(opt)
if opt.Action == opt.Action_Generate_H:
in_str = "$h_template"
elif opt.Action == opt.Action_Generate_C:
in_str = "$c_template"
elif opt.Action == opt.Action_Generate_C_Main:
in_str = "$c_template\n\n$main_template"
elif opt.Action == opt.Action_Generate_Table:
in_str = "$crc_table_init"
else:
sys.stderr.write("%s: error: unknown action. Please file a bug report!\n" % sys.argv[0])
sys.exit(1)
mp.parse(in_str)
if opt.OutputFile == None:
print(mp.out_str)
else:
try:
out_file = open(opt.OutputFile, "w")
out_file.write(mp.out_str)
out_file.close()
except IOError:
sys.stderr.write("%s: error: cannot write to file %s\n" % (sys.argv[0], opt.OutputFile))
sys.exit(1)
return 0
# program entry point
###############################################################################
if __name__ == "__main__":
sys.exit(main())