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"