crc 0.3 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/HISTORY.ja.md +85 -0
- data/README.ja.md +281 -0
- data/README.md +167 -73
- data/bin/rbcrc +297 -0
- data/bin/rbcrc.orig +295 -0
- data/gemstub.rb +30 -10
- data/lib/crc.rb +63 -257
- data/lib/crc/_aux.rb +37 -0
- data/lib/crc/_byruby.rb +94 -41
- data/lib/crc/_combine.rb +1 -1
- data/lib/crc/_extensions.rb +211 -0
- data/lib/crc/_file.rb +15 -0
- data/lib/crc/_magic.rb +93 -0
- data/lib/crc/{_modules.rb → _models.rb} +7 -6
- data/lib/crc/_shift.rb +198 -0
- data/lib/crc/_utils.rb +114 -0
- data/lib/crc/acrc.rb +18 -73
- data/lib/crc/codegen.rb +881 -0
- data/lib/crc/version.rb +1 -1
- data/test/common.rb +23 -0
- data/test/self_check.rb +31 -0
- data/test/test_arc.rb +23 -0
- data/test/test_block.rb +28 -0
- data/test/test_magic.rb +25 -0
- metadata +42 -19
data/gemstub.rb
CHANGED
@@ -1,22 +1,42 @@
|
|
1
|
-
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
unless File.read("README.md", mode: "rt") =~ /^\s*\*\s*version: (\d+(?:\.\w+)+)/i
|
4
|
+
raise "version number is not found in ``README.md''"
|
5
|
+
end
|
6
|
+
|
7
|
+
ver = $1
|
2
8
|
|
3
9
|
GEMSTUB = Gem::Specification.new do |s|
|
4
10
|
s.name = "crc"
|
5
|
-
s.version =
|
6
|
-
s.summary = "
|
11
|
+
s.version = ver
|
12
|
+
s.summary = "generic CRC calculator"
|
7
13
|
s.description = <<EOS
|
8
|
-
|
9
|
-
|
10
|
-
Customization is posible for 1 to 64 bit width, any polynomial primitives, and with/without bit reflection input/output.
|
14
|
+
Pure ruby implemented generic CRC (Cyclic Redundancy Check) calculator.
|
15
|
+
Customization is posible for 1 to 64 bit width, any polynomials, and with/without bit reflection input/output.
|
11
16
|
If you need more speed, please use crc-turbo.
|
12
17
|
EOS
|
13
|
-
s.homepage = "https://
|
18
|
+
s.homepage = "https://github.com/dearblue/ruby-crc"
|
14
19
|
s.licenses = ["BSD-2-Clause", "Zlib", "CC0-1.0"]
|
15
20
|
s.author = "dearblue"
|
16
|
-
s.email = "dearblue@users.
|
21
|
+
s.email = "dearblue@users.noreply.github.com"
|
22
|
+
|
23
|
+
s.required_ruby_version = ">= 2.2"
|
24
|
+
s.add_development_dependency "rake", ">= 12"
|
25
|
+
end
|
26
|
+
|
27
|
+
verfile = "lib/crc/version.rb"
|
28
|
+
task "version" => verfile
|
29
|
+
file verfile => "README.md" do
|
30
|
+
File.write(verfile, <<-"EOS", mode: "wb")
|
31
|
+
#!ruby
|
17
32
|
|
18
|
-
|
19
|
-
|
33
|
+
class CRC
|
34
|
+
VERSION = "#{ver}"
|
20
35
|
end
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
|
39
|
+
LIB << verfile
|
40
|
+
LIB.uniq!
|
21
41
|
|
22
42
|
EXTRA << "benchmark.rb"
|
data/lib/crc.rb
CHANGED
@@ -2,26 +2,30 @@
|
|
2
2
|
|
3
3
|
if ENV["RUBY_CRC_NOFAST"].to_i > 0
|
4
4
|
require_relative "crc/_byruby"
|
5
|
+
CRC::IMPLEMENT = :ruby
|
5
6
|
else
|
6
7
|
begin
|
8
|
+
gem "crc-turbo", "~> 0.4.A"
|
7
9
|
require File.join("crc", RUBY_VERSION[/\d+\.\d+/], "_turbo.so")
|
8
|
-
|
10
|
+
CRC::IMPLEMENT = :turbo
|
11
|
+
rescue LoadError, Gem::MissingSpecVersionError
|
9
12
|
require_relative "crc/_byruby"
|
13
|
+
CRC::IMPLEMENT = :ruby
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
13
17
|
require_relative "crc/version"
|
14
18
|
|
15
19
|
#
|
16
|
-
# This is a
|
20
|
+
# This is a generic CRC calculator.
|
17
21
|
#
|
18
|
-
# When you want to use CRC-32
|
22
|
+
# When you want to use CRC-32 model, there are following ways:
|
19
23
|
#
|
20
|
-
# 1.
|
24
|
+
# 1. Calculate CRC-32'd value at direct:
|
21
25
|
#
|
22
26
|
# CRC.crc32("123456789") # => 3421780262
|
23
27
|
#
|
24
|
-
# 2.
|
28
|
+
# 2. Calculate CRC-32'd hex-digest at direct:
|
25
29
|
#
|
26
30
|
# CRC::CRC32.hexdigest("123456789") # => "CBF43926"
|
27
31
|
#
|
@@ -41,159 +45,31 @@ class CRC
|
|
41
45
|
|
42
46
|
extend Utils
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
module Utils
|
48
|
-
extend self
|
49
|
-
|
50
|
-
def bitreflect_reference(num, bitsize)
|
51
|
-
n = 0
|
52
|
-
bitsize.times { n <<= 1; n |= (num & 0x01); num >>= 1 }
|
53
|
-
n
|
54
|
-
end
|
55
|
-
|
56
|
-
def bitreflect(num, bitsize)
|
57
|
-
case
|
58
|
-
when bitsize > 128
|
59
|
-
bitreflect_reference(num, bitsize)
|
60
|
-
when bitsize > 64
|
61
|
-
bitreflect128(num) >> (128 - bitsize)
|
62
|
-
when bitsize > 32
|
63
|
-
bitreflect64(num) >> (64 - bitsize)
|
64
|
-
when bitsize > 16
|
65
|
-
bitreflect32(num) >> (32 - bitsize)
|
66
|
-
when bitsize > 8
|
67
|
-
bitreflect16(num) >> (16 - bitsize)
|
68
|
-
else
|
69
|
-
bitreflect8(num) >> (8 - bitsize)
|
70
|
-
end
|
71
|
-
end
|
48
|
+
require_relative "crc/_extensions"
|
49
|
+
require_relative "crc/_utils"
|
50
|
+
require_relative "crc/_aux"
|
72
51
|
|
73
|
-
|
74
|
-
bitmask = ~(~0 << bitsize)
|
75
|
-
table = []
|
76
|
-
Aux.slide_to_head(bitsize, 0, bitmask & polynomial, bitmask) do |xx, poly, csh, head, carries, pad|
|
77
|
-
slice.times do |s|
|
78
|
-
table << (t = [])
|
79
|
-
256.times do |b|
|
80
|
-
r = (s == 0 ? (b << csh) : (table[-2][b]))
|
81
|
-
8.times { r = (r[head] == 0) ? (r << 1) : (((carries & r) << 1) ^ poly) }
|
82
|
-
t << r
|
83
|
-
end
|
84
|
-
t.freeze unless unfreeze
|
85
|
-
t
|
86
|
-
end
|
87
|
-
0
|
88
|
-
end
|
89
|
-
table.freeze unless unfreeze
|
90
|
-
table
|
91
|
-
end
|
92
|
-
|
93
|
-
def build_reflect_table(bitsize, polynomial, unfreeze = false, slice: 16)
|
94
|
-
polynomial = bitreflect(polynomial, bitsize)
|
95
|
-
table = []
|
96
|
-
slice.times do |s|
|
97
|
-
table << (t = [])
|
98
|
-
256.times do |b|
|
99
|
-
r = (s == 0) ? b : table[-2][b]
|
100
|
-
8.times { r = (r[0] == 0) ? (r >> 1) : ((r >> 1) ^ polynomial) }
|
101
|
-
t << r
|
102
|
-
end
|
103
|
-
t.freeze unless unfreeze
|
104
|
-
t
|
105
|
-
end
|
106
|
-
|
107
|
-
table.freeze unless unfreeze
|
108
|
-
table
|
109
|
-
end
|
110
|
-
|
111
|
-
def export_table(table, bitsize, linewidth, indentsize = 2)
|
112
|
-
bitsize0 = bitsize.to_i
|
113
|
-
indent = " " * indentsize.to_i
|
114
|
-
case
|
115
|
-
when bitsize0 > 64 || bitsize0 < 1
|
116
|
-
raise "invalid bitsize (expected to 1..64, but given #{bitsize})"
|
117
|
-
when bitsize0 > 32
|
118
|
-
packformat = "Q>"
|
119
|
-
hexwidth = 16
|
120
|
-
when bitsize0 > 16
|
121
|
-
packformat = "N"
|
122
|
-
hexwidth = 8
|
123
|
-
when bitsize0 > 8
|
124
|
-
packformat = "n"
|
125
|
-
hexwidth = 4
|
126
|
-
else # when bitsize0 > 0
|
127
|
-
packformat = "C"
|
128
|
-
hexwidth = 2
|
129
|
-
end
|
130
|
-
table = table.to_a.pack("#{packformat}*").unpack("H*")[0]
|
131
|
-
table.gsub!(/(?<=\w)(?=\w{#{hexwidth}}{#{linewidth}}+$)/, "\n")
|
132
|
-
table.gsub!(/(?<=\w)(?=\w{#{hexwidth}}+$)/, " ")
|
133
|
-
table.gsub!(/(?<=\w)(?=\s|$)/, ",")
|
134
|
-
table.gsub!(/(?:(?<=^)|(?<=\s))(?=\w)/, "0x")
|
135
|
-
table.gsub!(/^/, "#{indent} ")
|
136
|
-
<<-EOS
|
137
|
-
#{indent}TABLE = [
|
138
|
-
#{table}
|
139
|
-
#{indent}].freeze
|
140
|
-
EOS
|
141
|
-
end
|
142
|
-
|
143
|
-
#puts export_table(build_table(16, 0x1021), 16, 8); #abort "DEBUG EXIT"
|
144
|
-
#puts export_table(build_table!(32, 0xEDB88320), 32, 8); abort "DEBUG EXIT"
|
145
|
-
end
|
146
|
-
|
147
|
-
extend Utils
|
148
|
-
|
149
|
-
#
|
150
|
-
# Internal using module.
|
151
|
-
#
|
152
|
-
module Aux
|
153
|
-
def self.DIGEST(num, bitsize)
|
154
|
-
bits = (bitsize + 7) / 8 * 8
|
155
|
-
seq = ""
|
156
|
-
(bits - 8).step(0, -8) { |i| seq << yield((num >> i) & 0xff) }
|
157
|
-
seq
|
158
|
-
end
|
159
|
-
|
160
|
-
def self.digest(num, bitsize)
|
161
|
-
DIGEST(num, bitsize) { |n| n.chr(Encoding::BINARY) }
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.hexdigest(num, bitsize)
|
165
|
-
DIGEST(num, bitsize) { |n| "%02X" % n }
|
166
|
-
end
|
52
|
+
using Extensions
|
167
53
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
#
|
174
|
-
def self.slide_to_head(bitsize, state, polynomial, bitmask)
|
175
|
-
pad = bitsize & 0x07
|
176
|
-
if pad == 0
|
177
|
-
yield(state, polynomial, bitsize - 8, bitsize - 1, bitmask >> 1, 0)
|
178
|
-
else
|
179
|
-
pad = 8 - pad
|
180
|
-
yield(state << pad, polynomial << pad, bitsize - 8 + pad, bitsize - 1 + pad, (bitmask << pad >> 1) | 0x7f, pad) >> pad
|
181
|
-
end
|
54
|
+
module Calculator
|
55
|
+
def [](seq, *args)
|
56
|
+
c = new(*args)
|
57
|
+
c.update(seq) if seq
|
58
|
+
c
|
182
59
|
end
|
183
|
-
end
|
184
60
|
|
185
|
-
module ModuleClass
|
186
61
|
def setup(crc = nil)
|
187
62
|
crc ||= initial_crc
|
63
|
+
crc ^= xor_output
|
188
64
|
crc = CRC.bitreflect(crc, bitsize) if reflect_input? ^ reflect_output?
|
189
|
-
crc
|
65
|
+
crc & bitmask
|
190
66
|
end
|
191
67
|
|
192
68
|
alias init setup
|
193
69
|
|
194
70
|
def finish(state)
|
195
71
|
state = CRC.bitreflect(state, bitsize) if reflect_input? ^ reflect_output?
|
196
|
-
state ^ xor_output
|
72
|
+
state ^ xor_output & bitmask
|
197
73
|
end
|
198
74
|
|
199
75
|
def crc(seq, crc = nil)
|
@@ -209,24 +85,7 @@ class CRC
|
|
209
85
|
end
|
210
86
|
|
211
87
|
def variant?(obj)
|
212
|
-
|
213
|
-
when obj.kind_of?(CRC)
|
214
|
-
mod = obj.class
|
215
|
-
when obj.kind_of?(Class) && obj < CRC
|
216
|
-
mod = obj
|
217
|
-
else
|
218
|
-
return false
|
219
|
-
end
|
220
|
-
|
221
|
-
if bitsize == mod.bitsize &&
|
222
|
-
polynomial == mod.polynomial &&
|
223
|
-
reflect_input? == mod.reflect_input? &&
|
224
|
-
reflect_output? == mod.reflect_output? &&
|
225
|
-
xor_output == mod.xor_output
|
226
|
-
true
|
227
|
-
else
|
228
|
-
false
|
229
|
-
end
|
88
|
+
obj.variant_for?(self)
|
230
89
|
end
|
231
90
|
|
232
91
|
#
|
@@ -296,26 +155,22 @@ class CRC
|
|
296
155
|
#
|
297
156
|
# call-seq:
|
298
157
|
# initialize(initial_crc = nil, size = 0)
|
299
|
-
# initialize(seq, initial_crc = nil, size = 0)
|
300
158
|
#
|
301
|
-
def initialize(
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
@size = size.to_i
|
306
|
-
update(seq) if seq
|
307
|
-
end
|
159
|
+
def initialize(initial_crc = nil, size = 0)
|
160
|
+
m = get_crc_model
|
161
|
+
@state = m.setup((initial_crc || m.initial_crc).to_i)
|
162
|
+
@size = size.to_i
|
308
163
|
end
|
309
164
|
|
310
165
|
def reset(initial_crc = nil, size = 0)
|
311
|
-
m =
|
166
|
+
m = get_crc_model
|
312
167
|
@state = m.setup((initial_crc || m.initial_crc).to_i)
|
313
168
|
@size = size.to_i
|
314
169
|
self
|
315
170
|
end
|
316
171
|
|
317
172
|
def update(seq)
|
318
|
-
@state =
|
173
|
+
@state = get_crc_model.update(seq, state)
|
319
174
|
@size += seq.bytesize
|
320
175
|
self
|
321
176
|
end
|
@@ -323,20 +178,15 @@ class CRC
|
|
323
178
|
alias << update
|
324
179
|
|
325
180
|
def crc
|
326
|
-
|
181
|
+
get_crc_model.finish(state)
|
327
182
|
end
|
328
183
|
|
329
184
|
def +(crc2)
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
unless
|
334
|
-
|
335
|
-
m1.reflect_input? == m2.reflect_input? &&
|
336
|
-
m1.reflect_output? == m2.reflect_output? &&
|
337
|
-
# m1.initial_crc == m2.initial_crc &&
|
338
|
-
m1.xor_output == m2.xor_output
|
339
|
-
raise ArgumentError, "different CRC module (#{m1.inspect} and #{m2.inspect})"
|
185
|
+
m1 = get_crc_model
|
186
|
+
m2 = crc2.get_crc_model
|
187
|
+
raise ArgumentError, "not a CRC instance (#{crc2.inspect})" unless m2
|
188
|
+
unless m2.variant_for?(m1)
|
189
|
+
raise ArgumentError, "different CRC model (#{m1.inspect} and #{m2.inspect})"
|
340
190
|
end
|
341
191
|
m1.new(m1.combine(crc, crc2.crc, crc2.size), size + crc2.size)
|
342
192
|
end
|
@@ -344,15 +194,7 @@ class CRC
|
|
344
194
|
def ==(a)
|
345
195
|
case a
|
346
196
|
when CRC
|
347
|
-
|
348
|
-
m2 = a.class
|
349
|
-
if m1.bitsize == m2.bitsize &&
|
350
|
-
m1.polynomial == m2.polynomial &&
|
351
|
-
m1.reflect_input? == m2.reflect_input? &&
|
352
|
-
m1.reflect_output? == m2.reflect_output? &&
|
353
|
-
# m1.initial_crc == m2.initial_crc &&
|
354
|
-
m1.xor_output == m2.xor_output &&
|
355
|
-
state == a.state
|
197
|
+
if variant_for?(a) && state == a.state
|
356
198
|
true
|
357
199
|
else
|
358
200
|
false
|
@@ -372,87 +214,70 @@ class CRC
|
|
372
214
|
end
|
373
215
|
|
374
216
|
def digest
|
375
|
-
Aux.digest(crc,
|
217
|
+
Aux.digest(crc, get_crc_model.bitsize)
|
376
218
|
end
|
377
219
|
|
378
220
|
# return digest as internal state
|
379
221
|
def digest!
|
380
|
-
Aux.digest(state,
|
222
|
+
Aux.digest(state, get_crc_model.bitsize)
|
381
223
|
end
|
382
224
|
|
383
225
|
def hexdigest
|
384
|
-
Aux.hexdigest(crc,
|
226
|
+
Aux.hexdigest(crc, get_crc_model.bitsize)
|
385
227
|
end
|
386
228
|
|
387
229
|
# return hex-digest as internal state
|
388
230
|
def hexdigest!
|
389
|
-
Aux.hexdigest(state,
|
231
|
+
Aux.hexdigest(state, get_crc_model.bitsize)
|
390
232
|
end
|
391
233
|
|
392
234
|
alias to_str hexdigest
|
393
235
|
alias to_s hexdigest
|
394
236
|
|
395
237
|
def inspect
|
396
|
-
"\#<#{
|
238
|
+
"\#<#{get_crc_model}:#{hexdigest}>"
|
397
239
|
end
|
398
240
|
|
399
241
|
def pretty_inspect(q)
|
400
242
|
q.text inspect
|
401
243
|
end
|
402
244
|
|
403
|
-
|
404
|
-
def initialize_args(args)
|
405
|
-
case args.size
|
406
|
-
when 0
|
407
|
-
yield nil, nil, 0
|
408
|
-
when 1
|
409
|
-
if args[0].kind_of?(String)
|
410
|
-
yield args[0], nil, 0
|
411
|
-
else
|
412
|
-
yield nil, args[0], 0
|
413
|
-
end
|
414
|
-
when 2
|
415
|
-
if args[0].kind_of?(String)
|
416
|
-
yield args[0], args[1], 0
|
417
|
-
else
|
418
|
-
yield nil, args[0], args[1].to_i
|
419
|
-
end
|
420
|
-
when 3
|
421
|
-
yield args[0], args[1], args[2].to_i
|
422
|
-
else
|
423
|
-
raise ArgumentError, "wrong argument size (given #{args.size}, expect 0..3)"
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
MODULE_TABLE = {}
|
245
|
+
MODEL_TABLE = {}
|
428
246
|
|
429
247
|
class << self
|
430
|
-
def lookup(
|
431
|
-
|
432
|
-
|
433
|
-
|
248
|
+
def lookup(modelname)
|
249
|
+
modelname1 = modelname.to_s.gsub(/[\W_]+/, "")
|
250
|
+
modelname1.downcase!
|
251
|
+
MODEL_TABLE[modelname1] or raise NameError, "modelname is not matched (for #{modelname})"
|
434
252
|
end
|
435
253
|
|
436
254
|
alias [] lookup
|
437
255
|
|
438
|
-
def crc(
|
439
|
-
lookup(
|
256
|
+
def crc(modelname, seq, crc = nil)
|
257
|
+
lookup(modelname).crc(seq, crc)
|
440
258
|
end
|
441
259
|
|
442
|
-
def digest(
|
443
|
-
lookup(
|
260
|
+
def digest(modelname, seq, crc = nil)
|
261
|
+
lookup(modelname).digest(seq, crc)
|
444
262
|
end
|
445
263
|
|
446
|
-
def hexdigest(
|
447
|
-
lookup(
|
264
|
+
def hexdigest(modelname, seq, crc = nil)
|
265
|
+
lookup(modelname).hexdigest(seq, crc)
|
448
266
|
end
|
449
267
|
end
|
450
268
|
|
451
|
-
|
269
|
+
# NOTE: "Calcurator" は typo ですが、後方互換のため一時的に残します。
|
270
|
+
# TODO: CRC::Calcurator はいずれ削除されます。
|
271
|
+
CRC::Calcurator = CRC::Calculator
|
272
|
+
|
273
|
+
require_relative "crc/_models"
|
452
274
|
require_relative "crc/_combine"
|
275
|
+
require_relative "crc/_shift"
|
276
|
+
require_relative "crc/_magic"
|
277
|
+
require_relative "crc/_file"
|
453
278
|
|
454
279
|
#
|
455
|
-
# Create CRC
|
280
|
+
# Create CRC model classes.
|
456
281
|
#
|
457
282
|
LIST.each do |bitsize, polynomial, refin, refout, initial_crc, xor, check, *names|
|
458
283
|
names.flatten!
|
@@ -463,10 +288,10 @@ class CRC
|
|
463
288
|
|
464
289
|
names.each do |nm|
|
465
290
|
nm1 = nm.downcase.gsub(/[\W_]+/, "")
|
466
|
-
if
|
467
|
-
raise NameError, "collision crc-
|
291
|
+
if MODEL_TABLE.key?(nm1)
|
292
|
+
raise NameError, "collision crc-model name: #{nm} ({#{crc.to_str}} and {#{MODEL_TABLE[nm1].to_str}})"
|
468
293
|
end
|
469
|
-
|
294
|
+
MODEL_TABLE[nm1] = crc
|
470
295
|
|
471
296
|
name = nm.sub(/(?<=\bCRC)-(?=\d+)/, "").gsub(/[\W]+/, "_")
|
472
297
|
const_set(name, crc)
|
@@ -484,23 +309,4 @@ class CRC
|
|
484
309
|
check = Integer(check.to_i) if check
|
485
310
|
crc.const_set :CHECK, check
|
486
311
|
end
|
487
|
-
|
488
|
-
if $0 == __FILE__
|
489
|
-
$stderr.puts "#{__FILE__}:#{__LINE__}: SELF CHECK for CRC modules (#{File.basename($".grep(/_(?:byruby|turbo)/)[0]||"")})\n"
|
490
|
-
MODULE_TABLE.values.uniq.each do |crc|
|
491
|
-
check = crc::CHECK
|
492
|
-
checked = crc.crc("123456789")
|
493
|
-
case check
|
494
|
-
when nil
|
495
|
-
$stderr.puts "| %20s(\"123456789\") = %16X (check only)\n" % [crc.name, checked]
|
496
|
-
when checked
|
497
|
-
;
|
498
|
-
else
|
499
|
-
$stderr.puts "| %20s(\"123456789\") = %16X (expect to %X)\n" % [crc.name, checked, check]
|
500
|
-
end
|
501
|
-
end
|
502
|
-
$stderr.puts "#{__FILE__}:#{__LINE__}: DONE SELF CHECK\n"
|
503
|
-
|
504
|
-
exit
|
505
|
-
end
|
506
312
|
end
|