From de54ab53a5df3b857975094ce4c59d760240a6d6 Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Apr 2024 13:17:22 +0200 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=F0=9F=90=9B=20use=20latest=20json-p?= =?UTF-8?q?ack=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/fsa-to-node/json.ts | 4 +- src/json-joy/json-pack/JsonPackExtension.ts | 11 - src/json-joy/json-pack/JsonPackValue.ts | 13 - src/json-joy/json-pack/cbor/CborDecoder.ts | 408 ----------- .../json-pack/cbor/CborDecoderBase.ts | 349 ---------- src/json-joy/json-pack/cbor/CborEncoder.ts | 67 -- .../json-pack/cbor/CborEncoderFast.ts | 333 --------- src/json-joy/json-pack/cbor/constants.ts | 42 -- src/json-joy/json-pack/cbor/types.ts | 1 - src/json-joy/json-pack/json/JsonDecoder.ts | 644 ------------------ src/json-joy/json-pack/json/JsonEncoder.ts | 238 ------- src/json-joy/json-pack/types.ts | 57 -- src/snapshot/binary.ts | 6 +- src/snapshot/json.ts | 4 +- yarn.lock | 32 + 16 files changed, 41 insertions(+), 2171 deletions(-) delete mode 100644 src/json-joy/json-pack/JsonPackExtension.ts delete mode 100644 src/json-joy/json-pack/JsonPackValue.ts delete mode 100644 src/json-joy/json-pack/cbor/CborDecoder.ts delete mode 100644 src/json-joy/json-pack/cbor/CborDecoderBase.ts delete mode 100644 src/json-joy/json-pack/cbor/CborEncoder.ts delete mode 100644 src/json-joy/json-pack/cbor/CborEncoderFast.ts delete mode 100644 src/json-joy/json-pack/cbor/constants.ts delete mode 100644 src/json-joy/json-pack/cbor/types.ts delete mode 100644 src/json-joy/json-pack/json/JsonDecoder.ts delete mode 100644 src/json-joy/json-pack/json/JsonEncoder.ts delete mode 100644 src/json-joy/json-pack/types.ts diff --git a/package.json b/package.json index 9080d53e1..d0d4a76c9 100644 --- a/package.json +++ b/package.json @@ -124,6 +124,7 @@ } }, "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.2", "tslib": "^2.0.0" }, "devDependencies": { @@ -131,8 +132,8 @@ "@semantic-release/git": "^10.0.1", "@semantic-release/npm": "^9.0.1", "@types/jest": "^29.0.0", - "@types/node": "^10.17.60", "@types/mime": "^3.0.0", + "@types/node": "^10.17.60", "app-root-path": "^3.1.0", "assert": "^2.0.0", "buffer": "^6.0.3", diff --git a/src/fsa-to-node/json.ts b/src/fsa-to-node/json.ts index 8216404f1..0f9a5e492 100644 --- a/src/fsa-to-node/json.ts +++ b/src/fsa-to-node/json.ts @@ -1,5 +1,5 @@ -import { CborEncoder } from '../json-joy/json-pack/cbor/CborEncoder'; -import { CborDecoder } from '../json-joy/json-pack/cbor/CborDecoder'; +import { CborEncoder } from '@jsonjoy.com/json-pack/lib/cbor/CborEncoder'; +import { CborDecoder } from '@jsonjoy.com/json-pack/lib/cbor/CborDecoder'; export const encoder = new CborEncoder(); export const decoder = new CborDecoder(); diff --git a/src/json-joy/json-pack/JsonPackExtension.ts b/src/json-joy/json-pack/JsonPackExtension.ts deleted file mode 100644 index 81ab8bbb7..000000000 --- a/src/json-joy/json-pack/JsonPackExtension.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * A wrapping for MessagePack extension or CBOR tag value. When encoder - * encounters {@link JsonPackExtension} it will encode it as a MessagePack - * extension or CBOR tag. Likewise, the decoder will - * decode extensions into {@link JsonPackExtension}. - * - * @category Value - */ -export class JsonPackExtension { - constructor(public readonly tag: number, public readonly val: T) {} -} diff --git a/src/json-joy/json-pack/JsonPackValue.ts b/src/json-joy/json-pack/JsonPackValue.ts deleted file mode 100644 index cdf7f41de..000000000 --- a/src/json-joy/json-pack/JsonPackValue.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Use this wrapper is you have a pre-encoded MessagePack or CBOR value and you would - * like to dump it into a the document as-is. The contents of `buf` will - * be written as is to the document. - * - * It also serves as CBOR simple value container. In which case the type of value - * `val` field is "number". - * - * @category Value - */ -export class JsonPackValue { - constructor(public readonly val: T) {} -} diff --git a/src/json-joy/json-pack/cbor/CborDecoder.ts b/src/json-joy/json-pack/cbor/CborDecoder.ts deleted file mode 100644 index 64b925799..000000000 --- a/src/json-joy/json-pack/cbor/CborDecoder.ts +++ /dev/null @@ -1,408 +0,0 @@ -import {CONST, ERROR, MAJOR} from './constants'; -import {CborDecoderBase} from './CborDecoderBase'; -import {JsonPackValue} from '../JsonPackValue'; -import type {Path} from '../../json-pointer'; -import type {IReader, IReaderResettable} from '../../util/buffers'; - -export class CborDecoder< - R extends IReader & IReaderResettable = IReader & IReaderResettable, -> extends CborDecoderBase { - // -------------------------------------------------------------- Map reading - - public readAsMap(): Map { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - switch (major) { - case MAJOR.MAP: - return this.readMap(minor); - default: - throw ERROR.UNEXPECTED_MAJOR; - } - } - - public readMap(minor: number): Map { - const length = this.readMinorLen(minor); - if (length >= 0) return this.readMapRaw(length); - else return this.readMapIndef(); - } - - public readMapRaw(length: number): Map { - const map: Map = new Map(); - for (let i = 0; i < length; i++) { - const key = this.val(); - const value = this.val(); - map.set(key, value); - } - return map; - } - - public readMapIndef(): Map { - const map: Map = new Map(); - while (this.reader.peak() !== CONST.END) { - const key = this.val(); - if (this.reader.peak() === CONST.END) throw ERROR.UNEXPECTED_OBJ_BREAK; - const value = this.val(); - map.set(key, value); - } - this.reader.x++; - return map; - } - - // ----------------------------------------------------------- Value skipping - - public skipN(n: number): void { - for (let i = 0; i < n; i++) this.skipAny(); - } - public skipAny(): void { - this.skipAnyRaw(this.reader.u8()); - } - - public skipAnyRaw(octet: number): void { - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - switch (major) { - case MAJOR.UIN: - case MAJOR.NIN: - this.skipUNint(minor); - break; - case MAJOR.BIN: - this.skipBin(minor); - break; - case MAJOR.STR: - this.skipStr(minor); - break; - case MAJOR.ARR: - this.skipArr(minor); - break; - case MAJOR.MAP: - this.skipObj(minor); - break; - case MAJOR.TKN: - this.skipTkn(minor); - break; - case MAJOR.TAG: - this.skipTag(minor); - break; - } - } - - public skipMinorLen(minor: number): number { - if (minor <= 23) return minor; - switch (minor) { - case 24: - return this.reader.u8(); - case 25: - return this.reader.u16(); - case 26: - return this.reader.u32(); - case 27: - return Number(this.reader.u64()); - case 31: - return -1; - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - // --------------------------------------------------------- Integer skipping - - public skipUNint(minor: number): void { - if (minor <= 23) return; - switch (minor) { - case 24: - return this.reader.skip(1); - case 25: - return this.reader.skip(2); - case 26: - return this.reader.skip(4); - case 27: - return this.reader.skip(8); - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - // ---------------------------------------------------------- Binary skipping - - public skipBin(minor: number): void { - const length = this.skipMinorLen(minor); - if (length >= 0) this.reader.skip(length); - else { - while (this.reader.peak() !== CONST.END) this.skipBinChunk(); - this.reader.x++; - } - } - - public skipBinChunk(): void { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.BIN) throw ERROR.UNEXPECTED_BIN_CHUNK_MAJOR; - if (minor > 27) throw ERROR.UNEXPECTED_BIN_CHUNK_MINOR; - this.skipBin(minor); - } - - // ---------------------------------------------------------- String skipping - - public skipStr(minor: number): void { - const length = this.skipMinorLen(minor); - if (length >= 0) this.reader.skip(length); - else { - while (this.reader.peak() !== CONST.END) this.skipStrChunk(); - this.reader.x++; - } - } - - public skipStrChunk(): void { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.STR) throw ERROR.UNEXPECTED_STR_CHUNK_MAJOR; - if (minor > 27) throw ERROR.UNEXPECTED_STR_CHUNK_MINOR; - this.skipStr(minor); - } - - // ----------------------------------------------------------- Array skipping - - public skipArr(minor: number): void { - const length = this.skipMinorLen(minor); - if (length >= 0) this.skipN(length); - else { - while (this.reader.peak() !== CONST.END) this.skipAny(); - this.reader.x++; - } - } - - // ---------------------------------------------------------- Object skipping - - public skipObj(minor: number): void { - const length = this.readMinorLen(minor); - if (length >= 0) return this.skipN(length * 2); - else { - while (this.reader.peak() !== CONST.END) { - this.skipAny(); - if (this.reader.peak() === CONST.END) throw ERROR.UNEXPECTED_OBJ_BREAK; - this.skipAny(); - } - this.reader.x++; - } - } - - // ------------------------------------------------------------- Tag skipping - - public skipTag(minor: number): void { - const length = this.skipMinorLen(minor); - if (length < 0) throw ERROR.UNEXPECTED_MINOR; - this.skipAny(); - } - - // ----------------------------------------------------------- Token skipping - - public skipTkn(minor: number): void { - switch (minor) { - case 0xf8 & CONST.MINOR_MASK: - this.reader.skip(1); - return; - case 0xf9 & CONST.MINOR_MASK: - this.reader.skip(2); - return; - case 0xfa & CONST.MINOR_MASK: - this.reader.skip(4); - return; - case 0xfb & CONST.MINOR_MASK: - this.reader.skip(8); - return; - } - if (minor <= 23) return; - throw ERROR.UNEXPECTED_MINOR; - } - - // --------------------------------------------------------------- Validation - - /** - * Throws if at given offset in a buffer there is an invalid CBOR value, or - * if the value does not span the exact length specified in `size`. I.e. - * throws if: - * - * - The value is not a valid CBOR value. - * - The value is shorter than `size`. - * - The value is longer than `size`. - * - * @param value Buffer in which to validate CBOR value. - * @param offset Offset at which the value starts. - * @param size Expected size of the value. - */ - public validate(value: Uint8Array, offset: number = 0, size: number = value.length): void { - this.reader.reset(value); - this.reader.x = offset; - const start = offset; - this.skipAny(); - const end = this.reader.x; - if (end - start !== size) throw ERROR.INVALID_SIZE; - } - - // -------------------------------------------- One level reading - any value - - public decodeLevel(value: Uint8Array): unknown { - this.reader.reset(value); - return this.readLevel(); - } - - /** - * Decodes only one level of objects and arrays. Other values are decoded - * completely. - * - * @returns One level of decoded CBOR value. - */ - public readLevel(): unknown { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - switch (major) { - case MAJOR.ARR: - return this.readArrLevel(minor); - case MAJOR.MAP: - return this.readObjLevel(minor); - default: - return super.readAnyRaw(octet); - } - } - - /** - * Decodes primitive values, returns container values as `JsonPackValue`. - * - * @returns A primitive value, or CBOR container value as a blob. - */ - public readPrimitiveOrVal(): unknown | JsonPackValue { - const octet = this.reader.peak(); - const major = octet >> 5; - switch (major) { - case MAJOR.ARR: - case MAJOR.MAP: - return this.readAsValue(); - default: - return this.val(); - } - } - - public readAsValue(): JsonPackValue { - const reader = this.reader; - const start = reader.x; - this.skipAny(); - const end = reader.x; - return new JsonPackValue(reader.uint8.subarray(start, end)); - } - - // ----------------------------------------------- One level reading - object - - public readObjLevel(minor: number): Record { - const length = this.readMinorLen(minor); - if (length >= 0) return this.readObjRawLevel(length); - else return this.readObjIndefLevel(); - } - - public readObjRawLevel(length: number): Record { - const obj: Record = {}; - for (let i = 0; i < length; i++) { - const key = this.key(); - const value = this.readPrimitiveOrVal(); - obj[key] = value; - } - return obj; - } - - public readObjIndefLevel(): Record { - const obj: Record = {}; - while (this.reader.peak() !== CONST.END) { - const key = this.key(); - if (this.reader.peak() === CONST.END) throw ERROR.UNEXPECTED_OBJ_BREAK; - const value = this.readPrimitiveOrVal(); - obj[key] = value; - } - this.reader.x++; - return obj; - } - - // ------------------------------------------------ One level reading - array - - public readArrLevel(minor: number): unknown[] { - const length = this.readMinorLen(minor); - if (length >= 0) return this.readArrRawLevel(length); - return this.readArrIndefLevel(); - } - - public readArrRawLevel(length: number): unknown[] { - const arr: unknown[] = []; - for (let i = 0; i < length; i++) arr.push(this.readPrimitiveOrVal()); - return arr; - } - - public readArrIndefLevel(): unknown[] { - const arr: unknown[] = []; - while (this.reader.peak() !== CONST.END) arr.push(this.readPrimitiveOrVal()); - this.reader.x++; - return arr; - } - - // ---------------------------------------------------------- Shallow reading - - public readHdr(expectedMajor: number): number { - const octet = this.reader.u8(); - const major = octet >> 5; - if (major !== expectedMajor) throw ERROR.UNEXPECTED_MAJOR; - const minor = octet & CONST.MINOR_MASK; - if (minor < 24) return minor; - switch (minor) { - case 24: - return this.reader.u8(); - case 25: - return this.reader.u16(); - case 26: - return this.reader.u32(); - case 27: - return Number(this.reader.u64()); - case 31: - return -1; - } - throw ERROR.UNEXPECTED_MINOR; - } - - public readStrHdr(): number { - return this.readHdr(MAJOR.STR); - } - - public readObjHdr(): number { - return this.readHdr(MAJOR.MAP); - } - - public readArrHdr(): number { - return this.readHdr(MAJOR.ARR); - } - - public findKey(key: string): this { - const size = this.readObjHdr(); - for (let i = 0; i < size; i++) { - const k = this.key(); - if (k === key) return this; - this.skipAny(); - } - throw ERROR.KEY_NOT_FOUND; - } - - public findIndex(index: number): this { - const size = this.readArrHdr(); - if (index >= size) throw ERROR.INDEX_OUT_OF_BOUNDS; - for (let i = 0; i < index; i++) this.skipAny(); - return this; - } - - public find(path: Path): this { - for (let i = 0; i < path.length; i++) { - const segment = path[i]; - if (typeof segment === 'string') this.findKey(segment); - else this.findIndex(segment); - } - return this; - } -} diff --git a/src/json-joy/json-pack/cbor/CborDecoderBase.ts b/src/json-joy/json-pack/cbor/CborDecoderBase.ts deleted file mode 100644 index 3b27a6ea8..000000000 --- a/src/json-joy/json-pack/cbor/CborDecoderBase.ts +++ /dev/null @@ -1,349 +0,0 @@ -import {CONST, ERROR, MAJOR} from './constants'; -import {decodeF16} from '../../util/buffers/f16'; -import {JsonPackExtension} from '../JsonPackExtension'; -import {JsonPackValue} from '../JsonPackValue'; -import {Reader} from '../../util/buffers/Reader'; -import sharedCachedUtf8Decoder from '../../util/buffers/utf8/sharedCachedUtf8Decoder'; -import type {CachedUtf8Decoder} from '../../util/buffers/utf8/CachedUtf8Decoder'; -import type {IReader, IReaderResettable} from '../../util/buffers'; -import type {BinaryJsonDecoder, PackValue} from '../types'; - -export class CborDecoderBase - implements BinaryJsonDecoder -{ - public constructor( - public reader: R = new Reader() as any, - protected readonly keyDecoder: CachedUtf8Decoder = sharedCachedUtf8Decoder, - ) {} - - public read(uint8: Uint8Array): PackValue { - this.reader.reset(uint8); - return this.val() as PackValue; - } - - /** @deprecated */ - public decode(uint8: Uint8Array): unknown { - this.reader.reset(uint8); - return this.val(); - } - - // -------------------------------------------------------- Any value reading - - public val(): unknown { - const reader = this.reader; - const octet = reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major < MAJOR.ARR) { - if (major < MAJOR.BIN) return major === MAJOR.UIN ? this.readUint(minor) : this.readNint(minor); - else return major === MAJOR.BIN ? this.readBin(minor) : this.readStr(minor); - } else { - if (major < MAJOR.TAG) return major === MAJOR.ARR ? this.readArr(minor) : this.readObj(minor); - else return major === MAJOR.TAG ? this.readTag(minor) : this.readTkn(minor); - } - } - - public readAnyRaw(octet: number): unknown { - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major < MAJOR.ARR) { - if (major < MAJOR.BIN) return major === MAJOR.UIN ? this.readUint(minor) : this.readNint(minor); - else return major === MAJOR.BIN ? this.readBin(minor) : this.readStr(minor); - } else { - if (major < MAJOR.TAG) return major === MAJOR.ARR ? this.readArr(minor) : this.readObj(minor); - else return major === MAJOR.TAG ? this.readTag(minor) : this.readTkn(minor); - } - } - - public readMinorLen(minor: number): number { - if (minor < 24) return minor; - switch (minor) { - case 24: - return this.reader.u8(); - case 25: - return this.reader.u16(); - case 26: - return this.reader.u32(); - case 27: - return Number(this.reader.u64()); - case 31: - return -1; - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - // ----------------------------------------------------- Unsigned int reading - - public readUint(minor: number): number | bigint { - if (minor < 25) { - return minor === 24 ? this.reader.u8() : minor; - } else { - if (minor < 27) { - return minor === 25 ? this.reader.u16() : this.reader.u32(); - } else { - const num = this.reader.u64(); - return num > CONST.MAX_UINT ? num : Number(num); - } - } - } - - // ----------------------------------------------------- Negative int reading - - public readNint(minor: number): number | bigint { - if (minor < 25) { - return minor === 24 ? -this.reader.u8() - 1 : -minor - 1; - } else { - if (minor < 27) { - return minor === 25 ? -this.reader.u16() - 1 : -this.reader.u32() - 1; - } else { - const num = this.reader.u64(); - return num > CONST.MAX_UINT - 1 ? -num - BigInt(1) : -Number(num) - 1; - } - } - } - - // ----------------------------------------------------------- Binary reading - - public readBin(minor: number): Uint8Array { - const reader = this.reader; - if (minor <= 23) return reader.buf(minor); - switch (minor) { - case 24: - return reader.buf(reader.u8()); - case 25: - return reader.buf(reader.u16()); - case 26: - return reader.buf(reader.u32()); - case 27: - return reader.buf(Number(reader.u64())); - case 31: { - let size = 0; - const list: Uint8Array[] = []; - while (this.reader.peak() !== CONST.END) { - const uint8 = this.readBinChunk(); - size += uint8.length; - list.push(uint8); - } - this.reader.x++; - const res = new Uint8Array(size); - let offset = 0; - const length = list.length; - for (let i = 0; i < length; i++) { - const arr = list[i]; - res.set(arr, offset); - offset += arr.length; - } - return res; - } - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - public readBinChunk(): Uint8Array { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.BIN) throw ERROR.UNEXPECTED_BIN_CHUNK_MAJOR; - if (minor > 27) throw ERROR.UNEXPECTED_BIN_CHUNK_MINOR; - return this.readBin(minor); - } - - // ----------------------------------------------------------- String reading - - public readAsStr(): string { - const reader = this.reader; - const octet = reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.STR) throw ERROR.UNEXPECTED_STR_MAJOR; - return this.readStr(minor); - } - - public readStr(minor: number): string { - const reader = this.reader; - if (minor <= 23) return reader.utf8(minor); - switch (minor) { - case 24: - return reader.utf8(reader.u8()); - case 25: - return reader.utf8(reader.u16()); - case 26: - return reader.utf8(reader.u32()); - case 27: - return reader.utf8(Number(reader.u64())); - case 31: { - let str = ''; - while (reader.peak() !== CONST.END) str += this.readStrChunk(); - this.reader.x++; - return str; - } - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - public readStrLen(minor: number): number { - if (minor <= 23) return minor; - switch (minor) { - case 24: - return this.reader.u8(); - case 25: - return this.reader.u16(); - case 26: - return this.reader.u32(); - case 27: - return Number(this.reader.u64()); - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - public readStrChunk(): string { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.STR) throw ERROR.UNEXPECTED_STR_CHUNK_MAJOR; - if (minor > 27) throw ERROR.UNEXPECTED_STR_CHUNK_MINOR; - return this.readStr(minor); - } - - // ------------------------------------------------------------ Array reading - - public readArr(minor: number): unknown[] { - const length = this.readMinorLen(minor); - if (length >= 0) return this.readArrRaw(length); - return this.readArrIndef(); - } - - public readArrRaw(length: number): unknown[] { - const arr: unknown[] = []; - for (let i = 0; i < length; i++) arr.push(this.val()); - return arr; - } - - public readArrIndef(): unknown[] { - const arr: unknown[] = []; - while (this.reader.peak() !== CONST.END) arr.push(this.val()); - this.reader.x++; - return arr; - } - - // ----------------------------------------------------------- Object reading - - public readObj(minor: number): Record { - if (minor < 28) { - let length = minor; - switch (minor) { - case 24: - length = this.reader.u8(); - break; - case 25: - length = this.reader.u16(); - break; - case 26: - length = this.reader.u32(); - break; - case 27: - length = Number(this.reader.u64()); - break; - } - const obj: Record = {}; - for (let i = 0; i < length; i++) { - const key = this.key(); - if (key === '__proto__') throw ERROR.UNEXPECTED_OBJ_KEY; - const value = this.val(); - obj[key] = value; - } - return obj; - } else if (minor === 31) return this.readObjIndef(); - else throw ERROR.UNEXPECTED_MINOR; - } - - /** Remove this? */ - public readObjRaw(length: number): Record { - const obj: Record = {}; - for (let i = 0; i < length; i++) { - const key = this.key(); - const value = this.val(); - obj[key] = value; - } - return obj; - } - - public readObjIndef(): Record { - const obj: Record = {}; - while (this.reader.peak() !== CONST.END) { - const key = this.key(); - if (this.reader.peak() === CONST.END) throw ERROR.UNEXPECTED_OBJ_BREAK; - const value = this.val(); - obj[key] = value; - } - this.reader.x++; - return obj; - } - - public key(): string { - const octet = this.reader.u8(); - const major = octet >> 5; - const minor = octet & CONST.MINOR_MASK; - if (major !== MAJOR.STR) return String(this.readAnyRaw(octet)); - const length = this.readStrLen(minor); - if (length > 31) return this.reader.utf8(length); - const key = this.keyDecoder.decode(this.reader.uint8, this.reader.x, length); - this.reader.skip(length); - return key; - } - - // -------------------------------------------------------------- Tag reading - - public readTag(minor: number): JsonPackExtension | unknown { - if (minor <= 23) return this.readTagRaw(minor); - switch (minor) { - case 24: - return this.readTagRaw(this.reader.u8()); - case 25: - return this.readTagRaw(this.reader.u16()); - case 26: - return this.readTagRaw(this.reader.u32()); - case 27: - return this.readTagRaw(Number(this.reader.u64())); - default: - throw ERROR.UNEXPECTED_MINOR; - } - } - - public readTagRaw(tag: number): JsonPackExtension | unknown { - return new JsonPackExtension(tag, this.val()); - } - - // ------------------------------------------------------------ Token reading - - public readTkn(minor: number): number | true | false | null | undefined | JsonPackValue { - switch (minor) { - case 0xf4 & CONST.MINOR_MASK: - return false; - case 0xf5 & CONST.MINOR_MASK: - return true; - case 0xf6 & CONST.MINOR_MASK: - return null; - case 0xf7 & CONST.MINOR_MASK: - return undefined; - case 0xf8 & CONST.MINOR_MASK: - return new JsonPackValue(this.reader.u8()); - case 0xf9 & CONST.MINOR_MASK: - return this.f16(); - case 0xfa & CONST.MINOR_MASK: - return this.reader.f32(); - case 0xfb & CONST.MINOR_MASK: - return this.reader.f64(); - } - if (minor <= 23) return new JsonPackValue(minor); - throw ERROR.UNEXPECTED_MINOR; - } - - public f16(): number { - return decodeF16(this.reader.u16()); - } -} diff --git a/src/json-joy/json-pack/cbor/CborEncoder.ts b/src/json-joy/json-pack/cbor/CborEncoder.ts deleted file mode 100644 index 63587f505..000000000 --- a/src/json-joy/json-pack/cbor/CborEncoder.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {isFloat32} from '../../util/buffers/isFloat32'; -import {JsonPackExtension} from '../JsonPackExtension'; -import {CborEncoderFast} from './CborEncoderFast'; -import type {IWriter, IWriterGrowable} from '../../util/buffers'; - -export class CborEncoder extends CborEncoderFast { - /** - * Called when the encoder encounters a value that it does not know how to encode. - * - * @param value Some JavaScript value. - */ - public writeUnknown(value: unknown): void { - this.writeNull(); - } - - public writeAny(value: unknown): void { - switch (typeof value) { - case 'number': - return this.writeNumber(value as number); - case 'string': - return this.writeStr(value); - case 'boolean': - return this.writer.u8(0xf4 + +value); - case 'object': { - if (!value) return this.writer.u8(0xf6); - const constructor = value.constructor; - switch (constructor) { - case Object: - return this.writeObj(value as Record); - case Array: - return this.writeArr(value as unknown[]); - case Uint8Array: - return this.writeBin(value as Uint8Array); - case Map: - return this.writeMap(value as Map); - case JsonPackExtension: - return this.writeTag((value).tag, (value).val); - default: - return this.writeUnknown(value); - } - } - case 'undefined': - return this.writeUndef(); - case 'bigint': - return this.writeBigInt(value as bigint); - default: - return this.writeUnknown(value); - } - } - - public writeFloat(float: number): void { - if (isFloat32(float)) this.writer.u8f32(0xfa, float); - else this.writer.u8f64(0xfb, float); - } - - public writeMap(map: Map): void { - this.writeMapHdr(map.size); - map.forEach((value, key) => { - this.writeAny(key); - this.writeAny(value); - }); - } - - public writeUndef(): void { - this.writer.u8(0xf7); - } -} diff --git a/src/json-joy/json-pack/cbor/CborEncoderFast.ts b/src/json-joy/json-pack/cbor/CborEncoderFast.ts deleted file mode 100644 index b54ff07cc..000000000 --- a/src/json-joy/json-pack/cbor/CborEncoderFast.ts +++ /dev/null @@ -1,333 +0,0 @@ -import {Writer} from '../../util/buffers/Writer'; -import {CONST, MAJOR_OVERLAY} from './constants'; -import type {IWriter, IWriterGrowable} from '../../util/buffers'; -import type {BinaryJsonEncoder, StreamingBinaryJsonEncoder, TlvBinaryJsonEncoder} from '../types'; -import type {Slice} from '../../util/buffers/Slice'; - -const isSafeInteger = Number.isSafeInteger; - -/** - * Fast CBOR encoder supports only JSON values. Use regular `CborEncoder` if - * you need ability to encode all CBOR value types. - */ -export class CborEncoderFast - implements BinaryJsonEncoder, StreamingBinaryJsonEncoder, TlvBinaryJsonEncoder -{ - constructor(public readonly writer: W = new Writer() as any) {} - - public encode(value: unknown): Uint8Array { - this.writeAny(value); - return this.writer.flush(); - } - - public encodeToSlice(value: unknown): Slice { - this.writeAny(value); - return this.writer.flushSlice(); - } - - public writeAny(value: unknown): void { - switch (typeof value) { - case 'number': - return this.writeNumber(value as number); - case 'string': - return this.writeStr(value); - case 'boolean': - return this.writer.u8(0xf4 + +value); - case 'object': { - if (!value) return this.writer.u8(0xf6); - const constructor = value.constructor; - switch (constructor) { - case Array: - return this.writeArr(value as unknown[]); - default: - return this.writeObj(value as Record); - } - } - } - } - - public writeCbor(): void { - this.writer.u8u16(0xd9, 0xd9f7); - } - - public writeEnd(): void { - this.writer.u8(CONST.END); - } - - public writeNull(): void { - this.writer.u8(0xf6); - } - - public writeBoolean(bool: boolean): void { - if (bool) this.writer.u8(0xf5); - else this.writer.u8(0xf4); - } - - public writeNumber(num: number): void { - if (isSafeInteger(num)) this.writeInteger(num); - else if (typeof num === 'bigint') this.writeBigInt(num); - else this.writeFloat(num); - } - - public writeBigInt(int: bigint): void { - if (int >= 0) this.writeBigUint(int); - else this.writeBigSint(int); - } - - public writeBigUint(uint: bigint): void { - if (uint <= Number.MAX_SAFE_INTEGER) return this.writeUInteger(Number(uint)); - this.writer.u8u64(0x1b, uint); - } - - public writeBigSint(int: bigint): void { - if (int >= Number.MIN_SAFE_INTEGER) return this.encodeNint(Number(int)); - const uint = -BigInt(1) - int; - this.writer.u8u64(0x3b, uint); - } - - public writeInteger(int: number): void { - if (int >= 0) this.writeUInteger(int); - else this.encodeNint(int); - } - - public writeUInteger(uint: number): void { - const writer = this.writer; - writer.ensureCapacity(9); - const uint8 = writer.uint8; - let x = writer.x; - if (uint <= 23) { - uint8[x++] = MAJOR_OVERLAY.UIN + uint; - } else if (uint <= 0xff) { - uint8[x++] = 0x18; - uint8[x++] = uint; - } else if (uint <= 0xffff) { - uint8[x++] = 0x19; - writer.view.setUint16(x, uint); - x += 2; - } else if (uint <= 0xffffffff) { - uint8[x++] = 0x1a; - writer.view.setUint32(x, uint); - x += 4; - } else { - uint8[x++] = 0x1b; - writer.view.setBigUint64(x, BigInt(uint)); - x += 8; - } - writer.x = x; - } - - /** @deprecated Remove and use `writeNumber` instead. */ - public encodeNumber(num: number): void { - this.writeNumber(num); - } - - /** @deprecated Remove and use `writeInteger` instead. */ - public encodeInteger(int: number): void { - this.writeInteger(int); - } - - /** @deprecated */ - public encodeUint(uint: number): void { - this.writeUInteger(uint); - } - - public encodeNint(int: number): void { - const uint = -1 - int; - const writer = this.writer; - writer.ensureCapacity(9); - const uint8 = writer.uint8; - let x = writer.x; - if (uint < 24) { - uint8[x++] = MAJOR_OVERLAY.NIN + uint; - } else if (uint <= 0xff) { - uint8[x++] = 0x38; - uint8[x++] = uint; - } else if (uint <= 0xffff) { - uint8[x++] = 0x39; - writer.view.setUint16(x, uint); - x += 2; - } else if (uint <= 0xffffffff) { - uint8[x++] = 0x3a; - writer.view.setUint32(x, uint); - x += 4; - } else { - uint8[x++] = 0x3b; - writer.view.setBigUint64(x, BigInt(uint)); - x += 8; - } - writer.x = x; - } - - public writeFloat(float: number): void { - this.writer.u8f64(0xfb, float); - } - - public writeBin(buf: Uint8Array): void { - const length = buf.length; - this.writeBinHdr(length); - this.writer.buf(buf, length); - } - - public writeBinHdr(length: number): void { - const writer = this.writer; - if (length <= 23) writer.u8(MAJOR_OVERLAY.BIN + length); - else if (length <= 0xff) writer.u16((0x58 << 8) + length); - else if (length <= 0xffff) writer.u8u16(0x59, length); - else if (length <= 0xffffffff) writer.u8u32(0x5a, length); - else writer.u8u64(0x5b, length); - } - - public writeStr(str: string): void { - const writer = this.writer; - const length = str.length; - const maxSize = length * 4; - writer.ensureCapacity(5 + maxSize); - const uint8 = writer.uint8; - let lengthOffset: number = writer.x; - if (maxSize <= 23) writer.x++; - else if (maxSize <= 0xff) { - uint8[writer.x++] = 0x78; - lengthOffset = writer.x; - writer.x++; - } else if (maxSize <= 0xffff) { - uint8[writer.x++] = 0x79; - lengthOffset = writer.x; - writer.x += 2; - } else { - uint8[writer.x++] = 0x7a; - lengthOffset = writer.x; - writer.x += 4; - } - const bytesWritten = writer.utf8(str); - if (maxSize <= 23) uint8[lengthOffset] = MAJOR_OVERLAY.STR + bytesWritten; - else if (maxSize <= 0xff) uint8[lengthOffset] = bytesWritten; - else if (maxSize <= 0xffff) writer.view.setUint16(lengthOffset, bytesWritten); - else writer.view.setUint32(lengthOffset, bytesWritten); - } - - public writeStrHdr(length: number): void { - const writer = this.writer; - if (length <= 23) writer.u8(MAJOR_OVERLAY.STR + length); - else if (length <= 0xff) writer.u16((0x78 << 8) + length); - else if (length <= 0xffff) writer.u8u16(0x79, length); - else writer.u8u32(0x7a, length); - } - - public writeAsciiStr(str: string): void { - this.writeStrHdr(str.length); - this.writer.ascii(str); - } - - public writeArr(arr: unknown[]): void { - const length = arr.length; - this.writeArrHdr(length); - for (let i = 0; i < length; i++) this.writeAny(arr[i]); - } - - public writeArrHdr(length: number): void { - const writer = this.writer; - if (length <= 23) writer.u8(MAJOR_OVERLAY.ARR + length); - else if (length <= 0xff) writer.u16((0x98 << 8) + length); - else if (length <= 0xffff) writer.u8u16(0x99, length); - else if (length <= 0xffffffff) writer.u8u32(0x9a, length); - else writer.u8u64(0x9b, length); - } - - public writeObj(obj: Record): void { - const keys = Object.keys(obj); - const length = keys.length; - this.writeObjHdr(length); - for (let i = 0; i < length; i++) { - const key = keys[i]; - this.writeStr(key); - this.writeAny(obj[key]); - } - } - - public writeObjHdr(length: number): void { - const writer = this.writer; - if (length <= 23) writer.u8(MAJOR_OVERLAY.MAP + length); - else if (length <= 0xff) writer.u16((0xb8 << 8) + length); - else if (length <= 0xffff) writer.u8u16(0xb9, length); - else if (length <= 0xffffffff) writer.u8u32(0xba, length); - else writer.u8u64(0xbb, length); - } - - public writeMapHdr(length: number): void { - this.writeObjHdr(length); - } - - public writeStartMap(): void { - this.writer.u8(0xbf); - } - - public writeTag(tag: number, value: unknown): void { - this.writeTagHdr(tag); - this.writeAny(value); - } - - public writeTagHdr(tag: number): void { - const writer = this.writer; - if (tag <= 23) writer.u8(MAJOR_OVERLAY.TAG + tag); - else if (tag <= 0xff) writer.u16((0xd8 << 8) + tag); - else if (tag <= 0xffff) writer.u8u16(0xd9, tag); - else if (tag <= 0xffffffff) writer.u8u32(0xda, tag); - else writer.u8u64(0xdb, tag); - } - - public writeTkn(value: number): void { - const writer = this.writer; - if (value <= 23) writer.u8(MAJOR_OVERLAY.TKN + value); - else if (value <= 0xff) writer.u16((0xf8 << 8) + value); - } - - // ------------------------------------------------------- Streaming encoding - - public writeStartStr(): void { - this.writer.u8(0x7f); - } - - public writeStrChunk(str: string): void { - throw new Error('Not implemented'); - } - - public writeEndStr(): void { - throw new Error('Not implemented'); - } - - public writeStartBin(): void { - this.writer.u8(0x5f); - } - - public writeBinChunk(buf: Uint8Array): void { - throw new Error('Not implemented'); - } - - public writeEndBin(): void { - throw new Error('Not implemented'); - } - - public writeStartArr(): void { - this.writer.u8(0x9f); - } - - public writeArrChunk(item: unknown): void { - throw new Error('Not implemented'); - } - - public writeEndArr(): void { - this.writer.u8(CONST.END); - } - - public writeStartObj(): void { - this.writer.u8(0xbf); - } - - public writeObjChunk(key: string, value: unknown): void { - throw new Error('Not implemented'); - } - - public writeEndObj(): void { - this.writer.u8(CONST.END); - } -} diff --git a/src/json-joy/json-pack/cbor/constants.ts b/src/json-joy/json-pack/cbor/constants.ts deleted file mode 100644 index 86b3a5ae2..000000000 --- a/src/json-joy/json-pack/cbor/constants.ts +++ /dev/null @@ -1,42 +0,0 @@ -export const enum MAJOR { - UIN = 0b000, - NIN = 0b001, - BIN = 0b010, - STR = 0b011, - ARR = 0b100, - MAP = 0b101, - TAG = 0b110, - TKN = 0b111, -} - -export const enum MAJOR_OVERLAY { - UIN = 0b000_00000, - NIN = 0b001_00000, - BIN = 0b010_00000, - STR = 0b011_00000, - ARR = 0b100_00000, - MAP = 0b101_00000, - TAG = 0b110_00000, - TKN = 0b111_00000, -} - -export const enum CONST { - MINOR_MASK = 0b11111, - MAX_UINT = 9007199254740991, - END = 0xff, -} - -export const enum ERROR { - UNEXPECTED_MAJOR, - UNEXPECTED_MINOR, - UNEXPECTED_BIN_CHUNK_MAJOR, - UNEXPECTED_BIN_CHUNK_MINOR, - UNEXPECTED_STR_CHUNK_MAJOR, - UNEXPECTED_STR_CHUNK_MINOR, - UNEXPECTED_OBJ_KEY, - UNEXPECTED_OBJ_BREAK, - INVALID_SIZE, - KEY_NOT_FOUND, - INDEX_OUT_OF_BOUNDS, - UNEXPECTED_STR_MAJOR, -} diff --git a/src/json-joy/json-pack/cbor/types.ts b/src/json-joy/json-pack/cbor/types.ts deleted file mode 100644 index d80243c3e..000000000 --- a/src/json-joy/json-pack/cbor/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type CborUint8Array = Uint8Array & {__BRAND__: 'cbor'; __TYPE__: T}; diff --git a/src/json-joy/json-pack/json/JsonDecoder.ts b/src/json-joy/json-pack/json/JsonDecoder.ts deleted file mode 100644 index 7522fe960..000000000 --- a/src/json-joy/json-pack/json/JsonDecoder.ts +++ /dev/null @@ -1,644 +0,0 @@ -import {decodeUtf8} from '../../util/buffers/utf8/decodeUtf8'; -import {Reader} from '../../util/buffers/Reader'; -import {fromBase64Bin} from '../../util/base64/fromBase64Bin'; -import type {BinaryJsonDecoder, PackValue} from '../types'; - -const REGEX_REPLACE_ESCAPED_CHARS = /\\(b|f|n|r|t|"|\/|\\)/g; -const escapedCharReplacer = (char: string) => { - switch (char) { - case '\\b': - return '\b'; - case '\\f': - return '\f'; - case '\\n': - return '\n'; - case '\\r': - return '\r'; - case '\\t': - return '\t'; - case '\\"': - return '"'; - case '\\/': - return '/'; - case '\\\\': - return '\\'; - } - return char; -}; - -// Starts with "data:application/octet-stream;base64," - 64 61 74 61 3a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 65 61 6d 3b 62 61 73 65 36 34 2c -const hasBinaryPrefix = (u8: Uint8Array, x: number) => - u8[x] === 0x64 && - u8[x + 1] === 0x61 && - u8[x + 2] === 0x74 && - u8[x + 3] === 0x61 && - u8[x + 4] === 0x3a && - u8[x + 5] === 0x61 && - u8[x + 6] === 0x70 && - u8[x + 7] === 0x70 && - u8[x + 8] === 0x6c && - u8[x + 9] === 0x69 && - u8[x + 10] === 0x63 && - u8[x + 11] === 0x61 && - u8[x + 12] === 0x74 && - u8[x + 13] === 0x69 && - u8[x + 14] === 0x6f && - u8[x + 15] === 0x6e && - u8[x + 16] === 0x2f && - u8[x + 17] === 0x6f && - u8[x + 18] === 0x63 && - u8[x + 19] === 0x74 && - u8[x + 20] === 0x65 && - u8[x + 21] === 0x74 && - u8[x + 22] === 0x2d && - u8[x + 23] === 0x73 && - u8[x + 24] === 0x74 && - u8[x + 25] === 0x72 && - u8[x + 26] === 0x65 && - u8[x + 27] === 0x61 && - u8[x + 28] === 0x6d && - u8[x + 29] === 0x3b && - u8[x + 30] === 0x62 && - u8[x + 31] === 0x61 && - u8[x + 32] === 0x73 && - u8[x + 33] === 0x65 && - u8[x + 34] === 0x36 && - u8[x + 35] === 0x34 && - u8[x + 36] === 0x2c; - -const findEndingQuote = (uint8: Uint8Array, x: number): number => { - const len = uint8.length; - let char = uint8[x]; - let prev = 0; - while (x < len) { - if (char === 34 && prev !== 92) break; - if (char === 92 && prev === 92) prev = 0; - else prev = char; - char = uint8[++x]; - } - if (x === len) throw new Error('Invalid JSON'); - return x; -}; - -const fromCharCode = String.fromCharCode; - -const readShortUtf8StrAndUnescape = (reader: Reader): string => { - const buf = reader.uint8; - const len = buf.length; - const points: number[] = []; - let x = reader.x; - let prev = 0; - while (x < len) { - let code = buf[x++]!; - if ((code & 0x80) === 0) { - if (prev === 92) { - switch (code) { - case 98: // \b - code = 8; - break; - case 102: // \f - code = 12; - break; - case 110: // \n - code = 10; - break; - case 114: // \r - code = 13; - break; - case 116: // \t - code = 9; - break; - case 34: // \" - code = 34; - break; - case 47: // \/ - code = 47; - break; - case 92: // \\ - code = 92; - break; - default: - throw new Error('Invalid JSON'); - } - prev = 0; - } else { - if (code === 34) break; - prev = code; - if (prev === 92) continue; - } - } else { - const octet2 = buf[x++]! & 0x3f; - if ((code & 0xe0) === 0xc0) { - code = ((code & 0x1f) << 6) | octet2; - } else { - const octet3 = buf[x++]! & 0x3f; - if ((code & 0xf0) === 0xe0) { - code = ((code & 0x1f) << 12) | (octet2 << 6) | octet3; - } else { - if ((code & 0xf8) === 0xf0) { - const octet4 = buf[x++]! & 0x3f; - let unit = ((code & 0x07) << 0x12) | (octet2 << 0x0c) | (octet3 << 0x06) | octet4; - if (unit > 0xffff) { - unit -= 0x10000; - const unit0 = ((unit >>> 10) & 0x3ff) | 0xd800; - unit = 0xdc00 | (unit & 0x3ff); - points.push(unit0); - code = unit; - } else { - code = unit; - } - } - } - } - } - points.push(code); - } - reader.x = x; - return fromCharCode.apply(String, points); -}; - -export class JsonDecoder implements BinaryJsonDecoder { - public reader = new Reader(); - - public read(uint8: Uint8Array): PackValue { - this.reader.reset(uint8); - return this.readAny(); - } - - public readAny(): PackValue { - this.skipWhitespace(); - const reader = this.reader; - const x = reader.x; - const uint8 = reader.uint8; - const char = uint8[x]; - switch (char) { - case 34: // " - return uint8[x + 1] === 0x64 // d - ? this.tryReadBin() || this.readStr() - : this.readStr(); - case 91: // [ - return this.readArr(); - case 102: // f - return this.readFalse(); - case 110: // n - return this.readNull(); - case 116: // t - return this.readTrue(); - case 123: // { - return this.readObj(); - default: - if ((char >= 48 && char <= 57) || char === 45) return this.readNum(); - throw new Error('Invalid JSON'); - } - } - - public skipWhitespace(): void { - const reader = this.reader; - const uint8 = reader.uint8; - let x = reader.x; - let char: number = 0; - while (true) { - char = uint8[x]; - switch (char) { - case 32: // space - case 9: // tab - case 10: // line feed - case 13: // carriage return - x++; - continue; - default: - reader.x = x; - return; - } - } - } - - public readNull(): null { - if (this.reader.u32() !== 0x6e756c6c) throw new Error('Invalid JSON'); - return null; - } - - public readTrue(): true { - if (this.reader.u32() !== 0x74727565) throw new Error('Invalid JSON'); - return true; - } - - public readFalse(): false { - const reader = this.reader; - if (reader.u8() !== 0x66 || reader.u32() !== 0x616c7365) throw new Error('Invalid JSON'); - return false; - } - - public readBool(): unknown { - const reader = this.reader; - switch (reader.uint8[reader.x]) { - case 102: // f - return this.readFalse(); - case 116: // t - return this.readTrue(); - default: - throw new Error('Invalid JSON'); - } - } - - public readNum(): number { - const reader = this.reader; - const uint8 = reader.uint8; - let x = reader.x; - let c = uint8[x++]; - const c1 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c2 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c3 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c4 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c5 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c6 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c7 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c8 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 43 && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c9 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c10 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c11 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c12 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c13 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c14 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c15 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c16 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c17 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c18 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c19 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c20 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode( - c1, - c2, - c3, - c4, - c5, - c6, - c7, - c8, - c9, - c10, - c11, - c12, - c13, - c14, - c15, - c16, - c17, - c18, - c19, - c20, - ); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c21 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode( - c1, - c2, - c3, - c4, - c5, - c6, - c7, - c8, - c9, - c10, - c11, - c12, - c13, - c14, - c15, - c16, - c17, - c18, - c19, - c20, - c21, - ); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c22 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode( - c1, - c2, - c3, - c4, - c5, - c6, - c7, - c8, - c9, - c10, - c11, - c12, - c13, - c14, - c15, - c16, - c17, - c18, - c19, - c20, - c21, - c22, - ); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c23 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode( - c1, - c2, - c3, - c4, - c5, - c6, - c7, - c8, - c9, - c10, - c11, - c12, - c13, - c14, - c15, - c16, - c17, - c18, - c19, - c20, - c21, - c22, - c23, - ); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - const c24 = c; - c = uint8[x++]; - if (!c || ((c < 45 || c > 57) && c !== 69 && c !== 101)) { - reader.x = x - 1; - const num = +fromCharCode( - c1, - c2, - c3, - c4, - c5, - c6, - c7, - c8, - c9, - c10, - c11, - c12, - c13, - c14, - c15, - c16, - c17, - c18, - c19, - c20, - c21, - c22, - c24, - ); - if (num !== num) throw new Error('Invalid JSON'); - return num; - } - throw new Error('Invalid JSON'); - } - - public readStr(): string { - const reader = this.reader; - const uint8 = reader.uint8; - const char = uint8[reader.x++]; - if (char !== 0x22) throw new Error('Invalid JSON'); - const x0 = reader.x; - const x1 = findEndingQuote(uint8, x0); - let str = decodeUtf8(uint8, x0, x1 - x0); - /** @todo perf: maybe faster is to first check if there are any escaped chars. */ - str = str.replace(REGEX_REPLACE_ESCAPED_CHARS, escapedCharReplacer); - reader.x = x1 + 1; - return str; - } - - public tryReadBin(): Uint8Array | undefined { - const reader = this.reader; - const u8 = reader.uint8; - let x = reader.x; - if (u8[x++] !== 0x22) return undefined; - const hasDataUrlPrefix = hasBinaryPrefix(u8, x); - if (!hasDataUrlPrefix) return undefined; - x += 37; - const x0 = x; - x = findEndingQuote(u8, x); - reader.x = x0; - const bin = fromBase64Bin(reader.view, x0, x - x0); - reader.x = x + 1; - return bin; - } - - public readBin(): Uint8Array { - const reader = this.reader; - const u8 = reader.uint8; - let x = reader.x; - if (u8[x++] !== 0x22) throw new Error('Invalid JSON'); - const hasDataUrlPrefix = hasBinaryPrefix(u8, x); - if (!hasDataUrlPrefix) throw new Error('Invalid JSON'); - x += 37; - const x0 = x; - x = findEndingQuote(u8, x); - reader.x = x0; - const bin = fromBase64Bin(reader.view, x0, x - x0); - reader.x = x + 1; - return bin; - } - - public readArr(): PackValue[] { - const reader = this.reader; - if (reader.u8() !== 0x5b) throw new Error('Invalid JSON'); - const arr: PackValue[] = []; - const uint8 = reader.uint8; - while (true) { - this.skipWhitespace(); - const char = uint8[reader.x]; - if (char === 0x5d) return reader.x++, arr; // ] - if (char === 0x2c) { - reader.x++; - continue; - } // , - arr.push(this.readAny()); - } - } - - public readObj(): Record { - const reader = this.reader; - if (reader.u8() !== 0x7b) throw new Error('Invalid JSON'); - const obj: Record = {}; - const uint8 = reader.uint8; - while (true) { - this.skipWhitespace(); - let char = uint8[reader.x]; - if (char === 0x7d) return reader.x++, obj; // } - if (char === 0x2c) { - reader.x++; - continue; - } // , - char = uint8[reader.x++]; - if (char !== 0x22) throw new Error('Invalid JSON'); - const key = readShortUtf8StrAndUnescape(reader); - if (key === '__proto__') throw new Error('Invalid JSON'); - this.skipWhitespace(); - if (reader.u8() !== 0x3a) throw new Error('Invalid JSON'); - this.skipWhitespace(); - obj[key] = this.readAny(); - } - } -} diff --git a/src/json-joy/json-pack/json/JsonEncoder.ts b/src/json-joy/json-pack/json/JsonEncoder.ts deleted file mode 100644 index b7f8cf35b..000000000 --- a/src/json-joy/json-pack/json/JsonEncoder.ts +++ /dev/null @@ -1,238 +0,0 @@ -import {toBase64Bin} from '../../util/base64/toBase64Bin'; -import type {IWriter, IWriterGrowable} from '../../util/buffers'; -import type {BinaryJsonEncoder, StreamingBinaryJsonEncoder} from '../types'; - -export class JsonEncoder implements BinaryJsonEncoder, StreamingBinaryJsonEncoder { - constructor(public readonly writer: IWriter & IWriterGrowable) {} - - public encode(value: unknown): Uint8Array { - const writer = this.writer; - writer.reset(); - this.writeAny(value); - return writer.flush(); - } - - public writeAny(value: unknown): void { - switch (typeof value) { - case 'boolean': - return this.writeBoolean(value); - case 'number': - return this.writeNumber(value as number); - case 'string': - return this.writeStr(value); - case 'object': { - if (value === null) return this.writeNull(); - const constructor = value.constructor; - switch (constructor) { - case Array: - return this.writeArr(value as unknown[]); - case Uint8Array: - return this.writeBin(value as Uint8Array); - default: - return this.writeObj(value as Record); - } - } - default: - return this.writeNull(); - } - } - - public writeNull(): void { - this.writer.u32(0x6e756c6c); // null - } - - public writeBoolean(bool: boolean): void { - if (bool) this.writer.u32(0x74727565); // true - else this.writer.u8u32(0x66, 0x616c7365); // false - } - - public writeNumber(num: number): void { - const str = num.toString(); - this.writer.ascii(str); - } - - public writeInteger(int: number): void { - this.writeNumber(int >> 0 === int ? int : Math.trunc(int)); - } - - public writeUInteger(uint: number): void { - this.writeInteger(uint < 0 ? -uint : uint); - } - - public writeFloat(float: number): void { - this.writeNumber(float); - } - - public writeBin(buf: Uint8Array): void { - const writer = this.writer; - const length = buf.length; - writer.ensureCapacity(38 + 3 + (length << 1)); - // Write: "data:application/octet-stream;base64, - 22 64 61 74 61 3a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 65 61 6d 3b 62 61 73 65 36 34 2c - const view = writer.view; - let x = writer.x; - view.setUint32(x, 0x22_64_61_74); // "dat - x += 4; - view.setUint32(x, 0x61_3a_61_70); // a:ap - x += 4; - view.setUint32(x, 0x70_6c_69_63); // plic - x += 4; - view.setUint32(x, 0x61_74_69_6f); // atio - x += 4; - view.setUint32(x, 0x6e_2f_6f_63); // n/oc - x += 4; - view.setUint32(x, 0x74_65_74_2d); // tet- - x += 4; - view.setUint32(x, 0x73_74_72_65); // stre - x += 4; - view.setUint32(x, 0x61_6d_3b_62); // am;b - x += 4; - view.setUint32(x, 0x61_73_65_36); // ase6 - x += 4; - view.setUint16(x, 0x34_2c); // 4, - x += 2; - x = toBase64Bin(buf, 0, length, view, x); - writer.uint8[x++] = 0x22; // " - writer.x = x; - } - - public writeStr(str: string): void { - const writer = this.writer; - const length = str.length; - writer.ensureCapacity(length * 4 + 2); - if (length < 256) { - let x = writer.x; - const uint8 = writer.uint8; - uint8[x++] = 0x22; // " - for (let i = 0; i < length; i++) { - const code = str.charCodeAt(i); - switch (code) { - case 34: // " - case 92: // \ - uint8[x++] = 0x5c; // \ - break; - } - if (code < 32 || code > 126) { - writer.utf8(JSON.stringify(str)); - return; - } else uint8[x++] = code; - } - uint8[x++] = 0x22; // " - writer.x = x; - return; - } - writer.utf8(JSON.stringify(str)); - } - - public writeAsciiStr(str: string): void { - const length = str.length; - const writer = this.writer; - writer.ensureCapacity(length * 2 + 2); - const uint8 = writer.uint8; - let x = writer.x; - uint8[x++] = 0x22; // " - for (let i = 0; i < length; i++) { - const code = str.charCodeAt(i); - switch (code) { - case 34: // " - case 92: // \ - uint8[x++] = 0x5c; // \ - break; - } - uint8[x++] = code; - } - uint8[x++] = 0x22; // " - writer.x = x; - } - - public writeArr(arr: unknown[]): void { - const writer = this.writer; - writer.u8(0x5b); // [ - const length = arr.length; - const last = length - 1; - for (let i = 0; i < last; i++) { - this.writeAny(arr[i]); - writer.u8(0x2c); // , - } - if (last >= 0) this.writeAny(arr[last]); - writer.u8(0x5d); // ] - } - - public writeArrSeparator(): void { - this.writer.u8(0x2c); // , - } - - public writeObj(obj: Record): void { - const writer = this.writer; - const keys = Object.keys(obj); - const length = keys.length; - if (!length) return writer.u16(0x7b7d); // {} - writer.u8(0x7b); // { - for (let i = 0; i < length; i++) { - const key = keys[i]; - const value = obj[key]; - this.writeStr(key); - writer.u8(0x3a); // : - this.writeAny(value); - writer.u8(0x2c); // , - } - writer.uint8[writer.x - 1] = 0x7d; // } - } - - public writeObjSeparator(): void { - this.writer.u8(0x2c); // , - } - - public writeObjKeySeparator(): void { - this.writer.u8(0x3a); // : - } - - // ------------------------------------------------------- Streaming encoding - - public writeStartStr(): void { - throw new Error('Method not implemented.'); - } - - public writeStrChunk(str: string): void { - throw new Error('Method not implemented.'); - } - - public writeEndStr(): void { - throw new Error('Method not implemented.'); - } - - public writeStartBin(): void { - throw new Error('Method not implemented.'); - } - - public writeBinChunk(buf: Uint8Array): void { - throw new Error('Method not implemented.'); - } - - public writeEndBin(): void { - throw new Error('Method not implemented.'); - } - - public writeStartArr(): void { - this.writer.u8(0x5b); // [ - } - - public writeArrChunk(item: unknown): void { - throw new Error('Method not implemented.'); - } - - public writeEndArr(): void { - this.writer.u8(0x5d); // ] - } - - public writeStartObj(): void { - this.writer.u8(0x7b); // { - } - - public writeObjChunk(key: string, value: unknown): void { - throw new Error('Method not implemented.'); - } - - public writeEndObj(): void { - this.writer.u8(0x7d); // } - } -} diff --git a/src/json-joy/json-pack/types.ts b/src/json-joy/json-pack/types.ts deleted file mode 100644 index 217c288bf..000000000 --- a/src/json-joy/json-pack/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type {IReader, IReaderResettable, IWriter, IWriterGrowable} from '../util/buffers'; -import type {JsonPackExtension} from './JsonPackExtension'; -import type {JsonPackValue} from './JsonPackValue'; - -export type JsonPrimitive = string | number | bigint | boolean | null; -export type JsonValue = JsonPrimitive | JsonArray | JsonObject; -type JsonArray = JsonValue[] | readonly JsonValue[]; -type JsonObject = {[key: string]: JsonValue} | Readonly<{[key: string]: JsonValue}>; - -export type TypedJsonValue = T & JsonValue; - -export type PackPrimitive = JsonPrimitive | undefined | Uint8Array | JsonPackValue | JsonPackExtension | bigint; -export type PackValue = PackPrimitive | PackArray | PackObject; -type PackArray = PackValue[] | readonly PackValue[]; -type PackObject = {[key: string]: PackValue} | Readonly<{[key: string]: PackValue}>; - -export interface BinaryJsonEncoder { - writer: IWriter & IWriterGrowable; - writeAny(value: unknown): void; - writeNull(): void; - writeBoolean(bool: boolean): void; - writeNumber(num: number): void; - writeInteger(int: number): void; - writeUInteger(uint: number): void; - writeFloat(float: number): void; - writeBin(buf: Uint8Array): void; - writeAsciiStr(str: string): void; - writeStr(str: string): void; - writeArr(arr: unknown[]): void; - writeObj(obj: Record): void; -} - -export interface StreamingBinaryJsonEncoder { - writeStartStr(): void; - writeStrChunk(str: string): void; - writeEndStr(): void; - writeStartBin(): void; - writeBinChunk(buf: Uint8Array): void; - writeEndBin(): void; - writeStartArr(): void; - writeArrChunk(item: unknown): void; - writeEndArr(): void; - writeStartObj(): void; - writeObjChunk(key: string, value: unknown): void; - writeEndObj(): void; -} - -export interface TlvBinaryJsonEncoder { - writeBinHdr(length: number): void; - writeArrHdr(length: number): void; - writeObjHdr(length: number): void; -} - -export interface BinaryJsonDecoder { - reader: IReader & IReaderResettable; - read(uint8: Uint8Array): PackValue; -} diff --git a/src/snapshot/binary.ts b/src/snapshot/binary.ts index f1c068107..0e77bbfdb 100644 --- a/src/snapshot/binary.ts +++ b/src/snapshot/binary.ts @@ -1,9 +1,9 @@ -import { CborEncoder } from '../json-joy/json-pack/cbor/CborEncoder'; -import { CborDecoder } from '../json-joy/json-pack/cbor/CborDecoder'; +import { CborEncoder } from '@jsonjoy.com/json-pack/lib/cbor/CborEncoder'; +import { CborDecoder } from '@jsonjoy.com/json-pack/lib/cbor/CborDecoder'; import { fromSnapshotSync, toSnapshotSync } from './sync'; import { fromSnapshot, toSnapshot } from './async'; import { writer } from './shared'; -import type { CborUint8Array } from '../json-joy/json-pack/cbor/types'; +import type { CborUint8Array } from '@jsonjoy.com/json-pack/lib/cbor/types'; import type { AsyncSnapshotOptions, SnapshotNode, SnapshotOptions } from './types'; const encoder = new CborEncoder(writer); diff --git a/src/snapshot/json.ts b/src/snapshot/json.ts index f35ec9fa9..2b59194ca 100644 --- a/src/snapshot/json.ts +++ b/src/snapshot/json.ts @@ -1,5 +1,5 @@ -import { JsonEncoder } from '../json-joy/json-pack/json/JsonEncoder'; -import { JsonDecoder } from '../json-joy/json-pack/json/JsonDecoder'; +import { JsonEncoder } from '@jsonjoy.com/json-pack/lib/json/JsonEncoder'; +import { JsonDecoder } from '@jsonjoy.com/json-pack/lib/json/JsonDecoder'; import { fromSnapshotSync, toSnapshotSync } from './sync'; import { fromSnapshot, toSnapshot } from './async'; import { writer } from './shared'; diff --git a/yarn.lock b/yarn.lock index 377f78eeb..3a21d8bb5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -593,6 +593,28 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jsonjoy.com/base64@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/base64/-/base64-1.1.1.tgz#a717fd8840f7bad49c7fe66cc65db8bcfc4c4dc5" + integrity sha512-LnFjVChaGY8cZVMwAIMjvA1XwQjZ/zIXHyh28IyJkyNkzof4Dkm1+KN9UIm3lHhREH4vs7XwZ0NpkZKnwOtEfg== + +"@jsonjoy.com/json-pack@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.0.2.tgz#d7c8c284db828b29eebb9082134251a8216ec5cc" + integrity sha512-4KMApTgb1Hvjz9Ue7unziJ1xNy3k6d2erp0hz1iXryXsf6LEM3KwN6YrfbqT0vqkUO8Tu+CSnvMia9cWX6YGVw== + dependencies: + "@jsonjoy.com/base64" "^1.1.1" + "@jsonjoy.com/util" "^1.0.0" + hyperdyperid "^1.2.0" + thingies "^1.20.0" + +"@jsonjoy.com/util@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.1.0.tgz#9726365362ede17405d2b521b4c782582df7ed4f" + integrity sha512-Yz+xITJ3Y/w0DBISwPkBETP5/cITHXscjgQNZIkfrVz1V7/ahJY8vw+T+LZy/KtXgKuUWqu4GALAQ3bhGt9J8A== + dependencies: + hyperdyperid "^1.2.0" + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.5" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" @@ -3540,6 +3562,11 @@ husky@^8.0.1: resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +hyperdyperid@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" + integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6707,6 +6734,11 @@ text-table@~0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thingies@^1.20.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1" + integrity sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g== + through2@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" From c223b74b22254c6344b7e23175f85d77f5c9d0ea Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Apr 2024 13:24:38 +0200 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=F0=9F=A4=96=20use=20util=20packag?= =?UTF-8?q?e,=20remove=20more=20duplicate=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/json-joy/util/base64/constants.ts | 2 - .../util/base64/createFromBase64Bin.ts | 68 ----- src/json-joy/util/base64/createToBase64Bin.ts | 44 --- src/json-joy/util/base64/fromBase64Bin.ts | 3 - src/json-joy/util/base64/toBase64Bin.ts | 3 - src/json-joy/util/buffers/Reader.ts | 105 ------- src/json-joy/util/buffers/Slice.ts | 12 - src/json-joy/util/buffers/Writer.ts | 276 ------------------ src/json-joy/util/buffers/f16.ts | 16 - src/json-joy/util/buffers/index.ts | 1 - src/json-joy/util/buffers/isFloat32.ts | 6 - src/json-joy/util/buffers/types.ts | 126 -------- .../util/buffers/utf8/CachedUtf8Decoder.ts | 51 ---- src/json-joy/util/buffers/utf8/decodeAscii.ts | 167 ----------- .../util/buffers/utf8/decodeUtf8/index.ts | 3 - .../util/buffers/utf8/decodeUtf8/v10.ts | 39 --- .../util/buffers/utf8/decodeUtf8/v16.ts | 39 --- .../util/buffers/utf8/decodeUtf8/v18.ts | 36 --- src/json-joy/util/buffers/utf8/randomU32.ts | 7 - .../buffers/utf8/sharedCachedUtf8Decoder.ts | 3 - src/snapshot/shared.ts | 2 +- yarn.lock | 2 +- 23 files changed, 3 insertions(+), 1009 deletions(-) delete mode 100644 src/json-joy/util/base64/constants.ts delete mode 100644 src/json-joy/util/base64/createFromBase64Bin.ts delete mode 100644 src/json-joy/util/base64/createToBase64Bin.ts delete mode 100644 src/json-joy/util/base64/fromBase64Bin.ts delete mode 100644 src/json-joy/util/base64/toBase64Bin.ts delete mode 100644 src/json-joy/util/buffers/Reader.ts delete mode 100644 src/json-joy/util/buffers/Slice.ts delete mode 100644 src/json-joy/util/buffers/Writer.ts delete mode 100644 src/json-joy/util/buffers/f16.ts delete mode 100644 src/json-joy/util/buffers/index.ts delete mode 100644 src/json-joy/util/buffers/isFloat32.ts delete mode 100644 src/json-joy/util/buffers/types.ts delete mode 100644 src/json-joy/util/buffers/utf8/CachedUtf8Decoder.ts delete mode 100644 src/json-joy/util/buffers/utf8/decodeAscii.ts delete mode 100644 src/json-joy/util/buffers/utf8/decodeUtf8/index.ts delete mode 100644 src/json-joy/util/buffers/utf8/decodeUtf8/v10.ts delete mode 100644 src/json-joy/util/buffers/utf8/decodeUtf8/v16.ts delete mode 100644 src/json-joy/util/buffers/utf8/decodeUtf8/v18.ts delete mode 100644 src/json-joy/util/buffers/utf8/randomU32.ts delete mode 100644 src/json-joy/util/buffers/utf8/sharedCachedUtf8Decoder.ts diff --git a/package.json b/package.json index d0d4a76c9..900183894 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ }, "dependencies": { "@jsonjoy.com/json-pack": "^1.0.2", + "@jsonjoy.com/util": "^1.1.0", "tslib": "^2.0.0" }, "devDependencies": { diff --git a/src/json-joy/util/base64/constants.ts b/src/json-joy/util/base64/constants.ts deleted file mode 100644 index 46b192633..000000000 --- a/src/json-joy/util/base64/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; -export const hasBuffer = typeof Buffer === 'function' && typeof Buffer.from === 'function'; diff --git a/src/json-joy/util/base64/createFromBase64Bin.ts b/src/json-joy/util/base64/createFromBase64Bin.ts deleted file mode 100644 index 3b2ee1cc5..000000000 --- a/src/json-joy/util/base64/createFromBase64Bin.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {alphabet} from './constants'; - -export const createFromBase64Bin = (chars: string = alphabet, paddingOctet: number = 0x3d) => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - let max = 0; - for (let i = 0; i < chars.length; i++) max = Math.max(max, chars.charCodeAt(i)); - const table: number[] = []; - for (let i = 0; i <= max; i += 1) table[i] = -1; - for (let i = 0; i < chars.length; i++) table[chars.charCodeAt(i)] = i; - - return (view: DataView, offset: number, length: number): Uint8Array => { - if (!length) return new Uint8Array(0); - if (length % 4 !== 0) throw new Error('Base64 string length must be a multiple of 4'); - const end = offset + length; - const last = end - 1; - const lastOctet = view.getUint8(last); - const mainEnd = offset + (lastOctet !== paddingOctet ? length : length - 4); - let bufferLength = (length >> 2) * 3; - let padding = 0; - if (last > 0 && view.getUint8(last - 1) === paddingOctet) { - padding = 2; - bufferLength -= 2; - } else if (lastOctet === paddingOctet) { - padding = 1; - bufferLength -= 1; - } - const buf = new Uint8Array(bufferLength); - let j = 0; - let i = offset; - for (; i < mainEnd; i += 4) { - const word = view.getUint32(i); - const octet0 = word >>> 24; - const octet1 = (word >>> 16) & 0xff; - const octet2 = (word >>> 8) & 0xff; - const octet3 = word & 0xff; - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - const sextet2 = table[octet2]; - const sextet3 = table[octet3]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0 || sextet3 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - buf[j + 2] = (sextet2 << 6) | sextet3; - j += 3; - } - if (padding === 2) { - const word = view.getUint16(mainEnd); - const octet0 = word >> 8; - const octet1 = word & 0xff; - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - if (sextet0 < 0 || sextet1 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - } else if (padding === 1) { - const word = view.getUint16(mainEnd); - const octet0 = word >> 8; - const octet1 = word & 0xff; - const octet2 = view.getUint8(mainEnd + 2); - const sextet0 = table[octet0]; - const sextet1 = table[octet1]; - const sextet2 = table[octet2]; - if (sextet0 < 0 || sextet1 < 0 || sextet2 < 0) throw new Error('INVALID_BASE64_SEQ'); - buf[j] = (sextet0 << 2) | (sextet1 >> 4); - buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2); - } - return buf; - }; -}; diff --git a/src/json-joy/util/base64/createToBase64Bin.ts b/src/json-joy/util/base64/createToBase64Bin.ts deleted file mode 100644 index 865d09542..000000000 --- a/src/json-joy/util/base64/createToBase64Bin.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {alphabet} from './constants'; - -export const createToBase64Bin = (chars: string = alphabet) => { - if (chars.length !== 64) throw new Error('chars must be 64 characters long'); - - const table = chars.split('').map((c) => c.charCodeAt(0)); - const table2: number[] = []; - - for (const c1 of table) { - for (const c2 of table) { - const two = (c1 << 8) + c2; - table2.push(two); - } - } - - return (uint8: Uint8Array, start: number, length: number, dest: DataView, offset: number): number => { - const extraLength = length % 3; - const baseLength = length - extraLength; - for (; start < baseLength; start += 3) { - const o1 = uint8[start]; - const o2 = uint8[start + 1]; - const o3 = uint8[start + 2]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = ((o2 & 0b1111) << 8) | o3; - dest.setInt32(offset, (table2[v1] << 16) + table2[v2]); - offset += 4; - } - if (extraLength) { - if (extraLength === 1) { - const o1 = uint8[baseLength]; - dest.setInt32(offset, (table2[o1 << 4] << 16) + 0x3d3d); - return offset + 4; - } else { - const o1 = uint8[baseLength]; - const o2 = uint8[baseLength + 1]; - const v1 = (o1 << 4) | (o2 >> 4); - const v2 = (o2 & 0b1111) << 2; - dest.setInt32(offset, (table2[v1] << 16) + (table[v2] << 8) + 0x3d); - return offset + 4; - } - } - return offset; - }; -}; diff --git a/src/json-joy/util/base64/fromBase64Bin.ts b/src/json-joy/util/base64/fromBase64Bin.ts deleted file mode 100644 index 678898d5e..000000000 --- a/src/json-joy/util/base64/fromBase64Bin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createFromBase64Bin} from './createFromBase64Bin'; - -export const fromBase64Bin = createFromBase64Bin(); diff --git a/src/json-joy/util/base64/toBase64Bin.ts b/src/json-joy/util/base64/toBase64Bin.ts deleted file mode 100644 index 012f2c24a..000000000 --- a/src/json-joy/util/base64/toBase64Bin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {createToBase64Bin} from './createToBase64Bin'; - -export const toBase64Bin = createToBase64Bin(); diff --git a/src/json-joy/util/buffers/Reader.ts b/src/json-joy/util/buffers/Reader.ts deleted file mode 100644 index 160e9cdc8..000000000 --- a/src/json-joy/util/buffers/Reader.ts +++ /dev/null @@ -1,105 +0,0 @@ -import {decodeUtf8} from './utf8/decodeUtf8'; -import type {IReader, IReaderResettable} from './types'; - -export class Reader implements IReader, IReaderResettable { - public uint8 = new Uint8Array([]); - public view = new DataView(this.uint8.buffer); - public x = 0; - - public reset(uint8: Uint8Array): void { - this.x = 0; - this.uint8 = uint8; - this.view = new DataView(uint8.buffer, uint8.byteOffset, uint8.length); - } - - public peak(): number { - return this.view.getUint8(this.x); - } - - public skip(length: number): void { - this.x += length; - } - - public buf(size: number): Uint8Array { - const end = this.x + size; - const bin = this.uint8.subarray(this.x, end); - this.x = end; - return bin; - } - - public u8(): number { - return this.uint8[this.x++]; - // return this.view.getUint8(this.x++); - } - - public i8(): number { - return this.view.getInt8(this.x++); - } - - public u16(): number { - // const num = this.view.getUint16(this.x); - // this.x += 2; - // return num; - let x = this.x; - const num = (this.uint8[x++] << 8) + this.uint8[x++]; - this.x = x; - return num; - } - - public i16(): number { - const num = this.view.getInt16(this.x); - this.x += 2; - return num; - } - - public u32(): number { - const num = this.view.getUint32(this.x); - this.x += 4; - return num; - } - - public i32(): number { - const num = this.view.getInt32(this.x); - this.x += 4; - return num; - } - - public u64(): bigint { - const num = this.view.getBigUint64(this.x); - this.x += 8; - return num; - } - - public i64(): bigint { - const num = this.view.getBigInt64(this.x); - this.x += 8; - return num; - } - - public f32(): number { - const pos = this.x; - this.x += 4; - return this.view.getFloat32(pos); - } - - public f64(): number { - const pos = this.x; - this.x += 8; - return this.view.getFloat64(pos); - } - - public utf8(size: number): string { - const start = this.x; - this.x += size; - return decodeUtf8(this.uint8, start, size); - } - - public ascii(length: number): string { - const uint8 = this.uint8; - let str = ''; - const end = this.x + length; - for (let i = this.x; i < end; i++) str += String.fromCharCode(uint8[i]); - this.x = end; - return str; - } -} diff --git a/src/json-joy/util/buffers/Slice.ts b/src/json-joy/util/buffers/Slice.ts deleted file mode 100644 index c0287b831..000000000 --- a/src/json-joy/util/buffers/Slice.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class Slice { - constructor( - public readonly uint8: Uint8Array, - public readonly view: DataView, - public readonly start: number, - public readonly end: number, - ) {} - - public subarray(): Uint8Array { - return this.uint8.subarray(this.start, this.end); - } -} diff --git a/src/json-joy/util/buffers/Writer.ts b/src/json-joy/util/buffers/Writer.ts deleted file mode 100644 index 7433f5cd0..000000000 --- a/src/json-joy/util/buffers/Writer.ts +++ /dev/null @@ -1,276 +0,0 @@ -import {Slice} from './Slice'; -import {IWriterGrowable, IWriter} from './types'; - -const EMPTY_UINT8 = new Uint8Array([]); -const EMPTY_VIEW = new DataView(EMPTY_UINT8.buffer); - -declare global { - interface Uint8Array { - utf8Write(str: string, pos: number, maxLength: number): number - write(str: string, pos: number, maxLength: number, encoding: string): number; - } -} - -const hasBuffer = typeof Buffer === 'function'; -const utf8Write = hasBuffer - ? (Buffer.prototype.utf8Write as (this: Uint8Array, str: string, pos: number, maxLength: number) => number) - : null; -const from = hasBuffer ? Buffer.from : null; -const textEncoder = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null; - -/** - * Encoder class provides an efficient way to encode binary data. It grows the - * internal memory buffer automatically as more space is required. It is useful - * in cases when it is not known in advance the size of memory needed. - */ -export class Writer implements IWriter, IWriterGrowable { - /** @ignore */ - public uint8: Uint8Array; - /** @ignore */ - public view: DataView = EMPTY_VIEW; - /** @ignore */ - public x0: number = 0; - /** @ignore */ - public x: number = 0; - protected size: number; - - /** - * @param allocSize Number of bytes to allocate at a time when buffer ends. - */ - constructor(public allocSize: number = 64 * 1024) { - this.uint8 = new Uint8Array(allocSize); - this.size = allocSize; - this.view = new DataView(this.uint8.buffer); - } - - /** @ignore */ - protected grow(size: number) { - const x0 = this.x0; - const x = this.x; - const oldUint8 = this.uint8; - const newUint8 = new Uint8Array(size); - const view = new DataView(newUint8.buffer); - const activeSlice = oldUint8.subarray(x0, x); - newUint8.set(activeSlice, 0); - this.x = x - x0; - this.x0 = 0; - this.uint8 = newUint8; - this.size = size; - this.view = view; - } - - /** - * Make sure the internal buffer has enough space to write the specified number - * of bytes, otherwise resize the internal buffer to accommodate for more size. - * - * @param capacity Number of bytes. - */ - public ensureCapacity(capacity: number) { - const byteLength = this.size; - const remaining = byteLength - this.x; - if (remaining < capacity) { - const total = byteLength - this.x0; - const required = capacity - remaining; - const totalRequired = total + required; - this.grow(totalRequired <= this.allocSize ? this.allocSize : totalRequired * 2); - } - } - - /** @todo Consider renaming to "skip"? */ - public move(capacity: number) { - this.ensureCapacity(capacity); - this.x += capacity; - } - - public reset() { - this.x0 = this.x; - } - - /** - * Allocates a new {@link ArrayBuffer}, useful when the underlying - * {@link ArrayBuffer} cannot be shared between threads. - * - * @param size Size of memory to allocate. - */ - public newBuffer(size: number) { - const uint8 = (this.uint8 = new Uint8Array(size)); - this.size = size; - this.view = new DataView(uint8.buffer); - this.x = this.x0 = 0; - } - - /** - * @returns Encoded memory buffer contents. - */ - public flush(): Uint8Array { - const result = this.uint8.subarray(this.x0, this.x); - this.x0 = this.x; - return result; - } - - public flushSlice(): Slice { - const slice = new Slice(this.uint8, this.view, this.x0, this.x); - this.x0 = this.x; - return slice; - } - - public u8(char: number) { - this.ensureCapacity(1); - this.uint8[this.x++] = char; - } - - public u16(word: number) { - this.ensureCapacity(2); - this.view.setUint16(this.x, word); - this.x += 2; - } - - public u32(dword: number) { - this.ensureCapacity(4); - this.view.setUint32(this.x, dword); - this.x += 4; - } - - public i32(dword: number) { - this.ensureCapacity(4); - this.view.setInt32(this.x, dword); - this.x += 4; - } - - public u64(qword: number | bigint) { - this.ensureCapacity(8); - this.view.setBigUint64(this.x, BigInt(qword)); - this.x += 8; - } - - public f64(float: number) { - this.ensureCapacity(8); - this.view.setFloat64(this.x, float); - this.x += 8; - } - - public u8u16(u8: number, u16: number) { - this.ensureCapacity(3); - let x = this.x; - this.uint8[x++] = u8; - this.uint8[x++] = u16 >>> 8; - this.uint8[x++] = u16 & 0xff; - this.x = x; - } - - public u8u32(u8: number, u32: number) { - this.ensureCapacity(5); - let x = this.x; - this.uint8[x++] = u8; - this.view.setUint32(x, u32); - this.x = x + 4; - } - - public u8u64(u8: number, u64: number | bigint) { - this.ensureCapacity(9); - let x = this.x; - this.uint8[x++] = u8; - this.view.setBigUint64(x, BigInt(u64)); - this.x = x + 8; - } - - public u8f32(u8: number, f32: number) { - this.ensureCapacity(5); - let x = this.x; - this.uint8[x++] = u8; - this.view.setFloat32(x, f32); - this.x = x + 4; - } - - public u8f64(u8: number, f64: number) { - this.ensureCapacity(9); - let x = this.x; - this.uint8[x++] = u8; - this.view.setFloat64(x, f64); - this.x = x + 8; - } - - public buf(buf: Uint8Array, length: number): void { - this.ensureCapacity(length); - const x = this.x; - this.uint8.set(buf, x); - this.x = x + length; - } - - /** - * Encodes string as UTF-8. You need to call .ensureCapacity(str.length * 4) - * before calling - * - * @param str String to encode as UTF-8. - * @returns The number of bytes written - */ - public utf8(str: string): number { - const maxLength = str.length * 4; - if (maxLength < 168) return this.utf8Native(str); - if (utf8Write) { - const writeLength = utf8Write.call(this.uint8, str, this.x, maxLength); - this.x += writeLength; - return writeLength; - } else if (from) { - const uint8 = this.uint8; - const offset = uint8.byteOffset + this.x; - const buf = from(uint8.buffer).subarray(offset, offset + maxLength); - const writeLength = buf.write(str, 0, maxLength, 'utf8'); - this.x += writeLength; - return writeLength; - } else if (maxLength > 1024 && textEncoder) { - const writeLength = textEncoder!.encodeInto(str, this.uint8.subarray(this.x, this.x + maxLength)).written!; - this.x += writeLength; - return writeLength; - } - return this.utf8Native(str); - } - - public utf8Native(str: string): number { - const length = str.length; - const uint8 = this.uint8; - let offset = this.x; - let pos = 0; - while (pos < length) { - let value = str.charCodeAt(pos++); - if ((value & 0xffffff80) === 0) { - uint8[offset++] = value; - continue; - } else if ((value & 0xfffff800) === 0) { - uint8[offset++] = ((value >> 6) & 0x1f) | 0xc0; - } else { - if (value >= 0xd800 && value <= 0xdbff) { - if (pos < length) { - const extra = str.charCodeAt(pos); - if ((extra & 0xfc00) === 0xdc00) { - pos++; - value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000; - } - } - } - if ((value & 0xffff0000) === 0) { - uint8[offset++] = ((value >> 12) & 0x0f) | 0xe0; - uint8[offset++] = ((value >> 6) & 0x3f) | 0x80; - } else { - uint8[offset++] = ((value >> 18) & 0x07) | 0xf0; - uint8[offset++] = ((value >> 12) & 0x3f) | 0x80; - uint8[offset++] = ((value >> 6) & 0x3f) | 0x80; - } - } - uint8[offset++] = (value & 0x3f) | 0x80; - } - const writeLength = offset - this.x; - this.x = offset; - return writeLength; - } - - public ascii(str: string): void { - const length = str.length; - this.ensureCapacity(length); - const uint8 = this.uint8; - let x = this.x; - let pos = 0; - while (pos < length) uint8[x++] = str.charCodeAt(pos++); - this.x = x; - } -} diff --git a/src/json-joy/util/buffers/f16.ts b/src/json-joy/util/buffers/f16.ts deleted file mode 100644 index 51a415041..000000000 --- a/src/json-joy/util/buffers/f16.ts +++ /dev/null @@ -1,16 +0,0 @@ -const pow = Math.pow; - -export const decodeF16 = (binary: number): number => { - const exponent = (binary & 0x7c00) >> 10; - const fraction = binary & 0x03ff; - return ( - (binary >> 15 ? -1 : 1) * - (exponent - ? exponent === 0x1f - ? fraction - ? NaN - : Infinity - : pow(2, exponent - 15) * (1 + fraction / 0x400) - : 6.103515625e-5 * (fraction / 0x400)) - ); -}; diff --git a/src/json-joy/util/buffers/index.ts b/src/json-joy/util/buffers/index.ts deleted file mode 100644 index fcb073fef..000000000 --- a/src/json-joy/util/buffers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './types'; diff --git a/src/json-joy/util/buffers/isFloat32.ts b/src/json-joy/util/buffers/isFloat32.ts deleted file mode 100644 index 26e382346..000000000 --- a/src/json-joy/util/buffers/isFloat32.ts +++ /dev/null @@ -1,6 +0,0 @@ -const view = new DataView(new ArrayBuffer(4)); - -export const isFloat32 = (n: number): boolean => { - view.setFloat32(0, n); - return n === view.getFloat32(0); -}; diff --git a/src/json-joy/util/buffers/types.ts b/src/json-joy/util/buffers/types.ts deleted file mode 100644 index ae29727a8..000000000 --- a/src/json-joy/util/buffers/types.ts +++ /dev/null @@ -1,126 +0,0 @@ -import type {Slice} from './Slice'; - -export interface IWriter { - /** - * Uint8Array view of the current memory buffer. - */ - uint8: Uint8Array; - - /** - * DataView view of the current memory buffer. - */ - view: DataView; - - /** - * Position where last flush happened. - */ - x0: number; - - /** - * Current position in the internal buffer. - */ - x: number; - - u8(char: number): void; - u16(word: number): void; - u32(dword: number): void; - i32(dword: number): void; - u64(qword: number | bigint): void; - u8u16(u8: number, u16: number): void; - u8u32(u8: number, u32: number): void; - u8u64(u8: number, u64: number | bigint): void; - u8f32(u8: number, f64: number): void; - u8f64(u8: number, f64: number): void; - f64(dword: number): void; - - /** - * Write contents of a buffer. - * - * @param buf Buffer to copy from. - * @param length Number of octets to copy. - */ - buf(buf: Uint8Array, length: number): void; - - /** - * Write string as UTF-8. You need to call .ensureCapacity(str.length * 4) - * before calling - * - * @param str JavaScript string to encode as UTF-8 byte sequence. - */ - utf8(str: string): number; - - ascii(str: string): void; -} - -export interface IWriterGrowable { - /** @deprecated */ - reset(): void; - - /** - * Calling this method might reset the internal buffer. So, your references - * (such as `x`, `uint8`, `view`) to the internal buffer might become invalid. - * - * @param capacity How many octets to ensure are available after `x`. - */ - ensureCapacity(capacity: number): void; - move(length: number): void; - flush(): Uint8Array; - flushSlice(): Slice; - newBuffer(size: number): void; -} - -export interface IReaderBase { - /** Get current byte value without advancing the cursor. */ - peak(): number; - - /** Advance the cursor given number of octets. */ - skip(length: number): void; - - /** - * Create a new Uint8Array view of provided length starting at - * the current cursor position. - */ - buf(size: number): Uint8Array; - - u8(): number; - i8(): number; - u16(): number; - i16(): number; - u32(): number; - u64(): bigint; - i64(): bigint; - i32(): number; - f32(): number; - f64(): number; - - /** - * Decode a UTF-8 string. - * - * @param size Length of the string. - */ - utf8(size: number): string; - - ascii(length: number): string; -} - -export interface IReader extends IReaderBase { - /** - * Uint8Array view of the current memory buffer. - */ - uint8: Uint8Array; - - /** - * DataView view of the current memory buffer. - */ - view: DataView; - - /** - * Cursor in the current memory buffer. - */ - x: number; -} - -export interface IReaderResettable { - /** Set a new underlying buffer and reset cursor position to 0. */ - reset(uint8: Uint8Array): void; -} diff --git a/src/json-joy/util/buffers/utf8/CachedUtf8Decoder.ts b/src/json-joy/util/buffers/utf8/CachedUtf8Decoder.ts deleted file mode 100644 index f3c1af342..000000000 --- a/src/json-joy/util/buffers/utf8/CachedUtf8Decoder.ts +++ /dev/null @@ -1,51 +0,0 @@ -import decodeUtf8 from './decodeUtf8/v10'; -import {randomU32} from './randomU32'; - -class CacheItem { - constructor(public readonly bytes: Uint8Array, public readonly value: string) {} -} - -const enum CONST { - MAX_CACHED_STR_LEN = 31, - MAX_RECORDS_PER_SIZE = 16, -} - -export class CachedUtf8Decoder { - private readonly caches: CacheItem[][]; - - constructor() { - this.caches = []; - for (let i = 0; i < CONST.MAX_CACHED_STR_LEN; i++) this.caches.push([]); - } - - private get(bytes: Uint8Array, offset: number, size: number): string | null { - const records = this.caches[size - 1]!; - const len = records.length; - FIND_CHUNK: for (let i = 0; i < len; i++) { - const record = records[i]; - const recordBytes = record.bytes; - for (let j = 0; j < size; j++) if (recordBytes[j] !== bytes[offset + j]) continue FIND_CHUNK; - return record.value; - } - return null; - } - - private store(bytes: Uint8Array, value: string): void { - const records = this.caches[bytes.length - 1]!; - const record = new CacheItem(bytes, value); - const length = records.length; - if (length >= CONST.MAX_RECORDS_PER_SIZE) records[randomU32(0, CONST.MAX_RECORDS_PER_SIZE - 1)] = record; - else records.push(record); - } - - public decode(bytes: Uint8Array, offset: number, size: number): string { - if (!size) return ''; - const cachedValue = this.get(bytes, offset, size); - if (cachedValue !== null) return cachedValue; - const value = decodeUtf8(bytes, offset, size); - // Ensure to copy a slice of bytes because the byte may be NodeJS Buffer and Buffer#slice() returns a reference to its internal ArrayBuffer. - const copy = Uint8Array.prototype.slice.call(bytes, offset, offset + size); - this.store(copy, value); - return value; - } -} diff --git a/src/json-joy/util/buffers/utf8/decodeAscii.ts b/src/json-joy/util/buffers/utf8/decodeAscii.ts deleted file mode 100644 index 3246e6133..000000000 --- a/src/json-joy/util/buffers/utf8/decodeAscii.ts +++ /dev/null @@ -1,167 +0,0 @@ -const fromCharCode = String.fromCharCode; - -/** This code was borrowed form cbor-x under the MIT license. */ - -// MIT License - -// Copyright (c) 2020 Kris Zyp - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -export const decodeAscii = (src: Uint8Array, position: number, length: number): string | undefined => { - const bytes: number[] = []; - for (let i = 0; i < length; i++) { - const byte = src[position++]; - if (byte & 0x80) return; - bytes.push(byte); - } - return fromCharCode.apply(String, bytes); -}; - -export const decodeAsciiMax15 = (src: Uint8Array, position: number, length: number): string | undefined => { - if (length < 4) { - if (length < 2) { - if (length === 0) return ''; - else { - const a = src[position++]; - if ((a & 0x80) > 1) { - position -= 1; - return; - } - return fromCharCode(a); - } - } else { - const a = src[position++]; - const b = src[position++]; - if ((a & 0x80) > 0 || (b & 0x80) > 0) { - position -= 2; - return; - } - if (length < 3) return fromCharCode(a, b); - const c = src[position++]; - if ((c & 0x80) > 0) { - position -= 3; - return; - } - return fromCharCode(a, b, c); - } - } else { - const a = src[position++]; - const b = src[position++]; - const c = src[position++]; - const d = src[position++]; - if ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) { - position -= 4; - return; - } - if (length < 6) { - if (length === 4) return fromCharCode(a, b, c, d); - else { - const e = src[position++]; - if ((e & 0x80) > 0) { - position -= 5; - return; - } - return fromCharCode(a, b, c, d, e); - } - } else if (length < 8) { - const e = src[position++]; - const f = src[position++]; - if ((e & 0x80) > 0 || (f & 0x80) > 0) { - position -= 6; - return; - } - if (length < 7) return fromCharCode(a, b, c, d, e, f); - const g = src[position++]; - if ((g & 0x80) > 0) { - position -= 7; - return; - } - return fromCharCode(a, b, c, d, e, f, g); - } else { - const e = src[position++]; - const f = src[position++]; - const g = src[position++]; - const h = src[position++]; - if ((e & 0x80) > 0 || (f & 0x80) > 0 || (g & 0x80) > 0 || (h & 0x80) > 0) { - position -= 8; - return; - } - if (length < 10) { - if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h); - else { - const i = src[position++]; - if ((i & 0x80) > 0) { - position -= 9; - return; - } - return fromCharCode(a, b, c, d, e, f, g, h, i); - } - } else if (length < 12) { - const i = src[position++]; - const j = src[position++]; - if ((i & 0x80) > 0 || (j & 0x80) > 0) { - position -= 10; - return; - } - if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j); - const k = src[position++]; - if ((k & 0x80) > 0) { - position -= 11; - return; - } - return fromCharCode(a, b, c, d, e, f, g, h, i, j, k); - } else { - const i = src[position++]; - const j = src[position++]; - const k = src[position++]; - const l = src[position++]; - if ((i & 0x80) > 0 || (j & 0x80) > 0 || (k & 0x80) > 0 || (l & 0x80) > 0) { - position -= 12; - return; - } - if (length < 14) { - if (length === 12) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l); - else { - const m = src[position++]; - if ((m & 0x80) > 0) { - position -= 13; - return; - } - return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m); - } - } else { - const m = src[position++]; - const n = src[position++]; - if ((m & 0x80) > 0 || (n & 0x80) > 0) { - position -= 14; - return; - } - if (length < 15) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n); - const o = src[position++]; - if ((o & 0x80) > 0) { - position -= 15; - return; - } - return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); - } - } - } - } -}; diff --git a/src/json-joy/util/buffers/utf8/decodeUtf8/index.ts b/src/json-joy/util/buffers/utf8/decodeUtf8/index.ts deleted file mode 100644 index 7e9349894..000000000 --- a/src/json-joy/util/buffers/utf8/decodeUtf8/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import decodeUtf8 from './v16'; - -export {decodeUtf8}; diff --git a/src/json-joy/util/buffers/utf8/decodeUtf8/v10.ts b/src/json-joy/util/buffers/utf8/decodeUtf8/v10.ts deleted file mode 100644 index ebf8b03d0..000000000 --- a/src/json-joy/util/buffers/utf8/decodeUtf8/v10.ts +++ /dev/null @@ -1,39 +0,0 @@ -const fromCharCode = String.fromCharCode; - -export default (buf: Uint8Array, start: number, length: number): string => { - let offset = start; - const end = offset + length; - let str = ''; - while (offset < end) { - const octet1 = buf[offset++]!; - if ((octet1 & 0x80) === 0) { - str += fromCharCode(octet1); - continue; - } - const octet2 = buf[offset++]! & 0x3f; - if ((octet1 & 0xe0) === 0xc0) { - str += fromCharCode(((octet1 & 0x1f) << 6) | octet2); - continue; - } - const octet3 = buf[offset++]! & 0x3f; - if ((octet1 & 0xf0) === 0xe0) { - str += fromCharCode(((octet1 & 0x1f) << 12) | (octet2 << 6) | octet3); - continue; - } - if ((octet1 & 0xf8) === 0xf0) { - const octet4 = buf[offset++]! & 0x3f; - let unit = ((octet1 & 0x07) << 0x12) | (octet2 << 0x0c) | (octet3 << 0x06) | octet4; - if (unit > 0xffff) { - unit -= 0x10000; - const unit0 = ((unit >>> 10) & 0x3ff) | 0xd800; - unit = 0xdc00 | (unit & 0x3ff); - str += fromCharCode(unit0, unit); - } else { - str += fromCharCode(unit); - } - } else { - str += fromCharCode(octet1); - } - } - return str; -}; diff --git a/src/json-joy/util/buffers/utf8/decodeUtf8/v16.ts b/src/json-joy/util/buffers/utf8/decodeUtf8/v16.ts deleted file mode 100644 index 5953a774e..000000000 --- a/src/json-joy/util/buffers/utf8/decodeUtf8/v16.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {decodeAscii, decodeAsciiMax15} from '../decodeAscii'; -import v18 from './v18'; - -declare global { - interface Buffer { - utf8Slice(buf: Uint8Array, start: number, length: number): string - } - - interface Uint8Array { - toString(encoding?: string): string; - } -} - -type Decoder = (buf: Uint8Array, start: number, length: number) => string; - -const hasBuffer = typeof Buffer !== 'undefined'; -const utf8Slice = hasBuffer ? Buffer.prototype.utf8Slice : null; -const from = hasBuffer ? Buffer.from : null; - -const shortDecoder: Decoder = (buf, start, length) => decodeAsciiMax15(buf, start, length) ?? v18(buf, start, length); - -const midDecoder: Decoder = (buf, start, length) => decodeAscii(buf, start, length) ?? v18(buf, start, length); - -const longDecoder: Decoder = utf8Slice - ? (buf, start, length) => utf8Slice.call(buf, start, start + length) - : from - ? (buf, start, length) => - from(buf) - .subarray(start, start + length) - .toString('utf8') - : v18; - -const decoder: Decoder = (buf, start, length): string => { - if (length < 16) return shortDecoder(buf, start, length); - if (length < 32) return midDecoder(buf, start, length); - return longDecoder(buf, start, length); -}; - -export default decoder; diff --git a/src/json-joy/util/buffers/utf8/decodeUtf8/v18.ts b/src/json-joy/util/buffers/utf8/decodeUtf8/v18.ts deleted file mode 100644 index e1b518e00..000000000 --- a/src/json-joy/util/buffers/utf8/decodeUtf8/v18.ts +++ /dev/null @@ -1,36 +0,0 @@ -const fromCharCode = String.fromCharCode; - -export default (buf: Uint8Array, start: number, length: number): string => { - let offset = start; - const end = offset + length; - const points: number[] = []; - while (offset < end) { - let code = buf[offset++]!; - if ((code & 0x80) !== 0) { - const octet2 = buf[offset++]! & 0x3f; - if ((code & 0xe0) === 0xc0) { - code = ((code & 0x1f) << 6) | octet2; - } else { - const octet3 = buf[offset++]! & 0x3f; - if ((code & 0xf0) === 0xe0) { - code = ((code & 0x1f) << 12) | (octet2 << 6) | octet3; - } else { - if ((code & 0xf8) === 0xf0) { - const octet4 = buf[offset++]! & 0x3f; - let unit = ((code & 0x07) << 0x12) | (octet2 << 0x0c) | (octet3 << 0x06) | octet4; - if (unit > 0xffff) { - unit -= 0x10000; - const unit0 = ((unit >>> 10) & 0x3ff) | 0xd800; - code = 0xdc00 | (unit & 0x3ff); - points.push(unit0); - } else { - code = unit; - } - } - } - } - } - points.push(code); - } - return fromCharCode.apply(String, points); -}; diff --git a/src/json-joy/util/buffers/utf8/randomU32.ts b/src/json-joy/util/buffers/utf8/randomU32.ts deleted file mode 100644 index 1e289fa80..000000000 --- a/src/json-joy/util/buffers/utf8/randomU32.ts +++ /dev/null @@ -1,7 +0,0 @@ -let x = 1 + Math.round(Math.random() * ((-1>>>0)-1)); - -/** Generate a random 32-bit unsigned integer in the specified [min, max] range. */ -export function randomU32(min: number, max: number): number { - x ^= x << 13; x ^= x >>> 17; x ^= x << 5; - return (x >>> 0) % (max - min + 1) + min; -} diff --git a/src/json-joy/util/buffers/utf8/sharedCachedUtf8Decoder.ts b/src/json-joy/util/buffers/utf8/sharedCachedUtf8Decoder.ts deleted file mode 100644 index 86b2d4ad0..000000000 --- a/src/json-joy/util/buffers/utf8/sharedCachedUtf8Decoder.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {CachedUtf8Decoder} from './CachedUtf8Decoder'; - -export default new CachedUtf8Decoder(); diff --git a/src/snapshot/shared.ts b/src/snapshot/shared.ts index ef5e87d59..019166416 100644 --- a/src/snapshot/shared.ts +++ b/src/snapshot/shared.ts @@ -1,3 +1,3 @@ -import { Writer } from '../json-joy/util/buffers/Writer'; +import { Writer } from '@jsonjoy.com/util/lib/buffers/Writer'; export const writer = new Writer(1024 * 32); diff --git a/yarn.lock b/yarn.lock index 3a21d8bb5..e23a3a07e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -608,7 +608,7 @@ hyperdyperid "^1.2.0" thingies "^1.20.0" -"@jsonjoy.com/util@^1.0.0": +"@jsonjoy.com/util@^1.0.0", "@jsonjoy.com/util@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@jsonjoy.com/util/-/util-1.1.0.tgz#9726365362ede17405d2b521b4c782582df7ed4f" integrity sha512-Yz+xITJ3Y/w0DBISwPkBETP5/cITHXscjgQNZIkfrVz1V7/ahJY8vw+T+LZy/KtXgKuUWqu4GALAQ3bhGt9J8A== From c6e18b73d13664b263720a95353a5fc250446635 Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Apr 2024 13:26:41 +0200 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20=F0=9F=A4=96=20use=20sonic-forest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/json-joy/util/print/printTree.ts | 15 --------------- src/print/index.ts | 2 +- yarn.lock | 5 +++++ 4 files changed, 7 insertions(+), 16 deletions(-) delete mode 100644 src/json-joy/util/print/printTree.ts diff --git a/package.json b/package.json index 900183894..657952f8f 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "dependencies": { "@jsonjoy.com/json-pack": "^1.0.2", "@jsonjoy.com/util": "^1.1.0", + "sonic-forest": "^1.0.0", "tslib": "^2.0.0" }, "devDependencies": { diff --git a/src/json-joy/util/print/printTree.ts b/src/json-joy/util/print/printTree.ts deleted file mode 100644 index a054a5502..000000000 --- a/src/json-joy/util/print/printTree.ts +++ /dev/null @@ -1,15 +0,0 @@ -type Child = (tab: string) => string; - -export const printTree = (tab = '', children: (Child | null)[]): string => { - children = children.filter(Boolean); - let str = ''; - for (let i = 0; i < children.length; i++) { - const isLast = i >= children.length - 1; - const fn = children[i]; - if (!fn) continue; - const child = fn(tab + `${isLast ? ' ' : '│'} `); - const branch = child ? (isLast ? '└─' : '├─') : '│ '; - str += `\n${tab}${branch} ${child}`; - } - return str; -}; diff --git a/src/print/index.ts b/src/print/index.ts index e55aca864..3b8bb45d5 100644 --- a/src/print/index.ts +++ b/src/print/index.ts @@ -1,4 +1,4 @@ -import { printTree } from '../json-joy/util/print/printTree'; +import { printTree } from 'sonic-forest/lib/print/printTree'; import { basename } from '../node-to-fsa/util'; import type { FsSynchronousApi } from '../node/types'; import type { IDirent } from '../node/types/misc'; diff --git a/yarn.lock b/yarn.lock index e23a3a07e..d70b65d88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6379,6 +6379,11 @@ socks@^2.6.2: ip-address "^9.0.5" smart-buffer "^4.2.0" +sonic-forest@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sonic-forest/-/sonic-forest-1.0.0.tgz#b0b77d9bca76434f4ef87b61042d041da63f3be5" + integrity sha512-yFO2N4uTUFtgKLw03WWFpN1iEwZySweMsa18XN3Kt0yYrlmVHunC2ZgM+437zDoKISAJHcH3Cg18U7d6tuSgSQ== + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" From 0509f1548470e7a830fcd6f0a285b8e715934669 Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Apr 2024 13:27:41 +0200 Subject: [PATCH 4/5] =?UTF-8?q?chore:=20=F0=9F=A4=96=20remove=20/src/json-?= =?UTF-8?q?joy/=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/json-joy/json-pointer/index.ts | 1 - src/json-joy/json-pointer/types.ts | 2 -- 2 files changed, 3 deletions(-) delete mode 100644 src/json-joy/json-pointer/index.ts delete mode 100644 src/json-joy/json-pointer/types.ts diff --git a/src/json-joy/json-pointer/index.ts b/src/json-joy/json-pointer/index.ts deleted file mode 100644 index fcb073fef..000000000 --- a/src/json-joy/json-pointer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './types'; diff --git a/src/json-joy/json-pointer/types.ts b/src/json-joy/json-pointer/types.ts deleted file mode 100644 index 8c0860c59..000000000 --- a/src/json-joy/json-pointer/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type PathStep = string | number; -export type Path = readonly PathStep[]; From 0dfd7bbaf63282bef8d190a32e9c215bd8c2e496 Mon Sep 17 00:00:00 2001 From: streamich Date: Sat, 27 Apr 2024 13:32:09 +0200 Subject: [PATCH 5/5] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20describe=20mem?= =?UTF-8?q?fs()=20helper=20in=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/node/usage.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/node/usage.md b/docs/node/usage.md index 3823a18e8..e9e49f5c0 100644 --- a/docs/node/usage.md +++ b/docs/node/usage.md @@ -39,6 +39,16 @@ vol.writeFileSync('/foo', 'bar'); expect(vol.toJSON()).toEqual({ '/foo': 'bar' }); ``` +Construct new `memfs` volumes: + +```js +import { memfs } from 'memfs'; + +const { fs, vol } = memfs({ '/foo': 'bar' }); + +fs.readFileSync('/foo', 'utf8'); // bar +``` + Create as many filesystem volumes as you need: ```js