UNPKG

typescript

Version:

TypeScript is a language for application scale JavaScript development

213 lines 6.74 kB
// Minimal msgpack encoder/decoder. // Supports: arrays, unsigned integers, strings, booleans, binary data. import { Wtf8Decoder } from "./wtf8.js"; // ── MessagePack format constants ──────────────────────────────────── export const MSGPACK_FIXARRAY3 = 0x93; // 3-element fixarray export const MSGPACK_BIN8 = 0xc4; export const MSGPACK_BIN16 = 0xc5; export const MSGPACK_BIN32 = 0xc6; export const MSGPACK_UINT8 = 0xcc; // ── Bin header helpers ────────────────────────────────────────────── /** Compute the MessagePack bin header size for a given data length. */ export function binHeaderSize(len) { if (len < 0x100) return 2; // BIN8: marker + 1-byte size if (len < 0x10000) return 3; // BIN16: marker + 2-byte size return 5; // BIN32: marker + 4-byte size } /** Write a MessagePack bin header into `buf` at `off`, return new offset. */ export function writeBinHeader(buf, off, len) { if (len < 0x100) { buf[off++] = MSGPACK_BIN8; buf[off++] = len; } else if (len < 0x10000) { buf[off++] = MSGPACK_BIN16; buf[off++] = (len >>> 8) & 0xff; buf[off++] = len & 0xff; } else { buf[off++] = MSGPACK_BIN32; buf[off++] = (len >>> 24) & 0xff; buf[off++] = (len >>> 16) & 0xff; buf[off++] = (len >>> 8) & 0xff; buf[off++] = len & 0xff; } return off; } const encoder = new TextEncoder(); const decoder = new Wtf8Decoder(); export class MsgpackWriter { buf; view; pos; constructor(initialSize = 256) { this.buf = new Uint8Array(initialSize); this.view = new DataView(this.buf.buffer); this.pos = 0; } ensure(n) { if (this.pos + n > this.buf.length) { let newSize = this.buf.length * 2; while (newSize < this.pos + n) newSize *= 2; const next = new Uint8Array(newSize); next.set(this.buf); this.buf = next; this.view = new DataView(this.buf.buffer); } } writeArrayHeader(length) { if (length <= 0x0f) { this.ensure(1); this.buf[this.pos++] = 0x90 | length; } else if (length <= 0xffff) { this.ensure(3); this.buf[this.pos++] = 0xdc; this.view.setUint16(this.pos, length, false); this.pos += 2; } else { this.ensure(5); this.buf[this.pos++] = 0xdd; this.view.setUint32(this.pos, length, false); this.pos += 4; } } writeUint(value) { if (value <= 0x7f) { this.ensure(1); this.buf[this.pos++] = value; } else if (value <= 0xff) { this.ensure(2); this.buf[this.pos++] = 0xcc; this.buf[this.pos++] = value; } else if (value <= 0xffff) { this.ensure(3); this.buf[this.pos++] = 0xcd; this.view.setUint16(this.pos, value, false); this.pos += 2; } else { this.ensure(5); this.buf[this.pos++] = 0xce; this.view.setUint32(this.pos, value, false); this.pos += 4; } } writeString(str) { const encoded = encoder.encode(str); const len = encoded.length; if (len <= 0x1f) { this.ensure(1 + len); this.buf[this.pos++] = 0xa0 | len; } else if (len <= 0xff) { this.ensure(2 + len); this.buf[this.pos++] = 0xd9; this.buf[this.pos++] = len; } else if (len <= 0xffff) { this.ensure(3 + len); this.buf[this.pos++] = 0xda; this.view.setUint16(this.pos, len, false); this.pos += 2; } else { this.ensure(5 + len); this.buf[this.pos++] = 0xdb; this.view.setUint32(this.pos, len, false); this.pos += 4; } this.buf.set(encoded, this.pos); this.pos += len; } writeBool(value) { this.ensure(1); this.buf[this.pos++] = value ? 0xc3 : 0xc2; } finish() { return this.buf.subarray(0, this.pos); } } export class MsgpackReader { buf; view; pos; constructor(data, offset = 0) { this.buf = data; this.view = new DataView(data.buffer, data.byteOffset, data.byteLength); this.pos = offset; } readArrayHeader() { const byte = this.buf[this.pos++]; if ((byte & 0xf0) === 0x90) return byte & 0x0f; if (byte === 0xdc) { const len = this.view.getUint16(this.pos, false); this.pos += 2; return len; } if (byte === 0xdd) { const len = this.view.getUint32(this.pos, false); this.pos += 4; return len; } throw new Error(`Expected array header, got 0x${byte.toString(16)}`); } readUint() { const byte = this.buf[this.pos++]; if (byte <= 0x7f) return byte; if (byte === 0xcc) return this.buf[this.pos++]; if (byte === 0xcd) { const val = this.view.getUint16(this.pos, false); this.pos += 2; return val; } if (byte === 0xce) { const val = this.view.getUint32(this.pos, false); this.pos += 4; return val; } throw new Error(`Expected uint, got 0x${byte.toString(16)}`); } readString() { const byte = this.buf[this.pos++]; let len; if ((byte & 0xe0) === 0xa0) { len = byte & 0x1f; } else if (byte === 0xd9) { len = this.buf[this.pos++]; } else if (byte === 0xda) { len = this.view.getUint16(this.pos, false); this.pos += 2; } else if (byte === 0xdb) { len = this.view.getUint32(this.pos, false); this.pos += 4; } else { throw new Error(`Expected string, got 0x${byte.toString(16)}`); } const str = decoder.decode(this.buf.subarray(this.pos, this.pos + len)); this.pos += len; return str; } readBool() { const byte = this.buf[this.pos++]; if (byte === 0xc3) return true; if (byte === 0xc2) return false; throw new Error(`Expected bool, got 0x${byte.toString(16)}`); } } //# sourceMappingURL=msgpack.js.map