Class: Base32::Crockford
- Inherits:
-
Object
- Object
- Base32::Crockford
- Defined in:
- lib/base32/crockford.rb
Overview
encode a value with the encoding defined by Douglas Crockford in <www.crockford.com/wrmg/base32.html>
this is not the same as the Base32 encoding defined in RFC 4648
The Base32 symbol set is a superset of the Base16 symbol set.
We chose a symbol set of 10 digits and 22 letters. We exclude 4 of the 26 letters: I L O U.
Excluded Letters
- I
-
Can be confused with 1
- L
-
Can be confused with 1
- O
-
Can be confused with 0
- U
-
Accidental obscenity
When decoding, upper and lower case letters are accepted, and i and l will be treated as 1 and o will be treated as 0. When encoding, only upper case letters are used.
If the bit-length of the number to be encoded is not a multiple of 5 bits, then zero-extend the number to make its bit-length a multiple of 5.
Hyphens (-) can be inserted into symbol strings. This can partition a string into manageable pieces, improving readability by helping to prevent confusion. Hyphens are ignored during decoding. An application may look for hyphens to assure symbol string correctness.
Constant Summary collapse
- VERSION =
"0.2.3"
- ENCODE_CHARS =
%w(0 1 2 3 4 5 6 7 8 9 A B C D E F G H J K M N P Q R S T V W X Y Z ?)
- DECODE_MAP =
ENCODE_CHARS.to_enum(:each_with_index).inject({}) do |h,(c,i)| h[c] = i; h end.merge({'I' => 1, 'L' => 1, 'O' => 0})
- CHECKSUM_CHARS =
%w(* ~ $ = U)
- CHECKSUM_MAP =
{ "*" => 32, "~" => 33, "$" => 34, "=" => 35, "U" => 36 }
Class Method Summary collapse
- .clean(string) ⇒ Object
-
.decode(string, opts = {}) ⇒ Object
decode a string to an integer using Douglas Crockfords Base32 Encoding.
-
.decode!(string, opts = {}) ⇒ Object
same as decode, but raises ArgumentError when the string can’t be decoded.
-
.encode(number, opts = {}) ⇒ Object
encodes an integer into a string.
-
.normalize(string, opts = {}) ⇒ Object
return the canonical encoding of a string.
-
.valid?(string, opts = {}) ⇒ Boolean
returns false if the string contains invalid characters and can’t be decoded.
Class Method Details
.clean(string) ⇒ Object
154 155 156 |
# File 'lib/base32/crockford.rb', line 154 def clean(string) string.gsub(/-/,'').upcase end |
.decode(string, opts = {}) ⇒ Object
decode a string to an integer using Douglas Crockfords Base32 Encoding
the string is converted to uppercase and hyphens are stripped before decoding
I,i,l,L decodes to 1
O,o decodes to 0
Base32::Crockford.decode("16J") # => 1234
Base32::Crockford.decode("OI") # => 1
Base32::Crockford.decode("3G923-0VQVS") # => 123456789012345
returns nil
if the string contains invalid characters and can’t be decoded, or if checksum option is used and checksum is incorrect
108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/base32/crockford.rb', line 108 def self.decode(string, opts = {}) if opts[:checksum] checksum_char = string.slice!(-1) checksum_number = DECODE_MAP.merge(CHECKSUM_MAP)[checksum_char] end number = clean(string).split(//).map { |char| DECODE_MAP[char] or return nil }.inject(0) { |result,val| (result << 5) + val } number % 37 == checksum_number or return nil if opts[:checksum] number end |
.decode!(string, opts = {}) ⇒ Object
same as decode, but raises ArgumentError when the string can’t be decoded
125 126 127 |
# File 'lib/base32/crockford.rb', line 125 def self.decode!(string, opts = {}) decode(string) or raise ArgumentError end |
.encode(number, opts = {}) ⇒ Object
encodes an integer into a string
when checksum
is given, a checksum is added at the end of the the string, calculated as modulo 37 of number
. Five additional checksum symbols are used for symbol values 32-36
when split
is given a hyphen is inserted every <n> characters to improve readability
when length
is given, the resulting string is zero-padded to be exactly this number of characters long (hyphens are ignored)
Base32::Crockford.encode(1234) # => "16J"
Base32::Crockford.encode(123456789012345, :split=>5) # => "3G923-0VQVS"
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/base32/crockford.rb', line 72 def self.encode(number, opts = {}) # verify options raise ArgumentError unless (opts.keys - [:length, :split, :checksum] == []) str = number.to_s(2).reverse.scan(/.{1,5}/).map do |bits| ENCODE_CHARS[bits.reverse.to_i(2)] end.reverse.join str = str + (ENCODE_CHARS + CHECKSUM_CHARS)[number % 37] if opts[:checksum] str = str.rjust(opts[:length], '0') if opts[:length] if opts[:split] str = str.reverse str = str.scan(/.{1,#{opts[:split]}}/).map { |x| x.reverse } str = str.reverse.join("-") end str end |
.normalize(string, opts = {}) ⇒ Object
return the canonical encoding of a string. converts it to uppercase and removes hyphens
replaces invalid characters with a question mark (‘?’)
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/base32/crockford.rb', line 134 def self.normalize(string, opts = {}) checksum_char = string.slice!(-1) if opts[:checksum] string = clean(string).split(//).map { |char| ENCODE_CHARS[DECODE_MAP[char] || 32] }.join string = string + checksum_char if opts[:checksum] string end |
.valid?(string, opts = {}) ⇒ Boolean
returns false if the string contains invalid characters and can’t be decoded
149 150 151 |
# File 'lib/base32/crockford.rb', line 149 def self.valid?(string, opts = {}) !(normalize(string, opts) =~ /\?/) end |