Commits

vadimtsushko committed fc8e63f

Initial commit

Comments (0)

Files changed (31)

.hgignore

Empty file added.

lib/bson/binary.dart

+class Binary extends BsonObject{
+  static final BUFFER_SIZE = 256;
+  static final SUBTYPE_DEFAULT = 0;
+  static final SUBTYPE_FUNCTION = 1;
+  static final SUBTYPE_BYTE_ARRAY = 2;
+  static final SUBTYPE_UUID = 3;
+  static final SUBTYPE_MD5 = 4;
+  static final SUBTYPE_USER_DEFINED = 128;
+  //static final minBits = [1,2,3,4];
+  ByteArray bytes;
+  int offset;
+  Binary(int length): bytes = new ByteArray(length),offset=0;
+  String toHexString(){
+    StringBuffer stringBuffer = new StringBuffer();
+    for (final byte in bytes)
+    {      
+       if (byte < 16){
+        stringBuffer.add("0");
+       }       
+       stringBuffer.add(byte.toRadixString(16));
+    }
+    return stringBuffer.toString().toLowerCase();
+  }  
+  setIntExtended(int value, int numOfBytes){
+    ByteArray bytesTmp = new ByteArray(8);
+    if (numOfBytes == 3){
+      bytesTmp.setInt32(0,value);
+    }
+    else if (numOfBytes > 4 && numOfBytes < 8){
+      bytesTmp.setInt64(0,value);
+    }
+    else {
+        throw new Exception("Unsupported num of bits: ${numOfBytes*8}");
+    }
+    bytes.setRange(offset,numOfBytes,bytesTmp);
+  }
+  reverse(int numOfBytes){
+    swap(int x, int y){
+      int t = bytes[x+offset];
+      bytes[x+offset] = bytes[y+offset];
+      bytes[y+offset] = t;
+    }
+    for(int i=0;i<=(numOfBytes-1)%2;i++){
+      swap(i,numOfBytes-1-i);
+    }
+  }
+  encodeInt(int position,int value, int numOfBytes, bool forceBigEndian, bool signed) {
+    int bits = numOfBytes << 3; 
+    int max = Statics.MaxBits(bits);
+
+    if (value >= max || value < -(max / 2)) {
+      throw new Exception("encodeInt::overflow");      
+    }
+    switch(bits) {
+      case 32: 
+        bytes.setInt32(position,value);
+        break;
+      case 16: 
+        bytes.setInt16(position,value);
+        break;
+      case 8: 
+        bytes.setInt8(position,value);        
+        break;
+      case 24:        
+        setIntExtended(value,numOfBytes);
+        break;      
+      default:
+        throw new Exception("Unsupported num of bits: $bits");
+    }
+    if (forceBigEndian){
+      reverse(numOfBytes);
+    }
+  }
+  writeInt(int value, [int numOfBytes=4,bool forceBigEndian=false, bool signed=false]){
+    encodeInt(offset,value, numOfBytes,forceBigEndian,signed);
+    offset += numOfBytes;
+  }
+  writeByte(int value){
+    encodeInt(offset,value, 1,false,false);
+    offset += 1;
+  }
+  int writeDouble(){    
+    bytes.setFloat64(offset);
+    offset+=8;
+  } 
+  int writeInt64(){    
+    bytes.setInt64(offset);
+    offset+=8;
+  } 
+  int readByte(){    
+    return bytes[offset++];
+  }
+  int readInt32(){    
+    offset+=4;
+    return bytes.getInt32(offset-4);    
+  }  
+  int readInt64(){    
+    offset+=8;
+    return bytes.getInt64(offset-8);
+  }    
+  num readDouble(){    
+    offset+=8;
+    return bytes.getFloat64(offset-8);
+  }    
+
+  String readCString(){ 
+    List<int> stringBytes = [];
+    while (bytes[offset++]!= 0){
+       stringBytes.add(bytes[offset-1]);
+    }
+    return new String.fromCharCodes(stringBytes);
+  }  
+
+  warn(String msg){
+    print("Warning!!! $msg");
+  }
+  int byteLength() => bytes.length;
+  bool atEnd() => offset == bytes.length;
+  rewind(){
+    offset = 0;
+  }
+}

