@jsonjoy.com/json-pack
Version:
High-performance JSON serialization library
187 lines • 6.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BsonDecoder = void 0;
const Reader_1 = require("@jsonjoy.com/buffers/lib/Reader");
const values_1 = require("./values");
class BsonDecoder {
constructor(reader = new Reader_1.Reader()) {
this.reader = reader;
}
read(uint8) {
this.reader.reset(uint8);
return this.readDocument();
}
decode(uint8) {
this.reader.reset(uint8);
return this.readDocument();
}
readAny() {
return this.readDocument();
}
readDocument() {
const reader = this.reader;
const documentSize = reader.view.getInt32(reader.x, true);
reader.x += 4;
const startPos = reader.x;
const endPos = startPos + documentSize - 4 - 1;
const obj = {};
while (reader.x < endPos) {
const elementType = reader.u8();
if (elementType === 0)
break;
const key = this.readCString();
const value = this.readElementValue(elementType);
obj[key] = value;
}
if (reader.x <= endPos) {
reader.x = startPos + documentSize - 4;
}
return obj;
}
readCString() {
const reader = this.reader;
const uint8 = reader.uint8;
const x = reader.x;
let length = 0;
while (uint8[x + length] !== 0) {
length++;
}
if (length === 0) {
reader.x++;
return '';
}
const str = reader.utf8(length);
reader.x++;
return str;
}
readString() {
const reader = this.reader;
const length = reader.view.getInt32(reader.x, true);
reader.x += 4;
if (length <= 0) {
throw new Error('Invalid string length');
}
const str = reader.utf8(length - 1);
reader.x++;
return str;
}
readElementValue(type) {
const reader = this.reader;
switch (type) {
case 0x01:
const doubleVal = reader.view.getFloat64(reader.x, true);
reader.x += 8;
return doubleVal;
case 0x02:
return this.readString();
case 0x03:
return this.readDocument();
case 0x04:
return this.readArray();
case 0x05:
return this.readBinary();
case 0x06:
return undefined;
case 0x07:
return this.readObjectId();
case 0x08:
return reader.u8() === 1;
case 0x09:
const dateVal = reader.view.getBigInt64(reader.x, true);
reader.x += 8;
return new Date(Number(dateVal));
case 0x0a:
return null;
case 0x0b:
return this.readRegex();
case 0x0c:
return this.readDbPointer();
case 0x0d:
return new values_1.BsonJavascriptCode(this.readString());
case 0x0e:
return Symbol(this.readString());
case 0x0f:
return this.readCodeWithScope();
case 0x10:
const int32Val = reader.view.getInt32(reader.x, true);
reader.x += 4;
return int32Val;
case 0x11:
return this.readTimestamp();
case 0x12:
const int64Val = reader.view.getBigInt64(reader.x, true);
reader.x += 8;
return Number(int64Val);
case 0x13:
return this.readDecimal128();
case 0xff:
return new values_1.BsonMinKey();
case 0x7f:
return new values_1.BsonMaxKey();
default:
throw new Error(`Unsupported BSON type: 0x${type.toString(16)}`);
}
}
readArray() {
const doc = this.readDocument();
const keys = Object.keys(doc).sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
return keys.map((key) => doc[key]);
}
readBinary() {
const reader = this.reader;
const length = reader.view.getInt32(reader.x, true);
reader.x += 4;
const subtype = reader.u8();
const data = reader.buf(length);
if (subtype === 0) {
return data;
}
return new values_1.BsonBinary(subtype, data);
}
readObjectId() {
const reader = this.reader;
const uint8 = reader.uint8;
const x = reader.x;
const timestamp = (uint8[x] << 24) | (uint8[x + 1] << 16) | (uint8[x + 2] << 8) | uint8[x + 3];
const processLo = uint8[x + 4] | (uint8[x + 5] << 8) | (uint8[x + 6] << 16) | (uint8[x + 7] << 24);
const processHi = uint8[x + 8];
const processLoUnsigned = processLo >>> 0;
const process = processLoUnsigned + processHi * 0x100000000;
const counter = (uint8[x + 9] << 16) | (uint8[x + 10] << 8) | uint8[x + 11];
reader.x += 12;
return new values_1.BsonObjectId(timestamp, process, counter);
}
readRegex() {
const pattern = this.readCString();
const flags = this.readCString();
return new RegExp(pattern, flags);
}
readDbPointer() {
const name = this.readString();
const id = this.readObjectId();
return new values_1.BsonDbPointer(name, id);
}
readCodeWithScope() {
const reader = this.reader;
const totalLength = reader.view.getInt32(reader.x, true);
reader.x += 4;
const code = this.readString();
const scope = this.readDocument();
return new values_1.BsonJavascriptCodeWithScope(code, scope);
}
readTimestamp() {
const reader = this.reader;
const increment = reader.view.getInt32(reader.x, true);
reader.x += 4;
const timestamp = reader.view.getInt32(reader.x, true);
reader.x += 4;
return new values_1.BsonTimestamp(increment, timestamp);
}
readDecimal128() {
const reader = this.reader;
const data = reader.buf(16);
return new values_1.BsonDecimal128(data);
}
}
exports.BsonDecoder = BsonDecoder;
//# sourceMappingURL=BsonDecoder.js.map