1b2f83f861c0a17771137f7ff299bc5ca7914e04
[aai/esr-gui.git] /
1 "use strict"
2
3 var writeIEEE754 = require('../float_parser').writeIEEE754,
4   readIEEE754 = require('../float_parser').readIEEE754,
5   Long = require('../long').Long,
6   Map = require('../map'),
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   BSONRegExp = require('../regexp').BSONRegExp,
13   Int32 = require('../int_32').Int32,
14   MinKey = require('../min_key').MinKey,
15   MaxKey = require('../max_key').MaxKey,
16   Decimal128 = require('../decimal128'),
17   DBRef = require('../db_ref').DBRef,
18   Binary = require('../binary').Binary;
19
20 try {
21   var _Buffer = Uint8Array;
22 } catch(e) {
23   var _Buffer = Buffer;
24 }
25
26 var regexp = /\x00/
27
28 // To ensure that 0.4 of node works correctly
29 var isDate = function isDate(d) {
30   return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]';
31 }
32
33 var isRegExp = function isRegExp(d) {
34   return Object.prototype.toString.call(d) === '[object RegExp]';
35 }
36
37 var serializeString = function(buffer, key, value, index, isArray) {
38   // Encode String type
39   buffer[index++] = BSON.BSON_DATA_STRING;
40   // Number of written bytes
41   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
42   // Encode the name
43   index = index + numberOfWrittenBytes + 1;
44   buffer[index - 1] = 0;
45   // Write the string
46   var size = buffer.write(value, index + 4, 'utf8');
47   // Write the size of the string to buffer
48   buffer[index + 3] = (size + 1 >> 24) & 0xff;
49   buffer[index + 2] = (size + 1 >> 16) & 0xff;
50   buffer[index + 1] = (size + 1 >> 8) & 0xff;
51   buffer[index] = size + 1 & 0xff;
52   // Update index
53   index = index + 4 + size;
54   // Write zero
55   buffer[index++] = 0;
56   return index;
57 }
58
59 var serializeNumber = function(buffer, key, value, index, isArray) {
60   // We have an integer value
61   if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
62     // If the value fits in 32 bits encode as int, if it fits in a double
63     // encode it as a double, otherwise long
64     if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) {
65       // Set int type 32 bits or less
66       buffer[index++] = BSON.BSON_DATA_INT;
67       // Number of written bytes
68       var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
69       // Encode the name
70       index = index + numberOfWrittenBytes;
71       buffer[index++] = 0;
72       // Write the int value
73       buffer[index++] = value & 0xff;
74       buffer[index++] = (value >> 8) & 0xff;
75       buffer[index++] = (value >> 16) & 0xff;
76       buffer[index++] = (value >> 24) & 0xff;
77     } else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
78       // Encode as double
79       buffer[index++] = BSON.BSON_DATA_NUMBER;
80       // Number of written bytes
81       var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
82       // Encode the name
83       index = index + numberOfWrittenBytes;
84       buffer[index++] = 0;
85       // Write float
86       writeIEEE754(buffer, value, index, 'little', 52, 8);
87       // Ajust index
88       index = index + 8;
89     } else {
90       // Set long type
91       buffer[index++] = BSON.BSON_DATA_LONG;
92       // Number of written bytes
93       var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
94       // Encode the name
95       index = index + numberOfWrittenBytes;
96       buffer[index++] = 0;
97       var longVal = Long.fromNumber(value);
98       var lowBits = longVal.getLowBits();
99       var highBits = longVal.getHighBits();
100       // Encode low bits
101       buffer[index++] = lowBits & 0xff;
102       buffer[index++] = (lowBits >> 8) & 0xff;
103       buffer[index++] = (lowBits >> 16) & 0xff;
104       buffer[index++] = (lowBits >> 24) & 0xff;
105       // Encode high bits
106       buffer[index++] = highBits & 0xff;
107       buffer[index++] = (highBits >> 8) & 0xff;
108       buffer[index++] = (highBits >> 16) & 0xff;
109       buffer[index++] = (highBits >> 24) & 0xff;
110     }
111   } else {
112     // Encode as double
113     buffer[index++] = BSON.BSON_DATA_NUMBER;
114     // Number of written bytes
115     var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
116     // Encode the name
117     index = index + numberOfWrittenBytes;
118     buffer[index++] = 0;
119     // Write float
120     writeIEEE754(buffer, value, index, 'little', 52, 8);
121     // Ajust index
122     index = index + 8;
123   }
124
125   return index;
126 }
127
128 var serializeUndefined = function(buffer, key, value, index, isArray) {
129   // Set long type
130   buffer[index++] = BSON.BSON_DATA_NULL;
131   // Number of written bytes
132   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
133   // Encode the name
134   index = index + numberOfWrittenBytes;
135   buffer[index++] = 0;
136   return index;
137 }
138
139 var serializeBoolean = function(buffer, key, value, index, isArray) {
140   // Write the type
141   buffer[index++] = BSON.BSON_DATA_BOOLEAN;
142   // Number of written bytes
143   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
144   // Encode the name
145   index = index + numberOfWrittenBytes;
146   buffer[index++] = 0;
147   // Encode the boolean value
148   buffer[index++] = value ? 1 : 0;
149   return index;
150 }
151
152 var serializeDate = function(buffer, key, value, index, isArray) {
153   // Write the type
154   buffer[index++] = BSON.BSON_DATA_DATE;
155   // Number of written bytes
156   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
157   // Encode the name
158   index = index + numberOfWrittenBytes;
159   buffer[index++] = 0;
160
161   // Write the date
162   var dateInMilis = Long.fromNumber(value.getTime());
163   var lowBits = dateInMilis.getLowBits();
164   var highBits = dateInMilis.getHighBits();
165   // Encode low bits
166   buffer[index++] = lowBits & 0xff;
167   buffer[index++] = (lowBits >> 8) & 0xff;
168   buffer[index++] = (lowBits >> 16) & 0xff;
169   buffer[index++] = (lowBits >> 24) & 0xff;
170   // Encode high bits
171   buffer[index++] = highBits & 0xff;
172   buffer[index++] = (highBits >> 8) & 0xff;
173   buffer[index++] = (highBits >> 16) & 0xff;
174   buffer[index++] = (highBits >> 24) & 0xff;
175   return index;
176 }
177
178 var serializeRegExp = function(buffer, key, value, index, isArray) {
179   // Write the type
180   buffer[index++] = BSON.BSON_DATA_REGEXP;
181   // Number of written bytes
182   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
183   // Encode the name
184   index = index + numberOfWrittenBytes;
185   buffer[index++] = 0;
186   if (value.source && value.source.match(regexp) != null) {
187     throw Error("value " + value.source + " must not contain null bytes");
188   }
189   // Adjust the index
190   index = index + buffer.write(value.source, index, 'utf8');
191   // Write zero
192   buffer[index++] = 0x00;
193   // Write the parameters
194   if(value.global) buffer[index++] = 0x73; // s
195   if(value.ignoreCase) buffer[index++] = 0x69; // i
196   if(value.multiline) buffer[index++] = 0x6d; // m
197   // Add ending zero
198   buffer[index++] = 0x00;
199   return index;
200 }
201
202 var serializeBSONRegExp = function(buffer, key, value, index, isArray) {
203   // Write the type
204   buffer[index++] = BSON.BSON_DATA_REGEXP;
205   // Number of written bytes
206   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
207   // Encode the name
208   index = index + numberOfWrittenBytes;
209   buffer[index++] = 0;
210   // Adjust the index
211   index = index + buffer.write(value.pattern, index, 'utf8');
212   // Write zero
213   buffer[index++] = 0x00;
214   // Write the options
215   index = index + buffer.write(value.options.split('').sort().join(''), index, 'utf8');
216   // Add ending zero
217   buffer[index++] = 0x00;
218   return index;
219 }
220
221 var serializeMinMax = function(buffer, key, value, index, isArray) {
222   // Write the type of either min or max key
223   if(value === null) {
224     buffer[index++] = BSON.BSON_DATA_NULL;
225   } else if(value instanceof MinKey) {
226     buffer[index++] = BSON.BSON_DATA_MIN_KEY;
227   } else {
228     buffer[index++] = BSON.BSON_DATA_MAX_KEY;
229   }
230
231   // Number of written bytes
232   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
233   // Encode the name
234   index = index + numberOfWrittenBytes;
235   buffer[index++] = 0;
236   return index;
237 }
238
239 var serializeObjectId = function(buffer, key, value, index, isArray) {
240   // Write the type
241   buffer[index++] = BSON.BSON_DATA_OID;
242   // Number of written bytes
243   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
244
245   // Encode the name
246   index = index + numberOfWrittenBytes;
247   buffer[index++] = 0;
248
249   // Write the objectId into the shared buffer
250   if(typeof value.id == 'string') {
251     buffer.write(value.id, index, 'binary')
252   } else if(value.id && value.id.copy){
253     value.id.copy(buffer, index, 0, 12);
254   } else {
255     throw new Error('object [' + JSON.stringify(value) + "] is not a valid ObjectId");
256   }
257
258   // Ajust index
259   return index + 12;
260 }
261
262 var serializeBuffer = function(buffer, key, value, index, isArray) {
263   // Write the type
264   buffer[index++] = BSON.BSON_DATA_BINARY;
265   // Number of written bytes
266   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
267   // Encode the name
268   index = index + numberOfWrittenBytes;
269   buffer[index++] = 0;
270   // Get size of the buffer (current write point)
271   var size = value.length;
272   // Write the size of the string to buffer
273   buffer[index++] = size & 0xff;
274   buffer[index++] = (size >> 8) & 0xff;
275   buffer[index++] = (size >> 16) & 0xff;
276   buffer[index++] = (size >> 24) & 0xff;
277   // Write the default subtype
278   buffer[index++] = BSON.BSON_BINARY_SUBTYPE_DEFAULT;
279   // Copy the content form the binary field to the buffer
280   value.copy(buffer, index, 0, size);
281   // Adjust the index
282   index = index + size;
283   return index;
284 }
285
286 var serializeObject = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray, path) {
287   for(var i = 0; i < path.length; i++) {
288     if(path[i] === value) throw new Error('cyclic dependency detected');
289   }
290
291   // Push value to stack
292   path.push(value);
293   // Write the type
294   buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT;
295   // Number of written bytes
296   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
297   // Encode the name
298   index = index + numberOfWrittenBytes;
299   buffer[index++] = 0;
300   var endIndex = serializeInto(buffer, value, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
301   // Pop stack
302   path.pop();
303   // Write size
304   var size = endIndex - index;
305   return endIndex;
306 }
307
308 var serializeDecimal128 = function(buffer, key, value, index, isArray) {
309   buffer[index++] = BSON.BSON_DATA_DECIMAL128;
310   // Number of written bytes
311   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
312   // Encode the name
313   index = index + numberOfWrittenBytes;
314   buffer[index++] = 0;
315   // Write the data from the value
316   value.bytes.copy(buffer, index, 0, 16);
317   return index + 16;
318 }
319
320 var serializeLong = function(buffer, key, value, index, isArray) {
321   // Write the type
322   buffer[index++] = value._bsontype == 'Long' ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP;
323   // Number of written bytes
324   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
325   // Encode the name
326   index = index + numberOfWrittenBytes;
327   buffer[index++] = 0;
328   // Write the date
329   var lowBits = value.getLowBits();
330   var highBits = value.getHighBits();
331   // Encode low bits
332   buffer[index++] = lowBits & 0xff;
333   buffer[index++] = (lowBits >> 8) & 0xff;
334   buffer[index++] = (lowBits >> 16) & 0xff;
335   buffer[index++] = (lowBits >> 24) & 0xff;
336   // Encode high bits
337   buffer[index++] = highBits & 0xff;
338   buffer[index++] = (highBits >> 8) & 0xff;
339   buffer[index++] = (highBits >> 16) & 0xff;
340   buffer[index++] = (highBits >> 24) & 0xff;
341   return index;
342 }
343
344 var serializeInt32 = function(buffer, key, value, index, isArray) {
345   // Set int type 32 bits or less
346   buffer[index++] = BSON.BSON_DATA_INT;
347   // Number of written bytes
348   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
349   // Encode the name
350   index = index + numberOfWrittenBytes;
351   buffer[index++] = 0;
352   // Write the int value
353   buffer[index++] = value & 0xff;
354   buffer[index++] = (value >> 8) & 0xff;
355   buffer[index++] = (value >> 16) & 0xff;
356   buffer[index++] = (value >> 24) & 0xff;
357   return index;
358 }
359
360 var serializeDouble = function(buffer, key, value, index, isArray) {
361   // Encode as double
362   buffer[index++] = BSON.BSON_DATA_NUMBER;
363   // Number of written bytes
364   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
365   // Encode the name
366   index = index + numberOfWrittenBytes;
367   buffer[index++] = 0;
368   // Write float
369   writeIEEE754(buffer, value, index, 'little', 52, 8);
370   // Ajust index
371   index = index + 8;
372   return index;
373 }
374
375 var serializeFunction = function(buffer, key, value, index, checkKeys, depth, isArray) {
376   buffer[index++] = BSON.BSON_DATA_CODE;
377   // Number of written bytes
378   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
379   // Encode the name
380   index = index + numberOfWrittenBytes;
381   buffer[index++] = 0;
382   // Function string
383   var functionString = value.toString();
384   // Write the string
385   var size = buffer.write(functionString, index + 4, 'utf8') + 1;
386   // Write the size of the string to buffer
387   buffer[index] = size & 0xff;
388   buffer[index + 1] = (size >> 8) & 0xff;
389   buffer[index + 2] = (size >> 16) & 0xff;
390   buffer[index + 3] = (size >> 24) & 0xff;
391   // Update index
392   index = index + 4 + size - 1;
393   // Write zero
394   buffer[index++] = 0;
395   return index;
396 }
397
398 var serializeCode = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray) {
399   if(value.scope && typeof value.scope == 'object') {
400     // Write the type
401     buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE;
402     // Number of written bytes
403     var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
404     // Encode the name
405     index = index + numberOfWrittenBytes;
406     buffer[index++] = 0;
407
408     // Starting index
409     var startIndex = index;
410
411     // Serialize the function
412     // Get the function string
413     var functionString = typeof value.code == 'string' ? value.code : value.code.toString();
414     // Index adjustment
415     index = index + 4;
416     // Write string into buffer
417     var codeSize = buffer.write(functionString, index + 4, 'utf8') + 1;
418     // Write the size of the string to buffer
419     buffer[index] = codeSize & 0xff;
420     buffer[index + 1] = (codeSize >> 8) & 0xff;
421     buffer[index + 2] = (codeSize >> 16) & 0xff;
422     buffer[index + 3] = (codeSize >> 24) & 0xff;
423     // Write end 0
424     buffer[index + 4 + codeSize - 1] = 0;
425     // Write the
426     index = index + codeSize + 4;
427
428     //
429     // Serialize the scope value
430     var endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined)
431     index = endIndex - 1;
432
433     // Writ the total
434     var totalSize = endIndex - startIndex;
435
436     // Write the total size of the object
437     buffer[startIndex++] = totalSize & 0xff;
438     buffer[startIndex++] = (totalSize >> 8) & 0xff;
439     buffer[startIndex++] = (totalSize >> 16) & 0xff;
440     buffer[startIndex++] = (totalSize >> 24) & 0xff;
441     // Write trailing zero
442     buffer[index++] = 0;
443   } else {
444     buffer[index++] = BSON.BSON_DATA_CODE;
445     // Number of written bytes
446     var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
447     // Encode the name
448     index = index + numberOfWrittenBytes;
449     buffer[index++] = 0;
450     // Function string
451     var functionString = value.code.toString();
452     // Write the string
453     var size = buffer.write(functionString, index + 4, 'utf8') + 1;
454     // Write the size of the string to buffer
455     buffer[index] = size & 0xff;
456     buffer[index + 1] = (size >> 8) & 0xff;
457     buffer[index + 2] = (size >> 16) & 0xff;
458     buffer[index + 3] = (size >> 24) & 0xff;
459     // Update index
460     index = index + 4 + size - 1;
461     // Write zero
462     buffer[index++] = 0;
463   }
464
465   return index;
466 }
467
468 var serializeBinary = function(buffer, key, value, index, isArray) {
469   // Write the type
470   buffer[index++] = BSON.BSON_DATA_BINARY;
471   // Number of written bytes
472   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
473   // Encode the name
474   index = index + numberOfWrittenBytes;
475   buffer[index++] = 0;
476   // Extract the buffer
477   var data = value.value(true);
478   // Calculate size
479   var size = value.position;
480   // Add the deprecated 02 type 4 bytes of size to total
481   if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) size = size + 4;
482   // Write the size of the string to buffer
483   buffer[index++] = size & 0xff;
484   buffer[index++] = (size >> 8) & 0xff;
485   buffer[index++] = (size >> 16) & 0xff;
486   buffer[index++] = (size >> 24) & 0xff;
487   // Write the subtype to the buffer
488   buffer[index++] = value.sub_type;
489
490   // If we have binary type 2 the 4 first bytes are the size
491   if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) {
492     size = size - 4;
493     buffer[index++] = size & 0xff;
494     buffer[index++] = (size >> 8) & 0xff;
495     buffer[index++] = (size >> 16) & 0xff;
496     buffer[index++] = (size >> 24) & 0xff;
497   }
498
499   // Write the data to the object
500   data.copy(buffer, index, 0, value.position);
501   // Adjust the index
502   index = index + value.position;
503   return index;
504 }
505
506 var serializeSymbol = function(buffer, key, value, index, isArray) {
507   // Write the type
508   buffer[index++] = BSON.BSON_DATA_SYMBOL;
509   // Number of written bytes
510   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
511   // Encode the name
512   index = index + numberOfWrittenBytes;
513   buffer[index++] = 0;
514   // Write the string
515   var size = buffer.write(value.value, index + 4, 'utf8') + 1;
516   // Write the size of the string to buffer
517   buffer[index] = size & 0xff;
518   buffer[index + 1] = (size >> 8) & 0xff;
519   buffer[index + 2] = (size >> 16) & 0xff;
520   buffer[index + 3] = (size >> 24) & 0xff;
521   // Update index
522   index = index + 4 + size - 1;
523   // Write zero
524   buffer[index++] = 0x00;
525   return index;
526 }
527
528 var serializeDBRef = function(buffer, key, value, index, depth, serializeFunctions, isArray) {
529   // Write the type
530   buffer[index++] = BSON.BSON_DATA_OBJECT;
531   // Number of written bytes
532   var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
533
534   // Encode the name
535   index = index + numberOfWrittenBytes;
536   buffer[index++] = 0;
537
538   var startIndex = index;
539   var endIndex;
540
541   // Serialize object
542   if(null != value.db) {
543     endIndex = serializeInto(buffer, {
544         '$ref': value.namespace
545       , '$id' : value.oid
546       , '$db' : value.db
547     }, false, index, depth + 1, serializeFunctions);
548   } else {
549     endIndex = serializeInto(buffer, {
550         '$ref': value.namespace
551       , '$id' : value.oid
552     }, false, index, depth + 1, serializeFunctions);
553   }
554
555   // Calculate object size
556   var size = endIndex - startIndex;
557   // Write the size
558   buffer[startIndex++] = size & 0xff;
559   buffer[startIndex++] = (size >> 8) & 0xff;
560   buffer[startIndex++] = (size >> 16) & 0xff;
561   buffer[startIndex++] = (size >> 24) & 0xff;
562   // Set index
563   return endIndex;
564 }
565
566 var serializeInto = function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) {
567   startingIndex = startingIndex || 0;
568   path = path || [];
569
570   // Push the object to the path
571   path.push(object);
572
573   // Start place to serialize into
574   var index = startingIndex + 4;
575   var self = this;
576
577   // Special case isArray
578   if(Array.isArray(object)) {
579     // Get object keys
580     for(var i = 0; i < object.length; i++) {
581       var key = "" + i;
582       var value = object[i];
583
584       // Is there an override value
585       if(value && value.toBSON) {
586         if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function");
587         value = value.toBSON();
588       }
589
590       var type = typeof value;
591       if(type == 'string') {
592         index = serializeString(buffer, key, value, index, true);
593       } else if(type == 'number') {
594         index = serializeNumber(buffer, key, value, index, true);
595       } else if(type == 'boolean') {
596         index = serializeBoolean(buffer, key, value, index, true);
597       } else if(value instanceof Date || isDate(value)) {
598         index = serializeDate(buffer, key, value, index, true);
599       } else if(type == 'undefined' || value == null) {
600         index = serializeUndefined(buffer, key, value, index, true);
601       } else if(value['_bsontype'] == 'ObjectID') {
602         index = serializeObjectId(buffer, key, value, index, true);
603       } else if(Buffer.isBuffer(value)) {
604         index = serializeBuffer(buffer, key, value, index, true);
605       } else if(value instanceof RegExp || isRegExp(value)) {
606         index = serializeRegExp(buffer, key, value, index, true);
607       } else if(type == 'object' && value['_bsontype'] == null) {
608         index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true, path);
609       } else if(type == 'object' && value['_bsontype'] == 'Decimal128') {
610         index = serializeDecimal128(buffer, key, value, index, true);
611       } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') {
612         index = serializeLong(buffer, key, value, index, true);
613       } else if(value['_bsontype'] == 'Double') {
614         index = serializeDouble(buffer, key, value, index, true);
615       } else if(typeof value == 'function' && serializeFunctions) {
616         index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions, true);
617       } else if(value['_bsontype'] == 'Code') {
618         index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, true);
619       } else if(value['_bsontype'] == 'Binary') {
620         index = serializeBinary(buffer, key, value, index, true);
621       } else if(value['_bsontype'] == 'Symbol') {
622         index = serializeSymbol(buffer, key, value, index, true);
623       } else if(value['_bsontype'] == 'DBRef') {
624         index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true);
625       } else if(value['_bsontype'] == 'BSONRegExp') {
626         index = serializeBSONRegExp(buffer, key, value, index, true);
627       } else if(value['_bsontype'] == 'Int32') {
628         index = serializeInt32(buffer, key, value, index, true);
629       } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') {
630         index = serializeMinMax(buffer, key, value, index, true);
631       }
632     }
633   } else if(object instanceof Map) {
634     var iterator = object.entries();
635     var done = false;
636
637     while(!done) {
638       // Unpack the next entry
639       var entry = iterator.next();
640       done = entry.done;
641       // Are we done, then skip and terminate
642       if(done) continue;
643
644       // Get the entry values
645       var key = entry.value[0];
646       var value = entry.value[1];
647
648       // Check the type of the value
649       var type = typeof value;
650
651       // Check the key and throw error if it's illegal
652       if(key != '$db' && key != '$ref' && key != '$id') {
653         if (key.match(regexp) != null) {
654           // The BSON spec doesn't allow keys with null bytes because keys are
655           // null-terminated.
656           throw Error("key " + key + " must not contain null bytes");
657         }
658
659         if (checkKeys) {
660           if('$' == key[0]) {
661             throw Error("key " + key + " must not start with '$'");
662           } else if (!!~key.indexOf('.')) {
663             throw Error("key " + key + " must not contain '.'");
664           }
665         }
666       }
667
668       if(type == 'string') {
669         index = serializeString(buffer, key, value, index);
670       } else if(type == 'number') {
671         index = serializeNumber(buffer, key, value, index);
672       } else if(type == 'boolean') {
673         index = serializeBoolean(buffer, key, value, index);
674       } else if(value instanceof Date || isDate(value)) {
675         index = serializeDate(buffer, key, value, index);
676       } else if(value === undefined && ignoreUndefined == true) {
677       } else if(value === null || value === undefined) {
678         index = serializeUndefined(buffer, key, value, index);
679       } else if(value['_bsontype'] == 'ObjectID') {
680         index = serializeObjectId(buffer, key, value, index);
681       } else if(Buffer.isBuffer(value)) {
682         index = serializeBuffer(buffer, key, value, index);
683       } else if(value instanceof RegExp || isRegExp(value)) {
684         index = serializeRegExp(buffer, key, value, index);
685       } else if(type == 'object' && value['_bsontype'] == null) {
686         index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path);
687       } else if(type == 'object' && value['_bsontype'] == 'Decimal128') {
688         index = serializeDecimal128(buffer, key, value, index);
689       } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') {
690         index = serializeLong(buffer, key, value, index);
691       } else if(value['_bsontype'] == 'Double') {
692         index = serializeDouble(buffer, key, value, index);
693       } else if(value['_bsontype'] == 'Code') {
694         index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined);
695       } else if(typeof value == 'function' && serializeFunctions) {
696         index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
697       } else if(value['_bsontype'] == 'Binary') {
698         index = serializeBinary(buffer, key, value, index);
699       } else if(value['_bsontype'] == 'Symbol') {
700         index = serializeSymbol(buffer, key, value, index);
701       } else if(value['_bsontype'] == 'DBRef') {
702         index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
703       } else if(value['_bsontype'] == 'BSONRegExp') {
704         index = serializeBSONRegExp(buffer, key, value, index);
705       } else if(value['_bsontype'] == 'Int32') {
706         index = serializeInt32(buffer, key, value, index);
707       } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') {
708         index = serializeMinMax(buffer, key, value, index);
709       }
710     }
711   } else {
712     // Did we provide a custom serialization method
713     if(object.toBSON) {
714       if(typeof object.toBSON != 'function') throw new Error("toBSON is not a function");
715       object = object.toBSON();
716       if(object != null && typeof object != 'object') throw new Error("toBSON function did not return an object");
717     }
718
719     // Iterate over all the keys
720     for(var key in object) {
721       var value = object[key];
722       // Is there an override value
723       if(value && value.toBSON) {
724         if(typeof value.toBSON != 'function') throw new Error("toBSON is not a function");
725         value = value.toBSON();
726       }
727
728       // Check the type of the value
729       var type = typeof value;
730
731       // Check the key and throw error if it's illegal
732       if(key != '$db' && key != '$ref' && key != '$id') {
733         if (key.match(regexp) != null) {
734           // The BSON spec doesn't allow keys with null bytes because keys are
735           // null-terminated.
736           throw Error("key " + key + " must not contain null bytes");
737         }
738
739         if (checkKeys) {
740           if('$' == key[0]) {
741             throw Error("key " + key + " must not start with '$'");
742           } else if (!!~key.indexOf('.')) {
743             throw Error("key " + key + " must not contain '.'");
744           }
745         }
746       }
747
748       if(type == 'string') {
749         index = serializeString(buffer, key, value, index);
750       } else if(type == 'number') {
751         index = serializeNumber(buffer, key, value, index);
752       } else if(type == 'boolean') {
753         index = serializeBoolean(buffer, key, value, index);
754       } else if(value instanceof Date || isDate(value)) {
755         index = serializeDate(buffer, key, value, index);
756       } else if(value === undefined && ignoreUndefined == true) {
757       } else if(value === null || value === undefined) {
758         index = serializeUndefined(buffer, key, value, index);
759       } else if(value['_bsontype'] == 'ObjectID') {
760         index = serializeObjectId(buffer, key, value, index);
761       } else if(Buffer.isBuffer(value)) {
762         index = serializeBuffer(buffer, key, value, index);
763       } else if(value instanceof RegExp || isRegExp(value)) {
764         index = serializeRegExp(buffer, key, value, index);
765       } else if(type == 'object' && value['_bsontype'] == null) {
766         index = serializeObject(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, false, path);
767       } else if(type == 'object' && value['_bsontype'] == 'Decimal128') {
768         index = serializeDecimal128(buffer, key, value, index);
769       } else if(value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') {
770         index = serializeLong(buffer, key, value, index);
771       } else if(value['_bsontype'] == 'Double') {
772         index = serializeDouble(buffer, key, value, index);
773       } else if(value['_bsontype'] == 'Code') {
774         index = serializeCode(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined);
775       } else if(typeof value == 'function' && serializeFunctions) {
776         index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
777       } else if(value['_bsontype'] == 'Binary') {
778         index = serializeBinary(buffer, key, value, index);
779       } else if(value['_bsontype'] == 'Symbol') {
780         index = serializeSymbol(buffer, key, value, index);
781       } else if(value['_bsontype'] == 'DBRef') {
782         index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
783       } else if(value['_bsontype'] == 'BSONRegExp') {
784         index = serializeBSONRegExp(buffer, key, value, index);
785       } else if(value['_bsontype'] == 'Int32') {
786         index = serializeInt32(buffer, key, value, index);
787       } else if(value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') {
788         index = serializeMinMax(buffer, key, value, index);
789       }
790     }
791   }
792
793   // Remove the path
794   path.pop();
795
796   // Final padding byte for object
797   buffer[index++] = 0x00;
798
799   // Final size
800   var size = index - startingIndex;
801   // Write the size of the object
802   buffer[startingIndex++] = size & 0xff;
803   buffer[startingIndex++] = (size >> 8) & 0xff;
804   buffer[startingIndex++] = (size >> 16) & 0xff;
805   buffer[startingIndex++] = (size >> 24) & 0xff;
806   return index;
807 }
808
809 var BSON = {};
810
811 /**
812  * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
813  *
814  * @ignore
815  * @api private
816  */
817 var functionCache = BSON.functionCache = {};
818
819 /**
820  * Number BSON Type
821  *
822  * @classconstant BSON_DATA_NUMBER
823  **/
824 BSON.BSON_DATA_NUMBER = 1;
825 /**
826  * String BSON Type
827  *
828  * @classconstant BSON_DATA_STRING
829  **/
830 BSON.BSON_DATA_STRING = 2;
831 /**
832  * Object BSON Type
833  *
834  * @classconstant BSON_DATA_OBJECT
835  **/
836 BSON.BSON_DATA_OBJECT = 3;
837 /**
838  * Array BSON Type
839  *
840  * @classconstant BSON_DATA_ARRAY
841  **/
842 BSON.BSON_DATA_ARRAY = 4;
843 /**
844  * Binary BSON Type
845  *
846  * @classconstant BSON_DATA_BINARY
847  **/
848 BSON.BSON_DATA_BINARY = 5;
849 /**
850  * ObjectID BSON Type, deprecated
851  *
852  * @classconstant BSON_DATA_UNDEFINED
853  **/
854 BSON.BSON_DATA_UNDEFINED = 6;
855 /**
856  * ObjectID BSON Type
857  *
858  * @classconstant BSON_DATA_OID
859  **/
860 BSON.BSON_DATA_OID = 7;
861 /**
862  * Boolean BSON Type
863  *
864  * @classconstant BSON_DATA_BOOLEAN
865  **/
866 BSON.BSON_DATA_BOOLEAN = 8;
867 /**
868  * Date BSON Type
869  *
870  * @classconstant BSON_DATA_DATE
871  **/
872 BSON.BSON_DATA_DATE = 9;
873 /**
874  * null BSON Type
875  *
876  * @classconstant BSON_DATA_NULL
877  **/
878 BSON.BSON_DATA_NULL = 10;
879 /**
880  * RegExp BSON Type
881  *
882  * @classconstant BSON_DATA_REGEXP
883  **/
884 BSON.BSON_DATA_REGEXP = 11;
885 /**
886  * Code BSON Type
887  *
888  * @classconstant BSON_DATA_CODE
889  **/
890 BSON.BSON_DATA_CODE = 13;
891 /**
892  * Symbol BSON Type
893  *
894  * @classconstant BSON_DATA_SYMBOL
895  **/
896 BSON.BSON_DATA_SYMBOL = 14;
897 /**
898  * Code with Scope BSON Type
899  *
900  * @classconstant BSON_DATA_CODE_W_SCOPE
901  **/
902 BSON.BSON_DATA_CODE_W_SCOPE = 15;
903 /**
904  * 32 bit Integer BSON Type
905  *
906  * @classconstant BSON_DATA_INT
907  **/
908 BSON.BSON_DATA_INT = 16;
909 /**
910  * Timestamp BSON Type
911  *
912  * @classconstant BSON_DATA_TIMESTAMP
913  **/
914 BSON.BSON_DATA_TIMESTAMP = 17;
915 /**
916  * Long BSON Type
917  *
918  * @classconstant BSON_DATA_LONG
919  **/
920 BSON.BSON_DATA_LONG = 18;
921 /**
922  * Long BSON Type
923  *
924  * @classconstant BSON_DATA_DECIMAL128
925  **/
926 BSON.BSON_DATA_DECIMAL128 = 19;
927 /**
928  * MinKey BSON Type
929  *
930  * @classconstant BSON_DATA_MIN_KEY
931  **/
932 BSON.BSON_DATA_MIN_KEY = 0xff;
933 /**
934  * MaxKey BSON Type
935  *
936  * @classconstant BSON_DATA_MAX_KEY
937  **/
938 BSON.BSON_DATA_MAX_KEY = 0x7f;
939 /**
940  * Binary Default Type
941  *
942  * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
943  **/
944 BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
945 /**
946  * Binary Function Type
947  *
948  * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
949  **/
950 BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
951 /**
952  * Binary Byte Array Type
953  *
954  * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
955  **/
956 BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
957 /**
958  * Binary UUID Type
959  *
960  * @classconstant BSON_BINARY_SUBTYPE_UUID
961  **/
962 BSON.BSON_BINARY_SUBTYPE_UUID = 3;
963 /**
964  * Binary MD5 Type
965  *
966  * @classconstant BSON_BINARY_SUBTYPE_MD5
967  **/
968 BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
969 /**
970  * Binary User Defined Type
971  *
972  * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
973  **/
974 BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
975
976 // BSON MAX VALUES
977 BSON.BSON_INT32_MAX = 0x7FFFFFFF;
978 BSON.BSON_INT32_MIN = -0x80000000;
979
980 BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
981 BSON.BSON_INT64_MIN = -Math.pow(2, 63);
982
983 // JS MAX PRECISE VALUES
984 BSON.JS_INT_MAX = 0x20000000000000;  // Any integer up to 2^53 can be precisely represented by a double.
985 BSON.JS_INT_MIN = -0x20000000000000;  // Any integer down to -2^53 can be precisely represented by a double.
986
987 // Internal long versions
988 var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000);  // Any integer up to 2^53 can be precisely represented by a double.
989 var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000);  // Any integer down to -2^53 can be precisely represented by a double.
990
991 module.exports = serializeInto;