364 lines
12 KiB
JavaScript
364 lines
12 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.BsonEncoder = void 0;
|
||
|
const values_1 = require("./values");
|
||
|
class BsonEncoder {
|
||
|
constructor(writer) {
|
||
|
this.writer = writer;
|
||
|
}
|
||
|
encode(value) {
|
||
|
const writer = this.writer;
|
||
|
writer.reset();
|
||
|
this.writeAny(value);
|
||
|
return writer.flush();
|
||
|
}
|
||
|
writeAny(value) {
|
||
|
switch (typeof value) {
|
||
|
case 'object': {
|
||
|
if (value === null)
|
||
|
throw new Error('NOT_OBJ');
|
||
|
return this.writeObj(value);
|
||
|
}
|
||
|
}
|
||
|
throw new Error('NOT_OBJ');
|
||
|
}
|
||
|
writeNull() {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeUndef() {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeBoolean(bool) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeNumber(num) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeInteger(int) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeUInteger(uint) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeInt32(int) {
|
||
|
const writer = this.writer;
|
||
|
writer.ensureCapacity(4);
|
||
|
writer.view.setInt32(writer.x, int, true);
|
||
|
writer.x += 4;
|
||
|
}
|
||
|
writeInt64(int) {
|
||
|
const writer = this.writer;
|
||
|
writer.ensureCapacity(8);
|
||
|
writer.view.setBigInt64(writer.x, BigInt(int), true);
|
||
|
writer.x += 8;
|
||
|
}
|
||
|
writeFloat(float) {
|
||
|
const writer = this.writer;
|
||
|
writer.ensureCapacity(4);
|
||
|
writer.view.setFloat64(writer.x, float, true);
|
||
|
writer.x += 8;
|
||
|
}
|
||
|
writeBigInt(int) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeBin(buf) {
|
||
|
const length = buf.length;
|
||
|
this.writeInt32(length);
|
||
|
const writer = this.writer;
|
||
|
writer.u8(0);
|
||
|
writer.buf(buf, length);
|
||
|
}
|
||
|
writeStr(str) {
|
||
|
const writer = this.writer;
|
||
|
const length = str.length;
|
||
|
const maxSize = 4 + 1 + 4 * length;
|
||
|
writer.ensureCapacity(maxSize);
|
||
|
const x = writer.x;
|
||
|
this.writeInt32(length + 1);
|
||
|
const bytesWritten = writer.utf8(str);
|
||
|
writer.u8(0);
|
||
|
if (bytesWritten !== length) {
|
||
|
writer.view.setInt32(x, bytesWritten + 1, true);
|
||
|
}
|
||
|
}
|
||
|
writeAsciiStr(str) {
|
||
|
throw new Error('Method not implemented.');
|
||
|
}
|
||
|
writeArr(arr) {
|
||
|
this.writeObj(arr);
|
||
|
}
|
||
|
writeObj(obj) {
|
||
|
const writer = this.writer;
|
||
|
writer.ensureCapacity(8);
|
||
|
const x0 = writer.x0;
|
||
|
const dx = writer.x - x0;
|
||
|
writer.x += 4;
|
||
|
const keys = Object.keys(obj);
|
||
|
const length = keys.length;
|
||
|
for (let i = 0; i < length; i++) {
|
||
|
const key = keys[i];
|
||
|
const value = obj[key];
|
||
|
this.writeKey(key, value);
|
||
|
}
|
||
|
writer.u8(0);
|
||
|
const x = writer.x0 + dx;
|
||
|
const size = writer.x - x;
|
||
|
writer.view.setUint32(x, size, true);
|
||
|
}
|
||
|
writeCString(str) {
|
||
|
const writer = this.writer;
|
||
|
const length = str.length;
|
||
|
writer.ensureCapacity(1 + 4 * length);
|
||
|
const uint8 = writer.uint8;
|
||
|
let x = writer.x;
|
||
|
let pos = 0;
|
||
|
while (pos < length) {
|
||
|
let value = str.charCodeAt(pos++);
|
||
|
if ((value & 0xffffff80) === 0) {
|
||
|
if (!value)
|
||
|
break;
|
||
|
uint8[x++] = value;
|
||
|
continue;
|
||
|
}
|
||
|
else if ((value & 0xfffff800) === 0) {
|
||
|
const octet = ((value >> 6) & 0x1f) | 0xc0;
|
||
|
if (!octet)
|
||
|
break;
|
||
|
uint8[x++] = octet;
|
||
|
}
|
||
|
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) {
|
||
|
const octet1 = ((value >> 12) & 0x0f) | 0xe0;
|
||
|
const octet2 = ((value >> 6) & 0x3f) | 0x80;
|
||
|
if (!octet1 || !octet2)
|
||
|
throw new Error('INVALID_CSTRING');
|
||
|
uint8[x++] = octet1;
|
||
|
uint8[x++] = octet2;
|
||
|
}
|
||
|
else {
|
||
|
const octet1 = ((value >> 18) & 0x07) | 0xf0;
|
||
|
const octet2 = ((value >> 12) & 0x3f) | 0x80;
|
||
|
const octet3 = ((value >> 6) & 0x3f) | 0x80;
|
||
|
if (!octet1 || !octet2 || !octet3)
|
||
|
throw new Error('INVALID_CSTRING');
|
||
|
uint8[x++] = octet1;
|
||
|
uint8[x++] = octet2;
|
||
|
uint8[x++] = octet3;
|
||
|
}
|
||
|
}
|
||
|
const octet = (value & 0x3f) | 0x80;
|
||
|
if (!octet)
|
||
|
break;
|
||
|
uint8[x++] = octet;
|
||
|
}
|
||
|
uint8[x++] = 0;
|
||
|
writer.x = x;
|
||
|
}
|
||
|
writeObjectId(id) {
|
||
|
const writer = this.writer;
|
||
|
writer.ensureCapacity(12);
|
||
|
const uint8 = writer.uint8;
|
||
|
const x = writer.x;
|
||
|
const { timestamp, process, counter } = id;
|
||
|
uint8[x + 0] = timestamp >>> 24;
|
||
|
uint8[x + 1] = (timestamp >>> 16) & 0xff;
|
||
|
uint8[x + 2] = (timestamp >>> 8) & 0xff;
|
||
|
uint8[x + 3] = timestamp & 0xff;
|
||
|
uint8[x + 4] = process & 0xff;
|
||
|
uint8[x + 5] = (process >>> 8) & 0xff;
|
||
|
uint8[x + 6] = (process >>> 16) & 0xff;
|
||
|
uint8[x + 7] = (process >>> 24) & 0xff;
|
||
|
let lo32 = process | 0;
|
||
|
if (lo32 < 0)
|
||
|
lo32 += 4294967296;
|
||
|
const hi32 = (process - lo32) / 4294967296;
|
||
|
uint8[x + 8] = hi32 & 0xff;
|
||
|
uint8[x + 9] = counter >>> 16;
|
||
|
uint8[x + 10] = (counter >>> 8) & 0xff;
|
||
|
uint8[x + 11] = counter & 0xff;
|
||
|
writer.x += 12;
|
||
|
}
|
||
|
writeKey(key, value) {
|
||
|
const writer = this.writer;
|
||
|
switch (typeof value) {
|
||
|
case 'number': {
|
||
|
const isFloat = Math.floor(value) !== value;
|
||
|
if (isFloat) {
|
||
|
writer.u8(0x01);
|
||
|
this.writeCString(key);
|
||
|
this.writeFloat(value);
|
||
|
break;
|
||
|
}
|
||
|
if (value <= 2147483647 && value >= -2147483648) {
|
||
|
writer.u8(0x10);
|
||
|
this.writeCString(key);
|
||
|
this.writeInt32(value);
|
||
|
break;
|
||
|
}
|
||
|
writer.u8(0x12);
|
||
|
this.writeCString(key);
|
||
|
this.writeInt64(value);
|
||
|
break;
|
||
|
}
|
||
|
case 'string': {
|
||
|
writer.u8(0x02);
|
||
|
this.writeCString(key);
|
||
|
this.writeStr(value);
|
||
|
break;
|
||
|
}
|
||
|
case 'object': {
|
||
|
if (value === null) {
|
||
|
writer.u8(0x0a);
|
||
|
this.writeCString(key);
|
||
|
break;
|
||
|
}
|
||
|
const constructor = value.constructor;
|
||
|
switch (constructor) {
|
||
|
case Object: {
|
||
|
writer.u8(0x03);
|
||
|
this.writeCString(key);
|
||
|
this.writeObj(value);
|
||
|
break;
|
||
|
}
|
||
|
case Array: {
|
||
|
writer.u8(0x04);
|
||
|
this.writeCString(key);
|
||
|
this.writeObj(value);
|
||
|
break;
|
||
|
}
|
||
|
case Uint8Array: {
|
||
|
writer.u8(0x05);
|
||
|
this.writeCString(key);
|
||
|
this.writeBin(value);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonObjectId: {
|
||
|
writer.u8(0x07);
|
||
|
this.writeCString(key);
|
||
|
this.writeObjectId(value);
|
||
|
break;
|
||
|
}
|
||
|
case Date: {
|
||
|
writer.u8(0x09);
|
||
|
this.writeCString(key);
|
||
|
writer.ensureCapacity(8);
|
||
|
writer.view.setBigUint64(writer.x, BigInt(value.getTime()), true);
|
||
|
writer.x += 8;
|
||
|
break;
|
||
|
}
|
||
|
case RegExp: {
|
||
|
writer.u8(0x0b);
|
||
|
this.writeCString(key);
|
||
|
this.writeCString(value.source);
|
||
|
this.writeCString(value.flags);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonDbPointer: {
|
||
|
writer.u8(0x0c);
|
||
|
this.writeCString(key);
|
||
|
const pointer = value;
|
||
|
this.writeStr(pointer.name);
|
||
|
this.writeObjectId(pointer.id);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonJavascriptCode: {
|
||
|
writer.u8(0x0d);
|
||
|
this.writeCString(key);
|
||
|
this.writeStr(value.code);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonInt32: {
|
||
|
writer.u8(0x10);
|
||
|
this.writeCString(key);
|
||
|
this.writeInt32(value.value);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonInt64: {
|
||
|
writer.u8(0x12);
|
||
|
this.writeCString(key);
|
||
|
this.writeInt64(value.value);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonFloat: {
|
||
|
writer.u8(0x01);
|
||
|
this.writeCString(key);
|
||
|
this.writeFloat(value.value);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonTimestamp: {
|
||
|
writer.u8(0x11);
|
||
|
this.writeCString(key);
|
||
|
const ts = value;
|
||
|
this.writeInt32(ts.increment);
|
||
|
this.writeInt32(ts.timestamp);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonDecimal128: {
|
||
|
writer.u8(0x13);
|
||
|
this.writeCString(key);
|
||
|
const dec = value;
|
||
|
if (dec.data.length !== 16)
|
||
|
throw new Error('INVALID_DECIMAL128');
|
||
|
writer.buf(dec.data, 16);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonMinKey: {
|
||
|
writer.u8(0xff);
|
||
|
this.writeCString(key);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonMaxKey: {
|
||
|
writer.u8(0x7f);
|
||
|
this.writeCString(key);
|
||
|
break;
|
||
|
}
|
||
|
case values_1.BsonBinary: {
|
||
|
writer.u8(0x05);
|
||
|
this.writeCString(key);
|
||
|
const bin = value;
|
||
|
const length = bin.data.length;
|
||
|
this.writeInt32(length);
|
||
|
writer.u8(bin.subtype);
|
||
|
writer.buf(bin.data, length);
|
||
|
break;
|
||
|
}
|
||
|
default: {
|
||
|
writer.u8(0x03);
|
||
|
this.writeCString(key);
|
||
|
this.writeObj(value);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case 'boolean': {
|
||
|
writer.u8(0x08);
|
||
|
this.writeCString(key);
|
||
|
writer.u8(+value);
|
||
|
break;
|
||
|
}
|
||
|
case 'undefined': {
|
||
|
writer.u8(0x06);
|
||
|
this.writeCString(key);
|
||
|
break;
|
||
|
}
|
||
|
case 'symbol': {
|
||
|
writer.u8(0x0e);
|
||
|
this.writeCString(key);
|
||
|
this.writeStr(value.description || '');
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
exports.BsonEncoder = BsonEncoder;
|
||
|
//# sourceMappingURL=BsonEncoder.js.map
|