lib/bson/bson.dart

+#library("bson.dart");
+#import("../../../../../../dartrepo/dart-read-only/dart/utils/string_encoding/utf8.dart");
+#source("bson_type.dart");
+#source("objectid.dart");
+#source("timestamp.dart");
+#source("binary.dart");
+#source("statics.dart");
+#source("min_max_keys.dart");
+#source("bson_int.dart");
+#source("bson_string.dart");
+#source("bson_map.dart");
+#source("bson_array.dart");
+#source("bson_impl.dart");
+#source("bson_double.dart");
+
+

lib/bson/bson_array.dart

+class BsonArray extends BsonObject{
+  List data;
+  int _dataSize;
+  int dataSize(){
+    if (_dataSize === null){
+      _dataSize = 0;
+      for(var i = 0; i < data.length; i++) {
+        _dataSize += elementSize(i.toString(), data[i]);
+      }
+    }    
+    return _dataSize;
+  }
+
+  BsonArray(this.data);
+  get value()=>data;
+  byteLength()=>dataSize()+1+4;
+  int get typeByte() => BSON.BSON_DATA_ARRAY;  
+  packValue(Binary buffer){
+    buffer.writeInt(byteLength());
+      for(var i = 0; i < data.length; i++) {
+         bsonObjectFrom(data[i]).packElement(i.toString() ,buffer);
+      }
+     buffer.writeByte(0);
+  }  
+
+  unpackValue(Binary buffer){
+    data = [];        
+    buffer.offset += 4;
+    int typeByte = buffer.readByte();    
+    while (typeByte != 0){
+      BsonObject bsonObject = bsonObjectFromTypeByte(typeByte);
+      var element = bsonObject.unpackElement(buffer);
+      data.add(element.value);    
+      typeByte = buffer.readByte();
+    }    
+  }
+
+}

lib/bson/bson_double.dart

+class BsonDouble extends BsonObject{
+  num data;
+  BsonDouble(this.data);
+  get value()=>data;
+  byteLength()=>8;
+  int get typeByte() => BSON.BSON_DATA_NUMBER;
+  packValue(Binary buffer){
+     buffer.writeDouble(data);
+  }
+  unpackValue(Binary buffer){
+     data = buffer.readDouble();
+  }
+}

lib/bson/bson_impl.dart

