/* bson.c */ /* Copyright 2009, 2010 10gen Inc. * * 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. */ #include #include #include #include #include #include "bson.h" #include "encoding.h" const int initialBufferSize = 128; /* only need one of these */ static const int zero = 0; /* Custom standard function pointers. */ void *( *bson_malloc_func )( size_t ) = malloc; void *( *bson_realloc_func )( void *, size_t ) = realloc; void ( *bson_free_func )( void * ) = free; #ifdef R_SAFETY_NET bson_printf_func bson_printf; #else bson_printf_func bson_printf = printf; #endif bson_fprintf_func bson_fprintf = fprintf; bson_sprintf_func bson_sprintf = sprintf; static int _bson_errprintf( const char *, ... ); bson_printf_func bson_errprintf = _bson_errprintf; /* ObjectId fuzz functions. */ static int ( *oid_fuzz_func )( void ) = NULL; static int ( *oid_inc_func )( void ) = NULL; /* ---------------------------- READING ------------------------------ */ MONGO_EXPORT bson* bson_create() { return (bson*)bson_malloc(sizeof(bson)); } MONGO_EXPORT void bson_dispose(bson* b) { bson_free(b); } MONGO_EXPORT bson *bson_empty( bson *obj ) { static char *data = "\005\0\0\0\0"; bson_init_data( obj, data ); obj->finished = 1; obj->err = 0; obj->errstr = NULL; obj->stackPos = 0; return obj; } MONGO_EXPORT int bson_copy( bson *out, const bson *in ) { if ( !out ) return BSON_ERROR; if ( !in->finished ) return BSON_ERROR; bson_init_size( out, bson_size( in ) ); memcpy( out->data, in->data, bson_size( in ) ); out->finished = 1; return BSON_OK; } int bson_init_data( bson *b, char *data ) { b->data = data; return BSON_OK; } int bson_init_finished_data( bson *b, char *data ) { bson_init_data( b, data ); b->finished = 1; return BSON_OK; } static void _bson_reset( bson *b ) { b->finished = 0; b->stackPos = 0; b->err = 0; b->errstr = NULL; } MONGO_EXPORT int bson_size( const bson *b ) { int i; if ( ! b || ! b->data ) return 0; bson_little_endian32( &i, b->data ); return i; } MONGO_EXPORT int bson_buffer_size( const bson *b ) { return (b->cur - b->data + 1); } MONGO_EXPORT const char *bson_data( const bson *b ) { return (const char *)b->data; } static char hexbyte( char hex ) { switch ( hex ) { case '0': return 0x0; case '1': return 0x1; case '2': return 0x2; case '3': return 0x3; case '4': return 0x4; case '5': return 0x5; case '6': return 0x6; case '7': return 0x7; case '8': return 0x8; case '9': return 0x9; case 'a': case 'A': return 0xa; case 'b': case 'B': return 0xb; case 'c': case 'C': return 0xc; case 'd': case 'D': return 0xd; case 'e': case 'E': return 0xe; case 'f': case 'F': return 0xf; default: return 0x0; /* something smarter? */ } } MONGO_EXPORT void bson_oid_from_string( bson_oid_t *oid, const char *str ) { int i; for ( i=0; i<12; i++ ) { oid->bytes[i] = ( hexbyte( str[2*i] ) << 4 ) | hexbyte( str[2*i + 1] ); } } MONGO_EXPORT void bson_oid_to_string( const bson_oid_t *oid, char *str ) { static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; int i; for ( i=0; i<12; i++ ) { str[2*i] = hex[( oid->bytes[i] & 0xf0 ) >> 4]; str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ]; } str[24] = '\0'; } MONGO_EXPORT void bson_set_oid_fuzz( int ( *func )( void ) ) { oid_fuzz_func = func; } MONGO_EXPORT void bson_set_oid_inc( int ( *func )( void ) ) { oid_inc_func = func; } MONGO_EXPORT void bson_oid_gen( bson_oid_t *oid ) { static int incr = 0; static int fuzz = 0; int i; int t = time( NULL ); if( oid_inc_func ) i = oid_inc_func(); else i = incr++; if ( !fuzz ) { if ( oid_fuzz_func ) fuzz = oid_fuzz_func(); else { srand( t ); fuzz = rand(); } } bson_big_endian32( &oid->ints[0], &t ); oid->ints[1] = fuzz; bson_big_endian32( &oid->ints[2], &i ); } MONGO_EXPORT time_t bson_oid_generated_time( bson_oid_t *oid ) { time_t out; bson_big_endian32( &out, &oid->ints[0] ); return out; } MONGO_EXPORT void bson_print( const bson *b ) { bson_print_raw( b->data , 0 ); } MONGO_EXPORT void bson_print_raw( const char *data , int depth ) { bson_iterator i; const char *key; int temp; bson_timestamp_t ts; char oidhex[25]; bson scope; bson_iterator_from_buffer( &i, data ); while ( bson_iterator_next( &i ) ) { bson_type t = bson_iterator_type( &i ); if ( t == 0 ) break; key = bson_iterator_key( &i ); for ( temp=0; temp<=depth; temp++ ) bson_printf( "\t" ); bson_printf( "%s : %d \t " , key , t ); switch ( t ) { case BSON_DOUBLE: bson_printf( "%f" , bson_iterator_double( &i ) ); break; case BSON_STRING: bson_printf( "%s" , bson_iterator_string( &i ) ); break; case BSON_SYMBOL: bson_printf( "SYMBOL: %s" , bson_iterator_string( &i ) ); break; case BSON_OID: bson_oid_to_string( bson_iterator_oid( &i ), oidhex ); bson_printf( "%s" , oidhex ); break; case BSON_BOOL: bson_printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" ); break; case BSON_DATE: bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) ); break; case BSON_BINDATA: bson_printf( "BSON_BINDATA" ); break; case BSON_UNDEFINED: bson_printf( "BSON_UNDEFINED" ); break; case BSON_NULL: bson_printf( "BSON_NULL" ); break; case BSON_REGEX: bson_printf( "BSON_REGEX: %s", bson_iterator_regex( &i ) ); break; case BSON_CODE: bson_printf( "BSON_CODE: %s", bson_iterator_code( &i ) ); break; case BSON_CODEWSCOPE: bson_printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) ); bson_init( &scope ); bson_iterator_code_scope( &i, &scope ); bson_printf( "\n\t SCOPE: " ); bson_print( &scope ); break; case BSON_INT: bson_printf( "%d" , bson_iterator_int( &i ) ); break; case BSON_LONG: bson_printf( "%lld" , ( uint64_t )bson_iterator_long( &i ) ); break; case BSON_TIMESTAMP: ts = bson_iterator_timestamp( &i ); bson_printf( "i: %d, t: %d", ts.i, ts.t ); break; case BSON_OBJECT: case BSON_ARRAY: bson_printf( "\n" ); bson_print_raw( bson_iterator_value( &i ) , depth + 1 ); break; default: bson_errprintf( "can't print type : %d\n" , t ); } bson_printf( "\n" ); } } /* ---------------------------- ITERATOR ------------------------------ */ MONGO_EXPORT bson_iterator* bson_iterator_create() { return ( bson_iterator* )malloc( sizeof( bson_iterator ) ); } MONGO_EXPORT void bson_iterator_dispose(bson_iterator* i) { free(i); } MONGO_EXPORT void bson_iterator_init( bson_iterator *i, const bson *b ) { i->cur = b->data + 4; i->first = 1; } MONGO_EXPORT void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ) { i->cur = buffer + 4; i->first = 1; } MONGO_EXPORT bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ) { bson_iterator_init( it, (bson *)obj ); while( bson_iterator_next( it ) ) { if ( strcmp( name, bson_iterator_key( it ) ) == 0 ) break; } return bson_iterator_type( it ); } MONGO_EXPORT bson_bool_t bson_iterator_more( const bson_iterator *i ) { return *( i->cur ); } MONGO_EXPORT bson_type bson_iterator_next( bson_iterator *i ) { int ds; if ( i->first ) { i->first = 0; return ( bson_type )( *i->cur ); } switch ( bson_iterator_type( i ) ) { case BSON_EOO: return BSON_EOO; /* don't advance */ case BSON_UNDEFINED: case BSON_NULL: ds = 0; break; case BSON_BOOL: ds = 1; break; case BSON_INT: ds = 4; break; case BSON_LONG: case BSON_DOUBLE: case BSON_TIMESTAMP: case BSON_DATE: ds = 8; break; case BSON_OID: ds = 12; break; case BSON_STRING: case BSON_SYMBOL: case BSON_CODE: ds = 4 + bson_iterator_int_raw( i ); break; case BSON_BINDATA: ds = 5 + bson_iterator_int_raw( i ); break; case BSON_OBJECT: case BSON_ARRAY: case BSON_CODEWSCOPE: ds = bson_iterator_int_raw( i ); break; case BSON_DBREF: ds = 4+12 + bson_iterator_int_raw( i ); break; case BSON_REGEX: { const char *s = bson_iterator_value( i ); const char *p = s; p += strlen( p )+1; p += strlen( p )+1; ds = p-s; break; } default: { char msg[] = "unknown type: 000000000000"; bson_numstr( msg+14, ( unsigned )( i->cur[0] ) ); bson_fatal_msg( 0, msg ); return 0; } } i->cur += 1 + strlen( i->cur + 1 ) + 1 + ds; return ( bson_type )( *i->cur ); } MONGO_EXPORT bson_type bson_iterator_type( const bson_iterator *i ) { return ( bson_type )i->cur[0]; } MONGO_EXPORT const char *bson_iterator_key( const bson_iterator *i ) { return i->cur + 1; } MONGO_EXPORT const char *bson_iterator_value( const bson_iterator *i ) { const char *t = i->cur + 1; t += strlen( t ) + 1; return t; } /* types */ int bson_iterator_int_raw( const bson_iterator *i ) { int out; bson_little_endian32( &out, bson_iterator_value( i ) ); return out; } double bson_iterator_double_raw( const bson_iterator *i ) { double out; bson_little_endian64( &out, bson_iterator_value( i ) ); return out; } int64_t bson_iterator_long_raw( const bson_iterator *i ) { int64_t out; bson_little_endian64( &out, bson_iterator_value( i ) ); return out; } bson_bool_t bson_iterator_bool_raw( const bson_iterator *i ) { return bson_iterator_value( i )[0]; } MONGO_EXPORT bson_oid_t *bson_iterator_oid( const bson_iterator *i ) { return ( bson_oid_t * )bson_iterator_value( i ); } MONGO_EXPORT int bson_iterator_int( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_INT: return bson_iterator_int_raw( i ); case BSON_LONG: return bson_iterator_long_raw( i ); case BSON_DOUBLE: return bson_iterator_double_raw( i ); default: return 0; } } MONGO_EXPORT double bson_iterator_double( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_INT: return bson_iterator_int_raw( i ); case BSON_LONG: return bson_iterator_long_raw( i ); case BSON_DOUBLE: return bson_iterator_double_raw( i ); default: return 0; } } MONGO_EXPORT int64_t bson_iterator_long( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_INT: return bson_iterator_int_raw( i ); case BSON_LONG: return bson_iterator_long_raw( i ); case BSON_DOUBLE: return bson_iterator_double_raw( i ); default: return 0; } } MONGO_EXPORT bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ) { bson_timestamp_t ts; bson_little_endian32( &( ts.i ), bson_iterator_value( i ) ); bson_little_endian32( &( ts.t ), bson_iterator_value( i ) + 4 ); return ts; } MONGO_EXPORT int bson_iterator_timestamp_time( const bson_iterator *i ) { int time; bson_little_endian32( &time, bson_iterator_value( i ) + 4 ); return time; } MONGO_EXPORT int bson_iterator_timestamp_increment( const bson_iterator *i ) { int increment; bson_little_endian32( &increment, bson_iterator_value( i ) ); return increment; } MONGO_EXPORT bson_bool_t bson_iterator_bool( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_BOOL: return bson_iterator_bool_raw( i ); case BSON_INT: return bson_iterator_int_raw( i ) != 0; case BSON_LONG: return bson_iterator_long_raw( i ) != 0; case BSON_DOUBLE: return bson_iterator_double_raw( i ) != 0; case BSON_EOO: case BSON_NULL: return 0; default: return 1; } } MONGO_EXPORT const char *bson_iterator_string( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_STRING: case BSON_SYMBOL: return bson_iterator_value( i ) + 4; default: return ""; } } int bson_iterator_string_len( const bson_iterator *i ) { return bson_iterator_int_raw( i ); } MONGO_EXPORT const char *bson_iterator_code( const bson_iterator *i ) { switch ( bson_iterator_type( i ) ) { case BSON_STRING: case BSON_CODE: return bson_iterator_value( i ) + 4; case BSON_CODEWSCOPE: return bson_iterator_value( i ) + 8; default: return NULL; } } MONGO_EXPORT void bson_iterator_code_scope( const bson_iterator *i, bson *scope ) { if ( bson_iterator_type( i ) == BSON_CODEWSCOPE ) { int code_len; bson_little_endian32( &code_len, bson_iterator_value( i )+4 ); bson_init_data( scope, ( void * )( bson_iterator_value( i )+8+code_len ) ); _bson_reset( scope ); scope->finished = 1; } else { bson_empty( scope ); } } MONGO_EXPORT bson_date_t bson_iterator_date( const bson_iterator *i ) { return bson_iterator_long_raw( i ); } MONGO_EXPORT time_t bson_iterator_time_t( const bson_iterator *i ) { return bson_iterator_date( i ) / 1000; } MONGO_EXPORT int bson_iterator_bin_len( const bson_iterator *i ) { return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) ? bson_iterator_int_raw( i ) - 4 : bson_iterator_int_raw( i ); } MONGO_EXPORT char bson_iterator_bin_type( const bson_iterator *i ) { return bson_iterator_value( i )[4]; } MONGO_EXPORT const char *bson_iterator_bin_data( const bson_iterator *i ) { return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) ? bson_iterator_value( i ) + 9 : bson_iterator_value( i ) + 5; } MONGO_EXPORT const char *bson_iterator_regex( const bson_iterator *i ) { return bson_iterator_value( i ); } MONGO_EXPORT const char *bson_iterator_regex_opts( const bson_iterator *i ) { const char *p = bson_iterator_value( i ); return p + strlen( p ) + 1; } MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub ) { bson_init_data( sub, ( char * )bson_iterator_value( i ) ); _bson_reset( sub ); sub->finished = 1; } MONGO_EXPORT void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ) { bson_iterator_from_buffer( sub, bson_iterator_value( i ) ); } /* ---------------------------- BUILDING ------------------------------ */ static void _bson_init_size( bson *b, int size ) { if( size == 0 ) b->data = NULL; else b->data = ( char * )bson_malloc( size ); b->dataSize = size; b->cur = b->data + 4; _bson_reset( b ); } MONGO_EXPORT void bson_init( bson *b ) { _bson_init_size( b, initialBufferSize ); } void bson_init_size( bson *b, int size ) { _bson_init_size( b, size ); } void bson_append_byte( bson *b, char c ) { b->cur[0] = c; b->cur++; } void bson_append( bson *b, const void *data, int len ) { memcpy( b->cur , data , len ); b->cur += len; } void bson_append32( bson *b, const void *data ) { bson_little_endian32( b->cur, data ); b->cur += 4; } void bson_append64( bson *b, const void *data ) { bson_little_endian64( b->cur, data ); b->cur += 8; } int bson_ensure_space( bson *b, const int bytesNeeded ) { int pos = b->cur - b->data; char *orig = b->data; int new_size; if ( pos + bytesNeeded <= b->dataSize ) return BSON_OK; new_size = 1.5 * ( b->dataSize + bytesNeeded ); if( new_size < b->dataSize ) { if( ( b->dataSize + bytesNeeded ) < INT_MAX ) new_size = INT_MAX; else { b->err = BSON_SIZE_OVERFLOW; return BSON_ERROR; } } b->data = bson_realloc( b->data, new_size ); if ( !b->data ) bson_fatal_msg( !!b->data, "realloc() failed" ); b->dataSize = new_size; b->cur += b->data - orig; return BSON_OK; } MONGO_EXPORT int bson_finish( bson *b ) { int i; if( b->err & BSON_NOT_UTF8 ) return BSON_ERROR; if ( ! b->finished ) { if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; bson_append_byte( b, 0 ); i = b->cur - b->data; bson_little_endian32( b->data, &i ); b->finished = 1; } return BSON_OK; } MONGO_EXPORT void bson_destroy( bson *b ) { if (b) { bson_free( b->data ); b->err = 0; b->data = 0; b->cur = 0; b->finished = 1; } } static int bson_append_estart( bson *b, int type, const char *name, const int dataSize ) { const int len = strlen( name ) + 1; if ( b->finished ) { b->err |= BSON_ALREADY_FINISHED; return BSON_ERROR; } if ( bson_ensure_space( b, 1 + len + dataSize ) == BSON_ERROR ) { return BSON_ERROR; } if( bson_check_field_name( b, ( const char * )name, len - 1 ) == BSON_ERROR ) { bson_builder_error( b ); return BSON_ERROR; } bson_append_byte( b, ( char )type ); bson_append( b, name, len ); return BSON_OK; } /* ---------------------------- BUILDING TYPES ------------------------------ */ MONGO_EXPORT int bson_append_int( bson *b, const char *name, const int i ) { if ( bson_append_estart( b, BSON_INT, name, 4 ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b , &i ); return BSON_OK; } MONGO_EXPORT int bson_append_long( bson *b, const char *name, const int64_t i ) { if ( bson_append_estart( b , BSON_LONG, name, 8 ) == BSON_ERROR ) return BSON_ERROR; bson_append64( b , &i ); return BSON_OK; } MONGO_EXPORT int bson_append_double( bson *b, const char *name, const double d ) { if ( bson_append_estart( b, BSON_DOUBLE, name, 8 ) == BSON_ERROR ) return BSON_ERROR; bson_append64( b , &d ); return BSON_OK; } MONGO_EXPORT int bson_append_bool( bson *b, const char *name, const bson_bool_t i ) { if ( bson_append_estart( b, BSON_BOOL, name, 1 ) == BSON_ERROR ) return BSON_ERROR; bson_append_byte( b , i != 0 ); return BSON_OK; } MONGO_EXPORT int bson_append_null( bson *b, const char *name ) { if ( bson_append_estart( b , BSON_NULL, name, 0 ) == BSON_ERROR ) return BSON_ERROR; return BSON_OK; } MONGO_EXPORT int bson_append_undefined( bson *b, const char *name ) { if ( bson_append_estart( b, BSON_UNDEFINED, name, 0 ) == BSON_ERROR ) return BSON_ERROR; return BSON_OK; } int bson_append_string_base( bson *b, const char *name, const char *value, int len, bson_type type ) { int sl = len + 1; if ( bson_check_string( b, ( const char * )value, sl - 1 ) == BSON_ERROR ) return BSON_ERROR; if ( bson_append_estart( b, type, name, 4 + sl ) == BSON_ERROR ) { return BSON_ERROR; } bson_append32( b , &sl ); bson_append( b , value , sl - 1 ); bson_append( b , "\0" , 1 ); return BSON_OK; } MONGO_EXPORT int bson_append_string( bson *b, const char *name, const char *value ) { return bson_append_string_base( b, name, value, strlen ( value ), BSON_STRING ); } MONGO_EXPORT int bson_append_symbol( bson *b, const char *name, const char *value ) { return bson_append_string_base( b, name, value, strlen ( value ), BSON_SYMBOL ); } MONGO_EXPORT int bson_append_code( bson *b, const char *name, const char *value ) { return bson_append_string_base( b, name, value, strlen ( value ), BSON_CODE ); } MONGO_EXPORT int bson_append_string_n( bson *b, const char *name, const char *value, int len ) { return bson_append_string_base( b, name, value, len, BSON_STRING ); } MONGO_EXPORT int bson_append_symbol_n( bson *b, const char *name, const char *value, int len ) { return bson_append_string_base( b, name, value, len, BSON_SYMBOL ); } MONGO_EXPORT int bson_append_code_n( bson *b, const char *name, const char *value, int len ) { return bson_append_string_base( b, name, value, len, BSON_CODE ); } MONGO_EXPORT int bson_append_code_w_scope_n( bson *b, const char *name, const char *code, int len, const bson *scope ) { int sl = len + 1; int size = 4 + 4 + sl + bson_size( scope ); if ( bson_append_estart( b, BSON_CODEWSCOPE, name, size ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b, &size ); bson_append32( b, &sl ); bson_append( b, code, sl ); bson_append( b, scope->data, bson_size( scope ) ); return BSON_OK; } MONGO_EXPORT int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ) { return bson_append_code_w_scope_n( b, name, code, strlen ( code ), scope ); } MONGO_EXPORT int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ) { if ( type == BSON_BIN_BINARY_OLD ) { int subtwolen = len + 4; if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+4+len ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b, &subtwolen ); bson_append_byte( b, type ); bson_append32( b, &len ); bson_append( b, str, len ); } else { if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+len ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b, &len ); bson_append_byte( b, type ); bson_append( b, str, len ); } return BSON_OK; } MONGO_EXPORT int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ) { if ( bson_append_estart( b, BSON_OID, name, 12 ) == BSON_ERROR ) return BSON_ERROR; bson_append( b , oid , 12 ); return BSON_OK; } MONGO_EXPORT int bson_append_new_oid( bson *b, const char *name ) { bson_oid_t oid; bson_oid_gen( &oid ); return bson_append_oid( b, name, &oid ); } MONGO_EXPORT int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ) { const int plen = strlen( pattern )+1; const int olen = strlen( opts )+1; if ( bson_append_estart( b, BSON_REGEX, name, plen + olen ) == BSON_ERROR ) return BSON_ERROR; if ( bson_check_string( b, pattern, plen - 1 ) == BSON_ERROR ) return BSON_ERROR; bson_append( b , pattern , plen ); bson_append( b , opts , olen ); return BSON_OK; } MONGO_EXPORT int bson_append_bson( bson *b, const char *name, const bson *bson ) { if ( bson_append_estart( b, BSON_OBJECT, name, bson_size( bson ) ) == BSON_ERROR ) return BSON_ERROR; bson_append( b , bson->data , bson_size( bson ) ); return BSON_OK; } MONGO_EXPORT int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ) { bson_iterator next = *elem; int size; bson_iterator_next( &next ); size = next.cur - elem->cur; if ( name_or_null == NULL ) { if( bson_ensure_space( b, size ) == BSON_ERROR ) return BSON_ERROR; bson_append( b, elem->cur, size ); } else { int data_size = size - 2 - strlen( bson_iterator_key( elem ) ); bson_append_estart( b, elem->cur[0], name_or_null, data_size ); bson_append( b, bson_iterator_value( elem ), data_size ); } return BSON_OK; } MONGO_EXPORT int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ) { if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b , &( ts->i ) ); bson_append32( b , &( ts->t ) ); return BSON_OK; } MONGO_EXPORT int bson_append_timestamp2( bson *b, const char *name, int time, int increment ) { if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR; bson_append32( b , &increment ); bson_append32( b , &time ); return BSON_OK; } MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis ) { if ( bson_append_estart( b, BSON_DATE, name, 8 ) == BSON_ERROR ) return BSON_ERROR; bson_append64( b , &millis ); return BSON_OK; } MONGO_EXPORT int bson_append_time_t( bson *b, const char *name, time_t secs ) { return bson_append_date( b, name, ( bson_date_t )secs * 1000 ); } MONGO_EXPORT int bson_append_start_object( bson *b, const char *name ) { if ( bson_append_estart( b, BSON_OBJECT, name, 5 ) == BSON_ERROR ) return BSON_ERROR; b->stack[ b->stackPos++ ] = b->cur - b->data; bson_append32( b , &zero ); return BSON_OK; } MONGO_EXPORT int bson_append_start_array( bson *b, const char *name ) { if ( bson_append_estart( b, BSON_ARRAY, name, 5 ) == BSON_ERROR ) return BSON_ERROR; b->stack[ b->stackPos++ ] = b->cur - b->data; bson_append32( b , &zero ); return BSON_OK; } MONGO_EXPORT int bson_append_finish_object( bson *b ) { char *start; int i; if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; bson_append_byte( b , 0 ); start = b->data + b->stack[ --b->stackPos ]; i = b->cur - start; bson_little_endian32( start, &i ); return BSON_OK; } MONGO_EXPORT double bson_int64_to_double( int64_t i64 ) { return (double)i64; } MONGO_EXPORT int bson_append_finish_array( bson *b ) { return bson_append_finish_object( b ); } /* Error handling and allocators. */ static bson_err_handler err_handler = NULL; MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func ) { bson_err_handler old = err_handler; err_handler = func; return old; } MONGO_EXPORT void bson_free( void *ptr ) { bson_free_func( ptr ); } MONGO_EXPORT void *bson_malloc( int size ) { void *p; p = bson_malloc_func( size ); bson_fatal_msg( !!p, "malloc() failed" ); return p; } void *bson_realloc( void *ptr, int size ) { void *p; p = bson_realloc_func( ptr, size ); bson_fatal_msg( !!p, "realloc() failed" ); return p; } int _bson_errprintf( const char *format, ... ) { va_list ap; int ret; va_start( ap, format ); #ifndef R_SAFETY_NET ret = vfprintf( stderr, format, ap ); #endif va_end( ap ); return ret; } /** * This method is invoked when a non-fatal bson error is encountered. * Calls the error handler if available. * * @param */ void bson_builder_error( bson *b ) { if( err_handler ) err_handler( "BSON error." ); } void bson_fatal( int ok ) { bson_fatal_msg( ok, "" ); } void bson_fatal_msg( int ok , const char *msg ) { if ( ok ) return; if ( err_handler ) { err_handler( msg ); } #ifndef R_SAFETY_NET bson_errprintf( "error: %s\n" , msg ); exit( -5 ); #endif } /* Efficiently copy an integer to a string. */ extern const char bson_numstrs[1000][4]; void bson_numstr( char *str, int i ) { if( i < 1000 ) memcpy( str, bson_numstrs[i], 4 ); else bson_sprintf( str,"%d", i ); } MONGO_EXPORT void bson_swap_endian64( void *outp, const void *inp ) { const char *in = ( const char * )inp; char *out = ( char * )outp; out[0] = in[7]; out[1] = in[6]; out[2] = in[5]; out[3] = in[4]; out[4] = in[3]; out[5] = in[2]; out[6] = in[1]; out[7] = in[0]; } MONGO_EXPORT void bson_swap_endian32( void *outp, const void *inp ) { const char *in = ( const char * )inp; char *out = ( char * )outp; out[0] = in[3]; out[1] = in[2]; out[2] = in[1]; out[3] = in[0]; }