tor-browser

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

cbor.js (7663B)


      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 "use strict";
     26 const POW_2_24 = 5.960464477539063e-8;
     27 const POW_2_32 = 4294967296;
     28 
     29 function decode(data, tagger, simpleValue) {
     30  const dataView = new DataView(data);
     31  let offset = 0;
     32 
     33  if (typeof tagger !== "function") {
     34    tagger = function (value) {
     35      return value;
     36    };
     37  }
     38  if (typeof simpleValue !== "function") {
     39    simpleValue = function () {
     40      return undefined;
     41    };
     42  }
     43 
     44  function commitRead(length, value) {
     45    offset += length;
     46    return value;
     47  }
     48  function readArrayBuffer(length) {
     49    return commitRead(length, new Uint8Array(data, offset, length));
     50  }
     51  function readFloat16() {
     52    const tempArrayBuffer = new ArrayBuffer(4);
     53    const tempDataView = new DataView(tempArrayBuffer);
     54    const value = readUint16();
     55 
     56    const sign = value & 0x8000;
     57    let exponent = value & 0x7c00;
     58    const fraction = value & 0x03ff;
     59 
     60    if (exponent === 0x7c00) {
     61      exponent = 0xff << 10;
     62    } else if (exponent !== 0) {
     63      exponent += (127 - 15) << 10;
     64    } else if (fraction !== 0) {
     65      return (sign ? -1 : 1) * fraction * POW_2_24;
     66    }
     67 
     68    tempDataView.setUint32(
     69      0,
     70      (sign << 16) | (exponent << 13) | (fraction << 13)
     71    );
     72    return tempDataView.getFloat32(0);
     73  }
     74  function readFloat32() {
     75    return commitRead(4, dataView.getFloat32(offset));
     76  }
     77  function readFloat64() {
     78    return commitRead(8, dataView.getFloat64(offset));
     79  }
     80  function readUint8() {
     81    return commitRead(1, dataView.getUint8(offset));
     82  }
     83  function readUint16() {
     84    return commitRead(2, dataView.getUint16(offset));
     85  }
     86  function readUint32() {
     87    return commitRead(4, dataView.getUint32(offset));
     88  }
     89  function readUint64() {
     90    return readUint32() * POW_2_32 + readUint32();
     91  }
     92  function readBreak() {
     93    if (dataView.getUint8(offset) !== 0xff) {
     94      return false;
     95    }
     96    offset += 1;
     97    return true;
     98  }
     99  function readLength(additionalInformation) {
    100    if (additionalInformation < 24) {
    101      return additionalInformation;
    102    }
    103    if (additionalInformation === 24) {
    104      return readUint8();
    105    }
    106    if (additionalInformation === 25) {
    107      return readUint16();
    108    }
    109    if (additionalInformation === 26) {
    110      return readUint32();
    111    }
    112    if (additionalInformation === 27) {
    113      return readUint64();
    114    }
    115    if (additionalInformation === 31) {
    116      return -1;
    117    }
    118    throw new Error("Invalid length encoding");
    119  }
    120  function readIndefiniteStringLength(majorType) {
    121    const initialByte = readUint8();
    122    if (initialByte === 0xff) {
    123      return -1;
    124    }
    125    const length = readLength(initialByte & 0x1f);
    126    if (length < 0 || initialByte >> 5 !== majorType) {
    127      throw new Error("Invalid indefinite length element");
    128    }
    129    return length;
    130  }
    131 
    132  function appendUtf16Data(utf16data, length) {
    133    for (let i = 0; i < length; ++i) {
    134      let value = readUint8();
    135      if (value & 0x80) {
    136        if (value < 0xe0) {
    137          value = ((value & 0x1f) << 6) | (readUint8() & 0x3f);
    138          length -= 1;
    139        } else if (value < 0xf0) {
    140          value =
    141            ((value & 0x0f) << 12) |
    142            ((readUint8() & 0x3f) << 6) |
    143            (readUint8() & 0x3f);
    144          length -= 2;
    145        } else {
    146          value =
    147            ((value & 0x0f) << 18) |
    148            ((readUint8() & 0x3f) << 12) |
    149            ((readUint8() & 0x3f) << 6) |
    150            (readUint8() & 0x3f);
    151          length -= 3;
    152        }
    153      }
    154 
    155      if (value < 0x10000) {
    156        utf16data.push(value);
    157      } else {
    158        value -= 0x10000;
    159        utf16data.push(0xd800 | (value >> 10));
    160        utf16data.push(0xdc00 | (value & 0x3ff));
    161      }
    162    }
    163  }
    164 
    165  // eslint-disable-next-line complexity
    166  function decodeItem() {
    167    const initialByte = readUint8();
    168    const majorType = initialByte >> 5;
    169    const additionalInformation = initialByte & 0x1f;
    170    let i;
    171    let length;
    172 
    173    if (majorType === 7) {
    174      switch (additionalInformation) {
    175        case 25:
    176          return readFloat16();
    177        case 26:
    178          return readFloat32();
    179        case 27:
    180          return readFloat64();
    181      }
    182    }
    183 
    184    length = readLength(additionalInformation);
    185    if (length < 0 && (majorType < 2 || majorType > 6)) {
    186      throw new Error("Invalid length");
    187    }
    188 
    189    switch (majorType) {
    190      case 0:
    191        return length;
    192      case 1:
    193        return -1 - length;
    194      case 2:
    195        if (length < 0) {
    196          const elements = [];
    197          let fullArrayLength = 0;
    198          while ((length = readIndefiniteStringLength(majorType)) >= 0) {
    199            fullArrayLength += length;
    200            elements.push(readArrayBuffer(length));
    201          }
    202          const fullArray = new Uint8Array(fullArrayLength);
    203          let fullArrayOffset = 0;
    204          for (i = 0; i < elements.length; ++i) {
    205            fullArray.set(elements[i], fullArrayOffset);
    206            fullArrayOffset += elements[i].length;
    207          }
    208          return fullArray;
    209        }
    210        return readArrayBuffer(length);
    211      case 3: {
    212        const utf16data = [];
    213        if (length < 0) {
    214          while ((length = readIndefiniteStringLength(majorType)) >= 0) {
    215            appendUtf16Data(utf16data, length);
    216          }
    217        } else {
    218          appendUtf16Data(utf16data, length);
    219        }
    220        return String.fromCharCode.apply(null, utf16data);
    221      }
    222      case 4: {
    223        let retArray;
    224        if (length < 0) {
    225          retArray = [];
    226          while (!readBreak()) {
    227            retArray.push(decodeItem());
    228          }
    229        } else {
    230          retArray = new Array(length);
    231          for (i = 0; i < length; ++i) {
    232            retArray[i] = decodeItem();
    233          }
    234        }
    235        return retArray;
    236      }
    237      case 5: {
    238        const retObject = {};
    239        for (i = 0; i < length || (length < 0 && !readBreak()); ++i) {
    240          const key = decodeItem();
    241          retObject[key] = decodeItem();
    242        }
    243        return retObject;
    244      }
    245      case 6:
    246        return tagger(decodeItem(), length);
    247      case 7:
    248        switch (length) {
    249          case 20:
    250            return false;
    251          case 21:
    252            return true;
    253          case 22:
    254            return null;
    255          case 23:
    256            return undefined;
    257          default:
    258            return simpleValue(length);
    259        }
    260    }
    261 
    262    throw new Error("Invalid major byte");
    263  }
    264 
    265  const ret = decodeItem();
    266  if (offset !== data.byteLength) {
    267    throw new Error("Remaining bytes");
    268  }
    269 
    270  return ret;
    271 }
    272 
    273 module.exports = { decode };