You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
"use strict";
/** * Implementation of atob() according to the HTML and Infra specs, except that * instead of throwing INVALID_CHARACTER_ERR we return null. */ function atob(data) { // Web IDL requires DOMStrings to just be converted using ECMAScript
// ToString, which in our case amounts to using a template literal.
data = `${data}`; // "Remove all ASCII whitespace from data."
data = data.replace(/[ \t\n\f\r]/g, ""); // "If data's length divides by 4 leaving no remainder, then: if data ends
// with one or two U+003D (=) code points, then remove them from data."
if (data.length % 4 === 0) { data = data.replace(/==?$/, ""); } // "If data's length divides by 4 leaving a remainder of 1, then return
// failure."
//
// "If data contains a code point that is not one of
//
// U+002B (+)
// U+002F (/)
// ASCII alphanumeric
//
// then return failure."
if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) { return null; } // "Let output be an empty byte sequence."
let output = ""; // "Let buffer be an empty buffer that can have bits appended to it."
//
// We append bits via left-shift and or. accumulatedBits is used to track
// when we've gotten to 24 bits.
let buffer = 0; let accumulatedBits = 0; // "Let position be a position variable for data, initially pointing at the
// start of data."
//
// "While position does not point past the end of data:"
for (let i = 0; i < data.length; i++) { // "Find the code point pointed to by position in the second column of
// Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in
// the first cell of the same row.
//
// "Append to buffer the six bits corresponding to n, most significant bit
// first."
//
// atobLookup() implements the table from RFC 4648.
buffer <<= 6; buffer |= atobLookup(data[i]); accumulatedBits += 6; // "If buffer has accumulated 24 bits, interpret them as three 8-bit
// big-endian numbers. Append three bytes with values equal to those
// numbers to output, in the same order, and then empty buffer."
if (accumulatedBits === 24) { output += String.fromCharCode((buffer & 0xff0000) >> 16); output += String.fromCharCode((buffer & 0xff00) >> 8); output += String.fromCharCode(buffer & 0xff); buffer = accumulatedBits = 0; } // "Advance position by 1."
} // "If buffer is not empty, it contains either 12 or 18 bits. If it contains
// 12 bits, then discard the last four and interpret the remaining eight as
// an 8-bit big-endian number. If it contains 18 bits, then discard the last
// two and interpret the remaining 16 as two 8-bit big-endian numbers. Append
// the one or two bytes with values equal to those one or two numbers to
// output, in the same order."
if (accumulatedBits === 12) { buffer >>= 4; output += String.fromCharCode(buffer); } else if (accumulatedBits === 18) { buffer >>= 2; output += String.fromCharCode((buffer & 0xff00) >> 8); output += String.fromCharCode(buffer & 0xff); } // "Return output."
return output; } /** * A lookup table for atob(), which converts an ASCII character to the * corresponding six-bit number. */
const keystr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function atobLookup(chr) { const index = keystr.indexOf(chr); // Throw exception if character is not in the lookup string; should not be hit in tests
return index < 0 ? undefined : index; }
module.exports = atob;
|