1. Liam Staskawicz
  2. fantomongo

Source

fantomongo / fan / bson / BsonReader.fan

Liam Staskawicz 2282ec2 
















Liam Staskawicz 2d0737e 






Liam Staskawicz 6e5f66e 

Liam Staskawicz 2d0737e 








Liam Staskawicz 60843f6 
Liam Staskawicz 2d0737e 
Liam Staskawicz 60843f6 

Liam Staskawicz 2d0737e 

Liam Staskawicz 60843f6 

Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 
Liam Staskawicz 018c10d 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 

Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 

Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 

Liam Staskawicz 2d0737e 
Liam Staskawicz 018c10d 

Liam Staskawicz 932bcef 
Liam Staskawicz d7b01fd 
Liam Staskawicz 932bcef 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 
Liam Staskawicz 932bcef 
Liam Staskawicz 2d0737e 




















Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 




Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 





Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 




Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 




Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 




Liam Staskawicz 60843f6 
Liam Staskawicz a0e5da4 
Liam Staskawicz e37a57a 
Liam Staskawicz a0e5da4 
Liam Staskawicz 60843f6 

Liam Staskawicz a0e5da4 

Liam Staskawicz 9c54375 

Liam Staskawicz a0e5da4 
Liam Staskawicz 2d0737e 
Liam Staskawicz a0e5da4 
Liam Staskawicz 2d0737e 




Liam Staskawicz 60843f6 
Liam Staskawicz 6e5f66e 
Liam Staskawicz 2d0737e 




















Liam Staskawicz e1824f1 
Liam Staskawicz 2d0737e 











Liam Staskawicz d7b01fd 
Liam Staskawicz 2d0737e 

Liam Staskawicz 60843f6 
Liam Staskawicz e37a57a 
Liam Staskawicz 60843f6 
Liam Staskawicz e37a57a 

Liam Staskawicz 6e5f66e 

Liam Staskawicz d7b01fd 
Liam Staskawicz e37a57a 
Liam Staskawicz 2d0737e 















////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2010 Liam Staskawicz
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////


**
**  BsonReader
**
internal class BsonReader
{
  private static const Log log := Log.get("mongo")
  
  static internal Str:Obj? read(InStream ins)
  {
    bson := Str:Obj?[:] { ordered = true }
    readObject(ins, bson)
    return bson
  }
  
  static private Int readObject(InStream ins, Str:Obj? bson)
  {
    objectlen := ins.readS4
    remaining := objectlen - 4
    while (remaining > 0) {
      type := ins.read
      remaining--
      // Sys.out.printLine("type - ${type}, remaining - ${remaining}")
      switch (type)
      {
        case Bson.MINKEY:
          remaining = readMinKey(ins, remaining, bson)
        case Bson.EOO:
          if (remaining > 0)
            log.warn("Bson.read() - got EOO with $remaining bytes remaining")
          break // end of object - return whatever we have
        case Bson.DOUBLE:
          remaining = readFloat(ins, remaining, bson)
        case Bson.SYMBOL:
        case Bson.STRING:
          remaining = readStr(ins, remaining, bson)
        case Bson.OBJECT:
          remaining = readMap(ins, remaining, bson)
        case Bson.ARRAY:
          remaining = readArray(ins, remaining, bson)
        case Bson.BINARY:
          remaining = readBuf(ins, remaining, bson)
        case Bson.OID:
          remaining = readOID(ins, remaining, bson)
        case Bson.BOOLEAN:
          remaining = readBool(ins, remaining, bson)
        case Bson.TIMESTAMP: // both have the same format
        case Bson.DATE:
          remaining = readDate(ins, remaining, bson)
        case Bson.UNDEFINED:
        case Bson.NULL:
          remaining = readNull(ins, remaining, bson)
        // case Bson.REGEX:
          // remaining = readRegex(ins, remaining, bson)
        case Bson.CODE_W_SCOPE:
          remaining = readCode(ins, remaining, bson)
        case Bson.NUMBER_LONG:
          remaining = readLong(ins, remaining, bson)
        case Bson.NUMBER_INT:
          remaining = readInt(ins, remaining, bson)
        case Bson.MAXKEY:
          remaining = readMaxKey(ins, remaining, bson)
        default:
          throw Err("Unknown BSON type received - ${type}")
      }
    }
    return objectlen - remaining
  }
  
  static private Str readCStr(InStream ins)
  {
    str := ins.readStrToken(null, |i| { return i == 0 }) // read till we get a null
    ins.skip(1) // eat the null terminator...worth validating that this is 0?
    return str
  }
  
  static private Int readStr(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    val := ins.readChars(ins.readU4 - 1)
    ins.skip(1) // eat the null terminator...worth validating that this is 0?
    bson[name] = val
    return remaining - (name.size + val.size + 6) // 6 == 1 null, 1 null, 4 strlen
  }
  
  static private Int readInt(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = ins.readS4
    return remaining - (name.size + 5) // 5 == 1 null, 4 int len
  }
  
  static private Int readLong(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = ins.readS8
    return remaining - (name.size + 9) // 9 == 1 null, 8 long len
  }
  
  static private Int readFloat(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = ins.readF8
    return remaining - (name.size + 9) // 9 == 1 null, 8 floatlen
  }
  
  static private Int readBool(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = (ins.read == 0x01) ? true : false
    return remaining - (name.size + 2) // 2 == 1 null, 1 bool
  }
  
  static private Int readBuf(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    totallen := ins.readS4
    Buf? val
    switch (ins.read) { // type
      case Bson.BIN_LENGTH:
        len := ins.readS4
        if (len + 4 != totallen)
          throw MongoOpErr("BSON - bad data size got subtype 0x02 len: $len, totallen: $totallen")
        val = ins.readBufFully(null, len)
      default:
        val = ins.readBufFully(null, totallen)
    }
    bson[name] = val
    return remaining - (name.size + totallen + 6)  // 6 == 1 null, 4 len, 1 type
  }
  
  static private Int readDate(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = DateTime.fromJava(ins.readS8)
    return remaining - (name.size + 9) // 9 == 1 null, 8 date len
  }
  
  static private Int readNull(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = null
    return remaining - (name.size + 1)
  }
  
  static private Int readOID(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = ObjectID.fromStream(ins)
    return remaining - (name.size + 1 + ObjectID.SIZE)
  }
  
  static private Int readArray(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    arr := Str:Obj?[:] { ordered = true }
    arraylen := readObject(ins, arr)
    bson[name] = arr.vals
    return remaining - (name.size + 1 + arraylen)
  }
  
  static private Int readMap(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    v := Str:Obj?[:] { ordered = true }
    objlen := readObject(ins, v)
    bson[name] = v
    return remaining - (name.size + 1 + objlen)
  }
  
  static private Int readCode(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    totalsize := ins.readS4
    
    code := ins.readChars(ins.readS4 - 1)
    ins.skip(1) // eat null terminator
    
    scope := Str:Obj?[:] { ordered = true }
    readObject(ins, scope)
    bson[name] = Code(code, scope)
    return remaining - (name.size + 1 + totalsize + 4 + 4) // 4 - totalsize, 4 - strsize
  }
  
  static private Int readMinKey(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = MinKey() // todo - figure this out
    return remaining - (name.size + 1)
  }
  
  static private Int readMaxKey(InStream ins, Int remaining, Str:Obj? bson)
  {
    name := readCStr(ins)
    bson[name] = MaxKey() // todo - figure this out
    return remaining - (name.size + 1)
  }
  
}