class Multibases::BaseX
Public Class Methods
new(alphabet, strict: false, encoding: nil)
click to toggle source
# File lib/multibases/base_x.rb, line 26 def initialize(alphabet, strict: false, encoding: nil) @table = Table.from(alphabet, strict: strict, encoding: encoding) end
Public Instance Methods
decodable?(encoded)
click to toggle source
# File lib/multibases/base_x.rb, line 125 def decodable?(encoded) (encoded.uniq - @table.tr_ords).length.zero? end
decode(encoded)
click to toggle source
Decode encoded
to a byte array
@param encoded [String, Array, ByteArray] encoded string or byte array @return [DecodedByteArray] decoded byte array
# File lib/multibases/base_x.rb, line 83 def decode(encoded) return DecodedByteArray::EMPTY if encoded.empty? unless encoded.is_a?(Array) encoded = encoded.force_encoding(@table.encoding).bytes end unless decodable?(encoded) raise ArgumentError, "'#{encoded}' contains unknown characters'" end # Find leading zeroes zeroes_count = [ 0, encoded.find_index { |b| b.ord != @table.zero } || encoded.length ].max encoded = encoded.drop(zeroes_count) # Decode number from encoding base to base 10 encoded_big_number = 0 encoded.reverse.each_with_index do |char, i| table_i = @table.index(char) encoded_big_number += @table.base**i * table_i end # Build the output by reversing the bytes. Because the encoding is "lost" # the result might not be correct just yet. This is up to the caller to # fix. The algorithm **can not know** what the encoding was. output = 1.upto((Math.log2(encoded_big_number) / 8).ceil).collect do encoded_big_number, character_byte = encoded_big_number.divmod 256 character_byte end.reverse # Prepend the leading zeroes @table.decoded_zeroes_length(zeroes_count).times do output.unshift(0x00) end DecodedByteArray.new(output) end
encode(plain)
click to toggle source
Encode plain
to an encoded string
@param plain [String, Array] plain string or byte array @return [EncodedByteArray] encoded byte array
# File lib/multibases/base_x.rb, line 36 def encode(plain) return EncodedByteArray::EMPTY if plain.empty? plain = plain.bytes unless plain.is_a?(Array) expected_length = @table.encoded_length(plain) # Find leading zeroes zeroes_count = [ 0, plain.find_index { |b| b.ord != 0 } || plain.length ].max plain = plain.drop(zeroes_count) expected_length = @table.encoded_length(plain) unless @table.pad_to_power? # Encode number into destination base as byte array output = [] plain_big_number = plain.inject { |a, b| (a << 8) + b.ord } while plain_big_number >= @table.base mod = plain_big_number % @table.base output.unshift(@table.ord_at(mod)) plain_big_number = (plain_big_number - mod) / @table.base end output.unshift(@table.ord_at(plain_big_number)) # Prepend the leading zeroes @table.encoded_zeroes_length(zeroes_count).times do output.unshift(@table.zero) end # Padding at the front (to match expected length). Because of the if @table.pad_to_power? (expected_length - output.length).times do output.unshift(@table.zero) end end EncodedByteArray.new(output, encoding: @table.encoding) end
inspect()
click to toggle source
# File lib/multibases/base_x.rb, line 8 def inspect "[Multibases::Base#{@table.base} " \ "alphabet=\"#{@table.alphabet}\"" \ "#{@table.strict? ? ' strict' : ''}" \ ']' end