summaryrefslogtreecommitdiffstats
path: root/devtools/client/netmonitor/src/components/messages/msgpack.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/netmonitor/src/components/messages/msgpack.js365
1 files changed, 365 insertions, 0 deletions
diff --git a/devtools/client/netmonitor/src/components/messages/msgpack.js b/devtools/client/netmonitor/src/components/messages/msgpack.js
new file mode 100644
index 0000000000..e54e2707e9
--- /dev/null
+++ b/devtools/client/netmonitor/src/components/messages/msgpack.js
@@ -0,0 +1,365 @@
+// Copyright © 2019, Yves Goergen, https://unclassified.software/source/msgpack-js
+//
+// 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.
+
+"use strict";
+
+// Deserializes a MessagePack byte array to a value.
+//
+// array: The MessagePack byte array to deserialize. This must be an Array or Uint8Array containing bytes, not a string.
+function deserialize(array) {
+ const pow32 = 0x100000000; // 2^32
+ let pos = 0;
+ if (array instanceof ArrayBuffer) {
+ array = new Uint8Array(array);
+ }
+ if (typeof array !== "object" || typeof array.length === "undefined") {
+ throw new Error(
+ "Invalid argument type: Expected a byte array (Array or Uint8Array) to deserialize."
+ );
+ }
+ if (!array.length) {
+ throw new Error(
+ "Invalid argument: The byte array to deserialize is empty."
+ );
+ }
+ if (!(array instanceof Uint8Array)) {
+ array = new Uint8Array(array);
+ }
+ const data = read();
+ if (pos < array.length) {
+ // Junk data at the end
+ }
+ return data;
+
+ // eslint-disable-next-line complexity
+ function read() {
+ const byte = array[pos++];
+ if (byte >= 0x00 && byte <= 0x7f) {
+ return byte;
+ } // positive fixint
+ if (byte >= 0x80 && byte <= 0x8f) {
+ return readMap(byte - 0x80);
+ } // fixmap
+ if (byte >= 0x90 && byte <= 0x9f) {
+ return readArray(byte - 0x90);
+ } // fixarray
+ if (byte >= 0xa0 && byte <= 0xbf) {
+ return readStr(byte - 0xa0);
+ } // fixstr
+ if (byte === 0xc0) {
+ return null;
+ } // nil
+ if (byte === 0xc1) {
+ throw new Error("Invalid byte code 0xc1 found.");
+ } // never used
+ if (byte === 0xc2) {
+ return false;
+ } // false
+ if (byte === 0xc3) {
+ return true;
+ } // true
+ if (byte === 0xc4) {
+ return readBin(-1, 1);
+ } // bin 8
+ if (byte === 0xc5) {
+ return readBin(-1, 2);
+ } // bin 16
+ if (byte === 0xc6) {
+ return readBin(-1, 4);
+ } // bin 32
+ if (byte === 0xc7) {
+ return readExt(-1, 1);
+ } // ext 8
+ if (byte === 0xc8) {
+ return readExt(-1, 2);
+ } // ext 16
+ if (byte === 0xc9) {
+ return readExt(-1, 4);
+ } // ext 32
+ if (byte === 0xca) {
+ return readFloat(4);
+ } // float 32
+ if (byte === 0xcb) {
+ return readFloat(8);
+ } // float 64
+ if (byte === 0xcc) {
+ return readUInt(1);
+ } // uint 8
+ if (byte === 0xcd) {
+ return readUInt(2);
+ } // uint 16
+ if (byte === 0xce) {
+ return readUInt(4);
+ } // uint 32
+ if (byte === 0xcf) {
+ return readUInt(8);
+ } // uint 64
+ if (byte === 0xd0) {
+ return readInt(1);
+ } // int 8
+ if (byte === 0xd1) {
+ return readInt(2);
+ } // int 16
+ if (byte === 0xd2) {
+ return readInt(4);
+ } // int 32
+ if (byte === 0xd3) {
+ return readInt(8);
+ } // int 64
+ if (byte === 0xd4) {
+ return readExt(1);
+ } // fixext 1
+ if (byte === 0xd5) {
+ return readExt(2);
+ } // fixext 2
+ if (byte === 0xd6) {
+ return readExt(4);
+ } // fixext 4
+ if (byte === 0xd7) {
+ return readExt(8);
+ } // fixext 8
+ if (byte === 0xd8) {
+ return readExt(16);
+ } // fixext 16
+ if (byte === 0xd9) {
+ return readStr(-1, 1);
+ } // str 8
+ if (byte === 0xda) {
+ return readStr(-1, 2);
+ } // str 16
+ if (byte === 0xdb) {
+ return readStr(-1, 4);
+ } // str 32
+ if (byte === 0xdc) {
+ return readArray(-1, 2);
+ } // array 16
+ if (byte === 0xdd) {
+ return readArray(-1, 4);
+ } // array 32
+ if (byte === 0xde) {
+ return readMap(-1, 2);
+ } // map 16
+ if (byte === 0xdf) {
+ return readMap(-1, 4);
+ } // map 32
+ if (byte >= 0xe0 && byte <= 0xff) {
+ return byte - 256;
+ } // negative fixint
+ console.debug("msgpack array:", array);
+ throw new Error(
+ "Invalid byte value '" +
+ byte +
+ "' at index " +
+ (pos - 1) +
+ " in the MessagePack binary data (length " +
+ array.length +
+ "): Expecting a range of 0 to 255. This is not a byte array."
+ );
+ }
+
+ function readInt(size) {
+ let value = 0;
+ let first = true;
+ while (size-- > 0) {
+ if (first) {
+ const byte = array[pos++];
+ value += byte & 0x7f;
+ if (byte & 0x80) {
+ value -= 0x80; // Treat most-significant bit as -2^i instead of 2^i
+ }
+ first = false;
+ } else {
+ value *= 256;
+ value += array[pos++];
+ }
+ }
+ return value;
+ }
+
+ function readUInt(size) {
+ let value = 0;
+ while (size-- > 0) {
+ value *= 256;
+ value += array[pos++];
+ }
+ return value;
+ }
+
+ function readFloat(size) {
+ const view = new DataView(array.buffer, pos, size);
+ pos += size;
+ if (size === 4) {
+ return view.getFloat32(0, false);
+ }
+ if (size === 8) {
+ return view.getFloat64(0, false);
+ }
+ throw new Error("Invalid size for readFloat.");
+ }
+
+ function readBin(size, lengthSize) {
+ if (size < 0) {
+ size = readUInt(lengthSize);
+ }
+ const readData = array.subarray(pos, pos + size);
+ pos += size;
+ return readData;
+ }
+
+ function readMap(size, lengthSize) {
+ if (size < 0) {
+ size = readUInt(lengthSize);
+ }
+ const readData = {};
+ while (size-- > 0) {
+ const key = read();
+ readData[key] = read();
+ }
+ return readData;
+ }
+
+ function readArray(size, lengthSize) {
+ if (size < 0) {
+ size = readUInt(lengthSize);
+ }
+ const readData = [];
+ while (size-- > 0) {
+ readData.push(read());
+ }
+ return readData;
+ }
+
+ function readStr(size, lengthSize) {
+ if (size < 0) {
+ size = readUInt(lengthSize);
+ }
+ const start = pos;
+ pos += size;
+ return decodeUtf8(array, start, size);
+ }
+
+ function readExt(size, lengthSize) {
+ if (size < 0) {
+ size = readUInt(lengthSize);
+ }
+ const type = readUInt(1);
+ const readData = readBin(size);
+ switch (type) {
+ case 255:
+ return readExtDate(readData);
+ }
+ return { type, data: readData };
+ }
+
+ function readExtDate(givenData) {
+ if (givenData.length === 4) {
+ const sec =
+ ((givenData[0] << 24) >>> 0) +
+ ((givenData[1] << 16) >>> 0) +
+ ((givenData[2] << 8) >>> 0) +
+ givenData[3];
+ return new Date(sec * 1000);
+ }
+ if (givenData.length === 8) {
+ const ns =
+ ((givenData[0] << 22) >>> 0) +
+ ((givenData[1] << 14) >>> 0) +
+ ((givenData[2] << 6) >>> 0) +
+ (givenData[3] >>> 2);
+ const sec =
+ (givenData[3] & 0x3) * pow32 +
+ ((givenData[4] << 24) >>> 0) +
+ ((givenData[5] << 16) >>> 0) +
+ ((givenData[6] << 8) >>> 0) +
+ givenData[7];
+ return new Date(sec * 1000 + ns / 1000000);
+ }
+ if (givenData.length === 12) {
+ const ns =
+ ((givenData[0] << 24) >>> 0) +
+ ((givenData[1] << 16) >>> 0) +
+ ((givenData[2] << 8) >>> 0) +
+ givenData[3];
+ pos -= 8;
+ const sec = readInt(8);
+ return new Date(sec * 1000 + ns / 1000000);
+ }
+ throw new Error("Invalid givenData length for a date value.");
+ }
+}
+
+// Decodes a string from UTF-8 bytes.
+function decodeUtf8(bytes, start, length) {
+ // Based on: https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330
+ let i = start,
+ str = "";
+ length += start;
+ while (i < length) {
+ let c = bytes[i++];
+ if (c > 127) {
+ if (c > 191 && c < 224) {
+ if (i >= length) {
+ throw new Error("UTF-8 decode: incomplete 2-byte sequence");
+ }
+ c = ((c & 31) << 6) | (bytes[i++] & 63);
+ } else if (c > 223 && c < 240) {
+ if (i + 1 >= length) {
+ throw new Error("UTF-8 decode: incomplete 3-byte sequence");
+ }
+ c = ((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63);
+ } else if (c > 239 && c < 248) {
+ if (i + 2 >= length) {
+ throw new Error("UTF-8 decode: incomplete 4-byte sequence");
+ }
+ c =
+ ((c & 7) << 18) |
+ ((bytes[i++] & 63) << 12) |
+ ((bytes[i++] & 63) << 6) |
+ (bytes[i++] & 63);
+ } else {
+ throw new Error(
+ "UTF-8 decode: unknown multibyte start 0x" +
+ c.toString(16) +
+ " at index " +
+ (i - 1)
+ );
+ }
+ }
+ if (c <= 0xffff) {
+ str += String.fromCharCode(c);
+ } else if (c <= 0x10ffff) {
+ c -= 0x10000;
+ str += String.fromCharCode((c >> 10) | 0xd800);
+ str += String.fromCharCode((c & 0x3ff) | 0xdc00);
+ } else {
+ throw new Error(
+ "UTF-8 decode: code point 0x" + c.toString(16) + " exceeds UTF-16 reach"
+ );
+ }
+ }
+ return str;
+}
+
+// The exported functions
+const msgpack = {
+ deserialize,
+
+ // Compatibility with other libraries
+ decode: deserialize,
+};
+
+module.exports = msgpack;