|
@@ -1,782 +0,0 @@
|
|
|
-'use strict';
|
|
|
-
|
|
|
-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'),
|
|
|
- DBRef = require('../db_ref').DBRef,
|
|
|
- BSONRegExp = require('../regexp').BSONRegExp,
|
|
|
- Binary = require('../binary').Binary;
|
|
|
-
|
|
|
-var utils = require('./utils');
|
|
|
-
|
|
|
-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);
|
|
|
-
|
|
|
- // 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");
|
|
|
- }
|
|
|
-
|
|
|
- // Start deserializtion
|
|
|
- return deserializeObject(buffer, index, options, isArray);
|
|
|
-};
|
|
|
-
|
|
|
-var deserializeObject = function(buffer, index, options, isArray) {
|
|
|
- var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
|
|
|
- var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
|
|
|
- var cacheFunctionsCrc32 =
|
|
|
- options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
|
|
|
-
|
|
|
- if (!cacheFunctionsCrc32) var crc32 = null;
|
|
|
-
|
|
|
- var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
|
|
|
-
|
|
|
- // Return raw bson buffer instead of parsing it
|
|
|
- var raw = options['raw'] == null ? false : options['raw'];
|
|
|
-
|
|
|
- // 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');
|
|
|
-
|
|
|
- // 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');
|
|
|
-
|
|
|
- // Create holding object
|
|
|
- var object = isArray ? [] : {};
|
|
|
- // Used for arrays to skip having to perform utf8 decoding
|
|
|
- var arrayIndex = 0;
|
|
|
-
|
|
|
- var done = false;
|
|
|
-
|
|
|
- // While we have more left data left keep parsing
|
|
|
- // while (buffer[index + 1] !== 0) {
|
|
|
- while (!done) {
|
|
|
- // Read the type
|
|
|
- var elementType = buffer[index++];
|
|
|
- // If we get a zero it's the last byte, exit
|
|
|
- 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++;
|
|
|
- }
|
|
|
-
|
|
|
- // 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;
|
|
|
-
|
|
|
- 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);
|
|
|
- index = index + stringSize;
|
|
|
- } else if (elementType === BSON.BSON_DATA_OID) {
|
|
|
- var oid = utils.allocBuffer(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);
|
|
|
- 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');
|
|
|
-
|
|
|
- // 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) {
|
|
|
- _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;
|
|
|
-
|
|
|
- // 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;
|
|
|
- }
|
|
|
-
|
|
|
- object[name] = deserializeObject(buffer, _index, arrayOptions, true);
|
|
|
- index = index + objectSize;
|
|
|
-
|
|
|
- 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) {
|
|
|
- // Unpack the low and high bits
|
|
|
- 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;
|
|
|
- } else {
|
|
|
- object[name] = long;
|
|
|
- }
|
|
|
- } else if (elementType === BSON.BSON_DATA_DECIMAL128) {
|
|
|
- // Buffer to contain the decimal bytes
|
|
|
- var bytes = utils.allocBuffer(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');
|
|
|
-
|
|
|
- // 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) {
|
|
|
- // 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 (promoteBuffers && promoteValues) {
|
|
|
- object[name] = buffer.slice(index, index + binarySize);
|
|
|
- } else {
|
|
|
- object[name] = new Binary(buffer.slice(index, index + binarySize), subType);
|
|
|
- }
|
|
|
- } else {
|
|
|
- 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');
|
|
|
- }
|
|
|
-
|
|
|
- // Copy the data
|
|
|
- for (i = 0; i < binarySize; i++) {
|
|
|
- _buffer[i] = buffer[index + i];
|
|
|
- }
|
|
|
-
|
|
|
- if (promoteBuffers && promoteValues) {
|
|
|
- object[name] = _buffer;
|
|
|
- } else {
|
|
|
- object[name] = new Binary(_buffer, subType);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Update the index
|
|
|
- index = index + binarySize;
|
|
|
- } 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;
|
|
|
-
|
|
|
- // 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;
|
|
|
-
|
|
|
- // For each option add the corresponding one for javascript
|
|
|
- var optionsArray = new Array(regExpOptions.length);
|
|
|
-
|
|
|
- // Parse options
|
|
|
- for (i = 0; i < regExpOptions.length; i++) {
|
|
|
- switch (regExpOptions[i]) {
|
|
|
- case 'm':
|
|
|
- optionsArray[i] = 'm';
|
|
|
- break;
|
|
|
- case 's':
|
|
|
- optionsArray[i] = 'g';
|
|
|
- break;
|
|
|
- case 'i':
|
|
|
- optionsArray[i] = 'i';
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- object[name] = new RegExp(source, optionsArray.join(''));
|
|
|
- } 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
|
|
|
- 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;
|
|
|
-
|
|
|
- // Set the object
|
|
|
- object[name] = new BSONRegExp(source, regExpOptions);
|
|
|
- } 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');
|
|
|
- object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1));
|
|
|
- index = index + stringSize;
|
|
|
- } 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) {
|
|
|
- object[name] = new MinKey();
|
|
|
- } else if (elementType === BSON.BSON_DATA_MAX_KEY) {
|
|
|
- object[name] = new MaxKey();
|
|
|
- } 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) {
|
|
|
- // 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;
|
|
|
- // Got to do this to avoid V8 deoptimizing the call due to finding eval
|
|
|
- object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
|
|
|
- } else {
|
|
|
- object[name] = isolateEval(functionString);
|
|
|
- }
|
|
|
- } else {
|
|
|
- object[name] = new Code(functionString);
|
|
|
- }
|
|
|
-
|
|
|
- // Update parse index position
|
|
|
- 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);
|
|
|
-
|
|
|
- // 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
|
|
|
- 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
|
|
|
- functionString = buffer.toString('utf8', index, index + stringSize - 1);
|
|
|
- // Update parse index position
|
|
|
- index = index + stringSize;
|
|
|
- // Parse the element
|
|
|
- _index = index;
|
|
|
- // Decode the size of the object document
|
|
|
- objectSize =
|
|
|
- buffer[index] |
|
|
|
- (buffer[index + 1] << 8) |
|
|
|
- (buffer[index + 2] << 16) |
|
|
|
- (buffer[index + 3] << 24);
|
|
|
- // Decode the scope object
|
|
|
- var scopeObject = deserializeObject(buffer, _index, options, false);
|
|
|
- // Adjust the index
|
|
|
- index = index + objectSize;
|
|
|
-
|
|
|
- // 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');
|
|
|
- }
|
|
|
-
|
|
|
- // If we are evaluating the functions
|
|
|
- if (evalFunctions) {
|
|
|
- // If we have cache enabled let's look for the md5 of the function in the cache
|
|
|
- if (cacheFunctions) {
|
|
|
- hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
|
|
|
- // Got to do this to avoid V8 deoptimizing the call due to finding eval
|
|
|
- object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
|
|
|
- } else {
|
|
|
- object[name] = isolateEval(functionString);
|
|
|
- }
|
|
|
-
|
|
|
- object[name].scope = scopeObject;
|
|
|
- } else {
|
|
|
- object[name] = new Code(functionString, scopeObject);
|
|
|
- }
|
|
|
- } 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
|
|
|
- index = index + stringSize;
|
|
|
-
|
|
|
- // Read the oid
|
|
|
- var oidBuffer = utils.allocBuffer(12);
|
|
|
- buffer.copy(oidBuffer, 0, index, index + 12);
|
|
|
- oid = new ObjectID(oidBuffer);
|
|
|
-
|
|
|
- // 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);
|
|
|
- } else {
|
|
|
- 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 we have a db ref object
|
|
|
- if (object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
|
|
|
- return object;
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * Ensure eval is isolated.
|
|
|
- *
|
|
|
- * @ignore
|
|
|
- * @api private
|
|
|
- */
|
|
|
-var isolateEvalWithHash = function(functionCache, hash, functionString, object) {
|
|
|
- // Contains the value we are going to set
|
|
|
- var value = null;
|
|
|
-
|
|
|
- // Check for cache hit, eval if missing and return cached function
|
|
|
- if (functionCache[hash] == null) {
|
|
|
- eval('value = ' + functionString);
|
|
|
- functionCache[hash] = value;
|
|
|
- }
|
|
|
- // Set the object
|
|
|
- return functionCache[hash].bind(object);
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * Ensure eval is isolated.
|
|
|
- *
|
|
|
- * @ignore
|
|
|
- * @api private
|
|
|
- */
|
|
|
-var isolateEval = function(functionString) {
|
|
|
- // Contains the value we are going to set
|
|
|
- var value = null;
|
|
|
- // Eval the function
|
|
|
- eval('value = ' + functionString);
|
|
|
- return value;
|
|
|
-};
|
|
|
-
|
|
|
-var BSON = {};
|
|
|
-
|
|
|
-/**
|
|
|
- * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
|
|
|
- *
|
|
|
- * @ignore
|
|
|
- * @api private
|
|
|
- */
|
|
|
-var functionCache = (BSON.functionCache = {});
|
|
|
-
|
|
|
-/**
|
|
|
- * Number BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_NUMBER
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_NUMBER = 1;
|
|
|
-/**
|
|
|
- * String BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_STRING
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_STRING = 2;
|
|
|
-/**
|
|
|
- * Object BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_OBJECT
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_OBJECT = 3;
|
|
|
-/**
|
|
|
- * Array BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_ARRAY
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_ARRAY = 4;
|
|
|
-/**
|
|
|
- * Binary BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_BINARY
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_BINARY = 5;
|
|
|
-/**
|
|
|
- * Binary BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_UNDEFINED
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_UNDEFINED = 6;
|
|
|
-/**
|
|
|
- * ObjectID BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_OID
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_OID = 7;
|
|
|
-/**
|
|
|
- * Boolean BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_BOOLEAN
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_BOOLEAN = 8;
|
|
|
-/**
|
|
|
- * Date BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_DATE
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_DATE = 9;
|
|
|
-/**
|
|
|
- * null BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_NULL
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_NULL = 10;
|
|
|
-/**
|
|
|
- * RegExp BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_REGEXP
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_REGEXP = 11;
|
|
|
-/**
|
|
|
- * Code BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_DBPOINTER
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_DBPOINTER = 12;
|
|
|
-/**
|
|
|
- * Code BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_CODE
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_CODE = 13;
|
|
|
-/**
|
|
|
- * Symbol BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_SYMBOL
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_SYMBOL = 14;
|
|
|
-/**
|
|
|
- * Code with Scope BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_CODE_W_SCOPE
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_CODE_W_SCOPE = 15;
|
|
|
-/**
|
|
|
- * 32 bit Integer BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_INT
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_INT = 16;
|
|
|
-/**
|
|
|
- * Timestamp BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_TIMESTAMP
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_TIMESTAMP = 17;
|
|
|
-/**
|
|
|
- * Long BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_LONG
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_LONG = 18;
|
|
|
-/**
|
|
|
- * Long BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_DECIMAL128
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_DECIMAL128 = 19;
|
|
|
-/**
|
|
|
- * MinKey BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_MIN_KEY
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_MIN_KEY = 0xff;
|
|
|
-/**
|
|
|
- * MaxKey BSON Type
|
|
|
- *
|
|
|
- * @classconstant BSON_DATA_MAX_KEY
|
|
|
- **/
|
|
|
-BSON.BSON_DATA_MAX_KEY = 0x7f;
|
|
|
-
|
|
|
-/**
|
|
|
- * Binary Default Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
|
|
|
-/**
|
|
|
- * Binary Function Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
|
|
|
-/**
|
|
|
- * Binary Byte Array Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
|
|
|
-/**
|
|
|
- * Binary UUID Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_UUID
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_UUID = 3;
|
|
|
-/**
|
|
|
- * Binary MD5 Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_MD5
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
|
|
|
-/**
|
|
|
- * Binary User Defined Type
|
|
|
- *
|
|
|
- * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
|
|
|
- **/
|
|
|
-BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
|
|
|
-
|
|
|
-// BSON MAX VALUES
|
|
|
-BSON.BSON_INT32_MAX = 0x7fffffff;
|
|
|
-BSON.BSON_INT32_MIN = -0x80000000;
|
|
|
-
|
|
|
-BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
|
|
|
-BSON.BSON_INT64_MIN = -Math.pow(2, 63);
|
|
|
-
|
|
|
-// 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.
|
|
|
-
|
|
|
-// 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.
|
|
|
-
|
|
|
-module.exports = deserialize;
|