UNPKG

@cloudpss/ubjson

Version:

Opinionated UBJSON encoder/decoder for CloudPSS.

591 lines 23.3 kB
import { protoAction, constructorAction } from './decode.js'; import { unsupportedType } from './errors.js'; import { decode } from './string-decoder.js'; import { toUint8Array } from './utils.js'; 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, size: v.byteLength, offset: 0, options, }; } /** * 读取第一个非 NOOP 的字节 */ export function* readMarker(cursor) { let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); return marker; } /** 读取一个大于 0 的整数 */ export function* readLength(cursor) { let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); let length; switch (marker) { case 105 /* constants.INT8 */: if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } length = cursor.view.getInt8(cursor.offset++); break; case 85 /* constants.UINT8 */: length = yield* readUint8Data(cursor); break; case 73 /* constants.INT16 */: length = yield* readInt16Data(cursor); break; case 108 /* constants.INT32 */: length = yield* readInt32Data(cursor); break; case 76 /* constants.INT64 */: { const l = yield* 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) { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } return cursor.view.getInt8(cursor.offset++); } /** readUint8Data */ export function* readUint8Data(cursor) { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } return cursor.data[cursor.offset++]; } /** readInt16Data */ export function* readInt16Data(cursor) { if (cursor.offset + 2 > cursor.size) { yield cursor.offset - cursor.size + 2; } const value = cursor.view.getInt16(cursor.offset); cursor.offset += 2; return value; } /** readInt32Data */ export function* readInt32Data(cursor) { if (cursor.offset + 4 > cursor.size) { yield cursor.offset - cursor.size + 4; } const value = cursor.view.getInt32(cursor.offset); cursor.offset += 4; return value; } /** readInt64Data */ export function* readInt64Data(cursor) { if (cursor.offset + 8 > cursor.size) { yield cursor.offset - cursor.size + 8; } const value = cursor.view.getBigInt64(cursor.offset); cursor.offset += 8; return value; } /** readFloat32Data */ export function* readFloat32Data(cursor) { if (cursor.offset + 4 > cursor.size) { yield cursor.offset - cursor.size + 4; } const value = cursor.view.getFloat32(cursor.offset); cursor.offset += 4; return value; } /** readFloat64Data */ export function* readFloat64Data(cursor) { if (cursor.offset + 8 > cursor.size) { yield cursor.offset - cursor.size + 8; } const value = cursor.view.getFloat64(cursor.offset); cursor.offset += 8; return value; } /** 读取数据 */ export function* read(cursor) { let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); return yield* readData(cursor, marker); } /** 读取优化对象数据 */ function* readObjectOptimizedData(cursor, marker) { const { count, type } = marker; const object = {}; for (let i = 0; i < count; i++) { const key = yield* readKey(cursor); const value = yield* readData(cursor, type ?? (yield* 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 */: { let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); let length; switch (marker) { case 105 /* constants.INT8 */: if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } length = cursor.view.getInt8(cursor.offset++); break; case 85 /* constants.UINT8 */: length = yield* readUint8Data(cursor); break; case 73 /* constants.INT16 */: length = yield* readInt16Data(cursor); break; case 108 /* constants.INT32 */: length = yield* readInt32Data(cursor); break; case 76 /* constants.INT64 */: { const l = yield* 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'); } if (cursor.offset + length > cursor.size) { yield cursor.offset - cursor.size + length; } const begin = cursor.offset; const end = begin + length; cursor.offset = end; const { data } = cursor; return decode(data, begin, end); } case 123 /* constants.OBJECT */: { let type; let count; let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); switch (marker) { case 36 /* constants.TYPE_MARKER */: { do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } type = cursor.data[cursor.offset++]; } while (type === 78 /* constants.NO_OP */); let marker2; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker2 = cursor.data[cursor.offset++]; } while (marker2 === 78 /* constants.NO_OP */); if (marker2 !== 35 /* constants.COUNT_MARKER */) { throw new Error('Expected count marker'); } } /* fall through */ case 35 /* constants.COUNT_MARKER */: { count = yield* readLength(cursor); break; } default: { // 不是 '$' 或 '#' // 直到 '}' const object = {}; for (;;) { while (marker === 78 /* constants.NO_OP */) { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } if (marker === 125 /* constants.OBJECT_END */) break; let length; switch (marker) { case 105 /* constants.INT8 */: if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } length = cursor.view.getInt8(cursor.offset++); break; case 85 /* constants.UINT8 */: length = yield* readUint8Data(cursor); break; case 73 /* constants.INT16 */: length = yield* readInt16Data(cursor); break; case 108 /* constants.INT32 */: length = yield* readInt32Data(cursor); break; case 76 /* constants.INT64 */: { const l = yield* 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'); } if (cursor.offset + length > cursor.size) { yield cursor.offset - cursor.size + length; } marker = 78 /* constants.NO_OP */; const begin = cursor.offset; const end = begin + length; cursor.offset = end; const { data } = cursor; const key = decode(data, begin, end); let valueMarker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } valueMarker = cursor.data[cursor.offset++]; } while (valueMarker === 78 /* constants.NO_OP */); const value = yield* readData(cursor, valueMarker); if (key === '__proto__') { protoAction(cursor, object, value); continue; } if (key === 'constructor') { constructorAction(cursor, object, value); continue; } object[key] = value; } return object; } } return yield* readObjectOptimizedData(cursor, { type, count }); } case 91 /* constants.ARRAY */: { let type; let count; let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); switch (marker) { case 36 /* constants.TYPE_MARKER */: { do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } type = cursor.data[cursor.offset++]; } while (type === 78 /* constants.NO_OP */); let marker2; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker2 = cursor.data[cursor.offset++]; } while (marker2 === 78 /* constants.NO_OP */); if (marker2 !== 35 /* constants.COUNT_MARKER */) { throw new Error('Expected count marker'); } } /* fall through */ case 35 /* constants.COUNT_MARKER */: { count = yield* readLength(cursor); break; } default: { // 不是 '$' 或 '#' const array = []; for (;;) { while (marker === 78 /* constants.NO_OP */) { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } // 直到 ']' if (marker === 93 /* constants.ARRAY_END */) break; array.push(yield* readData(cursor, marker)); marker = 78 /* constants.NO_OP */; } return array; } } switch (type) { case 85 /* constants.UINT8 */: { if (cursor.offset + count > cursor.size) { yield cursor.offset - cursor.size + count; } const buf = new Uint8Array(cursor.data.buffer, cursor.data.byteOffset + cursor.offset, count).slice(); cursor.offset += count; return buf; } case 105 /* constants.INT8 */: { if (cursor.offset + count > cursor.size) { yield cursor.offset - cursor.size + count; } const buf = new Int8Array(cursor.data.buffer, cursor.data.byteOffset + cursor.offset, count).slice(); cursor.offset += count; return buf; } case 73 /* constants.INT16 */: { if (cursor.offset + count * 2 > cursor.size) { yield cursor.offset - cursor.size + count * 2; } const result = new Int16Array(count); for (let i = 0; i < count; i++) { result[i] = yield* readInt16Data(cursor); } return result; } case 108 /* constants.INT32 */: { if (cursor.offset + count * 4 > cursor.size) { yield cursor.offset - cursor.size + count * 4; } const result = new Int32Array(count); for (let i = 0; i < count; i++) { result[i] = yield* readInt32Data(cursor); } return result; } case 100 /* constants.FLOAT32 */: { if (cursor.offset + count * 4 > cursor.size) { yield cursor.offset - cursor.size + count * 4; } const result = new Float32Array(count); for (let i = 0; i < count; i++) { result[i] = yield* readFloat32Data(cursor); } return result; } case 68 /* constants.FLOAT64 */: { if (cursor.offset + count * 8 > cursor.size) { yield cursor.offset - cursor.size + count * 8; } const result = new Float64Array(count); for (let i = 0; i < count; i++) { result[i] = yield* readFloat64Data(cursor); } return result; } case 76 /* constants.INT64 */: { if (cursor.offset + count * 8 > cursor.size) { yield cursor.offset - cursor.size + count * 8; } const result = new BigInt64Array(count); for (let i = 0; i < count; i++) { result[i] = yield* 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 ? yield* read(cursor) : yield* readData(cursor, type); } return array; } case 68 /* constants.FLOAT64 */: { if (cursor.offset + 8 > cursor.size) { yield cursor.offset - cursor.size + 8; } const value = cursor.view.getFloat64(cursor.offset); cursor.offset += 8; return value; } case 85 /* constants.UINT8 */: { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } return cursor.data[cursor.offset++]; } case 73 /* constants.INT16 */: { if (cursor.offset + 2 > cursor.size) { yield cursor.offset - cursor.size + 2; } const value = cursor.view.getInt16(cursor.offset); cursor.offset += 2; return value; } case 100 /* constants.FLOAT32 */: { if (cursor.offset + 4 > cursor.size) { yield cursor.offset - cursor.size + 4; } const value = cursor.view.getFloat32(cursor.offset); cursor.offset += 4; return value; } case 67 /* constants.CHAR */: { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } return fromCharCode(cursor.data[cursor.offset++]); } case 108 /* constants.INT32 */: { if (cursor.offset + 4 > cursor.size) { yield cursor.offset - cursor.size + 4; } const value = cursor.view.getInt32(cursor.offset); cursor.offset += 4; return value; } case 105 /* constants.INT8 */: { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } return cursor.view.getInt8(cursor.offset++); } case 90 /* constants.NULL */: return null; case 84 /* constants.TRUE */: return true; case 70 /* constants.FALSE */: return false; case 76 /* constants.INT64 */: { if (cursor.offset + 8 > cursor.size) { yield cursor.offset - cursor.size + 8; } const value = cursor.view.getBigInt64(cursor.offset); cursor.offset += 8; if (value < Number.MIN_SAFE_INTEGER || value > Number.MAX_SAFE_INTEGER) { return value; } return Number(value); } case 72 /* constants.HIGH_PRECISION_NUMBER */: { const length = yield* readLength(cursor); if (cursor.offset + length > cursor.size) { yield cursor.offset - cursor.size + length; } const begin = cursor.offset; const _buffer = new Uint8Array(cursor.data.buffer, begin, length).slice(); cursor.offset = begin + length; // return _buffer unsupportedType('high precision number'); } } throw new Error(`Unexpected marker '${fromCharCode(marker)}'(${marker})`); } /** readKey */ export function* readKey(cursor) { let marker; do { if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } marker = cursor.data[cursor.offset++]; } while (marker === 78 /* constants.NO_OP */); let length; switch (marker) { case 105 /* constants.INT8 */: if (cursor.offset + 1 > cursor.size) { yield cursor.offset - cursor.size + 1; } length = cursor.view.getInt8(cursor.offset++); break; case 85 /* constants.UINT8 */: length = yield* readUint8Data(cursor); break; case 73 /* constants.INT16 */: length = yield* readInt16Data(cursor); break; case 108 /* constants.INT32 */: length = yield* readInt32Data(cursor); break; case 76 /* constants.INT64 */: { const l = yield* 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'); } if (cursor.offset + length > cursor.size) { yield cursor.offset - cursor.size + length; } const begin = cursor.offset; const end = begin + length; cursor.offset = end; const { data } = cursor; return decode(data, begin, end); } //# sourceMappingURL=decode-ae.js.map