crc 0.1
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 +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:
|