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