Created
September 22, 2016 21:42
-
-
Save robey/fc79f39e13771124d4efd31d709fd0ac to your computer and use it in GitHub Desktop.
fast browser-friendly base32 codec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// base32 implementation for fun. | |
const alphabet = "0123456789abcdefghjkmnpqrtuvwxyz"; | |
if (alphabet.length != 32) throw new Error("Base 32 requires a 32-character alphabet"); | |
// chars that look similar (dwim): | |
const alias = { o: 0, i: 1, l: 1, s: 5 }; | |
const reverseLookup = buildReverseTable(); | |
function buildReverseTable() { | |
const table = new Uint8Array(128); | |
for (let i = 0; i < 128; i++) table[i] = 0; | |
for (let i = 0; i < alphabet.length; i++) table[alphabet.charCodeAt(i)] = i; | |
Object.keys(alias).forEach(k => { | |
table[k.charCodeAt(0)] = alias[k]; | |
}); | |
// capitals should alias to lowercase: | |
for (let i = 0x40; i < 0x60; i++) table[i] = table[i + 0x20]; | |
return table; | |
} | |
function encode(buffer: Uint8Array): string { | |
// can't use Uint8Array here, because there's no way to map it into a string. :( | |
const outBuffer: number[] = new Array(Math.ceil(1.6 * buffer.length)); | |
let acc = 0, bits = 0, j = 0; | |
for (let i = 0; i < buffer.length; i++) { | |
acc = (acc << 8) | buffer[i]; | |
bits += 8; | |
while (bits >= 5) { | |
outBuffer[j++] = (acc >> (bits - 5)) & 0x1f; | |
acc = (acc & 0xfff); | |
bits -= 5; | |
} | |
} | |
if (bits > 0) outBuffer[j++] = (acc << (5 - bits)) & 0x1f; | |
return outBuffer.map(c => alphabet[c]).join(""); | |
} | |
function decode(buffer: string): Uint8Array { | |
const outBuffer = new Uint8Array(Math.ceil(buffer.length * 0.625)); | |
let acc = 0, bits = 0, j = 0; | |
for (let i = 0; i < buffer.length; i++) { | |
acc = (acc << 5) | reverseLookup[buffer.charCodeAt(i) & 0x7f]; | |
bits += 5; | |
while (bits >= 8) { | |
outBuffer[j++] = (acc >> (bits - 8)) & 0xff; | |
acc = (acc & 0xffff); | |
bits -= 8; | |
} | |
} | |
if (bits > 0) outBuffer[j++] = (acc << (8 - bits)) & 0xff; | |
return outBuffer; | |
} | |
// quick demo/test, you can erase this part. | |
const data = new Uint8Array([ | |
0x17, 0x05, 0x76, 0x84, 0xbe, 0xa1, 0xf9, 0x33, 0x14, 0x18, | |
0xb6, 0x33, 0xa8, 0xf3, 0x73, 0x11, 0x9d, 0x76, 0x5f, 0xd4 | |
]); | |
const encoded = "2w2qd15ym7wk650rprtuhwvk26eqcqym"; | |
console.log(data, encode(data)); | |
console.log(encoded, decode(encoded)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment