| /* |
| * The MIT License (MIT) |
| * |
| * Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| (function(global, undefined) { "use strict"; |
| var POW_2_24 = 5.960464477539063e-8, |
| POW_2_32 = 4294967296, |
| POW_2_53 = 9007199254740992; |
| |
| function encode(value) { |
| var data = new ArrayBuffer(256); |
| var dataView = new DataView(data); |
| var lastLength; |
| var offset = 0; |
| |
| function prepareWrite(length) { |
| var newByteLength = data.byteLength; |
| var requiredLength = offset + length; |
| while (newByteLength < requiredLength) |
| newByteLength <<= 1; |
| if (newByteLength !== data.byteLength) { |
| var oldDataView = dataView; |
| data = new ArrayBuffer(newByteLength); |
| dataView = new DataView(data); |
| var uint32count = (offset + 3) >> 2; |
| for (var i = 0; i < uint32count; ++i) |
| dataView.setUint32(i << 2, oldDataView.getUint32(i << 2)); |
| } |
| |
| lastLength = length; |
| return dataView; |
| } |
| function commitWrite() { |
| offset += lastLength; |
| } |
| function writeFloat64(value) { |
| commitWrite(prepareWrite(8).setFloat64(offset, value)); |
| } |
| function writeUint8(value) { |
| commitWrite(prepareWrite(1).setUint8(offset, value)); |
| } |
| function writeUint8Array(value) { |
| var dataView = prepareWrite(value.length); |
| for (var i = 0; i < value.length; ++i) |
| dataView.setUint8(offset + i, value[i]); |
| commitWrite(); |
| } |
| function writeUint16(value) { |
| commitWrite(prepareWrite(2).setUint16(offset, value)); |
| } |
| function writeUint32(value) { |
| commitWrite(prepareWrite(4).setUint32(offset, value)); |
| } |
| function writeUint64(value) { |
| var low = value % POW_2_32; |
| var high = (value - low) / POW_2_32; |
| var dataView = prepareWrite(8); |
| dataView.setUint32(offset, high); |
| dataView.setUint32(offset + 4, low); |
| commitWrite(); |
| } |
| function writeTypeAndLength(type, length) { |
| if (length < 24) { |
| writeUint8(type << 5 | length); |
| } else if (length < 0x100) { |
| writeUint8(type << 5 | 24); |
| writeUint8(length); |
| } else if (length < 0x10000) { |
| writeUint8(type << 5 | 25); |
| writeUint16(length); |
| } else if (length < 0x100000000) { |
| writeUint8(type << 5 | 26); |
| writeUint32(length); |
| } else { |
| writeUint8(type << 5 | 27); |
| writeUint64(length); |
| } |
| } |
| |
| function encodeItem(value) { |
| var i; |
| |
| if (value === false) |
| return writeUint8(0xf4); |
| if (value === true) |
| return writeUint8(0xf5); |
| if (value === null) |
| return writeUint8(0xf6); |
| if (value === undefined) |
| return writeUint8(0xf7); |
| |
| switch (typeof value) { |
| case "number": |
| if (Math.floor(value) === value) { |
| if (0 <= value && value <= POW_2_53) |
| return writeTypeAndLength(0, value); |
| if (-POW_2_53 <= value && value < 0) |
| return writeTypeAndLength(1, -(value + 1)); |
| } |
| writeUint8(0xfb); |
| return writeFloat64(value); |
| |
| case "string": |
| var utf8data = []; |
| for (i = 0; i < value.length; ++i) { |
| var charCode = value.charCodeAt(i); |
| if (charCode < 0x80) { |
| utf8data.push(charCode); |
| } else if (charCode < 0x800) { |
| utf8data.push(0xc0 | charCode >> 6); |
| utf8data.push(0x80 | charCode & 0x3f); |
| } else if (charCode < 0xd800) { |
| utf8data.push(0xe0 | charCode >> 12); |
| utf8data.push(0x80 | (charCode >> 6) & 0x3f); |
| utf8data.push(0x80 | charCode & 0x3f); |
| } else { |
| charCode = (charCode & 0x3ff) << 10; |
| charCode |= value.charCodeAt(++i) & 0x3ff; |
| charCode += 0x10000; |
| |
| utf8data.push(0xf0 | charCode >> 18); |
| utf8data.push(0x80 | (charCode >> 12) & 0x3f); |
| utf8data.push(0x80 | (charCode >> 6) & 0x3f); |
| utf8data.push(0x80 | charCode & 0x3f); |
| } |
| } |
| |
| writeTypeAndLength(3, utf8data.length); |
| return writeUint8Array(utf8data); |
| |
| default: |
| var length; |
| if (Array.isArray(value)) { |
| length = value.length; |
| writeTypeAndLength(4, length); |
| for (i = 0; i < length; ++i) |
| encodeItem(value[i]); |
| } else if (value instanceof Uint8Array) { |
| writeTypeAndLength(2, value.length); |
| writeUint8Array(value); |
| } else { |
| var keys = Object.keys(value); |
| length = keys.length; |
| writeTypeAndLength(5, length); |
| for (i = 0; i < length; ++i) { |
| var key = keys[i]; |
| encodeItem(key); |
| encodeItem(value[key]); |
| } |
| } |
| } |
| } |
| |
| encodeItem(value); |
| |
| if ("slice" in data) |
| return data.slice(0, offset); |
| |
| var ret = new ArrayBuffer(offset); |
| var retView = new DataView(ret); |
| for (var i = 0; i < offset; ++i) |
| retView.setUint8(i, dataView.getUint8(i)); |
| return ret; |
| } |
| |
| function decode(data, tagger, simpleValue) { |
| var dataView = new DataView(data); |
| var offset = 0; |
| |
| if (typeof tagger !== "function") |
| tagger = function(value) { return value; }; |
| if (typeof simpleValue !== "function") |
| simpleValue = function() { return undefined; }; |
| |
| function commitRead(length, value) { |
| offset += length; |
| return value; |
| } |
| function readArrayBuffer(length) { |
| return commitRead(length, new Uint8Array(data, offset, length)); |
| } |
| function readFloat16() { |
| var tempArrayBuffer = new ArrayBuffer(4); |
| var tempDataView = new DataView(tempArrayBuffer); |
| var value = readUint16(); |
| |
| var sign = value & 0x8000; |
| var exponent = value & 0x7c00; |
| var fraction = value & 0x03ff; |
| |
| if (exponent === 0x7c00) |
| exponent = 0xff << 10; |
| else if (exponent !== 0) |
| exponent += (127 - 15) << 10; |
| else if (fraction !== 0) |
| return (sign ? -1 : 1) * fraction * POW_2_24; |
| |
| tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); |
| return tempDataView.getFloat32(0); |
| } |
| function readFloat32() { |
| return commitRead(4, dataView.getFloat32(offset)); |
| } |
| function readFloat64() { |
| return commitRead(8, dataView.getFloat64(offset)); |
| } |
| function readUint8() { |
| return commitRead(1, dataView.getUint8(offset)); |
| } |
| function readUint16() { |
| return commitRead(2, dataView.getUint16(offset)); |
| } |
| function readUint32() { |
| return commitRead(4, dataView.getUint32(offset)); |
| } |
| function readUint64() { |
| return readUint32() * POW_2_32 + readUint32(); |
| } |
| function readBreak() { |
| if (dataView.getUint8(offset) !== 0xff) |
| return false; |
| offset += 1; |
| return true; |
| } |
| function readLength(additionalInformation) { |
| if (additionalInformation < 24) |
| return additionalInformation; |
| if (additionalInformation === 24) |
| return readUint8(); |
| if (additionalInformation === 25) |
| return readUint16(); |
| if (additionalInformation === 26) |
| return readUint32(); |
| if (additionalInformation === 27) |
| return readUint64(); |
| if (additionalInformation === 31) |
| return -1; |
| throw "Invalid length encoding"; |
| } |
| function readIndefiniteStringLength(majorType) { |
| var initialByte = readUint8(); |
| if (initialByte === 0xff) |
| return -1; |
| var length = readLength(initialByte & 0x1f); |
| if (length < 0 || (initialByte >> 5) !== majorType) |
| throw "Invalid indefinite length element"; |
| return length; |
| } |
| |
| function appendUtf16Data(utf16data, length) { |
| for (var i = 0; i < length; ++i) { |
| var value = readUint8(); |
| if (value & 0x80) { |
| if (value < 0xe0) { |
| value = (value & 0x1f) << 6 |
| | (readUint8() & 0x3f); |
| length -= 1; |
| } else if (value < 0xf0) { |
| value = (value & 0x0f) << 12 |
| | (readUint8() & 0x3f) << 6 |
| | (readUint8() & 0x3f); |
| length -= 2; |
| } else { |
| value = (value & 0x0f) << 18 |
| | (readUint8() & 0x3f) << 12 |
| | (readUint8() & 0x3f) << 6 |
| | (readUint8() & 0x3f); |
| length -= 3; |
| } |
| } |
| |
| if (value < 0x10000) { |
| utf16data.push(value); |
| } else { |
| value -= 0x10000; |
| utf16data.push(0xd800 | (value >> 10)); |
| utf16data.push(0xdc00 | (value & 0x3ff)); |
| } |
| } |
| } |
| |
| function decodeItem() { |
| var initialByte = readUint8(); |
| var majorType = initialByte >> 5; |
| var additionalInformation = initialByte & 0x1f; |
| var i; |
| var length; |
| |
| if (majorType === 7) { |
| switch (additionalInformation) { |
| case 25: |
| return readFloat16(); |
| case 26: |
| return readFloat32(); |
| case 27: |
| return readFloat64(); |
| } |
| } |
| |
| length = readLength(additionalInformation); |
| if (length < 0 && (majorType < 2 || 6 < majorType)) |
| throw "Invalid length"; |
| |
| switch (majorType) { |
| case 0: |
| return length; |
| case 1: |
| return -1 - length; |
| case 2: |
| if (length < 0) { |
| var elements = []; |
| var fullArrayLength = 0; |
| while ((length = readIndefiniteStringLength(majorType)) >= 0) { |
| fullArrayLength += length; |
| elements.push(readArrayBuffer(length)); |
| } |
| var fullArray = new Uint8Array(fullArrayLength); |
| var fullArrayOffset = 0; |
| for (i = 0; i < elements.length; ++i) { |
| fullArray.set(elements[i], fullArrayOffset); |
| fullArrayOffset += elements[i].length; |
| } |
| return fullArray; |
| } |
| return readArrayBuffer(length); |
| case 3: |
| var utf16data = []; |
| if (length < 0) { |
| while ((length = readIndefiniteStringLength(majorType)) >= 0) |
| appendUtf16Data(utf16data, length); |
| } else |
| appendUtf16Data(utf16data, length); |
| return String.fromCharCode.apply(null, utf16data); |
| case 4: |
| var retArray; |
| if (length < 0) { |
| retArray = []; |
| while (!readBreak()) |
| retArray.push(decodeItem()); |
| } else { |
| retArray = new Array(length); |
| for (i = 0; i < length; ++i) |
| retArray[i] = decodeItem(); |
| } |
| return retArray; |
| case 5: |
| var retObject = {}; |
| for (i = 0; i < length || length < 0 && !readBreak(); ++i) { |
| var key = decodeItem(); |
| retObject[key] = decodeItem(); |
| } |
| return retObject; |
| case 6: |
| return tagger(decodeItem(), length); |
| case 7: |
| switch (length) { |
| case 20: |
| return false; |
| case 21: |
| return true; |
| case 22: |
| return null; |
| case 23: |
| return undefined; |
| default: |
| return simpleValue(length); |
| } |
| } |
| } |
| |
| var ret = decodeItem(); |
| if (offset !== data.byteLength) |
| throw "Remaining bytes"; |
| return ret; |
| } |
| |
| var obj = { encode: encode, decode: decode }; |
| |
| if (typeof define === "function" && define.amd) |
| define("cbor/cbor", obj); |
| else if (typeof module !== "undefined" && module.exports) |
| module.exports = obj; |
| else if (!global.CBOR) |
| global.CBOR = obj; |
| |
| })(this); |