Skip to content

Instantly share code, notes, and snippets.

@fliptopbox
Last active July 17, 2019 13:55
Show Gist options
  • Save fliptopbox/dfbb7ce14730ba1533d48329e4d7740a to your computer and use it in GitHub Desktop.
Save fliptopbox/dfbb7ce14730ba1533d48329e4d7740a to your computer and use it in GitHub Desktop.
Base64 library - lets you encode UTF-16 or UTF-8 (with UMD decorator)
(function(root, factory, NS = "Base64") { if (typeof define === "function" && define.amd) { define([], factory); } else if (typeof exports === "object") { module.exports = factory(); } else { root[NS] = factory(); } })(this, function()
{
/*
Base64 library
Lets you encode with UTF-16 or UTF-8
https://gist.github.com/fliptopbox/dfbb7ce14730ba1533d48329e4d7740a
To see console output remove the # --> *#/
const teststring = `Ħ€ǁǿ ɰṏ®ʆď - http://say:[email protected]/?kilroy=was+here&now=gone#!extinct\n\rfin!`;
const utf16 = new Base64(16);
const utf8 = new Base64(8);
const A = utf16.encode(teststring);
const B = utf8.encode(teststring);
const Adec = utf16.decode(A);
const Bdec = utf8.decode(B);
const Alen = A.length;
const Blen = B.length;
const ratio = Alen / Blen;
const AlessThanB = Alen < Blen;
const percent = (AlessThanB ? ratio : (1 / ratio)) * 100 >> 0 / 100;
console.clear();
console.log("%cResults: Winner is %s (by %s%)", "font-size:2em;", AlessThanB ? "UTF-16" : "UTF-8", percent);
console.log("Decoded UTF-16 and UTF-8 strings are equal (%s)", Adec === Bdec);
console.log(`Length: UTF-16(%s) UTF-8(%s) A<B(%s) Ratio(%s%)`, Alen, Blen, AlessThanB, percent);
/**/
return Base64;
function Base64(bit = 8) {
//
// Base64 / binary data / UTF-8 strings utilities (#3)
// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
// Which method are we using 16bit or 8bit (default) ?
const utf8 = !(bit === 16);
function btoaUTF16(sString) {
const aUTF16CodeUnits = new Uint16Array(sString.length);
aUTF16CodeUnits.forEach((el, idx, arr) => {
arr[idx] = sString.charCodeAt(idx);
});
return btoa(String.fromCharCode(...new Uint8Array(aUTF16CodeUnits.buffer)));
}
function atobUTF16(sBase64) {
const sBinaryString = atob(sBase64);
const aBinaryView = new Uint8Array(sBinaryString.length);
aBinaryView.forEach((_, idx, arr) => {
arr[idx] = sBinaryString.charCodeAt(idx);
});
return String.fromCharCode(...new Uint16Array(aBinaryView.buffer));
}
//
// Traditional approach using URLencode and character escaping
const escaping = new RegExp("%([0-9A-F]{2})", "g"); // eg: "&" > %26 > 0x26
const toSolidBytes = (_, p1) => String.fromCharCode(`0x${p1}`);
function btoaUTF8(sString) {
return btoa(encodeURIComponent(sString).replace(escaping, toSolidBytes));
}
function atobUTF8(sBase64) {
return decodeURIComponent(
atob(sBase64)
.split("")
.map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
.join("")
);
}
this.encode = utf8 ? btoaUTF8 : btoaUTF16;
this.decode = utf8 ? atobUTF8 : atobUTF16;
this.escaping = escaping;
this.toSolidBytes = toSolidBytes;
this.bit = utf8 ? 8 : 16;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment