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