+class BSON {
+
+  static final BSON_INT32_MAX = 0x7FFFFFFF;
+  static final BSON_INT32_MIN = -0x80000000;
+
+  static final BSON_INT64_MAX = Math.pow(2, 63) - 1;
+  static final BSON_INT64_MIN = -Math.pow(2, 63);
+
+  // JS MAX PRECISE VALUES
+  static final JS_INT_MAX = 0x20000000000000;  // Any integer up to 2^53 can be precisely represented by a double.
+  static final JS_INT_MIN = -0x20000000000000;  // Any integer down to -2^53 can be precisely represented by a double.
+
+  // Internal long versions
+  static final JS_INT_MAX_LONG = 0x20000000000000;  // Any integer up to 2^53 can be precisely represented by a double.
+  static final JS_INT_MIN_LONG = -0x20000000000000;  // Any integer down to -2^53 can be precisely represented by a double.
+
+  /**
+   * Number BSON Type
+   *  
+   * @classconstant BSON_DATA_NUMBER
+   **/
+  static final BSON_DATA_NUMBER = 1;
+  /**
+   * String BSON Type
+   *  
+   * @classconstant BSON_DATA_STRING
+   **/
+  static final BSON_DATA_STRING = 2;
+  /**
+   * Object BSON Type
+   *  
+   * @classconstant BSON_DATA_OBJECT
+   **/
+  static final BSON_DATA_OBJECT = 3;
+  /**
+   * Array BSON Type
+   *  
+   * @classconstant BSON_DATA_ARRAY
+   **/
+  static final BSON_DATA_ARRAY = 4;
+  /**
+   * Binary BSON Type
+   *  
+   * @classconstant BSON_DATA_BINARY
+   **/
+  static final BSON_DATA_BINARY = 5;
+  /**
+   * ObjectID BSON Type
+   *  
+   * @classconstant BSON_DATA_OID
+   **/
+  static final BSON_DATA_OID = 7;
+  /**
+   * Boolean BSON Type
+   *  
+   * @classconstant BSON_DATA_BOOLEAN
+   **/
+  static final BSON_DATA_BOOLEAN = 8;
+  /**
+   * Date BSON Type
+   *  
+   * @classconstant BSON_DATA_DATE
+   **/
+  static final BSON_DATA_DATE = 9;
+  /**
+   * null BSON Type
+   *  
+   * @classconstant BSON_DATA_NULL
+   **/
+  static final BSON_DATA_NULL = 10;
+  /**
+   * RegExp BSON Type
+   *  
+   * @classconstant BSON_DATA_REGEXP
+   **/
+  static final BSON_DATA_REGEXP = 11;
+  /**
+   * Code BSON Type
+   *  
+   * @classconstant BSON_DATA_CODE
+   **/
+  static final BSON_DATA_CODE = 13;
+  /**
+   * Symbol BSON Type
+   *  
+   * @classconstant BSON_DATA_SYMBOL
+   **/
+  static final BSON_DATA_SYMBOL = 14;
+  /**
+   * Code with Scope BSON Type
+   *  
+   * @classconstant BSON_DATA_CODE_W_SCOPE
+   **/
+  static final BSON_DATA_CODE_W_SCOPE = 15;
+  /**
+   * 32 bit Integer BSON Type
+   *  
+   * @classconstant BSON_DATA_INT
+   **/
+  static final BSON_DATA_INT = 16;
+  /**
+   * Timestamp BSON Type
+   *  
+   * @classconstant BSON_DATA_TIMESTAMP
+   **/
+  static final BSON_DATA_TIMESTAMP = 17;
+  /**
+   * Long BSON Type
+   *  
+   * @classconstant BSON_DATA_LONG
+   **/
+  static final BSON_DATA_LONG = 18;
+  /**
+   * MinKey BSON Type
+   *  
+   * @classconstant BSON_DATA_MIN_KEY
+   **/
+  static final BSON_DATA_MIN_KEY = 0xff;
+  /**
+   * MaxKey BSON Type
+   *  
+   * @classconstant BSON_DATA_MAX_KEY
+   **/
+  static final BSON_DATA_MAX_KEY = 0x7f;
+
+  /**
+   * Binary Default Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
+   **/
+  static final BSON_BINARY_SUBTYPE_DEFAULT = 0;
+  /**
+   * Binary Function Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
+   **/
+  static final BSON_BINARY_SUBTYPE_FUNCTION = 1;
+  /**
+   * Binary Byte Array Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
+   **/
+  static final BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
+  /**
+   * Binary UUID Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_UUID
+   **/
+  static final BSON_BINARY_SUBTYPE_UUID = 3;
+  /**
+   * Binary MD5 Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_MD5
+   **/
+  static final BSON_BINARY_SUBTYPE_MD5 = 4;
+  /**
+   * Binary User Defined Type
+   *  
+   * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
+   **/
+  static final BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
+
+
+  Binary serialize(var object, [int offset = 0]) {
+    if (!((object is Map) || (object is List))){
+      throw new Exception("Invalid value for BSON serialize: $object");
+    }
+    BsonObject bsonObject = bsonObjectFrom(object);    
+    Binary buffer = new Binary(bsonObject.byteLength()+offset);
+    buffer.offset = offset;
+    bsonObjectFrom(object).packValue(buffer);
+    return buffer;  
+  }
+  deserialize(Binary buffer){
+    if(buffer.bytes.length < 5){
+      throw new Exception("corrupt bson message < 5 bytes long");
+    }    
+    var bsonMap = new BsonMap(null);
+    bsonMap.unpackValue(buffer);
+    return bsonMap.value;
+  }
+}

