summaryrefslogtreecommitdiff
path: root/node_modules/mongodb/external-libs/bson
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mongodb/external-libs/bson')
-rw-r--r--node_modules/mongodb/external-libs/bson/Makefile45
-rw-r--r--node_modules/mongodb/external-libs/bson/bson.cc2165
-rw-r--r--node_modules/mongodb/external-libs/bson/bson.h105
-rw-r--r--node_modules/mongodb/external-libs/bson/index.js20
-rw-r--r--node_modules/mongodb/external-libs/bson/test/test_bson.js349
-rw-r--r--node_modules/mongodb/external-libs/bson/test/test_full_bson.js218
-rw-r--r--node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js132
-rw-r--r--node_modules/mongodb/external-libs/bson/wscript39
8 files changed, 3073 insertions, 0 deletions
diff --git a/node_modules/mongodb/external-libs/bson/Makefile b/node_modules/mongodb/external-libs/bson/Makefile
new file mode 100644
index 0000000..ad877d4
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/Makefile
@@ -0,0 +1,45 @@
+NODE = node
+name = all
+JOBS = 1
+
+all:
+ rm -rf build .lock-wscript bson.node
+ node-waf configure build
+ cp -R ./build/Release/bson.node . || true
+ @$(NODE) --expose-gc test/test_bson.js
+ @$(NODE) --expose-gc test/test_full_bson.js
+ # @$(NODE) --expose-gc test/test_stackless_bson.js
+
+all_debug:
+ rm -rf build .lock-wscript bson.node
+ node-waf --debug configure build
+ cp -R ./build/Release/bson.node . || true
+ @$(NODE) --expose-gc test/test_bson.js
+ @$(NODE) --expose-gc test/test_full_bson.js
+ # @$(NODE) --expose-gc test/test_stackless_bson.js
+
+test:
+ @$(NODE) --expose-gc test/test_bson.js
+ @$(NODE) --expose-gc test/test_full_bson.js
+ # @$(NODE) --expose-gc test/test_stackless_bson.js
+
+clang:
+ rm -rf build .lock-wscript bson.node
+ CXX=clang node-waf configure build
+ cp -R ./build/Release/bson.node . || true
+ @$(NODE) --expose-gc test/test_bson.js
+ @$(NODE) --expose-gc test/test_full_bson.js
+ # @$(NODE) --expose-gc test/test_stackless_bson.js
+
+clang_debug:
+ rm -rf build .lock-wscript bson.node
+ CXX=clang node-waf --debug configure build
+ cp -R ./build/Release/bson.node . || true
+ @$(NODE) --expose-gc test/test_bson.js
+ @$(NODE) --expose-gc test/test_full_bson.js
+ # @$(NODE) --expose-gc test/test_stackless_bson.js
+
+clean:
+ rm -rf build .lock-wscript bson.node
+
+.PHONY: all \ No newline at end of file
diff --git a/node_modules/mongodb/external-libs/bson/bson.cc b/node_modules/mongodb/external-libs/bson/bson.cc
new file mode 100644
index 0000000..8906eea
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/bson.cc
@@ -0,0 +1,2165 @@
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include <v8.h>
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+#include <cstring>
+#include <cmath>
+#include <cstdlib>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include "bson.h"
+
+using namespace v8;
+using namespace node;
+using namespace std;
+
+// BSON DATA TYPES
+const uint32_t BSON_DATA_NUMBER = 1;
+const uint32_t BSON_DATA_STRING = 2;
+const uint32_t BSON_DATA_OBJECT = 3;
+const uint32_t BSON_DATA_ARRAY = 4;
+const uint32_t BSON_DATA_BINARY = 5;
+const uint32_t BSON_DATA_OID = 7;
+const uint32_t BSON_DATA_BOOLEAN = 8;
+const uint32_t BSON_DATA_DATE = 9;
+const uint32_t BSON_DATA_NULL = 10;
+const uint32_t BSON_DATA_REGEXP = 11;
+const uint32_t BSON_DATA_CODE = 13;
+const uint32_t BSON_DATA_SYMBOL = 14;
+const uint32_t BSON_DATA_CODE_W_SCOPE = 15;
+const uint32_t BSON_DATA_INT = 16;
+const uint32_t BSON_DATA_TIMESTAMP = 17;
+const uint32_t BSON_DATA_LONG = 18;
+const uint32_t BSON_DATA_MIN_KEY = 0xff;
+const uint32_t BSON_DATA_MAX_KEY = 0x7f;
+
+const int32_t BSON_INT32_MAX = (int32_t)2147483647L;
+const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L;
+
+const int64_t BSON_INT64_MAX = ((int64_t)1 << 63) - 1;
+const int64_t BSON_INT64_MIN = (int64_t)-1 << 63;
+
+const int64_t JS_INT_MAX = (int64_t)1 << 53;
+const int64_t JS_INT_MIN = (int64_t)-1 << 53;
+
+static Handle<Value> VException(const char *msg) {
+ HandleScope scope;
+ return ThrowException(Exception::Error(String::New(msg)));
+ };
+
+Persistent<FunctionTemplate> BSON::constructor_template;
+
+void BSON::Initialize(v8::Handle<v8::Object> target) {
+ // Grab the scope of the call from Node
+ HandleScope scope;
+ // Define a new function template
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("BSON"));
+
+ // Instance methods
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream);
+
+ // Experimental
+ // NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize2", CalculateObjectSize2);
+ // NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize2", BSONSerialize2);
+ // NODE_SET_METHOD(constructor_template->GetFunction(), "serialize2", BSONSerialize2);
+
+ target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction());
+}
+
+// Create a new instance of BSON and assing it the existing context
+Handle<Value> BSON::New(const Arguments &args) {
+ HandleScope scope;
+
+ // Check that we have an array
+ if(args.Length() == 1 && args[0]->IsArray()) {
+ // Cast the array to a local reference
+ Local<Array> array = Local<Array>::Cast(args[0]);
+
+ if(array->Length() > 0) {
+ // Create a bson object instance and return it
+ BSON *bson = new BSON();
+
+ // Setup pre-allocated comparision objects
+ bson->_bsontypeString = Persistent<String>::New(String::New("_bsontype"));
+ bson->_longLowString = Persistent<String>::New(String::New("low_"));
+ bson->_longHighString = Persistent<String>::New(String::New("high_"));
+ bson->_objectIDidString = Persistent<String>::New(String::New("id"));
+ bson->_binaryPositionString = Persistent<String>::New(String::New("position"));
+ bson->_binarySubTypeString = Persistent<String>::New(String::New("sub_type"));
+ bson->_binaryBufferString = Persistent<String>::New(String::New("buffer"));
+ bson->_doubleValueString = Persistent<String>::New(String::New("value"));
+ bson->_symbolValueString = Persistent<String>::New(String::New("value"));
+ bson->_dbRefRefString = Persistent<String>::New(String::New("$ref"));
+ bson->_dbRefIdRefString = Persistent<String>::New(String::New("$id"));
+ bson->_dbRefDbRefString = Persistent<String>::New(String::New("$db"));
+ bson->_dbRefNamespaceString = Persistent<String>::New(String::New("namespace"));
+ bson->_dbRefDbString = Persistent<String>::New(String::New("db"));
+ bson->_dbRefOidString = Persistent<String>::New(String::New("oid"));
+
+ // total number of found classes
+ uint32_t numberOfClasses = 0;
+
+ // Iterate over all entries to save the instantiate funtions
+ for(uint32_t i = 0; i < array->Length(); i++) {
+ // Let's get a reference to the function
+ Local<Function> func = Local<Function>::Cast(array->Get(i));
+ Local<String> functionName = func->GetName()->ToString();
+
+ // Save the functions making them persistant handles (they don't get collected)
+ if(functionName->StrictEquals(String::New("Long"))) {
+ bson->longConstructor = Persistent<Function>::New(func);
+ bson->longString = Persistent<String>::New(String::New("Long"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("ObjectID"))) {
+ bson->objectIDConstructor = Persistent<Function>::New(func);
+ bson->objectIDString = Persistent<String>::New(String::New("ObjectID"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("Binary"))) {
+ bson->binaryConstructor = Persistent<Function>::New(func);
+ bson->binaryString = Persistent<String>::New(String::New("Binary"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("Code"))) {
+ bson->codeConstructor = Persistent<Function>::New(func);
+ bson->codeString = Persistent<String>::New(String::New("Code"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("DBRef"))) {
+ bson->dbrefConstructor = Persistent<Function>::New(func);
+ bson->dbrefString = Persistent<String>::New(String::New("DBRef"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("Symbol"))) {
+ bson->symbolConstructor = Persistent<Function>::New(func);
+ bson->symbolString = Persistent<String>::New(String::New("Symbol"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("Double"))) {
+ bson->doubleConstructor = Persistent<Function>::New(func);
+ bson->doubleString = Persistent<String>::New(String::New("Double"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("Timestamp"))) {
+ bson->timestampConstructor = Persistent<Function>::New(func);
+ bson->timestampString = Persistent<String>::New(String::New("Timestamp"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("MinKey"))) {
+ bson->minKeyConstructor = Persistent<Function>::New(func);
+ bson->minKeyString = Persistent<String>::New(String::New("MinKey"));
+ numberOfClasses = numberOfClasses + 1;
+ } else if(functionName->StrictEquals(String::New("MaxKey"))) {
+ bson->maxKeyConstructor = Persistent<Function>::New(func);
+ bson->maxKeyString = Persistent<String>::New(String::New("MaxKey"));
+ numberOfClasses = numberOfClasses + 1;
+ }
+ }
+
+ // Check if we have the right number of constructors otherwise throw an error
+ if(numberOfClasses != 10) {
+ // Destroy object
+ delete(bson);
+ // Fire exception
+ return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
+ } else {
+ bson->Wrap(args.This());
+ return args.This();
+ }
+ } else {
+ return VException("No types passed in");
+ }
+ } else {
+ return VException("Argument passed in must be an array of types");
+ }
+}
+
+void BSON::write_int32(char *data, uint32_t value) {
+ // Write the int to the char*
+ memcpy(data, &value, 4);
+}
+
+void BSON::write_double(char *data, double value) {
+ // Write the double to the char*
+ memcpy(data, &value, 8);
+}
+
+void BSON::write_int64(char *data, int64_t value) {
+ // Write the int to the char*
+ memcpy(data, &value, 8);
+}
+
+char *BSON::check_key(Local<String> key) {
+ // Allocate space for they key string
+ char *key_str = (char *)malloc(key->Utf8Length() * sizeof(char) + 1);
+ // Error string
+ char *error_str = (char *)malloc(256 * sizeof(char));
+ // Decode the key
+ ssize_t len = DecodeBytes(key, BINARY);
+ DecodeWrite(key_str, len, key, BINARY);
+ *(key_str + key->Utf8Length()) = '\0';
+ // Check if we have a valid key
+ if(key->Utf8Length() > 0 && *(key_str) == '$') {
+ // Create the string
+ sprintf(error_str, "key %s must not start with '$'", key_str);
+ // Free up memory
+ free(key_str);
+ // Throw exception with string
+ throw error_str;
+ } else if(key->Utf8Length() > 0 && strchr(key_str, '.') != NULL) {
+ // Create the string
+ sprintf(error_str, "key %s must not contain '.'", key_str);
+ // Free up memory
+ free(key_str);
+ // Throw exception with string
+ throw error_str;
+ }
+ // Free allocated space
+ free(key_str);
+ free(error_str);
+ // Return No check key error
+ return NULL;
+}
+
+const char* BSON::ToCString(const v8::String::Utf8Value& value) {
+ return *value ? *value : "<string conversion failed>";
+}
+
+Handle<Value> BSON::decodeDBref(BSON *bson, Local<Value> ref, Local<Value> oid, Local<Value> db) {
+ HandleScope scope;
+ Local<Value> argv[] = {ref, oid, db};
+ Handle<Value> dbrefObj = bson->dbrefConstructor->NewInstance(3, argv);
+ return scope.Close(dbrefObj);
+}
+
+Handle<Value> BSON::decodeCode(BSON *bson, char *code, Handle<Value> scope_object) {
+ HandleScope scope;
+
+ Local<Value> argv[] = {String::New(code), scope_object->ToObject()};
+ Handle<Value> codeObj = bson->codeConstructor->NewInstance(2, argv);
+ return scope.Close(codeObj);
+}
+
+Handle<Value> BSON::decodeBinary(BSON *bson, uint32_t sub_type, uint32_t number_of_bytes, char *data) {
+ HandleScope scope;
+
+ // Create a buffer object that wraps the raw stream
+ Buffer *bufferObj = Buffer::New(data, number_of_bytes);
+ // Arguments to be passed to create the binary
+ Handle<Value> argv[] = {bufferObj->handle_, Uint32::New(sub_type)};
+ // Return the buffer handle
+ Local<Object> bufferObjHandle = bson->binaryConstructor->NewInstance(2, argv);
+ // Close the scope
+ return scope.Close(bufferObjHandle);
+}
+
+Handle<Value> BSON::decodeOid(BSON *bson, char *oid) {
+ HandleScope scope;
+
+ // Encode the string (string - null termiating character)
+ Local<Value> bin_value = Encode(oid, 12, BINARY)->ToString();
+
+ // Return the id object
+ Local<Value> argv[] = {bin_value};
+ Local<Object> oidObj = bson->objectIDConstructor->NewInstance(1, argv);
+ return scope.Close(oidObj);
+}
+
+Handle<Value> BSON::decodeLong(BSON *bson, char *data, uint32_t index) {
+ HandleScope scope;
+
+ // Decode the integer value
+ int32_t lowBits = 0;
+ int32_t highBits = 0;
+ memcpy(&lowBits, (data + index), 4);
+ memcpy(&highBits, (data + index + 4), 4);
+
+ // Decode 64bit value
+ int64_t value = 0;
+ memcpy(&value, (data + index), 8);
+
+ // If value is < 2^53 and >-2^53
+ if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
+ int64_t finalValue = 0;
+ memcpy(&finalValue, (data + index), 8);
+ return scope.Close(Number::New(finalValue));
+ }
+
+ // Instantiate the js object and pass it back
+ Local<Value> argv[] = {Int32::New(lowBits), Int32::New(highBits)};
+ Local<Object> longObject = bson->longConstructor->NewInstance(2, argv);
+ return scope.Close(longObject);
+}
+
+Handle<Value> BSON::decodeTimestamp(BSON *bson, char *data, uint32_t index) {
+ HandleScope scope;
+
+ // Decode the integer value
+ int32_t lowBits = 0;
+ int32_t highBits = 0;
+ memcpy(&lowBits, (data + index), 4);
+ memcpy(&highBits, (data + index + 4), 4);
+
+ // Build timestamp
+ Local<Value> argv[] = {Int32::New(lowBits), Int32::New(highBits)};
+ Handle<Value> timestamp_obj = bson->timestampConstructor->NewInstance(2, argv);
+ return scope.Close(timestamp_obj);
+}
+
+// Search for 0 terminated C string and return the string
+char* BSON::extract_string(char *data, uint32_t offset) {
+ char *prt = strchr((data + offset), '\0');
+ if(prt == NULL) return NULL;
+ // Figure out the length of the string
+ uint32_t length = (prt - data) - offset;
+ // Allocate memory for the new string
+ char *string_name = (char *)malloc((length * sizeof(char)) + 1);
+ // Copy the variable into the string_name
+ strncpy(string_name, (data + offset), length);
+ // Ensure the string is null terminated
+ *(string_name + length) = '\0';
+ // Return the unpacked string
+ return string_name;
+}
+
+// Decode a byte
+uint16_t BSON::deserialize_int8(char *data, uint32_t offset) {
+ uint16_t value = 0;
+ value |= *(data + offset + 0);
+ return value;
+}
+
+// Requires a 4 byte char array
+uint32_t BSON::deserialize_int32(char* data, uint32_t offset) {
+ uint32_t value = 0;
+ memcpy(&value, (data + offset), 4);
+ return value;
+}
+
+//------------------------------------------------------------------------------------------------
+//
+// Experimental
+//
+//------------------------------------------------------------------------------------------------
+Handle<Value> BSON::CalculateObjectSize2(const Arguments &args) {
+ HandleScope scope;
+ // Ensure we have a valid object
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
+ if(args.Length() > 1) return VException("One argument required - [object]");
+ // Calculate size of the object
+ uint32_t object_size = BSON::calculate_object_size2(args[0]);
+ // Return the object size
+ return scope.Close(Uint32::New(object_size));
+}
+
+uint32_t BSON::calculate_object_size2(Handle<Value> value) {
+ // Final object size
+ uint32_t object_size = (4 + 1);
+ uint32_t stackIndex = 0;
+ // Controls the flow
+ bool done = false;
+ bool finished = false;
+
+ // Current object we are processing
+ Local<Object> currentObject = value->ToObject();
+
+ // Current list of object keys
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> keys = currentObject->GetPropertyNames();
+ #else
+ Local<Array> keys = currentObject->GetOwnPropertyNames();
+ #endif
+
+ // Contains pointer to keysIndex
+ uint32_t keysIndex = 0;
+ uint32_t keysLength = keys->Length();
+
+ // printf("=================================================================================\n");
+ // printf("Start serializing\n");
+
+ while(!done) {
+ // If the index is bigger than the number of keys for the object
+ // we finished up the previous object and are ready for the next one
+ if(keysIndex >= keysLength) {
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ keys = currentObject->GetPropertyNames();
+ #else
+ keys = currentObject->GetOwnPropertyNames();
+ #endif
+ keysLength = keys->Length();
+ }
+
+ // Iterate over all the keys
+ while(keysIndex < keysLength) {
+ // Fetch the key name
+ Local<String> name = keys->Get(keysIndex++)->ToString();
+ // Fetch the object related to the key
+ Local<Value> value = currentObject->Get(name);
+ // Add size of the name, plus zero, plus type
+ object_size += name->Utf8Length() + 1 + 1;
+
+ // If we have a string
+ if(value->IsString()) {
+ object_size += value->ToString()->Utf8Length() + 1 + 4;
+ } else if(value->IsNumber()) {
+ // Check if we have a float value or a long value
+ Local<Number> number = value->ToNumber();
+ double d_number = number->NumberValue();
+ int64_t l_number = number->IntegerValue();
+ // Check if we have a double value and not a int64
+ double d_result = d_number - l_number;
+ // If we have a value after subtracting the integer value we have a float
+ if(d_result > 0 || d_result < 0) {
+ object_size = object_size + 8;
+ } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) {
+ object_size = object_size + 4;
+ } else {
+ object_size = object_size + 8;
+ }
+ } else if(value->IsBoolean()) {
+ object_size = object_size + 1;
+ } else if(value->IsDate()) {
+ object_size = object_size + 8;
+ } else if(value->IsRegExp()) {
+ // Fetch the string for the regexp
+ Handle<RegExp> regExp = Handle<RegExp>::Cast(value);
+ ssize_t len = DecodeBytes(regExp->GetSource(), UTF8);
+ int flags = regExp->GetFlags();
+
+ // global
+ if((flags & (1 << 0)) != 0) len++;
+ // ignorecase
+ if((flags & (1 << 1)) != 0) len++;
+ //multiline
+ if((flags & (1 << 2)) != 0) len++;
+ // if((flags & (1 << 2)) != 0) len++;
+ // Calculate the space needed for the regexp: size of string - 2 for the /'ses +2 for null termiations
+ object_size = object_size + len + 2;
+ } else if(value->IsNull() || value->IsUndefined()) {
+ }
+ // } else if(value->IsNumber()) {
+ // // Check if we have a float value or a long value
+ // Local<Number> number = value->ToNumber();
+ // double d_number = number->NumberValue();
+ // int64_t l_number = number->IntegerValue();
+ // // Check if we have a double value and not a int64
+ // double d_result = d_number - l_number;
+ // // If we have a value after subtracting the integer value we have a float
+ // if(d_result > 0 || d_result < 0) {
+ // object_size = name->Utf8Length() + 1 + object_size + 8 + 1;
+ // } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) {
+ // object_size = name->Utf8Length() + 1 + object_size + 4 + 1;
+ // } else {
+ // object_size = name->Utf8Length() + 1 + object_size + 8 + 1;
+ // }
+ // } else if(value->IsObject()) {
+ // printf("------------- hello\n");
+ // }
+ }
+
+ // If we have finished all the keys
+ if(keysIndex == keysLength) {
+ finished = false;
+ }
+
+ // Validate the stack
+ if(stackIndex == 0) {
+ // printf("======================================================================== 3\n");
+ done = true;
+ } else if(finished || keysIndex == keysLength) {
+ // Pop off the stack
+ stackIndex = stackIndex - 1;
+ // Fetch the current object stack
+ // vector<Local<Value> > currentObjectStored = stack.back();
+ // stack.pop_back();
+ // // Unroll the current object
+ // currentObject = currentObjectStored.back()->ToObject();
+ // currentObjectStored.pop_back();
+ // // Unroll the keysIndex
+ // keys = Local<Array>::Cast(currentObjectStored.back()->ToObject());
+ // currentObjectStored.pop_back();
+ // // Unroll the keysIndex
+ // keysIndex = currentObjectStored.back()->ToUint32()->Value();
+ // currentObjectStored.pop_back();
+ // // Check if we finished up
+ // if(keysIndex == keys->Length()) {
+ // finished = true;
+ // }
+ }
+ }
+
+ return object_size;
+}
+
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+Handle<Value> BSON::BSONDeserialize(const Arguments &args) {
+ HandleScope scope;
+
+ // Ensure that we have an parameter
+ if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1.");
+ if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1.");
+ // Throw an exception if the argument is not of type Buffer
+ if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String.");
+
+ // Define pointer to data
+ char *data;
+ Local<Object> obj = args[0]->ToObject();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
+ if(Buffer::HasInstance(obj)) {
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ data = buffer->data();
+ uint32_t length = buffer->length();
+ #else
+ data = Buffer::Data(obj);
+ uint32_t length = Buffer::Length(obj);
+ #endif
+
+ // Validate that we have at least 5 bytes
+ if(length < 5) {
+ return VException("corrupt bson message < 5 bytes long");
+ }
+
+ // Deserialize the data
+ return BSON::deserialize(bson, data, length, 0, NULL);
+ } else {
+ // The length of the data for this encoding
+ ssize_t len = DecodeBytes(args[0], BINARY);
+
+ // Validate that we have at least 5 bytes
+ if(len < 5) {
+ return VException("corrupt bson message < 5 bytes long");
+ }
+
+ // Let's define the buffer size
+ data = (char *)malloc(len);
+ // Write the data to the buffer from the string object
+ ssize_t written = DecodeWrite(data, len, args[0], BINARY);
+ // Assert that we wrote the same number of bytes as we have length
+ assert(written == len);
+ // Get result
+ Handle<Value> result = BSON::deserialize(bson, data, len, 0, NULL);
+ // Free memory
+ free(data);
+ // Deserialize the content
+ return result;
+ }
+}
+
+// Deserialize the stream
+Handle<Value> BSON::deserialize(BSON *bson, char *data, uint32_t inDataLength, uint32_t startIndex, bool is_array_item) {
+ HandleScope scope;
+ // Holds references to the objects that are going to be returned
+ Local<Object> return_data = Object::New();
+ Local<Array> return_array = Array::New();
+ // The current index in the char data
+ uint32_t index = startIndex;
+ // Decode the size of the BSON data structure
+ uint32_t size = BSON::deserialize_int32(data, index);
+
+ // If we have an illegal message size
+ if(size > inDataLength) return VException("corrupt bson message");
+
+ // Data length
+ uint32_t dataLength = index + size;
+
+ // Adjust the index to point to next piece
+ index = index + 4;
+
+ // While we have data left let's decode
+ while(index < dataLength) {
+ // Read the first to bytes to indicate the type of object we are decoding
+ uint8_t type = BSON::deserialize_int8(data, index);
+ // Adjust index to skip type byte
+ index = index + 1;
+
+ if(type == BSON_DATA_STRING) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Read the length of the string (next 4 bytes)
+ uint32_t string_size = BSON::deserialize_int32(data, index);
+ // Adjust index to point to start of string
+ index = index + 4;
+ // Decode the string and add zero terminating value at the end of the string
+ char *value = (char *)malloc((string_size * sizeof(char)));
+ strncpy(value, (data + index), string_size);
+ // Encode the string (string - null termiating character)
+ Local<Value> utf8_encoded_str = Encode(value, string_size - 1, UTF8)->ToString();
+ // Add the value to the data
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), utf8_encoded_str);
+ } else {
+ return_data->ForceSet(String::New(string_name), utf8_encoded_str);
+ }
+
+ // Adjust index
+ index = index + string_size;
+ // Free up the memory
+ free(value);
+ free(string_name);
+ } else if(type == BSON_DATA_INT) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Decode the integer value
+ uint32_t value = 0;
+ memcpy(&value, (data + index), 4);
+
+ // Adjust the index for the size of the value
+ index = index + 4;
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Integer::New(insert_index), Integer::New(value));
+ } else {
+ return_data->ForceSet(String::New(string_name), Integer::New(value));
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_TIMESTAMP) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), BSON::decodeTimestamp(bson, data, index));
+ } else {
+ return_data->ForceSet(String::New(string_name), BSON::decodeTimestamp(bson, data, index));
+ }
+
+ // Adjust the index for the size of the value
+ index = index + 8;
+
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_LONG) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), BSON::decodeLong(bson, data, index));
+ } else {
+ return_data->ForceSet(String::New(string_name), BSON::decodeLong(bson, data, index));
+ }
+
+ // Adjust the index for the size of the value
+ index = index + 8;
+
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_NUMBER) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Decode the integer value
+ double value = 0;
+ memcpy(&value, (data + index), 8);
+ // Adjust the index for the size of the value
+ index = index + 8;
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), Number::New(value));
+ } else {
+ return_data->ForceSet(String::New(string_name), Number::New(value));
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_MIN_KEY) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Create new MinKey
+ Local<Object> minKey = bson->minKeyConstructor->NewInstance();
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), minKey);
+ } else {
+ return_data->ForceSet(String::New(string_name), minKey);
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_MAX_KEY) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Create new MinKey
+ Local<Object> maxKey = bson->maxKeyConstructor->NewInstance();
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), maxKey);
+ } else {
+ return_data->ForceSet(String::New(string_name), maxKey);
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_NULL) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), Null());
+ } else {
+ return_data->ForceSet(String::New(string_name), Null());
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_BOOLEAN) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Decode the boolean value
+ char bool_value = *(data + index);
+ // Adjust the index for the size of the value
+ index = index + 1;
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), bool_value == 1 ? Boolean::New(true) : Boolean::New(false));
+ } else {
+ return_data->ForceSet(String::New(string_name), bool_value == 1 ? Boolean::New(true) : Boolean::New(false));
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_DATE) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Decode the value 64 bit integer
+ int64_t value = 0;
+ memcpy(&value, (data + index), 8);
+ // Adjust the index for the size of the value
+ index = index + 8;
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), Date::New((double)value));
+ } else {
+ return_data->ForceSet(String::New(string_name), Date::New((double)value));
+ }
+ // Free up the memory
+ free(string_name);
+ } else if(type == BSON_DATA_REGEXP) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Length variable
+ int32_t length_regexp = 0;
+ char chr;
+
+ // Locate end of the regexp expression \0
+ while((chr = *(data + index + length_regexp)) != '\0') {
+ length_regexp = length_regexp + 1;
+ }
+
+ // Contains the reg exp
+ char *reg_exp = (char *)malloc(length_regexp * sizeof(char) + 2);
+ // Copy the regexp from the data to the char *
+ memcpy(reg_exp, (data + index), (length_regexp + 1));
+ // Adjust the index to skip the first part of the regular expression
+ index = index + length_regexp + 1;
+
+ // Reset the length
+ int32_t options_length = 0;
+ // Locate the end of the options for the regexp terminated with a '\0'
+ while((chr = *(data + index + options_length)) != '\0') {
+ options_length = options_length + 1;
+ }
+
+ // Contains the reg exp
+ char *options = (char *)malloc(options_length * sizeof(char) + 1);
+ // Copy the options from the data to the char *
+ memcpy(options, (data + index), (options_length + 1));
+ // Adjust the index to skip the option part of the regular expression
+ index = index + options_length + 1;
+ // ARRRRGH Google does not expose regular expressions through the v8 api
+ // Have to use Script to instantiate the object (slower)
+
+ // Generate the string for execution in the string context
+ int flag = 0;
+
+ for(int i = 0; i < options_length; i++) {
+ // Multiline
+ if(*(options + i) == 'm') {
+ flag = flag | 4;
+ } else if(*(options + i) == 'i') {
+ flag = flag | 2;
+ }
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), RegExp::New(String::New(reg_exp), (v8::RegExp::Flags)flag));
+ } else {
+ return_data->ForceSet(String::New(string_name), RegExp::New(String::New(reg_exp), (v8::RegExp::Flags)flag));
+ }
+
+ // Free memory
+ free(reg_exp);
+ free(options);
+ free(string_name);
+ } else if(type == BSON_DATA_OID) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // The id string
+ char *oid_string = (char *)malloc(12 * sizeof(char));
+ // Copy the options from the data to the char *
+ memcpy(oid_string, (data + index), 12);
+
+ // Adjust the index
+ index = index + 12;
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), BSON::decodeOid(bson, oid_string));
+ } else {
+ return_data->ForceSet(String::New(string_name), BSON::decodeOid(bson, oid_string));
+ }
+
+ // Free memory
+ free(oid_string);
+ free(string_name);
+ } else if(type == BSON_DATA_BINARY) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Read the binary data size
+ uint32_t number_of_bytes = BSON::deserialize_int32(data, index);
+ // Adjust the index
+ index = index + 4;
+ // Decode the subtype, ensure it's positive
+ uint32_t sub_type = (int)*(data + index) & 0xff;
+ // Adjust the index
+ index = index + 1;
+ // Copy the binary data into a buffer
+ char *buffer = (char *)malloc(number_of_bytes * sizeof(char) + 1);
+ memcpy(buffer, (data + index), number_of_bytes);
+ *(buffer + number_of_bytes) = '\0';
+
+ // Adjust the index
+ index = index + number_of_bytes;
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), BSON::decodeBinary(bson, sub_type, number_of_bytes, buffer));
+ } else {
+ return_data->ForceSet(String::New(string_name), BSON::decodeBinary(bson, sub_type, number_of_bytes, buffer));
+ }
+ // Free memory
+ free(buffer);
+ free(string_name);
+ } else if(type == BSON_DATA_SYMBOL) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Read the length of the string (next 4 bytes)
+ uint32_t string_size = BSON::deserialize_int32(data, index);
+ // Adjust index to point to start of string
+ index = index + 4;
+ // Decode the string and add zero terminating value at the end of the string
+ char *value = (char *)malloc((string_size * sizeof(char)));
+ strncpy(value, (data + index), string_size);
+ // Encode the string (string - null termiating character)
+ Local<Value> utf8_encoded_str = Encode(value, string_size - 1, UTF8)->ToString();
+
+ // Wrap up the string in a Symbol Object
+ Local<Value> argv[] = {utf8_encoded_str};
+ Handle<Value> symbolObj = bson->symbolConstructor->NewInstance(1, argv);
+
+ // Add the value to the data
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), symbolObj);
+ } else {
+ return_data->ForceSet(String::New(string_name), symbolObj);
+ }
+
+ // Adjust index
+ index = index + string_size;
+ // Free up the memory
+ free(value);
+ free(string_name);
+ } else if(type == BSON_DATA_CODE) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Read the string size
+ uint32_t string_size = BSON::deserialize_int32(data, index);
+ // Adjust the index
+ index = index + 4;
+ // Read the string
+ char *code = (char *)malloc(string_size * sizeof(char) + 1);
+ // Copy string + terminating 0
+ memcpy(code, (data + index), string_size);
+
+ // Define empty scope object
+ Handle<Value> scope_object = Object::New();
+
+ // Define the try catch block
+ TryCatch try_catch;
+ // Decode the code object
+ Handle<Value> obj = BSON::decodeCode(bson, code, scope_object);
+ // If an error was thrown push it up the chain
+ if(try_catch.HasCaught()) {
+ free(string_name);
+ free(code);
+ // Rethrow exception
+ return try_catch.ReThrow();
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), obj);
+ } else {
+ return_data->ForceSet(String::New(string_name), obj);
+ }
+
+ // Clean up memory allocation
+ free(code);
+ free(string_name);
+ } else if(type == BSON_DATA_CODE_W_SCOPE) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Total number of bytes after array index
+ uint32_t total_code_size = BSON::deserialize_int32(data, index);
+ // Adjust the index
+ index = index + 4;
+ // Read the string size
+ uint32_t string_size = BSON::deserialize_int32(data, index);
+ // Adjust the index
+ index = index + 4;
+ // Read the string
+ char *code = (char *)malloc(string_size * sizeof(char) + 1);
+ // Copy string + terminating 0
+ memcpy(code, (data + index), string_size);
+ // Adjust the index
+ index = index + string_size;
+ // Get the scope object (bson object)
+ uint32_t bson_object_size = total_code_size - string_size - 8;
+ // Allocate bson object buffer and copy out the content
+ char *bson_buffer = (char *)malloc(bson_object_size * sizeof(char));
+ memcpy(bson_buffer, (data + index), bson_object_size);
+ // Adjust the index
+ index = index + bson_object_size;
+ // Parse the bson object
+ Handle<Value> scope_object = BSON::deserialize(bson, bson_buffer, inDataLength, 0, false);
+ // Define the try catch block
+ TryCatch try_catch;
+ // Decode the code object
+ Handle<Value> obj = BSON::decodeCode(bson, code, scope_object);
+ // If an error was thrown push it up the chain
+ if(try_catch.HasCaught()) {
+ // Clean up memory allocation
+ free(string_name);
+ free(bson_buffer);
+ free(code);
+ // Rethrow exception
+ return try_catch.ReThrow();
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), obj);
+ } else {
+ return_data->ForceSet(String::New(string_name), obj);
+ }
+
+ // Clean up memory allocation
+ free(code);
+ free(bson_buffer);
+ free(string_name);
+ } else if(type == BSON_DATA_OBJECT) {
+ // If this is the top level object we need to skip the undecoding
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Get the object size
+ uint32_t bson_object_size = BSON::deserialize_int32(data, index);
+ // Define the try catch block
+ TryCatch try_catch;
+ // Decode the code object
+ Handle<Value> obj = BSON::deserialize(bson, data + index, inDataLength, 0, false);
+ // Adjust the index
+ index = index + bson_object_size;
+ // If an error was thrown push it up the chain
+ if(try_catch.HasCaught()) {
+ // Rethrow exception
+ return try_catch.ReThrow();
+ }
+
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), obj);
+ } else {
+ return_data->ForceSet(String::New(string_name), obj);
+ }
+
+ // Clean up memory allocation
+ free(string_name);
+ } else if(type == BSON_DATA_ARRAY) {
+ // Read the null terminated index String
+ char *string_name = BSON::extract_string(data, index);
+ if(string_name == NULL) return VException("Invalid C String found.");
+ // Let's create a new string
+ index = index + strlen(string_name) + 1;
+ // Handle array value if applicable
+ uint32_t insert_index = 0;
+ if(is_array_item) {
+ insert_index = atoi(string_name);
+ }
+
+ // Get the size
+ uint32_t array_size = BSON::deserialize_int32(data, index);
+ // Define the try catch block
+ TryCatch try_catch;
+
+ // Decode the code object
+ Handle<Value> obj = BSON::deserialize(bson, data + index, inDataLength, 0, true);
+ // If an error was thrown push it up the chain
+ if(try_catch.HasCaught()) {
+ // Rethrow exception
+ return try_catch.ReThrow();
+ }
+ // Adjust the index for the next value
+ index = index + array_size;
+ // Add the element to the object
+ if(is_array_item) {
+ return_array->Set(Number::New(insert_index), obj);
+ } else {
+ return_data->ForceSet(String::New(string_name), obj);
+ }
+ // Clean up memory allocation
+ free(string_name);
+ }
+ }
+
+ // Check if we have a db reference
+ if(!is_array_item && return_data->Has(String::New("$ref")) && return_data->Has(String::New("$id"))) {
+ Handle<Value> dbrefValue = BSON::decodeDBref(bson, return_data->Get(String::New("$ref")), return_data->Get(String::New("$id")), return_data->Get(String::New("$db")));
+ return scope.Close(dbrefValue);
+ }
+
+ // Return the data object to javascript
+ if(is_array_item) {
+ return scope.Close(return_array);
+ } else {
+ return scope.Close(return_data);
+ }
+}
+
+Handle<Value> BSON::BSONSerialize(const Arguments &args) {
+ HandleScope scope;
+
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+ if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ uint32_t object_size = 0;
+ // Calculate the total size of the document in binary form to ensure we only allocate memory once
+ // With serialize function
+ if(args.Length() == 4) {
+ object_size = BSON::calculate_object_size(bson, args[0], args[3]->BooleanValue());
+ } else {
+ object_size = BSON::calculate_object_size(bson, args[0], false);
+ }
+
+ // Allocate the memory needed for the serializtion
+ char *serialized_object = (char *)malloc(object_size * sizeof(char));
+ // Catch any errors
+ try {
+ // Check if we have a boolean value
+ bool check_key = false;
+ if(args.Length() >= 3 && args[1]->IsBoolean()) {
+ check_key = args[1]->BooleanValue();
+ }
+
+ // Check if we have a boolean value
+ bool serializeFunctions = false;
+ if(args.Length() == 4 && args[1]->IsBoolean()) {
+ serializeFunctions = args[3]->BooleanValue();
+ }
+
+ // Serialize the object
+ BSON::serialize(bson, serialized_object, 0, Null(), args[0], check_key, serializeFunctions);
+ } catch(char *err_msg) {
+ // Free up serialized object space
+ free(serialized_object);
+ V8::AdjustAmountOfExternalAllocatedMemory(-object_size);
+ // Throw exception with the string
+ Handle<Value> error = VException(err_msg);
+ // free error message
+ free(err_msg);
+ // Return error
+ return error;
+ }
+
+ // Write the object size
+ BSON::write_int32((serialized_object), object_size);
+
+ // If we have 3 arguments
+ if(args.Length() == 3 || args.Length() == 4) {
+ // Local<Boolean> asBuffer = args[2]->ToBoolean();
+ Buffer *buffer = Buffer::New(serialized_object, object_size);
+ // Release the serialized string
+ free(serialized_object);
+ return scope.Close(buffer->handle_);
+ } else {
+ // Encode the string (string - null termiating character)
+ Local<Value> bin_value = Encode(serialized_object, object_size, BINARY)->ToString();
+ // Return the serialized content
+ return bin_value;
+ }
+}
+
+Handle<Value> BSON::CalculateObjectSize(const Arguments &args) {
+ HandleScope scope;
+ // Ensure we have a valid object
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]");
+ if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Object size
+ uint32_t object_size = 0;
+ // Check if we have our argument, calculate size of the object
+ if(args.Length() >= 2) {
+ object_size = BSON::calculate_object_size(bson, args[0], args[1]->BooleanValue());
+ } else {
+ object_size = BSON::calculate_object_size(bson, args[0], false);
+ }
+
+ // Return the object size
+ return scope.Close(Uint32::New(object_size));
+}
+
+uint32_t BSON::calculate_object_size(BSON *bson, Handle<Value> value, bool serializeFunctions) {
+ uint32_t object_size = 0;
+
+ // If we have an object let's unwrap it and calculate the sub sections
+ if(value->IsString()) {
+ // Let's calculate the size the string adds, length + type(1 byte) + size(4 bytes)
+ object_size += value->ToString()->Utf8Length() + 1 + 4;
+ } else if(value->IsNumber()) {
+ // Check if we have a float value or a long value
+ Local<Number> number = value->ToNumber();
+ double d_number = number->NumberValue();
+ int64_t l_number = number->IntegerValue();
+ // Check if we have a double value and not a int64
+ double d_result = d_number - l_number;
+ // If we have a value after subtracting the integer value we have a float
+ if(d_result > 0 || d_result < 0) {
+ object_size = object_size + 8;
+ } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) {
+ object_size = object_size + 4;
+ } else {
+ object_size = object_size + 8;
+ }
+ } else if(value->IsBoolean()) {
+ object_size = object_size + 1;
+ } else if(value->IsDate()) {
+ object_size = object_size + 8;
+ } else if(value->IsRegExp()) {
+ // Fetch the string for the regexp
+ Handle<RegExp> regExp = Handle<RegExp>::Cast(value);
+ ssize_t len = DecodeBytes(regExp->GetSource(), UTF8);
+ int flags = regExp->GetFlags();
+
+ // global
+ if((flags & (1 << 0)) != 0) len++;
+ // ignorecase
+ if((flags & (1 << 1)) != 0) len++;
+ //multiline
+ if((flags & (1 << 2)) != 0) len++;
+ // if((flags & (1 << 2)) != 0) len++;
+ // Calculate the space needed for the regexp: size of string - 2 for the /'ses +2 for null termiations
+ object_size = object_size + len + 2;
+ } else if(value->IsNull() || value->IsUndefined()) {
+ } else if(value->IsArray()) {
+ // Cast to array
+ Local<Array> array = Local<Array>::Cast(value->ToObject());
+ // Turn length into string to calculate the size of all the strings needed
+ char *length_str = (char *)malloc(256 * sizeof(char));
+ // Calculate the size of each element
+ for(uint32_t i = 0; i < array->Length(); i++) {
+ // Add "index" string size for each element
+ sprintf(length_str, "%d", i);
+ // Add the size of the string length
+ uint32_t label_length = strlen(length_str) + 1;
+ // Add the type definition size for each item
+ object_size = object_size + label_length + 1;
+ // Add size of the object
+ uint32_t object_length = BSON::calculate_object_size(bson, array->Get(Integer::New(i)), serializeFunctions);
+ object_size = object_size + object_length;
+ }
+ // Add the object size
+ object_size = object_size + 4 + 1;
+ // Free up memory
+ free(length_str);
+ } else if(value->IsFunction()) {
+ if(serializeFunctions) {
+ object_size += value->ToString()->Utf8Length() + 4 + 1;
+ }
+ } else if(value->ToObject()->Has(bson->_bsontypeString)) {
+ // Handle holder
+ Local<String> constructorString = value->ToObject()->GetConstructorName();
+
+ // BSON type object, avoid non-needed checking unless we have a type
+ if(bson->longString->StrictEquals(constructorString)) {
+ object_size = object_size + 8;
+ } else if(bson->timestampString->StrictEquals(constructorString)) {
+ object_size = object_size + 8;
+ } else if(bson->objectIDString->StrictEquals(constructorString)) {
+ object_size = object_size + 12;
+ } else if(bson->binaryString->StrictEquals(constructorString)) {
+ // Unpack the object and encode
+ Local<Uint32> positionObj = value->ToObject()->Get(String::New("position"))->ToUint32();
+ // Adjust the object_size, binary content lengt + total size int32 + binary size int32 + subtype
+ object_size += positionObj->Value() + 4 + 1;
+ } else if(bson->codeString->StrictEquals(constructorString)) {
+ // Unpack the object and encode
+ Local<Object> obj = value->ToObject();
+ // Get the function
+ Local<String> function = obj->Get(String::New("code"))->ToString();
+ // Get the scope object
+ Local<Object> scope = obj->Get(String::New("scope"))->ToObject();
+
+ // For Node < 0.6.X use the GetPropertyNames
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
+ #else
+ uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
+ #endif
+
+ // Check if the scope has any parameters
+ // Let's calculate the size the code object adds adds
+ if(propertyNameLength > 0) {
+ object_size += function->Utf8Length() + 4 + BSON::calculate_object_size(bson, scope, serializeFunctions) + 4 + 1;
+ } else {
+ object_size += function->Utf8Length() + 4 + 1;
+ }
+ } else if(bson->dbrefString->StrictEquals(constructorString)) {
+ // Unpack the dbref
+ Local<Object> dbref = value->ToObject();
+ // Create an object containing the right namespace variables
+ Local<Object> obj = Object::New();
+ // Build the new object
+ obj->Set(bson->_dbRefRefString, dbref->Get(bson->_dbRefNamespaceString));
+ obj->Set(bson->_dbRefIdRefString, dbref->Get(bson->_dbRefOidString));
+ if(!dbref->Get(bson->_dbRefDbString)->IsNull() && !dbref->Get(bson->_dbRefDbString)->IsUndefined()) obj->Set(bson->_dbRefDbRefString, dbref->Get(bson->_dbRefDbString));
+ // Calculate size
+ object_size += BSON::calculate_object_size(bson, obj, serializeFunctions);
+ } else if(bson->minKeyString->StrictEquals(constructorString) || bson->maxKeyString->Equals(constructorString)) {
+ } else if(bson->symbolString->StrictEquals(constructorString)) {
+ // Get string
+ Local<String> str = value->ToObject()->Get(String::New("value"))->ToString();
+ // Get the utf8 length
+ int utf8_length = str->Utf8Length();
+ // Check if we have a utf8 encoded string or not
+ if(utf8_length != str->Length()) {
+ // Let's calculate the size the string adds, length + type(1 byte) + size(4 bytes)
+ object_size += str->Utf8Length() + 1 + 4;
+ } else {
+ object_size += str->Length() + 1 + 4;
+ }
+ } else if(bson->doubleString->StrictEquals(constructorString)) {
+ object_size = object_size + 8;
+ }
+ } else if(value->IsObject()) {
+ // Unwrap the object
+ Local<Object> object = value->ToObject();
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> property_names = object->GetPropertyNames();
+ #else
+ Local<Array> property_names = object->GetOwnPropertyNames();
+ #endif
+
+ // Length of the property
+ uint32_t propertyLength = property_names->Length();
+
+ // Process all the properties on the object
+ for(uint32_t index = 0; index < propertyLength; index++) {
+ // Fetch the property name
+ Local<String> property_name = property_names->Get(index)->ToString();
+
+ // Fetch the object for the property
+ Local<Value> property = object->Get(property_name);
+ // Get size of property (property + property name length + 1 for terminating 0)
+ if(!property->IsFunction() || (property->IsFunction() && serializeFunctions)) {
+ // Convert name to char*
+ object_size += BSON::calculate_object_size(bson, property, serializeFunctions) + property_name->Utf8Length() + 1 + 1;
+ }
+ }
+
+ object_size = object_size + 4 + 1;
+ }
+
+ return object_size;
+}
+
+uint32_t BSON::serialize(BSON *bson, char *serialized_object, uint32_t index, Handle<Value> name, Handle<Value> value, bool check_key, bool serializeFunctions) {
+ // Scope for method execution
+ HandleScope scope;
+
+ // If we have a name check that key is valid
+ if(!name->IsNull() && check_key) {
+ if(BSON::check_key(name->ToString()) != NULL) return -1;
+ }
+
+ // If we have an object let's serialize it
+ if(value->IsString()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_STRING;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // Write the actual string into the char array
+ Local<String> str = value->ToString();
+ // Let's fetch the int value
+ uint32_t utf8_length = str->Utf8Length();
+
+ // Write the integer to the char *
+ BSON::write_int32((serialized_object + index), utf8_length + 1);
+ // Adjust the index
+ index = index + 4;
+ // Write string to char in utf8 format
+ str->WriteUtf8((serialized_object + index), utf8_length);
+ // Add the null termination
+ *(serialized_object + index + utf8_length) = '\0';
+ // Adjust the index
+ index = index + utf8_length + 1;
+ } else if(value->IsNumber()) {
+ uint32_t first_pointer = index;
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_INT;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ Local<Number> number = value->ToNumber();
+ // Get the values
+ double d_number = number->NumberValue();
+ int64_t l_number = number->IntegerValue();
+
+ // Check if we have a double value and not a int64
+ double d_result = d_number - l_number;
+ // If we have a value after subtracting the integer value we have a float
+ if(d_result > 0 || d_result < 0) {
+ // Write the double to the char array
+ BSON::write_double((serialized_object + index), d_number);
+ // Adjust type to be double
+ *(serialized_object + first_pointer) = BSON_DATA_NUMBER;
+ // Adjust index for double
+ index = index + 8;
+ } else if(l_number <= BSON_INT32_MAX && l_number >= BSON_INT32_MIN) {
+ // Smaller than 32 bit, write as 32 bit value
+ BSON::write_int32(serialized_object + index, value->ToInt32()->Value());
+ // Adjust the size of the index
+ index = index + 4;
+ } else if(l_number <= JS_INT_MAX && l_number >= JS_INT_MIN) {
+ // Write the double to the char array
+ BSON::write_double((serialized_object + index), d_number);
+ // Adjust type to be double
+ *(serialized_object + first_pointer) = BSON_DATA_NUMBER;
+ // Adjust index for double
+ index = index + 8;
+ } else {
+ BSON::write_double((serialized_object + index), d_number);
+ // Adjust type to be double
+ *(serialized_object + first_pointer) = BSON_DATA_NUMBER;
+ // Adjust the size of the index
+ index = index + 8;
+ }
+ } else if(value->IsBoolean()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_BOOLEAN;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // Save the boolean value
+ *(serialized_object + index) = value->BooleanValue() ? '\1' : '\0';
+ // Adjust the index
+ index = index + 1;
+ } else if(value->IsDate()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_DATE;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // Fetch the Integer value
+ int64_t integer_value = value->IntegerValue();
+ BSON::write_int64((serialized_object + index), integer_value);
+ // Adjust the index
+ index = index + 8;
+ } else if(value->IsNull() || value->IsUndefined()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_NULL;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+ } else if(value->IsArray()) {
+ // Cast to array
+ Local<Array> array = Local<Array>::Cast(value->ToObject());
+ // Turn length into string to calculate the size of all the strings needed
+ char *length_str = (char *)malloc(256 * sizeof(char));
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_ARRAY;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+ // Object size
+ uint32_t object_size = BSON::calculate_object_size(bson, value, serializeFunctions);
+ // Write the size of the object
+ BSON::write_int32((serialized_object + index), object_size);
+ // Adjust the index
+ index = index + 4;
+ // Write out all the elements
+ for(uint32_t i = 0; i < array->Length(); i++) {
+ // Add "index" string size for each element
+ sprintf(length_str, "%d", i);
+ // Encode the values
+ index = BSON::serialize(bson, serialized_object, index, String::New(length_str), array->Get(Integer::New(i)), check_key, serializeFunctions);
+ // Write trailing '\0' for object
+ *(serialized_object + index) = '\0';
+ }
+
+ // Pad the last item
+ *(serialized_object + index) = '\0';
+ index = index + 1;
+ // Free up memory
+ free(length_str);
+ } else if(value->IsRegExp()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_REGEXP;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // Fetch the string for the regexp
+ Handle<RegExp> regExp = Handle<RegExp>::Cast(value);
+ len = DecodeBytes(regExp->GetSource(), UTF8);
+ written = DecodeWrite((serialized_object + index), len, regExp->GetSource(), UTF8);
+ int flags = regExp->GetFlags();
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // global
+ if((flags & (1 << 0)) != 0) {
+ *(serialized_object + index) = 's';
+ index = index + 1;
+ }
+
+ // ignorecase
+ if((flags & (1 << 1)) != 0) {
+ *(serialized_object + index) = 'i';
+ index = index + 1;
+ }
+
+ //multiline
+ if((flags & (1 << 2)) != 0) {
+ *(serialized_object + index) = 'm';
+ index = index + 1;
+ }
+
+ // Add null termiation for the string
+ *(serialized_object + index) = '\0';
+ // Adjust the index
+ index = index + 1;
+ } else if(value->IsFunction()) {
+ if(serializeFunctions) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_CODE;
+
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+
+ // Function String
+ Local<String> function = value->ToString();
+
+ // Decode the function
+ len = DecodeBytes(function, BINARY);
+ // Write the size of the code string + 0 byte end of cString
+ BSON::write_int32((serialized_object + index), len + 1);
+ // Adjust the index
+ index = index + 4;
+
+ // Write the data into the serialization stream
+ written = DecodeWrite((serialized_object + index), len, function, BINARY);
+ // Write \0 for string
+ *(serialized_object + index + len) = 0x00;
+ // Adjust the index
+ index = index + len + 1;
+ }
+ } else if(value->ToObject()->Has(bson->_bsontypeString)) {
+ // Handle holder
+ Local<String> constructorString = value->ToObject()->GetConstructorName();
+ uint32_t originalIndex = index;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = 0x00;
+ // Adjust the index
+ index = index + len + 1;
+
+ // BSON type object, avoid non-needed checking unless we have a type
+ if(bson->longString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_LONG;
+ // Object reference
+ Local<Object> longObject = value->ToObject();
+
+ // Fetch the low and high bits
+ int32_t lowBits = longObject->Get(bson->_longLowString)->ToInt32()->Value();
+ int32_t highBits = longObject->Get(bson->_longHighString)->ToInt32()->Value();
+
+ // Write the content to the char array
+ BSON::write_int32((serialized_object + index), lowBits);
+ BSON::write_int32((serialized_object + index + 4), highBits);
+ // Adjust the index
+ index = index + 8;
+ } else if(bson->timestampString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_TIMESTAMP;
+ // Object reference
+ Local<Object> timestampObject = value->ToObject();
+
+ // Fetch the low and high bits
+ int32_t lowBits = timestampObject->Get(bson->_longLowString)->ToInt32()->Value();
+ int32_t highBits = timestampObject->Get(bson->_longHighString)->ToInt32()->Value();
+
+ // Write the content to the char array
+ BSON::write_int32((serialized_object + index), lowBits);
+ BSON::write_int32((serialized_object + index + 4), highBits);
+ // Adjust the index
+ index = index + 8;
+ } else if(bson->objectIDString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_OID;
+ // Convert to object
+ Local<Object> objectIDObject = value->ToObject();
+ // Let's grab the id
+ Local<String> idString = objectIDObject->Get(bson->_objectIDidString)->ToString();
+ // Let's decode the raw chars from the string
+ len = DecodeBytes(idString, BINARY);
+ written = DecodeWrite((serialized_object + index), len, idString, BINARY);
+ // Adjust the index
+ index = index + 12;
+ } else if(bson->binaryString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_BINARY;
+
+ // Let's get the binary object
+ Local<Object> binaryObject = value->ToObject();
+
+ // Grab the size(position of the binary)
+ uint32_t position = value->ToObject()->Get(bson->_binaryPositionString)->ToUint32()->Value();
+ // Grab the subtype
+ uint32_t subType = value->ToObject()->Get(bson->_binarySubTypeString)->ToUint32()->Value();
+ // Grab the buffer object
+ Local<Object> bufferObj = value->ToObject()->Get(bson->_binaryBufferString)->ToObject();
+
+ // Buffer data pointers
+ char *data;
+ uint32_t length;
+
+ // Unpack the buffer variable
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(bufferObj);
+ data = buffer->data();
+ length = buffer->length();
+ #else
+ data = Buffer::Data(bufferObj);
+ length = Buffer::Length(bufferObj);
+ #endif
+
+ // Write the size of the buffer out
+ BSON::write_int32((serialized_object + index), position);
+ // Adjust index
+ index = index + 4;
+ // Write subtype
+ *(serialized_object + index) = (char)subType;
+ // Adjust index
+ index = index + 1;
+ // Write binary content
+ memcpy((serialized_object + index), data, position);
+ // Adjust index.rar">_</a>
+ index = index + position;
+ } else if(bson->doubleString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_NUMBER;
+
+ // Unpack the double
+ Local<Object> doubleObject = value->ToObject();
+
+ // Fetch the double value
+ Local<Number> doubleValue = doubleObject->Get(bson->_doubleValueString)->ToNumber();
+ // Write the double to the char array
+ BSON::write_double((serialized_object + index), doubleValue->NumberValue());
+ // Adjust index for double
+ index = index + 8;
+ } else if(bson->symbolString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_SYMBOL;
+ // Unpack symbol object
+ Local<Object> symbolObj = value->ToObject();
+
+ // Grab the actual string
+ Local<String> str = symbolObj->Get(bson->_symbolValueString)->ToString();
+ // Let's fetch the int value
+ int utf8_length = str->Utf8Length();
+
+ // If the Utf8 length is different from the string length then we
+ // have a UTF8 encoded string, otherwise write it as ascii
+ if(utf8_length != str->Length()) {
+ // Write the integer to the char *
+ BSON::write_int32((serialized_object + index), utf8_length + 1);
+ // Adjust the index
+ index = index + 4;
+ // Write string to char in utf8 format
+ str->WriteUtf8((serialized_object + index), utf8_length);
+ // Add the null termination
+ *(serialized_object + index + utf8_length) = '\0';
+ // Adjust the index
+ index = index + utf8_length + 1;
+ } else {
+ // Write the integer to the char *
+ BSON::write_int32((serialized_object + index), str->Length() + 1);
+ // Adjust the index
+ index = index + 4;
+ // Write string to char in utf8 format
+ written = DecodeWrite((serialized_object + index), str->Length(), str, BINARY);
+ // Add the null termination
+ *(serialized_object + index + str->Length()) = '\0';
+ // Adjust the index
+ index = index + str->Length() + 1;
+ }
+ } else if(bson->codeString->StrictEquals(constructorString)) {
+ // Unpack the object and encode
+ Local<Object> obj = value->ToObject();
+ // Get the function
+ Local<String> function = obj->Get(String::New("code"))->ToString();
+ // Get the scope object
+ Local<Object> scope = obj->Get(String::New("scope"))->ToObject();
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
+ #else
+ uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
+ #endif
+
+ // Set the right type if we have a scope or not
+ if(propertyNameLength > 0) {
+ // Set basic data code object with scope object
+ *(serialized_object + originalIndex) = BSON_DATA_CODE_W_SCOPE;
+
+ // Calculate the size of the whole object
+ uint32_t scopeSize = BSON::calculate_object_size(bson, scope, false);
+ // Decode the function length
+ ssize_t len = DecodeBytes(function, UTF8);
+ // Calculate total size
+ uint32_t size = 4 + len + 1 + 4 + scopeSize;
+
+ // Write the total size
+ BSON::write_int32((serialized_object + index), size);
+ // Adjust the index
+ index = index + 4;
+
+ // Write the function size
+ BSON::write_int32((serialized_object + index), len + 1);
+ // Adjust the index
+ index = index + 4;
+
+ // Write the data into the serialization stream
+ ssize_t written = DecodeWrite((serialized_object + index), len, function, UTF8);
+ assert(written == len);
+ // Write \0 for string
+ *(serialized_object + index + len) = 0x00;
+ // Adjust the index with the length of the function
+ index = index + len + 1;
+ // Write the scope object
+ BSON::serialize(bson, (serialized_object + index), 0, Null(), scope, check_key, serializeFunctions);
+ // Adjust the index
+ index = index + scopeSize;
+ } else {
+ // Set basic data code object
+ *(serialized_object + originalIndex) = BSON_DATA_CODE;
+ // Decode the function
+ ssize_t len = DecodeBytes(function, BINARY);
+ // Write the size of the code string + 0 byte end of cString
+ BSON::write_int32((serialized_object + index), len + 1);
+ // Adjust the index
+ index = index + 4;
+
+ // Write the data into the serialization stream
+ ssize_t written = DecodeWrite((serialized_object + index), len, function, BINARY);
+ assert(written == len);
+ // Write \0 for string
+ *(serialized_object + index + len) = 0x00;
+ // Adjust the index
+ index = index + len + 1;
+ }
+ } else if(bson->dbrefString->StrictEquals(constructorString)) {
+ // Unpack the dbref
+ Local<Object> dbref = value->ToObject();
+ // Create an object containing the right namespace variables
+ Local<Object> obj = Object::New();
+
+ // Build the new object
+ obj->Set(bson->_dbRefRefString, dbref->Get(bson->_dbRefNamespaceString));
+ obj->Set(bson->_dbRefIdRefString, dbref->Get(bson->_dbRefOidString));
+ if(!dbref->Get(bson->_dbRefDbString)->IsNull() && !dbref->Get(bson->_dbRefDbString)->IsUndefined()) obj->Set(bson->_dbRefDbRefString, dbref->Get(bson->_dbRefDbString));
+
+ // Encode the variable
+ index = BSON::serialize(bson, serialized_object, originalIndex, name, obj, false, serializeFunctions);
+ } else if(bson->minKeyString->StrictEquals(constructorString)) {
+ // Save the string at the offset provided
+ *(serialized_object + originalIndex) = BSON_DATA_MIN_KEY;
+ } else if(bson->maxKeyString->StrictEquals(constructorString)) {
+ *(serialized_object + originalIndex) = BSON_DATA_MAX_KEY;
+ }
+ } else if(value->IsObject()) {
+ if(!name->IsNull()) {
+ // Save the string at the offset provided
+ *(serialized_object + index) = BSON_DATA_OBJECT;
+ // Adjust writing position for the first byte
+ index = index + 1;
+ // Convert name to char*
+ ssize_t len = DecodeBytes(name, UTF8);
+ ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
+ assert(written == len);
+ // Add null termiation for the string
+ *(serialized_object + index + len) = '\0';
+ // Adjust the index
+ index = index + len + 1;
+ }
+
+ // Unwrap the object
+ Local<Object> object = value->ToObject();
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> property_names = object->GetPropertyNames();
+ #else
+ Local<Array> property_names = object->GetOwnPropertyNames();
+ #endif
+
+ // Calculate size of the total object
+ uint32_t object_size = BSON::calculate_object_size(bson, value, serializeFunctions);
+ // Write the size
+ BSON::write_int32((serialized_object + index), object_size);
+ // Adjust size
+ index = index + 4;
+
+ // Process all the properties on the object
+ for(uint32_t i = 0; i < property_names->Length(); i++) {
+ // Fetch the property name
+ Local<String> property_name = property_names->Get(i)->ToString();
+ // Fetch the object for the property
+ Local<Value> property = object->Get(property_name);
+ // Write the next serialized object
+ // printf("========== !property->IsFunction() || (property->IsFunction() && serializeFunctions) = %d\n", !property->IsFunction() || (property->IsFunction() && serializeFunctions) == true ? 1 : 0);
+ if(!property->IsFunction() || (property->IsFunction() && serializeFunctions)) {
+ // Convert name to char*
+ ssize_t len = DecodeBytes(property_name, UTF8);
+ // char *data = new char[len];
+ char *data = (char *)malloc(len + 1);
+ *(data + len) = '\0';
+ ssize_t written = DecodeWrite(data, len, property_name, UTF8);
+ assert(written == len);
+ // Serialize the content
+ index = BSON::serialize(bson, serialized_object, index, property_name, property, check_key, serializeFunctions);
+ // Free up memory of data
+ free(data);
+ }
+ }
+ // Pad the last item
+ *(serialized_object + index) = '\0';
+ index = index + 1;
+
+ // Null out reminding fields if we have a toplevel object and nested levels
+ if(name->IsNull()) {
+ for(uint32_t i = 0; i < (object_size - index); i++) {
+ *(serialized_object + index + i) = '\0';
+ }
+ }
+ }
+
+ return index;
+}
+
+Handle<Value> BSON::SerializeWithBufferAndIndex(const Arguments &args) {
+ HandleScope scope;
+
+ //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, index) {
+ // Ensure we have the correct values
+ if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]");
+ if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Define pointer to data
+ char *data;
+ uint32_t length;
+ // Unpack the object
+ Local<Object> obj = args[2]->ToObject();
+
+ // Unpack the buffer object and get pointers to structures
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ data = buffer->data();
+ length = buffer->length();
+ #else
+ data = Buffer::Data(obj);
+ length = Buffer::Length(obj);
+ #endif
+
+ uint32_t object_size = 0;
+ // Calculate the total size of the document in binary form to ensure we only allocate memory once
+ if(args.Length() == 5) {
+ object_size = BSON::calculate_object_size(bson, args[0], args[4]->BooleanValue());
+ } else {
+ object_size = BSON::calculate_object_size(bson, args[0], false);
+ }
+
+ // Unpack the index variable
+ Local<Uint32> indexObject = args[3]->ToUint32();
+ uint32_t index = indexObject->Value();
+
+ // Allocate the memory needed for the serializtion
+ char *serialized_object = (char *)malloc(object_size * sizeof(char));
+
+ // Catch any errors
+ try {
+ // Check if we have a boolean value
+ bool check_key = false;
+ if(args.Length() >= 4 && args[1]->IsBoolean()) {
+ check_key = args[1]->BooleanValue();
+ }
+
+ bool serializeFunctions = false;
+ if(args.Length() == 5) {
+ serializeFunctions = args[4]->BooleanValue();
+ }
+
+ // Serialize the object
+ BSON::serialize(bson, serialized_object, 0, Null(), args[0], check_key, serializeFunctions);
+ } catch(char *err_msg) {
+ // Free up serialized object space
+ free(serialized_object);
+ V8::AdjustAmountOfExternalAllocatedMemory(-object_size);
+ // Throw exception with the string
+ Handle<Value> error = VException(err_msg);
+ // free error message
+ free(err_msg);
+ // Return error
+ return error;
+ }
+
+ for(uint32_t i = 0; i < object_size; i++) {
+ *(data + index + i) = *(serialized_object + i);
+ }
+
+ return scope.Close(Uint32::New(index + object_size - 1));
+}
+
+Handle<Value> BSON::BSONDeserializeStream(const Arguments &args) {
+ HandleScope scope;
+
+ // At least 3 arguments required
+ if(args.Length() < 5) VException("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))");
+
+ // If the number of argumets equals 3
+ if(args.Length() >= 5) {
+ if(!Buffer::HasInstance(args[0])) return VException("First argument must be Buffer instance");
+ if(!args[1]->IsUint32()) return VException("Second argument must be a positive index number");
+ if(!args[2]->IsUint32()) return VException("Third argument must be a positive number of documents to deserialize");
+ if(!args[3]->IsArray()) return VException("Fourth argument must be an array the size of documents to deserialize");
+ if(!args[4]->IsUint32()) return VException("Sixth argument must be a positive index number");
+ }
+
+ // If we have 4 arguments
+ if(args.Length() == 6 && !args[5]->IsObject()) return VException("Fifth argument must be an object with options");
+
+ // Define pointer to data
+ char *data;
+ uint32_t length;
+ Local<Object> obj = args[0]->ToObject();
+ uint32_t numberOfDocuments = args[2]->ToUint32()->Value();
+ uint32_t index = args[1]->ToUint32()->Value();
+ uint32_t resultIndex = args[4]->ToUint32()->Value();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Unpack the buffer variable
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ data = buffer->data();
+ length = buffer->length();
+ #else
+ data = Buffer::Data(obj);
+ length = Buffer::Length(obj);
+ #endif
+
+ // Fetch the documents
+ Local<Object> documents = args[3]->ToObject();
+
+ for(uint32_t i = 0; i < numberOfDocuments; i++) {
+ // Decode the size of the BSON data structure
+ uint32_t size = BSON::deserialize_int32(data, index);
+
+ // Get result
+ Handle<Value> result = BSON::deserialize(bson, data, size, index, NULL);
+
+ // Add result to array
+ documents->Set(i + resultIndex, result);
+
+ // Adjust the index for next pass
+ index = index + size;
+ }
+
+ // Return new index of parsing
+ return scope.Close(Uint32::New(index));
+}
+
+// Exporting function
+extern "C" void init(Handle<Object> target) {
+ HandleScope scope;
+ BSON::Initialize(target);
+}
+
+// NODE_MODULE(bson, BSON::Initialize);
+// NODE_MODULE(l, Long::Initialize);
diff --git a/node_modules/mongodb/external-libs/bson/bson.h b/node_modules/mongodb/external-libs/bson/bson.h
new file mode 100644
index 0000000..dcf21d1
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/bson.h
@@ -0,0 +1,105 @@
+#ifndef BSON_H_
+#define BSON_H_
+
+#include <node.h>
+#include <node_object_wrap.h>
+#include <v8.h>
+
+using namespace v8;
+using namespace node;
+
+class BSON : public ObjectWrap {
+ public:
+ BSON() : ObjectWrap() {}
+ ~BSON() {}
+
+ static void Initialize(Handle<Object> target);
+ static Handle<Value> BSONDeserializeStream(const Arguments &args);
+
+ // JS based objects
+ static Handle<Value> BSONSerialize(const Arguments &args);
+ static Handle<Value> BSONDeserialize(const Arguments &args);
+
+ // Calculate size of function
+ static Handle<Value> CalculateObjectSize(const Arguments &args);
+ static Handle<Value> SerializeWithBufferAndIndex(const Arguments &args);
+
+ // Experimental
+ static Handle<Value> CalculateObjectSize2(const Arguments &args);
+ static Handle<Value> BSONSerialize2(const Arguments &args);
+
+ // Constructor used for creating new BSON objects from C++
+ static Persistent<FunctionTemplate> constructor_template;
+
+ private:
+ static Handle<Value> New(const Arguments &args);
+ static Handle<Value> deserialize(BSON *bson, char *data, uint32_t dataLength, uint32_t startIndex, bool is_array_item);
+ static uint32_t serialize(BSON *bson, char *serialized_object, uint32_t index, Handle<Value> name, Handle<Value> value, bool check_key, bool serializeFunctions);
+
+ static char* extract_string(char *data, uint32_t offset);
+ static const char* ToCString(const v8::String::Utf8Value& value);
+ static uint32_t calculate_object_size(BSON *bson, Handle<Value> object, bool serializeFunctions);
+
+ static void write_int32(char *data, uint32_t value);
+ static void write_int64(char *data, int64_t value);
+ static void write_double(char *data, double value);
+ static uint16_t deserialize_int8(char *data, uint32_t offset);
+ static uint32_t deserialize_int32(char* data, uint32_t offset);
+ static char *check_key(Local<String> key);
+
+ // BSON type instantiate functions
+ Persistent<Function> longConstructor;
+ Persistent<Function> objectIDConstructor;
+ Persistent<Function> binaryConstructor;
+ Persistent<Function> codeConstructor;
+ Persistent<Function> dbrefConstructor;
+ Persistent<Function> symbolConstructor;
+ Persistent<Function> doubleConstructor;
+ Persistent<Function> timestampConstructor;
+ Persistent<Function> minKeyConstructor;
+ Persistent<Function> maxKeyConstructor;
+
+ // Equality Objects
+ Persistent<String> longString;
+ Persistent<String> objectIDString;
+ Persistent<String> binaryString;
+ Persistent<String> codeString;
+ Persistent<String> dbrefString;
+ Persistent<String> symbolString;
+ Persistent<String> doubleString;
+ Persistent<String> timestampString;
+ Persistent<String> minKeyString;
+ Persistent<String> maxKeyString;
+
+ // Equality speed up comparision objects
+ Persistent<String> _bsontypeString;
+ Persistent<String> _longLowString;
+ Persistent<String> _longHighString;
+ Persistent<String> _objectIDidString;
+ Persistent<String> _binaryPositionString;
+ Persistent<String> _binarySubTypeString;
+ Persistent<String> _binaryBufferString;
+ Persistent<String> _doubleValueString;
+ Persistent<String> _symbolValueString;
+
+ Persistent<String> _dbRefRefString;
+ Persistent<String> _dbRefIdRefString;
+ Persistent<String> _dbRefDbRefString;
+ Persistent<String> _dbRefNamespaceString;
+ Persistent<String> _dbRefDbString;
+ Persistent<String> _dbRefOidString;
+
+ // Decode JS function
+ static Handle<Value> decodeLong(BSON *bson, char *data, uint32_t index);
+ static Handle<Value> decodeTimestamp(BSON *bson, char *data, uint32_t index);
+ static Handle<Value> decodeOid(BSON *bson, char *oid);
+ static Handle<Value> decodeBinary(BSON *bson, uint32_t sub_type, uint32_t number_of_bytes, char *data);
+ static Handle<Value> decodeCode(BSON *bson, char *code, Handle<Value> scope);
+ static Handle<Value> decodeDBref(BSON *bson, Local<Value> ref, Local<Value> oid, Local<Value> db);
+
+ // Experimental
+ static uint32_t calculate_object_size2(Handle<Value> object);
+ static uint32_t serialize2(char *serialized_object, uint32_t index, Handle<Value> name, Handle<Value> value, uint32_t object_size, bool check_key);
+};
+
+#endif // BSON_H_
diff --git a/node_modules/mongodb/external-libs/bson/index.js b/node_modules/mongodb/external-libs/bson/index.js
new file mode 100644
index 0000000..2c66dee
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/index.js
@@ -0,0 +1,20 @@
+var bson = require('./bson');
+exports.BSON = bson.BSON;
+exports.Long = require('../../lib/mongodb/bson/long').Long;
+exports.ObjectID = require('../../lib/mongodb/bson/objectid').ObjectID;
+exports.DBRef = require('../../lib/mongodb/bson/db_ref').DBRef;
+exports.Code = require('../../lib/mongodb/bson/code').Code;
+exports.Timestamp = require('../../lib/mongodb/bson/timestamp').Timestamp;
+exports.Binary = require('../../lib/mongodb/bson/binary').Binary;
+exports.Double = require('../../lib/mongodb/bson/double').Double;
+exports.MaxKey = require('../../lib/mongodb/bson/max_key').MaxKey;
+exports.MinKey = require('../../lib/mongodb/bson/min_key').MinKey;
+exports.Symbol = require('../../lib/mongodb/bson/symbol').Symbol;
+
+// Just add constants tot he Native BSON parser
+exports.BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
+exports.BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
+exports.BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
+exports.BSON.BSON_BINARY_SUBTYPE_UUID = 3;
+exports.BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
+exports.BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
diff --git a/node_modules/mongodb/external-libs/bson/test/test_bson.js b/node_modules/mongodb/external-libs/bson/test/test_bson.js
new file mode 100644
index 0000000..706f1df
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/test/test_bson.js
@@ -0,0 +1,349 @@
+var sys = require('util'),
+ debug = require('util').debug,
+ inspect = require('util').inspect,
+ Buffer = require('buffer').Buffer,
+ BSON = require('../bson').BSON,
+ Buffer = require('buffer').Buffer,
+ BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
+ BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
+ Long = require('../../../lib/mongodb/bson/long').Long,
+ ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
+ Binary = require('../../../lib/mongodb/bson/bson').Binary,
+ Code = require('../../../lib/mongodb/bson/bson').Code,
+ DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
+ Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
+ Double = require('../../../lib/mongodb/bson/bson').Double,
+ MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
+ MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
+ Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp,
+ assert = require('assert');
+
+if(process.env['npm_package_config_native'] != null) return;
+
+sys.puts("=== EXECUTING TEST_BSON ===");
+
+// Should fail due to illegal key
+assert.throws(function() { new ObjectID('foo'); })
+assert.throws(function() { new ObjectID('foo'); })
+
+// Parsers
+var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+
+// Simple serialization and deserialization of edge value
+var doc = {doc:0x1ffffffffffffe};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+var doc = {doc:-0x1ffffffffffffe};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+//
+// Assert correct toJSON
+//
+var a = Long.fromNumber(10);
+assert.equal(10, a);
+
+var a = Long.fromNumber(9223372036854775807);
+assert.equal(9223372036854775807, a);
+
+// Simple serialization and deserialization test for a Single String value
+var doc = {doc:'Serialize'};
+var simple_string_serialized = bsonC.serialize(doc, true, false);
+
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Nested doc
+var doc = {a:{b:{c:1}}};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple integer serialization/deserialization test, including testing boundary conditions
+var doc = {doc:-1};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+var doc = {doc:2147483648};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+var doc = {doc:-2147483648};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization test for a Long value
+var doc = {doc:Long.fromNumber(9223372036854775807)};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Long.fromNumber(9223372036854775807)}, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+var doc = {doc:Long.fromNumber(-9223372036854775807)};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Long.fromNumber(-9223372036854775807)}, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization for a Float value
+var doc = {doc:2222.3333};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+var doc = {doc:-2222.3333};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization for a null value
+var doc = {doc:null};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization for a boolean value
+var doc = {doc:true};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization for a date value
+var date = new Date();
+var doc = {doc:date};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
+
+// Simple serialization and deserialization for a boolean value
+var doc = {doc:/abcd/mi};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.equal(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
+
+var doc = {doc:/abcd/};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
+assert.equal(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
+
+// Simple serialization and deserialization for a objectId value
+var doc = {doc:new ObjectID()};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+var doc2 = {doc:ObjectID.createFromHexString(doc.doc.toHexString())};
+
+assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc2, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
+
+// Simple serialization and deserialization for a Binary value
+var binary = new Binary();
+var string = 'binstring'
+for(var index = 0; index < string.length; index++) { binary.put(string.charAt(index)); }
+
+var Binary = new Binary();
+var string = 'binstring'
+for(var index = 0; index < string.length; index++) { Binary.put(string.charAt(index)); }
+
+var simple_string_serialized = bsonC.serialize({doc:binary}, false, true);
+assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Binary}, false, true));
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.value(), bsonC.deserialize(simple_string_serialized).doc.value());
+
+// Simple serialization and deserialization for a Code value
+var code = new Code('this.a > i', {'i': 1});
+var Code = new Code('this.a > i', {'i': 1});
+var simple_string_serialized_2 = bsonJS.serialize({doc:Code}, false, true);
+var simple_string_serialized = bsonC.serialize({doc:code}, false, true);
+
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2);
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc.scope, bsonC.deserialize(simple_string_serialized).doc.scope);
+
+// Simple serialization and deserialization for an Object
+var simple_string_serialized = bsonC.serialize({doc:{a:1, b:{c:2}}}, false, true);
+var simple_string_serialized_2 = bsonJS.serialize({doc:{a:1, b:{c:2}}}, false, true);
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, bsonC.deserialize(simple_string_serialized).doc);
+
+// Simple serialization and deserialization for an Array
+var simple_string_serialized = bsonC.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true);
+var simple_string_serialized_2 = bsonJS.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true);
+
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
+assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, bsonC.deserialize(simple_string_serialized).doc);
+
+// Simple serialization and deserialization for a DBRef
+var oid = new ObjectID()
+var oid2 = new ObjectID.createFromHexString(oid.toHexString())
+var simple_string_serialized = bsonJS.serialize({doc:new DBRef('namespace', oid2, 'integration_tests_')}, false, true);
+var simple_string_serialized_2 = bsonC.serialize({doc:new DBRef('namespace', oid, 'integration_tests_')}, false, true);
+
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
+// Ensure we have the same values for the dbref
+var object_js = bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary'));
+var object_c = bsonC.deserialize(simple_string_serialized);
+
+assert.equal(object_js.doc.namespace, object_c.doc.namespace);
+assert.equal(object_js.doc.oid.toHexString(), object_c.doc.oid.toHexString());
+assert.equal(object_js.doc.db, object_c.doc.db);
+
+// Serialized document
+var bytes = [47,0,0,0,2,110,97,109,101,0,6,0,0,0,80,97,116,116,121,0,16,97,103,101,0,34,0,0,0,7,95,105,100,0,76,100,12,23,11,30,39,8,89,0,0,1,0];
+var serialized_data = '';
+// Convert to chars
+for(var i = 0; i < bytes.length; i++) {
+ serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]);
+}
+var object = bsonC.deserialize(new Buffer(serialized_data, 'binary'));
+assert.equal('Patty', object.name)
+assert.equal(34, object.age)
+assert.equal('4c640c170b1e270859000001', object._id.toHexString())
+
+// Serialize utf8
+var doc = { "name" : "本荘由利地域に洪水警報", "name1" : "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "name2" : "abcdedede"};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+var simple_string_serialized2 = bsonJS.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, simple_string_serialized2)
+
+var object = bsonC.deserialize(simple_string_serialized);
+assert.equal(doc.name, object.name)
+assert.equal(doc.name1, object.name1)
+assert.equal(doc.name2, object.name2)
+
+// Serialize object with array
+var doc = {b:[1, 2, 3]};
+var simple_string_serialized = bsonC.serialize(doc, false, true);
+var simple_string_serialized_2 = bsonJS.serialize(doc, false, true);
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
+
+var object = bsonC.deserialize(simple_string_serialized);
+assert.deepEqual(doc, object)
+
+// Test equality of an object ID
+var object_id = new ObjectID();
+var object_id_2 = new ObjectID();
+assert.ok(object_id.equals(object_id));
+assert.ok(!(object_id.equals(object_id_2)))
+
+// Test same serialization for Object ID
+var object_id = new ObjectID();
+var object_id2 = ObjectID.createFromHexString(object_id.toString())
+var simple_string_serialized = bsonJS.serialize({doc:object_id}, false, true);
+var simple_string_serialized_2 = bsonC.serialize({doc:object_id2}, false, true);
+
+assert.equal(simple_string_serialized_2.length, simple_string_serialized.length);
+assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
+var object = bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary'));
+var object2 = bsonC.deserialize(simple_string_serialized);
+assert.equal(object.doc.id, object2.doc.id)
+
+// JS Object
+var c1 = { _id: new ObjectID, comments: [], title: 'number 1' };
+var c2 = { _id: new ObjectID, comments: [], title: 'number 2' };
+var doc = {
+ numbers: []
+ , owners: []
+ , comments: [c1, c2]
+ , _id: new ObjectID
+};
+
+var simple_string_serialized = bsonJS.serialize(doc, false, true);
+
+// C++ Object
+var c1 = { _id: ObjectID.createFromHexString(c1._id.toHexString()), comments: [], title: 'number 1' };
+var c2 = { _id: ObjectID.createFromHexString(c2._id.toHexString()), comments: [], title: 'number 2' };
+var doc = {
+ numbers: []
+ , owners: []
+ , comments: [c1, c2]
+ , _id: ObjectID.createFromHexString(doc._id.toHexString())
+};
+
+var simple_string_serialized_2 = bsonC.serialize(doc, false, true);
+
+for(var i = 0; i < simple_string_serialized_2.length; i++) {
+ // debug(i + "[" + simple_string_serialized_2[i] + "] = [" + simple_string_serialized[i] + "]")
+ assert.equal(simple_string_serialized_2[i], simple_string_serialized[i]);
+}
+
+// Deserialize the string
+var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
+var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
+assert.equal(doc._id.id, doc1._id.id)
+assert.equal(doc._id.id, doc2._id.id)
+assert.equal(doc1._id.id, doc2._id.id)
+
+var doc = {
+ _id: 'testid',
+ key1: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 },
+ key2: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 }
+};
+
+var simple_string_serialized = bsonJS.serialize(doc, false, true);
+var simple_string_serialized_2 = bsonC.serialize(doc, false, true);
+
+// Deserialize the string
+var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
+var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
+assert.deepEqual(doc2, doc1)
+assert.deepEqual(doc, doc2)
+assert.deepEqual(doc, doc1)
+
+// Serialize function
+var doc = {
+ _id: 'testid',
+ key1: function() {}
+}
+
+var simple_string_serialized = bsonJS.serialize(doc, false, true, true);
+var simple_string_serialized_2 = bsonC.serialize(doc, false, true, true);
+
+// Deserialize the string
+var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
+var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
+assert.equal(doc1.key1.code.toString(), doc2.key1.code.toString())
+
+var doc = {"user_id":"4e9fc8d55883d90100000003","lc_status":{"$ne":"deleted"},"owner_rating":{"$exists":false}};
+var simple_string_serialized = bsonJS.serialize(doc, false, true, true);
+var simple_string_serialized_2 = bsonC.serialize(doc, false, true, true);
+
+// Should serialize to the same value
+assert.equal(simple_string_serialized_2.toString('base64'), simple_string_serialized.toString('base64'))
+var doc1 = bsonJS.deserialize(simple_string_serialized_2);
+var doc2 = bsonC.deserialize(simple_string_serialized);
+assert.deepEqual(doc1, doc2)
+
+// Hex Id
+var hexId = new ObjectID().toString();
+var docJS = {_id: ObjectID.createFromHexString(hexId), 'funds.remaining': {$gte: 1.222}, 'transactions.id': {$ne: ObjectID.createFromHexString(hexId)}};
+var docC = {_id: ObjectID.createFromHexString(hexId), 'funds.remaining': {$gte: 1.222}, 'transactions.id': {$ne: ObjectID.createFromHexString(hexId)}};
+var docJSBin = bsonJS.serialize(docJS, false, true, true);
+var docCBin = bsonC.serialize(docC, false, true, true);
+assert.equal(docCBin.toString('base64'), docJSBin.toString('base64'));
+
+// // Complex document serialization
+// doc = {"DateTime": "Tue Nov 40 2011 17:27:55 GMT+0000 (WEST)","isActive": true,"Media": {"URL": "http://videos.sapo.pt/Tc85NsjaKjj8o5aV7Ubb"},"Title": "Lisboa fecha a ganhar 0.19%","SetPosition": 60,"Type": "videos","Thumbnail": [{"URL": "http://rd3.videos.sapo.pt/Tc85NsjaKjj8o5aV7Ubb/pic/320x240","Dimensions": {"Height": 240,"Width": 320}}],"Source": {"URL": "http://videos.sapo.pt","SetID": "1288","SourceID": "http://videos.sapo.pt/tvnet/rss2","SetURL": "http://noticias.sapo.pt/videos/tv-net_1288/","ItemID": "Tc85NsjaKjj8o5aV7Ubb","Name": "SAPO Vídeos"},"Category": "Tec_ciencia","Description": "Lisboa fecha a ganhar 0.19%","GalleryID": new ObjectID("4eea2a634ce8573200000000"),"InternalRefs": {"RegisterDate": "Thu Dec 15 2011 17:12:51 GMT+0000 (WEST)","ChangeDate": "Thu Dec 15 2011 17:12:51 GMT+0000 (WEST)","Hash": 332279244514},"_id": new ObjectID("4eea2a96e52778160000003a")}
+// var docJSBin = bsonJS.serialize(docJS, false, true, true);
+// var docCBin = bsonC.serialize(docC, false, true, true);
+//
+//
+
+// // Force garbage collect
+// global.gc();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/mongodb/external-libs/bson/test/test_full_bson.js b/node_modules/mongodb/external-libs/bson/test/test_full_bson.js
new file mode 100644
index 0000000..2a6506c
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/test/test_full_bson.js
@@ -0,0 +1,218 @@
+var sys = require('util'),
+ fs = require('fs'),
+ Buffer = require('buffer').Buffer,
+ BSON = require('../bson').BSON,
+ Buffer = require('buffer').Buffer,
+ assert = require('assert'),
+ BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
+ BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
+ Long = require('../../../lib/mongodb/bson/long').Long,
+ ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
+ Binary = require('../../../lib/mongodb/bson/bson').Binary,
+ Code = require('../../../lib/mongodb/bson/bson').Code,
+ DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
+ Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
+ Double = require('../../../lib/mongodb/bson/bson').Double,
+ MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
+ MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
+ Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp;
+
+if(process.env['npm_package_config_native'] != null) return;
+
+sys.puts("=== EXECUTING TEST_FULL_BSON ===");
+
+// Parsers
+var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+
+// Should Correctly Deserialize object
+var bytes = [95,0,0,0,2,110,115,0,42,0,0,0,105,110,116,101,103,114,97,116,105,111,110,95,116,101,115,116,115,95,46,116,101,115,116,95,105,110,100,101,120,95,105,110,102,111,114,109,97,116,105,111,110,0,8,117,110,105,113,117,101,0,0,3,107,101,121,0,12,0,0,0,16,97,0,1,0,0,0,0,2,110,97,109,101,0,4,0,0,0,97,95,49,0,0];
+var serialized_data = '';
+// Convert to chars
+for(var i = 0; i < bytes.length; i++) {
+ serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]);
+}
+var object = bsonC.deserialize(serialized_data);
+assert.equal("a_1", object.name);
+assert.equal(false, object.unique);
+assert.equal(1, object.key.a);
+
+// Should Correctly Deserialize object with all types
+var bytes = [26,1,0,0,7,95,105,100,0,161,190,98,75,118,169,3,0,0,3,0,0,4,97,114,114,97,121,0,26,0,0,0,16,48,0,1,0,0,0,16,49,0,2,0,0,0,16,50,0,3,0,0,0,0,2,115,116,114,105,110,103,0,6,0,0,0,104,101,108,108,111,0,3,104,97,115,104,0,19,0,0,0,16,97,0,1,0,0,0,16,98,0,2,0,0,0,0,9,100,97,116,101,0,161,190,98,75,0,0,0,0,7,111,105,100,0,161,190,98,75,90,217,18,0,0,1,0,0,5,98,105,110,97,114,121,0,7,0,0,0,2,3,0,0,0,49,50,51,16,105,110,116,0,42,0,0,0,1,102,108,111,97,116,0,223,224,11,147,169,170,64,64,11,114,101,103,101,120,112,0,102,111,111,98,97,114,0,105,0,8,98,111,111,108,101,97,110,0,1,15,119,104,101,114,101,0,25,0,0,0,12,0,0,0,116,104,105,115,46,120,32,61,61,32,51,0,5,0,0,0,0,3,100,98,114,101,102,0,37,0,0,0,2,36,114,101,102,0,5,0,0,0,116,101,115,116,0,7,36,105,100,0,161,190,98,75,2,180,1,0,0,2,0,0,0,10,110,117,108,108,0,0];
+var serialized_data = '';
+// Convert to chars
+for(var i = 0; i < bytes.length; i++) {
+ serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]);
+}
+
+var object = bsonJS.deserialize(new Buffer(serialized_data, 'binary'));
+assert.equal("hello", object.string);
+assert.deepEqual([1, 2, 3], object.array);
+assert.equal(1, object.hash.a);
+assert.equal(2, object.hash.b);
+assert.ok(object.date != null);
+assert.ok(object.oid != null);
+assert.ok(object.binary != null);
+assert.equal(42, object.int);
+assert.equal(33.3333, object.float);
+assert.ok(object.regexp != null);
+assert.equal(true, object.boolean);
+assert.ok(object.where != null);
+assert.ok(object.dbref != null);
+assert.ok(object['null'] == null);
+
+// Should Serialize and Deserialze String
+var test_string = {hello: 'world'}
+var serialized_data = bsonC.serialize(test_string)
+assert.deepEqual(test_string, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Integer
+var test_number = {doc: 5}
+var serialized_data = bsonC.serialize(test_number)
+assert.deepEqual(test_number, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize null value
+var test_null = {doc:null}
+var serialized_data = bsonC.serialize(test_null)
+var object = bsonC.deserialize(serialized_data);
+assert.deepEqual(test_null, object);
+
+// Should Correctly Serialize and Deserialize undefined value
+var test_undefined = {doc:undefined}
+var serialized_data = bsonC.serialize(test_undefined)
+var object = bsonJS.deserialize(new Buffer(serialized_data, 'binary'));
+assert.equal(null, object.doc)
+
+// Should Correctly Serialize and Deserialize Number
+var test_number = {doc: 5.5}
+var serialized_data = bsonC.serialize(test_number)
+assert.deepEqual(test_number, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Integer
+var test_int = {doc: 42}
+var serialized_data = bsonC.serialize(test_int)
+assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
+
+test_int = {doc: -5600}
+serialized_data = bsonC.serialize(test_int)
+assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
+
+test_int = {doc: 2147483647}
+serialized_data = bsonC.serialize(test_int)
+assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
+
+test_int = {doc: -2147483648}
+serialized_data = bsonC.serialize(test_int)
+assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Object
+var doc = {doc: {age: 42, name: 'Spongebob', shoe_size: 9.5}}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Array
+var doc = {doc: [1, 2, 'a', 'b']}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Array with added on functions
+var doc = {doc: [1, 2, 'a', 'b']}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize A Boolean
+var doc = {doc: true}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize a Date
+var date = new Date()
+//(2009, 11, 12, 12, 00, 30)
+date.setUTCDate(12)
+date.setUTCFullYear(2009)
+date.setUTCMonth(11 - 1)
+date.setUTCHours(12)
+date.setUTCMinutes(0)
+date.setUTCSeconds(30)
+var doc = {doc: date}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc, bsonC.deserialize(serialized_data));
+
+// // Should Correctly Serialize and Deserialize Oid
+var doc = {doc: new ObjectID()}
+var serialized_data = bsonC.serialize(doc)
+assert.deepEqual(doc.doc.toHexString(), bsonC.deserialize(serialized_data).doc.toHexString())
+
+// Should Correctly encode Empty Hash
+var test_code = {}
+var serialized_data = bsonC.serialize(test_code)
+assert.deepEqual(test_code, bsonC.deserialize(serialized_data));
+
+// Should Correctly Serialize and Deserialize Ordered Hash
+var doc = {doc: {b:1, a:2, c:3, d:4}}
+var serialized_data = bsonC.serialize(doc)
+var decoded_hash = bsonC.deserialize(serialized_data).doc
+var keys = []
+for(name in decoded_hash) keys.push(name)
+assert.deepEqual(['b', 'a', 'c', 'd'], keys)
+
+// Should Correctly Serialize and Deserialize Regular Expression
+// Serialize the regular expression
+var doc = {doc: /foobar/mi}
+var serialized_data = bsonC.serialize(doc)
+var doc2 = bsonC.deserialize(serialized_data);
+assert.equal(doc.doc.toString(), doc2.doc.toString())
+
+// Should Correctly Serialize and Deserialize a Binary object
+var bin = new Binary()
+var string = 'binstring'
+for(var index = 0; index < string.length; index++) {
+ bin.put(string.charAt(index))
+}
+var doc = {doc: bin}
+var serialized_data = bsonC.serialize(doc)
+var deserialized_data = bsonC.deserialize(serialized_data);
+assert.equal(doc.doc.value(), deserialized_data.doc.value())
+
+// Should Correctly Serialize and Deserialize a big Binary object
+var data = fs.readFileSync("../../test/gridstore/test_gs_weird_bug.png", 'binary');
+var bin = new Binary()
+bin.write(data)
+var doc = {doc: bin}
+var serialized_data = bsonC.serialize(doc)
+var deserialized_data = bsonC.deserialize(serialized_data);
+assert.equal(doc.doc.value(), deserialized_data.doc.value())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js b/node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js
new file mode 100644
index 0000000..f271cac
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js
@@ -0,0 +1,132 @@
+var Buffer = require('buffer').Buffer,
+ BSON = require('../bson').BSON,
+ Buffer = require('buffer').Buffer,
+ BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
+ BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
+ Long = require('../../../lib/mongodb/bson/long').Long,
+ ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
+ Binary = require('../../../lib/mongodb/bson/bson').Binary,
+ Code = require('../../../lib/mongodb/bson/bson').Code,
+ DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
+ Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
+ Double = require('../../../lib/mongodb/bson/bson').Double,
+ MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
+ MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
+ Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp;
+ assert = require('assert');
+
+if(process.env['npm_package_config_native'] != null) return;
+
+console.log("=== EXECUTING TEST_STACKLESS_BSON ===");
+
+// Parsers
+var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
+
+// Number of iterations for the benchmark
+var COUNT = 10000;
+// var COUNT = 1;
+// Sample simple doc
+var doc = {key:"Hello world", key2:"šđžčćŠĐŽČĆ", key3:'客家话', key4:'how are you doing dog!!'};
+// var doc = {};
+// for(var i = 0; i < 100; i++) {
+// doc['string' + i] = "dumdyms fsdfdsfdsfdsfsdfdsfsdfsdfsdfsdfsdfsdfsdffsfsdfs";
+// }
+
+// // Calculate size
+console.log(bsonC.calculateObjectSize2(doc));
+console.log(bsonJS.calculateObjectSize(doc));
+// assert.equal(bsonJS.calculateObjectSize(doc), bsonC.calculateObjectSize2(doc));
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// Benchmark calculateObjectSize
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+// Benchmark 1 JS BSON
+console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize(object))")
+start = new Date
+
+for (j=COUNT; --j>=0; ) {
+ var objectBSON = bsonJS.calculateObjectSize(doc);
+}
+
+end = new Date
+var opsprsecond = COUNT / ((end - start)/1000);
+console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+
+// Benchmark 2 C++ BSON calculateObjectSize
+console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize(object))")
+start = new Date
+
+for (j=COUNT; --j>=0; ) {
+ var objectBSON = bsonC.calculateObjectSize(doc);
+}
+
+end = new Date
+var opsprsecond = COUNT / ((end - start)/1000);
+console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+
+// Benchmark 3 C++ BSON calculateObjectSize2
+console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize2(object))")
+start = new Date
+
+for (j=COUNT; --j>=0; ) {
+ var objectBSON = bsonC.calculateObjectSize2(doc);
+}
+
+end = new Date
+var opsprsecond = COUNT / ((end - start)/1000);
+console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+
+// // Serialize the content
+// var _serializedDoc1 = bsonJS.serialize(doc, true, false);
+// var _serializedDoc2 = bsonC.serialize2(doc, true, false);
+// console.dir(_serializedDoc1);
+// console.dir(_serializedDoc2);
+// assert.equal(_serializedDoc1.toString('base64'), _serializedDoc2.toString('base64'))
+//
+//
+// // Benchmark 1
+// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
+// start = new Date
+//
+// for (j=COUNT; --j>=0; ) {
+// // var objectBSON = bsonC.serialize2(doc, true, false);
+// var objectBSON = bsonJS.serialize(doc, true, false);
+// }
+//
+// end = new Date
+// var opsprsecond = COUNT / ((end - start)/1000);
+// console.log("bson size (bytes): ", objectbsonC.length);
+// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
+//
+// // Benchmark 2
+// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
+// start = new Date
+//
+// for (j=COUNT; --j>=0; ) {
+// var objectBSON = bsonC.serialize2(doc, true, false);
+// }
+//
+// end = new Date
+// var opsprsecond = COUNT / ((end - start)/1000);
+// console.log("bson size (bytes): ", objectbsonC.length);
+// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
+//
+// // Benchmark 3
+// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
+// start = new Date
+//
+// for (j=COUNT; --j>=0; ) {
+// var objectBSON = bsonC.serialize(doc, true, false);
+// }
+//
+// end = new Date
+// var opsprsecond = COUNT / ((end - start)/1000);
+// console.log("bson size (bytes): ", objectbsonC.length);
+// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
+// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
diff --git a/node_modules/mongodb/external-libs/bson/wscript b/node_modules/mongodb/external-libs/bson/wscript
new file mode 100644
index 0000000..40f5317
--- /dev/null
+++ b/node_modules/mongodb/external-libs/bson/wscript
@@ -0,0 +1,39 @@
+import Options
+from os import unlink, symlink, popen
+from os.path import exists
+
+srcdir = "."
+blddir = "build"
+VERSION = "0.1.0"
+
+def set_options(opt):
+ opt.tool_options("compiler_cxx")
+ opt.add_option( '--debug'
+ , action='store_true'
+ , default=False
+ , help='Build debug variant [Default: False]'
+ , dest='debug'
+ )
+
+def configure(conf):
+ conf.check_tool("compiler_cxx")
+ conf.check_tool("node_addon")
+ conf.env.append_value('CXXFLAGS', ['-O3', '-funroll-loops'])
+
+ # conf.env.append_value('CXXFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra'])
+ # conf.check(lib='node', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='NODE')
+
+def build(bld):
+ obj = bld.new_task_gen("cxx", "shlib", "node_addon")
+ obj.target = "bson"
+ obj.source = ["bson.cc"]
+ # obj.uselib = "NODE"
+
+def shutdown():
+ # HACK to get compress.node out of build directory.
+ # better way to do this?
+ if Options.commands['clean']:
+ if exists('bson.node'): unlink('bson.node')
+ else:
+ if exists('build/default/bson.node') and not exists('bson.node'):
+ symlink('build/default/bson.node', 'bson.node')