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;
21 var _Buffer = Uint8Array;
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]';
33 var isRegExp = function isRegExp(d) {
34 return Object.prototype.toString.call(d) === '[object RegExp]';
37 var serializeString = function(buffer, key, value, index, isArray) {
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');
43 index = index + numberOfWrittenBytes + 1;
44 buffer[index - 1] = 0;
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;
53 index = index + 4 + size;
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');
70 index = index + numberOfWrittenBytes;
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) {
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');
83 index = index + numberOfWrittenBytes;
86 writeIEEE754(buffer, value, index, 'little', 52, 8);
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');
95 index = index + numberOfWrittenBytes;
97 var longVal = Long.fromNumber(value);
98 var lowBits = longVal.getLowBits();
99 var highBits = longVal.getHighBits();
101 buffer[index++] = lowBits & 0xff;
102 buffer[index++] = (lowBits >> 8) & 0xff;
103 buffer[index++] = (lowBits >> 16) & 0xff;
104 buffer[index++] = (lowBits >> 24) & 0xff;
106 buffer[index++] = highBits & 0xff;
107 buffer[index++] = (highBits >> 8) & 0xff;
108 buffer[index++] = (highBits >> 16) & 0xff;
109 buffer[index++] = (highBits >> 24) & 0xff;
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');
117 index = index + numberOfWrittenBytes;
120 writeIEEE754(buffer, value, index, 'little', 52, 8);
128 var serializeUndefined = function(buffer, key, value, index, isArray) {
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');
134 index = index + numberOfWrittenBytes;
139 var serializeBoolean = function(buffer, key, value, index, isArray) {
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');
145 index = index + numberOfWrittenBytes;
147 // Encode the boolean value
148 buffer[index++] = value ? 1 : 0;
152 var serializeDate = function(buffer, key, value, index, isArray) {
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');
158 index = index + numberOfWrittenBytes;
162 var dateInMilis = Long.fromNumber(value.getTime());
163 var lowBits = dateInMilis.getLowBits();
164 var highBits = dateInMilis.getHighBits();
166 buffer[index++] = lowBits & 0xff;
167 buffer[index++] = (lowBits >> 8) & 0xff;
168 buffer[index++] = (lowBits >> 16) & 0xff;
169 buffer[index++] = (lowBits >> 24) & 0xff;
171 buffer[index++] = highBits & 0xff;
172 buffer[index++] = (highBits >> 8) & 0xff;
173 buffer[index++] = (highBits >> 16) & 0xff;
174 buffer[index++] = (highBits >> 24) & 0xff;
178 var serializeRegExp = function(buffer, key, value, index, isArray) {
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');
184 index = index + numberOfWrittenBytes;
186 if (value.source && value.source.match(regexp) != null) {
187 throw Error("value " + value.source + " must not contain null bytes");
190 index = index + buffer.write(value.source, index, 'utf8');
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
198 buffer[index++] = 0x00;
202 var serializeBSONRegExp = function(buffer, key, value, index, isArray) {
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');
208 index = index + numberOfWrittenBytes;
211 index = index + buffer.write(value.pattern, index, 'utf8');
213 buffer[index++] = 0x00;
215 index = index + buffer.write(value.options.split('').sort().join(''), index, 'utf8');
217 buffer[index++] = 0x00;
221 var serializeMinMax = function(buffer, key, value, index, isArray) {
222 // Write the type of either min or max key
224 buffer[index++] = BSON.BSON_DATA_NULL;
225 } else if(value instanceof MinKey) {
226 buffer[index++] = BSON.BSON_DATA_MIN_KEY;
228 buffer[index++] = BSON.BSON_DATA_MAX_KEY;
231 // Number of written bytes
232 var numberOfWrittenBytes = !isArray ? buffer.write(key, index, 'utf8') : buffer.write(key, index, 'ascii');
234 index = index + numberOfWrittenBytes;
239 var serializeObjectId = function(buffer, key, value, index, isArray) {
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');
246 index = index + numberOfWrittenBytes;
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);
255 throw new Error('object [' + JSON.stringify(value) + "] is not a valid ObjectId");
262 var serializeBuffer = function(buffer, key, value, index, isArray) {
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');
268 index = index + numberOfWrittenBytes;
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);
282 index = index + size;
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');
291 // Push value to stack
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');
298 index = index + numberOfWrittenBytes;
300 var endIndex = serializeInto(buffer, value, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
304 var size = endIndex - index;
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');
313 index = index + numberOfWrittenBytes;
315 // Write the data from the value
316 value.bytes.copy(buffer, index, 0, 16);
320 var serializeLong = function(buffer, key, value, index, isArray) {
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');
326 index = index + numberOfWrittenBytes;
329 var lowBits = value.getLowBits();
330 var highBits = value.getHighBits();
332 buffer[index++] = lowBits & 0xff;
333 buffer[index++] = (lowBits >> 8) & 0xff;
334 buffer[index++] = (lowBits >> 16) & 0xff;
335 buffer[index++] = (lowBits >> 24) & 0xff;
337 buffer[index++] = highBits & 0xff;
338 buffer[index++] = (highBits >> 8) & 0xff;
339 buffer[index++] = (highBits >> 16) & 0xff;
340 buffer[index++] = (highBits >> 24) & 0xff;
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');
350 index = index + numberOfWrittenBytes;
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;
360 var serializeDouble = function(buffer, key, value, index, isArray) {
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');
366 index = index + numberOfWrittenBytes;
369 writeIEEE754(buffer, value, index, 'little', 52, 8);
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');
380 index = index + numberOfWrittenBytes;
383 var functionString = value.toString();
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;
392 index = index + 4 + size - 1;
398 var serializeCode = function(buffer, key, value, index, checkKeys, depth, serializeFunctions, ignoreUndefined, isArray) {
399 if(value.scope && typeof value.scope == 'object') {
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');
405 index = index + numberOfWrittenBytes;
409 var startIndex = index;
411 // Serialize the function
412 // Get the function string
413 var functionString = typeof value.code == 'string' ? value.code : value.code.toString();
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;
424 buffer[index + 4 + codeSize - 1] = 0;
426 index = index + codeSize + 4;
429 // Serialize the scope value
430 var endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined)
431 index = endIndex - 1;
434 var totalSize = endIndex - startIndex;
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
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');
448 index = index + numberOfWrittenBytes;
451 var functionString = value.code.toString();
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;
460 index = index + 4 + size - 1;
468 var serializeBinary = function(buffer, key, value, index, isArray) {
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');
474 index = index + numberOfWrittenBytes;
476 // Extract the buffer
477 var data = value.value(true);
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;
490 // If we have binary type 2 the 4 first bytes are the size
491 if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) {
493 buffer[index++] = size & 0xff;
494 buffer[index++] = (size >> 8) & 0xff;
495 buffer[index++] = (size >> 16) & 0xff;
496 buffer[index++] = (size >> 24) & 0xff;
499 // Write the data to the object
500 data.copy(buffer, index, 0, value.position);
502 index = index + value.position;
506 var serializeSymbol = function(buffer, key, value, index, isArray) {
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');
512 index = index + numberOfWrittenBytes;
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;
522 index = index + 4 + size - 1;
524 buffer[index++] = 0x00;
528 var serializeDBRef = function(buffer, key, value, index, depth, serializeFunctions, isArray) {
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');
535 index = index + numberOfWrittenBytes;
538 var startIndex = index;
542 if(null != value.db) {
543 endIndex = serializeInto(buffer, {
544 '$ref': value.namespace
547 }, false, index, depth + 1, serializeFunctions);
549 endIndex = serializeInto(buffer, {
550 '$ref': value.namespace
552 }, false, index, depth + 1, serializeFunctions);
555 // Calculate object size
556 var size = endIndex - startIndex;
558 buffer[startIndex++] = size & 0xff;
559 buffer[startIndex++] = (size >> 8) & 0xff;
560 buffer[startIndex++] = (size >> 16) & 0xff;
561 buffer[startIndex++] = (size >> 24) & 0xff;
566 var serializeInto = function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) {
567 startingIndex = startingIndex || 0;
570 // Push the object to the path
573 // Start place to serialize into
574 var index = startingIndex + 4;
577 // Special case isArray
578 if(Array.isArray(object)) {
580 for(var i = 0; i < object.length; i++) {
582 var value = object[i];
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();
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);
633 } else if(object instanceof Map) {
634 var iterator = object.entries();
638 // Unpack the next entry
639 var entry = iterator.next();
641 // Are we done, then skip and terminate
644 // Get the entry values
645 var key = entry.value[0];
646 var value = entry.value[1];
648 // Check the type of the value
649 var type = typeof value;
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
656 throw Error("key " + key + " must not contain null bytes");
661 throw Error("key " + key + " must not start with '$'");
662 } else if (!!~key.indexOf('.')) {
663 throw Error("key " + key + " must not contain '.'");
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);
712 // Did we provide a custom serialization method
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");
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();
728 // Check the type of the value
729 var type = typeof value;
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
736 throw Error("key " + key + " must not contain null bytes");
741 throw Error("key " + key + " must not start with '$'");
742 } else if (!!~key.indexOf('.')) {
743 throw Error("key " + key + " must not contain '.'");
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);
796 // Final padding byte for object
797 buffer[index++] = 0x00;
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;
812 * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
817 var functionCache = BSON.functionCache = {};
822 * @classconstant BSON_DATA_NUMBER
824 BSON.BSON_DATA_NUMBER = 1;
828 * @classconstant BSON_DATA_STRING
830 BSON.BSON_DATA_STRING = 2;
834 * @classconstant BSON_DATA_OBJECT
836 BSON.BSON_DATA_OBJECT = 3;
840 * @classconstant BSON_DATA_ARRAY
842 BSON.BSON_DATA_ARRAY = 4;
846 * @classconstant BSON_DATA_BINARY
848 BSON.BSON_DATA_BINARY = 5;
850 * ObjectID BSON Type, deprecated
852 * @classconstant BSON_DATA_UNDEFINED
854 BSON.BSON_DATA_UNDEFINED = 6;
858 * @classconstant BSON_DATA_OID
860 BSON.BSON_DATA_OID = 7;
864 * @classconstant BSON_DATA_BOOLEAN
866 BSON.BSON_DATA_BOOLEAN = 8;
870 * @classconstant BSON_DATA_DATE
872 BSON.BSON_DATA_DATE = 9;
876 * @classconstant BSON_DATA_NULL
878 BSON.BSON_DATA_NULL = 10;
882 * @classconstant BSON_DATA_REGEXP
884 BSON.BSON_DATA_REGEXP = 11;
888 * @classconstant BSON_DATA_CODE
890 BSON.BSON_DATA_CODE = 13;
894 * @classconstant BSON_DATA_SYMBOL
896 BSON.BSON_DATA_SYMBOL = 14;
898 * Code with Scope BSON Type
900 * @classconstant BSON_DATA_CODE_W_SCOPE
902 BSON.BSON_DATA_CODE_W_SCOPE = 15;
904 * 32 bit Integer BSON Type
906 * @classconstant BSON_DATA_INT
908 BSON.BSON_DATA_INT = 16;
910 * Timestamp BSON Type
912 * @classconstant BSON_DATA_TIMESTAMP
914 BSON.BSON_DATA_TIMESTAMP = 17;
918 * @classconstant BSON_DATA_LONG
920 BSON.BSON_DATA_LONG = 18;
924 * @classconstant BSON_DATA_DECIMAL128
926 BSON.BSON_DATA_DECIMAL128 = 19;
930 * @classconstant BSON_DATA_MIN_KEY
932 BSON.BSON_DATA_MIN_KEY = 0xff;
936 * @classconstant BSON_DATA_MAX_KEY
938 BSON.BSON_DATA_MAX_KEY = 0x7f;
940 * Binary Default Type
942 * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
944 BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
946 * Binary Function Type
948 * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
950 BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
952 * Binary Byte Array Type
954 * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
956 BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
960 * @classconstant BSON_BINARY_SUBTYPE_UUID
962 BSON.BSON_BINARY_SUBTYPE_UUID = 3;
966 * @classconstant BSON_BINARY_SUBTYPE_MD5
968 BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
970 * Binary User Defined Type
972 * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
974 BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
977 BSON.BSON_INT32_MAX = 0x7FFFFFFF;
978 BSON.BSON_INT32_MIN = -0x80000000;
980 BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
981 BSON.BSON_INT64_MIN = -Math.pow(2, 63);
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.
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.
991 module.exports = serializeInto;