lib/bson/bson_int.dart

+class BsonInt extends BsonObject{
+  int data;
+  BsonInt(this.data);
+  get value()=>data;
+  byteLength()=>4;
+  int get typeByte() => BSON.BSON_DATA_INT;
+  packValue(Binary buffer){
+     buffer.writeInt(data);
+  }
+  unpackValue(Binary buffer){
+     data = buffer.readInt32();
+  }
+}

lib/bson/bson_map.dart

+class BsonMap extends BsonObject{
+  Map data;
+  int _dataSize;
+  int dataSize(){
+    if (_dataSize === null){
+      _dataSize = 0;
+      data.forEach((var key, var value)
+        {
+           _dataSize += elementSize(key, value);
+        });
+    }    
+    return _dataSize;
+  }
+  BsonMap(this.data);
+  get value()=>data;
+  byteLength()=>dataSize()+1+4;
+  int get typeByte() => BSON.BSON_DATA_OBJECT;  
+  packValue(Binary buffer){
+    buffer.writeInt(byteLength());
+    data.forEach((var key, var value)
+      {
+         bsonObjectFrom(value).packElement(key ,buffer);
+      });     
+     buffer.writeByte(0);
+  }
+  unpackValue(Binary buffer){
+    data = {};    
+    buffer.offset += 4;    
+    int typeByte = buffer.readByte();
+    while (typeByte != 0){
+      BsonObject bsonObject = bsonObjectFromTypeByte(typeByte);
+      var element = bsonObject.unpackElement(buffer);
+      data[element.name] = element.value;    
+      typeByte = buffer.readByte();
+    }    
+  }
+}

lib/bson/bson_string.dart

+class BsonString extends BsonObject{
+  String data;
+  BsonString(this.data);
+  get value()=>data;
+  byteLength()=>data.length+1+4;
+  int get typeByte() => BSON.BSON_DATA_STRING;  
+  packValue(Binary buffer){
+     buffer.writeInt(data.length+1);
+     buffer.bytes.setRange(buffer.offset,data.length,data.charCodes());
+     buffer.offset += data.length;
+     buffer.writeByte(0);
+  }
+}
+
+class BsonCString extends BsonObject{
+  String data;
+  BsonCString(this.data);
+  get value()=>data;
+  byteLength()=>data.length+1;
+  packValue(Binary buffer){
+     buffer.bytes.setRange(buffer.offset,data.length,data.charCodes());
+     buffer.offset += data.length;
+     buffer.writeByte(0);    
+  }
+}

lib/bson/bson_type.dart

+class ElementPair{
+  String name;
+  var value;
+  ElementPair([this.name,this.value]);
+}
+class BsonObject {  
+  int get typeByte(){ throw const Exception("must be implemented");}
+  int byteLength() => 0;
+  packElement(String name, var buffer){
+    buffer.writeByte(typeByte);
+    if (name !== null){
+      new BsonCString(name).packValue(buffer);
+    }
+    packValue(buffer);
+  } 
+  packValue(var buffer){ throw const Exception("must be implemented");}
+
+  ElementPair unpackElement(buffer){
+    ElementPair result = new ElementPair();
+    result.name = buffer.readCString();    
+    unpackValue(buffer);
+    result.value = value;
+    return result;
+  }
+  uppackValue(var buffer){ throw const Exception("must be implemented");}
+  get value()=>null;
+}
+
+ int elementSize(name, value) {
+    int size = 1;
+    if (name !== null){
+      size += name.length + 1;
+    } 
+    size += bsonObjectFrom(value).byteLength();
+    return size;
+  }
+BsonObject bsonObjectFrom(var value){
+  if (value is BsonObject){
+    return value;
+  }
+  if (value is int){
+    return new BsonInt(value);
+  }    
+  if (value is num){
+    return new BsonDouble(value);
+  } 
+
+  if (value is String){
+    return new BsonString(value);
+  }        
+  if (value is Map){
+    return new BsonMap(value);
+  }        
+  if (value is List){
+    return new BsonArray(value);
+  }        
+  throw new Exception("Not implemented for $value");           
+}  
+
+BsonObject bsonObjectFromTypeByte(int typeByte){
+  switch(typeByte){
+    case BSON.BSON_DATA_INT:
+      return new BsonInt(null);
+    case BSON.BSON_DATA_NUMBER:
+      return new BsonDouble(null);
+    case BSON.BSON_DATA_STRING:
+      return new BsonString(null);
+    case BSON.BSON_DATA_ARRAY:
+      return new BsonArray([]);
+    case BSON.BSON_DATA_OBJECT:
+      return new BsonMap({});
+    default:
+      throw new Exception("Not implemented for BSON TYPE $typeByte");           
+  }  
+}
+

