UNPKG

38.9 kBtext/x-cView Raw
1//===========================================================================
2
3#include <stdarg.h>
4#include <cstdlib>
5#include <cstring>
6#include <string.h>
7#include <stdlib.h>
8
9#ifdef __clang__
10#pragma clang diagnostic push
11#pragma clang diagnostic ignored "-Wunused-parameter"
12#endif
13
14#include <v8.h>
15
16// this and the above block must be around the v8.h header otherwise
17// v8 is not happy
18#ifdef __clang__
19#pragma clang diagnostic pop
20#endif
21
22#include <node.h>
23#include <node_version.h>
24#include <node_buffer.h>
25
26#include <cmath>
27#include <iostream>
28#include <limits>
29#include <vector>
30
31#if defined(_WIN32) || defined(_WIN64)
32 // For alloca().
33 #include <malloc.h>
34#endif
35
36#if defined(__sun) || defined(_AIX)
37 #include <alloca.h>
38#endif
39
40#include "nan.h"
41#include "bson.h"
42
43using namespace v8;
44using namespace node;
45
46//===========================================================================
47
48void DataStream::WriteObjectId(const Local<Object>& object, const Local<String>& key)
49{
50 uint16_t buffer[12];
51 object->Get(key)->ToString()->Write(buffer, 0, 12);
52 for(uint32_t i = 0; i < 12; ++i)
53 {
54 *p++ = (char) buffer[i];
55 }
56}
57
58void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...)
59{
60 va_list info;
61 va_start(info, format);
62 char* string = (char*) malloc(allocationSize);
63 vsprintf(string, format, info);
64 va_end(info);
65
66 throw string;
67}
68
69void DataStream::CheckKey(const Local<String>& keyName)
70{
71 size_t keyLength = keyName->Utf8Length();
72 if(keyLength == 0) return;
73
74 // Allocate space for the key, do not need to zero terminate as WriteUtf8 does it
75 char* keyStringBuffer = (char*) alloca(keyLength + 1);
76 // Write the key to the allocated buffer
77 keyName->WriteUtf8(keyStringBuffer);
78 // Check for the zero terminator
79 char* terminator = strchr(keyStringBuffer, 0x00);
80
81 // If the location is not at the end of the string we've got an illegal 0x00 byte somewhere
82 if(terminator != &keyStringBuffer[keyLength]) {
83 ThrowAllocatedStringException(64+keyLength, "key %s must not contain null bytes", keyStringBuffer);
84 }
85
86 if(keyStringBuffer[0] == '$')
87 {
88 ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer);
89 }
90
91 if(strchr(keyStringBuffer, '.') != NULL)
92 {
93 ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer);
94 }
95}
96
97template<typename T> void BSONSerializer<T>::SerializeDocument(const Local<Value>& value)
98{
99 void* documentSize = this->BeginWriteSize();
100 Local<Object> object = bson->GetSerializeObject(value);
101
102 // Get the object property names
103 Local<Array> propertyNames = object->GetPropertyNames();
104
105 // Length of the property
106 int propertyLength = propertyNames->Length();
107 for(int i = 0; i < propertyLength; ++i)
108 {
109 const Local<String>& propertyName = propertyNames->Get(i)->ToString();
110 if(checkKeys) this->CheckKey(propertyName);
111
112 const Local<Value>& propertyValue = object->Get(propertyName);
113
114 if(serializeFunctions || !propertyValue->IsFunction())
115 {
116 void* typeLocation = this->BeginWriteType();
117 this->WriteString(propertyName);
118 SerializeValue(typeLocation, propertyValue);
119 }
120 }
121
122 this->WriteByte(0);
123 this->CommitSize(documentSize);
124}
125
126template<typename T> void BSONSerializer<T>::SerializeArray(const Local<Value>& value)
127{
128 void* documentSize = this->BeginWriteSize();
129
130 Local<Array> array = Local<Array>::Cast(value->ToObject());
131 uint32_t arrayLength = array->Length();
132
133 for(uint32_t i = 0; i < arrayLength; ++i)
134 {
135 void* typeLocation = this->BeginWriteType();
136 this->WriteUInt32String(i);
137 SerializeValue(typeLocation, array->Get(i));
138 }
139
140 this->WriteByte(0);
141 this->CommitSize(documentSize);
142}
143
144// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes.
145// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths)
146// and ensures that there is always consistency between bytes counted and bytes written by design.
147template<typename T> void BSONSerializer<T>::SerializeValue(void* typeLocation, const Local<Value>& value)
148{
149 if(value->IsNumber())
150 {
151 double doubleValue = value->NumberValue();
152 int intValue = (int) doubleValue;
153 if(intValue == doubleValue)
154 {
155 this->CommitType(typeLocation, BSON_TYPE_INT);
156 this->WriteInt32(intValue);
157 }
158 else
159 {
160 this->CommitType(typeLocation, BSON_TYPE_NUMBER);
161 this->WriteDouble(doubleValue);
162 }
163 }
164 else if(value->IsString())
165 {
166 this->CommitType(typeLocation, BSON_TYPE_STRING);
167 this->WriteLengthPrefixedString(value->ToString());
168 }
169 else if(value->IsBoolean())
170 {
171 this->CommitType(typeLocation, BSON_TYPE_BOOLEAN);
172 this->WriteBool(value);
173 }
174 else if(value->IsArray())
175 {
176 this->CommitType(typeLocation, BSON_TYPE_ARRAY);
177 SerializeArray(value);
178 }
179 else if(value->IsDate())
180 {
181 this->CommitType(typeLocation, BSON_TYPE_DATE);
182 this->WriteInt64(value);
183 }
184 else if(value->IsRegExp())
185 {
186 this->CommitType(typeLocation, BSON_TYPE_REGEXP);
187 const Local<RegExp>& regExp = Local<RegExp>::Cast(value);
188
189 this->WriteString(regExp->GetSource());
190
191 int flags = regExp->GetFlags();
192 if(flags & RegExp::kGlobal) this->WriteByte('s');
193 if(flags & RegExp::kIgnoreCase) this->WriteByte('i');
194 if(flags & RegExp::kMultiline) this->WriteByte('m');
195 this->WriteByte(0);
196 }
197 else if(value->IsFunction())
198 {
199 this->CommitType(typeLocation, BSON_TYPE_CODE);
200 this->WriteLengthPrefixedString(value->ToString());
201 }
202 else if(value->IsObject())
203 {
204 const Local<Object>& object = value->ToObject();
205 if(object->Has(Nan::New(bson->_bsontypeString)))
206 {
207 const Local<String>& constructorString = object->GetConstructorName();
208 if(Nan::New(bson->longString)->StrictEquals(constructorString))
209 {
210 this->CommitType(typeLocation, BSON_TYPE_LONG);
211 this->WriteInt32(object, Nan::New(bson->_longLowString));
212 this->WriteInt32(object, Nan::New(bson->_longHighString));
213 }
214 else if(Nan::New(bson->timestampString)->StrictEquals(constructorString))
215 {
216 this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP);
217 this->WriteInt32(object, Nan::New(bson->_longLowString));
218 this->WriteInt32(object, Nan::New(bson->_longHighString));
219 }
220 else if(Nan::New(bson->objectIDString)->StrictEquals(constructorString))
221 {
222 this->CommitType(typeLocation, BSON_TYPE_OID);
223 this->WriteObjectId(object, Nan::New(bson->_objectIDidString));
224 }
225 else if(Nan::New(bson->binaryString)->StrictEquals(constructorString))
226 {
227 this->CommitType(typeLocation, BSON_TYPE_BINARY);
228
229 uint32_t length = object->Get(Nan::New(bson->_binaryPositionString))->Uint32Value();
230 Local<Object> bufferObj = object->Get(Nan::New(bson->_binaryBufferString))->ToObject();
231
232 this->WriteInt32(length);
233 this->WriteByte(object, Nan::New(bson->_binarySubTypeString)); // write subtype
234 // If type 0x02 write the array length aswell
235 if(object->Get(Nan::New(bson->_binarySubTypeString))->Int32Value() == 0x02) {
236 this->WriteInt32(length);
237 }
238 // Write the actual data
239 this->WriteData(Buffer::Data(bufferObj), length);
240 }
241 else if(Nan::New(bson->doubleString)->StrictEquals(constructorString))
242 {
243 this->CommitType(typeLocation, BSON_TYPE_NUMBER);
244 this->WriteDouble(object, Nan::New(bson->_doubleValueString));
245 }
246 else if(Nan::New(bson->symbolString)->StrictEquals(constructorString))
247 {
248 this->CommitType(typeLocation, BSON_TYPE_SYMBOL);
249 this->WriteLengthPrefixedString(object->Get(Nan::New(bson->_symbolValueString))->ToString());
250 }
251 else if(Nan::New(bson->codeString)->StrictEquals(constructorString))
252 {
253 const Local<String>& function = object->Get(Nan::New(bson->_codeCodeString))->ToString();
254 const Local<Object>& scope = object->Get(Nan::New(bson->_codeScopeString))->ToObject();
255
256 // For Node < 0.6.X use the GetPropertyNames
257 #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
258 uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
259 #else
260 uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
261 #endif
262
263 if(propertyNameLength > 0)
264 {
265 this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE);
266 void* codeWidthScopeSize = this->BeginWriteSize();
267 this->WriteLengthPrefixedString(function->ToString());
268 SerializeDocument(scope);
269 this->CommitSize(codeWidthScopeSize);
270 }
271 else
272 {
273 this->CommitType(typeLocation, BSON_TYPE_CODE);
274 this->WriteLengthPrefixedString(function->ToString());
275 }
276 }
277 else if(Nan::New(bson->dbrefString)->StrictEquals(constructorString))
278 {
279 this->CommitType(typeLocation, BSON_TYPE_OBJECT);
280
281 void* dbRefSize = this->BeginWriteSize();
282
283 void* refType = this->BeginWriteType();
284 this->WriteData("$ref", 5);
285 SerializeValue(refType, object->Get(Nan::New(bson->_dbRefNamespaceString)));
286
287 void* idType = this->BeginWriteType();
288 this->WriteData("$id", 4);
289 SerializeValue(idType, object->Get(Nan::New(bson->_dbRefOidString)));
290
291 const Local<Value>& refDbValue = object->Get(Nan::New(bson->_dbRefDbString));
292 if(!refDbValue->IsUndefined())
293 {
294 void* dbType = this->BeginWriteType();
295 this->WriteData("$db", 4);
296 SerializeValue(dbType, refDbValue);
297 }
298
299 this->WriteByte(0);
300 this->CommitSize(dbRefSize);
301 }
302 else if(Nan::New(bson->minKeyString)->StrictEquals(constructorString))
303 {
304 this->CommitType(typeLocation, BSON_TYPE_MIN_KEY);
305 }
306 else if(Nan::New(bson->maxKeyString)->StrictEquals(constructorString))
307 {
308 this->CommitType(typeLocation, BSON_TYPE_MAX_KEY);
309 }
310 }
311 else if(Buffer::HasInstance(value))
312 {
313 this->CommitType(typeLocation, BSON_TYPE_BINARY);
314
315 #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
316 Local<Object> buffer = ObjectWrap::Unwrap<Buffer>(value->ToObject());
317 uint32_t length = object->length();
318 #else
319 uint32_t length = Buffer::Length(value->ToObject());
320 #endif
321
322 this->WriteInt32(length);
323 this->WriteByte(0);
324 this->WriteData(Buffer::Data(value->ToObject()), length);
325 }
326 else
327 {
328 this->CommitType(typeLocation, BSON_TYPE_OBJECT);
329 SerializeDocument(value);
330 }
331 }
332 else if(value->IsNull() || value->IsUndefined())
333 {
334 this->CommitType(typeLocation, BSON_TYPE_NULL);
335 }
336}
337
338// Data points to start of element list, length is length of entire document including '\0' but excluding initial size
339BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length)
340: bson(aBson),
341 pStart(data),
342 p(data),
343 pEnd(data + length - 1)
344{
345 if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
346}
347
348BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length)
349: bson(parentSerializer.bson),
350 pStart(parentSerializer.p),
351 p(parentSerializer.p),
352 pEnd(parentSerializer.p + length - 1)
353{
354 parentSerializer.p += length;
355 if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds");
356 if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
357}
358
359Local<Value> BSONDeserializer::ReadCString()
360{
361 char* start = p;
362 while(*p++ && (p < pEnd)) { }
363 if(p > pEnd) {
364 return Nan::Null();
365 }
366 return Nan::New<String>(start, (int32_t) (p-start-1) ).ToLocalChecked();
367}
368
369int32_t BSONDeserializer::ReadRegexOptions()
370{
371 int32_t options = 0;
372 for(;;)
373 {
374 switch(*p++)
375 {
376 case '\0': return options;
377 case 's': options |= RegExp::kGlobal; break;
378 case 'i': options |= RegExp::kIgnoreCase; break;
379 case 'm': options |= RegExp::kMultiline; break;
380 }
381 }
382}
383
384uint32_t BSONDeserializer::ReadIntegerString()
385{
386 uint32_t value = 0;
387 while(*p)
388 {
389 if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array");
390 value = value * 10 + *p++ - '0';
391 }
392 ++p;
393 return value;
394}
395
396Local<String> BSONDeserializer::ReadString()
397{
398 uint32_t length = ReadUInt32();
399 char* start = p;
400 p += length;
401 return Nan::New<String>(start, length-1).ToLocalChecked();
402}
403
404Local<String> BSONDeserializer::ReadObjectId()
405{
406 uint16_t objectId[12];
407 for(size_t i = 0; i < 12; ++i)
408 {
409 objectId[i] = *reinterpret_cast<unsigned char*>(p++);
410 }
411 return Nan::New<String>(objectId, 12).ToLocalChecked();
412}
413
414Local<Value> BSONDeserializer::DeserializeDocument(bool promoteLongs)
415{
416 uint32_t length = ReadUInt32();
417 if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes");
418
419 BSONDeserializer documentDeserializer(*this, length-4);
420 return documentDeserializer.DeserializeDocumentInternal(promoteLongs);
421}
422
423Local<Value> BSONDeserializer::DeserializeDocumentInternal(bool promoteLongs)
424{
425 Local<Object> returnObject = Nan::New<Object>();
426
427 while(HasMoreData())
428 {
429 BsonType type = (BsonType) ReadByte();
430 const Local<Value>& name = ReadCString();
431 if(name->IsNull()) ThrowAllocatedStringException(64, "Bad BSON Document: illegal CString");
432 // name->Is
433 const Local<Value>& value = DeserializeValue(type, promoteLongs);
434 Nan::DefineOwnProperty(returnObject, ((Local<Value>&)name).As<v8::String>(), value, v8::None);
435 }
436 if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes");
437
438 // From JavaScript:
439 // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
440 if(returnObject->Has(Nan::New(bson->_dbRefIdRefString)))
441 {
442 Local<Value> argv[] = { returnObject->Get(Nan::New(bson->_dbRefRefString)), returnObject->Get(Nan::New(bson->_dbRefIdRefString)), returnObject->Get(Nan::New(bson->_dbRefDbRefString)) };
443 return Nan::NewInstance(Nan::New(bson->dbrefConstructor), 3, argv).ToLocalChecked();
444 }
445 else
446 {
447 return returnObject;
448 }
449}
450
451Local<Value> BSONDeserializer::DeserializeArray(bool promoteLongs)
452{
453 uint32_t length = ReadUInt32();
454 if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes");
455
456 BSONDeserializer documentDeserializer(*this, length-4);
457 return documentDeserializer.DeserializeArrayInternal(promoteLongs);
458}
459
460Local<Value> BSONDeserializer::DeserializeArrayInternal(bool promoteLongs)
461{
462 Local<Array> returnArray = Nan::New<Array>();
463
464 while(HasMoreData())
465 {
466 BsonType type = (BsonType) ReadByte();
467 uint32_t index = ReadIntegerString();
468 const Local<Value>& value = DeserializeValue(type, promoteLongs);
469 returnArray->Set(index, value);
470 }
471 if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes");
472
473 return returnArray;
474}
475
476Local<Value> BSONDeserializer::DeserializeValue(BsonType type, bool promoteLongs)
477{
478 switch(type)
479 {
480 case BSON_TYPE_STRING:
481 return ReadString();
482
483 case BSON_TYPE_INT:
484 return Nan::New<Integer>(ReadInt32());
485
486 case BSON_TYPE_NUMBER:
487 return Nan::New<Number>(ReadDouble());
488
489 case BSON_TYPE_NULL:
490 return Nan::Null();
491
492 case BSON_TYPE_UNDEFINED:
493 return Nan::Undefined();
494
495 case BSON_TYPE_TIMESTAMP:
496 {
497 int32_t lowBits = ReadInt32();
498 int32_t highBits = ReadInt32();
499 Local<Value> argv[] = { Nan::New<Int32>(lowBits), Nan::New<Int32>(highBits) };
500 return Nan::NewInstance(Nan::New(bson->timestampConstructor), 2, argv).ToLocalChecked();
501 }
502
503 case BSON_TYPE_BOOLEAN:
504 return (ReadByte() != 0) ? Nan::True() : Nan::False();
505
506 case BSON_TYPE_REGEXP:
507 {
508 const Local<Value>& regex = ReadCString();
509 if(regex->IsNull()) ThrowAllocatedStringException(64, "Bad BSON Document: illegal CString");
510 int32_t options = ReadRegexOptions();
511 return RegExp::New(regex->ToString(), (RegExp::Flags) options);
512 }
513
514 case BSON_TYPE_CODE:
515 {
516 const Local<Value>& code = ReadString();
517 const Local<Value>& scope = Nan::New<Object>();
518 Local<Value> argv[] = { code, scope };
519 return Nan::NewInstance(Nan::New(bson->codeConstructor), 2, argv).ToLocalChecked();
520 }
521
522 case BSON_TYPE_CODE_W_SCOPE:
523 {
524 ReadUInt32();
525 const Local<Value>& code = ReadString();
526 const Local<Value>& scope = DeserializeDocument(promoteLongs);
527 Local<Value> argv[] = { code, scope->ToObject() };
528 return Nan::NewInstance(Nan::New(bson->codeConstructor), 2, argv).ToLocalChecked();
529 }
530
531 case BSON_TYPE_OID:
532 {
533 Local<Value> argv[] = { ReadObjectId() };
534 return Nan::NewInstance(Nan::New(bson->objectIDConstructor), 1, argv).ToLocalChecked();
535 }
536
537 case BSON_TYPE_BINARY:
538 {
539 uint32_t length = ReadUInt32();
540 uint32_t subType = ReadByte();
541 if(subType == 0x02) {
542 length = ReadInt32();
543 }
544
545 Local<Object> buffer = Nan::NewBuffer(p, length).ToLocalChecked();
546 p += length;
547
548 Local<Value> argv[] = { buffer, Nan::New<Uint32>(subType) };
549 return Nan::NewInstance(Nan::New(bson->binaryConstructor), 2, argv).ToLocalChecked();
550 }
551
552 case BSON_TYPE_LONG:
553 {
554 // Read 32 bit integers
555 int32_t lowBits = (int32_t) ReadInt32();
556 int32_t highBits = (int32_t) ReadInt32();
557
558 // Promote long is enabled
559 if(promoteLongs) {
560 // If value is < 2^53 and >-2^53
561 if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
562 // Adjust the pointer and read as 64 bit value
563 p -= 8;
564 // Read the 64 bit value
565 int64_t finalValue = (int64_t) ReadInt64();
566 return Nan::New<Number>(finalValue);
567 }
568 }
569
570 // Decode the Long value
571 Local<Value> argv[] = { Nan::New<Int32>(lowBits), Nan::New<Int32>(highBits) };
572 return Nan::NewInstance(Nan::New(bson->longConstructor), 2, argv).ToLocalChecked();
573 }
574
575 case BSON_TYPE_DATE:
576 return Nan::New<Date>((double) ReadInt64()).ToLocalChecked();
577
578 case BSON_TYPE_ARRAY:
579 return DeserializeArray(promoteLongs);
580
581 case BSON_TYPE_OBJECT:
582 return DeserializeDocument(promoteLongs);
583
584 case BSON_TYPE_SYMBOL:
585 {
586 const Local<String>& string = ReadString();
587 Local<Value> argv[] = { string };
588 return Nan::NewInstance(Nan::New(bson->symbolConstructor), 1, argv).ToLocalChecked();
589 }
590
591 case BSON_TYPE_MIN_KEY:
592 return Nan::NewInstance(Nan::New(bson->minKeyConstructor)).ToLocalChecked();
593
594 case BSON_TYPE_MAX_KEY:
595 return Nan::NewInstance(Nan::New(bson->maxKeyConstructor)).ToLocalChecked();
596
597 default:
598 ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type);
599 }
600
601 return Nan::Null();
602}
603
604Nan::Persistent<FunctionTemplate> BSON::constructor_template;
605
606BSON::BSON() : ObjectWrap()
607{
608 // Setup pre-allocated comparision objects
609 _bsontypeString.Reset(Nan::New<String>("_bsontype").ToLocalChecked());
610 _longLowString.Reset(Nan::New<String>("low_").ToLocalChecked());
611 _longHighString.Reset(Nan::New<String>("high_").ToLocalChecked());
612 _objectIDidString.Reset(Nan::New<String>("id").ToLocalChecked());
613 _binaryPositionString.Reset(Nan::New<String>("position").ToLocalChecked());
614 _binarySubTypeString.Reset(Nan::New<String>("sub_type").ToLocalChecked());
615 _binaryBufferString.Reset(Nan::New<String>("buffer").ToLocalChecked());
616 _doubleValueString.Reset(Nan::New<String>("value").ToLocalChecked());
617 _symbolValueString.Reset(Nan::New<String>("value").ToLocalChecked());
618 _dbRefRefString.Reset(Nan::New<String>("$ref").ToLocalChecked());
619 _dbRefIdRefString.Reset(Nan::New<String>("$id").ToLocalChecked());
620 _dbRefDbRefString.Reset(Nan::New<String>("$db").ToLocalChecked());
621 _dbRefNamespaceString.Reset(Nan::New<String>("namespace").ToLocalChecked());
622 _dbRefDbString.Reset(Nan::New<String>("db").ToLocalChecked());
623 _dbRefOidString.Reset(Nan::New<String>("oid").ToLocalChecked());
624 _codeCodeString.Reset(Nan::New<String>("code").ToLocalChecked());
625 _codeScopeString.Reset(Nan::New<String>("scope").ToLocalChecked());
626 _toBSONString.Reset(Nan::New<String>("toBSON").ToLocalChecked());
627
628 longString.Reset(Nan::New<String>("Long").ToLocalChecked());
629 objectIDString.Reset(Nan::New<String>("ObjectID").ToLocalChecked());
630 binaryString.Reset(Nan::New<String>("Binary").ToLocalChecked());
631 codeString.Reset(Nan::New<String>("Code").ToLocalChecked());
632 dbrefString.Reset(Nan::New<String>("DBRef").ToLocalChecked());
633 symbolString.Reset(Nan::New<String>("Symbol").ToLocalChecked());
634 doubleString.Reset(Nan::New<String>("Double").ToLocalChecked());
635 timestampString.Reset(Nan::New<String>("Timestamp").ToLocalChecked());
636 minKeyString.Reset(Nan::New<String>("MinKey").ToLocalChecked());
637 maxKeyString.Reset(Nan::New<String>("MaxKey").ToLocalChecked());
638}
639
640BSON::~BSON() {
641 _bsontypeString.Reset();
642 _longLowString.Reset();
643 _longHighString.Reset();
644 _objectIDidString.Reset();
645 _binaryPositionString.Reset();
646 _binarySubTypeString.Reset();
647 _binaryBufferString.Reset();
648 _doubleValueString.Reset();
649 _symbolValueString.Reset();
650 _dbRefRefString.Reset();
651 _dbRefIdRefString.Reset();
652 _dbRefDbRefString.Reset();
653 _dbRefNamespaceString.Reset();
654 _dbRefDbString.Reset();
655 _dbRefOidString.Reset();
656 _codeCodeString.Reset();
657 _codeScopeString.Reset();
658 _toBSONString.Reset();
659
660 longString.Reset();
661 objectIDString.Reset();
662 binaryString.Reset();
663 codeString.Reset();
664 dbrefString.Reset();
665 symbolString.Reset();
666 doubleString.Reset();
667 timestampString.Reset();
668 minKeyString.Reset();
669 maxKeyString.Reset();
670}
671
672void BSON::Initialize(v8::Local<v8::Object> target)
673{
674 // Grab the scope of the call from Node
675 Nan::HandleScope scope;
676 // Define a new function template
677 Local<FunctionTemplate> t = Nan::New<FunctionTemplate>();
678 t->InstanceTemplate()->SetInternalFieldCount(1);
679 t->SetClassName(Nan::New<String>("BSON").ToLocalChecked());
680
681 // Instance methods
682 Nan::SetPrototypeMethod(t, "calculateObjectSize", CalculateObjectSize);
683 Nan::SetPrototypeMethod(t, "serialize", BSONSerialize);
684 Nan::SetPrototypeMethod(t, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
685 Nan::SetPrototypeMethod(t, "deserialize", BSONDeserialize);
686 Nan::SetPrototypeMethod(t, "deserializeStream", BSONDeserializeStream);
687
688 constructor_template.Reset(t);
689
690 Nan::DefineOwnProperty(target, Nan::New<String>("BSON").ToLocalChecked(), t->GetFunction(), v8::None);
691}
692
693// Create a new instance of BSON and passing it the existing context
694NAN_METHOD(BSON::New)
695{
696 Nan::HandleScope scope;
697
698 // Check that we have an array
699 if(info.Length() == 1 && info[0]->IsArray())
700 {
701 // Cast the array to a local reference
702 Local<Array> array = Local<Array>::Cast(info[0]);
703
704 if(array->Length() > 0)
705 {
706 // Create a bson object instance and return it
707 BSON *bson = new BSON();
708
709 uint32_t foundClassesMask = 0;
710
711 // Iterate over all entries to save the instantiate funtions
712 for(uint32_t i = 0; i < array->Length(); i++) {
713 // Let's get a reference to the function
714 Local<Function> func = Local<Function>::Cast(array->Get(i));
715 Local<String> functionName = func->GetName()->ToString();
716
717 // Save the functions making them persistant handles (they don't get collected)
718 if(functionName->StrictEquals(Nan::New(bson->longString))) {
719 bson->longConstructor.Reset(func);
720 foundClassesMask |= 1;
721 } else if(functionName->StrictEquals(Nan::New(bson->objectIDString))) {
722 bson->objectIDConstructor.Reset(func);
723 foundClassesMask |= 2;
724 } else if(functionName->StrictEquals(Nan::New(bson->binaryString))) {
725 bson->binaryConstructor.Reset(func);
726 foundClassesMask |= 4;
727 } else if(functionName->StrictEquals(Nan::New(bson->codeString))) {
728 bson->codeConstructor.Reset(func);
729 foundClassesMask |= 8;
730 } else if(functionName->StrictEquals(Nan::New(bson->dbrefString))) {
731 bson->dbrefConstructor.Reset(func);
732 foundClassesMask |= 0x10;
733 } else if(functionName->StrictEquals(Nan::New(bson->symbolString))) {
734 bson->symbolConstructor.Reset(func);
735 foundClassesMask |= 0x20;
736 } else if(functionName->StrictEquals(Nan::New(bson->doubleString))) {
737 bson->doubleConstructor.Reset(func);
738 foundClassesMask |= 0x40;
739 } else if(functionName->StrictEquals(Nan::New(bson->timestampString))) {
740 bson->timestampConstructor.Reset(func);
741 foundClassesMask |= 0x80;
742 } else if(functionName->StrictEquals(Nan::New(bson->minKeyString))) {
743 bson->minKeyConstructor.Reset(func);
744 foundClassesMask |= 0x100;
745 } else if(functionName->StrictEquals(Nan::New(bson->maxKeyString))) {
746 bson->maxKeyConstructor.Reset(func);
747 foundClassesMask |= 0x200;
748 }
749 }
750
751 // Check if we have the right number of constructors otherwise throw an error
752 if(foundClassesMask != 0x3ff) {
753 delete bson;
754 return Nan::ThrowError("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
755 } else {
756 bson->Wrap(info.This());
757 info.GetReturnValue().Set(info.This());
758 }
759 }
760 else
761 {
762 return Nan::ThrowError("No types passed in");
763 }
764 }
765 else
766 {
767 return Nan::ThrowTypeError("Argument passed in must be an array of types");
768 }
769}
770
771//------------------------------------------------------------------------------------------------
772//------------------------------------------------------------------------------------------------
773//------------------------------------------------------------------------------------------------
774//------------------------------------------------------------------------------------------------
775
776NAN_METHOD(BSON::BSONDeserialize)
777{
778 Nan::HandleScope scope;
779
780 // Fail if the first argument is not a string or a buffer
781 if(info.Length() > 1 && !info[0]->IsString() && !Buffer::HasInstance(info[0]))
782 return Nan::ThrowError("First Argument must be a Buffer or String.");
783
784 // Promote longs
785 bool promoteLongs = true;
786
787 // If we have an options object
788 if(info.Length() == 2 && info[1]->IsObject()) {
789 Local<Object> options = info[1]->ToObject();
790
791 if(options->Has(Nan::New<String>("promoteLongs").ToLocalChecked())) {
792 promoteLongs = options->Get(Nan::New<String>("promoteLongs").ToLocalChecked())->ToBoolean()->Value();
793 }
794 }
795
796 // Define pointer to data
797 Local<Object> obj = info[0]->ToObject();
798
799 // Unpack the BSON parser instance
800 BSON *bson = ObjectWrap::Unwrap<BSON>(info.This());
801
802 // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
803 if(Buffer::HasInstance(obj))
804 {
805#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
806 Local<Object> buffer = ObjectWrap::Unwrap<Buffer>(obj);
807 char* data = buffer->data();
808 size_t length = buffer->length();
809#else
810 char* data = Buffer::Data(obj);
811 size_t length = Buffer::Length(obj);
812#endif
813
814 // Validate that we have at least 5 bytes
815 if(length < 5) return Nan::ThrowError("corrupt bson message < 5 bytes long");
816
817 try
818 {
819 BSONDeserializer deserializer(bson, data, length);
820 // deserializer.promoteLongs = promoteLongs;
821 info.GetReturnValue().Set(deserializer.DeserializeDocument(promoteLongs));
822 }
823 catch(char* exception)
824 {
825 Local<String> error = Nan::New<String>(exception).ToLocalChecked();
826 free(exception);
827 return Nan::ThrowError(error);
828 }
829
830 }
831 else
832 {
833 // The length of the data for this encoding
834 intptr_t len = Nan::DecodeBytes(info[0], (Nan::Encoding)BINARY);
835
836 // Validate that we have at least 5 bytes
837 if(len < 5) return Nan::ThrowError("corrupt bson message < 5 bytes long");
838
839 // Let's define the buffer size
840 char* data = (char *)malloc(len);
841 Nan::DecodeWrite(data, len, info[0], (Nan::Encoding)BINARY);
842
843 try
844 {
845 BSONDeserializer deserializer(bson, data, len);
846 // deserializer.promoteLongs = promoteLongs;
847 Local<Value> result = deserializer.DeserializeDocument(promoteLongs);
848 free(data);
849 info.GetReturnValue().Set(result);
850
851 }
852 catch(char* exception)
853 {
854 Local<String> error = Nan::New<String>(exception).ToLocalChecked();
855 free(exception);
856 free(data);
857 return Nan::ThrowError(error);
858 }
859 }
860}
861
862Local<Object> BSON::GetSerializeObject(const Local<Value>& argValue)
863{
864 Local<Object> object = argValue->ToObject();
865 if(object->Has(Nan::New(_toBSONString)))
866 {
867 const Local<Value>& toBSON = object->Get(Nan::New(_toBSONString));
868 if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function");
869
870 Local<Value> result = Local<Function>::Cast(toBSON)->Call(object, 0, NULL);
871 if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object");
872 return result->ToObject();
873 }
874 else
875 {
876 return object;
877 }
878}
879
880NAN_METHOD(BSON::BSONSerialize)
881{
882 Nan::HandleScope scope;
883
884 if(info.Length() == 1 && !info[0]->IsObject()) return Nan::ThrowError("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
885 if(info.Length() == 2 && !info[0]->IsObject() && !info[1]->IsBoolean()) return Nan::ThrowError("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
886 if(info.Length() == 3 && !info[0]->IsObject() && !info[1]->IsBoolean() && !info[2]->IsBoolean()) return Nan::ThrowError("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
887 if(info.Length() == 4 && !info[0]->IsObject() && !info[1]->IsBoolean() && !info[2]->IsBoolean() && !info[3]->IsBoolean()) return Nan::ThrowError("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
888 if(info.Length() > 4) return Nan::ThrowError("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
889
890 // Check if we have an array as the object
891 if(info[0]->IsArray()) return Nan::ThrowError("Only javascript objects supported");
892
893 // Unpack the BSON parser instance
894 BSON *bson = ObjectWrap::Unwrap<BSON>(info.This());
895
896 // Calculate the total size of the document in binary form to ensure we only allocate memory once
897 // With serialize function
898 bool serializeFunctions = (info.Length() >= 4) && info[3]->BooleanValue();
899
900 char *serialized_object = NULL;
901 size_t object_size;
902 try
903 {
904 Local<Object> object = bson->GetSerializeObject(info[0]);
905
906 BSONSerializer<CountStream> counter(bson, false, serializeFunctions);
907 counter.SerializeDocument(object);
908 object_size = counter.GetSerializeSize();
909
910 // Allocate the memory needed for the serialization
911 serialized_object = (char *)malloc(object_size);
912
913 // Check if we have a boolean value
914 bool checkKeys = info.Length() >= 3 && info[1]->IsBoolean() && info[1]->BooleanValue();
915 BSONSerializer<DataStream> data(bson, checkKeys, serializeFunctions, serialized_object);
916 data.SerializeDocument(object);
917 }
918 catch(char *err_msg)
919 {
920 free(serialized_object);
921 Local<String> error = Nan::New<String>(err_msg).ToLocalChecked();
922 free(err_msg);
923 return Nan::ThrowError(error);
924 }
925
926 // If we have 3 arguments
927 if(info.Length() == 3 || info.Length() == 4)
928 {
929 Local<Object> buffer = Nan::NewBuffer(serialized_object, object_size).ToLocalChecked();
930 free(serialized_object);
931 info.GetReturnValue().Set(buffer);
932 }
933 else
934 {
935 Local<Value> bin_value = Nan::Encode(serialized_object, object_size, (Nan::Encoding)BINARY)->ToString();
936 free(serialized_object);
937 info.GetReturnValue().Set(bin_value);
938 }
939}
940
941NAN_METHOD(BSON::CalculateObjectSize)
942{
943 Nan::HandleScope scope;
944 // Ensure we have a valid object
945 if(info.Length() == 1 && !info[0]->IsObject()) return Nan::ThrowError("One argument required - [object]");
946 if(info.Length() == 2 && !info[0]->IsObject() && !info[1]->IsBoolean()) return Nan::ThrowError("Two arguments required - [object, boolean]");
947 if(info.Length() > 3) return Nan::ThrowError("One or two arguments required - [object] or [object, boolean]");
948
949 // Unpack the BSON parser instance
950 BSON *bson = ObjectWrap::Unwrap<BSON>(info.This());
951 bool serializeFunctions = (info.Length() >= 2) && info[1]->BooleanValue();
952 BSONSerializer<CountStream> countSerializer(bson, false, serializeFunctions);
953 countSerializer.SerializeDocument(info[0]);
954
955 // Return the object size
956 info.GetReturnValue().Set(Nan::New<Uint32>((uint32_t) countSerializer.GetSerializeSize()));
957}
958
959NAN_METHOD(BSON::SerializeWithBufferAndIndex)
960{
961 Nan::HandleScope scope;
962
963 //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) {
964 // Ensure we have the correct values
965 if(info.Length() > 5) return Nan::ThrowError("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
966 if(info.Length() == 4 && !info[0]->IsObject() && !info[1]->IsBoolean() && !Buffer::HasInstance(info[2]) && !info[3]->IsUint32()) return Nan::ThrowError("Four parameters required [object, boolean, Buffer, int]");
967 if(info.Length() == 5 && !info[0]->IsObject() && !info[1]->IsBoolean() && !Buffer::HasInstance(info[2]) && !info[3]->IsUint32() && !info[4]->IsBoolean()) return Nan::ThrowError("Four parameters required [object, boolean, Buffer, int, boolean]");
968
969 uint32_t index;
970 size_t object_size;
971
972 try
973 {
974 BSON *bson = ObjectWrap::Unwrap<BSON>(info.This());
975
976 Local<Object> obj = info[2]->ToObject();
977 char* data = Buffer::Data(obj);
978 size_t length = Buffer::Length(obj);
979
980 index = info[3]->Uint32Value();
981 bool checkKeys = info.Length() >= 4 && info[1]->IsBoolean() && info[1]->BooleanValue();
982 bool serializeFunctions = (info.Length() == 5) && info[4]->BooleanValue();
983
984 BSONSerializer<DataStream> dataSerializer(bson, checkKeys, serializeFunctions, data+index);
985 dataSerializer.SerializeDocument(bson->GetSerializeObject(info[0]));
986 object_size = dataSerializer.GetSerializeSize();
987
988 if(object_size + index > length) return Nan::ThrowError("Serious error - overflowed buffer!!");
989 }
990 catch(char *exception)
991 {
992 Local<String> error = Nan::New<String>(exception).ToLocalChecked();
993 free(exception);
994 return Nan::ThrowError(error);
995 }
996
997 info.GetReturnValue().Set(Nan::New<Uint32>((uint32_t) (index + object_size - 1)));
998}
999
1000NAN_METHOD(BSON::BSONDeserializeStream)
1001{
1002 Nan::HandleScope scope;
1003
1004 // At least 3 arguments required
1005 if(info.Length() < 5) return Nan::ThrowError("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))");
1006
1007 // If the number of argumets equals 3
1008 if(info.Length() >= 5)
1009 {
1010 if(!Buffer::HasInstance(info[0])) return Nan::ThrowError("First argument must be Buffer instance");
1011 if(!info[1]->IsUint32()) return Nan::ThrowError("Second argument must be a positive index number");
1012 if(!info[2]->IsUint32()) return Nan::ThrowError("Third argument must be a positive number of documents to deserialize");
1013 if(!info[3]->IsArray()) return Nan::ThrowError("Fourth argument must be an array the size of documents to deserialize");
1014 if(!info[4]->IsUint32()) return Nan::ThrowError("Sixth argument must be a positive index number");
1015 }
1016
1017 // If we have 4 arguments
1018 if(info.Length() == 6 && !info[5]->IsObject()) return Nan::ThrowError("Fifth argument must be an object with options");
1019
1020 // Define pointer to data
1021 Local<Object> obj = info[0]->ToObject();
1022 uint32_t numberOfDocuments = info[2]->Uint32Value();
1023 uint32_t index = info[1]->Uint32Value();
1024 uint32_t resultIndex = info[4]->Uint32Value();
1025 bool promoteLongs = true;
1026
1027 // Check for the value promoteLongs in the options object
1028 if(info.Length() == 6) {
1029 Local<Object> options = info[5]->ToObject();
1030
1031 // Check if we have the promoteLong variable
1032 if(options->Has(Nan::New<String>("promoteLongs").ToLocalChecked())) {
1033 promoteLongs = options->Get(Nan::New<String>("promoteLongs").ToLocalChecked())->ToBoolean()->Value();
1034 }
1035 }
1036
1037 // Unpack the BSON parser instance
1038 BSON *bson = ObjectWrap::Unwrap<BSON>(info.This());
1039
1040 // Unpack the buffer variable
1041#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
1042 Local<Object> buffer = ObjectWrap::Unwrap<Buffer>(obj);
1043 char* data = buffer->data();
1044 size_t length = buffer->length();
1045#else
1046 char* data = Buffer::Data(obj);
1047 size_t length = Buffer::Length(obj);
1048#endif
1049
1050 // Fetch the documents
1051 Local<Object> documents = info[3]->ToObject();
1052
1053 BSONDeserializer deserializer(bson, data+index, length-index);
1054 for(uint32_t i = 0; i < numberOfDocuments; i++)
1055 {
1056 try
1057 {
1058 documents->Set(i + resultIndex, deserializer.DeserializeDocument(promoteLongs));
1059 }
1060 catch (char* exception)
1061 {
1062 Local<String> error = Nan::New<String>(exception).ToLocalChecked();
1063 free(exception);
1064 return Nan::ThrowError(error);
1065 }
1066 }
1067
1068 // Return new index of parsing
1069 info.GetReturnValue().Set(Nan::New<Uint32>((uint32_t) (index + deserializer.GetSerializeSize())));
1070}
1071
1072// Exporting function
1073extern "C" void init(Local<Object> target)
1074{
1075 Nan::HandleScope scope;
1076 BSON::Initialize(target);
1077}
1078
1079//NODE_MODULE(bson, BSON::Initialize);