You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							782 lines
						
					
					
						
							24 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							782 lines
						
					
					
						
							24 KiB
						
					
					
				| '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;
 | |
| 
 |