Skip to content

Instantly share code, notes, and snippets.

@justind000
Created September 14, 2020 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justind000/d2a22f31daee6f19c7eca9a40cf1b337 to your computer and use it in GitHub Desktop.
Save justind000/d2a22f31daee6f19c7eca9a40cf1b337 to your computer and use it in GitHub Desktop.
MsgPack decode for Helium Console - lacks float64
Copyright © 2020, Justin Decker
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.
function Decoder(bytes, port) {
return deserialize(bytes);;
}
function deserialize(array) {
pow32 = 0x100000000;
pos = 0;
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);
//}
data = read();
if (pos < array.length) {
// Junk data at the end
}
return data;
function read() {
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) {
value = 0;
first = true;
while (size-- > 0) {
if (first) {
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) {
value = 0;
while (size-- > 0) {
value *= 256;
value += array[pos++];
}
return value;
}
function readFloat(size) {
var bits = array[pos] << 24 | array[pos + 1] << 16 | array[pos + 2] << 8 | array[pos + 3];
var sign = (bits >>> 31 === 0) ? 1.0 : -1.0;
var e = bits >>> 23 & 0xff;
var m = (e === 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
var f = sign * m * Math.pow(2, e - 150);
f = Math.round(f * 10) / 10;
pos += size;
return f;
}
function readBin(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
data = array.subarray(pos, pos + size);
pos += size;
return data;
}
function readMap(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
data = {};
while (size-- > 0) {
key = read();
data[key] = read();
}
return data;
}
function readArray(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
data = [];
while (size-- > 0) {
data.push(read());
}
return data;
}
function readStr(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
start = pos;
pos += size;
return decodeUtf8(array, start, size);
}
function readExt(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
type = readUInt(1);
data = readBin(size);
switch (type) {
case 255:
return readExtDate(data);
}
return {
type: type,
data: data
};
}
function readExtDate(data) {
if (data.length === 4) {
sec = ((data[0] << 24) >>> 0) +
((data[1] << 16) >>> 0) +
((data[2] << 8) >>> 0) +
data[3];
return new Date(sec * 1000);
}
if (data.length === 8) {
ns = ((data[0] << 22) >>> 0) +
((data[1] << 14) >>> 0) +
((data[2] << 6) >>> 0) +
(data[3] >>> 2);
sec = ((data[3] & 0x3) * _pow32) +
((data[4] << 24) >>> 0) +
((data[5] << 16) >>> 0) +
((data[6] << 8) >>> 0) +
data[7];
return new Date(sec * 1000 + ns / 1000000);
}
if (data.length === 12) {
ns = ((data[0] << 24) >>> 0) +
((data[1] << 16) >>> 0) +
((data[2] << 8) >>> 0) +
data[3];
pos -= 8;
sec = readInt(8);
return new Date(sec * 1000 + ns / 1000000);
}
throw new Error("Invalid data length for a date value.");
}
}
// Encodes a string to UTF-8 bytes.
function encodeUtf8(str) {
// Prevent excessive array allocation and slicing for all 7-bit characters
ascii = true, length = str.length;
for (x = 0; x < length; x++) {
if (str.charCodeAt(x) > 127) {
ascii = false;
break;
}
}
// Based on: https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330
i = 0, bytes = new Uint8Array(str.length * (ascii ? 1 : 4));
for (ci = 0; ci !== length; ci++) {
c = str.charCodeAt(ci);
if (c < 128) {
bytes[i++] = c;
continue;
}
if (c < 2048) {
bytes[i++] = c >> 6 | 192;
} else {
if (c > 0xd7ff && c < 0xdc00) {
if (++ci >= length)
throw new Error("UTF-8 encode: incompe surrogate pair");
c2 = str.charCodeAt(ci);
if (c2 < 0xdc00 || c2 > 0xdfff)
throw new Error("UTF-8 encode: second surrogate character 0x" + c2.toString(16) + " at index " + ci + " out of range");
c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
bytes[i++] = c >> 18 | 240;
bytes[i++] = c >> 12 & 63 | 128;
} else bytes[i++] = c >> 12 | 224;
bytes[i++] = c >> 6 & 63 | 128;
}
bytes[i++] = c & 63 | 128;
}
return ascii ? bytes : bytes.subarray(0, i);
}
// Decodes a string from UTF-8 bytes.
function decodeUtf8(bytes, start, length) {
// Based on: https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330
i = start, str = "";
length += start;
while (i < length) {
c = bytes[i++];
if (c > 127) {
if (c > 191 && c < 224) {
if (i >= length)
throw new Error("UTF-8 decode: incompe 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: incompe 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: incompe 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment