/**
 * Extend from this class to handle events from parser.
 * Default implementation traverses whole object tree and does nothing.
 */ export abstract class BSONHandler { setString ( name , value ) { } setBoolean ( name , value ) { } setNull ( name ) { } setInteger ( name , value ) { } setUint8Array ( name , value ) { } pushArray ( name ) { return true ; } popArray ( ) { } pushObject ( name ) { return true ; } popObject ( ) { } } /**
 * Extend from this class to handle events from parser.
 * This implementation crashes on every unimplemented set/push method
 * to allow easier validation of input.
 */ export class ThrowingBSONHandler extends BSONHandler { setString ( name , value ) { assert ( false , 'Unexpected string field ' + name + ' : "' + value + '"' ) ; } setBoolean ( name , value ) { assert ( false , 'Unexpected boolean field ' + name + ' : ' + ( value ? 'true' : 'false' ) ) ; } setNull ( name ) { assert ( false , 'Unexpected null field ' + name ) ; } setInteger ( name , value ) { let arr = [ value ] ; assert ( false , 'Unexpected integer field ' + name + ' : ' + arr . toString ( ) ) ; } setUint8Array ( name , value ) { assert ( false , 'Unexpected byte array field ' + name + ' : ' + bin2str ( value ) ) ; } pushArray ( name ) { assert ( false , 'Unexpected array field' + name ) ; return true ; } pushObject ( name ) { assert ( false , 'Unexpected object field ' + name ) ; return true ; } } export class BSONDecoder < BSONHandlerT extends BSONHandler > { handler : BSONHandlerT ; readIndex : i32 = 0 ; constructor ( handler ) { this . handler = handler ; } deserialize ( buffer , startIndex = 0 ) { this . readIndex = startIndex ; assert ( buffer . length >= 5 , "Document error: Size < 5 bytes" ) ; let size = buffer [ this . readIndex ++ ] | i32 ( buffer [ this . readIndex ++ ] ) << 8 | i32 ( buffer [ this . readIndex ++ ] ) << 16 | i32 ( buffer [ this . readIndex ++ ] ) << 24 ; assert ( size <= buffer . length , "Document error: Size mismatch" ) ; assert ( buffer [ buffer . length - 1 ] == 0x00 , "Document error: Missing termination" ) ; for ( ; ; ) { let elementType = buffer [ this . readIndex ++ ] ; if ( elementType === 0 ) break ; let end = this . readIndex ; for ( ; buffer [ end ] !== 0x00 && end < buffer . length ; end ++ ) ; assert ( end < buffer . length - 1 , "Document error: Illegal key name" ) ; let name = bin2str ( buffer . subarray ( this . readIndex , end ) ) ; this . readIndex = ++ end ; switch ( elementType ) { case 0x02 : size = buffer [ this . readIndex ++ ] | i32 ( buffer [ this . readIndex ++ ] ) << 8 | i32 ( buffer [ this . readIndex ++ ] ) << 16 | i32 ( buffer [ this . readIndex ++ ] ) << 24 ; this . handler . setString ( name , bin2str ( buffer . subarray ( this . readIndex , this . readIndex += size - 1 ) ) ) ; this . readIndex ++ ; break ; case 0x03 : size = buffer [ this . readIndex ] | i32 ( buffer [ this . readIndex + 1 ] ) << 8 | i32 ( buffer [ this . readIndex + 2 ] ) << 16 | i32 ( buffer [ this . readIndex + 3 ] ) << 24 ; if ( this . handler . pushObject ( name ) ) { this . deserialize ( buffer , this . readIndex ) ; } else { this . readIndex += size ; } this . handler . popObject ( ) ; break ; case 0x04 : size = buffer [ this . readIndex ] | i32 ( buffer [ this . readIndex + 1 ] ) << 8 | i32 ( buffer [ this . readIndex + 2 ] ) << 16 | i32 ( buffer [ this . readIndex + 3 ] ) << 24 ; if ( this . handler . pushArray ( name ) ) { this . deserialize ( buffer , this . readIndex ) ; } else { this . readIndex += size ; } this . handler . popArray ( ) ; break ; case 0x05 : size = buffer [ this . readIndex ++ ] | i32 ( buffer [ this . readIndex ++ ] ) << 8 | i32 ( buffer [ this . readIndex ++ ] ) << 16 | i32 ( buffer [ this . readIndex ++ ] ) << 24 ; if ( buffer [ this . readIndex ++ ] === 0x04 ) { return ; } this . handler . setUint8Array ( name , buffer . subarray ( this . readIndex , this . readIndex += size ) ) ; break ; case 0x08 : this . handler . setBoolean ( name , buffer [ this . readIndex ++ ] === 1 ) ; break ; case 0x0A : this . handler . setNull ( name ) ; break ; case 0x10 : this . handler . setInteger ( name , buffer [ this . readIndex ++ ] | i32 ( buffer [ this . readIndex ++ ] ) << 8 | i32 ( buffer [ this . readIndex ++ ] ) << 16 | i32 ( buffer [ this . readIndex ++ ] ) << 24 ) ; break ; default : assert ( false , "Parsing error: Unknown element" ) ; } } } } export function bin2str ( bin ) { let str = '' , len = bin . length , i = 0 ; let c , c2 , c3 ; while ( i < len ) { c = bin [ i ] ; if ( c < 128 ) { str += String . fromCharCode ( c ) ; i ++ ; } else if ( ( c > 191 ) && ( c < 224 ) ) { c2 = bin [ i + 1 ] ; str += String . fromCharCode ( ( ( c & 31 ) << 6 ) | ( c2 & 63 ) ) ; i += 2 ; } else { c2 = bin [ i + 1 ] ; c3 = bin [ i + 2 ] ; str += String . fromCharCode ( ( ( c & 15 ) << 12 ) | ( ( c2 & 63 ) << 6 ) | ( c3 & 63 ) ) ; i += 3 ; } } return str ; }