#!/usr/bin/env python # -*- coding: Latin-1 -*- # pycrc -- parametrisable CRC calculation utility and C source code generator # # Copyright (c) 2006-2012 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 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())