Comparing version 1.0.4 to 2.0.0
@@ -0,1 +1,16 @@ | ||
<a name="2.0.0"></a> | ||
# 2.0.0 (2018-02-26) | ||
### Bug Fixes | ||
* **browser:** fixing browser property in package.json ([095fba9](https://github.com/mongodb/js-bson/commit/095fba9)) | ||
* **dbref:** only upgrade objects with allowed $keys to DBRefs ([98eb9e2](https://github.com/mongodb/js-bson/commit/98eb9e2)) | ||
* **decimal128:** add basic guard against REDOS attacks ([511ecc4](https://github.com/mongodb/js-bson/commit/511ecc4)) | ||
* **Decimal128:** update toString and fromString methods to correctly handle the case of too many significant digits ([25ed43e](https://github.com/mongodb/js-bson/commit/25ed43e)) | ||
* **objectid:** if pid is 1, use random value ([e188ae6](https://github.com/mongodb/js-bson/commit/e188ae6)) | ||
* **serializeWithBufferAndIndex:** write documents to start of intermediate buffer ([b4e4ac5](https://github.com/mongodb/js-bson/commit/b4e4ac5)) | ||
1.0.4 2016-01-11 | ||
@@ -2,0 +17,0 @@ ---------------- |
@@ -18,3 +18,3 @@ var BSON = require('./lib/bson/bson'), | ||
// BSON MAX VALUES | ||
BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
BSON.BSON_INT32_MAX = 0x7fffffff; | ||
BSON.BSON_INT32_MIN = -0x80000000; | ||
@@ -26,4 +26,4 @@ | ||
// JS MAX PRECISE VALUES | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
@@ -30,0 +30,0 @@ // Add BSON types to function creation |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
/** | ||
@@ -8,3 +10,3 @@ * Module dependencies. | ||
// to support hybrid environments like Electron | ||
if(typeof global !== 'undefined') { | ||
if (typeof global !== 'undefined') { | ||
var Buffer = require('buffer').Buffer; // TODO just use global Buffer | ||
@@ -30,7 +32,7 @@ } | ||
function Binary(buffer, subType) { | ||
if(!(this instanceof Binary)) return new Binary(buffer, subType); | ||
if (!(this instanceof Binary)) return new Binary(buffer, subType); | ||
this._bsontype = 'Binary'; | ||
if(buffer instanceof Number) { | ||
if (buffer instanceof Number) { | ||
this.sub_type = buffer; | ||
@@ -43,12 +45,15 @@ this.position = 0; | ||
if(buffer != null && !(buffer instanceof Number)) { | ||
if (buffer != null && !(buffer instanceof Number)) { | ||
// Only accept Buffer, Uint8Array or Arrays | ||
if(typeof buffer == 'string') { | ||
if (typeof buffer === 'string') { | ||
// Different ways of writing the length of the string for the different types | ||
if(typeof Buffer != 'undefined') { | ||
if (typeof Buffer !== 'undefined') { | ||
this.buffer = new Buffer(buffer); | ||
} else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) { | ||
} else if ( | ||
typeof Uint8Array !== 'undefined' || | ||
Object.prototype.toString.call(buffer) === '[object Array]' | ||
) { | ||
this.buffer = writeStringToArray(buffer); | ||
} else { | ||
throw new Error("only String, Buffer, Uint8Array or Array accepted"); | ||
throw new Error('only String, Buffer, Uint8Array or Array accepted'); | ||
} | ||
@@ -60,5 +65,5 @@ } else { | ||
} else { | ||
if(typeof Buffer != 'undefined') { | ||
this.buffer = new Buffer(Binary.BUFFER_SIZE); | ||
} else if(typeof Uint8Array != 'undefined'){ | ||
if (typeof Buffer !== 'undefined') { | ||
this.buffer = new Buffer(Binary.BUFFER_SIZE); | ||
} else if (typeof Uint8Array !== 'undefined') { | ||
this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE)); | ||
@@ -71,3 +76,3 @@ } else { | ||
} | ||
}; | ||
} | ||
@@ -82,10 +87,12 @@ /** | ||
// If it's a string and a has more than one character throw an error | ||
if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array"); | ||
if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255"); | ||
if (byte_value['length'] != null && typeof byte_value !== 'number' && byte_value.length !== 1) | ||
throw new Error('only accepts single character String, Uint8Array or Array'); | ||
if ((typeof byte_value !== 'number' && byte_value < 0) || byte_value > 255) | ||
throw new Error('only accepts number in a valid unsigned byte range 0-255'); | ||
// Decode the byte value once | ||
var decoded_byte = null; | ||
if(typeof byte_value == 'string') { | ||
if (typeof byte_value === 'string') { | ||
decoded_byte = byte_value.charCodeAt(0); | ||
} else if(byte_value['length'] != null) { | ||
} else if (byte_value['length'] != null) { | ||
decoded_byte = byte_value[0]; | ||
@@ -96,6 +103,6 @@ } else { | ||
if(this.buffer.length > this.position) { | ||
if (this.buffer.length > this.position) { | ||
this.buffer[this.position++] = decoded_byte; | ||
} else { | ||
if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
// Create additional overflow buffer | ||
@@ -108,5 +115,5 @@ var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); | ||
} else { | ||
var buffer = null; | ||
buffer = null; | ||
// Create a new buffer (typed or normal array) | ||
if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { | ||
if (Object.prototype.toString.call(this.buffer) === '[object Uint8Array]') { | ||
buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length)); | ||
@@ -118,3 +125,3 @@ } else { | ||
// We need to copy all the content to the new array | ||
for(var i = 0; i < this.buffer.length; i++) { | ||
for (var i = 0; i < this.buffer.length; i++) { | ||
buffer[i] = this.buffer[i]; | ||
@@ -140,16 +147,16 @@ } | ||
Binary.prototype.write = function write(string, offset) { | ||
offset = typeof offset == 'number' ? offset : this.position; | ||
offset = typeof offset === 'number' ? offset : this.position; | ||
// If the buffer is to small let's extend the buffer | ||
if(this.buffer.length < offset + string.length) { | ||
if (this.buffer.length < offset + string.length) { | ||
var buffer = null; | ||
// If we are in node.js | ||
if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
buffer = new Buffer(this.buffer.length + string.length); | ||
this.buffer.copy(buffer, 0, 0, this.buffer.length); | ||
} else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { | ||
} else if (Object.prototype.toString.call(this.buffer) === '[object Uint8Array]') { | ||
// Create a new buffer | ||
buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)) | ||
buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)); | ||
// Copy the content | ||
for(var i = 0; i < this.position; i++) { | ||
for (var i = 0; i < this.position; i++) { | ||
buffer[i] = this.buffer[i]; | ||
@@ -163,13 +170,19 @@ } | ||
if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { | ||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { | ||
string.copy(this.buffer, offset, 0, string.length); | ||
this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; | ||
this.position = offset + string.length > this.position ? offset + string.length : this.position; | ||
// offset = string.length | ||
} else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) { | ||
} else if ( | ||
typeof Buffer !== 'undefined' && | ||
typeof string === 'string' && | ||
Buffer.isBuffer(this.buffer) | ||
) { | ||
this.buffer.write(string, offset, 'binary'); | ||
this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; | ||
this.position = offset + string.length > this.position ? offset + string.length : this.position; | ||
// offset = string.length; | ||
} else if(Object.prototype.toString.call(string) == '[object Uint8Array]' | ||
|| Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') { | ||
for(var i = 0; i < string.length; i++) { | ||
} else if ( | ||
Object.prototype.toString.call(string) === '[object Uint8Array]' || | ||
(Object.prototype.toString.call(string) === '[object Array]' && typeof string !== 'string') | ||
) { | ||
for (i = 0; i < string.length; i++) { | ||
this.buffer[offset++] = string[i]; | ||
@@ -179,4 +192,4 @@ } | ||
this.position = offset > this.position ? offset : this.position; | ||
} else if(typeof string == 'string') { | ||
for(var i = 0; i < string.length; i++) { | ||
} else if (typeof string === 'string') { | ||
for (i = 0; i < string.length; i++) { | ||
this.buffer[offset++] = string.charCodeAt(i); | ||
@@ -198,13 +211,14 @@ } | ||
Binary.prototype.read = function read(position, length) { | ||
length = length && length > 0 | ||
? length | ||
: this.position; | ||
length = length && length > 0 ? length : this.position; | ||
// Let's return the data based on the type we have | ||
if(this.buffer['slice']) { | ||
if (this.buffer['slice']) { | ||
return this.buffer.slice(position, position + length); | ||
} else { | ||
// Create a buffer to keep the result | ||
var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length); | ||
for(var i = 0; i < length; i++) { | ||
var buffer = | ||
typeof Uint8Array !== 'undefined' | ||
? new Uint8Array(new ArrayBuffer(length)) | ||
: new Array(length); | ||
for (var i = 0; i < length; i++) { | ||
buffer[i] = this.buffer[position++]; | ||
@@ -227,18 +241,28 @@ } | ||
// Optimize to serialize for the situation where the data == size of buffer | ||
if(asRaw && typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer) && this.buffer.length == this.position) | ||
if ( | ||
asRaw && | ||
typeof Buffer !== 'undefined' && | ||
Buffer.isBuffer(this.buffer) && | ||
this.buffer.length === this.position | ||
) | ||
return this.buffer; | ||
// If it's a node.js buffer object | ||
if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); | ||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { | ||
return asRaw | ||
? this.buffer.slice(0, this.position) | ||
: this.buffer.toString('binary', 0, this.position); | ||
} else { | ||
if(asRaw) { | ||
if (asRaw) { | ||
// we support the slice command use it | ||
if(this.buffer['slice'] != null) { | ||
if (this.buffer['slice'] != null) { | ||
return this.buffer.slice(0, this.position); | ||
} else { | ||
// Create a new buffer to copy content to | ||
var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position); | ||
var newBuffer = | ||
Object.prototype.toString.call(this.buffer) === '[object Uint8Array]' | ||
? new Uint8Array(new ArrayBuffer(this.position)) | ||
: new Array(this.position); | ||
// Copy content | ||
for(var i = 0; i < this.position; i++) { | ||
for (var i = 0; i < this.position; i++) { | ||
newBuffer[i] = this.buffer[i]; | ||
@@ -270,3 +294,3 @@ } | ||
return this.buffer != null ? this.buffer.toString('base64') : ''; | ||
} | ||
}; | ||
@@ -278,3 +302,3 @@ /** | ||
return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : ''; | ||
} | ||
}; | ||
@@ -292,5 +316,8 @@ /** | ||
// Create a buffer | ||
var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length); | ||
var buffer = | ||
typeof Uint8Array !== 'undefined' | ||
? new Uint8Array(new ArrayBuffer(data.length)) | ||
: new Array(data.length); | ||
// Write the content to the buffer | ||
for(var i = 0; i < data.length; i++) { | ||
for (var i = 0; i < data.length; i++) { | ||
buffer[i] = data.charCodeAt(i); | ||
@@ -300,3 +327,3 @@ } | ||
return buffer; | ||
} | ||
}; | ||
@@ -309,5 +336,5 @@ /** | ||
var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { | ||
var result = ""; | ||
for(var i = startIndex; i < endIndex; i++) { | ||
result = result + String.fromCharCode(byteArray[i]); | ||
var result = ''; | ||
for (var i = startIndex; i < endIndex; i++) { | ||
result = result + String.fromCharCode(byteArray[i]); | ||
} | ||
@@ -314,0 +341,0 @@ return result; |
@@ -1,7 +0,5 @@ | ||
"use strict" | ||
'use strict'; | ||
var writeIEEE754 = require('./float_parser').writeIEEE754, | ||
readIEEE754 = require('./float_parser').readIEEE754, | ||
Map = require('./map'), | ||
Long = require('./long'), | ||
var Map = require('./map'), | ||
Long = require('./long'), | ||
Double = require('./double'), | ||
@@ -12,5 +10,5 @@ Timestamp = require('./timestamp'), | ||
Symbol = require('./symbol'), | ||
Int32 = require('./int_32'), | ||
Int32 = require('./int_32'), | ||
Code = require('./code'), | ||
Decimal128 = require('./decimal128'), | ||
Decimal128 = require('./decimal128'), | ||
MinKey = require('./min_key'), | ||
@@ -23,4 +21,4 @@ MaxKey = require('./max_key'), | ||
var deserialize = require('./parser/deserializer'), | ||
serializer = require('./parser/serializer'), | ||
calculateObjectSize = require('./parser/calculate_size'); | ||
serializer = require('./parser/serializer'), | ||
calculateObjectSize = require('./parser/calculate_size'); | ||
@@ -32,8 +30,7 @@ /** | ||
// Max Size | ||
var MAXSIZE = (1024*1024*17); | ||
var MAXSIZE = 1024 * 1024 * 17; | ||
// Max Document Buffer size | ||
var buffer = new Buffer(MAXSIZE); | ||
var BSON = function() { | ||
} | ||
var BSON = function() {}; | ||
@@ -51,20 +48,28 @@ /** | ||
BSON.prototype.serialize = function serialize(object, options) { | ||
options = options || {}; | ||
// Unpack the options | ||
var checkKeys = typeof options.checkKeys == 'boolean' | ||
? options.checkKeys : false; | ||
var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
? options.serializeFunctions : false; | ||
var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
? options.ignoreUndefined : true; | ||
options = options || {}; | ||
// Unpack the options | ||
var checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false; | ||
var serializeFunctions = | ||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; | ||
var ignoreUndefined = | ||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; | ||
// Attempt to serialize | ||
var serializationIndex = serializer(buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, []); | ||
// Create the final buffer | ||
var finishedBuffer = new Buffer(serializationIndex); | ||
// Copy into the finished buffer | ||
buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length); | ||
// Return the buffer | ||
return finishedBuffer; | ||
} | ||
// Attempt to serialize | ||
var serializationIndex = serializer( | ||
buffer, | ||
object, | ||
checkKeys, | ||
0, | ||
0, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
[] | ||
); | ||
// Create the final buffer | ||
var finishedBuffer = new Buffer(serializationIndex); | ||
// Copy into the finished buffer | ||
buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length); | ||
// Return the buffer | ||
return finishedBuffer; | ||
}; | ||
@@ -84,20 +89,26 @@ /** | ||
BSON.prototype.serializeWithBufferAndIndex = function(object, finalBuffer, options) { | ||
options = options || {}; | ||
// Unpack the options | ||
var checkKeys = typeof options.checkKeys == 'boolean' | ||
? options.checkKeys : false; | ||
var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
? options.serializeFunctions : false; | ||
var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
? options.ignoreUndefined : true; | ||
var startIndex = typeof options.index == 'number' | ||
? options.index : 0; | ||
options = options || {}; | ||
// Unpack the options | ||
var checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false; | ||
var serializeFunctions = | ||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; | ||
var ignoreUndefined = | ||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; | ||
var startIndex = typeof options.index === 'number' ? options.index : 0; | ||
// Attempt to serialize | ||
var serializationIndex = serializer(buffer, object, checkKeys, startIndex || 0, 0, serializeFunctions, ignoreUndefined); | ||
buffer.copy(finalBuffer, startIndex, 0, serializationIndex); | ||
// Attempt to serialize | ||
var serializationIndex = serializer( | ||
buffer, | ||
object, | ||
checkKeys, | ||
0, | ||
0, | ||
serializeFunctions, | ||
ignoreUndefined | ||
); | ||
buffer.copy(finalBuffer, startIndex, 0, serializationIndex); | ||
// Return the index | ||
return serializationIndex - 1; | ||
} | ||
// Return the index | ||
return startIndex + serializationIndex - 1; | ||
}; | ||
@@ -121,3 +132,3 @@ /** | ||
return deserialize(buffer, options); | ||
} | ||
}; | ||
@@ -134,11 +145,11 @@ /** | ||
BSON.prototype.calculateObjectSize = function(object, options) { | ||
options = options || {}; | ||
options = options || {}; | ||
var serializeFunctions = typeof options.serializeFunctions == 'boolean' | ||
? options.serializeFunctions : false; | ||
var ignoreUndefined = typeof options.ignoreUndefined == 'boolean' | ||
? options.ignoreUndefined : true; | ||
var serializeFunctions = | ||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false; | ||
var ignoreUndefined = | ||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true; | ||
return calculateObjectSize(object, serializeFunctions, ignoreUndefined); | ||
} | ||
}; | ||
@@ -165,9 +176,17 @@ /** | ||
*/ | ||
BSON.prototype.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { | ||
BSON.prototype.deserializeStream = function( | ||
data, | ||
startIndex, | ||
numberOfDocuments, | ||
documents, | ||
docStartIndex, | ||
options | ||
) { | ||
options = options != null ? options : {}; | ||
var index = startIndex; | ||
// Loop over all documents | ||
for(var i = 0; i < numberOfDocuments; i++) { | ||
for (var i = 0; i < numberOfDocuments; i++) { | ||
// Find size of the document | ||
var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; | ||
var size = | ||
data[index] | (data[index + 1] << 8) | (data[index + 2] << 16) | (data[index + 3] << 24); | ||
// Update options with index | ||
@@ -183,3 +202,3 @@ options['index'] = index; | ||
return index; | ||
} | ||
}; | ||
@@ -191,3 +210,3 @@ /** | ||
// BSON MAX VALUES | ||
BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
BSON.BSON_INT32_MAX = 0x7fffffff; | ||
BSON.BSON_INT32_MIN = -0x80000000; | ||
@@ -199,8 +218,8 @@ | ||
// JS MAX PRECISE VALUES | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
// Internal long versions | ||
var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
// var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
// var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
@@ -207,0 +226,0 @@ /** |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
/** | ||
@@ -10,3 +12,3 @@ * A class representation of the BSON Code type. | ||
var Code = function Code(code, scope) { | ||
if(!(this instanceof Code)) return new Code(code, scope); | ||
if (!(this instanceof Code)) return new Code(code, scope); | ||
this._bsontype = 'Code'; | ||
@@ -21,6 +23,6 @@ this.code = code; | ||
Code.prototype.toJSON = function() { | ||
return {scope:this.scope, code:this.code}; | ||
} | ||
return { scope: this.scope, code: this.code }; | ||
}; | ||
module.exports = Code; | ||
module.exports.Code = Code; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -5,3 +6,3 @@ * A class representation of the BSON DBRef type. | ||
* @class | ||
* @param {string} namespace the collection name. | ||
* @param {string} collection the collection name. | ||
* @param {ObjectID} oid the reference ObjectID. | ||
@@ -11,10 +12,11 @@ * @param {string} [db] optional db name, if omitted the reference is local to the current db. | ||
*/ | ||
function DBRef(namespace, oid, db) { | ||
if(!(this instanceof DBRef)) return new DBRef(namespace, oid, db); | ||
function DBRef(collection, oid, db, fields) { | ||
if (!(this instanceof DBRef)) return new DBRef(collection, oid, db, fields); | ||
this._bsontype = 'DBRef'; | ||
this.namespace = namespace; | ||
this.collection = collection; | ||
this.oid = oid; | ||
this.db = db; | ||
}; | ||
this.fields = fields || {}; | ||
} | ||
@@ -26,10 +28,13 @@ /** | ||
DBRef.prototype.toJSON = function() { | ||
return { | ||
'$ref':this.namespace, | ||
'$id':this.oid, | ||
'$db':this.db == null ? '' : this.db | ||
var o = { | ||
$ref: this.collection, | ||
$id: this.oid | ||
}; | ||
} | ||
if (this.db != null) o.$db = this.db; | ||
o = Object.assign(o, this.fields); | ||
return o; | ||
}; | ||
module.exports = DBRef; | ||
module.exports.DBRef = DBRef; | ||
module.exports.DBRef = DBRef; |
@@ -1,8 +0,8 @@ | ||
"use strict" | ||
'use strict'; | ||
var Long = require('./long'); | ||
let Long = require('./long'); | ||
var PARSE_STRING_REGEXP = /^(\+|\-)?(\d+|(\d*\.\d*))?(E|e)?([\-\+])?(\d+)?$/; | ||
var PARSE_INF_REGEXP = /^(\+|\-)?(Infinity|inf)$/i; | ||
var PARSE_NAN_REGEXP = /^(\+|\-)?NaN$/i; | ||
var PARSE_STRING_REGEXP = /^(\+|-)?(\d+|(\d*\.\d*))?(E|e)?([-+])?(\d+)?$/; | ||
var PARSE_INF_REGEXP = /^(\+|-)?(Infinity|inf)$/i; | ||
var PARSE_NAN_REGEXP = /^(\+|-)?NaN$/i; | ||
@@ -15,14 +15,64 @@ var EXPONENT_MAX = 6111; | ||
// Nan value bits as 32 bit values (due to lack of longs) | ||
var NAN_BUFFER = [0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
var NAN_BUFFER = [ | ||
0x7c, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00 | ||
].reverse(); | ||
// Infinity value bits 32 bit values (due to lack of longs) | ||
var INF_NEGATIVE_BUFFER = [0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
var INF_POSITIVE_BUFFER = [0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse(); | ||
var INF_NEGATIVE_BUFFER = [ | ||
0xf8, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00 | ||
].reverse(); | ||
var INF_POSITIVE_BUFFER = [ | ||
0x78, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00, | ||
0x00 | ||
].reverse(); | ||
var EXPONENT_REGEX = /^([\-\+])?(\d+)?$/; | ||
var EXPONENT_REGEX = /^([-+])?(\d+)?$/; | ||
// Detect if the value is a digit | ||
var isDigit = function(value) { | ||
return !isNaN(parseInt(value, 10)); | ||
} | ||
}; | ||
@@ -33,10 +83,8 @@ // Divide two uint128 values | ||
var _rem = Long.fromNumber(0); | ||
var i = 0; | ||
if(!value.parts[0] && !value.parts[1] && | ||
!value.parts[2] && !value.parts[3]) { | ||
if (!value.parts[0] && !value.parts[1] && !value.parts[2] && !value.parts[3]) { | ||
return { quotient: value, rem: _rem }; | ||
} | ||
for(var i = 0; i <= 3; i++) { | ||
for (let i = 0; i <= 3; i++) { | ||
// Adjust remainder to match value of next dividend | ||
@@ -51,8 +99,8 @@ _rem = _rem.shiftLeft(32); | ||
return { quotient: value, rem: _rem }; | ||
} | ||
}; | ||
// Multiply two Long values and return the 128 bit value | ||
var multiply64x2 = function(left, right) { | ||
if(!left && !right) { | ||
return {high: Long.fromNumber(0), low: Long.fromNumber(0)}; | ||
if (!left && !right) { | ||
return { high: Long.fromNumber(0), low: Long.fromNumber(0) }; | ||
} | ||
@@ -72,4 +120,4 @@ | ||
productMid = new Long(productMid.getLowBits(), 0) | ||
.add(productMid2) | ||
.add(productLow.shiftRightUnsigned(32)); | ||
.add(productMid2) | ||
.add(productLow.shiftRightUnsigned(32)); | ||
@@ -80,4 +128,4 @@ productHigh = productHigh.add(productMid.shiftRightUnsigned(32)); | ||
// Return the 128 bit result | ||
return {high: productHigh, low: productLow}; | ||
} | ||
return { high: productHigh, low: productLow }; | ||
}; | ||
@@ -90,47 +138,36 @@ var lessThan = function(left, right) { | ||
// Compare high bits first | ||
if(uhleft < uhright) { | ||
return true | ||
} else if(uhleft == uhright) { | ||
if (uhleft < uhright) { | ||
return true; | ||
} else if (uhleft === uhright) { | ||
var ulleft = left.low_ >>> 0; | ||
var ulright = right.low_ >>> 0; | ||
if(ulleft < ulright) return true; | ||
if (ulleft < ulright) return true; | ||
} | ||
return false; | ||
} | ||
}; | ||
var longtoHex = function(value) { | ||
var buffer = new Buffer(8); | ||
var index = 0; | ||
// Encode the low 64 bits of the decimal | ||
// Encode low bits | ||
buffer[index++] = value.low_ & 0xff; | ||
buffer[index++] = (value.low_ >> 8) & 0xff; | ||
buffer[index++] = (value.low_ >> 16) & 0xff; | ||
buffer[index++] = (value.low_ >> 24) & 0xff; | ||
// Encode high bits | ||
buffer[index++] = value.high_ & 0xff; | ||
buffer[index++] = (value.high_ >> 8) & 0xff; | ||
buffer[index++] = (value.high_ >> 16) & 0xff; | ||
buffer[index++] = (value.high_ >> 24) & 0xff; | ||
return buffer.reverse().toString('hex'); | ||
} | ||
var invalidErr = function(string, message) { | ||
throw new Error('"${string}" not a valid Decimal128 string - ' + message); | ||
}; | ||
var int32toHex = function(value) { | ||
var buffer = new Buffer(4); | ||
var index = 0; | ||
// Encode the low 64 bits of the decimal | ||
// Encode low bits | ||
buffer[index++] = value & 0xff; | ||
buffer[index++] = (value >> 8) & 0xff; | ||
buffer[index++] = (value >> 16) & 0xff; | ||
buffer[index++] = (value >> 24) & 0xff; | ||
return buffer.reverse().toString('hex'); | ||
} | ||
/** | ||
* A class representation of the BSON Decimal128 type. | ||
* | ||
* @class | ||
* @param {Buffer} bytes a buffer containing the raw Decimal128 bytes. | ||
* @return {Double} | ||
*/ | ||
var Decimal128 = function(bytes) { | ||
this._bsontype = 'Decimal128'; | ||
this.bytes = bytes; | ||
} | ||
}; | ||
/** | ||
* Create a Decimal128 instance from a string representation | ||
* | ||
* @method | ||
* @param {string} string a numeric string representation. | ||
* @return {Decimal128} returns a Decimal128 instance. | ||
*/ | ||
Decimal128.fromString = function(string) { | ||
@@ -178,4 +215,8 @@ // Parse state tracking | ||
// Trim the string | ||
string = string.trim(); | ||
// Naively prevent against REDOS attacks. | ||
// TODO: implementing a custom parsing for this, or refactoring the regex would yield | ||
// further gains. | ||
if (string.length >= 7000) { | ||
throw new Error('' + string + ' not a valid Decimal128 string'); | ||
} | ||
@@ -188,23 +229,39 @@ // Results | ||
// Validate the string | ||
if(!stringMatch | ||
&& ! infMatch | ||
&& ! nanMatch || string.length == 0) { | ||
throw new Error("" + string + " not a valid Decimal128 string"); | ||
if ((!stringMatch && !infMatch && !nanMatch) || string.length === 0) { | ||
throw new Error('' + string + ' not a valid Decimal128 string'); | ||
} | ||
// Check if we have an illegal exponent format | ||
if(stringMatch && stringMatch[4] && stringMatch[2] === undefined) { | ||
throw new Error("" + string + " not a valid Decimal128 string"); | ||
if (stringMatch) { | ||
// full_match = stringMatch[0] | ||
// sign = stringMatch[1] | ||
var unsignedNumber = stringMatch[2]; | ||
// stringMatch[3] is undefined if a whole number (ex "1", 12") | ||
// but defined if a number w/ decimal in it (ex "1.0, 12.2") | ||
var e = stringMatch[4]; | ||
var expSign = stringMatch[5]; | ||
var expNumber = stringMatch[6]; | ||
// they provided e, but didn't give an exponent number. for ex "1e" | ||
if (e && expNumber === undefined) invalidErr(string, 'missing exponent power'); | ||
// they provided e, but didn't give a number before it. for ex "e1" | ||
if (e && unsignedNumber === undefined) invalidErr(string, 'missing exponent base'); | ||
if (e === undefined && (expSign || expNumber)) { | ||
invalidErr(string, 'missing e before exponent'); | ||
} | ||
} | ||
// Get the negative or positive sign | ||
if(string[index] == '+' || string[index] == '-') { | ||
isNegative = string[index++] == '-'; | ||
if (string[index] === '+' || string[index] === '-') { | ||
isNegative = string[index++] === '-'; | ||
} | ||
// Check if user passed Infinity or NaN | ||
if(!isDigit(string[index]) && string[index] != '.') { | ||
if(string[index] == 'i' || string[index] == 'I') { | ||
if (!isDigit(string[index]) && string[index] !== '.') { | ||
if (string[index] === 'i' || string[index] === 'I') { | ||
return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); | ||
} else if(string[index] == 'N') { | ||
} else if (string[index] === 'N') { | ||
return new Decimal128(new Buffer(NAN_BUFFER)); | ||
@@ -215,7 +272,5 @@ } | ||
// Read all the digits | ||
while(isDigit(string[index]) || string[index] == '.') { | ||
if(string[index] == '.') { | ||
if(sawRadix) { | ||
return new Decimal128(new Buffer(NAN_BUFFER)); | ||
} | ||
while (isDigit(string[index]) || string[index] === '.') { | ||
if (string[index] === '.') { | ||
if (sawRadix) invalidErr(string, 'contains multiple periods'); | ||
@@ -227,5 +282,5 @@ sawRadix = true; | ||
if(nDigitsStored < 34) { | ||
if(string[index] != '0' || foundNonZero) { | ||
if(!foundNonZero) { | ||
if (nDigitsStored < 34) { | ||
if (string[index] !== '0' || foundNonZero) { | ||
if (!foundNonZero) { | ||
firstNonZero = nDigitsRead; | ||
@@ -242,10 +297,5 @@ } | ||
if(foundNonZero) { | ||
nDigits = nDigits + 1; | ||
} | ||
if (foundNonZero) nDigits = nDigits + 1; | ||
if (sawRadix) radixPosition = radixPosition + 1; | ||
if(sawRadix) { | ||
radixPosition = radixPosition + 1; | ||
} | ||
nDigitsRead = nDigitsRead + 1; | ||
@@ -255,8 +305,6 @@ index = index + 1; | ||
if(sawRadix && !nDigitsRead) { | ||
throw new Error("" + string + " not a valid Decimal128 string"); | ||
} | ||
if (sawRadix && !nDigitsRead) throw new Error('' + string + ' not a valid Decimal128 string'); | ||
// Read exponent if exists | ||
if(string[index] == 'e' || string[index] == 'E') { | ||
if (string[index] === 'e' || string[index] === 'E') { | ||
// Read exponent digits | ||
@@ -266,5 +314,3 @@ var match = string.substr(++index).match(EXPONENT_REGEX); | ||
// No digits read | ||
if(!match || !match[2]) { | ||
return new Decimal128(new Buffer(NAN_BUFFER)); | ||
} | ||
if (!match || !match[2]) return new Decimal128(new Buffer(NAN_BUFFER)); | ||
@@ -279,5 +325,3 @@ // Get exponent | ||
// Return not a number | ||
if(string[index]) { | ||
return new Decimal128(new Buffer(NAN_BUFFER)); | ||
} | ||
if (string[index]) return new Decimal128(new Buffer(NAN_BUFFER)); | ||
@@ -288,3 +332,3 @@ // Done reading input | ||
if(!nDigitsStored) { | ||
if (!nDigitsStored) { | ||
firstDigit = 0; | ||
@@ -299,5 +343,4 @@ lastDigit = 0; | ||
significantDigits = nDigits; | ||
if(exponent != 0 && significantDigits != 1) { | ||
while(string[firstNonZero + significantDigits - 1] == '0') { | ||
if (significantDigits !== 1) { | ||
while (string[firstNonZero + significantDigits - 1] === '0') { | ||
significantDigits = significantDigits - 1; | ||
@@ -313,3 +356,3 @@ } | ||
// Overflow prevention | ||
if(exponent <= radixPosition && radixPosition - exponent > (1 << 14)) { | ||
if (exponent <= radixPosition && radixPosition - exponent > 1 << 14) { | ||
exponent = EXPONENT_MIN; | ||
@@ -321,23 +364,21 @@ } else { | ||
// Attempt to normalize the exponent | ||
while(exponent > EXPONENT_MAX) { | ||
while (exponent > EXPONENT_MAX) { | ||
// Shift exponent to significand and decrease | ||
lastDigit = lastDigit + 1; | ||
if(lastDigit - firstDigit > MAX_DIGITS) { | ||
if (lastDigit - firstDigit > MAX_DIGITS) { | ||
// Check if we have a zero then just hard clamp, otherwise fail | ||
var digitsString = digits.join(''); | ||
if(digitsString.match(/^0+$/)) { | ||
if (digitsString.match(/^0+$/)) { | ||
exponent = EXPONENT_MAX; | ||
break; | ||
} else { | ||
return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); | ||
} | ||
invalidErr(string, 'overflow'); | ||
} | ||
exponent = exponent - 1; | ||
} | ||
while(exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
// Shift last digit | ||
if(lastDigit == 0) { | ||
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) { | ||
// Shift last digit. can only do this if < significant digits than # stored. | ||
if (lastDigit === 0 && significantDigits < nDigitsStored) { | ||
exponent = EXPONENT_MIN; | ||
@@ -348,3 +389,3 @@ significantDigits = 0; | ||
if(nDigitsStored < nDigits) { | ||
if (nDigitsStored < nDigits) { | ||
// adjust to match digits not stored | ||
@@ -357,20 +398,18 @@ nDigits = nDigits - 1; | ||
if(exponent < EXPONENT_MAX) { | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
} else { | ||
// Check if we have a zero then just hard clamp, otherwise fail | ||
var digitsString = digits.join(''); | ||
if(digitsString.match(/^0+$/)) { | ||
digitsString = digits.join(''); | ||
if (digitsString.match(/^0+$/)) { | ||
exponent = EXPONENT_MAX; | ||
break; | ||
} else { | ||
return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)) | ||
} | ||
invalidErr(string, 'overflow'); | ||
} | ||
} | ||
// Round | ||
// We've normalized the exponent, but might still need to round. | ||
if((lastDigit - firstDigit + 1 < significantDigits) && string[significantDigits] != '0') { | ||
if (lastDigit - firstDigit + 1 < significantDigits) { | ||
var endOfString = nDigitsRead; | ||
@@ -381,6 +420,11 @@ | ||
// digit and the position that digits are read to. | ||
if(sawRadix && exponent == EXPONENT_MIN) { | ||
if (sawRadix) { | ||
firstNonZero = firstNonZero + 1; | ||
endOfString = endOfString + 1; | ||
} | ||
// if negative, we need to increment again to account for - sign at start. | ||
if (isNegative) { | ||
firstNonZero = firstNonZero + 1; | ||
endOfString = endOfString + 1; | ||
} | ||
@@ -390,10 +434,8 @@ var roundDigit = parseInt(string[firstNonZero + lastDigit + 1], 10); | ||
if(roundDigit >= 5) { | ||
if (roundDigit >= 5) { | ||
roundBit = 1; | ||
if(roundDigit == 5) { | ||
roundBit = digits[lastDigit] % 2 == 1; | ||
for(var i = firstNonZero + lastDigit + 2; i < endOfString; i++) { | ||
if(parseInt(string[i], 10)) { | ||
if (roundDigit === 5) { | ||
roundBit = digits[lastDigit] % 2 === 1; | ||
for (i = firstNonZero + lastDigit + 2; i < endOfString; i++) { | ||
if (parseInt(string[i], 10)) { | ||
roundBit = 1; | ||
@@ -406,20 +448,20 @@ break; | ||
if(roundBit) { | ||
if (roundBit) { | ||
var dIdx = lastDigit; | ||
for(; dIdx >= 0; dIdx--) { | ||
if(++digits[dIdx] > 9) { | ||
for (; dIdx >= 0; dIdx--) { | ||
if (++digits[dIdx] > 9) { | ||
digits[dIdx] = 0; | ||
// overflowed most significant digit | ||
if(dIdx == 0) { | ||
if(exponent < EXPONENT_MAX) { | ||
if (dIdx === 0) { | ||
if (exponent < EXPONENT_MAX) { | ||
exponent = exponent + 1; | ||
digits[dIdx] = 1; | ||
} else { | ||
return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)) | ||
return new Decimal128( | ||
new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER) | ||
); | ||
} | ||
} | ||
} else { | ||
break; | ||
} | ||
@@ -437,11 +479,11 @@ } | ||
// read a zero | ||
if(significantDigits == 0) { | ||
if (significantDigits === 0) { | ||
significandHigh = Long.fromNumber(0); | ||
significandLow = Long.fromNumber(0); | ||
} else if(lastDigit - firstDigit < 17) { | ||
var dIdx = firstDigit; | ||
} else if (lastDigit - firstDigit < 17) { | ||
dIdx = firstDigit; | ||
significandLow = Long.fromNumber(digits[dIdx++]); | ||
significandHigh = new Long(0, 0); | ||
for(; dIdx <= lastDigit; dIdx++) { | ||
for (; dIdx <= lastDigit; dIdx++) { | ||
significandLow = significandLow.multiply(Long.fromNumber(10)); | ||
@@ -451,6 +493,6 @@ significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); | ||
} else { | ||
var dIdx = firstDigit; | ||
dIdx = firstDigit; | ||
significandHigh = Long.fromNumber(digits[dIdx++]); | ||
for(; dIdx <= lastDigit - 17; dIdx++) { | ||
for (; dIdx <= lastDigit - 17; dIdx++) { | ||
significandHigh = significandHigh.multiply(Long.fromNumber(10)); | ||
@@ -462,3 +504,3 @@ significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx])); | ||
for(; dIdx <= lastDigit; dIdx++) { | ||
for (; dIdx <= lastDigit; dIdx++) { | ||
significandLow = significandLow.multiply(Long.fromNumber(10)); | ||
@@ -469,7 +511,7 @@ significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); | ||
var significand = multiply64x2(significandHigh, Long.fromString("100000000000000000")); | ||
var significand = multiply64x2(significandHigh, Long.fromString('100000000000000000')); | ||
significand.low = significand.low.add(significandLow); | ||
if(lessThan(significand.low, significandLow)) { | ||
if (lessThan(significand.low, significandLow)) { | ||
significand.high = significand.high.add(Long.fromNumber(1)); | ||
@@ -479,10 +521,17 @@ } | ||
// Biased exponent | ||
var biasedExponent = (exponent + EXPONENT_BIAS); | ||
biasedExponent = exponent + EXPONENT_BIAS; | ||
var dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) }; | ||
// Encode combination, exponent, and significand. | ||
if(significand.high.shiftRightUnsigned(49).and(Long.fromNumber(1)).equals(Long.fromNumber)) { | ||
if ( | ||
significand.high | ||
.shiftRightUnsigned(49) | ||
.and(Long.fromNumber(1)) | ||
.equals(Long.fromNumber) | ||
) { | ||
// Encode '11' into bits 1 to 3 | ||
dec.high = dec.high.or(Long.fromNumber(0x3).shiftLeft(61)); | ||
dec.high = dec.high.or(Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47))); | ||
dec.high = dec.high.or( | ||
Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47)) | ||
); | ||
dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x7fffffffffff))); | ||
@@ -497,3 +546,3 @@ } else { | ||
// Encode sign | ||
if(isNegative) { | ||
if (isNegative) { | ||
dec.high = dec.high.or(Long.fromString('9223372036854775808')); | ||
@@ -504,3 +553,3 @@ } | ||
var buffer = new Buffer(16); | ||
var index = 0; | ||
index = 0; | ||
@@ -533,3 +582,3 @@ // Encode the low 64 bits of the decimal | ||
return new Decimal128(buffer); | ||
} | ||
}; | ||
@@ -545,6 +594,12 @@ // Extract least significant 5 bits | ||
// Value of combination field for NaN | ||
var COMBINATION_SNAN = 32; | ||
// var COMBINATION_SNAN = 32; | ||
// decimal128 exponent bias | ||
var EXPONENT_BIAS = 6176; | ||
EXPONENT_BIAS = 6176; | ||
/** | ||
* Create a string representation of the raw Decimal128 value | ||
* | ||
* @method | ||
* @return {string} returns a Decimal128 string representation. | ||
*/ | ||
Decimal128.prototype.toString = function() { | ||
@@ -570,3 +625,3 @@ // Note: bits in this routine are referred to starting at 0, | ||
var significand = new Array(36); | ||
for(var i = 0; i < significand.length; i++) significand[i] = 0; | ||
for (var i = 0; i < significand.length; i++) significand[i] = 0; | ||
// read pointer into significand | ||
@@ -586,5 +641,4 @@ var index = 0; | ||
// temporary storage for significand decoding | ||
var significand128 = {parts: new Array(4)}; | ||
var significand128 = { parts: new Array(4) }; | ||
// indexing variables | ||
var i; | ||
var j, k; | ||
@@ -596,3 +650,3 @@ | ||
// Unpack index | ||
var index = 0; | ||
index = 0; | ||
@@ -603,11 +657,15 @@ // Buffer reference | ||
// Unpack the low 64bits into a long | ||
low = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
midl = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
low = | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24); | ||
midl = | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24); | ||
// Unpack the high 64bits into a long | ||
midh = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
high = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
midh = | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24); | ||
high = | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24); | ||
// Unpack index | ||
var index = 0; | ||
index = 0; | ||
@@ -617,5 +675,6 @@ // Create the state of the decimal | ||
low: new Long(low, midl), | ||
high: new Long(midh, high) }; | ||
high: new Long(midh, high) | ||
}; | ||
if(dec.high.lessThan(Long.ZERO)) { | ||
if (dec.high.lessThan(Long.ZERO)) { | ||
string.push('-'); | ||
@@ -627,8 +686,8 @@ } | ||
if((combination >> 3) == 3) { | ||
if (combination >> 3 === 3) { | ||
// Check for 'special' values | ||
if(combination == COMBINATION_INFINITY) { | ||
return string.join('') + "Infinity"; | ||
} else if(combination == COMBINATION_NAN) { | ||
return "NaN"; | ||
if (combination === COMBINATION_INFINITY) { | ||
return string.join('') + 'Infinity'; | ||
} else if (combination === COMBINATION_NAN) { | ||
return 'NaN'; | ||
} else { | ||
@@ -655,7 +714,11 @@ biased_exponent = (high >> 15) & EXPONENT_MASK; | ||
if(significand128.parts[0] == 0 && significand128.parts[1] == 0 | ||
&& significand128.parts[2] == 0 && significand128.parts[3] == 0) { | ||
is_zero = true; | ||
if ( | ||
significand128.parts[0] === 0 && | ||
significand128.parts[1] === 0 && | ||
significand128.parts[2] === 0 && | ||
significand128.parts[3] === 0 | ||
) { | ||
is_zero = true; | ||
} else { | ||
for(var k = 3; k >= 0; k--) { | ||
for (k = 3; k >= 0; k--) { | ||
var least_digits = 0; | ||
@@ -669,5 +732,5 @@ // Peform the divide | ||
// Convert and output to string. | ||
if(!least_digits) continue; | ||
if (!least_digits) continue; | ||
for(var j = 8; j >= 0; j--) { | ||
for (j = 8; j >= 0; j--) { | ||
// significand[k * 9 + j] = Math.round(least_digits % 10); | ||
@@ -685,3 +748,3 @@ significand[k * 9 + j] = least_digits % 10; | ||
if(is_zero) { | ||
if (is_zero) { | ||
significand_digits = 1; | ||
@@ -691,5 +754,5 @@ significand[index] = 0; | ||
significand_digits = 36; | ||
var i = 0; | ||
i = 0; | ||
while(!significand[index]) { | ||
while (!significand[index]) { | ||
i++; | ||
@@ -710,14 +773,23 @@ significand_digits = significand_digits - 1; | ||
// change stored data if the string converted number is round tripped. | ||
if (scientific_exponent >= 34 || scientific_exponent <= -7 || exponent > 0) { | ||
// Scientific format | ||
if(scientific_exponent >= 34 || scientific_exponent <= -7 || | ||
exponent > 0) { | ||
// Scientific format | ||
// if there are too many significant digits, we should just be treating numbers | ||
// as + or - 0 and using the non-scientific exponent (this is for the "invalid | ||
// representation should be treated as 0/-0" spec cases in decimal128-1.json) | ||
if (significand_digits > 34) { | ||
string.push(0); | ||
if (exponent > 0) string.push('E+' + exponent); | ||
else if (exponent < 0) string.push('E' + exponent); | ||
return string.join(''); | ||
} | ||
string.push(significand[index++]); | ||
significand_digits = significand_digits - 1; | ||
if(significand_digits) { | ||
if (significand_digits) { | ||
string.push('.'); | ||
} | ||
for(var i = 0; i < significand_digits; i++) { | ||
for (i = 0; i < significand_digits; i++) { | ||
string.push(significand[index++]); | ||
@@ -728,3 +800,3 @@ } | ||
string.push('E'); | ||
if(scientific_exponent > 0) { | ||
if (scientific_exponent > 0) { | ||
string.push('+' + scientific_exponent); | ||
@@ -736,4 +808,4 @@ } else { | ||
// Regular format with no decimal place | ||
if(exponent >= 0) { | ||
for(var i = 0; i < significand_digits; i++) { | ||
if (exponent >= 0) { | ||
for (i = 0; i < significand_digits; i++) { | ||
string.push(significand[index++]); | ||
@@ -745,4 +817,4 @@ } | ||
// non-zero digits before radix | ||
if(radix_position > 0) { | ||
for(var i = 0; i < radix_position; i++) { | ||
if (radix_position > 0) { | ||
for (i = 0; i < radix_position; i++) { | ||
string.push(significand[index++]); | ||
@@ -756,7 +828,7 @@ } | ||
// add leading zeros after radix | ||
while(radix_position++ < 0) { | ||
while (radix_position++ < 0) { | ||
string.push('0'); | ||
} | ||
for(var i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) { | ||
for (i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) { | ||
string.push(significand[index++]); | ||
@@ -768,9 +840,9 @@ } | ||
return string.join(''); | ||
} | ||
}; | ||
Decimal128.prototype.toJSON = function() { | ||
return { "$numberDecimal": this.toString() }; | ||
} | ||
return { $numberDecimal: this.toString() }; | ||
}; | ||
module.exports = Decimal128; | ||
module.exports.Decimal128 = Decimal128; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -9,3 +10,3 @@ * A class representation of the BSON Double type. | ||
function Double(value) { | ||
if(!(this instanceof Double)) return new Double(value); | ||
if (!(this instanceof Double)) return new Double(value); | ||
@@ -31,5 +32,5 @@ this._bsontype = 'Double'; | ||
return this.value; | ||
} | ||
}; | ||
module.exports = Double; | ||
module.exports.Double = Double; |
@@ -0,18 +1,19 @@ | ||
'use strict'; | ||
// Copyright (c) 2008, Fair Oaks Labs, Inc. | ||
// All rights reserved. | ||
// | ||
// | ||
// Redistribution and use in source and binary forms, with or without | ||
// modification, are permitted provided that the following conditions are met: | ||
// | ||
// | ||
// * Redistributions of source code must retain the above copyright notice, | ||
// this list of conditions and the following disclaimer. | ||
// | ||
// | ||
// * Redistributions in binary form must reproduce the above copyright notice, | ||
// this list of conditions and the following disclaimer in the documentation | ||
// and/or other materials provided with the distribution. | ||
// | ||
// | ||
// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors | ||
// may be used to endorse or promote products derived from this software | ||
// without specific prior written permission. | ||
// | ||
// | ||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
@@ -34,21 +35,22 @@ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
var readIEEE754 = function(buffer, offset, endian, mLen, nBytes) { | ||
var e, m, | ||
bBE = (endian === 'big'), | ||
eLen = nBytes * 8 - mLen - 1, | ||
eMax = (1 << eLen) - 1, | ||
eBias = eMax >> 1, | ||
nBits = -7, | ||
i = bBE ? 0 : (nBytes - 1), | ||
d = bBE ? 1 : -1, | ||
s = buffer[offset + i]; | ||
var e, | ||
m, | ||
bBE = endian === 'big', | ||
eLen = nBytes * 8 - mLen - 1, | ||
eMax = (1 << eLen) - 1, | ||
eBias = eMax >> 1, | ||
nBits = -7, | ||
i = bBE ? 0 : nBytes - 1, | ||
d = bBE ? 1 : -1, | ||
s = buffer[offset + i]; | ||
i += d; | ||
e = s & ((1 << (-nBits)) - 1); | ||
s >>= (-nBits); | ||
e = s & ((1 << -nBits) - 1); | ||
s >>= -nBits; | ||
nBits += eLen; | ||
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); | ||
m = e & ((1 << (-nBits)) - 1); | ||
e >>= (-nBits); | ||
m = e & ((1 << -nBits) - 1); | ||
e >>= -nBits; | ||
nBits += mLen; | ||
@@ -60,3 +62,3 @@ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); | ||
} else if (e === eMax) { | ||
return m ? NaN : ((s ? -1 : 1) * Infinity); | ||
return m ? NaN : (s ? -1 : 1) * Infinity; | ||
} else { | ||
@@ -70,11 +72,13 @@ m = m + Math.pow(2, mLen); | ||
var writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) { | ||
var e, m, c, | ||
bBE = (endian === 'big'), | ||
eLen = nBytes * 8 - mLen - 1, | ||
eMax = (1 << eLen) - 1, | ||
eBias = eMax >> 1, | ||
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), | ||
i = bBE ? (nBytes-1) : 0, | ||
d = bBE ? -1 : 1, | ||
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; | ||
var e, | ||
m, | ||
c, | ||
bBE = endian === 'big', | ||
eLen = nBytes * 8 - mLen - 1, | ||
eMax = (1 << eLen) - 1, | ||
eBias = eMax >> 1, | ||
rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0, | ||
i = bBE ? nBytes - 1 : 0, | ||
d = bBE ? -1 : 1, | ||
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; | ||
@@ -92,3 +96,3 @@ value = Math.abs(value); | ||
} | ||
if (e+eBias >= 1) { | ||
if (e + eBias >= 1) { | ||
value += rt / c; | ||
@@ -115,8 +119,24 @@ } else { | ||
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); | ||
if (isNaN(value)) m = 0; | ||
while (mLen >= 8) { | ||
buffer[offset + i] = m & 0xff; | ||
i += d; | ||
m /= 256; | ||
mLen -= 8; | ||
} | ||
e = (e << mLen) | m; | ||
if (isNaN(value)) e += 8; | ||
eLen += mLen; | ||
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); | ||
while (eLen > 0) { | ||
buffer[offset + i] = e & 0xff; | ||
i += d; | ||
e /= 256; | ||
eLen -= 8; | ||
} | ||
buffer[offset + i - d] |= s * 128; | ||
@@ -126,2 +146,2 @@ }; | ||
exports.readIEEE754 = readIEEE754; | ||
exports.writeIEEE754 = writeIEEE754; | ||
exports.writeIEEE754 = writeIEEE754; |
@@ -0,7 +1,15 @@ | ||
'use strict'; | ||
/** | ||
* A class representation of a BSON Int32 type. | ||
* | ||
* @class | ||
* @param {number} value the number we want to represent as an int32. | ||
* @return {Int32} | ||
*/ | ||
var Int32 = function(value) { | ||
if(!(this instanceof Int32)) return new Int32(value); | ||
if (!(this instanceof Int32)) return new Int32(value); | ||
this._bsontype = 'Int32'; | ||
this.value = value; | ||
} | ||
}; | ||
@@ -23,5 +31,5 @@ /** | ||
return this.value; | ||
} | ||
}; | ||
module.exports = Int32; | ||
module.exports.Int32 = Int32; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
@@ -44,4 +45,4 @@ // you may not use this file except in compliance with the License. | ||
function Long(low, high) { | ||
if(!(this instanceof Long)) return new Long(low, high); | ||
if (!(this instanceof Long)) return new Long(low, high); | ||
this._bsontype = 'Long'; | ||
@@ -52,3 +53,3 @@ /** | ||
*/ | ||
this.low_ = low | 0; // force into 32 signed bits. | ||
this.low_ = low | 0; // force into 32 signed bits. | ||
@@ -59,4 +60,4 @@ /** | ||
*/ | ||
this.high_ = high | 0; // force into 32 signed bits. | ||
}; | ||
this.high_ = high | 0; // force into 32 signed bits. | ||
} | ||
@@ -80,4 +81,3 @@ /** | ||
Long.prototype.toNumber = function() { | ||
return this.high_ * Long.TWO_PWR_32_DBL_ + | ||
this.getLowBitsUnsigned(); | ||
return this.high_ * Long.TWO_PWR_32_DBL_ + this.getLowBitsUnsigned(); | ||
}; | ||
@@ -93,3 +93,3 @@ | ||
return this.toString(); | ||
} | ||
}; | ||
@@ -130,5 +130,6 @@ /** | ||
var rem = this; | ||
rem = this; | ||
var result = ''; | ||
while (true) { | ||
while (!rem.isZero()) { | ||
var remDiv = rem.div(radixToPower); | ||
@@ -177,4 +178,3 @@ var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); | ||
Long.prototype.getLowBitsUnsigned = function() { | ||
return (this.low_ >= 0) ? | ||
this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; | ||
return this.low_ >= 0 ? this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; | ||
}; | ||
@@ -196,9 +196,9 @@ | ||
} else { | ||
var val = this.high_ != 0 ? this.high_ : this.low_; | ||
var val = this.high_ !== 0 ? this.high_ : this.low_; | ||
for (var bit = 31; bit > 0; bit--) { | ||
if ((val & (1 << bit)) != 0) { | ||
if ((val & (1 << bit)) !== 0) { | ||
break; | ||
} | ||
} | ||
return this.high_ != 0 ? bit + 33 : bit + 1; | ||
return this.high_ !== 0 ? bit + 33 : bit + 1; | ||
} | ||
@@ -214,3 +214,3 @@ }; | ||
Long.prototype.isZero = function() { | ||
return this.high_ == 0 && this.low_ == 0; | ||
return this.high_ === 0 && this.low_ === 0; | ||
}; | ||
@@ -235,3 +235,3 @@ | ||
Long.prototype.isOdd = function() { | ||
return (this.low_ & 1) == 1; | ||
return (this.low_ & 1) === 1; | ||
}; | ||
@@ -247,3 +247,3 @@ | ||
Long.prototype.equals = function(other) { | ||
return (this.high_ == other.high_) && (this.low_ == other.low_); | ||
return this.high_ === other.high_ && this.low_ === other.low_; | ||
}; | ||
@@ -259,3 +259,3 @@ | ||
Long.prototype.notEquals = function(other) { | ||
return (this.high_ != other.high_) || (this.low_ != other.low_); | ||
return this.high_ !== other.high_ || this.low_ !== other.low_; | ||
}; | ||
@@ -361,23 +361,26 @@ | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a32 = this.high_ & 0xffff; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var a00 = this.low_ & 0xffff; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b32 = other.high_ & 0xffff; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var b00 = other.low_ & 0xffff; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
var c48 = 0, | ||
c32 = 0, | ||
c16 = 0, | ||
c00 = 0; | ||
c00 += a00 + b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c00 &= 0xffff; | ||
c16 += a16 + b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c16 &= 0xffff; | ||
c32 += a32 + b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 &= 0xffff; | ||
c48 += a48 + b48; | ||
c48 &= 0xFFFF; | ||
c48 &= 0xffff; | ||
return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
@@ -421,3 +424,5 @@ }; | ||
} else { | ||
return this.negate().multiply(other).negate(); | ||
return this.negate() | ||
.multiply(other) | ||
.negate(); | ||
} | ||
@@ -429,4 +434,3 @@ } else if (other.isNegative()) { | ||
// If both Longs are small, use float multiplication | ||
if (this.lessThan(Long.TWO_PWR_24_) && | ||
other.lessThan(Long.TWO_PWR_24_)) { | ||
if (this.lessThan(Long.TWO_PWR_24_) && other.lessThan(Long.TWO_PWR_24_)) { | ||
return Long.fromNumber(this.toNumber() * other.toNumber()); | ||
@@ -439,32 +443,35 @@ } | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a32 = this.high_ & 0xffff; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var a00 = this.low_ & 0xffff; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b32 = other.high_ & 0xffff; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var b00 = other.low_ & 0xffff; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
var c48 = 0, | ||
c32 = 0, | ||
c16 = 0, | ||
c00 = 0; | ||
c00 += a00 * b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c00 &= 0xffff; | ||
c16 += a16 * b00; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c16 &= 0xffff; | ||
c16 += a00 * b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c16 &= 0xffff; | ||
c32 += a32 * b00; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 &= 0xffff; | ||
c32 += a16 * b16; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 &= 0xffff; | ||
c32 += a00 * b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 &= 0xffff; | ||
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; | ||
c48 &= 0xFFFF; | ||
c48 &= 0xffff; | ||
return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
@@ -488,5 +495,4 @@ }; | ||
if (this.equals(Long.MIN_VALUE)) { | ||
if (other.equals(Long.ONE) || | ||
other.equals(Long.NEG_ONE)) { | ||
return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
if (other.equals(Long.ONE) || other.equals(Long.NEG_ONE)) { | ||
return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
} else if (other.equals(Long.MIN_VALUE)) { | ||
@@ -514,3 +520,5 @@ return Long.ONE; | ||
} else { | ||
return this.negate().div(other).negate(); | ||
return this.negate() | ||
.div(other) | ||
.negate(); | ||
} | ||
@@ -527,7 +535,7 @@ } else if (other.isNegative()) { | ||
var res = Long.ZERO; | ||
var rem = this; | ||
rem = this; | ||
while (rem.greaterThanOrEqual(other)) { | ||
// Approximate the result of division. This may be a little greater or | ||
// smaller than the actual value. | ||
var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
@@ -537,3 +545,3 @@ // We will tweak the approximate result by changing it in the 48-th digit or | ||
var log2 = Math.ceil(Math.log(approx) / Math.LN2); | ||
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); | ||
var delta = log2 <= 48 ? 1 : Math.pow(2, log2 - 48); | ||
@@ -625,3 +633,3 @@ // Decrease the approximation until it is smaller than the remainder. Note | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
if (numBits === 0) { | ||
return this; | ||
@@ -632,5 +640,3 @@ } else { | ||
var high = this.high_; | ||
return Long.fromBits( | ||
low << numBits, | ||
(high << numBits) | (low >>> (32 - numBits))); | ||
return Long.fromBits(low << numBits, (high << numBits) | (low >>> (32 - numBits))); | ||
} else { | ||
@@ -651,3 +657,3 @@ return Long.fromBits(0, low << (numBits - 32)); | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
if (numBits === 0) { | ||
return this; | ||
@@ -658,9 +664,5 @@ } else { | ||
var low = this.low_; | ||
return Long.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >> numBits); | ||
return Long.fromBits((low >>> numBits) | (high << (32 - numBits)), high >> numBits); | ||
} else { | ||
return Long.fromBits( | ||
high >> (numBits - 32), | ||
high >= 0 ? 0 : -1); | ||
return Long.fromBits(high >> (numBits - 32), high >= 0 ? 0 : -1); | ||
} | ||
@@ -679,3 +681,3 @@ } | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
if (numBits === 0) { | ||
return this; | ||
@@ -686,6 +688,4 @@ } else { | ||
var low = this.low_; | ||
return Long.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >>> numBits); | ||
} else if (numBits == 32) { | ||
return Long.fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits); | ||
} else if (numBits === 32) { | ||
return Long.fromBits(high, 0); | ||
@@ -737,5 +737,3 @@ } else { | ||
} else { | ||
return new Long( | ||
(value % Long.TWO_PWR_32_DBL_) | 0, | ||
(value / Long.TWO_PWR_32_DBL_) | 0); | ||
return new Long((value % Long.TWO_PWR_32_DBL_) | 0, (value / Long.TWO_PWR_32_DBL_) | 0); | ||
} | ||
@@ -765,3 +763,3 @@ }; | ||
Long.fromString = function(str, opt_radix) { | ||
if (str.length == 0) { | ||
if (str.length === 0) { | ||
throw Error('number format error: empty string'); | ||
@@ -775,3 +773,3 @@ } | ||
if (str.charAt(0) == '-') { | ||
if (str.charAt(0) === '-') { | ||
return Long.fromString(str.substring(1), radix).negate(); | ||
@@ -804,3 +802,2 @@ } else if (str.indexOf('-') >= 0) { | ||
/** | ||
@@ -870,4 +867,3 @@ * A cache of the Long representations of small integer values. | ||
/** @type {Long} */ | ||
Long.MAX_VALUE = | ||
Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); | ||
Long.MAX_VALUE = Long.fromBits(0xffffffff | 0, 0x7fffffff | 0); | ||
@@ -887,2 +883,2 @@ /** @type {Long} */ | ||
module.exports = Long; | ||
module.exports.Long = Long; | ||
module.exports.Long = Long; |
@@ -1,5 +0,5 @@ | ||
"use strict" | ||
'use strict'; | ||
// We have an ES6 Map available, return the native instance | ||
if(typeof global.Map !== 'undefined') { | ||
if (typeof global.Map !== 'undefined') { | ||
module.exports = global.Map; | ||
@@ -13,4 +13,4 @@ module.exports.Map = global.Map; | ||
for(var i = 0; i < array.length; i++) { | ||
if(array[i] == null) continue; // skip null and undefined | ||
for (var i = 0; i < array.length; i++) { | ||
if (array[i] == null) continue; // skip null and undefined | ||
var entry = array[i]; | ||
@@ -23,5 +23,5 @@ var key = entry[0]; | ||
// to the location in the ordered keys list | ||
this._values[key] = {v: value, i: this._keys.length - 1}; | ||
this._values[key] = { v: value, i: this._keys.length - 1 }; | ||
} | ||
} | ||
}; | ||
@@ -31,7 +31,7 @@ Map.prototype.clear = function() { | ||
this._values = {}; | ||
} | ||
}; | ||
Map.prototype.delete = function(key) { | ||
var value = this._values[key]; | ||
if(value == null) return false; | ||
if (value == null) return false; | ||
// Delete entry | ||
@@ -42,3 +42,3 @@ delete this._values[key]; | ||
return true; | ||
} | ||
}; | ||
@@ -55,6 +55,6 @@ Map.prototype.entries = function() { | ||
done: key !== undefined ? false : true | ||
} | ||
}; | ||
} | ||
}; | ||
} | ||
}; | ||
@@ -64,3 +64,3 @@ Map.prototype.forEach = function(callback, self) { | ||
for(var i = 0; i < this._keys.length; i++) { | ||
for (var i = 0; i < this._keys.length; i++) { | ||
var key = this._keys[i]; | ||
@@ -70,13 +70,13 @@ // Call the forEach callback | ||
} | ||
} | ||
}; | ||
Map.prototype.get = function(key) { | ||
return this._values[key] ? this._values[key].v : undefined; | ||
} | ||
}; | ||
Map.prototype.has = function(key) { | ||
return this._values[key] != null; | ||
} | ||
}; | ||
Map.prototype.keys = function(key) { | ||
Map.prototype.keys = function() { | ||
var self = this; | ||
@@ -91,9 +91,9 @@ var index = 0; | ||
done: key !== undefined ? false : true | ||
} | ||
}; | ||
} | ||
}; | ||
} | ||
}; | ||
Map.prototype.set = function(key, value) { | ||
if(this._values[key]) { | ||
if (this._values[key]) { | ||
this._values[key].v = value; | ||
@@ -107,7 +107,7 @@ return this; | ||
// to the location in the ordered keys list | ||
this._values[key] = {v: value, i: this._keys.length - 1}; | ||
this._values[key] = { v: value, i: this._keys.length - 1 }; | ||
return this; | ||
} | ||
}; | ||
Map.prototype.values = function(key, value) { | ||
Map.prototype.values = function() { | ||
var self = this; | ||
@@ -122,11 +122,13 @@ var index = 0; | ||
done: key !== undefined ? false : true | ||
} | ||
}; | ||
} | ||
}; | ||
} | ||
}; | ||
// Last ismaster | ||
Object.defineProperty(Map.prototype, 'size', { | ||
enumerable:true, | ||
get: function() { return this._keys.length; } | ||
enumerable: true, | ||
get: function() { | ||
return this._keys.length; | ||
} | ||
}); | ||
@@ -136,2 +138,2 @@ | ||
module.exports.Map = Map; | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -8,8 +9,8 @@ * A class representation of the BSON MaxKey type. | ||
function MaxKey() { | ||
if(!(this instanceof MaxKey)) return new MaxKey(); | ||
this._bsontype = 'MaxKey'; | ||
if (!(this instanceof MaxKey)) return new MaxKey(); | ||
this._bsontype = 'MaxKey'; | ||
} | ||
module.exports = MaxKey; | ||
module.exports.MaxKey = MaxKey; | ||
module.exports.MaxKey = MaxKey; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -8,4 +9,4 @@ * A class representation of the BSON MinKey type. | ||
function MinKey() { | ||
if(!(this instanceof MinKey)) return new MinKey(); | ||
if (!(this instanceof MinKey)) return new MinKey(); | ||
this._bsontype = 'MinKey'; | ||
@@ -15,2 +16,2 @@ } | ||
module.exports = MinKey; | ||
module.exports.MinKey = MinKey; | ||
module.exports.MinKey = MinKey; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -9,12 +10,13 @@ * Machine id. | ||
*/ | ||
var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); | ||
var MACHINE_ID = parseInt(Math.random() * 0xffffff, 10); | ||
// Regular expression that checks for hex value | ||
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); | ||
var hasBufferType = false; | ||
var checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$'); | ||
// Check if buffer exists | ||
try { | ||
if(Buffer && Buffer.from) hasBufferType = true; | ||
} catch(err) {}; | ||
if (Buffer && Buffer.from) var hasBufferType = true; | ||
} catch (err) { | ||
hasBufferType = false; | ||
} | ||
@@ -31,4 +33,4 @@ /** | ||
// Duck-typing to support ObjectId from different npm packages | ||
if(id instanceof ObjectID) return id; | ||
if(!(this instanceof ObjectID)) return new ObjectID(id); | ||
if (id instanceof ObjectID) return id; | ||
if (!(this instanceof ObjectID)) return new ObjectID(id); | ||
@@ -38,7 +40,7 @@ this._bsontype = 'ObjectID'; | ||
// The most common usecase (blank id, new objectId instance) | ||
if(id == null || typeof id == 'number') { | ||
if (id == null || typeof id === 'number') { | ||
// Generate a new id | ||
this.id = this.generate(id); | ||
// If we are caching the hex string | ||
if(ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
if (ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
// Return the object | ||
@@ -52,23 +54,27 @@ return; | ||
// Throw an error if it's not a valid setup | ||
if(!valid && id != null){ | ||
throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
} else if(valid && typeof id == 'string' && id.length == 24 && hasBufferType) { | ||
if (!valid && id != null) { | ||
throw new Error( | ||
'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters' | ||
); | ||
} else if (valid && typeof id === 'string' && id.length === 24 && hasBufferType) { | ||
return new ObjectID(new Buffer(id, 'hex')); | ||
} else if(valid && typeof id == 'string' && id.length == 24) { | ||
} else if (valid && typeof id === 'string' && id.length === 24) { | ||
return ObjectID.createFromHexString(id); | ||
} else if(id != null && id.length === 12) { | ||
} else if (id != null && id.length === 12) { | ||
// assume 12 byte string | ||
this.id = id; | ||
} else if(id != null && id.toHexString) { | ||
} else if (id != null && id.toHexString) { | ||
// Duck-typing to support ObjectId from different npm packages | ||
return id; | ||
} else { | ||
throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
throw new Error( | ||
'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters' | ||
); | ||
} | ||
if(ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
if (ObjectID.cacheHexString) this.__id = this.toString('hex'); | ||
}; | ||
// Allow usage of ObjectId as well as ObjectID | ||
var ObjectId = ObjectID; | ||
// var ObjectId = ObjectID; | ||
@@ -88,12 +94,16 @@ // Precomputed hex table enables speedy hex string conversion | ||
ObjectID.prototype.toHexString = function() { | ||
if(ObjectID.cacheHexString && this.__id) return this.__id; | ||
if (ObjectID.cacheHexString && this.__id) return this.__id; | ||
var hexString = ''; | ||
if(!this.id || !this.id.length) { | ||
throw new Error('invalid ObjectId, ObjectId.id must be either a string or a Buffer, but is [' + JSON.stringify(this.id) + ']'); | ||
if (!this.id || !this.id.length) { | ||
throw new Error( | ||
'invalid ObjectId, ObjectId.id must be either a string or a Buffer, but is [' + | ||
JSON.stringify(this.id) + | ||
']' | ||
); | ||
} | ||
if(this.id instanceof _Buffer) { | ||
if (this.id instanceof _Buffer) { | ||
hexString = convertToHex(this.id); | ||
if(ObjectID.cacheHexString) this.__id = hexString; | ||
if (ObjectID.cacheHexString) this.__id = hexString; | ||
return hexString; | ||
@@ -106,3 +116,3 @@ } | ||
if(ObjectID.cacheHexString) this.__id = hexString; | ||
if (ObjectID.cacheHexString) this.__id = hexString; | ||
return hexString; | ||
@@ -119,3 +129,3 @@ }; | ||
ObjectID.prototype.get_inc = function() { | ||
return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF; | ||
return (ObjectID.index = (ObjectID.index + 1) % 0xffffff); | ||
}; | ||
@@ -142,8 +152,11 @@ | ||
ObjectID.prototype.generate = function(time) { | ||
if ('number' != typeof time) { | ||
time = ~~(Date.now()/1000); | ||
if ('number' !== typeof time) { | ||
time = ~~(Date.now() / 1000); | ||
} | ||
// Use pid | ||
var pid = (typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid) % 0xFFFF; | ||
var pid = | ||
(typeof process === 'undefined' || process.pid === 1 | ||
? Math.floor(Math.random() * 100000) | ||
: process.pid) % 0xffff; | ||
var inc = this.get_inc(); | ||
@@ -181,3 +194,3 @@ // Buffer used | ||
// Is the id a buffer then use the buffer toString method to return the format | ||
if(this.id && this.id.copy) { | ||
if (this.id && this.id.copy) { | ||
return this.id.toString(typeof format === 'string' ? format : 'hex'); | ||
@@ -215,14 +228,19 @@ } | ||
*/ | ||
ObjectID.prototype.equals = function equals (otherId) { | ||
var id; | ||
ObjectID.prototype.equals = function equals(otherId) { | ||
// var id; | ||
if(otherId instanceof ObjectID) { | ||
return this.toString() == otherId.toString(); | ||
} else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 12 && this.id instanceof _Buffer) { | ||
if (otherId instanceof ObjectID) { | ||
return this.toString() === otherId.toString(); | ||
} else if ( | ||
typeof otherId === 'string' && | ||
ObjectID.isValid(otherId) && | ||
otherId.length === 12 && | ||
this.id instanceof _Buffer | ||
) { | ||
return otherId === this.id.toString('binary'); | ||
} else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 24) { | ||
} else if (typeof otherId === 'string' && ObjectID.isValid(otherId) && otherId.length === 24) { | ||
return otherId.toLowerCase() === this.toHexString(); | ||
} else if(typeof otherId == 'string' && ObjectID.isValid(otherId) && otherId.length == 12) { | ||
} else if (typeof otherId === 'string' && ObjectID.isValid(otherId) && otherId.length === 12) { | ||
return otherId === this.id; | ||
} else if(otherId != null && (otherId instanceof ObjectID || otherId.toHexString)) { | ||
} else if (otherId != null && (otherId instanceof ObjectID || otherId.toHexString)) { | ||
return otherId.toHexString() === this.toHexString(); | ||
@@ -232,3 +250,3 @@ } else { | ||
} | ||
} | ||
}; | ||
@@ -243,6 +261,6 @@ /** | ||
var timestamp = new Date(); | ||
var time = this.id[3] | this.id[2] << 8 | this.id[1] << 16 | this.id[0] << 24; | ||
var time = this.id[3] | (this.id[2] << 8) | (this.id[1] << 16) | (this.id[0] << 24); | ||
timestamp.setTime(Math.floor(time) * 1000); | ||
return timestamp; | ||
} | ||
}; | ||
@@ -252,3 +270,3 @@ /** | ||
*/ | ||
ObjectID.index = ~~(Math.random() * 0xFFFFFF); | ||
ObjectID.index = ~~(Math.random() * 0xffffff); | ||
@@ -258,3 +276,3 @@ /** | ||
*/ | ||
ObjectID.createPk = function createPk () { | ||
ObjectID.createPk = function createPk() { | ||
return new ObjectID(); | ||
@@ -270,3 +288,3 @@ }; | ||
*/ | ||
ObjectID.createFromTime = function createFromTime (time) { | ||
ObjectID.createFromTime = function createFromTime(time) { | ||
var buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | ||
@@ -283,7 +301,7 @@ // Encode time into first 4 bytes | ||
// Lookup tables | ||
var encodeLookup = '0123456789abcdef'.split('') | ||
var decodeLookup = [] | ||
var i = 0 | ||
while (i < 10) decodeLookup[0x30 + i] = i++ | ||
while (i < 16) decodeLookup[0x41 - 10 + i] = decodeLookup[0x61 - 10 + i] = i++ | ||
//var encodeLookup = '0123456789abcdef'.split(''); | ||
var decodeLookup = []; | ||
i = 0; | ||
while (i < 10) decodeLookup[0x30 + i] = i++; | ||
while (i < 16) decodeLookup[0x41 - 10 + i] = decodeLookup[0x61 - 10 + i] = i++; | ||
@@ -293,3 +311,3 @@ var _Buffer = Buffer; | ||
return bytes.toString('hex'); | ||
} | ||
}; | ||
@@ -303,10 +321,12 @@ /** | ||
*/ | ||
ObjectID.createFromHexString = function createFromHexString (string) { | ||
ObjectID.createFromHexString = function createFromHexString(string) { | ||
// Throw an error if it's not a valid setup | ||
if(typeof string === 'undefined' || string != null && string.length != 24) { | ||
throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); | ||
if (typeof string === 'undefined' || (string != null && string.length !== 24)) { | ||
throw new Error( | ||
'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters' | ||
); | ||
} | ||
// Use Buffer.from method if available | ||
if(hasBufferType) return new ObjectID(new Buffer(string, 'hex')); | ||
if (hasBufferType) return new ObjectID(new Buffer(string, 'hex')); | ||
@@ -319,3 +339,3 @@ // Calculate lengths | ||
while (i < 24) { | ||
array[n++] = decodeLookup[string.charCodeAt(i++)] << 4 | decodeLookup[string.charCodeAt(i++)] | ||
array[n++] = (decodeLookup[string.charCodeAt(i++)] << 4) | decodeLookup[string.charCodeAt(i++)]; | ||
} | ||
@@ -333,17 +353,17 @@ | ||
ObjectID.isValid = function isValid(id) { | ||
if(id == null) return false; | ||
if (id == null) return false; | ||
if(typeof id == 'number') { | ||
if (typeof id === 'number') { | ||
return true; | ||
} | ||
if(typeof id == 'string') { | ||
return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id)); | ||
if (typeof id === 'string') { | ||
return id.length === 12 || (id.length === 24 && checkForHexRegExp.test(id)); | ||
} | ||
if(id instanceof ObjectID) { | ||
if (id instanceof ObjectID) { | ||
return true; | ||
} | ||
if(id instanceof _Buffer) { | ||
if (id instanceof _Buffer) { | ||
return true; | ||
@@ -353,4 +373,4 @@ } | ||
// Duck-Typing detection of ObjectId like objects | ||
if(id.toHexString) { | ||
return id.id.length == 12 || (id.id.length == 24 && checkForHexRegExp.test(id.id)); | ||
if (id.toHexString) { | ||
return id.id.length === 12 || (id.id.length === 24 && checkForHexRegExp.test(id.id)); | ||
} | ||
@@ -364,14 +384,14 @@ | ||
*/ | ||
Object.defineProperty(ObjectID.prototype, "generationTime", { | ||
enumerable: true | ||
, get: function () { | ||
return this.id[3] | this.id[2] << 8 | this.id[1] << 16 | this.id[0] << 24; | ||
} | ||
, set: function (value) { | ||
// Encode time into first 4 bytes | ||
this.id[3] = value & 0xff; | ||
this.id[2] = (value >> 8) & 0xff; | ||
this.id[1] = (value >> 16) & 0xff; | ||
this.id[0] = (value >> 24) & 0xff; | ||
} | ||
Object.defineProperty(ObjectID.prototype, 'generationTime', { | ||
enumerable: true, | ||
get: function() { | ||
return this.id[3] | (this.id[2] << 8) | (this.id[1] << 16) | (this.id[0] << 24); | ||
}, | ||
set: function(value) { | ||
// Encode time into first 4 bytes | ||
this.id[3] = value & 0xff; | ||
this.id[2] = (value >> 8) & 0xff; | ||
this.id[1] = (value >> 16) & 0xff; | ||
this.id[0] = (value >> 24) & 0xff; | ||
} | ||
}); | ||
@@ -378,0 +398,0 @@ |
@@ -1,17 +0,15 @@ | ||
"use strict" | ||
'use strict'; | ||
var writeIEEE754 = require('../float_parser').writeIEEE754 | ||
, readIEEE754 = require('../float_parser').readIEEE754 | ||
, Long = require('../long').Long | ||
, Double = require('../double').Double | ||
, Timestamp = require('../timestamp').Timestamp | ||
, ObjectID = require('../objectid').ObjectID | ||
, Symbol = require('../symbol').Symbol | ||
, BSONRegExp = require('../regexp').BSONRegExp | ||
, Code = require('../code').Code | ||
, Decimal128 = require('../decimal128') | ||
, MinKey = require('../min_key').MinKey | ||
, MaxKey = require('../max_key').MaxKey | ||
, DBRef = require('../db_ref').DBRef | ||
, Binary = require('../binary').Binary; | ||
var Long = require('../long').Long, | ||
Double = require('../double').Double, | ||
Timestamp = require('../timestamp').Timestamp, | ||
ObjectID = require('../objectid').ObjectID, | ||
Symbol = require('../symbol').Symbol, | ||
BSONRegExp = require('../regexp').BSONRegExp, | ||
Code = require('../code').Code, | ||
Decimal128 = require('../decimal128'), | ||
MinKey = require('../min_key').MinKey, | ||
MaxKey = require('../max_key').MaxKey, | ||
DBRef = require('../db_ref').DBRef, | ||
Binary = require('../binary').Binary; | ||
@@ -21,25 +19,36 @@ // To ensure that 0.4 of node works correctly | ||
return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; | ||
} | ||
}; | ||
var calculateObjectSize = function calculateObjectSize(object, serializeFunctions, ignoreUndefined) { | ||
var totalLength = (4 + 1); | ||
var calculateObjectSize = function calculateObjectSize( | ||
object, | ||
serializeFunctions, | ||
ignoreUndefined | ||
) { | ||
var totalLength = 4 + 1; | ||
if(Array.isArray(object)) { | ||
for(var i = 0; i < object.length; i++) { | ||
totalLength += calculateElement(i.toString(), object[i], serializeFunctions, true, ignoreUndefined) | ||
if (Array.isArray(object)) { | ||
for (var i = 0; i < object.length; i++) { | ||
totalLength += calculateElement( | ||
i.toString(), | ||
object[i], | ||
serializeFunctions, | ||
true, | ||
ignoreUndefined | ||
); | ||
} | ||
} else { | ||
// If we have toBSON defined, override the current object | ||
if(object.toBSON) { | ||
object = object.toBSON(); | ||
} | ||
// If we have toBSON defined, override the current object | ||
// Calculate size | ||
for(var key in object) { | ||
totalLength += calculateElement(key, object[key], serializeFunctions, false, ignoreUndefined) | ||
if (object.toBSON) { | ||
object = object.toBSON(); | ||
} | ||
// Calculate size | ||
for (var key in object) { | ||
totalLength += calculateElement(key, object[key], serializeFunctions, false, ignoreUndefined); | ||
} | ||
} | ||
return totalLength; | ||
} | ||
}; | ||
@@ -51,87 +60,182 @@ /** | ||
function calculateElement(name, value, serializeFunctions, isArray, ignoreUndefined) { | ||
// If we have toBSON defined, override the current object | ||
if(value && value.toBSON){ | ||
// If we have toBSON defined, override the current object | ||
if (value && value.toBSON) { | ||
value = value.toBSON(); | ||
} | ||
switch(typeof value) { | ||
switch (typeof value) { | ||
case 'string': | ||
return 1 + Buffer.byteLength(name, 'utf8') + 1 + 4 + Buffer.byteLength(value, 'utf8') + 1; | ||
case 'number': | ||
if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { // 32 bit | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (4 + 1); | ||
if (Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
if (value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { | ||
// 32 bit | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (4 + 1); | ||
} else { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (8 + 1); | ||
} | ||
} else { // 64 bit | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
} else { | ||
// 64 bit | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (8 + 1); | ||
} | ||
case 'undefined': | ||
if(isArray || !ignoreUndefined) return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1); | ||
if (isArray || !ignoreUndefined) | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + 1; | ||
return 0; | ||
case 'boolean': | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1 + 1); | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (1 + 1); | ||
case 'object': | ||
if(value == null || value instanceof MinKey || value instanceof MaxKey || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1); | ||
} else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (12 + 1); | ||
} else if(value instanceof Date || isDate(value)) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
} else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (1 + 4 + 1) + value.length; | ||
} else if(value instanceof Long || value instanceof Double || value instanceof Timestamp | ||
|| value['_bsontype'] == 'Long' || value['_bsontype'] == 'Double' || value['_bsontype'] == 'Timestamp') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (8 + 1); | ||
} else if(value instanceof Decimal128 || value['_bsontype'] == 'Decimal128') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (16 + 1); | ||
} else if(value instanceof Code || value['_bsontype'] == 'Code') { | ||
if ( | ||
value == null || | ||
value instanceof MinKey || | ||
value instanceof MaxKey || | ||
value['_bsontype'] === 'MinKey' || | ||
value['_bsontype'] === 'MaxKey' | ||
) { | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + 1; | ||
} else if (value instanceof ObjectID || value['_bsontype'] === 'ObjectID') { | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (12 + 1); | ||
} else if (value instanceof Date || isDate(value)) { | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (8 + 1); | ||
} else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (1 + 4 + 1) + value.length | ||
); | ||
} else if ( | ||
value instanceof Long || | ||
value instanceof Double || | ||
value instanceof Timestamp || | ||
value['_bsontype'] === 'Long' || | ||
value['_bsontype'] === 'Double' || | ||
value['_bsontype'] === 'Timestamp' | ||
) { | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (8 + 1); | ||
} else if (value instanceof Decimal128 || value['_bsontype'] === 'Decimal128') { | ||
return (name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (16 + 1); | ||
} else if (value instanceof Code || value['_bsontype'] === 'Code') { | ||
// Calculate size depending on the availability of a scope | ||
if(value.scope != null && Object.keys(value.scope).length > 0) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + 4 + Buffer.byteLength(value.code.toString(), 'utf8') + 1 + calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined); | ||
if (value.scope != null && Object.keys(value.scope).length > 0) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
4 + | ||
4 + | ||
Buffer.byteLength(value.code.toString(), 'utf8') + | ||
1 + | ||
calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined) | ||
); | ||
} else { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + Buffer.byteLength(value.code.toString(), 'utf8') + 1; | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
4 + | ||
Buffer.byteLength(value.code.toString(), 'utf8') + | ||
1 | ||
); | ||
} | ||
} else if(value instanceof Binary || value['_bsontype'] == 'Binary') { | ||
} else if (value instanceof Binary || value['_bsontype'] === 'Binary') { | ||
// Check what kind of subtype we have | ||
if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (value.position + 1 + 4 + 1 + 4); | ||
if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
(value.position + 1 + 4 + 1 + 4) | ||
); | ||
} else { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + (value.position + 1 + 4 + 1); | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + (value.position + 1 + 4 + 1) | ||
); | ||
} | ||
} else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + Buffer.byteLength(value.value, 'utf8') + 4 + 1 + 1; | ||
} else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { | ||
} else if (value instanceof Symbol || value['_bsontype'] === 'Symbol') { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
Buffer.byteLength(value.value, 'utf8') + | ||
4 + | ||
1 + | ||
1 | ||
); | ||
} else if (value instanceof DBRef || value['_bsontype'] === 'DBRef') { | ||
// Set up correct object for serialization | ||
var ordered_values = { | ||
'$ref': value.namespace | ||
, '$id' : value.oid | ||
$ref: value.collection, | ||
$id: value.oid | ||
}; | ||
// Add db reference if it exists | ||
if(null != value.db) { | ||
if (value.db != null) { | ||
ordered_values['$db'] = value.db; | ||
} | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + calculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined); | ||
} else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.source, 'utf8') + 1 | ||
+ (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 | ||
} else if(value instanceof BSONRegExp || value['_bsontype'] == 'BSONRegExp') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.pattern, 'utf8') + 1 | ||
+ Buffer.byteLength(value.options, 'utf8') + 1 | ||
ordered_values = Object.assign(ordered_values, value.fields); | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
calculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined) | ||
); | ||
} else if ( | ||
value instanceof RegExp || | ||
Object.prototype.toString.call(value) === '[object RegExp]' | ||
) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
Buffer.byteLength(value.source, 'utf8') + | ||
1 + | ||
(value.global ? 1 : 0) + | ||
(value.ignoreCase ? 1 : 0) + | ||
(value.multiline ? 1 : 0) + | ||
1 | ||
); | ||
} else if (value instanceof BSONRegExp || value['_bsontype'] === 'BSONRegExp') { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
Buffer.byteLength(value.pattern, 'utf8') + | ||
1 + | ||
Buffer.byteLength(value.options, 'utf8') + | ||
1 | ||
); | ||
} else { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + calculateObjectSize(value, serializeFunctions, ignoreUndefined) + 1; | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
calculateObjectSize(value, serializeFunctions, ignoreUndefined) + | ||
1 | ||
); | ||
} | ||
case 'function': | ||
// WTF for 0.4.X where typeof /someregexp/ === 'function' | ||
if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + Buffer.byteLength(value.source, 'utf8') + 1 | ||
+ (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 | ||
if ( | ||
value instanceof RegExp || | ||
Object.prototype.toString.call(value) === '[object RegExp]' || | ||
String.call(value) === '[object RegExp]' | ||
) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
Buffer.byteLength(value.source, 'utf8') + | ||
1 + | ||
(value.global ? 1 : 0) + | ||
(value.ignoreCase ? 1 : 0) + | ||
(value.multiline ? 1 : 0) + | ||
1 | ||
); | ||
} else { | ||
if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + 4 + Buffer.byteLength(value.toString(), 'utf8') + 1 + calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined); | ||
} else if(serializeFunctions) { | ||
return (name != null ? (Buffer.byteLength(name, 'utf8') + 1) : 0) + 1 + 4 + Buffer.byteLength(value.toString(), 'utf8') + 1; | ||
if (serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
4 + | ||
4 + | ||
Buffer.byteLength(value.toString(), 'utf8') + | ||
1 + | ||
calculateObjectSize(value.scope, serializeFunctions, ignoreUndefined) | ||
); | ||
} else if (serializeFunctions) { | ||
return ( | ||
(name != null ? Buffer.byteLength(name, 'utf8') + 1 : 0) + | ||
1 + | ||
4 + | ||
Buffer.byteLength(value.toString(), 'utf8') + | ||
1 | ||
); | ||
} | ||
@@ -147,9 +251,9 @@ } | ||
// BSON MAX VALUES | ||
BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
BSON.BSON_INT32_MAX = 0x7fffffff; | ||
BSON.BSON_INT32_MIN = -0x80000000; | ||
// JS MAX PRECISE VALUES | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
module.exports = calculateObjectSize; |
@@ -1,15 +0,12 @@ | ||
"use strict" | ||
'use strict'; | ||
var readIEEE754 = require('../float_parser').readIEEE754, | ||
f = require('util').format, | ||
Long = require('../long').Long, | ||
var Long = require('../long').Long, | ||
Double = require('../double').Double, | ||
Timestamp = require('../timestamp').Timestamp, | ||
ObjectID = require('../objectid').ObjectID, | ||
Symbol = require('../symbol').Symbol, | ||
Code = require('../code').Code, | ||
MinKey = require('../min_key').MinKey, | ||
MaxKey = require('../max_key').MaxKey, | ||
Decimal128 = require('../decimal128'), | ||
Int32 = require('../int_32'), | ||
Decimal128 = require('../decimal128'), | ||
Int32 = require('../int_32'), | ||
DBRef = require('../db_ref').DBRef, | ||
@@ -20,131 +17,180 @@ BSONRegExp = require('../regexp').BSONRegExp, | ||
var deserialize = function(buffer, options, isArray) { | ||
options = options == null ? {} : options; | ||
var index = options && options.index ? options.index : 0; | ||
// Read the document size | ||
var size = buffer[index] | buffer[index+1] << 8 | buffer[index+2] << 16 | buffer[index+3] << 24; | ||
options = options == null ? {} : options; | ||
var index = options && options.index ? options.index : 0; | ||
// Read the document size | ||
var size = | ||
buffer[index] | | ||
(buffer[index + 1] << 8) | | ||
(buffer[index + 2] << 16) | | ||
(buffer[index + 3] << 24); | ||
// Ensure buffer is valid size | ||
if(size < 5 || buffer.length < size || (size + index) > buffer.length) { | ||
throw new Error("corrupt bson message"); | ||
} | ||
// Ensure buffer is valid size | ||
if (size < 5 || buffer.length !== size || size + index > buffer.length) { | ||
throw new Error('corrupt bson message'); | ||
} | ||
// Illegal end value | ||
if(buffer[index + size - 1] != 0) { | ||
throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00"); | ||
} | ||
// Illegal end value | ||
if (buffer[index + size - 1] !== 0) { | ||
throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00"); | ||
} | ||
// Start deserializtion | ||
return deserializeObject(buffer, index, options, isArray); | ||
} | ||
// Start deserializtion | ||
return deserializeObject(buffer, index, options, isArray); | ||
}; | ||
var deserializeObject = function(buffer, index, options, isArray) { | ||
var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions']; | ||
var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions']; | ||
var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions']; | ||
var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32']; | ||
var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw']; | ||
var cacheFunctionsCrc32 = | ||
options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32']; | ||
// Return raw bson buffer instead of parsing it | ||
var raw = options['raw'] == null ? false : options['raw']; | ||
if (!cacheFunctionsCrc32) var crc32 = null; | ||
// Return BSONRegExp objects instead of native regular expressions | ||
var bsonRegExp = typeof options['bsonRegExp'] == 'boolean' ? options['bsonRegExp'] : false; | ||
var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw']; | ||
// Controls the promotion of values vs wrapper classes | ||
var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers']; | ||
var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs']; | ||
var promoteValues = options['promoteValues'] == null ? true : options['promoteValues']; | ||
// Return raw bson buffer instead of parsing it | ||
var raw = options['raw'] == null ? false : options['raw']; | ||
// Set the start index | ||
var startIndex = index; | ||
// Return BSONRegExp objects instead of native regular expressions | ||
var bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false; | ||
// Controls the promotion of values vs wrapper classes | ||
var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers']; | ||
var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs']; | ||
var promoteValues = options['promoteValues'] == null ? true : options['promoteValues']; | ||
// Set the start index | ||
var startIndex = index; | ||
// Validate that we have at least 4 bytes of buffer | ||
if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long"); | ||
if (buffer.length < 5) throw new Error('corrupt bson message < 5 bytes long'); | ||
// Read the document size | ||
var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
// Read the document size | ||
var size = | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24); | ||
// Ensure buffer is valid size | ||
if(size < 5 || size > buffer.length) throw new Error("corrupt bson message"); | ||
// Ensure buffer is valid size | ||
if (size < 5 || size > buffer.length) throw new Error('corrupt bson message'); | ||
// Create holding object | ||
var object = isArray ? [] : {}; | ||
// Used for arrays to skip having to perform utf8 decoding | ||
var arrayIndex = 0; | ||
// Used for arrays to skip having to perform utf8 decoding | ||
var arrayIndex = 0, | ||
done = false; | ||
// While we have more left data left keep parsing | ||
while(true) { | ||
while (!done) { | ||
// Read the type | ||
var elementType = buffer[index++]; | ||
// If we get a zero it's the last byte, exit | ||
if(elementType == 0) { | ||
break; | ||
} | ||
if (elementType === 0) break; | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while(buffer[i] !== 0x00 && i < buffer.length) { | ||
i++ | ||
} | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while (buffer[i] !== 0x00 && i < buffer.length) { | ||
i++; | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
var name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i); | ||
// If are at the end of the buffer there is a problem with the document | ||
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString'); | ||
var name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i); | ||
index = i + 1; | ||
index = i + 1; | ||
if(elementType == BSON.BSON_DATA_STRING) { | ||
var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
object[name] = buffer.toString('utf8', index, index + stringSize - 1); | ||
if (elementType === BSON.BSON_DATA_STRING) { | ||
var stringSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
if ( | ||
stringSize <= 0 || | ||
stringSize > buffer.length - index || | ||
buffer[index + stringSize - 1] !== 0 | ||
) | ||
throw new Error('bad string length in bson'); | ||
var s = buffer.toString('utf8', index, index + stringSize - 1); | ||
for (i = 0; i < s.length; i++) { | ||
if (s.charCodeAt(i) === 0xfffd) { | ||
throw new Error('Invalid UTF-8 string in BSON document'); | ||
} | ||
} | ||
object[name] = s; | ||
index = index + stringSize; | ||
} else if(elementType == BSON.BSON_DATA_OID) { | ||
var oid = new Buffer(12); | ||
buffer.copy(oid, 0, index, index + 12); | ||
} else if (elementType === BSON.BSON_DATA_OID) { | ||
var oid = new Buffer(12); | ||
buffer.copy(oid, 0, index, index + 12); | ||
object[name] = new ObjectID(oid); | ||
index = index + 12; | ||
} else if(elementType == BSON.BSON_DATA_INT && promoteValues == false) { | ||
object[name] = new Int32(buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24); | ||
} else if(elementType == BSON.BSON_DATA_INT) { | ||
object[name] = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
} else if(elementType == BSON.BSON_DATA_NUMBER && promoteValues == false) { | ||
object[name] = new Double(buffer.readDoubleLE(index)); | ||
index = index + 8; | ||
} else if(elementType == BSON.BSON_DATA_NUMBER) { | ||
object[name] = buffer.readDoubleLE(index); | ||
} else if (elementType === BSON.BSON_DATA_INT && promoteValues === false) { | ||
object[name] = new Int32( | ||
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24) | ||
); | ||
} else if (elementType === BSON.BSON_DATA_INT) { | ||
object[name] = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
} else if (elementType === BSON.BSON_DATA_NUMBER && promoteValues === false) { | ||
object[name] = new Double(buffer.readDoubleLE(index)); | ||
index = index + 8; | ||
} else if(elementType == BSON.BSON_DATA_DATE) { | ||
var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
} else if (elementType === BSON.BSON_DATA_NUMBER) { | ||
object[name] = buffer.readDoubleLE(index); | ||
index = index + 8; | ||
} else if (elementType === BSON.BSON_DATA_DATE) { | ||
var lowBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
var highBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
object[name] = new Date(new Long(lowBits, highBits).toNumber()); | ||
} else if(elementType == BSON.BSON_DATA_BOOLEAN) { | ||
if(buffer[index] != 0 && buffer[index] != 1) throw new Error('illegal boolean type value'); | ||
object[name] = buffer[index++] == 1; | ||
} else if(elementType == BSON.BSON_DATA_OBJECT) { | ||
var _index = index; | ||
var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
if(objectSize <= 0 || objectSize > (buffer.length - index)) throw new Error("bad embedded document length in bson"); | ||
} else if (elementType === BSON.BSON_DATA_BOOLEAN) { | ||
if (buffer[index] !== 0 && buffer[index] !== 1) throw new Error('illegal boolean type value'); | ||
object[name] = buffer[index++] === 1; | ||
} else if (elementType === BSON.BSON_DATA_OBJECT) { | ||
var _index = index; | ||
var objectSize = | ||
buffer[index] | | ||
(buffer[index + 1] << 8) | | ||
(buffer[index + 2] << 16) | | ||
(buffer[index + 3] << 24); | ||
if (objectSize <= 0 || objectSize > buffer.length - index) | ||
throw new Error('bad embedded document length in bson'); | ||
// We have a raw value | ||
if(raw) { | ||
object[name] = buffer.slice(index, index + objectSize); | ||
} else { | ||
object[name] = deserializeObject(buffer, _index, options, false); | ||
} | ||
// We have a raw value | ||
if (raw) { | ||
object[name] = buffer.slice(index, index + objectSize); | ||
} else { | ||
object[name] = deserializeObject(buffer, _index, options, false); | ||
} | ||
index = index + objectSize; | ||
} else if(elementType == BSON.BSON_DATA_ARRAY) { | ||
var _index = index; | ||
var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
var arrayOptions = options; | ||
} else if (elementType === BSON.BSON_DATA_ARRAY) { | ||
_index = index; | ||
objectSize = | ||
buffer[index] | | ||
(buffer[index + 1] << 8) | | ||
(buffer[index + 2] << 16) | | ||
(buffer[index + 3] << 24); | ||
var arrayOptions = options; | ||
// Stop index | ||
var stopIndex = index + objectSize; | ||
// Stop index | ||
var stopIndex = index + objectSize; | ||
// All elements of array to be returned as raw bson | ||
if(fieldsAsRaw && fieldsAsRaw[name]) { | ||
arrayOptions = {}; | ||
for(var n in options) arrayOptions[n] = options[n]; | ||
arrayOptions['raw'] = true; | ||
} | ||
// All elements of array to be returned as raw bson | ||
if (fieldsAsRaw && fieldsAsRaw[name]) { | ||
arrayOptions = {}; | ||
for (var n in options) arrayOptions[n] = options[n]; | ||
arrayOptions['raw'] = true; | ||
} | ||
@@ -154,52 +200,74 @@ object[name] = deserializeObject(buffer, _index, arrayOptions, true); | ||
if(buffer[index - 1] != 0) throw new Error('invalid array terminator byte'); | ||
if(index != stopIndex) throw new Error('corrupted array bson'); | ||
} else if(elementType == BSON.BSON_DATA_UNDEFINED) { | ||
if (buffer[index - 1] !== 0) throw new Error('invalid array terminator byte'); | ||
if (index !== stopIndex) throw new Error('corrupted array bson'); | ||
} else if (elementType === BSON.BSON_DATA_UNDEFINED) { | ||
object[name] = undefined; | ||
} else if(elementType == BSON.BSON_DATA_NULL) { | ||
object[name] = null; | ||
} else if(elementType == BSON.BSON_DATA_LONG) { | ||
} else if (elementType === BSON.BSON_DATA_NULL) { | ||
object[name] = null; | ||
} else if (elementType === BSON.BSON_DATA_LONG) { | ||
// Unpack the low and high bits | ||
var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
lowBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
highBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
var long = new Long(lowBits, highBits); | ||
// Promote the long if possible | ||
if(promoteLongs && promoteValues == true) { | ||
object[name] = long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) ? long.toNumber() : long; | ||
if (promoteLongs && promoteValues === true) { | ||
object[name] = | ||
long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) | ||
? long.toNumber() | ||
: long; | ||
} else { | ||
object[name] = long; | ||
} | ||
} else if(elementType == BSON.BSON_DATA_DECIMAL128) { | ||
// Buffer to contain the decimal bytes | ||
var bytes = new Buffer(16); | ||
// Copy the next 16 bytes into the bytes buffer | ||
buffer.copy(bytes, 0, index, index + 16); | ||
// Update index | ||
index = index + 16; | ||
// Assign the new Decimal128 value | ||
var decimal128 = new Decimal128(bytes); | ||
// If we have an alternative mapper use that | ||
object[name] = decimal128.toObject ? decimal128.toObject() : decimal128; | ||
} else if(elementType == BSON.BSON_DATA_BINARY) { | ||
var binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
var totalBinarySize = binarySize; | ||
} else if (elementType === BSON.BSON_DATA_DECIMAL128) { | ||
// Buffer to contain the decimal bytes | ||
var bytes = new Buffer(16); | ||
// Copy the next 16 bytes into the bytes buffer | ||
buffer.copy(bytes, 0, index, index + 16); | ||
// Update index | ||
index = index + 16; | ||
// Assign the new Decimal128 value | ||
var decimal128 = new Decimal128(bytes); | ||
// If we have an alternative mapper use that | ||
object[name] = decimal128.toObject ? decimal128.toObject() : decimal128; | ||
} else if (elementType === BSON.BSON_DATA_BINARY) { | ||
var binarySize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
var totalBinarySize = binarySize; | ||
var subType = buffer[index++]; | ||
// Did we have a negative binary size, throw | ||
if(binarySize < 0) throw new Error('Negative binary type element size found'); | ||
// Did we have a negative binary size, throw | ||
if (binarySize < 0) throw new Error('Negative binary type element size found'); | ||
// Is the length longer than the document | ||
if(binarySize > buffer.length) throw new Error('Binary type size larger than document size'); | ||
// Is the length longer than the document | ||
if (binarySize > buffer.length) throw new Error('Binary type size larger than document size'); | ||
// Decode as raw Buffer object if options specifies it | ||
if(buffer['slice'] != null) { | ||
// Decode as raw Buffer object if options specifies it | ||
if (buffer['slice'] != null) { | ||
// If we have subtype 2 skip the 4 bytes for the size | ||
if(subType == Binary.SUBTYPE_BYTE_ARRAY) { | ||
binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
if(binarySize < 0) throw new Error('Negative binary type element size found for subtype 0x02'); | ||
if(binarySize > (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
if(binarySize < (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
if (subType === Binary.SUBTYPE_BYTE_ARRAY) { | ||
binarySize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
if (binarySize < 0) | ||
throw new Error('Negative binary type element size found for subtype 0x02'); | ||
if (binarySize > totalBinarySize - 4) | ||
throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
if (binarySize < totalBinarySize - 4) | ||
throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
} | ||
if(promoteBuffers && promoteValues) { | ||
if (promoteBuffers && promoteValues) { | ||
object[name] = buffer.slice(index, index + binarySize); | ||
@@ -210,17 +278,27 @@ } else { | ||
} else { | ||
var _buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(binarySize)) : new Array(binarySize); | ||
var _buffer = | ||
typeof Uint8Array !== 'undefined' | ||
? new Uint8Array(new ArrayBuffer(binarySize)) | ||
: new Array(binarySize); | ||
// If we have subtype 2 skip the 4 bytes for the size | ||
if(subType == Binary.SUBTYPE_BYTE_ARRAY) { | ||
binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
if(binarySize < 0) throw new Error('Negative binary type element size found for subtype 0x02'); | ||
if(binarySize > (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
if(binarySize < (totalBinarySize - 4)) throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
if (subType === Binary.SUBTYPE_BYTE_ARRAY) { | ||
binarySize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
if (binarySize < 0) | ||
throw new Error('Negative binary type element size found for subtype 0x02'); | ||
if (binarySize > totalBinarySize - 4) | ||
throw new Error('Binary type with subtype 0x02 contains to long binary size'); | ||
if (binarySize < totalBinarySize - 4) | ||
throw new Error('Binary type with subtype 0x02 contains to short binary size'); | ||
} | ||
// Copy the data | ||
for(var i = 0; i < binarySize; i++) { | ||
for (i = 0; i < binarySize; i++) { | ||
_buffer[i] = buffer[index + i]; | ||
} | ||
if(promoteBuffers && promoteValues) { | ||
if (promoteBuffers && promoteValues) { | ||
object[name] = _buffer; | ||
@@ -234,27 +312,27 @@ } else { | ||
index = index + binarySize; | ||
} else if(elementType == BSON.BSON_DATA_REGEXP && bsonRegExp == false) { | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while(buffer[i] !== 0x00 && i < buffer.length) { | ||
i++ | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
// Return the C string | ||
var source = buffer.toString('utf8', index, i); | ||
} else if (elementType === BSON.BSON_DATA_REGEXP && bsonRegExp === false) { | ||
// Get the start search index | ||
i = index; | ||
// Locate the end of the c string | ||
while (buffer[i] !== 0x00 && i < buffer.length) { | ||
i++; | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString'); | ||
// Return the C string | ||
var source = buffer.toString('utf8', index, i); | ||
// Create the regexp | ||
index = i + 1; | ||
index = i + 1; | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while(buffer[i] !== 0x00 && i < buffer.length) { | ||
i++ | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
// Return the C string | ||
var regExpOptions = buffer.toString('utf8', index, i); | ||
index = i + 1; | ||
// Get the start search index | ||
i = index; | ||
// Locate the end of the c string | ||
while (buffer[i] !== 0x00 && i < buffer.length) { | ||
i++; | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString'); | ||
// Return the C string | ||
var regExpOptions = buffer.toString('utf8', index, i); | ||
index = i + 1; | ||
@@ -265,4 +343,4 @@ // For each option add the corresponding one for javascript | ||
// Parse options | ||
for(var i = 0; i < regExpOptions.length; i++) { | ||
switch(regExpOptions[i]) { | ||
for (i = 0; i < regExpOptions.length; i++) { | ||
switch (regExpOptions[i]) { | ||
case 'm': | ||
@@ -281,25 +359,25 @@ optionsArray[i] = 'm'; | ||
object[name] = new RegExp(source, optionsArray.join('')); | ||
} else if(elementType == BSON.BSON_DATA_REGEXP && bsonRegExp == true) { | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while(buffer[i] !== 0x00 && i < buffer.length) { | ||
i++ | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
// Return the C string | ||
var source = buffer.toString('utf8', index, i); | ||
} else if (elementType === BSON.BSON_DATA_REGEXP && bsonRegExp === true) { | ||
// Get the start search index | ||
i = index; | ||
// Locate the end of the c string | ||
while (buffer[i] !== 0x00 && i < buffer.length) { | ||
i++; | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString'); | ||
// Return the C string | ||
source = buffer.toString('utf8', index, i); | ||
index = i + 1; | ||
// Get the start search index | ||
var i = index; | ||
// Locate the end of the c string | ||
while(buffer[i] !== 0x00 && i < buffer.length) { | ||
i++ | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString") | ||
// Return the C string | ||
var regExpOptions = buffer.toString('utf8', index, i); | ||
// Get the start search index | ||
i = index; | ||
// Locate the end of the c string | ||
while (buffer[i] !== 0x00 && i < buffer.length) { | ||
i++; | ||
} | ||
// If are at the end of the buffer there is a problem with the document | ||
if (i >= buffer.length) throw new Error('Bad BSON Document: illegal CString'); | ||
// Return the C string | ||
regExpOptions = buffer.toString('utf8', index, i); | ||
index = i + 1; | ||
@@ -309,25 +387,52 @@ | ||
object[name] = new BSONRegExp(source, regExpOptions); | ||
} else if(elementType == BSON.BSON_DATA_SYMBOL) { | ||
var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1)); | ||
} else if (elementType === BSON.BSON_DATA_SYMBOL) { | ||
stringSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
if ( | ||
stringSize <= 0 || | ||
stringSize > buffer.length - index || | ||
buffer[index + stringSize - 1] !== 0 | ||
) | ||
throw new Error('bad string length in bson'); | ||
// symbol is deprecated - upgrade to string. | ||
object[name] = buffer.toString('utf8', index, index + stringSize - 1); | ||
index = index + stringSize; | ||
} else if(elementType == BSON.BSON_DATA_TIMESTAMP) { | ||
var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
} else if (elementType === BSON.BSON_DATA_TIMESTAMP) { | ||
lowBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
highBits = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
object[name] = new Timestamp(lowBits, highBits); | ||
} else if(elementType == BSON.BSON_DATA_MIN_KEY) { | ||
} else if (elementType === BSON.BSON_DATA_MIN_KEY) { | ||
object[name] = new MinKey(); | ||
} else if(elementType == BSON.BSON_DATA_MAX_KEY) { | ||
} else if (elementType === BSON.BSON_DATA_MAX_KEY) { | ||
object[name] = new MaxKey(); | ||
} else if(elementType == BSON.BSON_DATA_CODE) { | ||
var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
} else if (elementType === BSON.BSON_DATA_CODE) { | ||
stringSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
if ( | ||
stringSize <= 0 || | ||
stringSize > buffer.length - index || | ||
buffer[index + stringSize - 1] !== 0 | ||
) | ||
throw new Error('bad string length in bson'); | ||
var functionString = buffer.toString('utf8', index, index + stringSize - 1); | ||
// If we are evaluating the functions | ||
if(evalFunctions) { | ||
var value = null; | ||
if (evalFunctions) { | ||
// If we have cache enabled let's look for the md5 of the function in the cache | ||
if(cacheFunctions) { | ||
if (cacheFunctions) { | ||
var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; | ||
@@ -340,3 +445,3 @@ // Got to do this to avoid V8 deoptimizing the call due to finding eval | ||
} else { | ||
object[name] = new Code(functionString); | ||
object[name] = new Code(functionString); | ||
} | ||
@@ -346,23 +451,40 @@ | ||
index = index + stringSize; | ||
} else if(elementType == BSON.BSON_DATA_CODE_W_SCOPE) { | ||
var totalSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
} else if (elementType === BSON.BSON_DATA_CODE_W_SCOPE) { | ||
var totalSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
// Element cannot be shorter than totalSize + stringSize + documentSize + terminator | ||
if(totalSize < (4 + 4 + 4 + 1)) { | ||
throw new Error("code_w_scope total size shorter minimum expected length"); | ||
} | ||
// Element cannot be shorter than totalSize + stringSize + documentSize + terminator | ||
if (totalSize < 4 + 4 + 4 + 1) { | ||
throw new Error('code_w_scope total size shorter minimum expected length'); | ||
} | ||
// Get the code string size | ||
var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
// Check if we have a valid string | ||
if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
// Get the code string size | ||
stringSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
// Check if we have a valid string | ||
if ( | ||
stringSize <= 0 || | ||
stringSize > buffer.length - index || | ||
buffer[index + stringSize - 1] !== 0 | ||
) | ||
throw new Error('bad string length in bson'); | ||
// Javascript function | ||
var functionString = buffer.toString('utf8', index, index + stringSize - 1); | ||
functionString = buffer.toString('utf8', index, index + stringSize - 1); | ||
// Update parse index position | ||
index = index + stringSize; | ||
// Parse the element | ||
var _index = index; | ||
_index = index; | ||
// Decode the size of the object document | ||
var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; | ||
objectSize = | ||
buffer[index] | | ||
(buffer[index + 1] << 8) | | ||
(buffer[index + 2] << 16) | | ||
(buffer[index + 3] << 24); | ||
// Decode the scope object | ||
@@ -373,19 +495,17 @@ var scopeObject = deserializeObject(buffer, _index, options, false); | ||
// Check if field length is to short | ||
if(totalSize < (4 + 4 + objectSize + stringSize)) { | ||
throw new Error('code_w_scope total size is to short, truncating scope'); | ||
} | ||
// Check if field length is to short | ||
if (totalSize < 4 + 4 + objectSize + stringSize) { | ||
throw new Error('code_w_scope total size is to short, truncating scope'); | ||
} | ||
// Check if totalSize field is to long | ||
if(totalSize > (4 + 4 + objectSize + stringSize)) { | ||
throw new Error('code_w_scope total size is to long, clips outer document'); | ||
} | ||
// Check if totalSize field is to long | ||
if (totalSize > 4 + 4 + objectSize + stringSize) { | ||
throw new Error('code_w_scope total size is to long, clips outer document'); | ||
} | ||
// If we are evaluating the functions | ||
if(evalFunctions) { | ||
// Contains the value we are going to set | ||
var value = null; | ||
if (evalFunctions) { | ||
// If we have cache enabled let's look for the md5 of the function in the cache | ||
if(cacheFunctions) { | ||
var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; | ||
if (cacheFunctions) { | ||
hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; | ||
// Got to do this to avoid V8 deoptimizing the call due to finding eval | ||
@@ -399,43 +519,87 @@ object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); | ||
} else { | ||
object[name] = new Code(functionString, scopeObject); | ||
object[name] = new Code(functionString, scopeObject); | ||
} | ||
} else if(elementType == BSON.BSON_DATA_DBPOINTER) { | ||
// Get the code string size | ||
var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; | ||
// Check if we have a valid string | ||
if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson"); | ||
// Namespace | ||
} else if (elementType === BSON.BSON_DATA_DBPOINTER) { | ||
// Get the code string size | ||
stringSize = | ||
buffer[index++] | | ||
(buffer[index++] << 8) | | ||
(buffer[index++] << 16) | | ||
(buffer[index++] << 24); | ||
// Check if we have a valid string | ||
if ( | ||
stringSize <= 0 || | ||
stringSize > buffer.length - index || | ||
buffer[index + stringSize - 1] !== 0 | ||
) | ||
throw new Error('bad string length in bson'); | ||
// Namespace | ||
var namespace = buffer.toString('utf8', index, index + stringSize - 1); | ||
// Update parse index position | ||
// Update parse index position | ||
index = index + stringSize; | ||
// Read the oid | ||
var oidBuffer = new Buffer(12); | ||
buffer.copy(oidBuffer, 0, index, index + 12); | ||
var oid = new ObjectID(oidBuffer); | ||
// Read the oid | ||
var oidBuffer = new Buffer(12); | ||
buffer.copy(oidBuffer, 0, index, index + 12); | ||
oid = new ObjectID(oidBuffer); | ||
// Update the index | ||
index = index + 12; | ||
// Update the index | ||
index = index + 12; | ||
// Split the namespace | ||
var parts = namespace.split('.'); | ||
var db = parts.shift(); | ||
var collection = parts.join('.'); | ||
// Upgrade to DBRef type | ||
object[name] = new DBRef(collection, oid, db); | ||
for (i = 0; i < namespace.length; i++) { | ||
if (namespace.charCodeAt(i) === 0xfffd) { | ||
throw new Error('Invalid UTF-8 string in BSON document'); | ||
} | ||
} | ||
// Split the namespace | ||
var parts = namespace.split('.'); | ||
var db, collection; | ||
if (parts.length === 2) { | ||
db = parts.shift(); | ||
collection = parts.shift(); | ||
} else { | ||
collection = namespace; | ||
} | ||
// Upgrade to DBRef type | ||
object[name] = new DBRef(collection, oid, db); | ||
} else { | ||
throw new Error("Detected unknown BSON type " + elementType.toString(16) + " for fieldname \"" + name + "\", are you using the latest BSON parser"); | ||
} | ||
throw new Error( | ||
'Detected unknown BSON type ' + | ||
elementType.toString(16) + | ||
' for fieldname "' + | ||
name + | ||
'", are you using the latest BSON parser?' | ||
); | ||
} | ||
} | ||
// Check if the deserialization was against a valid array/object | ||
if(size != (index - startIndex)) { | ||
if(isArray) throw new Error('corrupt array bson'); | ||
throw new Error('corrupt object bson'); | ||
} | ||
// Check if the deserialization was against a valid array/object | ||
if (size !== index - startIndex) { | ||
if (isArray) throw new Error('corrupt array bson'); | ||
throw new Error('corrupt object bson'); | ||
} | ||
// Check if we have a db ref object | ||
if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']); | ||
// check if object's $ keys are those of a DBRef | ||
var dollarKeys = Object.keys(object).filter(k => k.startsWith('$')); | ||
var valid = true; | ||
dollarKeys.forEach(k => { | ||
if (['$ref', '$id', '$db'].indexOf(k) === -1) valid = false; | ||
}); | ||
// if a $key not in "$ref", "$id", "$db", don't make a DBRef | ||
if (!valid) return object; | ||
if (object['$id'] != null && object['$ref'] != null) { | ||
let copy = Object.assign({}, object); | ||
delete copy.$ref; | ||
delete copy.$id; | ||
delete copy.$db; | ||
return new DBRef(object.$ref, object.$id, object.$db || null, copy); | ||
} | ||
return object; | ||
} | ||
}; | ||
@@ -453,4 +617,4 @@ /** | ||
// Check for cache hit, eval if missing and return cached function | ||
if(functionCache[hash] == null) { | ||
eval("value = " + functionString); | ||
if (functionCache[hash] == null) { | ||
eval('value = ' + functionString); | ||
functionCache[hash] = value; | ||
@@ -460,3 +624,3 @@ } | ||
return functionCache[hash].bind(object); | ||
} | ||
}; | ||
@@ -473,5 +637,5 @@ /** | ||
// Eval the function | ||
eval("value = " + functionString); | ||
eval('value = ' + functionString); | ||
return value; | ||
} | ||
}; | ||
@@ -486,3 +650,3 @@ var BSON = {}; | ||
*/ | ||
var functionCache = BSON.functionCache = {}; | ||
var functionCache = (BSON.functionCache = {}); | ||
@@ -654,3 +818,3 @@ /** | ||
// BSON MAX VALUES | ||
BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
BSON.BSON_INT32_MAX = 0x7fffffff; | ||
BSON.BSON_INT32_MIN = -0x80000000; | ||
@@ -662,9 +826,9 @@ | ||
// JS MAX PRECISE VALUES | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
// Internal long versions | ||
var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
module.exports = deserialize | ||
module.exports = deserialize; |
@@ -1,27 +0,16 @@ | ||
"use strict" | ||
'use strict'; | ||
var writeIEEE754 = require('../float_parser').writeIEEE754, | ||
readIEEE754 = require('../float_parser').readIEEE754, | ||
Long = require('../long').Long, | ||
Map = require('../map'), | ||
Double = require('../double').Double, | ||
Timestamp = require('../timestamp').Timestamp, | ||
ObjectID = require('../objectid').ObjectID, | ||
Symbol = require('../symbol').Symbol, | ||
Code = require('../code').Code, | ||
BSONRegExp = require('../regexp').BSONRegExp, | ||
Int32 = require('../int_32').Int32, | ||
MinKey = require('../min_key').MinKey, | ||
MaxKey = require('../max_key').MaxKey, | ||
Decimal128 = require('../decimal128'), | ||
DBRef = require('../db_ref').DBRef, | ||
Binary = require('../binary').Binary; | ||
try { | ||
var _Buffer = Uint8Array; | ||
} catch(e) { | ||
var _Buffer = Buffer; | ||
} | ||
// try { | ||
// var _Buffer = Uint8Array; | ||
// } catch (e) { | ||
// _Buffer = Buffer; | ||
// } | ||
var regexp = /\x00/ | ||
var regexp = /\x00/; // eslint-disable-line no-control-regex | ||
@@ -31,7 +20,7 @@ // To ensure that 0.4 of node works correctly | ||
return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; | ||
} | ||
}; | ||
var isRegExp = function isRegExp(d) { | ||
return Object.prototype.toString.call(d) === '[object RegExp]'; | ||
} | ||
}; | ||
@@ -42,3 +31,5 @@ var serializeString = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -50,6 +41,6 @@ index = index + numberOfWrittenBytes + 1; | ||
// Write the size of the string to buffer | ||
buffer[index + 3] = (size + 1 >> 24) & 0xff; | ||
buffer[index + 2] = (size + 1 >> 16) & 0xff; | ||
buffer[index + 1] = (size + 1 >> 8) & 0xff; | ||
buffer[index] = size + 1 & 0xff; | ||
buffer[index + 3] = ((size + 1) >> 24) & 0xff; | ||
buffer[index + 2] = ((size + 1) >> 16) & 0xff; | ||
buffer[index + 1] = ((size + 1) >> 8) & 0xff; | ||
buffer[index] = (size + 1) & 0xff; | ||
// Update index | ||
@@ -60,14 +51,16 @@ index = index + 4 + size; | ||
return index; | ||
} | ||
}; | ||
var serializeNumber = function(buffer, key, value, index, isArray) { | ||
// We have an integer value | ||
if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
if (Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
// If the value fits in 32 bits encode as int, if it fits in a double | ||
// encode it as a double, otherwise long | ||
if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { | ||
if (value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { | ||
// Set int type 32 bits or less | ||
buffer[index++] = BSON.BSON_DATA_INT; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -81,7 +74,9 @@ index = index + numberOfWrittenBytes; | ||
buffer[index++] = (value >> 24) & 0xff; | ||
} else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
} else if (value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { | ||
// Encode as double | ||
buffer[index++] = BSON.BSON_DATA_NUMBER; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -98,3 +93,5 @@ index = index + numberOfWrittenBytes; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -121,3 +118,5 @@ index = index + numberOfWrittenBytes; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -133,3 +132,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -139,4 +138,8 @@ var serializeNull = function(buffer, key, value, index, isArray) { | ||
buffer[index++] = BSON.BSON_DATA_NULL; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -146,3 +149,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -153,3 +156,5 @@ var serializeBoolean = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -161,3 +166,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -168,3 +173,5 @@ var serializeDate = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -189,3 +196,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -196,3 +203,6 @@ var serializeRegExp = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -202,3 +212,3 @@ index = index + numberOfWrittenBytes; | ||
if (value.source && value.source.match(regexp) != null) { | ||
throw Error("value " + value.source + " must not contain null bytes"); | ||
throw Error('value ' + value.source + ' must not contain null bytes'); | ||
} | ||
@@ -210,9 +220,10 @@ // Adjust the index | ||
// Write the parameters | ||
if(value.global) buffer[index++] = 0x73; // s | ||
if(value.ignoreCase) buffer[index++] = 0x69; // i | ||
if(value.multiline) buffer[index++] = 0x6d; // m | ||
if (value.global) buffer[index++] = 0x73; // s | ||
if (value.ignoreCase) buffer[index++] = 0x69; // i | ||
if (value.multiline) buffer[index++] = 0x6d; // m | ||
// Add ending zero | ||
buffer[index++] = 0x00; | ||
return index; | ||
} | ||
}; | ||
@@ -223,3 +234,5 @@ var serializeBSONRegExp = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -233,3 +246,3 @@ index = index + numberOfWrittenBytes; | ||
// null-terminated. | ||
throw Error("pattern " + value.pattern + " must not contain null bytes"); | ||
throw Error('pattern ' + value.pattern + ' must not contain null bytes'); | ||
} | ||
@@ -242,13 +255,22 @@ | ||
// Write the options | ||
index = index + buffer.write(value.options.split('').sort().join(''), index, 'utf8'); | ||
index = | ||
index + | ||
buffer.write( | ||
value.options | ||
.split('') | ||
.sort() | ||
.join(''), | ||
index, | ||
'utf8' | ||
); | ||
// Add ending zero | ||
buffer[index++] = 0x00; | ||
return index; | ||
} | ||
}; | ||
var serializeMinMax = function(buffer, key, value, index, isArray) { | ||
// Write the type of either min or max key | ||
if(value === null) { | ||
if (value === null) { | ||
buffer[index++] = BSON.BSON_DATA_NULL; | ||
} else if(value instanceof MinKey) { | ||
} else if (value instanceof MinKey) { | ||
buffer[index++] = BSON.BSON_DATA_MIN_KEY; | ||
@@ -260,3 +282,5 @@ } else { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -266,3 +290,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -273,3 +297,5 @@ var serializeObjectId = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
@@ -281,8 +307,8 @@ // Encode the name | ||
// Write the objectId into the shared buffer | ||
if(typeof value.id == 'string') { | ||
buffer.write(value.id, index, 'binary') | ||
} else if(value.id && value.id.copy){ | ||
if (typeof value.id === 'string') { | ||
buffer.write(value.id, index, 'binary'); | ||
} else if (value.id && value.id.copy) { | ||
value.id.copy(buffer, index, 0, 12); | ||
} else { | ||
throw new Error('object [' + JSON.stringify(value) + "] is not a valid ObjectId"); | ||
throw new Error('object [' + JSON.stringify(value) + '] is not a valid ObjectId'); | ||
} | ||
@@ -292,3 +318,3 @@ | ||
return index + 12; | ||
} | ||
}; | ||
@@ -299,3 +325,5 @@ var serializeBuffer = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -318,7 +346,18 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
var serializeObject = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray, path) { | ||
for(var i = 0; i < path.length; i++) { | ||
if(path[i] === value) throw new Error('cyclic dependency detected'); | ||
var serializeObject = function( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
isArray, | ||
path | ||
) { | ||
for (var i = 0; i < path.length; i++) { | ||
if (path[i] === value) throw new Error('cyclic dependency detected'); | ||
} | ||
@@ -331,13 +370,22 @@ | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
index = index + numberOfWrittenBytes; | ||
buffer[index++] = 0; | ||
var endIndex = serializeInto(buffer, value, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path); | ||
var endIndex = serializeInto( | ||
buffer, | ||
value, | ||
checkKeys, | ||
index, | ||
depth + 1, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
path | ||
); | ||
// Pop stack | ||
path.pop(); | ||
// Write size | ||
var size = endIndex - index; | ||
return endIndex; | ||
} | ||
}; | ||
@@ -347,3 +395,5 @@ var serializeDecimal128 = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -355,9 +405,11 @@ index = index + numberOfWrittenBytes; | ||
return index + 16; | ||
} | ||
}; | ||
var serializeLong = function(buffer, key, value, index, isArray) { | ||
// Write the type | ||
buffer[index++] = value._bsontype == 'Long' ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP; | ||
buffer[index++] = value._bsontype === 'Long' ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -380,3 +432,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -387,3 +439,5 @@ var serializeInt32 = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -398,3 +452,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -404,13 +458,19 @@ var serializeDouble = function(buffer, key, value, index, isArray) { | ||
buffer[index++] = BSON.BSON_DATA_NUMBER; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
index = index + numberOfWrittenBytes; | ||
buffer[index++] = 0; | ||
// Write float | ||
writeIEEE754(buffer, value, index, 'little', 52, 8); | ||
// Ajust index | ||
writeIEEE754(buffer, value.value, index, 'little', 52, 8); | ||
// Adjust index | ||
index = index + 8; | ||
return index; | ||
} | ||
}; | ||
@@ -420,3 +480,5 @@ var serializeFunction = function(buffer, key, value, index, checkKeys, depth, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -439,10 +501,22 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
var serializeCode = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray) { | ||
if(value.scope && typeof value.scope == 'object') { | ||
var serializeCode = function( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
isArray | ||
) { | ||
if (value.scope && typeof value.scope === 'object') { | ||
// Write the type | ||
buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -457,3 +531,3 @@ index = index + numberOfWrittenBytes; | ||
// Get the function string | ||
var functionString = typeof value.code == 'string' ? value.code : value.code.toString(); | ||
var functionString = typeof value.code === 'string' ? value.code : value.code.toString(); | ||
// Index adjustment | ||
@@ -475,3 +549,11 @@ index = index + 4; | ||
// Serialize the scope value | ||
var endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined) | ||
var endIndex = serializeInto( | ||
buffer, | ||
value.scope, | ||
checkKeys, | ||
index, | ||
depth + 1, | ||
serializeFunctions, | ||
ignoreUndefined | ||
); | ||
index = endIndex - 1; | ||
@@ -492,3 +574,5 @@ | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -498,3 +582,3 @@ index = index + numberOfWrittenBytes; | ||
// Function string | ||
var functionString = value.code.toString(); | ||
functionString = value.code.toString(); | ||
// Write the string | ||
@@ -514,3 +598,3 @@ var size = buffer.write(functionString, index + 4, 'utf8') + 1; | ||
return index; | ||
} | ||
}; | ||
@@ -521,3 +605,5 @@ var serializeBinary = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -531,3 +617,3 @@ index = index + numberOfWrittenBytes; | ||
// Add the deprecated 02 type 4 bytes of size to total | ||
if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) size = size + 4; | ||
if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) size = size + 4; | ||
// Write the size of the string to buffer | ||
@@ -542,3 +628,3 @@ buffer[index++] = size & 0xff; | ||
// If we have binary type 2 the 4 first bytes are the size | ||
if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { | ||
if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) { | ||
size = size - 4; | ||
@@ -556,3 +642,3 @@ buffer[index++] = size & 0xff; | ||
return index; | ||
} | ||
}; | ||
@@ -563,3 +649,5 @@ var serializeSymbol = function(buffer, key, value, index, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
// Encode the name | ||
@@ -580,3 +668,3 @@ index = index + numberOfWrittenBytes; | ||
return index; | ||
} | ||
}; | ||
@@ -587,3 +675,5 @@ var serializeDBRef = function(buffer, key, value, index, depth, serializeFunctions, isArray) { | ||
// Number of written bytes | ||
var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii'); | ||
var numberOfWrittenBytes = !isArray | ||
? buffer.write(key, index, 'utf8') | ||
: buffer.write(key, index, 'ascii'); | ||
@@ -596,17 +686,12 @@ // Encode the name | ||
var endIndex; | ||
var output = { | ||
$ref: value.collection, | ||
$id: value.oid | ||
}; | ||
// Serialize object | ||
if(null != value.db) { | ||
endIndex = serializeInto(buffer, { | ||
'$ref': value.namespace | ||
, '$id' : value.oid | ||
, '$db' : value.db | ||
}, false, index, depth + 1, serializeFunctions); | ||
} else { | ||
endIndex = serializeInto(buffer, { | ||
'$ref': value.namespace | ||
, '$id' : value.oid | ||
}, false, index, depth + 1, serializeFunctions); | ||
} | ||
if (value.db != null) output.$db = value.db; | ||
output = Object.assign(output, value.fields); | ||
endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions); | ||
// Calculate object size | ||
@@ -621,5 +706,14 @@ var size = endIndex - startIndex; | ||
return endIndex; | ||
} | ||
}; | ||
var serializeInto = function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) { | ||
var serializeInto = function serializeInto( | ||
buffer, | ||
object, | ||
checkKeys, | ||
startingIndex, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
path | ||
) { | ||
startingIndex = startingIndex || 0; | ||
@@ -633,14 +727,13 @@ path = path || []; | ||
var index = startingIndex + 4; | ||
var self = this; | ||
// Special case isArray | ||
if(Array.isArray(object)) { | ||
if (Array.isArray(object)) { | ||
// Get object keys | ||
for(var i = 0; i < object.length; i++) { | ||
var key = "" + i; | ||
for (var i = 0; i < object.length; i++) { | ||
var key = '' + i; | ||
var value = object[i]; | ||
// Is there an override value | ||
if(value && value.toBSON) { | ||
if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
if (value && value.toBSON) { | ||
if (typeof value.toBSON !== 'function') throw new Error('toBSON is not a function'); | ||
value = value.toBSON(); | ||
@@ -650,51 +743,81 @@ } | ||
var type = typeof value; | ||
if(type == 'string') { | ||
if (type === 'string') { | ||
index = serializeString(buffer, key, value, index, true); | ||
} else if(type == 'number') { | ||
} else if (type === 'number') { | ||
index = serializeNumber(buffer, key, value, index, true); | ||
} else if(type == 'boolean') { | ||
} else if (type === 'boolean') { | ||
index = serializeBoolean(buffer, key, value, index, true); | ||
} else if(value instanceof Date || isDate(value)) { | ||
} else if (value instanceof Date || isDate(value)) { | ||
index = serializeDate(buffer, key, value, index, true); | ||
} else if(value === undefined) { | ||
} else if (value === undefined) { | ||
index = serializeNull(buffer, key, value, index, true); | ||
} else if(value === null) { | ||
} else if (value === null) { | ||
index = serializeNull(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'ObjectID') { | ||
} else if (value['_bsontype'] === 'ObjectID') { | ||
index = serializeObjectId(buffer, key, value, index, true); | ||
} else if(Buffer.isBuffer(value)) { | ||
} else if (Buffer.isBuffer(value)) { | ||
index = serializeBuffer(buffer, key, value, index, true); | ||
} else if(value instanceof RegExp || isRegExp(value)) { | ||
} else if (value instanceof RegExp || isRegExp(value)) { | ||
index = serializeRegExp(buffer, key, value, index, true); | ||
} else if(type == 'object' && value['_bsontype'] == null) { | ||
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true, path); | ||
} else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
} else if (type === 'object' && value['_bsontype'] == null) { | ||
index = serializeObject( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
true, | ||
path | ||
); | ||
} else if (type === 'object' && value['_bsontype'] === 'Decimal128') { | ||
index = serializeDecimal128(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') { | ||
index = serializeLong(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'Double') { | ||
} else if (value['_bsontype'] === 'Double') { | ||
index = serializeDouble(buffer, key, value, index, true); | ||
} else if(typeof value == 'function' && serializeFunctions) { | ||
index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions, true); | ||
} else if(value['_bsontype'] == 'Code') { | ||
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true); | ||
} else if(value['_bsontype'] == 'Binary') { | ||
} else if (typeof value === 'function' && serializeFunctions) { | ||
index = serializeFunction( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
true | ||
); | ||
} else if (value['_bsontype'] === 'Code') { | ||
index = serializeCode( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
true | ||
); | ||
} else if (value['_bsontype'] === 'Binary') { | ||
index = serializeBinary(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'Symbol') { | ||
} else if (value['_bsontype'] === 'Symbol') { | ||
index = serializeSymbol(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'DBRef') { | ||
} else if (value['_bsontype'] === 'DBRef') { | ||
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true); | ||
} else if(value['_bsontype'] == 'BSONRegExp') { | ||
} else if (value['_bsontype'] === 'BSONRegExp') { | ||
index = serializeBSONRegExp(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'Int32') { | ||
} else if (value['_bsontype'] === 'Int32') { | ||
index = serializeInt32(buffer, key, value, index, true); | ||
} else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') { | ||
index = serializeMinMax(buffer, key, value, index, true); | ||
} | ||
} | ||
} else if(object instanceof Map) { | ||
} else if (object instanceof Map) { | ||
var iterator = object.entries(); | ||
var done = false; | ||
while(!done) { | ||
while (!done) { | ||
// Unpack the next entry | ||
@@ -704,24 +827,24 @@ var entry = iterator.next(); | ||
// Are we done, then skip and terminate | ||
if(done) continue; | ||
if (done) continue; | ||
// Get the entry values | ||
var key = entry.value[0]; | ||
var value = entry.value[1]; | ||
key = entry.value[0]; | ||
value = entry.value[1]; | ||
// Check the type of the value | ||
var type = typeof value; | ||
type = typeof value; | ||
// Check the key and throw error if it's illegal | ||
if(key != '$db' && key != '$ref' && key != '$id') { | ||
if (key !== '$db' && key !== '$ref' && key !== '$id') { | ||
if (key.match(regexp) != null) { | ||
// The BSON spec doesn't allow keys with null bytes because keys are | ||
// null-terminated. | ||
throw Error("key " + key + " must not contain null bytes"); | ||
throw Error('key ' + key + ' must not contain null bytes'); | ||
} | ||
if (checkKeys) { | ||
if('$' == key[0]) { | ||
throw Error("key " + key + " must not start with '$'"); | ||
} else if (!!~key.indexOf('.')) { | ||
throw Error("key " + key + " must not contain '.'"); | ||
if ('$' === key[0]) { | ||
throw Error('key ' + key + " must not start with '$'"); | ||
} else if (~key.indexOf('.')) { | ||
throw Error('key ' + key + " must not contain '.'"); | ||
} | ||
@@ -731,42 +854,61 @@ } | ||
if(type == 'string') { | ||
if (type === 'string') { | ||
index = serializeString(buffer, key, value, index); | ||
} else if(type == 'number') { | ||
} else if (type === 'number') { | ||
index = serializeNumber(buffer, key, value, index); | ||
} else if(type == 'boolean') { | ||
} else if (type === 'boolean') { | ||
index = serializeBoolean(buffer, key, value, index); | ||
} else if(value instanceof Date || isDate(value)) { | ||
} else if (value instanceof Date || isDate(value)) { | ||
index = serializeDate(buffer, key, value, index); | ||
} else if(value === undefined && ignoreUndefined == true) { | ||
} else if(value === null || value === undefined) { | ||
} else if (value === null || (value === undefined && ignoreUndefined === false)) { | ||
index = serializeNull(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'ObjectID') { | ||
} else if (value['_bsontype'] === 'ObjectID') { | ||
index = serializeObjectId(buffer, key, value, index); | ||
} else if(Buffer.isBuffer(value)) { | ||
} else if (Buffer.isBuffer(value)) { | ||
index = serializeBuffer(buffer, key, value, index); | ||
} else if(value instanceof RegExp || isRegExp(value)) { | ||
} else if (value instanceof RegExp || isRegExp(value)) { | ||
index = serializeRegExp(buffer, key, value, index); | ||
} else if(type == 'object' && value['_bsontype'] == null) { | ||
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path); | ||
} else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
} else if (type === 'object' && value['_bsontype'] == null) { | ||
index = serializeObject( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
false, | ||
path | ||
); | ||
} else if (type === 'object' && value['_bsontype'] === 'Decimal128') { | ||
index = serializeDecimal128(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') { | ||
index = serializeLong(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Double') { | ||
} else if (value['_bsontype'] === 'Double') { | ||
index = serializeDouble(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Code') { | ||
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined); | ||
} else if(typeof value == 'function' && serializeFunctions) { | ||
} else if (value['_bsontype'] === 'Code') { | ||
index = serializeCode( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined | ||
); | ||
} else if (typeof value === 'function' && serializeFunctions) { | ||
index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions); | ||
} else if(value['_bsontype'] == 'Binary') { | ||
} else if (value['_bsontype'] === 'Binary') { | ||
index = serializeBinary(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Symbol') { | ||
} else if (value['_bsontype'] === 'Symbol') { | ||
index = serializeSymbol(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'DBRef') { | ||
} else if (value['_bsontype'] === 'DBRef') { | ||
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions); | ||
} else if(value['_bsontype'] == 'BSONRegExp') { | ||
} else if (value['_bsontype'] === 'BSONRegExp') { | ||
index = serializeBSONRegExp(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Int32') { | ||
} else if (value['_bsontype'] === 'Int32') { | ||
index = serializeInt32(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') { | ||
index = serializeMinMax(buffer, key, value, index); | ||
@@ -777,14 +919,15 @@ } | ||
// Did we provide a custom serialization method | ||
if(object.toBSON) { | ||
if(typeof object.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
if (object.toBSON) { | ||
if (typeof object.toBSON !== 'function') throw new Error('toBSON is not a function'); | ||
object = object.toBSON(); | ||
if(object != null && typeof object != 'object') throw new Error("toBSON function did not return an object"); | ||
if (object != null && typeof object !== 'object') | ||
throw new Error('toBSON function did not return an object'); | ||
} | ||
// Iterate over all the keys | ||
for(var key in object) { | ||
var value = object[key]; | ||
for (key in object) { | ||
value = object[key]; | ||
// Is there an override value | ||
if(value && value.toBSON) { | ||
if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function"); | ||
if (value && value.toBSON) { | ||
if (typeof value.toBSON !== 'function') throw new Error('toBSON is not a function'); | ||
value = value.toBSON(); | ||
@@ -794,17 +937,17 @@ } | ||
// Check the type of the value | ||
var type = typeof value; | ||
type = typeof value; | ||
// Check the key and throw error if it's illegal | ||
if(key != '$db' && key != '$ref' && key != '$id') { | ||
if (key !== '$db' && key !== '$ref' && key !== '$id') { | ||
if (key.match(regexp) != null) { | ||
// The BSON spec doesn't allow keys with null bytes because keys are | ||
// null-terminated. | ||
throw Error("key " + key + " must not contain null bytes"); | ||
throw Error('key ' + key + ' must not contain null bytes'); | ||
} | ||
if (checkKeys) { | ||
if('$' == key[0]) { | ||
throw Error("key " + key + " must not start with '$'"); | ||
} else if (!!~key.indexOf('.')) { | ||
throw Error("key " + key + " must not contain '.'"); | ||
if ('$' === key[0]) { | ||
throw Error('key ' + key + " must not start with '$'"); | ||
} else if (~key.indexOf('.')) { | ||
throw Error('key ' + key + " must not contain '.'"); | ||
} | ||
@@ -814,42 +957,63 @@ } | ||
if(type == 'string') { | ||
if (type === 'string') { | ||
index = serializeString(buffer, key, value, index); | ||
} else if(type == 'number') { | ||
} else if (type === 'number') { | ||
index = serializeNumber(buffer, key, value, index); | ||
} else if(type == 'boolean') { | ||
} else if (type === 'boolean') { | ||
index = serializeBoolean(buffer, key, value, index); | ||
} else if(value instanceof Date || isDate(value)) { | ||
} else if (value instanceof Date || isDate(value)) { | ||
index = serializeDate(buffer, key, value, index); | ||
} else if(value === undefined && ignoreUndefined == true) { | ||
} else if(value === null || value === undefined) { | ||
} else if (value === undefined) { | ||
if (ignoreUndefined === false) index = serializeNull(buffer, key, value, index); | ||
} else if (value === null) { | ||
index = serializeNull(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'ObjectID') { | ||
} else if (value['_bsontype'] === 'ObjectID') { | ||
index = serializeObjectId(buffer, key, value, index); | ||
} else if(Buffer.isBuffer(value)) { | ||
} else if (Buffer.isBuffer(value)) { | ||
index = serializeBuffer(buffer, key, value, index); | ||
} else if(value instanceof RegExp || isRegExp(value)) { | ||
} else if (value instanceof RegExp || isRegExp(value)) { | ||
index = serializeRegExp(buffer, key, value, index); | ||
} else if(type == 'object' && value['_bsontype'] == null) { | ||
index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path); | ||
} else if(type == 'object' && value['_bsontype'] == 'Decimal128') { | ||
} else if (type === 'object' && value['_bsontype'] == null) { | ||
index = serializeObject( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined, | ||
false, | ||
path | ||
); | ||
} else if (type === 'object' && value['_bsontype'] === 'Decimal128') { | ||
index = serializeDecimal128(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { | ||
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') { | ||
index = serializeLong(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Double') { | ||
} else if (value['_bsontype'] === 'Double') { | ||
index = serializeDouble(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Code') { | ||
index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined); | ||
} else if(typeof value == 'function' && serializeFunctions) { | ||
} else if (value['_bsontype'] === 'Code') { | ||
index = serializeCode( | ||
buffer, | ||
key, | ||
value, | ||
index, | ||
checkKeys, | ||
depth, | ||
serializeFunctions, | ||
ignoreUndefined | ||
); | ||
} else if (typeof value === 'function' && serializeFunctions) { | ||
index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions); | ||
} else if(value['_bsontype'] == 'Binary') { | ||
} else if (value['_bsontype'] === 'Binary') { | ||
index = serializeBinary(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Symbol') { | ||
} else if (value['_bsontype'] === 'Symbol') { | ||
index = serializeSymbol(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'DBRef') { | ||
} else if (value['_bsontype'] === 'DBRef') { | ||
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions); | ||
} else if(value['_bsontype'] == 'BSONRegExp') { | ||
} else if (value['_bsontype'] === 'BSONRegExp') { | ||
index = serializeBSONRegExp(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'Int32') { | ||
} else if (value['_bsontype'] === 'Int32') { | ||
index = serializeInt32(buffer, key, value, index); | ||
} else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { | ||
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') { | ||
index = serializeMinMax(buffer, key, value, index); | ||
@@ -874,3 +1038,3 @@ } | ||
return index; | ||
} | ||
}; | ||
@@ -885,3 +1049,3 @@ var BSON = {}; | ||
*/ | ||
var functionCache = BSON.functionCache = {}; | ||
// var functionCache = (BSON.functionCache = {}); | ||
@@ -1046,3 +1210,3 @@ /** | ||
// BSON MAX VALUES | ||
BSON.BSON_INT32_MAX = 0x7FFFFFFF; | ||
BSON.BSON_INT32_MAX = 0x7fffffff; | ||
BSON.BSON_INT32_MIN = -0x80000000; | ||
@@ -1054,9 +1218,9 @@ | ||
// JS MAX PRECISE VALUES | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. | ||
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. | ||
// Internal long versions | ||
var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
// var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. | ||
// var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. | ||
module.exports = serializeInto; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -8,3 +9,3 @@ * A class representation of the BSON RegExp type. | ||
function BSONRegExp(pattern, options) { | ||
if(!(this instanceof BSONRegExp)) return new BSONRegExp(); | ||
if (!(this instanceof BSONRegExp)) return new BSONRegExp(); | ||
@@ -17,11 +18,14 @@ // Execute | ||
// Validate options | ||
for(var i = 0; i < this.options.length; i++) { | ||
if(!(this.options[i] == 'i' | ||
|| this.options[i] == 'm' | ||
|| this.options[i] == 'x' | ||
|| this.options[i] == 'l' | ||
|| this.options[i] == 's' | ||
|| this.options[i] == 'u' | ||
)) { | ||
throw new Error('the regular expression options [' + this.options[i] + "] is not supported"); | ||
for (var i = 0; i < this.options.length; i++) { | ||
if ( | ||
!( | ||
this.options[i] === 'i' || | ||
this.options[i] === 'm' || | ||
this.options[i] === 'x' || | ||
this.options[i] === 'l' || | ||
this.options[i] === 's' || | ||
this.options[i] === 'u' | ||
) | ||
) { | ||
throw new Error('the regular expression options [' + this.options[i] + '] is not supported'); | ||
} | ||
@@ -28,0 +32,0 @@ } |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -10,3 +11,3 @@ * A class representation of the BSON Symbol type. | ||
function Symbol(value) { | ||
if(!(this instanceof Symbol)) return new Symbol(value); | ||
if (!(this instanceof Symbol)) return new Symbol(value); | ||
this._bsontype = 'Symbol'; | ||
@@ -31,3 +32,3 @@ this.value = value; | ||
return this.value; | ||
} | ||
}; | ||
@@ -39,3 +40,3 @@ /** | ||
return this.value; | ||
} | ||
}; | ||
@@ -47,5 +48,5 @@ /** | ||
return this.value; | ||
} | ||
}; | ||
module.exports = Symbol; | ||
module.exports.Symbol = Symbol; | ||
module.exports.Symbol = Symbol; |
@@ -1,719 +0,60 @@ | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// Copyright 2009 Google Inc. All Rights Reserved | ||
'use strict'; | ||
var Long = require('./long'); | ||
/** | ||
* This type is for INTERNAL use in MongoDB only and should not be used in applications. | ||
* The appropriate corresponding type is the JavaScript Date type. | ||
* | ||
* Defines a Timestamp class for representing a 64-bit two's-complement | ||
* integer value, which faithfully simulates the behavior of a Java "Timestamp". This | ||
* implementation is derived from TimestampLib in GWT. | ||
* | ||
* Constructs a 64-bit two's-complement integer, given its low and high 32-bit | ||
* values as *signed* integers. See the from* functions below for more | ||
* convenient ways of constructing Timestamps. | ||
* | ||
* The internal representation of a Timestamp is the two given signed, 32-bit values. | ||
* We use 32-bit pieces because these are the size of integers on which | ||
* Javascript performs bit-operations. For operations like addition and | ||
* multiplication, we split each number into 16-bit pieces, which can easily be | ||
* multiplied within Javascript's floating-point representation without overflow | ||
* or change in sign. | ||
* | ||
* In the algorithms below, we frequently reduce the negative case to the | ||
* positive case by negating the input(s) and then post-processing the result. | ||
* Note that we must ALWAYS check specially whether those values are MIN_VALUE | ||
* (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as | ||
* a positive number, it overflows back into a negative). Not handling this | ||
* case would often result in infinite recursion. | ||
* | ||
* @class | ||
* @param {number} low the low (signed) 32 bits of the Timestamp. | ||
* @param {number} high the high (signed) 32 bits of the Timestamp. | ||
* @return {Timestamp} | ||
*/ | ||
function Timestamp(low, high) { | ||
if(!(this instanceof Timestamp)) return new Timestamp(low, high); | ||
var Timestamp = function(low, high) { | ||
if (low instanceof Long) { | ||
Long.call(this, low.low_, low.high_); | ||
} else { | ||
Long.call(this, low, high); | ||
} | ||
this._bsontype = 'Timestamp'; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
this.low_ = low | 0; // force into 32 signed bits. | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
this.high_ = high | 0; // force into 32 signed bits. | ||
}; | ||
/** | ||
* Return the int value. | ||
* | ||
* @return {number} the value, assuming it is a 32-bit integer. | ||
*/ | ||
Timestamp.prototype.toInt = function() { | ||
return this.low_; | ||
}; | ||
Timestamp.prototype = Object.create(Long.prototype); | ||
Timestamp.prototype.constructor = Timestamp; | ||
/** | ||
* Return the Number value. | ||
* | ||
* @method | ||
* @return {number} the closest floating-point representation to this value. | ||
*/ | ||
Timestamp.prototype.toNumber = function() { | ||
return this.high_ * Timestamp.TWO_PWR_32_DBL_ + | ||
this.getLowBitsUnsigned(); | ||
}; | ||
/** | ||
* Return the JSON value. | ||
* | ||
* @method | ||
* @return {string} the JSON representation. | ||
* @return {String} the JSON representation. | ||
*/ | ||
Timestamp.prototype.toJSON = function() { | ||
return this.toString(); | ||
} | ||
/** | ||
* Return the String value. | ||
* | ||
* @method | ||
* @param {number} [opt_radix] the radix in which the text should be written. | ||
* @return {string} the textual representation of this value. | ||
*/ | ||
Timestamp.prototype.toString = function(opt_radix) { | ||
var radix = opt_radix || 10; | ||
if (radix < 2 || 36 < radix) { | ||
throw Error('radix out of range: ' + radix); | ||
} | ||
if (this.isZero()) { | ||
return '0'; | ||
} | ||
if (this.isNegative()) { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
// We need to change the Timestamp value before it can be negated, so we remove | ||
// the bottom-most digit in this base and then recurse to do the rest. | ||
var radixTimestamp = Timestamp.fromNumber(radix); | ||
var div = this.div(radixTimestamp); | ||
var rem = div.multiply(radixTimestamp).subtract(this); | ||
return div.toString(radix) + rem.toInt().toString(radix); | ||
} else { | ||
return '-' + this.negate().toString(radix); | ||
} | ||
} | ||
// Do several (6) digits each time through the loop, so as to | ||
// minimize the calls to the very expensive emulated div. | ||
var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6)); | ||
var rem = this; | ||
var result = ''; | ||
while (true) { | ||
var remDiv = rem.div(radixToPower); | ||
var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); | ||
var digits = intval.toString(radix); | ||
rem = remDiv; | ||
if (rem.isZero()) { | ||
return digits + result; | ||
} else { | ||
while (digits.length < 6) { | ||
digits = '0' + digits; | ||
} | ||
result = '' + digits + result; | ||
} | ||
} | ||
return { | ||
$timestamp: this.toString() | ||
}; | ||
}; | ||
/** | ||
* Return the high 32-bits value. | ||
* Returns a Timestamp represented by the given (32-bit) integer value. | ||
* | ||
* @method | ||
* @return {number} the high 32-bits as a signed value. | ||
*/ | ||
Timestamp.prototype.getHighBits = function() { | ||
return this.high_; | ||
}; | ||
/** | ||
* Return the low 32-bits value. | ||
* | ||
* @method | ||
* @return {number} the low 32-bits as a signed value. | ||
*/ | ||
Timestamp.prototype.getLowBits = function() { | ||
return this.low_; | ||
}; | ||
/** | ||
* Return the low unsigned 32-bits value. | ||
* | ||
* @method | ||
* @return {number} the low 32-bits as an unsigned value. | ||
*/ | ||
Timestamp.prototype.getLowBitsUnsigned = function() { | ||
return (this.low_ >= 0) ? | ||
this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_; | ||
}; | ||
/** | ||
* Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
* | ||
* @method | ||
* @return {number} Returns the number of bits needed to represent the absolute value of this Timestamp. | ||
*/ | ||
Timestamp.prototype.getNumBitsAbs = function() { | ||
if (this.isNegative()) { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return 64; | ||
} else { | ||
return this.negate().getNumBitsAbs(); | ||
} | ||
} else { | ||
var val = this.high_ != 0 ? this.high_ : this.low_; | ||
for (var bit = 31; bit > 0; bit--) { | ||
if ((val & (1 << bit)) != 0) { | ||
break; | ||
} | ||
} | ||
return this.high_ != 0 ? bit + 33 : bit + 1; | ||
} | ||
}; | ||
/** | ||
* Return whether this value is zero. | ||
* | ||
* @method | ||
* @return {boolean} whether this value is zero. | ||
*/ | ||
Timestamp.prototype.isZero = function() { | ||
return this.high_ == 0 && this.low_ == 0; | ||
}; | ||
/** | ||
* Return whether this value is negative. | ||
* | ||
* @method | ||
* @return {boolean} whether this value is negative. | ||
*/ | ||
Timestamp.prototype.isNegative = function() { | ||
return this.high_ < 0; | ||
}; | ||
/** | ||
* Return whether this value is odd. | ||
* | ||
* @method | ||
* @return {boolean} whether this value is odd. | ||
*/ | ||
Timestamp.prototype.isOdd = function() { | ||
return (this.low_ & 1) == 1; | ||
}; | ||
/** | ||
* Return whether this Timestamp equals the other | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp equals the other | ||
*/ | ||
Timestamp.prototype.equals = function(other) { | ||
return (this.high_ == other.high_) && (this.low_ == other.low_); | ||
}; | ||
/** | ||
* Return whether this Timestamp does not equal the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp does not equal the other. | ||
*/ | ||
Timestamp.prototype.notEquals = function(other) { | ||
return (this.high_ != other.high_) || (this.low_ != other.low_); | ||
}; | ||
/** | ||
* Return whether this Timestamp is less than the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp is less than the other. | ||
*/ | ||
Timestamp.prototype.lessThan = function(other) { | ||
return this.compare(other) < 0; | ||
}; | ||
/** | ||
* Return whether this Timestamp is less than or equal to the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp is less than or equal to the other. | ||
*/ | ||
Timestamp.prototype.lessThanOrEqual = function(other) { | ||
return this.compare(other) <= 0; | ||
}; | ||
/** | ||
* Return whether this Timestamp is greater than the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp is greater than the other. | ||
*/ | ||
Timestamp.prototype.greaterThan = function(other) { | ||
return this.compare(other) > 0; | ||
}; | ||
/** | ||
* Return whether this Timestamp is greater than or equal to the other. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} whether this Timestamp is greater than or equal to the other. | ||
*/ | ||
Timestamp.prototype.greaterThanOrEqual = function(other) { | ||
return this.compare(other) >= 0; | ||
}; | ||
/** | ||
* Compares this Timestamp with the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to compare against. | ||
* @return {boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. | ||
*/ | ||
Timestamp.prototype.compare = function(other) { | ||
if (this.equals(other)) { | ||
return 0; | ||
} | ||
var thisNeg = this.isNegative(); | ||
var otherNeg = other.isNegative(); | ||
if (thisNeg && !otherNeg) { | ||
return -1; | ||
} | ||
if (!thisNeg && otherNeg) { | ||
return 1; | ||
} | ||
// at this point, the signs are the same, so subtraction will not overflow | ||
if (this.subtract(other).isNegative()) { | ||
return -1; | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
/** | ||
* The negation of this value. | ||
* | ||
* @method | ||
* @return {Timestamp} the negation of this value. | ||
*/ | ||
Timestamp.prototype.negate = function() { | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.MIN_VALUE; | ||
} else { | ||
return this.not().add(Timestamp.ONE); | ||
} | ||
}; | ||
/** | ||
* Returns the sum of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to add to this one. | ||
* @return {Timestamp} the sum of this and the given Timestamp. | ||
*/ | ||
Timestamp.prototype.add = function(other) { | ||
// Divide each number into 4 chunks of 16 bits, and then sum the chunks. | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
c00 += a00 + b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c16 += a16 + b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c32 += a32 + b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c48 += a48 + b48; | ||
c48 &= 0xFFFF; | ||
return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
}; | ||
/** | ||
* Returns the difference of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to subtract from this. | ||
* @return {Timestamp} the difference of this and the given Timestamp. | ||
*/ | ||
Timestamp.prototype.subtract = function(other) { | ||
return this.add(other.negate()); | ||
}; | ||
/** | ||
* Returns the product of this and the given Timestamp. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp to multiply with this. | ||
* @return {Timestamp} the product of this and the other. | ||
*/ | ||
Timestamp.prototype.multiply = function(other) { | ||
if (this.isZero()) { | ||
return Timestamp.ZERO; | ||
} else if (other.isZero()) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; | ||
} | ||
if (this.isNegative()) { | ||
if (other.isNegative()) { | ||
return this.negate().multiply(other.negate()); | ||
} else { | ||
return this.negate().multiply(other).negate(); | ||
} | ||
} else if (other.isNegative()) { | ||
return this.multiply(other.negate()).negate(); | ||
} | ||
// If both Timestamps are small, use float multiplication | ||
if (this.lessThan(Timestamp.TWO_PWR_24_) && | ||
other.lessThan(Timestamp.TWO_PWR_24_)) { | ||
return Timestamp.fromNumber(this.toNumber() * other.toNumber()); | ||
} | ||
// Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products. | ||
// We can skip products that would overflow. | ||
var a48 = this.high_ >>> 16; | ||
var a32 = this.high_ & 0xFFFF; | ||
var a16 = this.low_ >>> 16; | ||
var a00 = this.low_ & 0xFFFF; | ||
var b48 = other.high_ >>> 16; | ||
var b32 = other.high_ & 0xFFFF; | ||
var b16 = other.low_ >>> 16; | ||
var b00 = other.low_ & 0xFFFF; | ||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0; | ||
c00 += a00 * b00; | ||
c16 += c00 >>> 16; | ||
c00 &= 0xFFFF; | ||
c16 += a16 * b00; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c16 += a00 * b16; | ||
c32 += c16 >>> 16; | ||
c16 &= 0xFFFF; | ||
c32 += a32 * b00; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 += a16 * b16; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c32 += a00 * b32; | ||
c48 += c32 >>> 16; | ||
c32 &= 0xFFFF; | ||
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; | ||
c48 &= 0xFFFF; | ||
return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); | ||
}; | ||
/** | ||
* Returns this Timestamp divided by the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp by which to divide. | ||
* @return {Timestamp} this Timestamp divided by the given one. | ||
*/ | ||
Timestamp.prototype.div = function(other) { | ||
if (other.isZero()) { | ||
throw Error('division by zero'); | ||
} else if (this.isZero()) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.equals(Timestamp.MIN_VALUE)) { | ||
if (other.equals(Timestamp.ONE) || | ||
other.equals(Timestamp.NEG_ONE)) { | ||
return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.ONE; | ||
} else { | ||
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. | ||
var halfThis = this.shiftRight(1); | ||
var approx = halfThis.div(other).shiftLeft(1); | ||
if (approx.equals(Timestamp.ZERO)) { | ||
return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE; | ||
} else { | ||
var rem = this.subtract(other.multiply(approx)); | ||
var result = approx.add(rem.div(other)); | ||
return result; | ||
} | ||
} | ||
} else if (other.equals(Timestamp.MIN_VALUE)) { | ||
return Timestamp.ZERO; | ||
} | ||
if (this.isNegative()) { | ||
if (other.isNegative()) { | ||
return this.negate().div(other.negate()); | ||
} else { | ||
return this.negate().div(other).negate(); | ||
} | ||
} else if (other.isNegative()) { | ||
return this.div(other.negate()).negate(); | ||
} | ||
// Repeat the following until the remainder is less than other: find a | ||
// floating-point that approximates remainder / other *from below*, add this | ||
// into the result, and subtract it from the remainder. It is critical that | ||
// the approximate value is less than or equal to the real value so that the | ||
// remainder never becomes negative. | ||
var res = Timestamp.ZERO; | ||
var rem = this; | ||
while (rem.greaterThanOrEqual(other)) { | ||
// Approximate the result of division. This may be a little greater or | ||
// smaller than the actual value. | ||
var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); | ||
// We will tweak the approximate result by changing it in the 48-th digit or | ||
// the smallest non-fractional digit, whichever is larger. | ||
var log2 = Math.ceil(Math.log(approx) / Math.LN2); | ||
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); | ||
// Decrease the approximation until it is smaller than the remainder. Note | ||
// that if it is too large, the product overflows and is negative. | ||
var approxRes = Timestamp.fromNumber(approx); | ||
var approxRem = approxRes.multiply(other); | ||
while (approxRem.isNegative() || approxRem.greaterThan(rem)) { | ||
approx -= delta; | ||
approxRes = Timestamp.fromNumber(approx); | ||
approxRem = approxRes.multiply(other); | ||
} | ||
// We know the answer can't be zero... and actually, zero would cause | ||
// infinite recursion since we would make no progress. | ||
if (approxRes.isZero()) { | ||
approxRes = Timestamp.ONE; | ||
} | ||
res = res.add(approxRes); | ||
rem = rem.subtract(approxRem); | ||
} | ||
return res; | ||
}; | ||
/** | ||
* Returns this Timestamp modulo the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other Timestamp by which to mod. | ||
* @return {Timestamp} this Timestamp modulo the given one. | ||
*/ | ||
Timestamp.prototype.modulo = function(other) { | ||
return this.subtract(this.div(other).multiply(other)); | ||
}; | ||
/** | ||
* The bitwise-NOT of this value. | ||
* | ||
* @method | ||
* @return {Timestamp} the bitwise-NOT of this value. | ||
*/ | ||
Timestamp.prototype.not = function() { | ||
return Timestamp.fromBits(~this.low_, ~this.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-AND of this Timestamp and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Timestamp with which to AND. | ||
* @return {Timestamp} the bitwise-AND of this and the other. | ||
*/ | ||
Timestamp.prototype.and = function(other) { | ||
return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-OR of this Timestamp and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Timestamp with which to OR. | ||
* @return {Timestamp} the bitwise-OR of this and the other. | ||
*/ | ||
Timestamp.prototype.or = function(other) { | ||
return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_); | ||
}; | ||
/** | ||
* Returns the bitwise-XOR of this Timestamp and the given one. | ||
* | ||
* @method | ||
* @param {Timestamp} other the Timestamp with which to XOR. | ||
* @return {Timestamp} the bitwise-XOR of this and the other. | ||
*/ | ||
Timestamp.prototype.xor = function(other) { | ||
return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); | ||
}; | ||
/** | ||
* Returns this Timestamp with bits shifted to the left by the given amount. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the left by the given amount. | ||
*/ | ||
Timestamp.prototype.shiftLeft = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var low = this.low_; | ||
if (numBits < 32) { | ||
var high = this.high_; | ||
return Timestamp.fromBits( | ||
low << numBits, | ||
(high << numBits) | (low >>> (32 - numBits))); | ||
} else { | ||
return Timestamp.fromBits(0, low << (numBits - 32)); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns this Timestamp with bits shifted to the right by the given amount. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the right by the given amount. | ||
*/ | ||
Timestamp.prototype.shiftRight = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var high = this.high_; | ||
if (numBits < 32) { | ||
var low = this.low_; | ||
return Timestamp.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >> numBits); | ||
} else { | ||
return Timestamp.fromBits( | ||
high >> (numBits - 32), | ||
high >= 0 ? 0 : -1); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns this Timestamp with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. | ||
* | ||
* @method | ||
* @param {number} numBits the number of bits by which to shift. | ||
* @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits. | ||
*/ | ||
Timestamp.prototype.shiftRightUnsigned = function(numBits) { | ||
numBits &= 63; | ||
if (numBits == 0) { | ||
return this; | ||
} else { | ||
var high = this.high_; | ||
if (numBits < 32) { | ||
var low = this.low_; | ||
return Timestamp.fromBits( | ||
(low >>> numBits) | (high << (32 - numBits)), | ||
high >>> numBits); | ||
} else if (numBits == 32) { | ||
return Timestamp.fromBits(high, 0); | ||
} else { | ||
return Timestamp.fromBits(high >>> (numBits - 32), 0); | ||
} | ||
} | ||
}; | ||
/** | ||
* Returns a Timestamp representing the given (32-bit) integer value. | ||
* | ||
* @method | ||
* @param {number} value the 32-bit integer in question. | ||
* @return {Timestamp} the corresponding Timestamp value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromInt = function(value) { | ||
if (-128 <= value && value < 128) { | ||
var cachedObj = Timestamp.INT_CACHE_[value]; | ||
if (cachedObj) { | ||
return cachedObj; | ||
} | ||
} | ||
var obj = new Timestamp(value | 0, value < 0 ? -1 : 0); | ||
if (-128 <= value && value < 128) { | ||
Timestamp.INT_CACHE_[value] = obj; | ||
} | ||
return obj; | ||
return new Timestamp(Long.fromInt(value)); | ||
}; | ||
/** | ||
* Returns a Timestamp representing the given value, provided that it is a finite number. Otherwise, zero is returned. | ||
* Returns a Timestamp representing the given number value, provided that it is a finite number. Otherwise, zero is returned. | ||
* | ||
* @method | ||
* @param {number} value the number in question. | ||
* @return {Timestamp} the corresponding Timestamp value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromNumber = function(value) { | ||
if (isNaN(value) || !isFinite(value)) { | ||
return Timestamp.ZERO; | ||
} else if (value <= -Timestamp.TWO_PWR_63_DBL_) { | ||
return Timestamp.MIN_VALUE; | ||
} else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) { | ||
return Timestamp.MAX_VALUE; | ||
} else if (value < 0) { | ||
return Timestamp.fromNumber(-value).negate(); | ||
} else { | ||
return new Timestamp( | ||
(value % Timestamp.TWO_PWR_32_DBL_) | 0, | ||
(value / Timestamp.TWO_PWR_32_DBL_) | 0); | ||
} | ||
return new Timestamp(Long.fromNumber(value)); | ||
}; | ||
/** | ||
* Returns a Timestamp representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. | ||
* Returns a Timestamp for the given high and low bits. Each is assumed to use 32 bits. | ||
* | ||
@@ -723,3 +64,3 @@ * @method | ||
* @param {number} highBits the high 32-bits. | ||
* @return {Timestamp} the corresponding Timestamp value. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
@@ -731,128 +72,14 @@ Timestamp.fromBits = function(lowBits, highBits) { | ||
/** | ||
* Returns a Timestamp representation of the given string, written using the given radix. | ||
* Returns a Timestamp from the given string, optionally using the given radix. | ||
* | ||
* @method | ||
* @param {string} str the textual representation of the Timestamp. | ||
* @param {number} opt_radix the radix in which the text is written. | ||
* @return {Timestamp} the corresponding Timestamp value. | ||
* @param {String} str the textual representation of the Timestamp. | ||
* @param {number} [opt_radix] the radix in which the text is written. | ||
* @return {Timestamp} the timestamp. | ||
*/ | ||
Timestamp.fromString = function(str, opt_radix) { | ||
if (str.length == 0) { | ||
throw Error('number format error: empty string'); | ||
} | ||
var radix = opt_radix || 10; | ||
if (radix < 2 || 36 < radix) { | ||
throw Error('radix out of range: ' + radix); | ||
} | ||
if (str.charAt(0) == '-') { | ||
return Timestamp.fromString(str.substring(1), radix).negate(); | ||
} else if (str.indexOf('-') >= 0) { | ||
throw Error('number format error: interior "-" character: ' + str); | ||
} | ||
// Do several (8) digits each time through the loop, so as to | ||
// minimize the calls to the very expensive emulated div. | ||
var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8)); | ||
var result = Timestamp.ZERO; | ||
for (var i = 0; i < str.length; i += 8) { | ||
var size = Math.min(8, str.length - i); | ||
var value = parseInt(str.substring(i, i + size), radix); | ||
if (size < 8) { | ||
var power = Timestamp.fromNumber(Math.pow(radix, size)); | ||
result = result.multiply(power).add(Timestamp.fromNumber(value)); | ||
} else { | ||
result = result.multiply(radixToPower); | ||
result = result.add(Timestamp.fromNumber(value)); | ||
} | ||
} | ||
return result; | ||
return new Timestamp(Long.fromString(str, opt_radix)); | ||
}; | ||
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the | ||
// from* methods on which they depend. | ||
/** | ||
* A cache of the Timestamp representations of small integer values. | ||
* @type {Object} | ||
* @ignore | ||
*/ | ||
Timestamp.INT_CACHE_ = {}; | ||
// NOTE: the compiler should inline these constant values below and then remove | ||
// these variables, so there should be no runtime penalty for these. | ||
/** | ||
* Number used repeated below in calculations. This must appear before the | ||
* first call to any from* function below. | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_16_DBL_ = 1 << 16; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_24_DBL_ = 1 << 24; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_; | ||
/** | ||
* @type {number} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2; | ||
/** @type {Timestamp} */ | ||
Timestamp.ZERO = Timestamp.fromInt(0); | ||
/** @type {Timestamp} */ | ||
Timestamp.ONE = Timestamp.fromInt(1); | ||
/** @type {Timestamp} */ | ||
Timestamp.NEG_ONE = Timestamp.fromInt(-1); | ||
/** @type {Timestamp} */ | ||
Timestamp.MAX_VALUE = | ||
Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); | ||
/** @type {Timestamp} */ | ||
Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0); | ||
/** | ||
* @type {Timestamp} | ||
* @ignore | ||
*/ | ||
Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24); | ||
/** | ||
* Expose. | ||
*/ | ||
module.exports = Timestamp; | ||
module.exports.Timestamp = Timestamp; | ||
module.exports.Timestamp = Timestamp; |
@@ -15,4 +15,5 @@ { | ||
], | ||
"version": "1.0.4", | ||
"version": "2.0.0", | ||
"author": "Christian Amor Kvalheim <christkv@gmail.com>", | ||
"license": "Apache-2.0", | ||
"contributors": [], | ||
@@ -25,13 +26,18 @@ "repository": "mongodb/js-bson", | ||
"devDependencies": { | ||
"benchmark": "1.0.0", | ||
"colors": "1.1.0", | ||
"nodeunit": "0.9.0", | ||
"babel-core": "^6.14.0", | ||
"babel-loader": "^6.2.5", | ||
"babel-polyfill": "^6.13.0", | ||
"babel-preset-es2015": "^6.14.0", | ||
"babel-preset-stage-0": "^6.5.0", | ||
"babel-register": "^6.14.0", | ||
"webpack": "^1.13.2", | ||
"webpack-polyfills-plugin": "0.0.9" | ||
"benchmark": "^2.1.4", | ||
"babel-core": "^6.26.0", | ||
"babel-loader": "^7.1.2", | ||
"babel-polyfill": "^6.26.0", | ||
"babel-preset-env": "^1.6.0", | ||
"babel-preset-stage-0": "^6.24.1", | ||
"babel-register": "^6.26.0", | ||
"chai": "^4.1.2", | ||
"conventional-changelog-cli": "^1.3.5", | ||
"eslint": "^4.7.2", | ||
"eslint-plugin-prettier": "^2.3.1", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.5.3", | ||
"prettier": "^1.7.0", | ||
"webpack": "^3.6.0", | ||
"webpack-polyfills-plugin": "0.1.0" | ||
}, | ||
@@ -46,10 +52,14 @@ "config": { | ||
"engines": { | ||
"node": ">=0.6.19" | ||
"node": ">=4.0.0" | ||
}, | ||
"scripts": { | ||
"test": "nodeunit ./test/node", | ||
"build": "webpack --config ./webpack.dist.config.js" | ||
"test": "mocha ./test/node", | ||
"build": "webpack --config ./webpack.dist.config.js", | ||
"lint": "eslint lib test", | ||
"format": "prettier --print-width 100 --tab-width 2 --single-quote --write 'test/**/*.js' 'lib/**/*.js'", | ||
"changelog": "conventional-changelog -p angular -i HISTORY.md -s", | ||
"coverage": "istanbul cover _mocha -- --recursive --ui tdd test/node", | ||
"prepublishOnly": "npm run build" | ||
}, | ||
"browser": "lib/bson/bson.js", | ||
"license": "Apache-2.0" | ||
"browser": "browser_build/bson.js" | ||
} |
# BSON parser | ||
If you don't yet know what BSON actually is, read [the spec](http://bsonspec.org). | ||
BSON is short for Binary JSON and is the binary-encoded serialization of JSON-like documents. You can learn more about it in [the specification](http://bsonspec.org). | ||
The browser version of the BSON parser is compiled using webpack and the current | ||
version is pre-compiled in the browser_build directory. To build a new version perform the following operation. | ||
This browser version of the BSON parser is compiled using [webpack](https://webpack.js.org/) and the current version is pre-compiled in the `browser_build` directory. | ||
This is the default BSON parser, however, there is a C++ Node.js addon version as well that does not support the browser. It can be found at [mongod-js/bson-ext](https://github.com/mongodb-js/bson-ext). | ||
## Usage | ||
To build a new version perform the following operations: | ||
``` | ||
@@ -36,3 +41,3 @@ npm install | ||
A simple example of how to use BSON in `node.js`: | ||
A simple example of how to use BSON in `Node.js`: | ||
@@ -67,18 +72,16 @@ ```js | ||
For all BSON types documentation, please refer to the documentation for the mongodb driver. | ||
For all BSON types documentation, please refer to the documentation for the [MongoDB Node.js driver](https://github.com/mongodb/node-mongodb-native). | ||
https://github.com/mongodb/node-mongodb-native | ||
### BSON serialization and deserialiation | ||
**`new BSON()`** - Creates a new BSON seralizer/deserializer you can use to serialize and deserialize BSON. | ||
**`new BSON()`** - Creates a new BSON serializer/deserializer you can use to serialize and deserialize BSON. | ||
#### BSON.serialize | ||
The BSON serialize method takes a javascript object and an optional options object and returns a Node.js Buffer. | ||
The BSON `serialize` method takes a JavaScript object and an optional options object and returns a Node.js Buffer. | ||
* BSON.serialize(object, options) | ||
* @param {Object} object the Javascript object to serialize. | ||
* `BSON.serialize(object, options)` | ||
* @param {Object} object the JavaScript object to serialize. | ||
* @param {Boolean} [options.checkKeys=false] the serializer will check if keys are valid. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the javascript. functions. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the JavaScript functions. | ||
* @param {Boolean} [options.ignoreUndefined=true] | ||
@@ -89,9 +92,9 @@ * @return {Buffer} returns a Buffer instance. | ||
The BSON serializeWithBufferAndIndex method takes an object, a target buffer instance and an optional options object and returns the end serialization index in the final buffer. | ||
The BSON `serializeWithBufferAndIndex` method takes an object, a target buffer instance and an optional options object and returns the end serialization index in the final buffer. | ||
* BSON.serializeWithBufferAndIndex(object, buffer, options) | ||
* @param {Object} object the Javascript object to serialize. | ||
* `BSON.serializeWithBufferAndIndex(object, buffer, options)` | ||
* @param {Object} object the JavaScript object to serialize. | ||
* @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. | ||
* @param {Boolean} [options.checkKeys=false] the serializer will check if keys are valid. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the javascript functions. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the JavaScript functions. | ||
* @param {Boolean} [options.ignoreUndefined=true] ignore undefined fields. | ||
@@ -103,7 +106,7 @@ * @param {Number} [options.index=0] the index in the buffer where we wish to start serializing into. | ||
The BSON calculateObjectSize method takes a javascript object and an optional options object and returns the size of the BSON object. | ||
The BSON `calculateObjectSize` method takes a JavaScript object and an optional options object and returns the size of the BSON object. | ||
* BSON.calculateObjectSize(object, options) | ||
* @param {Object} object the Javascript object to serialize. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the javascript. functions. | ||
* `BSON.calculateObjectSize(object, options)` | ||
* @param {Object} object the JavaScript object to serialize. | ||
* @param {Boolean} [options.serializeFunctions=false] serialize the JavaScript functions. | ||
* @param {Boolean} [options.ignoreUndefined=true] | ||
@@ -114,5 +117,5 @@ * @return {Buffer} returns a Buffer instance. | ||
The BSON deserialize method takes a node.js Buffer and an optional options object and returns a deserialized Javascript object. | ||
The BSON `deserialize` method takes a Node.js Buffer and an optional options object and returns a deserialized JavaScript object. | ||
* BSON.deserialize(buffer, options) | ||
* `BSON.deserialize(buffer, options)` | ||
* @param {Object} [options.evalFunctions=false] evaluate functions in the BSON document scoped to the object deserialized. | ||
@@ -122,3 +125,3 @@ * @param {Object} [options.cacheFunctions=false] cache evaluated functions for reuse. | ||
* @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
* @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
* @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a Node.js Buffer instance. | ||
* @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
@@ -131,5 +134,5 @@ * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
The BSON deserializeStream method takes a node.js Buffer, startIndex and allow more control over deserialization of a Buffer containing concatenated BSON documents. | ||
The BSON `deserializeStream` method takes a Node.js Buffer, `startIndex` and allow more control over deserialization of a Buffer containing concatenated BSON documents. | ||
* BSON.deserializeStream(buffer, startIndex, numberOfDocuments, documents, docStartIndex, options) | ||
* `BSON.deserializeStream(buffer, startIndex, numberOfDocuments, documents, docStartIndex, options)` | ||
* @param {Buffer} buffer the buffer containing the serialized set of BSON documents. | ||
@@ -144,6 +147,12 @@ * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. | ||
* @param {Object} [options.promoteLongs=true] when deserializing a Long will fit it into a Number if it's smaller than 53 bits | ||
* @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a node.js Buffer instance. | ||
* @param {Object} [options.promoteBuffers=false] when deserializing a Binary will return it as a Node.js Buffer instance. | ||
* @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. | ||
* @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. | ||
* @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. | ||
* @return {Object} returns the deserialized Javascript Object. | ||
* @return {Object} returns the deserialized JavaScript Object. | ||
## FAQ | ||
#### Why does `undefined` get converted to `null`? | ||
The `undefined` BSON type has been [deprecated for many years](http://bsonspec.org/spec.html), so this library has dropped support for it. Use the `ignoreUndefined` option (for example, from the [driver](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect) ) to instead remove `undefined` keys. |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
151
680229
16
19156
3