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.
data/gemstub.rb CHANGED
@@ -1,22 +1,42 @@
1
- require_relative "lib/crc/version"
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 = CRC::VERSION
6
- s.summary = "general CRC generator"
11
+ s.version = ver
12
+ s.summary = "generic CRC calculator"
7
13
  s.description = <<EOS
8
- This is a general CRC (Cyclic Redundancy Check) generator for ruby.
9
- It is written by pure ruby.
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://osdn.jp/projects/rutsubo/"
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.osdn.me"
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
- s.required_ruby_version = ">= 2.0"
19
- s.add_development_dependency "rake"
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
- rescue LoadError
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 general CRC generator.
20
+ # This is a generic CRC calculator.
17
21
  #
18
- # When you want to use CRC-32 module, there are following ways:
22
+ # When you want to use CRC-32 model, there are following ways:
19
23
  #
20
- # 1. Generate CRC-32'd value at direct:
24
+ # 1. Calculate CRC-32'd value at direct:
21
25
  #
22
26
  # CRC.crc32("123456789") # => 3421780262
23
27
  #
24
- # 2. Generate CRC-32'd hex-digest at direct:
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
- # Utilities.
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
- def build_table(bitsize, polynomial, unfreeze = false, slice: 16)
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
- # call-seq:
170
- # slide_to_head(bitsize, state, polynomial, bitmask) { |padded_state, padded_polynomial, shift_input, off_msb, carries_mask, padding_size| padded_new_state } -> new_state
171
- #
172
- # YIELD(padded_state, padded_polynomial, shift_input, off_msb, carries_mask, padding_size) -> padded_new_state
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 ^ xor_output
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
- case
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(*args)
302
- initialize_args(args) do |seq, initial_crc, size|
303
- m = self.class
304
- @state = m.setup((initial_crc || m.initial_crc).to_i)
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 = self.class
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 = self.class.update(seq, 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
- self.class.finish(state)
181
+ get_crc_model.finish(state)
327
182
  end
328
183
 
329
184
  def +(crc2)
330
- raise ArgumentError, "not a CRC instance (#{crc2.inspect})" unless crc2.kind_of?(CRC)
331
- m1 = self.class
332
- m2 = crc2.class
333
- unless m1.bitsize == m2.bitsize &&
334
- m1.polynomial == m2.polynomial &&
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
- m1 = self.class
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, self.class.bitsize)
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, self.class.bitsize)
222
+ Aux.digest(state, get_crc_model.bitsize)
381
223
  end
382
224
 
383
225
  def hexdigest
384
- Aux.hexdigest(crc, self.class.bitsize)
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, self.class.bitsize)
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
- "\#<#{self.class}:#{hexdigest}>"
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
- private
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(modulename)
431
- modulename1 = modulename.to_s.gsub(/[\W_]+/, "")
432
- modulename1.downcase!
433
- MODULE_TABLE[modulename1] or raise NameError, "modulename is not matched (for #{modulename})"
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(modulename, seq, crc = nil)
439
- lookup(modulename).crc(seq, crc)
256
+ def crc(modelname, seq, crc = nil)
257
+ lookup(modelname).crc(seq, crc)
440
258
  end
441
259
 
442
- def digest(modulename, seq, crc = nil)
443
- lookup(modulename).digest(seq, crc)
260
+ def digest(modelname, seq, crc = nil)
261
+ lookup(modelname).digest(seq, crc)
444
262
  end
445
263
 
446
- def hexdigest(modulename, seq, crc = nil)
447
- lookup(modulename).hexdigest(seq, crc)
264
+ def hexdigest(modelname, seq, crc = nil)
265
+ lookup(modelname).hexdigest(seq, crc)
448
266
  end
449
267
  end
450
268
 
451
- require_relative "crc/_modules"
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 module classes.
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 MODULE_TABLE.key?(nm1)
467
- raise NameError, "collision crc-module name: #{nm} (#{crc::GENERATOR} and #{MODULE_TABLE[nm1]::GENERATOR})"
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
- MODULE_TABLE[nm1] = crc
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