Skip to content

Instantly share code, notes, and snippets.

@adacosta
Created October 2, 2009 16:12
Show Gist options
  • Save adacosta/199854 to your computer and use it in GitHub Desktop.
Save adacosta/199854 to your computer and use it in GitHub Desktop.
require 'base64'
require 'test/unit'
module B64
CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split ''
# === Encode Non-MIME
# convert string to binary
# copy groups of 8 bits to 6 bits
# add b64 padding - 0 fill (to 6) the right side of the last bit grouping
# add byte padding (1.8 + 1.9 compat)
def self.encode64(string="")
encoded, buffer = '', string.unpack('B*')[0]
buffer.scan(/.{6}/).each { |nib| encoded << CHARS[nib.to_i(2)] }
encoded << CHARS[((buffer[-(buffer.size % 6)..-1] << "00000")[/^(.{6})(.+)/,1]).to_i(2)]
(string.send((string.respond_to?(:bytesize) ? :bytesize : :size)) % 4).times { encoded << '=' }
encoded
end
# === Decode MIME and non-MIME
# iterate string as character array
# left pad each 6 bit representation with 0s
# lop off trailing 0s (from encoded fill)
# covert decoded bits to new character set
def self.decode64(string="")
decoded = ""
string.unpack('C*').each do |char_num|
b64_index = CHARS.index(char_num.chr)
decoded << "%06d" % b64_index.to_s(2) if b64_index
end
(decoded.size % 8).times { decoded.chop! }
decoded.gsub!(/(.{8})/) { |b| b.to_i(2).chr }
end
end
class TC_B64 < Test::Unit::TestCase
LOGIN_STRING = "username:password"
STRING = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
PARAGRAPH = %Q[
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce dolor massa, tincidunt eu pulvinar id, congue vel lacus.
Ut at nisi volutpat elit consequat facilisis.
Nam imperdiet fringilla urna, ut ultricies tellus hendrerit sed.
Sed eleifend velit ut enim ultrices tincidunt.
Cras non eros augue, non posuere nibh. Vivamus sit amet nisl magna, eu blandit ante.
Curabitur nec magna eget nibh porttitor congue vel sed felis.
Phasellus vitae consectetur purus. Curabitur luctus tortor ac nisl lobortis imperdiet.
Integer eu pharetra mi. Aenean luctus nibh et est iaculis vehicula.
Nunc dictum accumsan urna, vitae auctor nisl consequat ut. Donec at tortor dolor,
varius placerat libero. Donec consequat pulvinar urna, non posuere libero tempor at.
]
def test_encode_and_decode
assert_equal LOGIN_STRING, B64.decode64(B64.encode64(LOGIN_STRING))
assert_equal STRING, B64.decode64(B64.encode64(STRING))
assert_equal PARAGRAPH, B64.decode64(B64.encode64(PARAGRAPH))
end
def test_encode_is_non_mime
# \n is a notable MIME marker
assert (B64.encode64(PARAGRAPH)[/\n/].nil?)
# Base64 encodes mime...verify our output doesn't match
assert_not_equal Base64.encode64(PARAGRAPH), B64.encode64(PARAGRAPH)
end
# NOTE: Depending on byte alignment, codings can be equal.
# One example is the included STRING test, where PARAGRAPH wouldn't
# show the same result.
# assert_equal PARAGRAPH, Base64.decode64(B64.encode64(PARAGRAPH)) #=> true
def test_base64_std_lib_fails_decoding_non_mime
# Base64 can't decode non-MIME encoded base64
assert_not_equal STRING, Base64.decode64(B64.encode64(STRING))
end
def test_can_decode_base64_std_lib
# decode works on MIME encoded base64
assert_equal LOGIN_STRING, B64.decode64(Base64.encode64(LOGIN_STRING))
assert_equal STRING, B64.decode64(Base64.encode64(STRING))
assert_equal PARAGRAPH, B64.decode64(Base64.encode64(PARAGRAPH))
end
# require "benchmark"
# def test_zbenchies
# n = 5000
# encoded_login_string = B64.encode64(LOGIN_STRING)
# puts ""
# Benchmark.bm do |x|
# x.report("Base64.encode64") { n.times do; Base64.encode64(LOGIN_STRING); end }
# x.report("B64.encode64") { n.times do ; B64.encode64(LOGIN_STRING); end }
# x.report("Base64.decode64") { n.times do; Base64.decode64(encoded_login_string); end }
# x.report("B64.decode64") { n.times do ; B64.decode64(encoded_login_string); end }
# end
# end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment