Skip to content

Commit 91ee75f

Browse files
dearbluepostmodern
authored andcommitted
Unified Digest::CRC#update
The generic `Digest::CRC#update` method is provided, eliminating the need to define separate `#updates` for many CRCs. However, the `Digest::CRC::REFLECT_INPUT` constant must be overridden by `true` or `false`. To speed things up a bit, the following is made: - Use local variables instead of instance variables inside loops. - Suppress generation of multi-precision integers.
1 parent 4840a60 commit 91ee75f

21 files changed

+161
-254
lines changed

README.md

+3-9
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ require 'digest/crc32'
115115
module Digest
116116
class CRC3000 < CRC32
117117

118-
WIDTH = 4
118+
WIDTH = 32
119+
120+
REFLECT_INPUT = true
119121

120122
INIT_CRC = 0xffffffff
121123

@@ -124,14 +126,6 @@ module Digest
124126
TABLE = [
125127
# ....
126128
].freeze
127-
128-
def update(data)
129-
data.each_byte do |b|
130-
@crc = (((@crc >> 8) & 0x00ffffff) ^ @table[(@crc ^ b) & 0xff])
131-
end
132-
133-
return self
134-
end
135129
end
136130
end
137131
```

lib/digest/crc.rb

+57-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class CRC < Digest::Class
1717
# The bit width of the CRC checksum
1818
WIDTH = 0
1919

20+
# Define true or false whether the input direction is bit reversed or not of the CRC checksum
21+
REFLECT_INPUT = nil
22+
2023
# Default place holder CRC table
2124
TABLE = [].freeze
2225

@@ -64,10 +67,11 @@ def self.pack(crc)
6467
# Initializes the CRC checksum.
6568
#
6669
def initialize
67-
@init_crc = self.class.const_get(:INIT_CRC)
68-
@xor_mask = self.class.const_get(:XOR_MASK)
69-
@width = self.class.const_get(:WIDTH)
70-
@table = self.class.const_get(:TABLE)
70+
@init_crc = self.class.const_get(:INIT_CRC)
71+
@xor_mask = self.class.const_get(:XOR_MASK)
72+
@width = self.class.const_get(:WIDTH)
73+
@reflect_input = self.class.const_get(:REFLECT_INPUT)
74+
@table = self.class.const_get(:TABLE)
7175

7276
reset
7377
end
@@ -97,10 +101,57 @@ def digest_length
97101
# @param [String] data
98102
# The data to update the CRC checksum with.
99103
#
100-
# @abstract
104+
# @raise [NotImplementedError]
105+
# If WIDTH, TABLE, or REFLECT_INPUT constants are not set properly.
101106
#
102107
def update(data)
103-
raise(NotImplementedError,"#{self.class}##{__method__} not implemented")
108+
unless @width >= 1
109+
raise(NotImplementedError, "incompleted #{self.class} as CRC (expected WIDTH to be 1 or more)")
110+
end
111+
112+
if @table.empty?
113+
raise(NotImplementedError, "incompleted #{self.class} as CRC (expected TABLE to be not empty)")
114+
end
115+
116+
if @reflect_input.nil?
117+
raise(NotImplementedError, "incompleted #{self.class} as CRC (expected REFLECT_INPUT to be not nil)")
118+
end
119+
120+
table = @table
121+
crc = @crc
122+
123+
if @reflect_input
124+
if @width > 8
125+
data.each_byte do |b|
126+
crc = table[b ^ (0xff & crc)] ^ (crc >> 8)
127+
end
128+
else
129+
data.each_byte do |b|
130+
# Omit (crc >> 8) since bits upper than the lower 8 bits are always 0
131+
crc = table[b ^ (0xff & crc)]
132+
end
133+
end
134+
else
135+
if @width > 8
136+
higher_bit_off = @width - 8
137+
remain_mask = ~(-1 << higher_bit_off)
138+
139+
data.each_byte do |b|
140+
crc = table[b ^ (0xff & (crc >> higher_bit_off))] ^ ((remain_mask & crc) << 8)
141+
end
142+
else
143+
padding = 8 - @width
144+
145+
data.each_byte do |b|
146+
# Omit (crc << 8) since bits lower than the upper 8 bits are always 0
147+
crc = table[b ^ (0xff & (crc << padding))]
148+
end
149+
end
150+
end
151+
152+
@crc = crc
153+
154+
self
104155
end
105156

106157
#

lib/digest/crc15.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class CRC15 < CRC
1010

1111
WIDTH = 15
1212

13+
REFLECT_INPUT = false
14+
1315
# Generated by `./pycrc.py --algorithm=table-driven --model=crc-16 --generate=c`
1416
TABLE = [
1517
0x0000, 0x4599, 0x4eab, 0x0b32, 0x58cf, 0x1d56, 0x1664, 0x53fd, 0x7407, 0x319e, 0x3aac, 0x7f35, 0x2cc8, 0x6951, 0x6263, 0x27fa,
@@ -30,20 +32,6 @@ class CRC15 < CRC
3032
0x276f, 0x62f6, 0x69c4, 0x2c5d, 0x7fa0, 0x3a39, 0x310b, 0x7492, 0x5368, 0x16f1, 0x1dc3, 0x585a, 0x0ba7, 0x4e3e, 0x450c, 0x0095
3133
].freeze
3234

33-
#
34-
# Updates the CRC15 checksum.
35-
#
36-
# @param [String] data
37-
# The data to update the checksum with.
38-
#
39-
def update(data)
40-
data.each_byte do |b|
41-
@crc = (@table[((@crc >> 7) ^ b) & 0xff] ^ (@crc << 8)) & 0x7fff
42-
end
43-
44-
return self
45-
end
46-
4735
end
4836
end
4937

lib/digest/crc16.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class CRC16 < CRC
88

99
WIDTH = 16
1010

11+
REFLECT_INPUT = true
12+
1113
INIT_CRC = 0x0000
1214

1315
# Generated by `./pycrc.py --algorithm=table-driven --model=crc-16`
@@ -46,20 +48,6 @@ class CRC16 < CRC
4648
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
4749
].freeze
4850

49-
#
50-
# Updates the CRC16 checksum.
51-
#
52-
# @param [String] data
53-
# The data to update the checksum with.
54-
#
55-
def update(data)
56-
data.each_byte do |b|
57-
@crc = ((@table[(@crc ^ b) & 0xff] ^ (@crc >> 8)) & 0xffff)
58-
end
59-
60-
return self
61-
end
62-
6351
end
6452
end
6553

lib/digest/crc16_ccitt.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Digest
66
#
77
class CRC16CCITT < CRC16
88

9+
REFLECT_INPUT = false
10+
911
INIT_CRC = 0xffff
1012

1113
# Generated by `./pycrc.py --algorithm=table-driven --model=crc-16-ccitt --generate=c`
@@ -44,20 +46,6 @@ class CRC16CCITT < CRC16
4446
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
4547
].freeze
4648

47-
#
48-
# Updates the CRC16 CCITT checksum.
49-
#
50-
# @param [String] data
51-
# The data to update the checksum with.
52-
#
53-
def update(data)
54-
data.each_byte do |b|
55-
@crc = ((@table[((@crc >> 8) ^ b) & 0xff] ^ (@crc << 8)) & 0xffff)
56-
end
57-
58-
return self
59-
end
60-
6149
end
6250
end
6351

lib/digest/crc16_dnp.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Digest
66
#
77
class CRC16DNP < CRC16
88

9+
REFLECT_INPUT = true
10+
911
INIT_CRC = 0
1012

1113
TABLE = [
@@ -43,20 +45,6 @@ class CRC16DNP < CRC16
4345
0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235
4446
].freeze
4547

46-
#
47-
# Updates the CRC16 DNP checksum.
48-
#
49-
# @param [String] data
50-
# The data to update the checksum with.
51-
#
52-
def update(data)
53-
data.each_byte do |b|
54-
@crc = ((@crc >> 8) ^ @table[(@crc ^ b) & 0xff])
55-
end
56-
57-
return self
58-
end
59-
6048
def finish
6149
self.class.pack(~@crc)
6250
end

lib/digest/crc16_genibus.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Digest
88
#
99
class CRC16Genibus < CRC16
1010

11+
REFLECT_INPUT = false
12+
1113
INIT_XOR = 0xffff
1214

1315
INIT_CRC = 0x0000 ^ INIT_XOR
@@ -50,20 +52,6 @@ class CRC16Genibus < CRC16
5052
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
5153
].freeze
5254

53-
#
54-
# Updates the CRC16 Genibus checksum.
55-
#
56-
# @param [String] data
57-
# The data to update the checksum with.
58-
#
59-
def update(data)
60-
data.each_byte do |b|
61-
@crc = (@table[((@crc >> 8) ^ b) & 0xff] ^ (@crc << 8)) & 0xffff
62-
end
63-
64-
return self
65-
end
66-
6755
end
6856
end
6957

lib/digest/crc16_kermit.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Digest
88
#
99
class CRC16Kermit < CRC16
1010

11+
REFLECT_INPUT = true
12+
1113
# Generated by `./pycrc.py --algorithm=table-driven --model=kermit --generate=c`
1214
TABLE = [
1315
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
@@ -44,20 +46,6 @@ class CRC16Kermit < CRC16
4446
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
4547
].freeze
4648

47-
#
48-
# Updates the CRC16 Kermit checksum.
49-
#
50-
# @param [String] data
51-
# The data to update the checksum with.
52-
#
53-
def update(data)
54-
data.each_byte do |b|
55-
@crc = (@table[(@crc ^ b) & 0xff] ^ (@crc >> 8)) & 0xffff
56-
end
57-
58-
return self
59-
end
60-
6149
end
6250
end
6351

lib/digest/crc16_x_25.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Digest
66
#
77
class CRC16X25 < CRC16
88

9+
REFLECT_INPUT = true
10+
911
INIT_XOR = 0xffff
1012

1113
INIT_CRC = 0x0 ^ INIT_XOR
@@ -47,7 +49,7 @@ class CRC16X25 < CRC16
4749
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
4850
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
4951
].freeze
50-
52+
5153
end
5254
end
5355

lib/digest/crc16_xmodem.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Digest
66
#
77
class CRC16XModem < CRC16
88

9+
REFLECT_INPUT = false
10+
911
# Generated by `./pycrc.py --algorithm=table-driven --model=xmodem --generate=c`
1012
TABLE = [
1113
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
@@ -42,20 +44,6 @@ class CRC16XModem < CRC16
4244
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
4345
].freeze
4446

45-
#
46-
# Updates the CRC16 XModem checksum.
47-
#
48-
# @param [String] data
49-
# The data to update the checksum with.
50-
#
51-
def update(data)
52-
data.each_byte do |b|
53-
@crc = ((@table[((@crc >> 8) ^ b) & 0xff] ^ (@crc << 8)) & 0xffff)
54-
end
55-
56-
return self
57-
end
58-
5947
end
6048
end
6149

lib/digest/crc16_zmodem.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ module Digest
66
#
77
class CRC16ZModem < CRC16
88

9+
REFLECT_INPUT = false
10+
911
# Generated by `./pycrc.py --algorithm=table-driven --model=zmodem --generate=c`
1012
TABLE = [
1113
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
@@ -42,20 +44,6 @@ class CRC16ZModem < CRC16
4244
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
4345
].freeze
4446

45-
#
46-
# Updates the CRC16 checksum.
47-
#
48-
# @param [String] data
49-
# The data to update the checksum with.
50-
#
51-
def update(data)
52-
data.each_byte do |b|
53-
@crc = ((@table[((@crc >> 8) ^ b) & 0xff] ^ (@crc << 8)) & 0xffff)
54-
end
55-
56-
return self
57-
end
58-
5947
end
6048
end
6149

lib/digest/crc24.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class CRC24 < CRC
88

99
WIDTH = 24
1010

11+
REFLECT_INPUT = false
12+
1113
INIT_CRC = 0xb704ce
1214

1315
# Generated by `./pycrc.py --algorithm=table-drive --model=crc24 --generate=c`
@@ -46,20 +48,6 @@ class CRC24 < CRC
4648
0x42fa2f, 0xc4b6d4, 0xc82f22, 0x4e63d9, 0xd11cce, 0x575035, 0x5bc9c3, 0xdd8538
4749
].freeze
4850

49-
#
50-
# Updates the CRC24 checksum.
51-
#
52-
# @param [String] data
53-
# The data to update the checksum with.
54-
#
55-
def update(data)
56-
data.each_byte do |b|
57-
@crc = ((@table[((@crc >> 16) ^ b) & 0xff] ^ (@crc << 8)) & 0xffffff)
58-
end
59-
60-
return self
61-
end
62-
6351
end
6452
end
6553

0 commit comments

Comments
 (0)