Skip to content

Instantly share code, notes, and snippets.

@Nephos
Created January 18, 2018 08:24
Show Gist options
  • Save Nephos/73f53123c2a1f1ace91d5d846f4d15e1 to your computer and use it in GitHub Desktop.
Save Nephos/73f53123c2a1f1ace91d5d846f4d15e1 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
module Base64
extend self
ALPHA = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + %w(- /)
def encode(input, verbose = false)
bytes = text_to_bytes(input)
slice3 = bytes_to_slice3(bytes)
bytes6 = slice3_to_bytes6(slice3)
alpha = bytes6_to_alpha(bytes6)
if verbose
puts "== encode"
pp bytes
pp slice3
pp bytes6
pp alpha
end
out = alpha.join('')
pad_size = bytes.size % 3
if pad_size > 0
pad = "==="
out[-pad_size-1..-1] = pad[0..pad_size]
end
out
end
def decode(input, verbose = false)
pad_size = input.count('=')
input.delete '='
bytes6 = alpha_to_bytes6(input)
slice3 = bytes6_to_slice3(bytes6)
bytes = slice3_to_bytes(slice3)
out = bytes_to_text(bytes)
if verbose
puts "== decode"
pp bytes6
pp slice3
pp bytes
end
out[0..-1-pad_size]
end
# encode
# "xxxx" => [x, x, x, x]
def text_to_bytes(input)
input.each_byte.to_a
end
# decode
# [x, x, x, x] => "xxxx"
def bytes_to_text(input)
input.map { |v| v.chr }.join('')
end
# encode
# [x, x, x, x] => [x + x + x, x]
def bytes_to_slice3(input)
input.each_slice(3).map { |v| (v[0] << 16) + (v[1].to_i << 8) + (v[2].to_i << 0) }
end
# decode
# [x + x + x, x] => [x, x, x, x]
def slice3_to_bytes(input)
input.map { |v| [(v >> 16) & 0xff, (v >> 8) & 0xff, (v >> 0) & 0xff] }.flatten
end
# encode
# [x + x + x, x] => [y, y, y, y, x]
def slice3_to_bytes6(input)
input.map { |v| [ (v & (2**24-1)) >> 18, (v & (2**18-1)) >> 12, (v & (2**12-1)) >> 6, (v & (2**6-1)) >> 0 ] }.flatten
end
# decode
# [y, y, y, y, x] => [x + x + x, x]
def bytes6_to_slice3(input)
input.each_slice(4).map { |v| (v[0].to_i << 18) + (v[1].to_i << 12) + (v[2].to_i << 6) + (v[3].to_i << 0) }
end
# encode
# [y, y, y, y, x] => ["y", "y", "y", "y", "x"]
def bytes6_to_alpha(input)
input.map { |v| ALPHA[v] }
end
# decode
# ["yyyyx"] => [y, y, y, y, x]
def alpha_to_bytes6(input)
input.each_char.map { |v| ALPHA.index(v) }
end
end
if $0 == __FILE__
data = ARGV[1] || STDIN.gets.to_s.chomp
if ARGV[0] == "-d"
puts Base64.decode(data)
elsif ARGV[0] == "-e"
puts Base64.encode(data)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment