UNPKG

@cloudpss/ubjson

Version:

Opinionated UBJSON encoder/decoder for CloudPSS.

394 lines 12.9 kB
import { UnexpectedEofError, unsupportedType } from './errors.js'; import { decode } from './string-decoder.js'; import { toUint8Array } from './utils.js'; const { defineProperty } = Object; const { fromCharCode } = String; /** 创建数据包装 */ export function DecodeCursor(data, options) { const d = toUint8Array(data); const v = new DataView(d.buffer, d.byteOffset, d.byteLength); return { data: d, view: v, offset: 0, eof() { throw new UnexpectedEofError(); }, options, }; } /** * 读取第一个非 NOOP 的字节 * @returns 返回读取到的字节,如果读取到末尾则返回 undefined */ export function readMarkerOrUndefined(cursor) { let marker; do { marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); return marker; } /** * 读取第一个非 NOOP 的字节 */ export function readMarker(cursor) { let marker; do { marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); if (marker === undefined) return cursor.eof(); return marker; } /** 读取一个大于 0 的整数 */ export function readLength(cursor) { const marker = readMarker(cursor); let length; switch (marker) { case 105 /* constants.INT8 */: length = readInt8Data(cursor); break; case 85 /* constants.UINT8 */: length = readUint8Data(cursor); break; case 73 /* constants.INT16 */: length = readInt16Data(cursor); break; case 108 /* constants.INT32 */: length = readInt32Data(cursor); break; case 76 /* constants.INT64 */: { const l = readInt64Data(cursor); if (l < 0 || l > Number.MAX_SAFE_INTEGER) { throw new Error('Invalid length'); } length = Number(l); break; } default: throw new Error(`Unexpected marker '${fromCharCode(marker)}'(${marker}) for int length`); } if (length < 0) { throw new Error('Invalid length'); } return length; } /** readInt8Data */ export function readInt8Data(cursor) { try { return cursor.view.getInt8(cursor.offset++); } catch { return cursor.eof(); } } /** readUint8Data */ export function readUint8Data(cursor) { const result = cursor.data[cursor.offset++]; if (result === undefined) return cursor.eof(); return result; } /** readInt16Data */ export function readInt16Data(cursor) { try { const result = cursor.view.getInt16(cursor.offset); cursor.offset += 2; return result; } catch { return cursor.eof(); } } /** readInt32Data */ export function readInt32Data(cursor) { try { const result = cursor.view.getInt32(cursor.offset); cursor.offset += 4; return result; } catch { return cursor.eof(); } } /** readInt64Data */ export function readInt64Data(cursor) { try { const result = cursor.view.getBigInt64(cursor.offset); cursor.offset += 8; return result; } catch { return cursor.eof(); } } /** readFloat32Data */ export function readFloat32Data(cursor) { try { const result = cursor.view.getFloat32(cursor.offset); cursor.offset += 4; return result; } catch { return cursor.eof(); } } /** readFloat64Data */ export function readFloat64Data(cursor) { try { const result = cursor.view.getFloat64(cursor.offset); cursor.offset += 8; return result; } catch { return cursor.eof(); } } /** 读取数据 */ export function read(cursor) { const marker = readMarker(cursor); return readData(cursor, marker); } /** 处理 `__proto__` */ export function protoAction(cursor, obj, value) { if (cursor.options?.protoAction === 'error') { throw new Error('Unexpected "__proto__"'); } else if (cursor.options?.protoAction === 'allow') { defineProperty(obj, '__proto__', { value, enumerable: true, configurable: true, writable: true, }); } } /** 处理 `constructor` */ export function constructorAction(cursor, obj, value) { if (cursor.options?.constructorAction === 'error') { throw new Error('Unexpected "constructor"'); } else if (cursor.options?.constructorAction === 'remove') { return; } // eslint-disable-next-line @typescript-eslint/dot-notation obj['constructor'] = value; } /** 读取优化对象数据 */ function readObjectOptimizedData(cursor, marker) { const { count, type } = marker; const object = {}; for (let i = 0; i < count; i++) { const key = readKey(cursor); const value = readData(cursor, type ?? readMarker(cursor)); if (key === '__proto__') { protoAction(cursor, object, value); continue; } if (key === 'constructor') { constructorAction(cursor, object, value); continue; } object[key] = value; } return object; } /** 根据标签读取后续数据 */ export function readData(cursor, marker) { // 按照出现频率排序 switch (marker) { case 83 /* constants.STRING */: { const length = readLength(cursor); const begin = cursor.offset; const end = begin + length; cursor.offset = end; const { data } = cursor; if (end > data.length) cursor.eof(); return decode(data, begin, end); } case 123 /* constants.OBJECT */: { const markers = readOptimizedFormatMarkers(cursor); if (markers == null) { // 直到 '}' const object = {}; while (readMarker(cursor) !== 125 /* constants.OBJECT_END */) { cursor.offset--; const key = readKey(cursor); const value = read(cursor); if (key === '__proto__') { protoAction(cursor, object, value); continue; } if (key === 'constructor') { constructorAction(cursor, object, value); continue; } object[key] = value; } return object; } return readObjectOptimizedData(cursor, markers); } case 91 /* constants.ARRAY */: { const markers = readOptimizedFormatMarkers(cursor); if (markers == null) { const array = []; for (;;) { const marker = readMarker(cursor); // 直到 ']' if (marker === 93 /* constants.ARRAY_END */) break; array.push(readData(cursor, marker)); } return array; } const { count, type } = markers; switch (type) { case 85 /* constants.UINT8 */: try { const buf = new Uint8Array(cursor.data.buffer, cursor.data.byteOffset + cursor.offset, count).slice(); cursor.offset += count; return buf; } catch { return cursor.eof(); } case 105 /* constants.INT8 */: try { const buf = new Int8Array(cursor.data.buffer, cursor.data.byteOffset + cursor.offset, count).slice(); cursor.offset += count; return buf; } catch { return cursor.eof(); } case 73 /* constants.INT16 */: { const result = new Int16Array(count); for (let i = 0; i < count; i++) { result[i] = readInt16Data(cursor); } return result; } case 108 /* constants.INT32 */: { const result = new Int32Array(count); for (let i = 0; i < count; i++) { result[i] = readInt32Data(cursor); } return result; } case 100 /* constants.FLOAT32 */: { const result = new Float32Array(count); for (let i = 0; i < count; i++) { result[i] = readFloat32Data(cursor); } return result; } case 68 /* constants.FLOAT64 */: { const result = new Float64Array(count); for (let i = 0; i < count; i++) { result[i] = readFloat64Data(cursor); } return result; } case 76 /* constants.INT64 */: { const result = new BigInt64Array(count); for (let i = 0; i < count; i++) { result[i] = readInt64Data(cursor); } return result; } case 90 /* constants.NULL */: return Array.from({ length: count }).fill(null); case 84 /* constants.TRUE */: return Array.from({ length: count }).fill(true); case 70 /* constants.FALSE */: return Array.from({ length: count }).fill(false); case undefined: default: break; } const array = []; array.length = count; for (let i = 0; i < count; i++) { array[i] = type === undefined ? read(cursor) : readData(cursor, type); } return array; } case 68 /* constants.FLOAT64 */: return readFloat64Data(cursor); case 85 /* constants.UINT8 */: return readUint8Data(cursor); case 73 /* constants.INT16 */: return readInt16Data(cursor); case 100 /* constants.FLOAT32 */: return readFloat32Data(cursor); case 67 /* constants.CHAR */: return fromCharCode(readUint8Data(cursor)); case 108 /* constants.INT32 */: return readInt32Data(cursor); case 105 /* constants.INT8 */: return readInt8Data(cursor); case 90 /* constants.NULL */: return null; case 84 /* constants.TRUE */: return true; case 70 /* constants.FALSE */: return false; case 76 /* constants.INT64 */: { const n = readInt64Data(cursor); if (n < Number.MIN_SAFE_INTEGER || n > Number.MAX_SAFE_INTEGER) { return n; } return Number(n); } case 72 /* constants.HIGH_PRECISION_NUMBER */: { const length = readLength(cursor); try { const _buffer = new Uint8Array(cursor.data.buffer, cursor.offset, length).slice(); cursor.offset += length; // return buffer; } catch { return cursor.eof(); } unsupportedType('high precision number'); } } if (typeof marker != 'number') return marker; throw new Error(`Unexpected marker '${fromCharCode(marker)}'(${marker})`); } /** readKey */ export function readKey(cursor) { const length = readLength(cursor); const begin = cursor.offset; const end = begin + length; cursor.offset = end; const { data } = cursor; if (end > data.length) cursor.eof(); return decode(data, begin, end); } /** 读取 Optimized Format 数据 */ export function readOptimizedFormatMarkers(cursor) { let type; let count; switch (readMarker(cursor)) { case 36 /* constants.TYPE_MARKER */: type = readMarker(cursor); if (readMarker(cursor) !== 35 /* constants.COUNT_MARKER */) { throw new Error('Expected count marker'); } /* fall through */ case 35 /* constants.COUNT_MARKER */: count = readLength(cursor); break; default: // 不是 '$' 或 '#',回溯 cursor.offset--; return undefined; } return { type, count }; } //# sourceMappingURL=decode.js.map