Skip to content

Instantly share code, notes, and snippets.

@shuhei
Created August 3, 2013 06:44
Show Gist options
  • Save shuhei/6145486 to your computer and use it in GitHub Desktop.
Save shuhei/6145486 to your computer and use it in GitHub Desktop.
Base64 encoding
module B64
extend self
ENCODING_TABLE = [
('A'..'Z').to_a,
('a'..'z').to_a,
('0'..'9').to_a,
['+', '/']
].flatten
DECODING_TABLE = ENCODING_TABLE
.each_with_index
.reduce({}) do |table, char_with_index|
char, index = char_with_index
table[char] = index
table
end
def encode(str)
str
.each_byte
.map { |byte| byte_to_bits(byte) }
.flatten
.each_slice(6)
.map { |bits| bits + [0] * (6 - bits.size) } # Fill with 0.
.map { |bits| bits_to_num(bits) }
.map { |num| ENCODING_TABLE[num] }
.each_slice(4)
.map { |chars| chars + ['='] * (4 - chars.size) } # Fill with '='.
.flatten
.join
end
def decode(encoded)
encoded
.sub(/=+\Z/, '')
.split('')
.map { |char| DECODING_TABLE[char] }
.map { |num| num_to_bits(num, 6) }
.flatten
.each_slice(8)
.select { |bits| bits.size == 8 } # Remove trailing zeros.
.map { |bits| bits_to_num(bits) }
.map { |byte| byte.chr }
.join
end
def byte_to_bits(byte)
num_to_bits(byte, 8)
end
def num_to_bits(num, bit_size)
(0...bit_size).to_a.reverse.map do |i|
(num >> i) & 1
end
end
def bits_to_num(bits)
size = bits.size
(0...size).map.reduce(0) do |sum, i|
sum + (bits[i] << (size - 1 - i))
end
end
end
require_relative 'b64'
require 'minitest/unit'
require 'minitest/autorun'
class TestB64 < MiniTest::Unit::TestCase
def test_encode
assert_equal 'QUJDREVGRw==', B64.encode('ABCDEFG')
assert_equal 'SGVsbG8sIFdvcmxkIQ==', B64.encode('Hello, World!')
end
def test_decode
assert_equal 'ABCDEFG', B64.decode('QUJDREVGRw==')
assert_equal 'Hello, World!', B64.decode('SGVsbG8sIFdvcmxkIQ==')
end
def test_byte_to_bits
assert_equal [0, 1, 0, 0, 0, 0, 0, 1], B64.byte_to_bits(65)
end
def test_bits_to_num
assert_equal 11, B64.bits_to_num([0, 0, 1, 0, 1, 1])
end
def test_encoding_table
assert_equal 64, B64::ENCODING_TABLE.size
assert_equal 'o', B64::ENCODING_TABLE[40]
assert_equal '+', B64::ENCODING_TABLE[62]
end
def test_decoding_table
assert_equal 64, B64::DECODING_TABLE.size
assert_equal 40, B64::DECODING_TABLE['o']
assert_equal 62, B64::DECODING_TABLE['+']
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment