3 var writeIEEE754 = require('../float_parser').writeIEEE754,
4 readIEEE754 = require('../float_parser').readIEEE754,
5 f = require('util').format,
6 Long = require('../long').Long,
7 Double = require('../double').Double,
8 Timestamp = require('../timestamp').Timestamp,
9 ObjectID = require('../objectid').ObjectID,
10 Symbol = require('../symbol').Symbol,
11 Code = require('../code').Code,
12 MinKey = require('../min_key').MinKey,
13 MaxKey = require('../max_key').MaxKey,
14 DBRef = require('../db_ref').DBRef,
15 BSONRegExp = require('../regexp').BSONRegExp,
16 Binary = require('../binary').Binary;
21 * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
26 var functionCache = BSON.functionCache = {};
31 * @classconstant BSON_DATA_NUMBER
33 BSON.BSON_DATA_NUMBER = 1;
37 * @classconstant BSON_DATA_STRING
39 BSON.BSON_DATA_STRING = 2;
43 * @classconstant BSON_DATA_OBJECT
45 BSON.BSON_DATA_OBJECT = 3;
49 * @classconstant BSON_DATA_ARRAY
51 BSON.BSON_DATA_ARRAY = 4;
55 * @classconstant BSON_DATA_BINARY
57 BSON.BSON_DATA_BINARY = 5;
61 * @classconstant BSON_DATA_OID
63 BSON.BSON_DATA_OID = 7;
67 * @classconstant BSON_DATA_BOOLEAN
69 BSON.BSON_DATA_BOOLEAN = 8;
73 * @classconstant BSON_DATA_DATE
75 BSON.BSON_DATA_DATE = 9;
79 * @classconstant BSON_DATA_NULL
81 BSON.BSON_DATA_NULL = 10;
85 * @classconstant BSON_DATA_REGEXP
87 BSON.BSON_DATA_REGEXP = 11;
91 * @classconstant BSON_DATA_CODE
93 BSON.BSON_DATA_CODE = 13;
97 * @classconstant BSON_DATA_SYMBOL
99 BSON.BSON_DATA_SYMBOL = 14;
101 * Code with Scope BSON Type
103 * @classconstant BSON_DATA_CODE_W_SCOPE
105 BSON.BSON_DATA_CODE_W_SCOPE = 15;
107 * 32 bit Integer BSON Type
109 * @classconstant BSON_DATA_INT
111 BSON.BSON_DATA_INT = 16;
113 * Timestamp BSON Type
115 * @classconstant BSON_DATA_TIMESTAMP
117 BSON.BSON_DATA_TIMESTAMP = 17;
121 * @classconstant BSON_DATA_LONG
123 BSON.BSON_DATA_LONG = 18;
127 * @classconstant BSON_DATA_MIN_KEY
129 BSON.BSON_DATA_MIN_KEY = 0xff;
133 * @classconstant BSON_DATA_MAX_KEY
135 BSON.BSON_DATA_MAX_KEY = 0x7f;
138 * Binary Default Type
140 * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
142 BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
144 * Binary Function Type
146 * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
148 BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
150 * Binary Byte Array Type
152 * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
154 BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
158 * @classconstant BSON_BINARY_SUBTYPE_UUID
160 BSON.BSON_BINARY_SUBTYPE_UUID = 3;
164 * @classconstant BSON_BINARY_SUBTYPE_MD5
166 BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
168 * Binary User Defined Type
170 * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
172 BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
175 BSON.BSON_INT32_MAX = 0x7FFFFFFF;
176 BSON.BSON_INT32_MIN = -0x80000000;
178 BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
179 BSON.BSON_INT64_MIN = -Math.pow(2, 63);
181 // JS MAX PRECISE VALUES
182 BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double.
183 BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double.
185 // Internal long versions
186 var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double.
187 var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double.
189 var deserialize = function(buffer, options, isArray) {
191 // Read the document size
192 var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
194 // Ensure buffer is valid size
195 if(size < 5 || buffer.length < size) {
196 throw new Error("corrupt bson message");
200 if(buffer[size - 1] != 0) {
201 throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
204 // Start deserializtion
205 return deserializeObject(buffer, options, isArray);
208 // // Reads in a C style string
209 // var readCStyleStringSpecial = function(buffer, index) {
210 // // Get the start search index
212 // // Locate the end of the c string
213 // while(buffer[i] !== 0x00 && i < buffer.length) {
216 // // If are at the end of the buffer there is a problem with the document
217 // if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString")
218 // // Grab utf8 encoded string
219 // var string = buffer.toString('utf8', index, i);
220 // // Update index position
223 // return {s: string, i: index};
226 // Reads in a C style string
227 var readCStyleStringSpecial = function(buffer, index) {
228 // Get the start search index
230 // Locate the end of the c string
231 while(buffer[i] !== 0x00 && i < buffer.length) {
234 // If are at the end of the buffer there is a problem with the document
235 if(i >= buffer.length) throw new Error("Bad BSON Document: illegal CString")
236 // Grab utf8 encoded string
237 return buffer.toString('utf8', index, i);
240 var DeserializationMethods = {}
241 DeserializationMethods[BSON.BSON_DATA_OID] = function(name, object, buffer, index) {
242 var string = buffer.toString('binary', index, index + 12);
243 object[name] = new ObjectID(string);
247 DeserializationMethods[BSON.BSON_DATA_NUMBER] = function(name, object, buffer, index) {
248 object[name] = buffer.readDoubleLE(index);
252 DeserializationMethods[BSON.BSON_DATA_INT] = function(name, object, buffer, index) {
253 object[name] = buffer.readInt32LE(index);
257 DeserializationMethods[BSON.BSON_DATA_TIMESTAMP] = function(name, object, buffer, index) {
258 var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
259 var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
260 object[name] = new Timestamp(lowBits, highBits);
264 DeserializationMethods[BSON.BSON_DATA_STRING] = function(name, object, buffer, index) {
265 var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
266 if(stringSize <= 0 || stringSize > (buffer.length - index) || buffer[index + stringSize - 1] != 0) throw new Error("bad string length in bson");
267 object[name] = buffer.toString('utf8', index, index + stringSize - 1);
268 return index + stringSize;
271 DeserializationMethods[BSON.BSON_DATA_BOOLEAN] = function(name, object, buffer, index) {
272 object[name] = buffer[index++] == 1;
276 var deserializeObject = function(buffer, options, isArray) {
278 options = options == null ? {} : options;
279 var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
280 var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
281 var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
282 var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
283 var fieldsAsRaw = options['fieldsAsRaw'] == null ? {} : options['fieldsAsRaw'];
284 // Return BSONRegExp objects instead of native regular expressions
285 var bsonRegExp = typeof options['bsonRegExp'] == 'boolean' ? options['bsonRegExp'] : false;
286 var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
288 // Validate that we have at least 4 bytes of buffer
289 if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long");
292 var index = typeof options['index'] == 'number' ? options['index'] : 0;
294 // Read the document size
295 var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
297 // Ensure buffer is valid size
298 if(size < 5 || size > buffer.length) throw new Error("corrupt bson message");
300 // Create holding object
301 var object = isArray ? [] : {};
303 // While we have more left data left keep parsing
306 var elementType = buffer[index++];
307 // If we get a zero it's the last byte, exit
308 if(elementType == 0) break;
309 var name = readCStyleStringSpecial(buffer, index);
310 index = index + name.length + 1;
312 // console.log("----------- 0 " + elementType + " :: " + name)
313 index = DeserializationMethods[elementType](name, object, buffer, index);
314 // console.log('--------------- 1')
317 // Check if we have a db ref object
318 if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
320 // Return the final objects
325 * Ensure eval is isolated.
330 var isolateEvalWithHash = function(functionCache, hash, functionString, object) {
331 // Contains the value we are going to set
334 // Check for cache hit, eval if missing and return cached function
335 if(functionCache[hash] == null) {
336 eval("value = " + functionString);
337 functionCache[hash] = value;
340 return functionCache[hash].bind(object);
344 * Ensure eval is isolated.
349 var isolateEval = function(functionString) {
350 // Contains the value we are going to set
353 eval("value = " + functionString);
357 module.exports = deserialize