tor-browser

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

cbor.js (12175B)


      1 /*
      2 * The MIT License (MIT)
      3 *
      4 * Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com>
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in all
     14 * copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22 * SOFTWARE.
     23 */
     24 
     25 (function(global, undefined) { "use strict";
     26 var POW_2_24 = 5.960464477539063e-8,
     27    POW_2_32 = 4294967296,
     28    POW_2_53 = 9007199254740992;
     29 
     30 function encode(value) {
     31  var data = new ArrayBuffer(256);
     32  var dataView = new DataView(data);
     33  var lastLength;
     34  var offset = 0;
     35 
     36  function prepareWrite(length) {
     37    var newByteLength = data.byteLength;
     38    var requiredLength = offset + length;
     39    while (newByteLength < requiredLength)
     40      newByteLength <<= 1;
     41    if (newByteLength !== data.byteLength) {
     42      var oldDataView = dataView;
     43      data = new ArrayBuffer(newByteLength);
     44      dataView = new DataView(data);
     45      var uint32count = (offset + 3) >> 2;
     46      for (var i = 0; i < uint32count; ++i)
     47        dataView.setUint32(i << 2, oldDataView.getUint32(i << 2));
     48    }
     49 
     50    lastLength = length;
     51    return dataView;
     52  }
     53  function commitWrite() {
     54    offset += lastLength;
     55  }
     56  function writeFloat64(value) {
     57    commitWrite(prepareWrite(8).setFloat64(offset, value));
     58  }
     59  function writeUint8(value) {
     60    commitWrite(prepareWrite(1).setUint8(offset, value));
     61  }
     62  function writeUint8Array(value) {
     63    var dataView = prepareWrite(value.length);
     64    for (var i = 0; i < value.length; ++i)
     65      dataView.setUint8(offset + i, value[i]);
     66    commitWrite();
     67  }
     68  function writeUint16(value) {
     69    commitWrite(prepareWrite(2).setUint16(offset, value));
     70  }
     71  function writeUint32(value) {
     72    commitWrite(prepareWrite(4).setUint32(offset, value));
     73  }
     74  function writeUint64(value) {
     75    var low = value % POW_2_32;
     76    var high = (value - low) / POW_2_32;
     77    var dataView = prepareWrite(8);
     78    dataView.setUint32(offset, high);
     79    dataView.setUint32(offset + 4, low);
     80    commitWrite();
     81  }
     82  function writeTypeAndLength(type, length) {
     83    if (length < 24) {
     84      writeUint8(type << 5 | length);
     85    } else if (length < 0x100) {
     86      writeUint8(type << 5 | 24);
     87      writeUint8(length);
     88    } else if (length < 0x10000) {
     89      writeUint8(type << 5 | 25);
     90      writeUint16(length);
     91    } else if (length < 0x100000000) {
     92      writeUint8(type << 5 | 26);
     93      writeUint32(length);
     94    } else {
     95      writeUint8(type << 5 | 27);
     96      writeUint64(length);
     97    }
     98  }
     99 
    100  function encodeItem(value) {
    101    var i;
    102 
    103    if (value === false)
    104      return writeUint8(0xf4);
    105    if (value === true)
    106      return writeUint8(0xf5);
    107    if (value === null)
    108      return writeUint8(0xf6);
    109    if (value === undefined)
    110      return writeUint8(0xf7);
    111 
    112    switch (typeof value) {
    113      case "number":
    114        if (Math.floor(value) === value) {
    115          if (0 <= value && value <= POW_2_53)
    116            return writeTypeAndLength(0, value);
    117          if (-POW_2_53 <= value && value < 0)
    118            return writeTypeAndLength(1, -(value + 1));
    119        }
    120        writeUint8(0xfb);
    121        return writeFloat64(value);
    122 
    123      case "string":
    124        var utf8data = [];
    125        for (i = 0; i < value.length; ++i) {
    126          var charCode = value.charCodeAt(i);
    127          if (charCode < 0x80) {
    128            utf8data.push(charCode);
    129          } else if (charCode < 0x800) {
    130            utf8data.push(0xc0 | charCode >> 6);
    131            utf8data.push(0x80 | charCode & 0x3f);
    132          } else if (charCode < 0xd800) {
    133            utf8data.push(0xe0 | charCode >> 12);
    134            utf8data.push(0x80 | (charCode >> 6)  & 0x3f);
    135            utf8data.push(0x80 | charCode & 0x3f);
    136          } else {
    137            charCode = (charCode & 0x3ff) << 10;
    138            charCode |= value.charCodeAt(++i) & 0x3ff;
    139            charCode += 0x10000;
    140 
    141            utf8data.push(0xf0 | charCode >> 18);
    142            utf8data.push(0x80 | (charCode >> 12)  & 0x3f);
    143            utf8data.push(0x80 | (charCode >> 6)  & 0x3f);
    144            utf8data.push(0x80 | charCode & 0x3f);
    145          }
    146        }
    147 
    148        writeTypeAndLength(3, utf8data.length);
    149        return writeUint8Array(utf8data);
    150 
    151      default:
    152        var length;
    153        if (Array.isArray(value)) {
    154          length = value.length;
    155          writeTypeAndLength(4, length);
    156          for (i = 0; i < length; ++i)
    157            encodeItem(value[i]);
    158        } else if (value instanceof Uint8Array) {
    159          writeTypeAndLength(2, value.length);
    160          writeUint8Array(value);
    161        } else {
    162          var keys = Object.keys(value);
    163          length = keys.length;
    164          writeTypeAndLength(5, length);
    165          for (i = 0; i < length; ++i) {
    166            var key = keys[i];
    167            encodeItem(key);
    168            encodeItem(value[key]);
    169          }
    170        }
    171    }
    172  }
    173 
    174  encodeItem(value);
    175 
    176  if ("slice" in data)
    177    return data.slice(0, offset);
    178 
    179  var ret = new ArrayBuffer(offset);
    180  var retView = new DataView(ret);
    181  for (var i = 0; i < offset; ++i)
    182    retView.setUint8(i, dataView.getUint8(i));
    183  return ret;
    184 }
    185 
    186 function decode(data, tagger, simpleValue) {
    187  var dataView = new DataView(data);
    188  var offset = 0;
    189 
    190  if (typeof tagger !== "function")
    191    tagger = function(value) { return value; };
    192  if (typeof simpleValue !== "function")
    193    simpleValue = function() { return undefined; };
    194 
    195  function commitRead(length, value) {
    196    offset += length;
    197    return value;
    198  }
    199  function readArrayBuffer(length) {
    200    return commitRead(length, new Uint8Array(data, offset, length));
    201  }
    202  function readFloat16() {
    203    var tempArrayBuffer = new ArrayBuffer(4);
    204    var tempDataView = new DataView(tempArrayBuffer);
    205    var value = readUint16();
    206 
    207    var sign = value & 0x8000;
    208    var exponent = value & 0x7c00;
    209    var fraction = value & 0x03ff;
    210 
    211    if (exponent === 0x7c00)
    212      exponent = 0xff << 10;
    213    else if (exponent !== 0)
    214      exponent += (127 - 15) << 10;
    215    else if (fraction !== 0)
    216      return (sign ? -1 : 1) * fraction * POW_2_24;
    217 
    218    tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
    219    return tempDataView.getFloat32(0);
    220  }
    221  function readFloat32() {
    222    return commitRead(4, dataView.getFloat32(offset));
    223  }
    224  function readFloat64() {
    225    return commitRead(8, dataView.getFloat64(offset));
    226  }
    227  function readUint8() {
    228    return commitRead(1, dataView.getUint8(offset));
    229  }
    230  function readUint16() {
    231    return commitRead(2, dataView.getUint16(offset));
    232  }
    233  function readUint32() {
    234    return commitRead(4, dataView.getUint32(offset));
    235  }
    236  function readUint64() {
    237    return readUint32() * POW_2_32 + readUint32();
    238  }
    239  function readBreak() {
    240    if (dataView.getUint8(offset) !== 0xff)
    241      return false;
    242    offset += 1;
    243    return true;
    244  }
    245  function readLength(additionalInformation) {
    246    if (additionalInformation < 24)
    247      return additionalInformation;
    248    if (additionalInformation === 24)
    249      return readUint8();
    250    if (additionalInformation === 25)
    251      return readUint16();
    252    if (additionalInformation === 26)
    253      return readUint32();
    254    if (additionalInformation === 27)
    255      return readUint64();
    256    if (additionalInformation === 31)
    257      return -1;
    258    throw "Invalid length encoding";
    259  }
    260  function readIndefiniteStringLength(majorType) {
    261    var initialByte = readUint8();
    262    if (initialByte === 0xff)
    263      return -1;
    264    var length = readLength(initialByte & 0x1f);
    265    if (length < 0 || (initialByte >> 5) !== majorType)
    266      throw "Invalid indefinite length element";
    267    return length;
    268  }
    269 
    270  function appendUtf16Data(utf16data, length) {
    271    for (var i = 0; i < length; ++i) {
    272      var value = readUint8();
    273      if (value & 0x80) {
    274        if (value < 0xe0) {
    275          value = (value & 0x1f) <<  6
    276                | (readUint8() & 0x3f);
    277          length -= 1;
    278        } else if (value < 0xf0) {
    279          value = (value & 0x0f) << 12
    280                | (readUint8() & 0x3f) << 6
    281                | (readUint8() & 0x3f);
    282          length -= 2;
    283        } else {
    284          value = (value & 0x0f) << 18
    285                | (readUint8() & 0x3f) << 12
    286                | (readUint8() & 0x3f) << 6
    287                | (readUint8() & 0x3f);
    288          length -= 3;
    289        }
    290      }
    291 
    292      if (value < 0x10000) {
    293        utf16data.push(value);
    294      } else {
    295        value -= 0x10000;
    296        utf16data.push(0xd800 | (value >> 10));
    297        utf16data.push(0xdc00 | (value & 0x3ff));
    298      }
    299    }
    300  }
    301 
    302  function decodeItem() {
    303    var initialByte = readUint8();
    304    var majorType = initialByte >> 5;
    305    var additionalInformation = initialByte & 0x1f;
    306    var i;
    307    var length;
    308 
    309    if (majorType === 7) {
    310      switch (additionalInformation) {
    311        case 25:
    312          return readFloat16();
    313        case 26:
    314          return readFloat32();
    315        case 27:
    316          return readFloat64();
    317      }
    318    }
    319 
    320    length = readLength(additionalInformation);
    321    if (length < 0 && (majorType < 2 || 6 < majorType))
    322      throw "Invalid length";
    323 
    324    switch (majorType) {
    325      case 0:
    326        return length;
    327      case 1:
    328        return -1 - length;
    329      case 2:
    330        if (length < 0) {
    331          var elements = [];
    332          var fullArrayLength = 0;
    333          while ((length = readIndefiniteStringLength(majorType)) >= 0) {
    334            fullArrayLength += length;
    335            elements.push(readArrayBuffer(length));
    336          }
    337          var fullArray = new Uint8Array(fullArrayLength);
    338          var fullArrayOffset = 0;
    339          for (i = 0; i < elements.length; ++i) {
    340            fullArray.set(elements[i], fullArrayOffset);
    341            fullArrayOffset += elements[i].length;
    342          }
    343          return fullArray;
    344        }
    345        return readArrayBuffer(length);
    346      case 3:
    347        var utf16data = [];
    348        if (length < 0) {
    349          while ((length = readIndefiniteStringLength(majorType)) >= 0)
    350            appendUtf16Data(utf16data, length);
    351        } else
    352          appendUtf16Data(utf16data, length);
    353        return String.fromCharCode.apply(null, utf16data);
    354      case 4:
    355        var retArray;
    356        if (length < 0) {
    357          retArray = [];
    358          while (!readBreak())
    359            retArray.push(decodeItem());
    360        } else {
    361          retArray = new Array(length);
    362          for (i = 0; i < length; ++i)
    363            retArray[i] = decodeItem();
    364        }
    365        return retArray;
    366      case 5:
    367        var retObject = {};
    368        for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
    369          var key = decodeItem();
    370          retObject[key] = decodeItem();
    371        }
    372        return retObject;
    373      case 6:
    374        return tagger(decodeItem(), length);
    375      case 7:
    376        switch (length) {
    377          case 20:
    378            return false;
    379          case 21:
    380            return true;
    381          case 22:
    382            return null;
    383          case 23:
    384            return undefined;
    385          default:
    386            return simpleValue(length);
    387        }
    388    }
    389  }
    390 
    391  var ret = decodeItem();
    392  if (offset !== data.byteLength)
    393    throw "Remaining bytes";
    394  return ret;
    395 }
    396 
    397 var obj = { encode: encode, decode: decode };
    398 
    399 if (typeof define === "function" && define.amd)
    400  define("cbor/cbor", obj);
    401 else if (typeof module !== "undefined" && module.exports)
    402  module.exports = obj;
    403 else if (!global.CBOR)
    404  global.CBOR = obj;
    405 
    406 })(this);