lib/bson/min_max_keys.dart

+class MinKey extends BsonObject{
+
+}
+class MaxKey extends BsonObject{  
+}

lib/bson/objectid.dart

+class ObjectId extends BsonObject{  
+  Binary id;
+  factory ObjectId(){
+    Timestamp ts = new Timestamp(null,0);    
+    return new ObjectId.fromSeconds(ts.seconds);
+  }
+  ObjectId.fromSeconds(int seconds): id=new Binary(12){
+    id.writeInt(seconds,4,forceBigEndian:true);
+    id.writeInt(Statics.MachineId,3);
+    id.writeInt(Statics.Pid,2);    
+    id.writeInt(Statics.nextIncrement,3,forceBigEndian:true);
+  }  
+  String toString()=>"ObjectId(${id.toHexString()})";
+  get value() => id;
+  int byteLength() => 12;
+}

lib/bson/statics.dart

+class Statics{
+  static int _current_increment;
+  static int get nextIncrement()
+  {
+    if (_current_increment === null)
+    {
+      _current_increment = 0;
+    } 
+    return _current_increment++;
+  }   
+  static int _requestId;
+  static int get nextRequestId()
+  {
+    if (_requestId === null)
+    {
+      _requestId = 1;
+    } 
+    return ++_requestId;
+  }   
+
+  static List<int> _maxBits;  
+  static int MaxBits(int bits){    
+    int res;
+    if (_maxBits === null){
+      _maxBits = new List<int>(65);
+      _maxBits[0] = 0;
+      for (var i = 1; i < 65; i++) {
+        _maxBits[i]=(2 << i-1);
+      }
+    }
+    return _maxBits[bits];
+  }
+  static num _MashineId;
+  static num get MachineId(){
+    if (_MashineId === null){
+       _MashineId = (Math.random() * 0xFFFFFFFF).floor().toInt();
+    }
+    return _MashineId;
+  }
+  static num _Pid;
+  static num get Pid(){
+    if (_Pid === null){
+       _Pid = (Math.random() * 0xFFFF).floor().toInt();
+    }
+    return _Pid;
+  }  
+}

lib/bson/timestamp.dart

+class Timestamp extends BsonObject{  
+  int seconds;
+  int increment;  
+  Timestamp([this.seconds,this.increment]){
+    if (seconds === null){
+      seconds = (new Date.now().value / 1000).toInt();
+    }
+    if (increment === null){
+      increment = Statics.nextIncrement;
+    }          
+  }
+  String toString()=>"Timestamp(seconds: $seconds, increment: $increment)";
+  int byteLength() => 8;  
+}
+#library("mongo");
+#import("dart:io");
+#import("bson/bson.dart");
+#source("networking/connection.dart");
+#source("networking/mongo_message.dart");
+#source("networking/mongo_query_message.dart");
+#source("networking/mongo_reply_message.dart");

lib/networking/connection.dart

