Skip to content

Instantly share code, notes, and snippets.

@josephg
Created June 2, 2014 17:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephg/d8e9c258eeac4cb4bb22 to your computer and use it in GitHub Desktop.
Save josephg/d8e9c258eeac4cb4bb22 to your computer and use it in GitHub Desktop.
assert = require 'assert'
_a = 'a'.charCodeAt(0)
_f = 'f'.charCodeAt(0)
_A = 'A'.charCodeAt(0)
_F = 'F'.charCodeAt(0)
hexForChar = (c, pos = 0) ->
ascii = c.charCodeAt pos
switch
when _a <= ascii <= _f then 10 + ascii - _a
when _A <= ascii <= _F then 10 + ascii - _A
else +c[pos]
exports.fromHex = fromHex = (str) ->
# Array buffers would be faster, but they aren't dynamically sized.
# Eh.
bytes = []
for i in [0...str.length] by 2
high = hexForChar str, i
low = hexForChar str, i + 1
bytes.push (high << 4) + low
break unless low? # ignore trailing single characters
bytes
exports.toHex = toHex = (bytes) ->
str = '' # Actually not so bad these days on v8.
for b in bytes
vals = b.toString(16)
str += if vals.length is 1 then "0#{vals}" else vals
str
base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
'abcdefghijklmnopqrstuvwxyz' + '0123456789+/'
base64Map = {}
base64Map[c] = i for c, i in base64Chars
base64Map['='] = '=' # special
# There's an implementation of base64 encoding & decoding built
# into the standard library, but it felt like the point of this
# question was to write my own. Eh. Did it. Felt good.
exports.fromBase64 = fromBase64 = (str) ->
bytes = []
overflow = 0
# Remove all newlines before processing.
pos = 0
getNextChar = ->
pos++ while pos < str.length and base64Map[str[pos]] is undefined
str[pos++]
while pos < str.length
group = (base64Map[getNextChar()] for [0...4])
bytes.push group[0]<<2 | group[1]>>4
# Just care about one byte.
break if group[2] is '='
bytes.push (group[1] & 0xf)<<4 | group[2]>>2
break if group[3] is '='
bytes.push (group[2] & 0x3)<<6 | group[3]
bytes
exports.toBase64 = toBase64 = (bytes) ->
str = ''
for i in [0...bytes.length] by 3
str += base64Chars[bytes[i] >> 2]
# This still works correctly if we overflow the array.
# Good ol' javascript.
str += base64Chars[(bytes[i] & 3)<<4 | (bytes[i+1]>>4)]
if i + 1 >= bytes.length
str += '=='
break
str += base64Chars[(bytes[i+1] & 0xf)<<2 | bytes[i+2]>>6]
if i + 2 >= bytes.length
str += '='
break
str += base64Chars[bytes[i+2] & 0x3f]
str
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment