UNPKG

@devgrid/messagepack

Version:
310 lines 10.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const smartbuffer_1 = require("@devgrid/smartbuffer"); const getSize = (first) => { switch (first) { case 0xc4: return 2; case 0xc5: return 3; case 0xc6: return 5; case 0xc7: return 3; case 0xc8: return 4; case 0xc9: return 6; case 0xca: return 5; case 0xcb: return 9; case 0xcc: return 2; case 0xcd: return 3; case 0xce: return 5; case 0xcf: return 9; case 0xd0: return 2; case 0xd1: return 3; case 0xd2: return 5; case 0xd3: return 9; case 0xd4: return 3; case 0xd5: return 4; case 0xd6: return 6; case 0xd7: return 10; case 0xd8: return 18; case 0xd9: return 2; case 0xda: return 3; case 0xdb: return 5; case 0xde: return 3; default: return -1; } }; const buildDecodeResult = (value, bytesConsumed) => ({ value, bytesConsumed, }); const isValidDataSize = (dataLength, bufLength, headerLength) => bufLength >= headerLength + dataLength; class Decoder { constructor(decodingTypes) { this.decodingTypes = decodingTypes; } decode(buf) { const smartBuf = (0, smartbuffer_1.isSmartBuffer)(buf) ? buf : smartbuffer_1.SmartBuffer.wrap(buf, undefined, true); const result = this.tryDecode(smartBuf); if (result) { return result.value; } throw new Error('Incomplete buffer'); } tryDecode(buf) { const bufLength = buf.length; if (bufLength <= 0) { return null; } const first = buf.readUInt8(); let length; let result = 0; let type; const size = getSize(first); if (size !== -1 && bufLength < size) { return null; } switch (first) { case 0xc0: return buildDecodeResult(null, 1); case 0xc2: return buildDecodeResult(false, 1); case 0xc3: return buildDecodeResult(true, 1); case 0xcc: result = buf.readUInt8(); return buildDecodeResult(result, 2); case 0xcd: result = buf.readUInt16BE(); return buildDecodeResult(result, 3); case 0xce: result = buf.readUInt32BE(); return buildDecodeResult(result, 5); case 0xcf: result = buf.readUInt64BE().toNumber(); return buildDecodeResult(result, 9); case 0xd0: result = buf.readInt8(); return buildDecodeResult(result, 2); case 0xd1: result = buf.readInt16BE(); return buildDecodeResult(result, 3); case 0xd2: result = buf.readInt32BE(); return buildDecodeResult(result, 5); case 0xd3: result = buf.readInt64BE().toNumber(); return buildDecodeResult(result, 9); case 0xca: result = buf.readFloatBE(); return buildDecodeResult(result, 5); case 0xcb: result = buf.readDoubleBE(); return buildDecodeResult(result, 9); case 0xd9: length = buf.readUInt8(); if (!isValidDataSize(length, bufLength, 2)) { return null; } result = buf.toString('utf8', buf.roffset, buf.roffset + length); buf.skipRead(length); return buildDecodeResult(result, 2 + length); case 0xda: length = buf.readUInt16BE(); if (!isValidDataSize(length, bufLength, 3)) { return null; } result = buf.toString('utf8', buf.roffset, buf.roffset + length); buf.skipRead(length); return buildDecodeResult(result, 3 + length); case 0xdb: length = buf.readUInt32BE(); if (!isValidDataSize(length, bufLength, 5)) { return null; } result = buf.toString('utf8', buf.roffset, buf.roffset + length); buf.skipRead(length); return buildDecodeResult(result, 5 + length); case 0xc4: length = buf.readUInt8(); if (!isValidDataSize(length, bufLength, 2)) { return null; } result = buf.slice(buf.roffset, buf.roffset + length).buffer; buf.skipRead(length); return buildDecodeResult(result, 2 + length); case 0xc5: length = buf.readUInt16BE(); if (!isValidDataSize(length, bufLength, 3)) { return null; } result = buf.slice(buf.roffset, buf.roffset + length).buffer; buf.skipRead(length); return buildDecodeResult(result, 3 + length); case 0xc6: length = buf.readUInt32BE(); if (!isValidDataSize(length, bufLength, 5)) { return null; } result = buf.slice(buf.roffset, buf.roffset + length).buffer; buf.skipRead(length); return buildDecodeResult(result, 5 + length); case 0xdc: if (bufLength < 3) { return null; } length = buf.readUInt16BE(); return this.decodeArray(buf, length, 3); case 0xdd: if (bufLength < 5) { return null; } length = buf.readUInt32BE(); return this.decodeArray(buf, length, 5); case 0xde: length = buf.readUInt16BE(); return this.decodeMap(buf, length, 3); case 0xdf: throw new Error('map too big to decode in JS'); case 0xd4: return this.decodeFixExt(buf, 1); case 0xd5: return this.decodeFixExt(buf, 2); case 0xd6: return this.decodeFixExt(buf, 4); case 0xd7: return this.decodeFixExt(buf, 8); case 0xd8: return this.decodeFixExt(buf, 16); case 0xc7: length = buf.readUInt8(); type = buf.readUInt8(); if (!isValidDataSize(length, bufLength, 3)) { return null; } return this.decodeExt(buf, type, length, 3); case 0xc8: length = buf.readUInt16BE(); type = buf.readUInt8(); if (!isValidDataSize(length, bufLength, 4)) { return null; } return this.decodeExt(buf, type, length, 4); case 0xc9: length = buf.readUInt32BE(); type = buf.readUInt8(); if (!isValidDataSize(length, bufLength, 6)) { return null; } return this.decodeExt(buf, type, length, 6); } if ((first & 0xf0) === 0x90) { length = first & 0x0f; return this.decodeArray(buf, length, 1); } else if ((first & 0xf0) === 0x80) { length = first & 0x0f; return this.decodeMap(buf, length, 1); } else if ((first & 0xe0) === 0xa0) { length = first & 0x1f; if (isValidDataSize(length, bufLength, 1)) { result = buf.toString('utf8', buf.roffset, buf.roffset + length); buf.skipRead(length); return buildDecodeResult(result, length + 1); } return null; } else if (first >= 0xe0) { result = first - 0x100; return buildDecodeResult(result, 1); } else if (first < 0x80) { return buildDecodeResult(first, 1); } throw new Error('Not implemented yet'); } decodeMap(buf, length, headerLength) { const result = {}; let key; let totalBytesConsumed = 0; for (let i = 0; i < length; ++i) { const keyResult = this.tryDecode(buf); if (keyResult) { const valueResult = this.tryDecode(buf); if (valueResult) { key = keyResult.value; result[key] = valueResult.value; totalBytesConsumed += keyResult.bytesConsumed + valueResult.bytesConsumed; } else { return null; } } else { return null; } } return buildDecodeResult(result, headerLength + totalBytesConsumed); } decodeArray(buf, length, headerLength) { const result = []; let totalBytesConsumed = 0; for (let i = 0; i < length; ++i) { const decodeResult = this.tryDecode(buf); if (decodeResult) { result.push(decodeResult.value); totalBytesConsumed += decodeResult.bytesConsumed; } else { return null; } } return buildDecodeResult(result, headerLength + totalBytesConsumed); } decodeFixExt(buf, size) { const type = buf.readUInt8(); return this.decodeExt(buf, type, size, 2); } decodeExt(buf, type, size, headerSize) { const decTypes = this.decodingTypes; const decode = decTypes.get(type); if (decode) { const value = decode(buf.slice(buf.roffset, buf.roffset + size)); buf.skipRead(size); return buildDecodeResult(value, headerSize + size); } if (type === 0) { const val = buf.readUInt8(); if (val === 0) { return buildDecodeResult(undefined, headerSize + size); } } throw new Error(`Unable to find ext type ${type}`); } } exports.default = Decoder; //# sourceMappingURL=decoder.js.map