blob: d446362650235c969b66a006f714f0789282b413 [file] [log] [blame]
Brian Silverman84b22232019-01-25 20:29:29 -08001#!/usr/bin/env python
2
3# pycrc -- parameterisable CRC calculation utility and C source code generator
4#
5# Copyright (c) 2006-2017 Thomas Pircher <tehpeh-web@tty1.net>
6#
7# Permission is hereby granted, free of charge, to any person obtaining a copy
8# of this software and associated documentation files (the "Software"), to
9# deal in the Software without restriction, including without limitation the
10# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11# sell copies of the Software, and to permit persons to whom the Software is
12# furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice shall be included in
15# all copies or substantial portions of the Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24
25
26"""
27pycrc is a fully parameterisable Cyclic Redundancy Check (CRC) calculation
28utility and C source code generator written in Python.
29
30It can:
31 - generate the checksum of a string
32 - generate the checksum of a file
33 - generate the C header file and source of any of the algorithms below
34
35It supports the following CRC algorithms:
36 - bit-by-bit the basic algorithm which operates bit by bit on the
37 augmented message
38 - bit-by-bit-fast a variation of the simple bit-by-bit algorithm
39 - table-driven the standard table driven algorithm
40"""
41
42from __future__ import print_function
43from pycrc import progname, version, url
44from pycrc.opt import Options
45from pycrc.algorithms import Crc
46import pycrc.codegen as cg
47import binascii
48import sys
49
50
51
52def print_parameters(opt):
53 """
54 Generate a string with the options pretty-printed (used in the --verbose mode).
55 """
56 return str(cg.ParamBlock(opt, ''))
57
58
59def check_string(opt):
60 """
61 Return the calculated CRC sum of a string.
62 """
63 error = False
64 if opt.undefined_crc_parameters:
65 sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
66 sys.exit(1)
67 if opt.algorithm == 0:
68 opt.algorithm = opt.algo_bit_by_bit | opt.algo_bit_by_bit_fast | opt.algo_table_driven
69
70 alg = Crc(
71 width=opt.width, poly=opt.poly,
72 reflect_in=opt.reflect_in, xor_in=opt.xor_in,
73 reflect_out=opt.reflect_out, xor_out=opt.xor_out,
74 table_idx_width=opt.tbl_idx_width)
75
76 crc = None
77 if opt.algorithm & opt.algo_bit_by_bit:
78 bbb_crc = alg.bit_by_bit(opt.check_string)
79 if crc != None and bbb_crc != crc:
80 error = True
81 crc = bbb_crc
82 if opt.algorithm & opt.algo_bit_by_bit_fast:
83 bbf_crc = alg.bit_by_bit_fast(opt.check_string)
84 if crc != None and bbf_crc != crc:
85 error = True
86 crc = bbf_crc
87 if opt.algorithm & opt.algo_table_driven:
88 # no point making the python implementation slower by using less than 8 bits as index.
89 opt.tbl_idx_width = 8
90 tbl_crc = alg.table_driven(opt.check_string)
91 if crc != None and tbl_crc != crc:
92 error = True
93 crc = tbl_crc
94
95 if error:
96 sys.stderr.write("{0:s}: error: different checksums!\n".format(progname))
97 if opt.algorithm & opt.algo_bit_by_bit:
98 sys.stderr.write(" bit-by-bit: {0:#x}\n".format(bbb_crc))
99 if opt.algorithm & opt.algo_bit_by_bit_fast:
100 sys.stderr.write(" bit-by-bit-fast: {0:#x}\n".format(bbf_crc))
101 if opt.algorithm & opt.algo_table_driven:
102 sys.stderr.write(" table_driven: {0:#x}\n".format(tbl_crc))
103 sys.exit(1)
104 return crc
105
106
107def check_hexstring(opt):
108 """
109 Return the calculated CRC sum of a hex string.
110 """
111 if opt.undefined_crc_parameters:
112 sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
113 sys.exit(1)
114 if len(opt.check_string) % 2 != 0:
115 opt.check_string = "0" + opt.check_string
116 if sys.version_info >= (3, 0):
117 opt.check_string = bytes(opt.check_string, 'utf_8')
118 try:
119 check_str = bytearray(binascii.unhexlify(opt.check_string))
120 except TypeError:
121 sys.stderr.write(
122 "{0:s}: error: invalid hex string {1:s}\n".format(progname, opt.check_string))
123 sys.exit(1)
124
125 opt.check_string = check_str
126 return check_string(opt)
127
128
129def crc_file_update(alg, register, check_bytes):
130 """
131 Update the CRC using the bit-by-bit-fast CRC algorithm.
132 """
133 # If the input data is a string, convert to bytes.
134 if isinstance(check_bytes, str):
135 check_bytes = bytearray(check_bytes, 'utf_8')
136
137 for octet in check_bytes:
138 if alg.reflect_in:
139 octet = alg.reflect(octet, 8)
140 for j in range(8):
141 bit = register & alg.msb_mask
142 register <<= 1
143 if octet & (0x80 >> j):
144 bit ^= alg.msb_mask
145 if bit:
146 register ^= alg.poly
147 register &= alg.mask
148 return register
149
150
151def check_file(opt):
152 """
153 Calculate the CRC of a file.
154 This algorithm uses the table_driven CRC algorithm.
155 """
156 if opt.undefined_crc_parameters:
157 sys.stderr.write("{0:s}: error: undefined parameters\n".format(progname))
158 sys.exit(1)
159 alg = Crc(
160 width=opt.width, poly=opt.poly,
161 reflect_in=opt.reflect_in, xor_in=opt.xor_in,
162 reflect_out=opt.reflect_out, xor_out=opt.xor_out,
163 table_idx_width=opt.tbl_idx_width)
164
165 if not opt.reflect_in:
166 register = opt.xor_in
167 else:
168 register = alg.reflect(opt.xor_in, opt.width)
169
170 try:
171 with open(opt.check_file, 'rb') as f:
172 check_bytes = bytearray(f.read(1024))
173 while check_bytes != b"":
174 register = crc_file_update(alg, register, check_bytes)
175 check_bytes = bytearray(f.read(1024))
176 except IOError:
177 sys.stderr.write(
178 "{0:s}: error: can't open file {1:s}\n".format(progname, opt.check_file))
179 sys.exit(1)
180
181 if opt.reflect_out:
182 register = alg.reflect(register, opt.width)
183 register = register ^ opt.xor_out
184 return register
185
186
187def write_file(filename, out_str):
188 """
189 Write the content of out_str to filename.
190 """
191 try:
192 out_file = open(filename, "w")
193 out_file.write(out_str)
194 out_file.close()
195 except IOError:
196 sys.stderr.write("{0:s}: error: cannot write to file {1:s}\n".format(progname, filename))
197 sys.exit(1)
198
199
200def main():
201 """
202 Main function.
203 """
204 opt = Options(progname, version, url)
205 opt.parse(sys.argv[1:])
206 if opt.verbose:
207 print(print_parameters(opt))
208 if opt.action == opt.action_check_str:
209 crc = check_string(opt)
210 print("{0:#x}".format(crc))
211 if opt.action == opt.action_check_hex_str:
212 crc = check_hexstring(opt)
213 print("{0:#x}".format(crc))
214 if opt.action == opt.action_check_file:
215 crc = check_file(opt)
216 print("{0:#x}".format(crc))
217 if opt.action in set([
218 opt.action_generate_h, opt.action_generate_c, opt.action_generate_c_main,
219 opt.action_generate_table]):
220 if opt.action == opt.action_generate_h:
221 in_str = "$h_template"
222 elif opt.action == opt.action_generate_c:
223 in_str = "$c_template"
224 elif opt.action == opt.action_generate_c_main:
225 in_str = "$c_template\n\n$main_template"
226 elif opt.action == opt.action_generate_table:
227 in_str = "$crc_table_init"
228 else:
229 sys.stderr.write(
230 "{0:s}: error: unknown action. Please file a bug report!\n".format(progname))
231 sys.exit(1)
232 out = str(cg.File(opt, ''))
233 if opt.output_file == None:
234 print(out)
235 else:
236 write_file(opt.output_file, out)
237 return 0
238
239
240if __name__ == "__main__":
241 sys.exit(main())