tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

base64.any.js (5267B)


      1 // META: global=window,dedicatedworker,shadowrealm
      2 
      3 /**
      4 * btoa() as defined by the HTML5 spec, which mostly just references RFC4648.
      5 */
      6 function mybtoa(s) {
      7    // String conversion as required by WebIDL.
      8    s = String(s);
      9 
     10    // "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the
     11    // method's first argument contains any character whose code point is
     12    // greater than U+00FF."
     13    for (var i = 0; i < s.length; i++) {
     14        if (s.charCodeAt(i) > 255) {
     15            return "INVALID_CHARACTER_ERR";
     16        }
     17    }
     18 
     19    var out = "";
     20    for (var i = 0; i < s.length; i += 3) {
     21        var groupsOfSix = [undefined, undefined, undefined, undefined];
     22        groupsOfSix[0] = s.charCodeAt(i) >> 2;
     23        groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
     24        if (s.length > i + 1) {
     25            groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
     26            groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
     27        }
     28        if (s.length > i + 2) {
     29            groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
     30            groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
     31        }
     32        for (var j = 0; j < groupsOfSix.length; j++) {
     33            if (typeof groupsOfSix[j] == "undefined") {
     34                out += "=";
     35            } else {
     36                out += btoaLookup(groupsOfSix[j]);
     37            }
     38        }
     39    }
     40    return out;
     41 }
     42 
     43 /**
     44 * Lookup table for mybtoa(), which converts a six-bit number into the
     45 * corresponding ASCII character.
     46 */
     47 function btoaLookup(idx) {
     48    if (idx < 26) {
     49        return String.fromCharCode(idx + 'A'.charCodeAt(0));
     50    }
     51    if (idx < 52) {
     52        return String.fromCharCode(idx - 26 + 'a'.charCodeAt(0));
     53    }
     54    if (idx < 62) {
     55        return String.fromCharCode(idx - 52 + '0'.charCodeAt(0));
     56    }
     57    if (idx == 62) {
     58        return '+';
     59    }
     60    if (idx == 63) {
     61        return '/';
     62    }
     63    // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
     64 }
     65 
     66 function btoaException(input) {
     67    input = String(input);
     68    for (var i = 0; i < input.length; i++) {
     69        if (input.charCodeAt(i) > 255) {
     70            return true;
     71        }
     72    }
     73    return false;
     74 }
     75 
     76 function testBtoa(input) {
     77    // "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the
     78    // method's first argument contains any character whose code point is
     79    // greater than U+00FF."
     80    var normalizedInput = String(input);
     81    for (var i = 0; i < normalizedInput.length; i++) {
     82        if (normalizedInput.charCodeAt(i) > 255) {
     83            assert_throws_dom("InvalidCharacterError", function() { btoa(input); },
     84                "Code unit " + i + " has value " + normalizedInput.charCodeAt(i) + ", which is greater than 255");
     85            return;
     86        }
     87    }
     88    assert_equals(btoa(input), mybtoa(input));
     89    assert_equals(atob(btoa(input)), String(input), "atob(btoa(input)) must be the same as String(input)");
     90 }
     91 
     92 var tests = ["עברית", "", "ab", "abc", "abcd", "abcde",
     93    // This one is thrown in because IE9 seems to fail atob(btoa()) on it.  Or
     94    // possibly to fail btoa().  I actually can't tell what's happening here,
     95    // but it doesn't hurt.
     96    "\xff\xff\xc0",
     97    // Is your DOM implementation binary-safe?
     98    "\0a", "a\0b",
     99    // WebIDL tests.
    100    undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0,
    101    {toString: function() { return "foo" }},
    102 ];
    103 for (var i = 0; i < 258; i++) {
    104    tests.push(String.fromCharCode(i));
    105 }
    106 tests.push(String.fromCharCode(10000));
    107 tests.push(String.fromCharCode(65534));
    108 tests.push(String.fromCharCode(65535));
    109 
    110 // This is supposed to be U+10000.
    111 tests.push(String.fromCharCode(0xd800, 0xdc00));
    112 tests = tests.map(
    113    function(elem) {
    114        var expected = mybtoa(elem);
    115        if (expected === "INVALID_CHARACTER_ERR") {
    116            return ["btoa("  + format_value(elem) + ") must raise INVALID_CHARACTER_ERR", elem];
    117        }
    118        return ["btoa(" + format_value(elem) + ") == " + format_value(mybtoa(elem)), elem];
    119    }
    120 );
    121 
    122 var everything = "";
    123 for (var i = 0; i < 256; i++) {
    124    everything += String.fromCharCode(i);
    125 }
    126 tests.push(["btoa(first 256 code points concatenated)", everything]);
    127 
    128 generate_tests(testBtoa, tests);
    129 
    130 promise_test(() => fetch_json("../../../fetch/data-urls/resources/base64.json").then(runAtobTests), "atob() setup.");
    131 
    132 const idlTests = [
    133  [undefined, null],
    134  [null, [158, 233, 101]],
    135  [7, null],
    136  [12, [215]],
    137  [1.5, null],
    138  [true, [182, 187]],
    139  [false, null],
    140  [NaN, [53, 163]],
    141  [+Infinity, [34, 119, 226, 158, 43, 114]],
    142  [-Infinity, null],
    143  [0, null],
    144  [-0, null],
    145  [{toString: function() { return "foo" }}, [126, 138]],
    146  [{toString: function() { return "abcd" }}, [105, 183, 29]]
    147 ];
    148 
    149 function runAtobTests(tests) {
    150  const allTests = tests.concat(idlTests);
    151  for(let i = 0; i < allTests.length; i++) {
    152    const input = allTests[i][0],
    153          output = allTests[i][1];
    154    test(() => {
    155      if(output === null) {
    156        assert_throws_dom("InvalidCharacterError", () => globalThis.atob(input));
    157      } else {
    158        const result = globalThis.atob(input);
    159        for(let ii = 0; ii < output.length; ii++) {
    160          assert_equals(result.charCodeAt(ii), output[ii]);
    161        }
    162      }
    163    }, "atob(" + format_value(input) + ")");
    164  }
    165 }