multibases 0.2.0 → 0.3.0
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 +4 -4
- data/.gitignore +9 -9
- data/CHANGELOG.md +12 -2
- data/README.md +6 -0
- data/bin/setup +8 -8
- data/lib/multibases/bare.rb +3 -13
- data/lib/multibases/base16.rb +15 -10
- data/lib/multibases/base2.rb +15 -10
- data/lib/multibases/base32.rb +9 -6
- data/lib/multibases/base64.rb +17 -8
- data/lib/multibases/base_x.rb +6 -6
- data/lib/multibases/byte_array.rb +23 -8
- data/lib/multibases/error.rb +42 -0
- data/lib/multibases/ord_table.rb +49 -17
- data/lib/multibases/registry.rb +4 -4
- data/lib/multibases/version.rb +1 -1
- data/lib/table.csv +23 -23
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b13bedd48880500a221befb94a50e4846437428e1acd7c52639d31fbfc0f6eaa
|
|
4
|
+
data.tar.gz: ee4a4bc0057c318236f3dd9152582b1bc9f621acd42e88081ba910280146280f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 889019b38214fe663dced15fd1c01cf4d27cf06778b5f4f27480c0fd75630c8cfaa929b0c6a725d233e675ae1e07190282ba54e72c031e69201ee6d001dc9ff0
|
|
7
|
+
data.tar.gz: f52ad51235bd80e03ac6fc4c4d191d1c63c6875eb0e6c794aa956f221cc09bbb8ba8375a91b28e0a1bbbd29da83368ed4ccfae36dc9cf80d9e3afa3ced68ed80
|
data/.gitignore
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/.bundle/
|
|
2
|
-
/.yardoc
|
|
3
|
-
/_yardoc/
|
|
4
|
-
/coverage/
|
|
5
|
-
/doc/
|
|
6
|
-
/pkg/
|
|
7
|
-
/spec/reports/
|
|
8
|
-
/tmp/
|
|
9
|
-
Gemfile.lock
|
|
1
|
+
/.bundle/
|
|
2
|
+
/.yardoc
|
|
3
|
+
/_yardoc/
|
|
4
|
+
/coverage/
|
|
5
|
+
/doc/
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/tmp/
|
|
9
|
+
Gemfile.lock
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
- Fix convenience methods `names` and `codes`.
|
|
6
|
+
- Add `encoding` to `ByteArray` in order to not _guess_ the output encoding. The
|
|
7
|
+
encoding is determined in the encoding engine (when encoding) and has to be
|
|
8
|
+
supplied when decoding (because the encoding information is thrown away).
|
|
9
|
+
- Force `encoding` argument in `to_s` of `ByteArray`
|
|
10
|
+
- Extract errors to `error.rb`.
|
|
11
|
+
- Extract table strictness to its own method.
|
|
12
|
+
|
|
3
13
|
## 0.2.0
|
|
4
14
|
|
|
5
|
-
- Add convenience methods to registry, like `multicodecs
|
|
6
|
-
- Change tests to use fixture files and add `rake` task to update these
|
|
15
|
+
- Add convenience methods to registry, like `multicodecs`.
|
|
16
|
+
- Change tests to use fixture files and add `rake` task to update these.
|
|
7
17
|
|
|
8
18
|
## 0.1.0
|
|
9
19
|
|
data/README.md
CHANGED
|
@@ -19,6 +19,12 @@ This gem can be used _both_ for encoding into or decoding from multibase packed
|
|
|
19
19
|
strings, as well as serve as a _general purpose_ library to do `BaseX` encoding
|
|
20
20
|
and decoding _without_ adding the prefix.
|
|
21
21
|
|
|
22
|
+
> 🙌🏽 This is called `multibases` instead of the singular form, to stay
|
|
23
|
+
> consistent with the `multihashes` gem, which was _forced_ to take a different
|
|
24
|
+
> name has `multihash` was already taken, which is also the case for `multibase`
|
|
25
|
+
> and others. In the future, this might be renamed to `multiformats-base`, with
|
|
26
|
+
> a backwards-compatible interface.
|
|
27
|
+
|
|
22
28
|
## Installation
|
|
23
29
|
|
|
24
30
|
Add this line to your application's Gemfile:
|
data/bin/setup
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
IFS=$'\n\t'
|
|
4
|
-
set -vx
|
|
5
|
-
|
|
6
|
-
bundle install
|
|
7
|
-
|
|
8
|
-
# Do any other automated setup that you need to do here
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
IFS=$'\n\t'
|
|
4
|
+
set -vx
|
|
5
|
+
|
|
6
|
+
bundle install
|
|
7
|
+
|
|
8
|
+
# Do any other automated setup that you need to do here
|
data/lib/multibases/bare.rb
CHANGED
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'multibases/version'
|
|
4
|
+
require 'multibases/error'
|
|
4
5
|
require 'multibases/registry'
|
|
6
|
+
require 'multibases/byte_array'
|
|
5
7
|
|
|
6
8
|
module Multibases
|
|
7
|
-
class Error < StandardError; end
|
|
8
|
-
|
|
9
|
-
class NoEngine < Error
|
|
10
|
-
def initialize(encoding)
|
|
11
|
-
super(
|
|
12
|
-
"There is no engine registered to encode or decode #{encoding}.\n" \
|
|
13
|
-
'Either pass it as an argument, or use Multibases.implement to ' \
|
|
14
|
-
'register it globally.'
|
|
15
|
-
)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
9
|
Encoded = Struct.new(:code, :encoding, :length, :data) do
|
|
20
10
|
##
|
|
21
11
|
# Packs the data and the code into an encoded string
|
|
@@ -40,7 +30,7 @@ module Multibases
|
|
|
40
30
|
end
|
|
41
31
|
|
|
42
32
|
class Identity
|
|
43
|
-
def initialize(*_); end
|
|
33
|
+
def initialize(*_, encoding: nil); end
|
|
44
34
|
|
|
45
35
|
def encode(data)
|
|
46
36
|
EncodedByteArray.new(data.is_a?(Array) ? data : data.bytes)
|
data/lib/multibases/base16.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require 'multibases/byte_array'
|
|
4
|
+
require 'multibases/ord_table'
|
|
5
5
|
|
|
6
6
|
module Multibases
|
|
7
7
|
class Base16
|
|
@@ -14,14 +14,17 @@ module Multibases
|
|
|
14
14
|
|
|
15
15
|
# RFC 4648 implementation
|
|
16
16
|
def self.encode(plain)
|
|
17
|
-
plain = plain.
|
|
17
|
+
plain = plain.pack('C*') if plain.is_a?(Array)
|
|
18
18
|
|
|
19
19
|
# plain.each_byte.map do |byte| byte.to_s(16) end.join
|
|
20
|
-
EncodedByteArray.new(
|
|
20
|
+
EncodedByteArray.new(
|
|
21
|
+
plain.unpack1('H*').bytes,
|
|
22
|
+
encoding: Encoding::US_ASCII
|
|
23
|
+
)
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def self.decode(packed)
|
|
24
|
-
packed = packed.
|
|
27
|
+
packed = packed.pack('C*') if packed.is_a?(Array)
|
|
25
28
|
|
|
26
29
|
# packed.scan(/../).map { |x| x.hex.chr }.join
|
|
27
30
|
DecodedByteArray.new(Array(String(packed)).pack('H*').bytes)
|
|
@@ -48,8 +51,8 @@ module Multibases
|
|
|
48
51
|
end
|
|
49
52
|
end
|
|
50
53
|
|
|
51
|
-
def initialize(alphabet, strict: false)
|
|
52
|
-
@table = Table.from(alphabet, strict: strict)
|
|
54
|
+
def initialize(alphabet, strict: false, encoding: nil)
|
|
55
|
+
@table = Table.from(alphabet, strict: strict, encoding: encoding)
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def encode(plain)
|
|
@@ -58,7 +61,8 @@ module Multibases
|
|
|
58
61
|
|
|
59
62
|
encoded.transcode(
|
|
60
63
|
Default.table_ords(force_strict: @table.strict?),
|
|
61
|
-
table_ords
|
|
64
|
+
table_ords,
|
|
65
|
+
encoding: @table.encoding
|
|
62
66
|
)
|
|
63
67
|
end
|
|
64
68
|
|
|
@@ -66,7 +70,7 @@ module Multibases
|
|
|
66
70
|
return DecodedByteArray::EMPTY if encoded.empty?
|
|
67
71
|
|
|
68
72
|
unless encoded.is_a?(Array)
|
|
69
|
-
encoded = encoded.force_encoding(
|
|
73
|
+
encoded = encoded.force_encoding(@table.encoding).bytes
|
|
70
74
|
end
|
|
71
75
|
|
|
72
76
|
unless decodable?(encoded)
|
|
@@ -76,7 +80,8 @@ module Multibases
|
|
|
76
80
|
unless default?
|
|
77
81
|
encoded = ByteArray.new(encoded).transcode(
|
|
78
82
|
table_ords,
|
|
79
|
-
Default.table_ords(force_strict: @table.strict?)
|
|
83
|
+
Default.table_ords(force_strict: @table.strict?),
|
|
84
|
+
encoding: Encoding::US_ASCII
|
|
80
85
|
)
|
|
81
86
|
end
|
|
82
87
|
|
data/lib/multibases/base2.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require 'multibases/byte_array'
|
|
4
|
+
require 'multibases/ord_table'
|
|
5
5
|
|
|
6
6
|
module Multibases
|
|
7
7
|
class Base2
|
|
@@ -10,12 +10,15 @@ module Multibases
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def self.encode(plain)
|
|
13
|
-
plain = plain.
|
|
14
|
-
EncodedByteArray.new(
|
|
13
|
+
plain = plain.pack('C*') if plain.is_a?(Array)
|
|
14
|
+
EncodedByteArray.new(
|
|
15
|
+
plain.unpack1('B*').bytes,
|
|
16
|
+
encoding: Encoding::US_ASCII
|
|
17
|
+
)
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
def self.decode(packed)
|
|
18
|
-
packed = packed.
|
|
21
|
+
packed = packed.pack('C*') if packed.is_a?(Array)
|
|
19
22
|
# Pack only works on an array with a single bit string
|
|
20
23
|
DecodedByteArray.new(Array(String(packed)).pack('B*').bytes)
|
|
21
24
|
end
|
|
@@ -40,8 +43,8 @@ module Multibases
|
|
|
40
43
|
end
|
|
41
44
|
end
|
|
42
45
|
|
|
43
|
-
def initialize(alphabet, strict: false)
|
|
44
|
-
@table = Table.from(alphabet, strict: strict)
|
|
46
|
+
def initialize(alphabet, strict: false, encoding: nil)
|
|
47
|
+
@table = Table.from(alphabet, strict: strict, encoding: encoding)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
def encode(plain)
|
|
@@ -50,7 +53,8 @@ module Multibases
|
|
|
50
53
|
|
|
51
54
|
encoded.transcode(
|
|
52
55
|
Default.table_ords(force_strict: @table.strict?),
|
|
53
|
-
table_ords
|
|
56
|
+
table_ords,
|
|
57
|
+
encoding: @table.encoding
|
|
54
58
|
)
|
|
55
59
|
end
|
|
56
60
|
|
|
@@ -58,7 +62,7 @@ module Multibases
|
|
|
58
62
|
return DecodedByteArray::EMPTY if encoded.empty?
|
|
59
63
|
|
|
60
64
|
unless encoded.is_a?(Array)
|
|
61
|
-
encoded = encoded.force_encoding(
|
|
65
|
+
encoded = encoded.force_encoding(@table.encoding).bytes
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
unless decodable?(encoded)
|
|
@@ -68,7 +72,8 @@ module Multibases
|
|
|
68
72
|
unless default?
|
|
69
73
|
encoded = ByteArray.new(encoded).transcode(
|
|
70
74
|
table_ords,
|
|
71
|
-
Default.table_ords(force_strict: @table.strict?)
|
|
75
|
+
Default.table_ords(force_strict: @table.strict?),
|
|
76
|
+
encoding: Encoding::US_ASCII
|
|
72
77
|
)
|
|
73
78
|
end
|
|
74
79
|
|
data/lib/multibases/base32.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require 'multibases/byte_array'
|
|
4
|
+
require 'multibases/ord_table'
|
|
5
5
|
|
|
6
6
|
module Multibases
|
|
7
7
|
# RFC 3548
|
|
@@ -59,7 +59,7 @@ module Multibases
|
|
|
59
59
|
|
|
60
60
|
c = bytes.inject(0) do |m, o|
|
|
61
61
|
i = @table.index(o)
|
|
62
|
-
raise ArgumentError, "Invalid character '#{o.
|
|
62
|
+
raise ArgumentError, "Invalid character '#{[o].pack('C*')}'" if i.nil?
|
|
63
63
|
|
|
64
64
|
(m << 5) + i
|
|
65
65
|
end >> p
|
|
@@ -79,14 +79,17 @@ module Multibases
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
def initialize(alphabet, strict: false)
|
|
83
|
-
@table = Table.from(alphabet, strict: strict)
|
|
82
|
+
def initialize(alphabet, strict: false, encoding: nil)
|
|
83
|
+
@table = Table.from(alphabet, strict: strict, encoding: encoding)
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def encode(plain)
|
|
87
87
|
return EncodedByteArray::EMPTY if plain.empty?
|
|
88
88
|
|
|
89
|
-
EncodedByteArray.new(
|
|
89
|
+
EncodedByteArray.new(
|
|
90
|
+
chunks(plain, 5).collect(&:encode).flatten,
|
|
91
|
+
encoding: @table.encoding
|
|
92
|
+
)
|
|
90
93
|
end
|
|
91
94
|
|
|
92
95
|
def decode(encoded)
|
data/lib/multibases/base64.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
require 'multibases/byte_array'
|
|
5
|
+
require 'multibases/ord_table'
|
|
6
|
+
|
|
3
7
|
module Multibases
|
|
4
8
|
class Base64
|
|
5
9
|
def inspect
|
|
@@ -11,14 +15,17 @@ module Multibases
|
|
|
11
15
|
|
|
12
16
|
# RFC 4648 implementation
|
|
13
17
|
def self.encode(plain)
|
|
14
|
-
plain = plain.
|
|
18
|
+
plain = plain.pack('C*') if plain.is_a?(Array)
|
|
15
19
|
|
|
16
20
|
# Base64.strict_encode(plain)
|
|
17
|
-
EncodedByteArray.new(
|
|
21
|
+
EncodedByteArray.new(
|
|
22
|
+
Array(String(plain)).pack('m0').bytes,
|
|
23
|
+
encoding: Encoding::US_ASCII
|
|
24
|
+
)
|
|
18
25
|
end
|
|
19
26
|
|
|
20
27
|
def self.decode(packed)
|
|
21
|
-
packed = packed.
|
|
28
|
+
packed = packed.pack('C*') if packed.is_a?(Array)
|
|
22
29
|
# Base64.strict_decode64("m").first
|
|
23
30
|
# Don't use m0, as that requires padderding _always_
|
|
24
31
|
DecodedByteArray.new(packed.unpack1('m').bytes)
|
|
@@ -48,8 +55,8 @@ module Multibases
|
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
57
|
|
|
51
|
-
def initialize(alphabet, strict: false)
|
|
52
|
-
@table = Table.from(alphabet, strict: strict)
|
|
58
|
+
def initialize(alphabet, strict: false, encoding: nil)
|
|
59
|
+
@table = Table.from(alphabet, strict: strict, encoding: encoding)
|
|
53
60
|
end
|
|
54
61
|
|
|
55
62
|
def encode(plain)
|
|
@@ -61,7 +68,8 @@ module Multibases
|
|
|
61
68
|
|
|
62
69
|
encoded.transcode(
|
|
63
70
|
Default.table_ords(force_strict: @table.strict?),
|
|
64
|
-
table_ords
|
|
71
|
+
table_ords,
|
|
72
|
+
encoding: @table.encoding
|
|
65
73
|
)
|
|
66
74
|
end
|
|
67
75
|
|
|
@@ -69,7 +77,7 @@ module Multibases
|
|
|
69
77
|
return DecodedByteArray::EMPTY if encoded.empty?
|
|
70
78
|
|
|
71
79
|
unless encoded.is_a?(Array)
|
|
72
|
-
encoded = encoded.force_encoding(
|
|
80
|
+
encoded = encoded.force_encoding(@table.encoding).bytes
|
|
73
81
|
end
|
|
74
82
|
|
|
75
83
|
unless decodable?(encoded)
|
|
@@ -79,7 +87,8 @@ module Multibases
|
|
|
79
87
|
unless default?
|
|
80
88
|
encoded = ByteArray.new(encoded).transcode(
|
|
81
89
|
table_ords,
|
|
82
|
-
Default.table_ords(force_strict: @table.strict?)
|
|
90
|
+
Default.table_ords(force_strict: @table.strict?),
|
|
91
|
+
encoding: Encoding::US_ASCII
|
|
83
92
|
)
|
|
84
93
|
end
|
|
85
94
|
|
data/lib/multibases/base_x.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require 'multibases/byte_array'
|
|
4
|
+
require 'multibases/ord_table'
|
|
5
5
|
|
|
6
6
|
module Multibases
|
|
7
7
|
class BaseX
|
|
@@ -23,8 +23,8 @@ module Multibases
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def initialize(alphabet, strict: false)
|
|
27
|
-
@table = Table.from(alphabet, strict: strict)
|
|
26
|
+
def initialize(alphabet, strict: false, encoding: nil)
|
|
27
|
+
@table = Table.from(alphabet, strict: strict, encoding: encoding)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
##
|
|
@@ -71,7 +71,7 @@ module Multibases
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
EncodedByteArray.new(output)
|
|
74
|
+
EncodedByteArray.new(output, encoding: @table.encoding)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
##
|
|
@@ -84,7 +84,7 @@ module Multibases
|
|
|
84
84
|
return DecodedByteArray::EMPTY if encoded.empty?
|
|
85
85
|
|
|
86
86
|
unless encoded.is_a?(Array)
|
|
87
|
-
encoded = encoded.force_encoding(
|
|
87
|
+
encoded = encoded.force_encoding(@table.encoding).bytes
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
unless decodable?(encoded)
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'multibases/error'
|
|
4
|
+
|
|
3
5
|
module Multibases
|
|
6
|
+
|
|
4
7
|
class ByteArray < DelegateClass(Array)
|
|
8
|
+
def initialize(array, encoding: nil)
|
|
9
|
+
super array
|
|
10
|
+
|
|
11
|
+
@encoding = encoding
|
|
12
|
+
end
|
|
13
|
+
|
|
5
14
|
def hash
|
|
6
15
|
__getobj__.hash
|
|
7
16
|
end
|
|
@@ -18,11 +27,11 @@ module Multibases
|
|
|
18
27
|
super || __getobj__.is_a?(klazz)
|
|
19
28
|
end
|
|
20
29
|
|
|
21
|
-
def transcode(from, to)
|
|
30
|
+
def transcode(from, to, encoding: nil)
|
|
22
31
|
from = from.each_with_index.to_h
|
|
23
32
|
to = Hash[to.each_with_index.to_a.collect(&:reverse)]
|
|
24
33
|
|
|
25
|
-
self.class.new(map { |byte| to[from[byte]] })
|
|
34
|
+
self.class.new(map { |byte| to[from[byte]] }, encoding: encoding)
|
|
26
35
|
end
|
|
27
36
|
|
|
28
37
|
alias to_a to_arr
|
|
@@ -31,11 +40,14 @@ module Multibases
|
|
|
31
40
|
|
|
32
41
|
class EncodedByteArray < ByteArray
|
|
33
42
|
def inspect
|
|
34
|
-
|
|
43
|
+
encoding = @encoding || Encoding::BINARY
|
|
44
|
+
"[Multibases::EncodedByteArray \"#{to_str(encoding)}\"]"
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
def to_str
|
|
38
|
-
|
|
47
|
+
def to_str(encoding = @encoding)
|
|
48
|
+
raise MissingEncoding unless encoding
|
|
49
|
+
|
|
50
|
+
pack('C*').force_encoding(encoding)
|
|
39
51
|
end
|
|
40
52
|
|
|
41
53
|
def chomp!(ord)
|
|
@@ -54,11 +66,14 @@ module Multibases
|
|
|
54
66
|
|
|
55
67
|
class DecodedByteArray < ByteArray
|
|
56
68
|
def inspect
|
|
57
|
-
|
|
69
|
+
encoding = @encoding || Encoding::BINARY
|
|
70
|
+
"[Multibases::DecodedByteArray \"#{to_str(encoding)}\"]"
|
|
58
71
|
end
|
|
59
72
|
|
|
60
|
-
def to_str(encoding =
|
|
61
|
-
|
|
73
|
+
def to_str(encoding = @encoding)
|
|
74
|
+
raise MissingEncoding unless encoding
|
|
75
|
+
|
|
76
|
+
pack('C*').force_encoding(encoding)
|
|
62
77
|
end
|
|
63
78
|
|
|
64
79
|
def force_encoding(*args)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Multibases
|
|
2
|
+
class Error < StandardError; end
|
|
3
|
+
|
|
4
|
+
class NoEngine < Error
|
|
5
|
+
def initialize(encoding)
|
|
6
|
+
super(
|
|
7
|
+
"There is no engine registered to encode or decode #{encoding}.\n" \
|
|
8
|
+
'Either pass it as an argument, or use Multibases.implement to ' \
|
|
9
|
+
'register it globally.'
|
|
10
|
+
)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class AlphabetOutOfRange < Error
|
|
15
|
+
def initialize(ord)
|
|
16
|
+
super(
|
|
17
|
+
'The multibase spec currently only allows for alphabet characters in ' \
|
|
18
|
+
"the 0-255 range. '#{ord}' is outside that range."
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class AlphabetEncodingInvalid < Error
|
|
24
|
+
def initialize(encoding)
|
|
25
|
+
super(
|
|
26
|
+
"The encoding '#{encoding}' is invalid for the given alphabet. " \
|
|
27
|
+
'Supply an encoding that is valid for each character in the alphabet.'
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class MissingEncoding < Error
|
|
33
|
+
def initialize
|
|
34
|
+
super 'Can not convert from ByteArray to string without encoding. Pass ' \
|
|
35
|
+
'the resulting string encoding as the first argument of to_s.' \
|
|
36
|
+
"\n" \
|
|
37
|
+
'This does not default to UTF-8 or US-ASCII because that would ' \
|
|
38
|
+
'hide issues until you have output that is NOT encoding as UTF-8 ' \
|
|
39
|
+
'or US-ASCII and does not fit in those ranges.'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/multibases/ord_table.rb
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'multibases/error'
|
|
4
|
+
|
|
3
5
|
module Multibases
|
|
4
6
|
class OrdTable
|
|
5
|
-
def initialize(ords, strict:, padder: nil)
|
|
7
|
+
def initialize(ords, strict:, padder: nil, encoding: nil)
|
|
6
8
|
ords = ords.uniq
|
|
7
9
|
|
|
8
10
|
@ords = ords
|
|
9
11
|
@base = ords.length
|
|
10
12
|
@padder = padder
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
chars_upcased = chars.map(&:upcase).uniq
|
|
15
|
-
chars_cased = chars_upcased - chars_downcased
|
|
16
|
-
|
|
17
|
-
# Strict means that the algorithm may _not_ treat incorrectly cased
|
|
18
|
-
# input the same as correctly cased input. In other words, the table is
|
|
19
|
-
# strict if a character exists that is both upcased and downcased and
|
|
20
|
-
# therefore has a canonical casing.
|
|
21
|
-
@strict = strict ||
|
|
22
|
-
chars_cased.empty? ||
|
|
23
|
-
chars.length != chars_downcased.length
|
|
24
|
-
|
|
25
|
-
@loose_ords = (chars + chars_downcased + chars_upcased).uniq.map(&:ord)
|
|
14
|
+
calculate_strictness(strict: strict)
|
|
15
|
+
calculate_encoding(encoding: encoding)
|
|
26
16
|
end
|
|
27
17
|
|
|
28
18
|
def eql?(other)
|
|
@@ -48,10 +38,52 @@ module Multibases
|
|
|
48
38
|
end
|
|
49
39
|
|
|
50
40
|
def alphabet
|
|
51
|
-
@ords.
|
|
41
|
+
@ords.pack('C*')
|
|
52
42
|
end
|
|
53
43
|
|
|
54
|
-
attr_reader :base, :factor, :padder
|
|
44
|
+
attr_reader :base, :factor, :padder, :encoding
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def calculate_strictness(strict:)
|
|
49
|
+
chars = alphabet.chars
|
|
50
|
+
chars_downcased = chars.map(&:downcase).uniq
|
|
51
|
+
chars_upcased = chars.map(&:upcase).uniq
|
|
52
|
+
chars_cased = chars_upcased - chars_downcased
|
|
53
|
+
|
|
54
|
+
# Strict means that the algorithm may _not_ treat incorrectly cased
|
|
55
|
+
# input the same as correctly cased input. In other words, the table is
|
|
56
|
+
# strict if a character exists that is both upcased and downcased and
|
|
57
|
+
# therefore has a canonical casing.
|
|
58
|
+
@strict = strict ||
|
|
59
|
+
chars_cased.empty? ||
|
|
60
|
+
chars.length != chars_downcased.length
|
|
61
|
+
|
|
62
|
+
@loose_ords = (chars + chars_downcased + chars_upcased).uniq.map(&:ord)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def calculate_encoding(encoding:)
|
|
66
|
+
invalid_ord = @ords.find { |ord| ord > 255 }
|
|
67
|
+
raise AlphabetOutOfBoundary, invalid_ord if invalid_ord
|
|
68
|
+
|
|
69
|
+
if encoding
|
|
70
|
+
raise AlphabetEncodingInvalid, encoding unless valid_encoding?(encoding)
|
|
71
|
+
|
|
72
|
+
@encoding = encoding
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
@encoding = fits_seven_bits? ? Encoding::US_ASCII : Encoding::ASCII_8BIT
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def valid_encoding?(encoding)
|
|
80
|
+
ords = strict? ? @ords : @loose_ords
|
|
81
|
+
ords.pack('C*').force_encoding(encoding).valid_encoding?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def fits_seven_bits?
|
|
85
|
+
valid_encoding?(Encoding::US_ASCII)
|
|
86
|
+
end
|
|
55
87
|
end
|
|
56
88
|
|
|
57
89
|
class IndexedOrdTable < OrdTable
|
data/lib/multibases/registry.rb
CHANGED
|
@@ -27,11 +27,11 @@ module Multibases
|
|
|
27
27
|
find_by(code: entry, encoding: entry)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def implement(encoding, code, implementation = nil, alphabet = nil)
|
|
30
|
+
def implement(encoding, code, implementation = nil, alphabet = nil, alphabet_encoding = nil)
|
|
31
31
|
Multibases::IMPLEMENTATIONS[encoding] = Registration.new(
|
|
32
32
|
code,
|
|
33
33
|
encoding,
|
|
34
|
-
implementation&.new(alphabet)
|
|
34
|
+
implementation&.new(alphabet, encoding: alphabet_encoding)
|
|
35
35
|
)
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -50,11 +50,11 @@ module Multibases
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def codes
|
|
53
|
-
|
|
53
|
+
Multibases::IMPLEMENTATIONS.values.map(&:code)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def names
|
|
57
|
-
|
|
57
|
+
Multibases::IMPLEMENTATIONS.keys
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def multibase_version(multibase_semver = nil)
|
data/lib/multibases/version.rb
CHANGED
data/lib/table.csv
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
encoding, code, description
|
|
2
|
-
identity, 0x00, 8-bit binary (encoder and decoder keeps data unmodified)
|
|
3
|
-
base1, 1, unary (11111)
|
|
4
|
-
base2, 0, binary (01010101)
|
|
5
|
-
base8, 7, octal
|
|
6
|
-
base10, 9, decimal
|
|
7
|
-
base16, f, hexadecimal
|
|
8
|
-
base16upper, F, hexadecimal
|
|
9
|
-
base32hex, v, rfc4648 no padding - highest char
|
|
10
|
-
base32hexupper, V, rfc4648 no padding - highest char
|
|
11
|
-
base32hexpad, t, rfc4648 with padding
|
|
12
|
-
base32hexpadupper, T, rfc4648 with padding
|
|
13
|
-
base32, b, rfc4648 no padding
|
|
14
|
-
base32upper, B, rfc4648 no padding
|
|
15
|
-
base32pad, c, rfc4648 with padding
|
|
16
|
-
base32padupper, C, rfc4648 with padding
|
|
17
|
-
base32z, h, z-base-32 (used by Tahoe-LAFS)
|
|
18
|
-
base58flickr, Z, base58 flicker
|
|
19
|
-
base58btc, z, base58 bitcoin
|
|
20
|
-
base64, m, rfc4648 no padding
|
|
21
|
-
base64pad, M, rfc4648 with padding - MIME encoding
|
|
22
|
-
base64url, u, rfc4648 no padding
|
|
23
|
-
base64urlpad, U, rfc4648 with padding
|
|
1
|
+
encoding, code, description
|
|
2
|
+
identity, 0x00, 8-bit binary (encoder and decoder keeps data unmodified)
|
|
3
|
+
base1, 1, unary (11111)
|
|
4
|
+
base2, 0, binary (01010101)
|
|
5
|
+
base8, 7, octal
|
|
6
|
+
base10, 9, decimal
|
|
7
|
+
base16, f, hexadecimal
|
|
8
|
+
base16upper, F, hexadecimal
|
|
9
|
+
base32hex, v, rfc4648 no padding - highest char
|
|
10
|
+
base32hexupper, V, rfc4648 no padding - highest char
|
|
11
|
+
base32hexpad, t, rfc4648 with padding
|
|
12
|
+
base32hexpadupper, T, rfc4648 with padding
|
|
13
|
+
base32, b, rfc4648 no padding
|
|
14
|
+
base32upper, B, rfc4648 no padding
|
|
15
|
+
base32pad, c, rfc4648 with padding
|
|
16
|
+
base32padupper, C, rfc4648 with padding
|
|
17
|
+
base32z, h, z-base-32 (used by Tahoe-LAFS)
|
|
18
|
+
base58flickr, Z, base58 flicker
|
|
19
|
+
base58btc, z, base58 bitcoin
|
|
20
|
+
base64, m, rfc4648 no padding
|
|
21
|
+
base64pad, M, rfc4648 with padding - MIME encoding
|
|
22
|
+
base64url, u, rfc4648 no padding
|
|
23
|
+
base64urlpad, U, rfc4648 with padding
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multibases
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Derk-Jan Karrenbeld
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-06-
|
|
11
|
+
date: 2019-06-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -81,6 +81,7 @@ files:
|
|
|
81
81
|
- lib/multibases/base64.rb
|
|
82
82
|
- lib/multibases/base_x.rb
|
|
83
83
|
- lib/multibases/byte_array.rb
|
|
84
|
+
- lib/multibases/error.rb
|
|
84
85
|
- lib/multibases/ord_table.rb
|
|
85
86
|
- lib/multibases/registry.rb
|
|
86
87
|
- lib/multibases/version.rb
|
|
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
107
108
|
- !ruby/object:Gem::Version
|
|
108
109
|
version: '0'
|
|
109
110
|
requirements: []
|
|
110
|
-
rubygems_version: 3.0.
|
|
111
|
+
rubygems_version: 3.0.2
|
|
111
112
|
signing_key:
|
|
112
113
|
specification_version: 4
|
|
113
114
|
summary: Ruby implementation of the multibase specification
|