UNPKG

@cloudpss/ubjson

Version:

222 lines (210 loc) 6.94 kB
const CHUNK_SIZE = 0x1000; const REPLACE_CHAR = 0xfffd; const { fromCharCode } = String; /** 解码 */ export function jsDecode(bytes: Uint8Array, begin: number, end: number): string { let offset = begin; const units: number[] = []; let result = ''; while (offset < end) { const byte1 = bytes[offset++]!; if ((byte1 & 0x80) === 0) { // 1 byte units.push(byte1); } else if ((byte1 & 0xe0) === 0xc0) { // 2 bytes const byte2 = bytes[offset++]! & 0x3f; units.push(((byte1 & 0x1f) << 6) | byte2); } else if ((byte1 & 0xf0) === 0xe0) { // 3 bytes const byte2 = bytes[offset++]! & 0x3f; const byte3 = bytes[offset++]! & 0x3f; units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); } else if ((byte1 & 0xf8) === 0xf0) { // 4 bytes const byte2 = bytes[offset++]! & 0x3f; const byte3 = bytes[offset++]! & 0x3f; const byte4 = bytes[offset++]! & 0x3f; let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; if (unit > 0xffff) { unit -= 0x1_0000; units.push(((unit >>> 10) & 0x3ff) | 0xd800); unit = 0xdc00 | (unit & 0x3ff); } units.push(unit); } else { units.push(REPLACE_CHAR); } if (units.length >= CHUNK_SIZE) { result += fromCharCode(...units); units.length = 0; } } if (units.length > 0) { result += fromCharCode(...units); } return result; } /** 解码 Ascii */ export function longStringInJS(buf: Uint8Array, begin: number, length: number): string | undefined { const bytes = []; for (let i = 0; i < length; i++) { const byte = buf[begin++]!; if (byte & 0x80) { return; } bytes.push(byte); } return fromCharCode(...bytes); } /** 解码 Ascii */ export function shortStringInJS(buf: Uint8Array, begin: number, length: number): string | undefined { if (length < 4) { if (length < 2) { if (length === 0) return ''; const a = buf[begin]!; if ((a & 0x80) > 0) { return; } return fromCharCode(a); } const a = buf[begin++]!; const b = buf[begin++]!; if ((a & 0x80) > 0 || (b & 0x80) > 0) { return; } if (length < 3) return fromCharCode(a, b); const c = buf[begin++]!; if ((c & 0x80) > 0) { return; } return fromCharCode(a, b, c); } const a = buf[begin++]!; const b = buf[begin++]!; const c = buf[begin++]!; const d = buf[begin++]!; if ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) { return; } if (length < 6) { if (length === 4) return fromCharCode(a, b, c, d); const e = buf[begin++]!; if ((e & 0x80) > 0) { return; } return fromCharCode(a, b, c, d, e); } const e = buf[begin++]!; const f = buf[begin++]!; if ((e & 0x80) > 0 || (f & 0x80) > 0) { return; } if (length < 8) { if (length < 7) return fromCharCode(a, b, c, d, e, f); const g = buf[begin++]!; if ((g & 0x80) > 0) { return; } return fromCharCode(a, b, c, d, e, f, g); } const g = buf[begin++]!; const h = buf[begin++]!; if ((g & 0x80) > 0 || (h & 0x80) > 0) { return; } if (length < 10) { if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h); const i = buf[begin++]!; if ((i & 0x80) > 0) { return; } return fromCharCode(a, b, c, d, e, f, g, h, i); } const i = buf[begin++]!; const j = buf[begin++]!; if ((i & 0x80) > 0 || (j & 0x80) > 0) { return; } if (length < 12) { if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j); const k = buf[begin++]!; if ((k & 0x80) > 0) { return; } return fromCharCode(a, b, c, d, e, f, g, h, i, j, k); } const k = buf[begin++]!; const l = buf[begin++]!; if ((k & 0x80) > 0 || (l & 0x80) > 0) { return; } if (length < 14) { if (length === 12) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l); const m = buf[begin++]!; if ((m & 0x80) > 0) { begin -= 13; return; } return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m); } const m = buf[begin++]!; const n = buf[begin++]!; if ((m & 0x80) > 0 || (n & 0x80) > 0) { return; } if (length < 15) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n); const o = buf[begin++]!; if ((o & 0x80) > 0) { return; } return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); } let TEXT_DECODER: TextDecoder | null; /** 解码 */ export function nativeDecode(data: Uint8Array, begin: number, end: number): string { return TEXT_DECODER!.decode(data.subarray(begin, end)); } /** Undocumented */ type BufferUndocumented = Buffer & { utf8Slice: (this: Uint8Array, start: number, end: number) => string; }; let utf8Slice: ((this: Uint8Array, start: number, end: number) => string) | null; /** 解码 */ export function nodeDecode(data: Uint8Array, begin: number, end: number): string { return utf8Slice!.call(data, begin, end); } let longDecode: (data: Uint8Array, begin: number, end: number) => string = nativeDecode; /** * 默认解码器阈值 * @see /benchmark/string-decoder.js */ const DEFAULT_TEXT_DECODER_THRESHOLD = 16; /** 字符串解码,无缓存 */ export function decode(data: Uint8Array, begin: number, end: number): string { const length = end - begin; if (length < 16) { const result = shortStringInJS(data, begin, length); if (result != null) return result; } // 只有小字符串有优化价值 if (length < DEFAULT_TEXT_DECODER_THRESHOLD) { // if (length < 32) { // const result = longStringInJS(data, begin, length); // if (result != null) return result; // } // 为小字符串优化 return jsDecode(data, begin, end); } // 使用系统解码 return longDecode(data, begin, end); } /** 重设环境 */ export function resetEnv(): void { TEXT_DECODER = typeof TextDecoder == 'function' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: false }) : null; const hasBuffer = typeof Buffer == 'function'; utf8Slice = hasBuffer ? (Buffer.prototype as BufferUndocumented).utf8Slice : null; longDecode = typeof utf8Slice == 'function' ? nodeDecode : TEXT_DECODER ? nativeDecode : jsDecode; } resetEnv();