Base64 decode (v3)

Revision 3 of this benchmark created on


Description

Testing decoding from a string to an ArrayBuffer full of binary data.

Preparation HTML

<script>
  //  Modified from:
  // https://github.com/kanaka/noVNC/blob/master/include/base64.js
  
  var _pad = '=';
  
  var _to_binary_table = [
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
  ];
  
  
  /* Convert Base64 data to a string */
  // @public
  function decode(data, offset, allocator) {
    "use strict";
    offset = typeof (offset) !== 'undefined' ? offset : 0;
    var binTable = _to_binary_table,
          result, result_length, idx, i, c, padding,
          leftbits = 0, // number of bits decoded, but yet to be appended
          leftdata = 0, // bits decoded, but yet to be appended
          data_length = data.indexOf('=') - offset;
  
    if (data_length < 0) { data_length = data.length - offset; }
  
    /* Every four characters is 3 resulting numbers */
    result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
    result = allocator ? allocator(result_length) : (new Array(result_length));
  
    // Convert one by one.
    for (idx = 0, i = offset; i < data.length; i++) {
      c = binTable[data.charCodeAt(i) & 0x7f];
      padding = (data.charAt(i) === _pad);
      // Skip illegal characters and whitespace
      if (c === -1) {
        console.error("Illegal character '" + data.charCodeAt(i) + "'");
        continue;
      }
  
      // Collect data into leftdata, update bitcount
      leftdata = (leftdata << 6) | c;
      leftbits += 6;
  
      // If we have 8 or more bits, append 8 bits to the result
      if (leftbits >= 8) {
        leftbits -= 8;
        // Append if not padding.
        if (!padding) {
          result[idx++] = (leftdata >> leftbits) & 0xff;
        }
        leftdata &= (1 << leftbits) - 1;
      }
    }
  
    // If there are any bits left, the base64 string was corrupted
    if (leftbits) {
      throw { name: 'Base64-Error',
        message: 'Corrupted base64 string'
      };
    }
  
    return result;
  }
          
  function useatob(data, offset, allocator) {
    if (offset) {
      data = data.slice(offset);
    }
    var str = atob(data);
    var len = str.length;
    var result = allocator(len);
    var ii;
    for (ii = 0; ii < len; ++ii) {
      result[ii] = str.charCodeAt(ii);
    }
    return result;
  }
  
      var test_string = "/KkDAQABZQEYUEUxZjliYTQ4MTExMjE2NGI0YzRjMzQyBCEGAfLsq0KNQzzBBo/AQAPrmAO/L9fivg+C9b5LbQ6/AAABGFBFMGQ3NDE4NWI1YWZjMGIwYWQ4Y2NlNAQhBgHjpmFBf8Iownq/S0ADy7LCPWBQtL5vH2Y/EHt4vgAAARhQRTYyNDA0MmMwOWQ5NjE5MjYxNDJmOGQEIQYBrJqpwtr1sMLpkStAA/ic9z6btq6+2+vtPvSYKL8AAAEYUEU3YjEyMjRkNWY0NzgzMTk4OTRiNDkwBCEGAdHKb0KUkVrCRnm7QAP7ibi+as1bPg3Q7T7sqEe/AAABGFBFOGQ0Y2NhMjUwZWE1YTgwYTZiMzdkZgQhBgH/45RCjaZPQq91F0ADiFIJP333bL6FmqQ+mcY+vwAAARhQRTFjODQ5MDYxODNiMDY2YWYxNDgzMTUEIQYBWKuewW/EKULXXjxAA7rPtD5BRVS+tnXsPnJqSb8AAAEYUEU0NGY2YTM4NjY2NzcwOGE1ODMzMmIyBCEGAQ4m3EEhNWVBmasKQAP0BCw/zjDBPBOw1Lw9YT2/AAABGFBFN2ZiNTM1ZmI0NTVlOGU3OTI1NDM0ZQQhBgGUJlJBUNLEQedvs0ADv0JIvrm9hT4xtkE/lQcRvwAAARhQRTUxMWUzYTAyYjdjZTA2Mzk1NzczZDIEIQYB85xrQtVjLkI+1KRAAyK25L36SuM9ZjQyPyBRM78AAAEYUEUzZmVlMzg3ZTY0Y2U0MDkzOTY5ZTA4BCEGAbbbPcLhyqpBsuASQAP68dE+SRuCPjE/7L7Umz6/AAABGFBFMjk3YWM1N2FkYmUzZWM2MDg5YzNiOAQhBgH7K0RB76otQtQKg0ADAPoMu4copjz0hH4/PPLXvQAAARhQRWU1ZmIxMTUyZDkyMmNmODRmNDZiM2YEIQYBMTQXwd73xsAwKZVAA/gguLxAHQK+mfp5v2PgML4AAAEYUEViZmI5ZjFkMmRlN2RhMWI5YmZkM2RjBC4GAcUa275RextBwycFQAPqJaM+kOLGPp8hK7+iYQy/AAwDBC0xXzALBAAAAEMAARhQRTkxZmJmNjhkYTE4MDc4OTQwNTUzOGEEIQYBkZQPQeBJoUH2C1VAA4WFRz1c46e+B+duP031Db4AAAEYUEVlOWE5ODY5NzRlYzk3YzU0YzdkYjk4BCEGAX7fW0GG5yVCejaTQAPehOK8v9rHvWkIdb/Q3Iq+AAAAAA==";
  
      var data = new ArrayBuffer(937);
      var view = new Uint8Array(data);
  
      var lastres;
      function dump() {
        var ii;
        var ret = [];
        for (ii = 0; ii < view.length; ++ii) {
          ret.push(view[ii]);
        }
        var res = ret.join(',');
        console.log(res);
        if (lastres) {
          if (lastres !== res) {
            console.log('NOT EQUAL');
          }
        }
        lastres = res;
      }
  
      decode(test_string, 0, function(byte_length) {
        return view;
      });
      //dump();
  
      useatob(test_string, 0, function(byte_length) {
        return view;
      });
      //dump();
  var a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("")
      , m = {"=":0}
      , i = 64;

    while(m[a[--i]]=i);


function decode2(s){
      for (var out=[],b,i=0,len=s.length,s=s.split("");i<len;) {
        b = m[s[i++]]<<18 | m[s[i++]]<<12 | m[s[i++]]<<6 | m[s[i++]];
        out.push(b>>16 & 0xff, b>>8 & 0xff, b & 0xff);
      }
      if (s[len-1] == "=") out.length -= s[len-2] == "=" ? 2 : 1;
      return String.fromCharCode.apply(null, out);
    }

function usedecode2(data, offset, allocator) {
    if (offset) {
      data = data.slice(offset);
    }
    var str = decode2(data);
    var len = str.length;
    var result = allocator(len);
    var ii;
    for (ii = 0; ii < len; ++ii) {
      result[ii] = str.charCodeAt(ii);
    }
    return result;
  }

</script>

Test runner

Ready to run.

Testing in
TestOps/sec
noVNC Base64 module
    decode(test_string, 0, function(byte_length) {
      return view;
    });
ready
window.atob
    useatob(test_string, 0, function(byte_length) {
      return view;
    });
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.