+class SocketOptions{
+  String host;
+  int port;  
+  SocketOptions([this.host='127.0.0.1', this.port=27017]);
+}
+class Connection{
+  Binary lengthBuffer;
+  SocketOptions socketOptions;
+  Binary messageBuffer;
+  Socket socket;
+  var completeCallback;
+  Connection(){
+    socketOptions = new SocketOptions();
+  }
+  connect(){
+    socket = new Socket(socketOptions.host, socketOptions.port);
+    if (socket == null) {
+      throw "can't get send socket";
+    }
+    lengthBuffer = new Binary(4);
+  }
+  int sendData(Binary msg){
+    while (msg.offset != msg.bytes.length){
+      msg.offset += socket.writeList(msg.bytes,msg.offset,msg.bytes.length-msg.offset);
+    }    
+    return msg.offset;
+  }
+  
+   void receiveData() {
+    if (messageBuffer === null){
+      int numBytes = socket.readList(lengthBuffer.bytes, 0, 4);
+      if (numBytes == 0) {
+        return;
+      }
+      int messageLength = lengthBuffer.readInt32();      
+      print(messageLength);
+      messageBuffer = new Binary(messageLength);
+      messageBuffer.writeInt(messageLength);
+    }
+    messageBuffer.offset += socket.readList(messageBuffer.bytes,messageBuffer.offset,messageBuffer.bytes.length-messageBuffer.offset);
+    if (messageBuffer.atEnd()){
+      socket.onData = null;
+      socket.onError = null;
+      MongoReplyMessage reply = new MongoReplyMessage();
+      messageBuffer.rewind();
+      reply.deserialize(messageBuffer);
+      completeCallback(reply);
+    }   
+  }
+  query(MongoQueryMessage queryMessage, callback){
+    completeCallback = callback;
+    Binary buffer = queryMessage.serialize();  
+    socket.onError = ()=>print("Socket error");  
+    socket.onData = receiveData;
+    sendData(buffer);
+  }
+}

lib/networking/mongo_message.dart

+class MongoMessage{
+  static final Reply = 1;
+  static final Message = 1000;
+  static final Update = 2001;
+  static final Insert = 2002;
+  static final Query = 2004;
+  static final GetMore = 2005;
+  static final Delete = 2006;
+  static final KillCursors = 2007;
+
+  int _messageLength;
+  int _requestId;
+  int get requestId(){
+    if (_requestId === null){
+      _requestId = Statics.nextRequestId;    
+    }
+    return _requestId;      
+  }
+  int responseTo;
+  int opcode = MongoMessage.Reply;
+  int get messageLength(){
+    throw ("Must be implemented");
+  }
+  Binary serialize(){
+    throw Exception("Must be implemented");    
+  }  
+  MongoMessage deserialize(Binary buffer){
+    throw Exception("Must be implemented");    
+  }  
+  readMessageHeaderFrom(Binary buffer)
+  {
+      _messageLength = buffer.readInt32();
+      _requestId = buffer.readInt32();
+      responseTo = buffer.readInt32();
+      if (buffer.readInt32() != opcode)
+      {
+          throw "Message header opcode is not the expected one.";
+      }
+  }
+
+  writeMessageHeaderTo(Binary buffer)
+  {
+      buffer.writeInt(messageLength); // messageLength will be backpatched later
+      buffer.writeInt(requestId);
+      buffer.writeInt(0); // responseTo not used in requests sent by client
+      buffer.writeInt(opcode);
+  }
+
+}

lib/networking/mongo_query_message.dart

+class MongoQueryMessage extends MongoMessage{
+  BsonCString _collectionFullName;
+  int flags;
+  int numberToSkip;
+  int numberToReturn;
+  BsonMap _query;
+  BsonMap _fields;
+  MongoQueryMessage(String collectionFullName,
+            this.flags,
+            this.numberToSkip,
+            this.numberToReturn,
+            Map query,
+            Map fields){
+    _collectionFullName = new BsonCString(collectionFullName);
+    _query = new BsonMap(query);
+    if (fields !== null){
+      _fields = new BsonMap(fields);
+    }
+    opcode = MongoMessage.Query;    
+  }
+  int get messageLength(){
+    int result = 16+4+_collectionFullName.byteLength()+4+4+_query.byteLength();
+    if (_fields !== null){
+      result += _fields.byteLength();
+    }
+    return result;
+  }
+  Binary serialize(){
+    Binary buffer = new Binary(messageLength);
+    writeMessageHeaderTo(buffer);
+    buffer.writeInt(flags);
+    _collectionFullName.packValue(buffer);
+    buffer.writeInt(numberToSkip);
+    buffer.writeInt(numberToReturn);
+    _query.packValue(buffer);
+    buffer.offset = 0;
+    return buffer;
+  }
+}

