@cloudpss/ubjson
Version:
Opinionated UBJSON encoder/decoder for CloudPSS.
591 lines • 23.3 kB
JavaScript
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