@jsonjoy.com/json-pack
Version:
High-performance JSON serialization library
394 lines • 12.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CborDecoder = void 0;
const CborDecoderBase_1 = require("./CborDecoderBase");
const JsonPackValue_1 = require("../JsonPackValue");
class CborDecoder extends CborDecoderBase_1.CborDecoderBase {
// -------------------------------------------------------------- Map reading
readAsMap() {
const octet = this.reader.u8();
const major = octet >> 5;
const minor = octet & 31 /* CONST.MINOR_MASK */;
switch (major) {
case 5 /* MAJOR.MAP */:
return this.readMap(minor);
default:
throw 0 /* ERROR.UNEXPECTED_MAJOR */;
}
}
readMap(minor) {
const length = this.readMinorLen(minor);
if (length >= 0)
return this.readMapRaw(length);
else
return this.readMapIndef();
}
readMapRaw(length) {
const map = new Map();
for (let i = 0; i < length; i++) {
const key = this.readAny();
const value = this.readAny();
map.set(key, value);
}
return map;
}
readMapIndef() {
const map = new Map();
while (this.reader.peak() !== 255 /* CONST.END */) {
const key = this.readAny();
if (this.reader.peak() === 255 /* CONST.END */)
throw 7 /* ERROR.UNEXPECTED_OBJ_BREAK */;
const value = this.readAny();
map.set(key, value);
}
this.reader.x++;
return map;
}
// ----------------------------------------------------------- Value skipping
skipN(n) {
for (let i = 0; i < n; i++)
this.skipAny();
}
skipAny() {
this.skipAnyRaw(this.reader.u8());
}
skipAnyRaw(octet) {
const major = octet >> 5;
const minor = octet & 31 /* CONST.MINOR_MASK */;
switch (major) {
case 0 /* MAJOR.UIN */:
case 1 /* MAJOR.NIN */:
this.skipUNint(minor);
break;
case 2 /* MAJOR.BIN */:
this.skipBin(minor);
break;
case 3 /* MAJOR.STR */:
this.skipStr(minor);
break;
case 4 /* MAJOR.ARR */:
this.skipArr(minor);
break;
case 5 /* MAJOR.MAP */:
this.skipObj(minor);
break;
case 7 /* MAJOR.TKN */:
this.skipTkn(minor);
break;
case 6 /* MAJOR.TAG */:
this.skipTag(minor);
break;
}
}
skipMinorLen(minor) {
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 1 /* ERROR.UNEXPECTED_MINOR */;
}
}
// --------------------------------------------------------- Integer skipping
skipUNint(minor) {
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 1 /* ERROR.UNEXPECTED_MINOR */;
}
}
// ---------------------------------------------------------- Binary skipping
skipBin(minor) {
const length = this.skipMinorLen(minor);
if (length >= 0)
this.reader.skip(length);
else {
while (this.reader.peak() !== 255 /* CONST.END */)
this.skipBinChunk();
this.reader.x++;
}
}
skipBinChunk() {
const octet = this.reader.u8();
const major = octet >> 5;
const minor = octet & 31 /* CONST.MINOR_MASK */;
if (major !== 2 /* MAJOR.BIN */)
throw 2 /* ERROR.UNEXPECTED_BIN_CHUNK_MAJOR */;
if (minor > 27)
throw 3 /* ERROR.UNEXPECTED_BIN_CHUNK_MINOR */;
this.skipBin(minor);
}
// ---------------------------------------------------------- String skipping
skipStr(minor) {
const length = this.skipMinorLen(minor);
if (length >= 0)
this.reader.skip(length);
else {
while (this.reader.peak() !== 255 /* CONST.END */)
this.skipStrChunk();
this.reader.x++;
}
}
skipStrChunk() {
const octet = this.reader.u8();
const major = octet >> 5;
const minor = octet & 31 /* CONST.MINOR_MASK */;
if (major !== 3 /* MAJOR.STR */)
throw 4 /* ERROR.UNEXPECTED_STR_CHUNK_MAJOR */;
if (minor > 27)
throw 5 /* ERROR.UNEXPECTED_STR_CHUNK_MINOR */;
this.skipStr(minor);
}
// ----------------------------------------------------------- Array skipping
skipArr(minor) {
const length = this.skipMinorLen(minor);
if (length >= 0)
this.skipN(length);
else {
while (this.reader.peak() !== 255 /* CONST.END */)
this.skipAny();
this.reader.x++;
}
}
// ---------------------------------------------------------- Object skipping
skipObj(minor) {
const length = this.readMinorLen(minor);
if (length >= 0)
return this.skipN(length * 2);
else {
while (this.reader.peak() !== 255 /* CONST.END */) {
this.skipAny();
if (this.reader.peak() === 255 /* CONST.END */)
throw 7 /* ERROR.UNEXPECTED_OBJ_BREAK */;
this.skipAny();
}
this.reader.x++;
}
}
// ------------------------------------------------------------- Tag skipping
skipTag(minor) {
const length = this.skipMinorLen(minor);
if (length < 0)
throw 1 /* ERROR.UNEXPECTED_MINOR */;
this.skipAny();
}
// ----------------------------------------------------------- Token skipping
skipTkn(minor) {
switch (minor) {
case 0xf8 & 31 /* CONST.MINOR_MASK */:
this.reader.skip(1);
return;
case 0xf9 & 31 /* CONST.MINOR_MASK */:
this.reader.skip(2);
return;
case 0xfa & 31 /* CONST.MINOR_MASK */:
this.reader.skip(4);
return;
case 0xfb & 31 /* CONST.MINOR_MASK */:
this.reader.skip(8);
return;
}
if (minor <= 23)
return;
throw 1 /* 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.
*/
validate(value, offset = 0, size = value.length) {
this.reader.reset(value);
this.reader.x = offset;
const start = offset;
this.skipAny();
const end = this.reader.x;
if (end - start !== size)
throw 8 /* ERROR.INVALID_SIZE */;
}
// -------------------------------------------- One level reading - any value
decodeLevel(value) {
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.
*/
readLevel() {
const octet = this.reader.u8();
const major = octet >> 5;
const minor = octet & 31 /* CONST.MINOR_MASK */;
switch (major) {
case 4 /* MAJOR.ARR */:
return this.readArrLevel(minor);
case 5 /* 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.
*/
readPrimitiveOrVal() {
const octet = this.reader.peak();
const major = octet >> 5;
switch (major) {
case 4 /* MAJOR.ARR */:
case 5 /* MAJOR.MAP */:
return this.readAsValue();
default:
return this.readAny();
}
}
readAsValue() {
const reader = this.reader;
const start = reader.x;
this.skipAny();
const end = reader.x;
return new JsonPackValue_1.JsonPackValue(reader.uint8.subarray(start, end));
}
// ----------------------------------------------- One level reading - object
readObjLevel(minor) {
const length = this.readMinorLen(minor);
if (length >= 0)
return this.readObjRawLevel(length);
else
return this.readObjIndefLevel();
}
readObjRawLevel(length) {
const obj = {};
for (let i = 0; i < length; i++) {
const key = this.key();
const value = this.readPrimitiveOrVal();
obj[key] = value;
}
return obj;
}
readObjIndefLevel() {
const obj = {};
while (this.reader.peak() !== 255 /* CONST.END */) {
const key = this.key();
if (this.reader.peak() === 255 /* CONST.END */)
throw 7 /* ERROR.UNEXPECTED_OBJ_BREAK */;
const value = this.readPrimitiveOrVal();
obj[key] = value;
}
this.reader.x++;
return obj;
}
// ------------------------------------------------ One level reading - array
readArrLevel(minor) {
const length = this.readMinorLen(minor);
if (length >= 0)
return this.readArrRawLevel(length);
return this.readArrIndefLevel();
}
readArrRawLevel(length) {
const arr = [];
for (let i = 0; i < length; i++)
arr.push(this.readPrimitiveOrVal());
return arr;
}
readArrIndefLevel() {
const arr = [];
while (this.reader.peak() !== 255 /* CONST.END */)
arr.push(this.readPrimitiveOrVal());
this.reader.x++;
return arr;
}
// ---------------------------------------------------------- Shallow reading
readHdr(expectedMajor) {
const octet = this.reader.u8();
const major = octet >> 5;
if (major !== expectedMajor)
throw 0 /* ERROR.UNEXPECTED_MAJOR */;
const minor = octet & 31 /* 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 1 /* ERROR.UNEXPECTED_MINOR */;
}
readStrHdr() {
return this.readHdr(3 /* MAJOR.STR */);
}
readObjHdr() {
return this.readHdr(5 /* MAJOR.MAP */);
}
readArrHdr() {
return this.readHdr(4 /* MAJOR.ARR */);
}
findKey(key) {
const size = this.readObjHdr();
for (let i = 0; i < size; i++) {
const k = this.key();
if (k === key)
return this;
this.skipAny();
}
throw 9 /* ERROR.KEY_NOT_FOUND */;
}
findIndex(index) {
const size = this.readArrHdr();
if (index >= size)
throw 10 /* ERROR.INDEX_OUT_OF_BOUNDS */;
for (let i = 0; i < index; i++)
this.skipAny();
return this;
}
find(path) {
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;
}
}
exports.CborDecoder = CborDecoder;
//# sourceMappingURL=CborDecoder.js.map