lib/networking/mongo_reply_message.dart

+class MongoReplyMessage extends MongoMessage{
+  BsonCString _collectionFullName;
+  int responseFlags;
+  // 64bit integer
+  int cursorId =-1; 
+  int startingFrom;
+  int numberReturned = -1;
+  List documents;  
+  deserialize(Binary buffer){
+    readMessageHeaderFrom(buffer);
+    responseFlags = buffer.readInt32();
+    cursorId = buffer.readInt64();
+    startingFrom = buffer.readInt32();
+    numberReturned = buffer.readInt32();
+    documents = new List(numberReturned);
+    for (int n=0;n<numberReturned;n++){
+      BsonMap doc = new BsonMap({});
+      doc.unpackValue(buffer);
+      documents[n] = doc.value;
+    }
+  }
+  int get messageLength(){
+    int result = 16+4+_collectionFullName.byteLength()+4+4+_query.byteLength();
+    if (_fields !== null){
+      result += _fields.byteLength();
+    }
+    return result;
+  }
+  Binary serialize(){
+    Binary buffer = new Binary(messageLength);
+    writeMessageHeaderTo(buffer);
+    buffer.writeInt(flags);
+    _collectionFullName.packValue(buffer);
+    buffer.writeInt(numberToSkip);
+    buffer.writeInt(numberToReturn);
+    _query.packValue(buffer);
+    buffer.offset = 0;
+    return buffer;
+  }
+}

mongo.status

Empty file added.

tests/ConnectionTest.dart

+#import("../lib/mongo.dart");
+#import("../lib/bson/bson.dart");
+#import("dart:io");
+main(){
+  Connection conn = new Connection();
+  conn.connect();
+  MongoQueryMessage queryMessage = new MongoQueryMessage("db.\$cmd",0,0,0xffffffff,{"ping":0x1},null);
+/*
+  Binary buffer = queryMessage.serialize();
+  print(buffer.toHexString());
+  Expect.stringEquals('350000000200000000000000d407000000000000746573742e24636d640000000000ffffffff0f0000001070696e67000100000000',
+    buffer.toHexString());
+*/    
+  //print(conn.sendMessage(buffer));
+  conn.query(queryMessage,(reply)=>print(reply.documents));
+}

tests/bson/BSonTypesTest.dart

+#import("../../lib/bson/bson.dart");
+main(){
+  Expect.isTrue(bsonObjectFrom(1234) is BsonInt);
+  Expect.isTrue(bsonObjectFrom("asdfasdf") is BsonString);
+}

tests/bson/BsonBinaryTest.dart

+#import("../../lib/bson/bson.dart");
+testBinary(){
+   Binary b = new Binary(8);
+   b.writeInt(0,4);
+   b.writeInt(1,4);
+   Expect.equals(b.toHexString(),'0000000001000000');   
+   b = new Binary(8);
+   b.writeInt(0,4);
+   b = new Binary(8);
+   b.writeInt(0,4);
+   b.writeInt(0x01020304,4);
+   Expect.equals(b.toHexString(),'0000000004030201');
+   b = new Binary(8);
+   b.writeInt(0,4);
+   b.writeInt(0x01020304,4,forceBigEndian:true);
+   Expect.equals(b.toHexString(),'0000000001020304');
+   b = new Binary(8);
+   b.writeInt(0,4);
+   b.writeInt(1,4,forceBigEndian:true);   
+   Expect.equals(b.toHexString(),'0000000000000001');   
+   b = new Binary(8);   
+   b.writeInt(1,3,forceBigEndian:true);
+   Expect.equals('0000010000000000',b.toHexString());
+   b = new Binary(8);
+   b.writeInt(0,3);
+   b.writeInt(1,3,forceBigEndian:true);
+   Expect.equals('0000000000010000',b.toHexString());   
+}
+
+main(){
+   testBinary();
+}

