@jsonjoy.com/json-pack
Version:
High-performance JSON serialization library
253 lines • 8.64 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IonDecoderBase = void 0;
const tslib_1 = require("tslib");
const Reader_1 = require("@jsonjoy.com/buffers/lib/Reader");
const sharedCachedUtf8Decoder_1 = tslib_1.__importDefault(require("@jsonjoy.com/buffers/lib/utf8/sharedCachedUtf8Decoder"));
const Import_1 = require("./Import");
class IonDecoderBase {
constructor(reader) {
this.reader = (reader ?? new Reader_1.Reader());
this.utf8Decoder = sharedCachedUtf8Decoder_1.default;
}
val() {
const typedesc = this.reader.u8();
const type = (typedesc >> 4) & 0xf;
const length = typedesc & 0xf;
switch (type) {
case 0 /* TYPE.NULL */:
return this.readNull(length);
case 1 /* TYPE.BOOL */:
return this.readBool(length);
case 2 /* TYPE.UINT */:
return this.readUint(length);
case 3 /* TYPE.NINT */:
return this.readNint(length);
case 4 /* TYPE.FLOT */:
return this.readFloat(length);
case 8 /* TYPE.STRI */:
return this.readString(length);
case 10 /* TYPE.BINA */:
return this.readBinary(length);
case 11 /* TYPE.LIST */:
return this.readList(length);
case 13 /* TYPE.STRU */:
return this.readStruct(length);
case 14 /* TYPE.ANNO */:
return this.readAnnotation(length);
default:
throw new Error(`Unknown Ion type: 0x${type.toString(16)}`);
}
}
readNull(length) {
if (length === 15)
return null;
if (length === 0) {
// NOP padding - skip bytes
this.val(); // Read and discard next value
return null;
}
if (length === 14) {
// Extended length NOP padding
const padLength = this.readVUint();
this.reader.x += padLength;
this.val(); // Read and discard next value
return null;
}
// Regular NOP padding
this.reader.x += length;
this.val(); // Read and discard next value
return null;
}
readBool(length) {
if (length === 15)
return null;
if (length === 0)
return false;
if (length === 1)
return true;
throw new Error(`Invalid bool length: ${length}`);
}
readUint(length) {
if (length === 15)
return null;
if (length === 0)
return 0;
let value = 0;
for (let i = 0; i < length; i++) {
value = value * 256 + this.reader.u8();
}
return value;
}
readNint(length) {
if (length === 15)
return null;
if (length === 0)
throw new Error('Negative zero is illegal');
let value = 0;
for (let i = 0; i < length; i++) {
value = value * 256 + this.reader.u8();
}
return -value;
}
readFloat(length) {
if (length === 15)
return null;
if (length === 0)
return 0.0;
if (length === 4)
return this.reader.f32();
if (length === 8)
return this.reader.f64();
throw new Error(`Unsupported float length: ${length}`);
}
readString(length) {
if (length === 15)
return null;
let actualLength = length;
if (length === 14) {
actualLength = this.readVUint();
}
if (actualLength === 0)
return '';
return this.reader.utf8(actualLength);
}
readBinary(length) {
if (length === 15)
return null;
let actualLength = length;
if (length === 14) {
actualLength = this.readVUint();
}
if (actualLength === 0)
return new Uint8Array(0);
return this.reader.buf(actualLength);
}
readList(length) {
if (length === 15)
return null;
let actualLength = length;
if (length === 14) {
actualLength = this.readVUint();
}
if (actualLength === 0)
return [];
const endPos = this.reader.x + actualLength;
const list = [];
while (this.reader.x < endPos) {
list.push(this.val());
}
if (this.reader.x !== endPos) {
throw new Error('List parsing error: incorrect length');
}
return list;
}
readStruct(length) {
if (length === 15)
return null;
let actualLength = length;
if (length === 14) {
actualLength = this.readVUint();
}
if (actualLength === 0)
return {};
const endPos = this.reader.x + actualLength;
const struct = {};
while (this.reader.x < endPos) {
const fieldNameId = this.readVUint();
const fieldName = this.getSymbolText(fieldNameId);
const fieldValue = this.val();
struct[fieldName] = fieldValue;
}
if (this.reader.x !== endPos) {
throw new Error('Struct parsing error: incorrect length');
}
return struct;
}
readAnnotation(length) {
if (length < 3) {
throw new Error('Annotation wrapper must have at least 3 bytes');
}
let _actualLength = length;
if (length === 14) {
_actualLength = this.readVUint();
}
const annotLength = this.readVUint();
const endAnnotPos = this.reader.x + annotLength;
// Skip annotations for now - just read and ignore them
while (this.reader.x < endAnnotPos) {
this.readVUint(); // Skip annotation symbol ID
}
if (this.reader.x !== endAnnotPos) {
throw new Error('Annotation parsing error: incorrect annotation length');
}
// Return the actual value, ignoring annotations
return this.val();
}
readVUint() {
let value = 0;
let byte;
do {
byte = this.reader.u8();
value = (value << 7) | (byte & 0x7f);
} while ((byte & 0x80) === 0);
return value;
}
readVInt() {
const firstByte = this.reader.u8();
// Single byte case
if (firstByte & 0x80) {
const sign = firstByte & 0x40 ? -1 : 1;
const magnitude = firstByte & 0x3f;
return sign * magnitude;
}
// Multi-byte case
const sign = firstByte & 0x40 ? -1 : 1;
let magnitude = firstByte & 0x3f;
let byte;
do {
byte = this.reader.u8();
magnitude = (magnitude << 7) | (byte & 0x7f);
} while ((byte & 0x80) === 0);
return sign * magnitude;
}
getSymbolText(symbolId) {
if (!this.symbols) {
throw new Error('No symbol table available');
}
const symbol = this.symbols.getText(symbolId);
if (symbol === undefined) {
throw new Error(`Unknown symbol ID: ${symbolId}`);
}
return symbol;
}
validateBVM() {
const bvm = this.reader.u32();
if (bvm !== 0xe00100ea) {
throw new Error(`Invalid Ion Binary Version Marker: 0x${bvm.toString(16)}`);
}
}
readSymbolTable() {
// Check if there's enough data and if the next byte indicates an annotation
if (this.reader.x < this.reader.uint8.length) {
const nextByte = this.reader.peak();
const type = (nextByte >> 4) & 0xf;
if (type === 14 /* TYPE.ANNO */) {
// This might be a symbol table annotation
const annotValue = this.val();
// The annotated value should be a struct with a 'symbols' field
if (annotValue && typeof annotValue === 'object' && !Array.isArray(annotValue)) {
const symbolsKey = 'symbols'; // This is what symbol ID 7 maps to
const obj = annotValue;
if (symbolsKey in obj && Array.isArray(obj[symbolsKey])) {
// Update the symbol table with new symbols
const newSymbols = obj[symbolsKey];
this.symbols = new Import_1.Import(this.symbols || null, newSymbols);
}
}
}
}
}
}
exports.IonDecoderBase = IonDecoderBase;
//# sourceMappingURL=IonDecoderBase.js.map