btoa.js
 1  "use strict";
 2  
 3  /**
 4   * btoa() as defined by the HTML and Infra specs, which mostly just references
 5   * RFC 4648.
 6   */
 7  function btoa(s) {
 8    let i;
 9    // String conversion as required by Web IDL.
10    s = `${s}`;
11    // "The btoa() method must throw an "InvalidCharacterError" DOMException if
12    // data contains any character whose code point is greater than U+00FF."
13    for (i = 0; i < s.length; i++) {
14      if (s.charCodeAt(i) > 255) {
15        return null;
16      }
17    }
18    let out = "";
19    for (i = 0; i < s.length; i += 3) {
20      const groupsOfSix = [undefined, undefined, undefined, undefined];
21      groupsOfSix[0] = s.charCodeAt(i) >> 2;
22      groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
23      if (s.length > i + 1) {
24        groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
25        groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
26      }
27      if (s.length > i + 2) {
28        groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
29        groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
30      }
31      for (let j = 0; j < groupsOfSix.length; j++) {
32        if (typeof groupsOfSix[j] === "undefined") {
33          out += "=";
34        } else {
35          out += btoaLookup(groupsOfSix[j]);
36        }
37      }
38    }
39    return out;
40  }
41  
42  /**
43   * Lookup table for btoa(), which converts a six-bit number into the
44   * corresponding ASCII character.
45   */
46  const keystr =
47    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
48  
49  function btoaLookup(index) {
50    if (index >= 0 && index < 64) {
51      return keystr[index];
52    }
53  
54    // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
55    return undefined;
56  }
57  
58  module.exports = btoa;