tests/bson/BsonImplTest.dart

+#import("../../lib/bson/bson.dart");
+testSerializeDesirialize(){
+  var bson = new BSON();
+  var map = {'_id':5, 'a':4};
+  Binary buffer = bson.serialize(map);
+  Expect.stringEquals('15000000105f696400050000001061000400000000',buffer.toHexString());
+  buffer.offset = 0;
+  Map root = bson.deserialize(buffer);    
+  Expect.equals(root['a'],4);
+  Expect.equals(root['_id'],5);
+  var doc1 = {'a': [15]};
+  buffer = bson.serialize(doc1);
+  Expect.stringEquals('140000000461000c0000001030000f0000000000',buffer.toHexString());
+  buffer.offset = 0;
+  root = bson.deserialize(buffer);  
+  Expect.equals(15, root['a'][0]);
+  doc1 = {'_id':5, 'a': [2,3,5]};    
+  buffer = bson.serialize(doc1);
+  Expect.stringEquals('2b000000105f696400050000000461001a0000001030000200000010310003000000103200050000000000',buffer.toHexString());
+  buffer.offset = 0;
+  buffer.readByte();
+  Expect.equals(1,buffer.offset);
+  buffer.readInt32();
+  Expect.equals(5,buffer.offset);
+  buffer.offset = 0;
+  root = bson.deserialize(buffer);  
+  Expect.equals(doc1['a'][2],root['a'][2]);
+  Expect.equals(buffer.byteLength(),buffer.offset);
+}
+main(){
+ testSerializeDesirialize();
+}

tests/bson/BsonObjectIdTest.dart

+#import("../../lib/bson/bson.dart");
+testObjectId(){
+  var id1 = new ObjectId();
+  Expect.isNotNull(id1);
+  id1 = new ObjectId();
+  var id2 = new ObjectId();
+  Expect.notEquals(id1,id2,"ObjectIds must be different albeit by increment");
+  id1 = new ObjectId.fromSeconds(10);
+  var leading8chars = id1.id.toHexString().substring(0,8);
+  Expect.stringEquals("0000000a",leading8chars, 'Timestamp part of ObjectId must be encoded BigEndian');
+}
+
+main(){
+   testObjectId();
+}

tests/bson/data/01.data

Binary file added.

tests/bson/data/02.data

Binary file added.

tests/bson/data/03.data

Binary file added.

tests/bson/data/create_test_data.rb

+require 'bson'
+doc = {'_id'=>5, 'a'=>4}
+message = BSON::BSON_RUBY.serialize(doc)
+
+#message.to_a.each do | byte |
+    #puts byte.to_i
+#end
+
+File.open('01.data', "wb") do |file|
+   file.write(message.to_a.pack('C*'))
+end
+
+doc = {'_id'=>5, 'a'=> [2,3,5]}
+message = BSON::BSON_RUBY.serialize(doc)
+message.to_a.each do | byte |
+    puts byte.to_i
+end
+
+File.open('02.data', "wb") do |file|
+   file.write(message.to_a.pack('C*'))
+end
+
+doc = {'a'=> [15]}
+message = BSON::BSON_RUBY.serialize(doc)
+message.to_a.each do | byte |
+    puts byte.to_i
+end
+
+File.open('03.data', "wb") do |file|
+   file.write(message.to_a.pack('C*'))
+end

tests/bson/data/create_test_message.rb

+require 'mongo'
+
+db = Mongo::Connection.new.db("test")
+print db.command({ping:1})

tests/bson/data/test.data

Binary file added.