|
|
- /*
- * 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);
|