crc 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.md +67 -0
- data/Rakefile +212 -0
- data/benchmark.rb +45 -0
- data/gemstub.rb +21 -0
- data/lib/crc.rb +405 -0
- data/lib/crc/_byruby.rb +226 -0
- data/lib/crc/_modules.rb +105 -0
- data/lib/crc/finder.rb +29 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bee58adf97d048655d45b3f33a14781b150638c7
|
4
|
+
data.tar.gz: bd49389a8b03124937b87c7a09deaf1fd03b3f8e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba1a3e68cef316f5e46db132c8fceeb66bace335427ec49b01987f87bb12b74ab7409649b5240baa4876231fd52da93f999fb6fdb01fa1f56657a9183f3b03fd
|
7
|
+
data.tar.gz: 707b71a8fcd2dfe0593ce3d94b4fbd3b2265c202e67d6e704c39c758c275e1386fe14626090c8ace254c78edb6e7ff03846b8ea551bf4335e110c1eef78f9a41
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2016, dearblue. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or
|
4
|
+
without modification, are permitted provided that the following
|
5
|
+
conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in
|
11
|
+
the documentation and/or other materials provided with the
|
12
|
+
distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
15
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
16
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
17
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
18
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
19
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
20
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
21
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
22
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
23
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
# crc - CRC generator for ruby
|
3
|
+
|
4
|
+
This is a general CRC (Cyclic Redundancy Check) generator for ruby.
|
5
|
+
|
6
|
+
It is written by pure ruby with based on slice-by-eight algorithm (byte-order-free slice-by-16 algorithm).
|
7
|
+
|
8
|
+
Included built-in CRC modules are CRC-32, CRC-64-ECMA, CRC-64-ISO, CRC-16-CCITT, CRC-16-IBM, CRC-8, CRC-5-USB, CRC-5-EPC and more.
|
9
|
+
|
10
|
+
And your defined CRC modules to use.
|
11
|
+
|
12
|
+
This is slower than x95+ of zlib/crc32, and slower than x135+ of extlzma/crc32 on FreeBSD 10.3R amd64.
|
13
|
+
|
14
|
+
If you need more speed, please use crc-turbo.
|
15
|
+
|
16
|
+
|
17
|
+
## SUMMARY
|
18
|
+
|
19
|
+
* package name: crc
|
20
|
+
* author: dearblue (mailto:dearblue@users.osdn.me)
|
21
|
+
* report issue to: <https://osdn.jp/projects/rutsubo/ticket/>
|
22
|
+
* how to install: ``gem install crc``
|
23
|
+
* version: 0.1
|
24
|
+
* release quality: thechnical preview
|
25
|
+
* licensing: BSD-2-Clause
|
26
|
+
* dependency gems: none
|
27
|
+
* dependency external c libraries: none
|
28
|
+
* bundled external c libraries: none
|
29
|
+
|
30
|
+
## FEATURES
|
31
|
+
|
32
|
+
* ``CRC.crc32(seq, init = 0) -> crc-32 integer`` (likely as ``Zlib.crc32``)
|
33
|
+
* ``CRC::CRC32.crc(seq, init = 0) -> crc-32 integer`` (likely as ``Zlib.crc32``)
|
34
|
+
* ``CRC::CRC32.digest(seq, init = 0) -> crc-32 digest`` (likely as ``Digest::XXXX.digest``)
|
35
|
+
* ``CRC::CRC32.hexdigest(seq, init = 0) -> crc-32 hex-digest`` (likely as ``Digest::XXXX.hexdigest``)
|
36
|
+
* ``CRC::CRC32.new(init = 0) -> crc-32 context`` (likely as ``Digest::XXXX.new``)
|
37
|
+
* ``CRC::CRC32#update(seq) -> self`` (likely as ``Digest::XXXX#update``)
|
38
|
+
* ``CRC::CRC32#finish -> crc-32 integer`` (likely as ``Digest::XXXX#finish``)
|
39
|
+
* ``CRC.crc("crc-32", seq, init = 0) -> crc-32 integer``
|
40
|
+
* ``CRC.digest("crc-32", seq, init = 0) -> crc-32 digest``
|
41
|
+
* ``CRC.hexdigest("crc-32", seq, init = 0) -> crc-32 hex-digest``
|
42
|
+
|
43
|
+
----
|
44
|
+
|
45
|
+
* ``CRC.create_module(bitsize, poly, init_state, refin, refout, xorout) -> new crc module class``
|
46
|
+
|
47
|
+
``` ruby:ruby
|
48
|
+
MyCRC32 = CRC.create_module(32, 0x04C11DB7)
|
49
|
+
p MyCRC32.class # => Class
|
50
|
+
p MyCRC32.hexdigest("123456789") # => "CBF43926"
|
51
|
+
```
|
52
|
+
|
53
|
+
|
54
|
+
## BUILD-IN CRC MODULES
|
55
|
+
|
56
|
+
``` shell:shell
|
57
|
+
% ruby -rcrc -e 'puts CRC::MODULE_TABLE.values.uniq.map { |m| m::TRAITS.name }.join(", ")'
|
58
|
+
```
|
59
|
+
|
60
|
+
CRC-1, CRC-3-ROHC, CRC-4-ITU, CRC-5-EPC, CRC-5-ITU, CRC-5-USB, CRC-6-CDMA2000-A, CRC-6-CDMA2000-B, CRC-6-DARC, CRC-6-ITU, CRC-7, CRC-7-MVB, CRC-8, CRC-8-CCITT, CRC-8-Dallas/Maxim, CRC-8-DARC, CRC-8-SAE, CRC-8-WCDMA, CRC-10, CRC-10-CDMA2000, CRC-11, CRC-12, CRC-12-CDMA2000, CRC-13-BBC, CRC-14-DARC, CRC-15-CAN, CRC-15-MPT1327, Chakravarty, CRC-16-ARINC, CRC-16-CCITT, CRC-16-CDMA2000, CRC-16-DECT, CRC-16-T10-DIF, CRC-16-DNP, CRC-16-IBM, CRC-16-LZH, CRC-17-CAN, CRC-21-CAN, CRC-24, CRC-24-Radix-64, CRC-30, CRC-32, CRC-32C, CRC-32K, CRC-32K2, CRC-32Q, CRC-40-GSM, CRC-64-ECMA, CRC-64-ISO
|
61
|
+
|
62
|
+
|
63
|
+
## ENVIRONMENT VARIABLES FOR BEHAVIOR
|
64
|
+
|
65
|
+
* ``RUBY_CRC_NOFAST=1``: Force use ruby implementation with slice-by-16 algorithm. Not used "crc-turbo".
|
66
|
+
* ``RUBY_CRC_NOFAST=2``: Switch to lookup table algorithm from slice-by-16 algorithm. Slower to about 52% (when CRC-32).
|
67
|
+
* ``RUBY_CRC_NOFAST=3``: Switch to reference algorithm from slice-by-16 algorithm. Slower to about 7% (when CRC-32).
|
data/Rakefile
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
|
2
|
+
require "pathname"
|
3
|
+
require "rake/clean"
|
4
|
+
|
5
|
+
docnames = "{README,LICENSE,CHANGELOG,Changelog,HISTORY}"
|
6
|
+
doctypes = "{,.txt,.rd,.rdoc,.md,.markdown}"
|
7
|
+
cexttypes = "{c,C,cc,cxx,cpp,h,H,hh}"
|
8
|
+
|
9
|
+
DOC = FileList["#{docnames}{,.ja}#{doctypes}"] +
|
10
|
+
FileList["{contrib,ext}/**/#{docnames}{,.ja}#{doctypes}"] +
|
11
|
+
FileList["ext/**/*.#{cexttypes}"]
|
12
|
+
EXT = FileList["ext/**/*"]
|
13
|
+
BIN = FileList["bin/*"]
|
14
|
+
LIB = FileList["lib/**/*.rb"]
|
15
|
+
SPEC = FileList["spec/**/*"]
|
16
|
+
TEST = FileList["test/**/*"]
|
17
|
+
EXAMPLE = FileList["examples/**/*"]
|
18
|
+
GEMSTUB_SRC = "gemstub.rb"
|
19
|
+
RAKEFILE = [File.basename(__FILE__), GEMSTUB_SRC]
|
20
|
+
EXTRA = []
|
21
|
+
EXTCONF = FileList["ext/**/extconf.rb"]
|
22
|
+
EXTCONF.reject! { |n| !File.file?(n) }
|
23
|
+
EXTMAP = {}
|
24
|
+
|
25
|
+
load GEMSTUB_SRC
|
26
|
+
|
27
|
+
EXTMAP.dup.each_pair do |dir, name|
|
28
|
+
EXTMAP[Pathname.new(dir).cleanpath.to_s] = Pathname.new(name).cleanpath.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
GEMSTUB.extensions += EXTCONF
|
32
|
+
GEMSTUB.executables += FileList["bin/*"].map { |n| File.basename n }
|
33
|
+
GEMSTUB.executables.sort!
|
34
|
+
|
35
|
+
PACKAGENAME = "#{GEMSTUB.name}-#{GEMSTUB.version}"
|
36
|
+
GEMFILE = "#{PACKAGENAME}.gem"
|
37
|
+
GEMSPEC = "#{PACKAGENAME}.gemspec"
|
38
|
+
|
39
|
+
GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + EXTRA
|
40
|
+
GEMSTUB.files.sort!
|
41
|
+
if GEMSTUB.rdoc_options.nil? || GEMSTUB.rdoc_options.empty?
|
42
|
+
readme = %W(.md .markdown .rd .rdoc .txt #{""}).map { |ext| "README#{ext}" }.find { |m| DOC.find { |n| n == m } }
|
43
|
+
GEMSTUB.rdoc_options = %w(--charset UTF-8) + (readme ? %W(-m #{readme}) : [])
|
44
|
+
end
|
45
|
+
GEMSTUB.extra_rdoc_files += DOC + LIB + EXT.reject { |n| n.include?("/externals/") || !%w(.h .hh .c .cc .cpp .cxx).include?(File.extname(n)) }
|
46
|
+
GEMSTUB.extra_rdoc_files.sort!
|
47
|
+
|
48
|
+
GEMSTUB_TRYOUT = GEMSTUB.dup
|
49
|
+
GEMSTUB_TRYOUT.version = "#{GEMSTUB.version}#{Time.now.strftime(".TRYOUT.%Y%m%d.%H%M%S")}"
|
50
|
+
PACKAGENAME_TRYOUT = "#{GEMSTUB.name}-#{GEMSTUB_TRYOUT.version}"
|
51
|
+
GEMFILE_TRYOUT = "#{PACKAGENAME_TRYOUT}.gem"
|
52
|
+
GEMSPEC_TRYOUT = "#{PACKAGENAME_TRYOUT}.gemspec"
|
53
|
+
|
54
|
+
CLEAN << GEMSPEC << GEMSPEC_TRYOUT
|
55
|
+
CLOBBER << GEMFILE
|
56
|
+
|
57
|
+
task :default => :tryout do
|
58
|
+
$stderr.puts <<-EOS
|
59
|
+
#{__FILE__}:#{__LINE__}:
|
60
|
+
\ttype ``rake release'' to build release package.
|
61
|
+
EOS
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "build tryout package"
|
65
|
+
task :tryout
|
66
|
+
|
67
|
+
desc "build release package"
|
68
|
+
task :release => :all
|
69
|
+
|
70
|
+
unless EXTCONF.empty?
|
71
|
+
RUBYSET ||= (ENV["RUBYSET"] || "").split(",")
|
72
|
+
|
73
|
+
if RUBYSET.nil? || RUBYSET.empty?
|
74
|
+
$stderr.puts <<-EOS
|
75
|
+
#{__FILE__}:
|
76
|
+
|
|
77
|
+
| If you want binary gem package, launch rake with ``RUBYSET`` enviroment
|
78
|
+
| variable for set ruby interpreters by comma separated.
|
79
|
+
|
|
80
|
+
| e.g.) $ rake RUBYSET=ruby
|
81
|
+
| or) $ rake RUBYSET=ruby21,ruby22,ruby23
|
82
|
+
|
|
83
|
+
EOS
|
84
|
+
else
|
85
|
+
platforms = RUBYSET.map { |ruby| `#{ruby} --disable-gems -e "puts RUBY_PLATFORM"`.chomp }
|
86
|
+
platforms1 = platforms.uniq
|
87
|
+
unless platforms1.size == 1 && !platforms1[0].empty?
|
88
|
+
abort <<-EOS
|
89
|
+
#{__FILE__}:#{__LINE__}: different platforms:
|
90
|
+
#{RUBYSET.zip(platforms).map { |ruby, platform| "%24s => %s" % [ruby, platform] }.join("\n")}
|
91
|
+
ABORTED.
|
92
|
+
EOS
|
93
|
+
end
|
94
|
+
PLATFORM = platforms1[0]
|
95
|
+
|
96
|
+
RUBY_VERSIONS = RUBYSET.map do |ruby|
|
97
|
+
ver = `#{ruby} --disable-gems -e "puts RUBY_VERSION"`.slice(/\d+\.\d+/)
|
98
|
+
raise "failed ruby checking - ``#{ruby}''" unless $?.success?
|
99
|
+
[ver, ruby]
|
100
|
+
end
|
101
|
+
|
102
|
+
SOFILES_SET = RUBY_VERSIONS.map { |(ver, ruby)|
|
103
|
+
EXTCONF.map { |extconf|
|
104
|
+
extdir = Pathname.new(extconf).cleanpath.dirname.to_s
|
105
|
+
case
|
106
|
+
when soname = EXTMAP[extdir.sub(/^ext\//i, "")]
|
107
|
+
soname = soname.sub(/\.so$/i, "")
|
108
|
+
when extdir == "ext" || extdir == "."
|
109
|
+
soname = GEMSTUB.name
|
110
|
+
else
|
111
|
+
soname = File.basename(extdir)
|
112
|
+
end
|
113
|
+
|
114
|
+
[ruby, File.join("lib", "#{soname.sub(/(?<=\/)|^(?!.*\/)/, "#{ver}/")}.so"), extconf]
|
115
|
+
}
|
116
|
+
}.flatten(1)
|
117
|
+
SOFILES = SOFILES_SET.map { |(ruby, sopath, extconf)| sopath }
|
118
|
+
|
119
|
+
GEMSTUB_NATIVE = GEMSTUB.dup
|
120
|
+
GEMSTUB_NATIVE.files += SOFILES
|
121
|
+
GEMSTUB_NATIVE.platform = Gem::Platform.new(PLATFORM).to_s
|
122
|
+
GEMSTUB_NATIVE.extensions.clear
|
123
|
+
GEMFILE_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.version}-#{GEMSTUB_NATIVE.platform}.gem"
|
124
|
+
GEMSPEC_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.platform}.gemspec"
|
125
|
+
|
126
|
+
task :all => ["native-gem", GEMFILE]
|
127
|
+
|
128
|
+
desc "build binary gem package"
|
129
|
+
task "native-gem" => GEMFILE_NATIVE
|
130
|
+
|
131
|
+
desc "generate binary gemspec"
|
132
|
+
task "native-gemspec" => GEMSPEC_NATIVE
|
133
|
+
|
134
|
+
file GEMFILE_NATIVE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
|
135
|
+
sh "gem build #{GEMSPEC_NATIVE}"
|
136
|
+
end
|
137
|
+
|
138
|
+
file GEMSPEC_NATIVE => RAKEFILE do
|
139
|
+
File.write(GEMSPEC_NATIVE, GEMSTUB_NATIVE.to_ruby, mode: "wb")
|
140
|
+
end
|
141
|
+
|
142
|
+
desc "build c-extension libraries"
|
143
|
+
task "sofiles" => SOFILES
|
144
|
+
|
145
|
+
SOFILES_SET.each do |(ruby, soname, extconf)|
|
146
|
+
sodir = File.dirname(soname)
|
147
|
+
makefile = File.join(sodir, "Makefile")
|
148
|
+
|
149
|
+
CLEAN << GEMSPEC_NATIVE << sodir
|
150
|
+
CLOBBER << GEMFILE_NATIVE
|
151
|
+
|
152
|
+
directory sodir
|
153
|
+
|
154
|
+
desc "generate Makefile for binary extension library"
|
155
|
+
file makefile => [sodir, extconf] do
|
156
|
+
rel_extconf = Pathname.new(extconf).relative_path_from(Pathname.new(sodir)).to_s
|
157
|
+
cd sodir do
|
158
|
+
sh *%W"#{ruby} #{rel_extconf} --ruby=#{ruby} #{ENV["EXTCONF"]}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
desc "build binary extension library"
|
163
|
+
file soname => [makefile] + EXT do
|
164
|
+
cd sodir do
|
165
|
+
sh "make"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
task :all => GEMFILE
|
174
|
+
task :tryout => GEMFILE_TRYOUT
|
175
|
+
|
176
|
+
desc "generate local rdoc"
|
177
|
+
task :rdoc => DOC + LIB do
|
178
|
+
sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + LIB)
|
179
|
+
end
|
180
|
+
|
181
|
+
desc "launch rspec"
|
182
|
+
task rspec: :all do
|
183
|
+
sh "rspec"
|
184
|
+
end
|
185
|
+
|
186
|
+
desc "build gem package"
|
187
|
+
task gem: GEMFILE
|
188
|
+
|
189
|
+
desc "generate gemspec"
|
190
|
+
task gemspec: GEMSPEC
|
191
|
+
|
192
|
+
desc "print package name"
|
193
|
+
task "package-name" do
|
194
|
+
puts PACKAGENAME
|
195
|
+
end
|
196
|
+
|
197
|
+
file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC] do
|
198
|
+
sh "gem build #{GEMSPEC}"
|
199
|
+
end
|
200
|
+
|
201
|
+
file GEMFILE_TRYOUT => DOC + EXT + EXTCONF + BIN + LIB + SPEC + TEST + EXAMPLE + RAKEFILE + [GEMSPEC_TRYOUT] do
|
202
|
+
#file GEMFILE_TRYOUT do
|
203
|
+
sh "gem build #{GEMSPEC_TRYOUT}"
|
204
|
+
end
|
205
|
+
|
206
|
+
file GEMSPEC => RAKEFILE do
|
207
|
+
File.write(GEMSPEC, GEMSTUB.to_ruby, mode: "wb")
|
208
|
+
end
|
209
|
+
|
210
|
+
file GEMSPEC_TRYOUT => RAKEFILE do
|
211
|
+
File.write(GEMSPEC_TRYOUT, GEMSTUB_TRYOUT.to_ruby, mode: "wb")
|
212
|
+
end
|
data/benchmark.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# Only this code to the PUBLIC DOMAIN.
|
3
|
+
#
|
4
|
+
|
5
|
+
require "benchmark"
|
6
|
+
#require "securerandom"
|
7
|
+
require "zlib"
|
8
|
+
require "crc"
|
9
|
+
begin; require "extlzma"; rescue LoadError; no_extlzma = true; end
|
10
|
+
begin; require "digest/crc"; rescue LoadError; no_digest_crc = true; end
|
11
|
+
|
12
|
+
def measure(generator_name)
|
13
|
+
print " * measuring for #{generator_name}..."
|
14
|
+
$stdout.flush
|
15
|
+
realms = 5.times.map do
|
16
|
+
real = (Benchmark.measure { yield }.real * 1000)
|
17
|
+
print " #{real.ceil} ms."
|
18
|
+
$stdout.flush
|
19
|
+
real
|
20
|
+
end.min
|
21
|
+
puts " (#{realms.ceil} ms.)\n"
|
22
|
+
[generator_name, realms]
|
23
|
+
end
|
24
|
+
|
25
|
+
size = 20
|
26
|
+
puts " ** preparing #{size} MiB data...\n"
|
27
|
+
#s = SecureRandom.random_bytes(size << 20)
|
28
|
+
s = "0" * (size << 20)
|
29
|
+
|
30
|
+
crc = measure("ruby-crc/crc32") { CRC.crc32(s) }[1]
|
31
|
+
comparisons = []
|
32
|
+
comparisons << measure("zlib/crc-32") { Zlib.crc32(s) }
|
33
|
+
comparisons << measure("extlzma/crc-32") { LZMA.crc32(s) } unless no_extlzma
|
34
|
+
comparisons << measure("digest/crc-32") { Digest::CRC32.digest(s) } unless no_digest_crc
|
35
|
+
comparisons << measure("ruby-crc/crc-64") { CRC.crc64(s) }
|
36
|
+
comparisons << measure("extlzma/crc-64") { LZMA.crc64(s) } unless no_extlzma
|
37
|
+
|
38
|
+
puts <<'EOS'
|
39
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
40
|
+
(slowly at over 1.0)
|
41
|
+
EOS
|
42
|
+
|
43
|
+
comparisons.each do |name, meas|
|
44
|
+
puts "%24s : ruby-crc/crc32 = %10.5f : 1.0\n" % [name, crc / meas]
|
45
|
+
end
|
data/gemstub.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
GEMSTUB = Gem::Specification.new do |s|
|
2
|
+
s.name = "crc"
|
3
|
+
s.version = "0.1"
|
4
|
+
s.summary = "general CRC generator"
|
5
|
+
s.description = <<EOS
|
6
|
+
This is a general CRC (Cyclic Redundancy Check) generator for ruby.
|
7
|
+
It is written by pure ruby with based on slice-by-eight algorithm (byte-order-free slice-by-16 algorithm).
|
8
|
+
Included built-in CRC modules are CRC-32, CRC-64-ECMA, CRC-64-ISO, CRC-16-CCITT, CRC-16-IBM, CRC-8, CRC-5-USB, CRC-5-EPC and more.
|
9
|
+
And your defined CRC modules to use.
|
10
|
+
If you need more speed, please use crc-turbo.
|
11
|
+
EOS
|
12
|
+
s.homepage = "https://osdn.jp/projects/rutsubo/"
|
13
|
+
s.license = "BSD-2-Clause"
|
14
|
+
s.author = "dearblue"
|
15
|
+
s.email = "dearblue@users.osdn.me"
|
16
|
+
|
17
|
+
s.required_ruby_version = ">= 2.0"
|
18
|
+
s.add_development_dependency "rake", "~> 11.0"
|
19
|
+
end
|
20
|
+
|
21
|
+
EXTRA << "benchmark.rb"
|
data/lib/crc.rb
ADDED
@@ -0,0 +1,405 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
if ENV["RUBY_CRC_NOFAST"].to_i > 0
|
4
|
+
require_relative "crc/_byruby"
|
5
|
+
else
|
6
|
+
begin
|
7
|
+
require File.join("crc", RUBY_VERSION[/\d+\.\d+/], "_turbo.so")
|
8
|
+
rescue LoadError
|
9
|
+
require_relative "crc/_byruby"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module CRC
|
14
|
+
CRC = self
|
15
|
+
|
16
|
+
extend Utils
|
17
|
+
|
18
|
+
module Utils
|
19
|
+
extend self
|
20
|
+
|
21
|
+
def bitreflect_reference(num, bitsize)
|
22
|
+
n = 0
|
23
|
+
bitsize.times { n <<= 1; n |= (num & 0x01); num >>= 1 }
|
24
|
+
n
|
25
|
+
end
|
26
|
+
|
27
|
+
def bitreflect(num, bitsize)
|
28
|
+
case
|
29
|
+
when bitsize > 64
|
30
|
+
bitreflect_reference(num, bitsize)
|
31
|
+
when bitsize > 32
|
32
|
+
bitreflect64(num) >> (64 - bitsize)
|
33
|
+
when bitsize > 16
|
34
|
+
bitreflect32(num) >> (32 - bitsize)
|
35
|
+
when bitsize > 8
|
36
|
+
bitreflect16(num) >> (16 - bitsize)
|
37
|
+
else
|
38
|
+
bitreflect8(num) >> ( 8 - bitsize)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if false
|
43
|
+
20.times do
|
44
|
+
n = rand(1 << 62)
|
45
|
+
bitsize = rand(64) + 1
|
46
|
+
a = bitreflect_reference(n, bitsize)
|
47
|
+
b = bitreflect(n, bitsize)
|
48
|
+
puts "0x%016X (%2d) => 0x%016X, 0x%016X (%s)" % [n, bitsize, a, b, (a == b)]
|
49
|
+
end
|
50
|
+
puts
|
51
|
+
require "benchmark"
|
52
|
+
Benchmark.bm(24) do |bm|
|
53
|
+
t = 1 << 16
|
54
|
+
4.times do
|
55
|
+
bm.report("reference(-1, 8)") { t.times { bitreflect_reference(-1, 8) } }
|
56
|
+
bm.report("reference(-1, 16)") { t.times { bitreflect_reference(-1, 16) } }
|
57
|
+
bm.report("reference(-1, 24)") { t.times { bitreflect_reference(-1, 24) } }
|
58
|
+
bm.report("reference(-1, 32)") { t.times { bitreflect_reference(-1, 32) } }
|
59
|
+
bm.report("reference(-1, 64)") { t.times { bitreflect_reference(-1, 64) } }
|
60
|
+
bm.report("bitreflect(-1, 8)") { t.times { bitreflect(-1, 8) } }
|
61
|
+
bm.report("bitreflect(-1, 16)") { t.times { bitreflect(-1, 16) } }
|
62
|
+
bm.report("bitreflect(-1, 24)") { t.times { bitreflect(-1, 24) } }
|
63
|
+
bm.report("bitreflect(-1, 32)") { t.times { bitreflect(-1, 32) } }
|
64
|
+
bm.report("bitreflect(-1, 64)") { t.times { bitreflect(-1, 64) } }
|
65
|
+
puts
|
66
|
+
end
|
67
|
+
end
|
68
|
+
abort "TEST ABORT"
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_table(bitsize, polynomial)
|
72
|
+
bitmask = ~(~0 << bitsize)
|
73
|
+
carrydown = bitmask >> 1
|
74
|
+
polynomial = bitmask & polynomial
|
75
|
+
table = []
|
76
|
+
head = 7
|
77
|
+
256.times do |i|
|
78
|
+
8.times { i = (i[head] == 0) ? (i << 1) : (((i & carrydown) << 1) ^ polynomial) }
|
79
|
+
table << i
|
80
|
+
end
|
81
|
+
|
82
|
+
table.freeze
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_table8(bitsize, polynomial, unfreeze = false)
|
86
|
+
bitmask = ~(~0 << bitsize)
|
87
|
+
table = []
|
88
|
+
Aux.slide_to_head(bitsize, 0, bitmask & polynomial, bitmask) do |xx, poly, csh, head, carries, pad|
|
89
|
+
8.times do |s|
|
90
|
+
table << (t = [])
|
91
|
+
256.times do |b|
|
92
|
+
r = (s == 0 ? (b << csh) : (table[-2][b]))
|
93
|
+
8.times { r = (r[head] == 0) ? (r << 1) : (((carries & r) << 1) ^ poly) }
|
94
|
+
t << r
|
95
|
+
end
|
96
|
+
t.freeze unless unfreeze
|
97
|
+
t
|
98
|
+
end
|
99
|
+
0
|
100
|
+
end
|
101
|
+
table.freeze unless unfreeze
|
102
|
+
table
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_table!(bitsize, polynomial)
|
106
|
+
polynomial = bitreflect(polynomial, bitsize)
|
107
|
+
table = []
|
108
|
+
256.times do |i|
|
109
|
+
8.times { i = (i[0] == 0) ? (i >> 1) : ((i >> 1) ^ polynomial) }
|
110
|
+
table << i
|
111
|
+
end
|
112
|
+
|
113
|
+
table.freeze
|
114
|
+
end
|
115
|
+
|
116
|
+
def build_table8!(bitsize, polynomial, unfreeze = false)
|
117
|
+
polynomial = bitreflect(polynomial, bitsize)
|
118
|
+
table = []
|
119
|
+
16.times do |s|
|
120
|
+
table << (t = [])
|
121
|
+
256.times do |b|
|
122
|
+
r = (s == 0) ? b : table[-2][b]
|
123
|
+
8.times { r = (r[0] == 0) ? (r >> 1) : ((r >> 1) ^ polynomial) }
|
124
|
+
t << r
|
125
|
+
end
|
126
|
+
t.freeze unless unfreeze
|
127
|
+
t
|
128
|
+
end
|
129
|
+
|
130
|
+
table.freeze unless unfreeze
|
131
|
+
table
|
132
|
+
end
|
133
|
+
|
134
|
+
def export_table(table, bitsize, linewidth, indentsize = 2)
|
135
|
+
bitsize0 = bitsize.to_i
|
136
|
+
indent = " " * indentsize.to_i
|
137
|
+
case
|
138
|
+
when bitsize0 > 64 || bitsize0 < 1
|
139
|
+
raise "invalid bitsize (expected to 1..64, but given #{bitsize})"
|
140
|
+
when bitsize0 > 32
|
141
|
+
packformat = "Q>"
|
142
|
+
hexwidth = 16
|
143
|
+
when bitsize0 > 16
|
144
|
+
packformat = "N"
|
145
|
+
hexwidth = 8
|
146
|
+
when bitsize0 > 8
|
147
|
+
packformat = "n"
|
148
|
+
hexwidth = 4
|
149
|
+
else # when bitsize0 > 0
|
150
|
+
packformat = "C"
|
151
|
+
hexwidth = 2
|
152
|
+
end
|
153
|
+
table = table.to_a.pack("#{packformat}*").unpack("H*")[0]
|
154
|
+
table.gsub!(/(?<=\w)(?=\w{#{hexwidth}}{#{linewidth}}+$)/, "\n")
|
155
|
+
table.gsub!(/(?<=\w)(?=\w{#{hexwidth}}+$)/, " ")
|
156
|
+
table.gsub!(/(?<=\w)(?=\s|$)/, ",")
|
157
|
+
table.gsub!(/(?:(?<=^)|(?<=\s))(?=\w)/, "0x")
|
158
|
+
table.gsub!(/^/, "#{indent} ")
|
159
|
+
<<-EOS
|
160
|
+
#{indent}TABLE = [
|
161
|
+
#{table}
|
162
|
+
#{indent}].freeze
|
163
|
+
EOS
|
164
|
+
end
|
165
|
+
|
166
|
+
#puts export_table(build_table(16, 0x1021), 16, 8); #abort "DEBUG EXIT"
|
167
|
+
#puts export_table(build_table!(32, 0xEDB88320), 32, 8); abort "DEBUG EXIT"
|
168
|
+
end
|
169
|
+
|
170
|
+
extend Utils
|
171
|
+
|
172
|
+
module Aux
|
173
|
+
def self.DIGEST(state, bitsize)
|
174
|
+
bits = (bitsize + 7) / 8 * 8
|
175
|
+
seq = "".b
|
176
|
+
(bits - 8).step(0, -8) { |i| seq << yield((state >> i) & 0xff) }
|
177
|
+
seq
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.digest(state, bitsize)
|
181
|
+
DIGEST(state, bitsize) { |n| [n].pack("C") }
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.hexdigest(state, bitsize)
|
185
|
+
DIGEST(state, bitsize) { |n| "%02X" % n }
|
186
|
+
end
|
187
|
+
|
188
|
+
#
|
189
|
+
# call-seq:
|
190
|
+
# slide_to_head(bitsize, state, polynomial, bitmask) { |padded_state, padded_polynomial, shift_input, off_msb, carries_mask, padding_size| padded_new_state } -> new_state
|
191
|
+
#
|
192
|
+
# YIELD(padded_state, padded_polynomial, shift_input, off_msb, carries_mask, padding_size) -> padded_new_state
|
193
|
+
#
|
194
|
+
def self.slide_to_head(bitsize, state, polynomial, bitmask)
|
195
|
+
pad = bitsize & 0x07
|
196
|
+
if pad == 0
|
197
|
+
yield(state, polynomial, bitsize - 8, bitsize - 1, bitmask >> 1, 0)
|
198
|
+
else
|
199
|
+
pad = 8 - pad
|
200
|
+
yield(state << pad, polynomial << pad, bitsize - 8 + pad, bitsize - 1 + pad, (bitmask << pad >> 1) | 0x7f, pad) >> pad
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class Generator
|
206
|
+
def crc(seq, state = nil)
|
207
|
+
finish(update(seq, setup(state)))
|
208
|
+
end
|
209
|
+
|
210
|
+
def setup(state = nil)
|
211
|
+
state ||= initial_state
|
212
|
+
state ^= xor_output
|
213
|
+
state = CRC.bitreflect(state, bitsize) if reflect_input ^ reflect_output
|
214
|
+
state
|
215
|
+
end
|
216
|
+
|
217
|
+
def finish(state)
|
218
|
+
state = CRC.bitreflect(state, bitsize) if reflect_input ^ reflect_output
|
219
|
+
state ^ xor_output
|
220
|
+
end
|
221
|
+
|
222
|
+
def digest(seq, state = nil)
|
223
|
+
Aux.digest(crc(seq, state), bitsize)
|
224
|
+
end
|
225
|
+
|
226
|
+
def hexdigest(seq, state = nil)
|
227
|
+
Aux.hexdigest(crc(seq, state), bitsize)
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_s
|
231
|
+
case
|
232
|
+
when bitsize > 64 then width = 20
|
233
|
+
when bitsize > 32 then width = 16
|
234
|
+
when bitsize > 16 then width = 8
|
235
|
+
when bitsize > 8 then width = 4
|
236
|
+
else width = 2
|
237
|
+
end
|
238
|
+
|
239
|
+
if reflect_input
|
240
|
+
ref = ", reflect-in#{reflect_output ? "/out" : ""}"
|
241
|
+
else
|
242
|
+
ref = reflect_output ? ", reflect-out" : ""
|
243
|
+
end
|
244
|
+
|
245
|
+
case initial_state
|
246
|
+
when 0 then init = "0"
|
247
|
+
when bitmask then init = "~0"
|
248
|
+
when 1 then init = "1"
|
249
|
+
else init = "0x%0#{width}X" % initial_state
|
250
|
+
end
|
251
|
+
|
252
|
+
case xor_output
|
253
|
+
when 0 then xor = "0"
|
254
|
+
when bitmask then xor = "~0"
|
255
|
+
when 1 then xor = "1"
|
256
|
+
else xor = "0x%0#{width}X" % xor_output
|
257
|
+
end
|
258
|
+
|
259
|
+
if nm = name
|
260
|
+
"#{nm}(CRC-%d-0x%0#{width}X init=%s%s, xor=%s)" % [bitsize, polynomial, init, ref, xor]
|
261
|
+
else
|
262
|
+
"(CRC-%d-0x%0#{width}X init=%s%s, xor=%s)" % [bitsize, polynomial, init, ref, xor]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def inspect
|
267
|
+
"\#<#{self.class} #{to_s}>"
|
268
|
+
end
|
269
|
+
|
270
|
+
def pretty_inspect(q)
|
271
|
+
q.text inspect
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class BasicCRC < Struct.new(:internal_state, :initial_state)
|
276
|
+
BasicStruct = superclass
|
277
|
+
|
278
|
+
class BasicStruct
|
279
|
+
alias state! internal_state
|
280
|
+
alias set_state! internal_state=
|
281
|
+
end
|
282
|
+
|
283
|
+
def initialize(initial_state = nil)
|
284
|
+
generator = self.class::GENERATOR
|
285
|
+
initial_state ||= generator.initial_state
|
286
|
+
super generator.setup(initial_state), initial_state
|
287
|
+
end
|
288
|
+
|
289
|
+
def reset(initial_state = self.initial_state)
|
290
|
+
generator = self.class::GENERATOR
|
291
|
+
initial_state ||= generator.initial_state
|
292
|
+
set_state! generator.setup(initial_state)
|
293
|
+
self.initial_state = initial_state
|
294
|
+
self
|
295
|
+
end
|
296
|
+
|
297
|
+
def update(seq)
|
298
|
+
set_state! self.class::GENERATOR.update!(seq, state!)
|
299
|
+
self
|
300
|
+
end
|
301
|
+
|
302
|
+
alias << update
|
303
|
+
|
304
|
+
def finish
|
305
|
+
self.class::GENERATOR.finish(state!)
|
306
|
+
end
|
307
|
+
|
308
|
+
alias state finish
|
309
|
+
|
310
|
+
def digest
|
311
|
+
Aux.DIGEST(state, self.class::GENERATOR.bitsize) { |n| [n].pack("C") }
|
312
|
+
end
|
313
|
+
|
314
|
+
# ビット反転せずに値を返す
|
315
|
+
def digest!
|
316
|
+
Aux.DIGEST(state!, self.class::GENERATOR.bitsize) { |n| [n].pack("C") }
|
317
|
+
end
|
318
|
+
|
319
|
+
def hexdigest
|
320
|
+
Aux.DIGEST(state, self.class::GENERATOR.bitsize) { |n| "%02X" % n }
|
321
|
+
end
|
322
|
+
|
323
|
+
# ビット反転せずに値を返す
|
324
|
+
def hexdigest!
|
325
|
+
Aux.DIGEST(state!, self.class::GENERATOR.bitsize) { |n| "%02X" % n }
|
326
|
+
end
|
327
|
+
|
328
|
+
alias to_str hexdigest
|
329
|
+
alias to_s hexdigest
|
330
|
+
|
331
|
+
def inspect
|
332
|
+
"\#<#{self.class}:#{hexdigest}>"
|
333
|
+
end
|
334
|
+
|
335
|
+
def pretty_inspect(q)
|
336
|
+
q.text inspect
|
337
|
+
end
|
338
|
+
|
339
|
+
class << self
|
340
|
+
def inspect
|
341
|
+
|
342
|
+
if const_defined?(:GENERATOR)
|
343
|
+
if nm = name
|
344
|
+
"#{nm}(#{self::GENERATOR.to_s})"
|
345
|
+
else
|
346
|
+
super.sub(/(?=\>$)/) { " #{self::GENERATOR.to_s}" }
|
347
|
+
end
|
348
|
+
else
|
349
|
+
super
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def pretty_inspect(q)
|
354
|
+
q.text inspect
|
355
|
+
end
|
356
|
+
|
357
|
+
def crc(seq, state = nil)
|
358
|
+
self::GENERATOR.crc(seq, state)
|
359
|
+
end
|
360
|
+
|
361
|
+
def digest(seq, state = nil)
|
362
|
+
Aux.digest(self::GENERATOR.crc(seq, state), self::GENERATOR.bitsize)
|
363
|
+
end
|
364
|
+
|
365
|
+
def hexdigest(seq, state = nil)
|
366
|
+
Aux.hexdigest(self::GENERATOR.crc(seq, state), self::GENERATOR.bitsize)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
MODULE_TABLE = {}
|
372
|
+
|
373
|
+
class << self
|
374
|
+
def lookup(modulename)
|
375
|
+
modulename1 = modulename.to_s.gsub(/[\W_]+/, "")
|
376
|
+
modulename1.downcase!
|
377
|
+
MODULE_TABLE[modulename1] or raise NameError, "modulename is not matched (for #{modulename})"
|
378
|
+
end
|
379
|
+
|
380
|
+
alias [] lookup
|
381
|
+
|
382
|
+
def crc(modulename, seq, state = nil)
|
383
|
+
lookup(modulename).crc(seq, state)
|
384
|
+
end
|
385
|
+
|
386
|
+
def digest(modulename, seq, state = nil)
|
387
|
+
lookup(modulename).digest(seq, state)
|
388
|
+
end
|
389
|
+
|
390
|
+
def hexdigest(modulename, seq, state = nil)
|
391
|
+
lookup(modulename).hexdigest(seq, state)
|
392
|
+
end
|
393
|
+
|
394
|
+
def create_module(bitsize, polynomial, initial_state = 0, refin = true, refout = true, xor = ~0, name = nil)
|
395
|
+
generator = Generator.new(bitsize, polynomial, initial_state, refin, refout, xor, name)
|
396
|
+
crc = Class.new(BasicCRC)
|
397
|
+
crc.const_set :GENERATOR, generator
|
398
|
+
crc
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
SELF_TEST = ($0 == __FILE__) ? true : false
|
403
|
+
end
|
404
|
+
|
405
|
+
require_relative "crc/_modules"
|
data/lib/crc/_byruby.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: dearblue <dearblue@users.osdn.me>
|
3
|
+
# License:: BSD-2-Clause
|
4
|
+
#++
|
5
|
+
|
6
|
+
#
|
7
|
+
# Ruby implemented CRC generator.
|
8
|
+
# It's Based on the Intel's slice-by-eight algorithm (but byte-order-free).
|
9
|
+
#
|
10
|
+
# It's faster than about 50% (CRC-32) and about 30% (CRC-64) of
|
11
|
+
# lookup-table algorithm. But need more memory.
|
12
|
+
#
|
13
|
+
# reference:
|
14
|
+
# * http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
|
15
|
+
# * xz-utils (src/liblzma/check/crc32_fast.c, src/liblzma/check/crc32_tablegen.c)
|
16
|
+
#
|
17
|
+
# If defined "RUBY_CRC_NOFAST=2" enviroment variable, switch to lookup-table algorithm.
|
18
|
+
#
|
19
|
+
# If defined "RUBY_CRC_NOFAST=3" enviroment variable, switch to reference algorithm.
|
20
|
+
#
|
21
|
+
module CRC
|
22
|
+
module Utils
|
23
|
+
def bitreflect8(n)
|
24
|
+
n = n.to_i
|
25
|
+
n = ((n & 0x55) << 1) | ((n >> 1) & 0x55)
|
26
|
+
n = ((n & 0x33) << 2) | ((n >> 2) & 0x33)
|
27
|
+
return ((n & 0x0f) << 4) | (n >> 4) # 0x0f
|
28
|
+
end
|
29
|
+
|
30
|
+
def bitreflect16(n)
|
31
|
+
n = n.to_i
|
32
|
+
n = ((n & 0x5555) << 1) | ((n >> 1) & 0x5555)
|
33
|
+
n = ((n & 0x3333) << 2) | ((n >> 2) & 0x3333)
|
34
|
+
n = ((n & 0x0f0f) << 4) | ((n >> 4) & 0x0f0f)
|
35
|
+
return ((n & 0x00ff) << 8) | (n >> 8) # 0x00ff
|
36
|
+
end
|
37
|
+
|
38
|
+
def bitreflect32(n)
|
39
|
+
n = n.to_i
|
40
|
+
n = ((n & 0x55555555) << 1) | ((n >> 1) & 0x55555555)
|
41
|
+
n = ((n & 0x33333333) << 2) | ((n >> 2) & 0x33333333)
|
42
|
+
n = ((n & 0x0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f)
|
43
|
+
n = ((n & 0x00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff)
|
44
|
+
return ((n & 0x0000ffff) << 16) | (n >> 16) # 0x0000ffff
|
45
|
+
end
|
46
|
+
|
47
|
+
def bitreflect64(n)
|
48
|
+
n = n.to_i
|
49
|
+
n = ((n & 0x5555555555555555) << 1) | ((n >> 1) & 0x5555555555555555)
|
50
|
+
n = ((n & 0x3333333333333333) << 2) | ((n >> 2) & 0x3333333333333333)
|
51
|
+
n = ((n & 0x0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f)
|
52
|
+
n = ((n & 0x00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff)
|
53
|
+
n = ((n & 0x0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff)
|
54
|
+
return ((n & 0x00000000ffffffff) << 32) | (n >> 32) # 0x00000000ffffffff
|
55
|
+
end
|
56
|
+
|
57
|
+
def bitreflect128(n)
|
58
|
+
n = n.to_i
|
59
|
+
n = ((n & 0x55555555555555555555555555555555) << 1) | ((n >> 1) & 0x55555555555555555555555555555555)
|
60
|
+
n = ((n & 0x33333333333333333333333333333333) << 2) | ((n >> 2) & 0x33333333333333333333333333333333)
|
61
|
+
n = ((n & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f)
|
62
|
+
n = ((n & 0x00ff00ff00ff00ff00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff00ff00ff00ff00ff)
|
63
|
+
n = ((n & 0x0000ffff0000ffff0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff0000ffff0000ffff)
|
64
|
+
n = ((n & 0x00000000ffffffff00000000ffffffff) << 32) | ((n >> 32) & 0x00000000ffffffff00000000ffffffff)
|
65
|
+
return ((n & 0x0000000000000000ffffffffffffffff) << 64) | (n >> 64) # 0x0000000000000000ffffffffffffffff
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Generator < Struct.new(:bitsize, :bitmask, :polynomial, :initial_state, :table8, :reflect_input, :reflect_output, :xor_output, :name)
|
70
|
+
BasicStruct = superclass
|
71
|
+
|
72
|
+
def initialize(bitsize, polynomial, initial_state = 0, reflect_input = true, reflect_output = true, xor_output = ~0, name = nil)
|
73
|
+
bitsize = bitsize.to_i
|
74
|
+
if bitsize < 1 || bitsize > 64
|
75
|
+
raise ArgumentError, "wrong bitsize (except 1..64, but given #{bitsize})"
|
76
|
+
end
|
77
|
+
bitmask = ~(~0 << bitsize)
|
78
|
+
polynomial = bitmask & polynomial
|
79
|
+
initial_state = bitmask & initial_state
|
80
|
+
xor_output = bitmask & xor_output
|
81
|
+
name = (name.nil? || ((name = String(name)).empty?)) ? nil : name
|
82
|
+
super(bitsize, bitmask, polynomial, initial_state, nil,
|
83
|
+
!!reflect_input, !!reflect_output, xor_output, name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_with_reference(seq, state)
|
87
|
+
if reflect_input
|
88
|
+
poly = CRC.bitreflect(polynomial, bitsize)
|
89
|
+
seq.each_byte do |ch|
|
90
|
+
state ^= ch
|
91
|
+
8.times { state = (state[0] == 0) ? (state >> 1) : ((state >> 1) ^ poly) }
|
92
|
+
|
93
|
+
# 8.times { state = (state >> 1) ^ (poly & -state[0]) }
|
94
|
+
# NOTE: ruby だと、分岐したほうが2割くらい高速
|
95
|
+
end
|
96
|
+
|
97
|
+
state
|
98
|
+
else
|
99
|
+
Aux.slide_to_head(bitsize, state, polynomial, bitmask) do |s, poly, csh, head, carries|
|
100
|
+
seq.each_byte do |ch|
|
101
|
+
s ^= ch << csh
|
102
|
+
8.times { s = (s[head] == 0) ? (s << 1) : (((carries & s) << 1) ^ poly) }
|
103
|
+
end
|
104
|
+
|
105
|
+
s
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def update_with_lookup_table(seq, state)
|
111
|
+
t = table8[0]
|
112
|
+
|
113
|
+
if reflect_input
|
114
|
+
String(seq).each_byte do |ch|
|
115
|
+
state = t[state & 0xff ^ ch] ^ (state >> 8)
|
116
|
+
end
|
117
|
+
state
|
118
|
+
else
|
119
|
+
Aux.slide_to_head(bitsize, state, polynomial, bitmask) do |s, poly, csh, head, carries|
|
120
|
+
carries8 = carries >> 7
|
121
|
+
String(seq).each_byte do |ch|
|
122
|
+
s = t[(s >> csh) ^ ch] ^ ((carries8 & s) << 8)
|
123
|
+
end
|
124
|
+
s
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def update_with_slice_by_eight(seq, s)
|
130
|
+
tX = table8
|
131
|
+
t0 = tX[ 0]; t1 = tX[ 1]; t2 = tX[ 2]; t3 = tX[ 3]
|
132
|
+
t4 = tX[ 4]; t5 = tX[ 5]; t6 = tX[ 6]; t7 = tX[ 7]
|
133
|
+
t8 = tX[ 8]; t9 = tX[ 9]; tA = tX[10]; tB = tX[11]
|
134
|
+
tC = tX[12]; tD = tX[13]; tE = tX[14]; tF = tX[15]
|
135
|
+
|
136
|
+
i = 0
|
137
|
+
ii = seq.bytesize
|
138
|
+
iii = ii & ~15
|
139
|
+
|
140
|
+
if reflect_input
|
141
|
+
if bitsize <= 32
|
142
|
+
# speed improvement for 32-bits CRC
|
143
|
+
while i < iii
|
144
|
+
s = tF[seq.getbyte(i ) ^ (s ) & 0xff] ^ tE[seq.getbyte(i + 1) ^ (s >> 8) & 0xff] ^
|
145
|
+
tD[seq.getbyte(i + 2) ^ (s >> 16) & 0xff] ^ tC[seq.getbyte(i + 3) ^ (s >> 24) & 0xff] ^
|
146
|
+
tB[seq.getbyte(i + 4) ] ^ tA[seq.getbyte(i + 5) ] ^
|
147
|
+
t9[seq.getbyte(i + 6) ] ^ t8[seq.getbyte(i + 7) ] ^
|
148
|
+
t7[seq.getbyte(i + 8) ] ^ t6[seq.getbyte(i + 9) ] ^
|
149
|
+
t5[seq.getbyte(i + 10) ] ^ t4[seq.getbyte(i + 11) ] ^
|
150
|
+
t3[seq.getbyte(i + 12) ] ^ t2[seq.getbyte(i + 13) ] ^
|
151
|
+
t1[seq.getbyte(i + 14) ] ^ t0[seq.getbyte(i + 15) ]
|
152
|
+
i += 16
|
153
|
+
end
|
154
|
+
else
|
155
|
+
while i < iii
|
156
|
+
s = tF[seq.getbyte(i ) ^ (s ) & 0xff] ^ tE[seq.getbyte(i + 1) ^ (s >> 8) & 0xff] ^
|
157
|
+
tD[seq.getbyte(i + 2) ^ (s >> 16) & 0xff] ^ tC[seq.getbyte(i + 3) ^ (s >> 24) & 0xff] ^
|
158
|
+
tB[seq.getbyte(i + 4) ^ (s >> 32) & 0xff] ^ tA[seq.getbyte(i + 5) ^ (s >> 40) & 0xff] ^
|
159
|
+
t9[seq.getbyte(i + 6) ^ (s >> 48) & 0xff] ^ t8[seq.getbyte(i + 7) ^ (s >> 56) & 0xff] ^
|
160
|
+
t7[seq.getbyte(i + 8) ] ^ t6[seq.getbyte(i + 9) ] ^
|
161
|
+
t5[seq.getbyte(i + 10) ] ^ t4[seq.getbyte(i + 11) ] ^
|
162
|
+
t3[seq.getbyte(i + 12) ] ^ t2[seq.getbyte(i + 13) ] ^
|
163
|
+
t1[seq.getbyte(i + 14) ] ^ t0[seq.getbyte(i + 15) ]
|
164
|
+
i += 16
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
(iii...ii).each do |n|
|
169
|
+
s = t0[seq.getbyte(n) ^ s & 0xff] ^ (s >> 8)
|
170
|
+
end
|
171
|
+
|
172
|
+
s
|
173
|
+
else
|
174
|
+
Aux.slide_to_head(bitsize, s, polynomial, bitmask) do |s, poly, csh, head, carries|
|
175
|
+
sh = 64 - (head + 1)
|
176
|
+
|
177
|
+
while i < iii
|
178
|
+
s <<= sh
|
179
|
+
s = t7[seq.getbyte(i ) ^ (s >> 56) & 0xff] ^ t6[seq.getbyte(i + 1) ^ (s >> 48) & 0xff] ^
|
180
|
+
t5[seq.getbyte(i + 2) ^ (s >> 40) & 0xff] ^ t4[seq.getbyte(i + 3) ^ (s >> 32) & 0xff] ^
|
181
|
+
t3[seq.getbyte(i + 4) ^ (s >> 24) & 0xff] ^ t2[seq.getbyte(i + 5) ^ (s >> 16) & 0xff] ^
|
182
|
+
t1[seq.getbyte(i + 6) ^ (s >> 8) & 0xff] ^ t0[seq.getbyte(i + 7) ^ (s >> 0) & 0xff]
|
183
|
+
i += 8
|
184
|
+
end
|
185
|
+
|
186
|
+
carries8 = carries >> 7
|
187
|
+
(iii...ii).each do |n|
|
188
|
+
s = t0[(s >> csh) ^ seq.getbyte(n)] ^ ((carries8 & s) << 8)
|
189
|
+
end
|
190
|
+
s
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def table8
|
196
|
+
unless t = super
|
197
|
+
if reflect_input
|
198
|
+
set_table8 t = CRC.build_table8!(bitsize, polynomial)
|
199
|
+
else
|
200
|
+
set_table8 t = CRC.build_table8(bitsize, polynomial)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
define_singleton_method :table8, self.class.superclass.instance_method(:table8)
|
205
|
+
|
206
|
+
t
|
207
|
+
end
|
208
|
+
|
209
|
+
case ENV["RUBY_CRC_NOFAST"].to_i
|
210
|
+
when 0, 1
|
211
|
+
alias update update_with_slice_by_eight
|
212
|
+
when 2
|
213
|
+
alias update update_with_lookup_table
|
214
|
+
else
|
215
|
+
alias update update_with_reference
|
216
|
+
end
|
217
|
+
|
218
|
+
class BasicStruct
|
219
|
+
alias set_table8 table8=
|
220
|
+
private :set_table8
|
221
|
+
|
222
|
+
undef :bitsize=, :bitmask=, :polynomial=, :initial_state=, :table8=,
|
223
|
+
:reflect_input=, :reflect_output=, :xor_output=, :name=, :[]=
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/crc/_modules.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
module CRC
|
4
|
+
|
5
|
+
#
|
6
|
+
# references from:
|
7
|
+
# * https://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
8
|
+
# * https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB
|
9
|
+
# * http://reveng.sourceforge.net/crc-catalogue/all.htm
|
10
|
+
# * http://crcmod.sourceforge.net/crcmod.predefined.html
|
11
|
+
# * https://users.ece.cmu.edu/~koopman/roses/dsn04/koopman04_crc_poly_embedded.pdf
|
12
|
+
#
|
13
|
+
|
14
|
+
list = [
|
15
|
+
#
|
16
|
+
# module name, polynomial, refrect input,
|
17
|
+
# bit size, reflect output,
|
18
|
+
# initial state, xor external, crc("123456789"), alias names...
|
19
|
+
#
|
20
|
+
[:CRC1, 0x01, 1, 0, true, true, ~0, nil, "CRC-1"],
|
21
|
+
[:CRC3_ROHC, 0x03, 3, ~0, true, true, 0, 0x06, "CRC-3-ROHC"],
|
22
|
+
[:CRC4_ITU, 0x03, 4, 0, true, true, 0, 0x07, "CRC-4-ITU"],
|
23
|
+
[:CRC5_EPC, 0x09, 5, 0x09, false, false, 0, 0x00, "CRC-5-EPC"],
|
24
|
+
[:CRC5_ITU, 0x15, 5, 0, true, true, 0, 0x07, "CRC-5-ITU"],
|
25
|
+
[:CRC5_USB, 0x05, 5, 0, true, true, ~0, 0x19, "CRC-5-USB"],
|
26
|
+
[:CRC6_CDMA2000_A, 0x27, 6, ~0, false, false, 0, 0x0D, "CRC-6-CDMA2000-A"],
|
27
|
+
[:CRC6_CDMA2000_B, 0x07, 6, ~0, false, false, 0, 0x3B, "CRC-6-CDMA2000-B"],
|
28
|
+
[:CRC6_DARC, 0x19, 6, 0, true, true, 0, 0x26, "CRC-6-DARC"],
|
29
|
+
[:CRC6_ITU, 0x03, 6, 0, true, true, 0, 0x06, "CRC-6-ITU"],
|
30
|
+
[:CRC7, 0x09, 7, 0, false, false, 0, 0x75, "CRC-7"],
|
31
|
+
[:CRC7_MVB, 0x65, 7, 0, true, true, ~0, nil, "CRC-7-MVB"],
|
32
|
+
[:CRC8, 0xD5, 8, 0, true, true, ~0, nil, "CRC-8"],
|
33
|
+
[:CRC8_CCITT, 0x07, 8, 0, true, true, ~0, nil, "CRC-8-CCITT"],
|
34
|
+
[:CRC8_DALLAS_MAXIM, 0x31, 8, 0, true, true, ~0, nil, "CRC-8-Dallas/Maxim"],
|
35
|
+
[:CRC8_DARC, 0x39, 8, 0, true, true, 0, 0x15, "CRC-8-DARC"],
|
36
|
+
[:CRC8_SAE, 0x1D, 8, 0, true, true, ~0, nil, "CRC-8-SAE"],
|
37
|
+
[:CRC8_WCDMA, 0x9B, 8, 0, true, true, 0, 0x25, "CRC-8-WCDMA"],
|
38
|
+
[:CRC10, 0x0233, 10, 0, false, false, 0, 0x0199, "CRC-10"],
|
39
|
+
[:CRC10_CDMA2000, 0x03D9, 10, ~0, false, false, 0, 0x0233, "CRC-10-CDMA2000"],
|
40
|
+
[:CRC11, 0x0385, 11, 0x1a, false, false, 0, 0x05a3, "CRC-11"],
|
41
|
+
[:CRC12, 0x080F, 12, 0, false, true, 0, 0x0daf, "CRC-12"],
|
42
|
+
[:CRC12_CDMA2000, 0x0F13, 12, ~0, false, false, 0, 0x0d4d, "CRC-12-CDMA2000"],
|
43
|
+
[:CRC13_BBC, 0x1CF5, 13, 0, false, false, 0, 0x04fa, "CRC-13-BBC"],
|
44
|
+
[:CRC14_DARC, 0x0805, 14, 0, true, true, 0, 0x082d, "CRC-14-DARC"],
|
45
|
+
[:CRC15_CAN, 0x4599, 15, 0, false, false, 0, 0x059e, "CRC-15-CAN"],
|
46
|
+
[:CRC15_MPT1327, 0x6815, 15, 1, false, false, 1, nil, "CRC-15-MPT1327"],
|
47
|
+
[:CHAKRAVARTY, 0x2F15, 16, 0, true, true, ~0, nil, "Chakravarty"],
|
48
|
+
[:CRC16_ARINC, 0xA02B, 16, 0, true, true, ~0, nil, "CRC-16-ARINC"],
|
49
|
+
[:CRC16_CCITT, 0x1021, 16, 0, true, true, ~0, nil, "CRC-16-CCITT", "CRC-CCITT"],
|
50
|
+
[:CRC16_CDMA2000, 0xC867, 16, 0, true, true, ~0, nil, "CRC-16-CDMA2000"],
|
51
|
+
[:CRC16_DECT, 0x0589, 16, 0, true, true, ~0, nil, "CRC-16-DECT"],
|
52
|
+
[:CRC16_T10_DIF, 0x8BB7, 16, 0, true, true, ~0, nil, "CRC-16-T10-DIF"],
|
53
|
+
[:CRC16_DNP, 0x3D65, 16, 0, true, true, ~0, nil, "CRC-16-DNP"],
|
54
|
+
[:CRC16_IBM, 0x8005, 16, 0, true, true, ~0, nil, "CRC-16-IBM", "CRC-16", "CRC-16-ANSI"],
|
55
|
+
[:CRC16_LZH, 0x8005, 16, 0, true, true, 0, 0xBB3D, "CRC-16-LZH", "CRC-LZH"],
|
56
|
+
[:CRC17_CAN, 0x0001685B, 17, 0, true, true, ~0, nil, "CRC-17-CAN"],
|
57
|
+
[:CRC21_CAN, 0x00102899, 21, 0, true, true, ~0, nil, "CRC-21-CAN"],
|
58
|
+
[:CRC24, 0x005D6DCB, 24, 0, true, true, ~0, nil, "CRC-24"],
|
59
|
+
[:CRC24_RADIX_64, 0x00864CFB, 24, 0, true, true, ~0, nil, "CRC-24-Radix-64"],
|
60
|
+
[:CRC30, 0x2030B9C7, 30, 0, true, true, ~0, nil, "CRC-30"],
|
61
|
+
[:CRC32, 0x04c11db7, 32, 0, true, true, ~0, 0xCBF43926, "CRC-32"],
|
62
|
+
[:CRC32C, 0x1edc6f41, 32, 0, true, true, ~0, 0xE3069283, "CRC-32C"],
|
63
|
+
[:CRC32K, 0x741B8CD7, 32, 0, true, true, ~0, nil, "CRC-32K"],
|
64
|
+
[:CRC32K2, 0x32583499, 32, 0, true, true, ~0, nil, "CRC-32K2"],
|
65
|
+
[:CRC32Q, 0x814141AB, 32, 0, false, false, 0, 0x3010BF7F, "CRC-32Q"],
|
66
|
+
[:CRC40_GSM, 0x0000000004820009, 40, ~0, false, false, ~0, 0xD4164FC646, "CRC-40-GSM"],
|
67
|
+
[:CRC64_ECMA, 0x42F0E1EBA9EA3693, 64, 0, true, true, ~0, 0x995DC9BBDF1939FA, "CRC-64-ECMA", "CRC-64"],
|
68
|
+
[:CRC64_ISO, 0x000000000000001B, 64, 0, true, true, ~0, nil, "CRC-64-ISO"],
|
69
|
+
]
|
70
|
+
|
71
|
+
$stderr.puts "#{__FILE__}:#{__LINE__}: SELF CHECK for CRC modules (#{File.basename($".grep(/\/crc\/_(?:byruby|turbo)/)[0]||"")})\n" if SELF_TEST
|
72
|
+
list.each do |name, polynomial, bitsize, initial_state, refin, refout, xor, check, *names|
|
73
|
+
names.map! { |nm| nm.freeze }
|
74
|
+
|
75
|
+
crc = create_module(bitsize, polynomial, initial_state, refin, refout, xor, names[0])
|
76
|
+
|
77
|
+
const_set(name, crc)
|
78
|
+
names.each { |nm| MODULE_TABLE[nm.downcase.gsub(/[\W_]+/, "")] = crc }
|
79
|
+
|
80
|
+
check = Integer(check.to_i) if check
|
81
|
+
crc.const_set :CHECK, check
|
82
|
+
|
83
|
+
generator = crc::GENERATOR
|
84
|
+
define_singleton_method(name.downcase, ->(*args) { generator.crc(*args) })
|
85
|
+
define_singleton_method("#{name.downcase}_digest", ->(*args) { generator.digest(*args) })
|
86
|
+
define_singleton_method("#{name.downcase}_hexdigest", ->(*args) { generator.hexdigest(*args) })
|
87
|
+
|
88
|
+
if SELF_TEST
|
89
|
+
checked = generator.crc("123456789")
|
90
|
+
case
|
91
|
+
when check.nil?
|
92
|
+
$stderr.puts "| %20s(\"123456789\") = %16X (check only)\n" % [names[0], checked]
|
93
|
+
when check != checked
|
94
|
+
$stderr.puts "| %20s(\"123456789\") = %16X (expect to %016X)\n" % [names[0], checked, check]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
exit if SELF_TEST
|
99
|
+
|
100
|
+
class << self
|
101
|
+
alias crc64 crc64_ecma
|
102
|
+
end
|
103
|
+
|
104
|
+
CRC64 = CRC64_ECMA
|
105
|
+
end
|
data/lib/crc/finder.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "../crc"
|
2
|
+
|
3
|
+
module CRC
|
4
|
+
def self.find(crc, seq, bitsize, polynomial, initstate = [0, ~0, 1], xor = [0, ~0, 1])
|
5
|
+
bitsize0 = bitsize.to_i
|
6
|
+
if bitsize0 < 1 || bitsize0 > 128
|
7
|
+
raise ArgumentError, "wrong bitsize (expect 1..128, but given #{bitsize})"
|
8
|
+
end
|
9
|
+
bitmask = ~(~0 << bitsize0)
|
10
|
+
crc &= bitmask
|
11
|
+
[polynomial, Utils.bitreflect(polynomial, bitsize0)].each do |poly|
|
12
|
+
poly &= bitmask
|
13
|
+
[false, true].each do |refin|
|
14
|
+
[false, true].each do |refout|
|
15
|
+
Array(xor).each do |xormask|
|
16
|
+
xormask &= bitmask
|
17
|
+
Array(initstate).each do |init|
|
18
|
+
init &= bitmask
|
19
|
+
mod = CRC.create_module(bitsize0, poly, init, refin, refout, xormask)
|
20
|
+
return mod if mod.crc(seq) == crc
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- dearblue
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '11.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '11.0'
|
27
|
+
description: |
|
28
|
+
This is a general CRC (Cyclic Redundancy Check) generator for ruby.
|
29
|
+
It is written by pure ruby with based on slice-by-eight algorithm (byte-order-free slice-by-16 algorithm).
|
30
|
+
Included built-in CRC modules are CRC-32, CRC-64-ECMA, CRC-64-ISO, CRC-16-CCITT, CRC-16-IBM, CRC-8, CRC-5-USB, CRC-5-EPC and more.
|
31
|
+
And your defined CRC modules to use.
|
32
|
+
If you need more speed, please use crc-turbo.
|
33
|
+
email: dearblue@users.osdn.me
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files:
|
37
|
+
- LICENSE
|
38
|
+
- README.md
|
39
|
+
- lib/crc.rb
|
40
|
+
- lib/crc/_byruby.rb
|
41
|
+
- lib/crc/_modules.rb
|
42
|
+
- lib/crc/finder.rb
|
43
|
+
files:
|
44
|
+
- LICENSE
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- benchmark.rb
|
48
|
+
- gemstub.rb
|
49
|
+
- lib/crc.rb
|
50
|
+
- lib/crc/_byruby.rb
|
51
|
+
- lib/crc/_modules.rb
|
52
|
+
- lib/crc/finder.rb
|
53
|
+
homepage: https://osdn.jp/projects/rutsubo/
|
54
|
+
licenses:
|
55
|
+
- BSD-2-Clause
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options:
|
59
|
+
- "--charset"
|
60
|
+
- UTF-8
|
61
|
+
- "-m"
|
62
|
+
- README.md
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.6.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: general CRC generator
|
81
|
+
test_files: []
|
82
|
+
has_rdoc:
|