aboutsummaryrefslogtreecommitdiff
path: root/node_modules/bser/index.js
diff options
context:
space:
mode:
authorJoel Kronqvist <work.joelkronqvist@pm.me>2022-03-11 20:46:06 +0200
committerJoel Kronqvist <work.joelkronqvist@pm.me>2022-03-11 20:46:06 +0200
commit080c5819d87b933816d724a83f3bf4f1686770a7 (patch)
tree4a2ccc68b27edf7d4cbc586c932cc7542b655e19 /node_modules/bser/index.js
parent5ac7049a9d30733165cc212dee308163c2a14644 (diff)
parentd003b82235a9329f912522a2f70aa950dfce4998 (diff)
downloadLYLLRuoka-080c5819d87b933816d724a83f3bf4f1686770a7.tar.gz
LYLLRuoka-080c5819d87b933816d724a83f3bf4f1686770a7.zip
Merge branch 'master' of https://github.com/JoelHMikael/FoodJS
Updating remote changes
Diffstat (limited to 'node_modules/bser/index.js')
-rw-r--r--node_modules/bser/index.js586
1 files changed, 586 insertions, 0 deletions
diff --git a/node_modules/bser/index.js b/node_modules/bser/index.js
new file mode 100644
index 0000000..4ae14d3
--- /dev/null
+++ b/node_modules/bser/index.js
@@ -0,0 +1,586 @@
+/* Copyright 2015-present Facebook, Inc.
+ * Licensed under the Apache License, Version 2.0 */
+
+var EE = require('events').EventEmitter;
+var util = require('util');
+var os = require('os');
+var assert = require('assert');
+var Int64 = require('node-int64');
+
+// BSER uses the local endianness to reduce byte swapping overheads
+// (the protocol is expressly local IPC only). We need to tell node
+// to use the native endianness when reading various native values.
+var isBigEndian = os.endianness() == 'BE';
+
+// Find the next power-of-2 >= size
+function nextPow2(size) {
+ return Math.pow(2, Math.ceil(Math.log(size) / Math.LN2));
+}
+
+// Expandable buffer that we can provide a size hint for
+function Accumulator(initsize) {
+ this.buf = Buffer.alloc(nextPow2(initsize || 8192));
+ this.readOffset = 0;
+ this.writeOffset = 0;
+}
+// For testing
+exports.Accumulator = Accumulator
+
+// How much we can write into this buffer without allocating
+Accumulator.prototype.writeAvail = function() {
+ return this.buf.length - this.writeOffset;
+}
+
+// How much we can read
+Accumulator.prototype.readAvail = function() {
+ return this.writeOffset - this.readOffset;
+}
+
+// Ensure that we have enough space for size bytes
+Accumulator.prototype.reserve = function(size) {
+ if (size < this.writeAvail()) {
+ return;
+ }
+
+ // If we can make room by shunting down, do so
+ if (this.readOffset > 0) {
+ this.buf.copy(this.buf, 0, this.readOffset, this.writeOffset);
+ this.writeOffset -= this.readOffset;
+ this.readOffset = 0;
+ }
+
+ // If we made enough room, no need to allocate more
+ if (size < this.writeAvail()) {
+ return;
+ }
+
+ // Allocate a replacement and copy it in
+ var buf = Buffer.alloc(nextPow2(this.buf.length + size - this.writeAvail()));
+ this.buf.copy(buf);
+ this.buf = buf;
+}
+
+// Append buffer or string. Will resize as needed
+Accumulator.prototype.append = function(buf) {
+ if (Buffer.isBuffer(buf)) {
+ this.reserve(buf.length);
+ buf.copy(this.buf, this.writeOffset, 0, buf.length);
+ this.writeOffset += buf.length;
+ } else {
+ var size = Buffer.byteLength(buf);
+ this.reserve(size);
+ this.buf.write(buf, this.writeOffset);
+ this.writeOffset += size;
+ }
+}
+
+Accumulator.prototype.assertReadableSize = function(size) {
+ if (this.readAvail() < size) {
+ throw new Error("wanted to read " + size +
+ " bytes but only have " + this.readAvail());
+ }
+}
+
+Accumulator.prototype.peekString = function(size) {
+ this.assertReadableSize(size);
+ return this.buf.toString('utf-8', this.readOffset, this.readOffset + size);
+}
+
+Accumulator.prototype.readString = function(size) {
+ var str = this.peekString(size);
+ this.readOffset += size;
+ return str;
+}
+
+Accumulator.prototype.peekInt = function(size) {
+ this.assertReadableSize(size);
+ switch (size) {
+ case 1:
+ return this.buf.readInt8(this.readOffset, size);
+ case 2:
+ return isBigEndian ?
+ this.buf.readInt16BE(this.readOffset, size) :
+ this.buf.readInt16LE(this.readOffset, size);
+ case 4:
+ return isBigEndian ?
+ this.buf.readInt32BE(this.readOffset, size) :
+ this.buf.readInt32LE(this.readOffset, size);
+ case 8:
+ var big = this.buf.slice(this.readOffset, this.readOffset + 8);
+ if (isBigEndian) {
+ // On a big endian system we can simply pass the buffer directly
+ return new Int64(big);
+ }
+ // Otherwise we need to byteswap
+ return new Int64(byteswap64(big));
+ default:
+ throw new Error("invalid integer size " + size);
+ }
+}
+
+Accumulator.prototype.readInt = function(bytes) {
+ var ival = this.peekInt(bytes);
+ if (ival instanceof Int64 && isFinite(ival.valueOf())) {
+ ival = ival.valueOf();
+ }
+ this.readOffset += bytes;
+ return ival;
+}
+
+Accumulator.prototype.peekDouble = function() {
+ this.assertReadableSize(8);
+ return isBigEndian ?
+ this.buf.readDoubleBE(this.readOffset) :
+ this.buf.readDoubleLE(this.readOffset);
+}
+
+Accumulator.prototype.readDouble = function() {
+ var dval = this.peekDouble();
+ this.readOffset += 8;
+ return dval;
+}
+
+Accumulator.prototype.readAdvance = function(size) {
+ if (size > 0) {
+ this.assertReadableSize(size);
+ } else if (size < 0 && this.readOffset + size < 0) {
+ throw new Error("advance with negative offset " + size +
+ " would seek off the start of the buffer");
+ }
+ this.readOffset += size;
+}
+
+Accumulator.prototype.writeByte = function(value) {
+ this.reserve(1);
+ this.buf.writeInt8(value, this.writeOffset);
+ ++this.writeOffset;
+}
+
+Accumulator.prototype.writeInt = function(value, size) {
+ this.reserve(size);
+ switch (size) {
+ case 1:
+ this.buf.writeInt8(value, this.writeOffset);
+ break;
+ case 2:
+ if (isBigEndian) {
+ this.buf.writeInt16BE(value, this.writeOffset);
+ } else {
+ this.buf.writeInt16LE(value, this.writeOffset);
+ }
+ break;
+ case 4:
+ if (isBigEndian) {
+ this.buf.writeInt32BE(value, this.writeOffset);
+ } else {
+ this.buf.writeInt32LE(value, this.writeOffset);
+ }
+ break;
+ default:
+ throw new Error("unsupported integer size " + size);
+ }
+ this.writeOffset += size;
+}
+
+Accumulator.prototype.writeDouble = function(value) {
+ this.reserve(8);
+ if (isBigEndian) {
+ this.buf.writeDoubleBE(value, this.writeOffset);
+ } else {
+ this.buf.writeDoubleLE(value, this.writeOffset);
+ }
+ this.writeOffset += 8;
+}
+
+var BSER_ARRAY = 0x00;
+var BSER_OBJECT = 0x01;
+var BSER_STRING = 0x02;
+var BSER_INT8 = 0x03;
+var BSER_INT16 = 0x04;
+var BSER_INT32 = 0x05;
+var BSER_INT64 = 0x06;
+var BSER_REAL = 0x07;
+var BSER_TRUE = 0x08;
+var BSER_FALSE = 0x09;
+var BSER_NULL = 0x0a;
+var BSER_TEMPLATE = 0x0b;
+var BSER_SKIP = 0x0c;
+
+var ST_NEED_PDU = 0; // Need to read and decode PDU length
+var ST_FILL_PDU = 1; // Know the length, need to read whole content
+
+var MAX_INT8 = 127;
+var MAX_INT16 = 32767;
+var MAX_INT32 = 2147483647;
+
+function BunserBuf() {
+ EE.call(this);
+ this.buf = new Accumulator();
+ this.state = ST_NEED_PDU;
+}
+util.inherits(BunserBuf, EE);
+exports.BunserBuf = BunserBuf;
+
+BunserBuf.prototype.append = function(buf, synchronous) {
+ if (synchronous) {
+ this.buf.append(buf);
+ return this.process(synchronous);
+ }
+
+ try {
+ this.buf.append(buf);
+ } catch (err) {
+ this.emit('error', err);
+ return;
+ }
+ // Arrange to decode later. This allows the consuming
+ // application to make progress with other work in the
+ // case that we have a lot of subscription updates coming
+ // in from a large tree.
+ this.processLater();
+}
+
+BunserBuf.prototype.processLater = function() {
+ var self = this;
+ process.nextTick(function() {
+ try {
+ self.process(false);
+ } catch (err) {
+ self.emit('error', err);
+ }
+ });
+}
+
+// Do something with the buffer to advance our state.
+// If we're running synchronously we'll return either
+// the value we've decoded or undefined if we don't
+// yet have enought data.
+// If we're running asynchronously, we'll emit the value
+// when it becomes ready and schedule another invocation
+// of process on the next tick if we still have data we
+// can process.
+BunserBuf.prototype.process = function(synchronous) {
+ if (this.state == ST_NEED_PDU) {
+ if (this.buf.readAvail() < 2) {
+ return;
+ }
+ // Validate BSER header
+ this.expectCode(0);
+ this.expectCode(1);
+ this.pduLen = this.decodeInt(true /* relaxed */);
+ if (this.pduLen === false) {
+ // Need more data, walk backwards
+ this.buf.readAdvance(-2);
+ return;
+ }
+ // Ensure that we have a big enough buffer to read the rest of the PDU
+ this.buf.reserve(this.pduLen);
+ this.state = ST_FILL_PDU;
+ }
+
+ if (this.state == ST_FILL_PDU) {
+ if (this.buf.readAvail() < this.pduLen) {
+ // Need more data
+ return;
+ }
+
+ // We have enough to decode it
+ var val = this.decodeAny();
+ if (synchronous) {
+ return val;
+ }
+ this.emit('value', val);
+ this.state = ST_NEED_PDU;
+ }
+
+ if (!synchronous && this.buf.readAvail() > 0) {
+ this.processLater();
+ }
+}
+
+BunserBuf.prototype.raise = function(reason) {
+ throw new Error(reason + ", in Buffer of length " +
+ this.buf.buf.length + " (" + this.buf.readAvail() +
+ " readable) at offset " + this.buf.readOffset + " buffer: " +
+ JSON.stringify(this.buf.buf.slice(
+ this.buf.readOffset, this.buf.readOffset + 32).toJSON()));
+}
+
+BunserBuf.prototype.expectCode = function(expected) {
+ var code = this.buf.readInt(1);
+ if (code != expected) {
+ this.raise("expected bser opcode " + expected + " but got " + code);
+ }
+}
+
+BunserBuf.prototype.decodeAny = function() {
+ var code = this.buf.peekInt(1);
+ switch (code) {
+ case BSER_INT8:
+ case BSER_INT16:
+ case BSER_INT32:
+ case BSER_INT64:
+ return this.decodeInt();
+ case BSER_REAL:
+ this.buf.readAdvance(1);
+ return this.buf.readDouble();
+ case BSER_TRUE:
+ this.buf.readAdvance(1);
+ return true;
+ case BSER_FALSE:
+ this.buf.readAdvance(1);
+ return false;
+ case BSER_NULL:
+ this.buf.readAdvance(1);
+ return null;
+ case BSER_STRING:
+ return this.decodeString();
+ case BSER_ARRAY:
+ return this.decodeArray();
+ case BSER_OBJECT:
+ return this.decodeObject();
+ case BSER_TEMPLATE:
+ return this.decodeTemplate();
+ default:
+ this.raise("unhandled bser opcode " + code);
+ }
+}
+
+BunserBuf.prototype.decodeArray = function() {
+ this.expectCode(BSER_ARRAY);
+ var nitems = this.decodeInt();
+ var arr = [];
+ for (var i = 0; i < nitems; ++i) {
+ arr.push(this.decodeAny());
+ }
+ return arr;
+}
+
+BunserBuf.prototype.decodeObject = function() {
+ this.expectCode(BSER_OBJECT);
+ var nitems = this.decodeInt();
+ var res = {};
+ for (var i = 0; i < nitems; ++i) {
+ var key = this.decodeString();
+ var val = this.decodeAny();
+ res[key] = val;
+ }
+ return res;
+}
+
+BunserBuf.prototype.decodeTemplate = function() {
+ this.expectCode(BSER_TEMPLATE);
+ var keys = this.decodeArray();
+ var nitems = this.decodeInt();
+ var arr = [];
+ for (var i = 0; i < nitems; ++i) {
+ var obj = {};
+ for (var keyidx = 0; keyidx < keys.length; ++keyidx) {
+ if (this.buf.peekInt(1) == BSER_SKIP) {
+ this.buf.readAdvance(1);
+ continue;
+ }
+ var val = this.decodeAny();
+ obj[keys[keyidx]] = val;
+ }
+ arr.push(obj);
+ }
+ return arr;
+}
+
+BunserBuf.prototype.decodeString = function() {
+ this.expectCode(BSER_STRING);
+ var len = this.decodeInt();
+ return this.buf.readString(len);
+}
+
+// This is unusual compared to the other decode functions in that
+// we may not have enough data available to satisfy the read, and
+// we don't want to throw. This is only true when we're reading
+// the PDU length from the PDU header; we'll set relaxSizeAsserts
+// in that case.
+BunserBuf.prototype.decodeInt = function(relaxSizeAsserts) {
+ if (relaxSizeAsserts && (this.buf.readAvail() < 1)) {
+ return false;
+ } else {
+ this.buf.assertReadableSize(1);
+ }
+ var code = this.buf.peekInt(1);
+ var size = 0;
+ switch (code) {
+ case BSER_INT8:
+ size = 1;
+ break;
+ case BSER_INT16:
+ size = 2;
+ break;
+ case BSER_INT32:
+ size = 4;
+ break;
+ case BSER_INT64:
+ size = 8;
+ break;
+ default:
+ this.raise("invalid bser int encoding " + code);
+ }
+
+ if (relaxSizeAsserts && (this.buf.readAvail() < 1 + size)) {
+ return false;
+ }
+ this.buf.readAdvance(1);
+ return this.buf.readInt(size);
+}
+
+// synchronously BSER decode a string and return the value
+function loadFromBuffer(input) {
+ var buf = new BunserBuf();
+ var result = buf.append(input, true);
+ if (buf.buf.readAvail()) {
+ throw Error(
+ 'excess data found after input buffer, use BunserBuf instead');
+ }
+ if (typeof result === 'undefined') {
+ throw Error(
+ 'no bser found in string and no error raised!?');
+ }
+ return result;
+}
+exports.loadFromBuffer = loadFromBuffer
+
+// Byteswap an arbitrary buffer, flipping from one endian
+// to the other, returning a new buffer with the resultant data
+function byteswap64(buf) {
+ var swap = Buffer.alloc(buf.length);
+ for (var i = 0; i < buf.length; i++) {
+ swap[i] = buf[buf.length -1 - i];
+ }
+ return swap;
+}
+
+function dump_int64(buf, val) {
+ // Get the raw bytes. The Int64 buffer is big endian
+ var be = val.toBuffer();
+
+ if (isBigEndian) {
+ // We're a big endian system, so the buffer is exactly how we
+ // want it to be
+ buf.writeByte(BSER_INT64);
+ buf.append(be);
+ return;
+ }
+ // We need to byte swap to get the correct representation
+ var le = byteswap64(be);
+ buf.writeByte(BSER_INT64);
+ buf.append(le);
+}
+
+function dump_int(buf, val) {
+ var abs = Math.abs(val);
+ if (abs <= MAX_INT8) {
+ buf.writeByte(BSER_INT8);
+ buf.writeInt(val, 1);
+ } else if (abs <= MAX_INT16) {
+ buf.writeByte(BSER_INT16);
+ buf.writeInt(val, 2);
+ } else if (abs <= MAX_INT32) {
+ buf.writeByte(BSER_INT32);
+ buf.writeInt(val, 4);
+ } else {
+ dump_int64(buf, new Int64(val));
+ }
+}
+
+function dump_any(buf, val) {
+ switch (typeof(val)) {
+ case 'number':
+ // check if it is an integer or a float
+ if (isFinite(val) && Math.floor(val) === val) {
+ dump_int(buf, val);
+ } else {
+ buf.writeByte(BSER_REAL);
+ buf.writeDouble(val);
+ }
+ return;
+ case 'string':
+ buf.writeByte(BSER_STRING);
+ dump_int(buf, Buffer.byteLength(val));
+ buf.append(val);
+ return;
+ case 'boolean':
+ buf.writeByte(val ? BSER_TRUE : BSER_FALSE);
+ return;
+ case 'object':
+ if (val === null) {
+ buf.writeByte(BSER_NULL);
+ return;
+ }
+ if (val instanceof Int64) {
+ dump_int64(buf, val);
+ return;
+ }
+ if (Array.isArray(val)) {
+ buf.writeByte(BSER_ARRAY);
+ dump_int(buf, val.length);
+ for (var i = 0; i < val.length; ++i) {
+ dump_any(buf, val[i]);
+ }
+ return;
+ }
+ buf.writeByte(BSER_OBJECT);
+ var keys = Object.keys(val);
+
+ // First pass to compute number of defined keys
+ var num_keys = keys.length;
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ var v = val[key];
+ if (typeof(v) == 'undefined') {
+ num_keys--;
+ }
+ }
+ dump_int(buf, num_keys);
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ var v = val[key];
+ if (typeof(v) == 'undefined') {
+ // Don't include it
+ continue;
+ }
+ dump_any(buf, key);
+ try {
+ dump_any(buf, v);
+ } catch (e) {
+ throw new Error(
+ e.message + ' (while serializing object property with name `' +
+ key + "')");
+ }
+ }
+ return;
+
+ default:
+ throw new Error('cannot serialize type ' + typeof(val) + ' to BSER');
+ }
+}
+
+// BSER encode value and return a buffer of the contents
+function dumpToBuffer(val) {
+ var buf = new Accumulator();
+ // Build out the header
+ buf.writeByte(0);
+ buf.writeByte(1);
+ // Reserve room for an int32 to hold our PDU length
+ buf.writeByte(BSER_INT32);
+ buf.writeInt(0, 4); // We'll come back and fill this in at the end
+
+ dump_any(buf, val);
+
+ // Compute PDU length
+ var off = buf.writeOffset;
+ var len = off - 7 /* the header length */;
+ buf.writeOffset = 3; // The length value to fill in
+ buf.writeInt(len, 4); // write the length in the space we reserved
+ buf.writeOffset = off;
+
+ return buf.buf.slice(0, off);
+}
+exports.dumpToBuffer = dumpToBuffer