From 95d644507b503e9801a1c866944ef094d5f3cda4 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Wed, 11 Jan 2023 18:47:36 -0600 Subject: [PATCH] perf(btoa): improve btoa() speed This utilizes more performant methods to generate the string. Co-authored-by: Dumitru Uzun --- base64.js | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/base64.js b/base64.js index e558553..d517861 100644 --- a/base64.js +++ b/base64.js @@ -28,26 +28,32 @@ InvalidCharacterError.prototype.name = 'InvalidCharacterError'; // encoder - // [https://gist.github.com/999166] by [https://github.com/nignag] function btoa(input) { - var str = String (input); - for ( - // initialize result and counter - var block, charCode, idx = 0, map = chars, output = ''; - // if the next str index does not exist: - // change the mapping table to "=" - // check if d has no fractional digits - str.charAt (idx | 0) || (map = '=', idx % 1); - // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 - output += map.charAt (63 & block >> 8 - idx % 1 * 8) - ) { - charCode = str.charCodeAt (idx += 3 / 4); - if (charCode > 0xFF) { + var data = String (input), o1, o2, o3, bits, i = 0, acc = ''; + + while (i < data.length) { + // pack three octets into four hextets + o1 = data.charCodeAt (i++); + o2 = data.charCodeAt (i++); + o3 = data.charCodeAt (i++); + + if (o1 > 128 || o2 > 128 || o3 > 128) { throw new InvalidCharacterError ("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); } - block = block << 8 | charCode; + + bits = (o1 << 16) | (o2 << 8) | o3; + // use hextets to index into b64, and append result to encoded string + acc += chars.charAt ((bits >> 18) & 0x3F) + + chars.charAt ((bits >> 12) & 0x3F) + + chars.charAt ((bits >> 6) & 0x3F) + + chars.charAt ((bits) & 0x3F); + } + + switch (data.length % 3) { + case 0: return acc; + case 1: return acc.slice (0, -2) + '=='; + case 2: return acc.slice (0, -1) + '='; } - return output; } // decoder