2009-03-04 22:38:06 +00:00
/*
* Copyright 2009 10 gen , 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 .
*/
/*
* This file contains C implementations of some of the functions needed by the
* bson module . If possible , these implementations should be used to speed up
* BSON encoding and decoding .
*/
2009-03-03 22:07:22 +00:00
# include "ruby.h"
2009-08-03 16:06:51 +00:00
# if HAVE_RUBY_ST_H
2009-08-03 15:18:13 +00:00
# include "ruby/st.h"
2009-08-03 16:06:51 +00:00
# endif
# if HAVE_ST_H
# include "st.h"
# endif
# if HAVE_RUBY_REGEX_H
2009-08-03 15:18:13 +00:00
# include "ruby/regex.h"
2009-08-03 16:06:51 +00:00
# endif
# if HAVE_REGEX_H
# include "regex.h"
# endif
2009-12-02 20:22:16 +00:00
# include <string.h>
2009-06-05 18:52:01 +00:00
# include <math.h>
2009-10-29 15:44:07 +00:00
# include <unistd.h>
# include <time.h>
2009-03-03 22:07:22 +00:00
2009-12-02 20:22:16 +00:00
# include "version.h"
# include "buffer.h"
2009-12-02 20:23:45 +00:00
# include "encoding_helpers.h"
2009-12-02 20:22:16 +00:00
# define SAFE_WRITE(buffer, data, size) \
if ( buffer_write ( ( buffer ) , ( data ) , ( size ) ) ! = 0 ) \
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " )
# define SAFE_WRITE_AT_POS(buffer, position, data, size) \
if ( buffer_write_at_position ( ( buffer ) , ( position ) , ( data ) , ( size ) ) ! = 0 ) \
2009-12-17 14:47:27 +00:00
rb_raise ( rb_eRuntimeError , " invalid write at position in buffer.c " )
2009-12-02 20:22:16 +00:00
2009-11-13 16:41:50 +00:00
# define MAX_HOSTNAME_LENGTH 256
2009-03-03 22:07:22 +00:00
2009-03-10 15:48:06 +00:00
static VALUE Binary ;
2009-03-10 17:19:18 +00:00
static VALUE Time ;
static VALUE ObjectID ;
2009-03-10 18:58:20 +00:00
static VALUE DBRef ;
2009-03-12 20:12:52 +00:00
static VALUE Code ;
2009-03-10 19:33:03 +00:00
static VALUE RegexpOfHolding ;
2009-03-10 19:41:28 +00:00
static VALUE OrderedHash ;
2009-08-13 19:52:11 +00:00
static VALUE InvalidName ;
2009-12-02 20:23:45 +00:00
static VALUE InvalidStringEncoding ;
2009-12-16 16:32:54 +00:00
static VALUE InvalidDocument ;
2009-10-29 15:44:07 +00:00
static VALUE DigestMD5 ;
2009-03-10 15:48:06 +00:00
2009-09-04 15:02:04 +00:00
# if HAVE_RUBY_ENCODING_H
# include "ruby/encoding.h"
# define STR_NEW(p,n) rb_enc_str_new((p), (n), rb_utf8_encoding())
2009-12-02 20:23:45 +00:00
/* MUST call TO_UTF8 before calling write_utf8. */
# define TO_UTF8(string) rb_str_export_to_enc((string), rb_utf8_encoding())
2009-12-17 17:17:19 +00:00
static void write_utf8 ( buffer_t buffer , VALUE string , char check_null ) {
result_t status = check_string ( RSTRING_PTR ( string ) , RSTRING_LEN ( string ) ,
0 , check_null ) ;
if ( status = = HAS_NULL ) {
buffer_free ( buffer ) ;
rb_raise ( InvalidDocument , " Key names / regex patterns must not contain the NULL byte " ) ;
}
2009-12-02 20:23:45 +00:00
SAFE_WRITE ( buffer , RSTRING_PTR ( string ) , RSTRING_LEN ( string ) ) ;
}
2009-09-04 15:02:04 +00:00
# else
# define STR_NEW(p,n) rb_str_new((p), (n))
2009-12-02 20:23:45 +00:00
/* MUST call TO_UTF8 before calling write_utf8. */
# define TO_UTF8(string) (string)
2009-12-17 17:17:19 +00:00
static void write_utf8 ( buffer_t buffer , VALUE string , char check_null ) {
result_t status = check_string ( RSTRING_PTR ( string ) , RSTRING_LEN ( string ) ,
1 , check_null ) ;
if ( status = = HAS_NULL ) {
buffer_free ( buffer ) ;
rb_raise ( InvalidDocument , " Key names / regex patterns must not contain the NULL byte " ) ;
} else if ( status = = NOT_UTF_8 ) {
2009-12-02 20:23:45 +00:00
buffer_free ( buffer ) ;
rb_raise ( InvalidStringEncoding , " String not valid UTF-8 " ) ;
}
SAFE_WRITE ( buffer , RSTRING_PTR ( string ) , RSTRING_LEN ( string ) ) ;
}
2009-09-04 15:02:04 +00:00
# endif
2009-03-23 16:14:38 +00:00
// this sucks. but for some reason these moved around between 1.8 and 1.9
# ifdef ONIGURUMA_H
# define IGNORECASE ONIG_OPTION_IGNORECASE
# define MULTILINE ONIG_OPTION_MULTILINE
# define EXTENDED ONIG_OPTION_EXTEND
# else
# define IGNORECASE RE_OPTION_IGNORECASE
# define MULTILINE RE_OPTION_MULTILINE
# define EXTENDED RE_OPTION_EXTENDED
# endif
2009-07-17 16:16:33 +00:00
/* TODO we ought to check that the malloc or asprintf was successful
* and raise an exception if not . */
2009-12-18 19:19:53 +00:00
/* TODO maybe we can use something more portable like vsnprintf instead
* of this hack . And share it with the Python extension ; ) */
# ifndef HAVE_ASPRINTF
2009-07-17 16:16:33 +00:00
# define INT2STRING(buffer, i) \
{ \
int vslength = _scprintf ( " %d " , i ) + 1 ; \
* buffer = malloc ( vslength ) ; \
_snprintf ( * buffer , vslength , " %d " , i ) ; \
}
# else
# define INT2STRING(buffer, i) asprintf(buffer, "%d", i);
# endif
2009-03-23 16:14:38 +00:00
// this sucks too.
2009-12-17 17:17:19 +00:00
# ifndef RREGEXP_SRC
# define RREGEXP_SRC(r) rb_str_new(RREGEXP((r))->str, RREGEXP((r))->len)
2009-03-23 16:14:38 +00:00
# endif
2009-03-04 15:05:50 +00:00
static char zero = 0 ;
2009-03-04 16:07:22 +00:00
static char one = 1 ;
2009-03-05 18:16:34 +00:00
static int cmp_char ( const void * a , const void * b ) {
return * ( char * ) a - * ( char * ) b ;
}
2009-12-02 20:22:16 +00:00
static void write_doc ( buffer_t buffer , VALUE hash , VALUE check_keys ) ;
2009-03-05 20:48:40 +00:00
static int write_element ( VALUE key , VALUE value , VALUE extra ) ;
2009-03-10 14:45:56 +00:00
static VALUE elements_to_hash ( const char * buffer , int max ) ;
2009-03-04 15:05:50 +00:00
2009-12-02 20:22:16 +00:00
static VALUE pack_extra ( buffer_t buffer , VALUE check_keys ) {
2009-09-04 14:22:28 +00:00
return rb_ary_new3 ( 2 , LL2NUM ( ( long long ) buffer ) , check_keys ) ;
2009-06-01 21:38:11 +00:00
}
2009-12-02 20:22:16 +00:00
static void write_name_and_type ( buffer_t buffer , VALUE name , char type ) {
SAFE_WRITE ( buffer , & type , 1 ) ;
2009-12-02 20:23:45 +00:00
name = TO_UTF8 ( name ) ;
2009-12-17 17:17:19 +00:00
write_utf8 ( buffer , name , 1 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-03-04 15:05:50 +00:00
}
2009-03-05 20:48:40 +00:00
static int write_element_allow_id ( VALUE key , VALUE value , VALUE extra , int allow_id ) {
2009-12-02 20:22:16 +00:00
buffer_t buffer = ( buffer_t ) NUM2LL ( rb_ary_entry ( extra , 0 ) ) ;
2009-06-02 13:38:31 +00:00
VALUE check_keys = rb_ary_entry ( extra , 1 ) ;
2009-03-04 15:05:50 +00:00
2009-03-05 15:27:19 +00:00
if ( TYPE ( key ) = = T_SYMBOL ) {
// TODO better way to do this... ?
key = rb_str_new2 ( rb_id2name ( SYM2ID ( key ) ) ) ;
}
if ( TYPE ( key ) ! = T_STRING ) {
2009-12-02 22:01:49 +00:00
buffer_free ( buffer ) ;
2009-03-05 15:27:19 +00:00
rb_raise ( rb_eTypeError , " keys must be strings or symbols " ) ;
}
2009-03-23 16:14:38 +00:00
if ( ! allow_id & & strcmp ( " _id " , RSTRING_PTR ( key ) ) = = 0 ) {
2009-03-05 20:48:40 +00:00
return ST_CONTINUE ;
}
2009-06-02 13:38:31 +00:00
if ( check_keys = = Qtrue ) {
2009-07-17 16:16:33 +00:00
int i ;
2009-06-02 13:38:31 +00:00
if ( RSTRING_LEN ( key ) > 0 & & RSTRING_PTR ( key ) [ 0 ] = = ' $ ' ) {
2009-12-02 22:01:49 +00:00
buffer_free ( buffer ) ;
2009-08-13 19:52:11 +00:00
rb_raise ( InvalidName , " key must not start with '$' " ) ;
2009-06-02 13:38:31 +00:00
}
for ( i = 0 ; i < RSTRING_LEN ( key ) ; i + + ) {
if ( RSTRING_PTR ( key ) [ i ] = = ' . ' ) {
2009-12-02 22:01:49 +00:00
buffer_free ( buffer ) ;
2009-08-13 19:52:11 +00:00
rb_raise ( InvalidName , " key must not contain '.' " ) ;
2009-06-02 13:38:31 +00:00
}
2009-06-01 21:38:11 +00:00
}
}
2009-03-04 15:05:50 +00:00
switch ( TYPE ( value ) ) {
2009-03-05 22:03:49 +00:00
case T_BIGNUM :
2009-03-04 16:07:22 +00:00
case T_FIXNUM :
2009-03-10 17:19:18 +00:00
{
2009-08-04 14:39:25 +00:00
if ( rb_funcall ( value , rb_intern ( " > " ) , 1 , LL2NUM ( 9223372036854775807LL ) ) = = Qtrue | |
2010-01-11 23:01:36 +00:00
rb_funcall ( value , rb_intern ( " < " ) , 1 , LL2NUM ( - 9223372036854775808ULL ) ) = = Qtrue ) {
2009-12-02 22:01:49 +00:00
buffer_free ( buffer ) ;
2009-08-04 14:39:25 +00:00
rb_raise ( rb_eRangeError , " MongoDB can only handle 8-byte ints " ) ;
}
if ( rb_funcall ( value , rb_intern ( " > " ) , 1 , INT2NUM ( 2147483647L ) ) = = Qtrue | |
rb_funcall ( value , rb_intern ( " < " ) , 1 , INT2NUM ( - 2147483648L ) ) = = Qtrue ) {
long long ll_value ;
write_name_and_type ( buffer , key , 0x12 ) ;
ll_value = NUM2LL ( value ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & ll_value , 8 ) ;
2009-08-04 14:39:25 +00:00
} else {
int int_value ;
write_name_and_type ( buffer , key , 0x10 ) ;
int_value = NUM2LL ( value ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & int_value , 4 ) ;
2009-08-03 15:08:10 +00:00
}
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 16:07:22 +00:00
case T_TRUE :
2009-03-10 17:19:18 +00:00
{
write_name_and_type ( buffer , key , 0x08 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & one , 1 ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 16:07:22 +00:00
case T_FALSE :
2009-03-10 17:19:18 +00:00
{
write_name_and_type ( buffer , key , 0x08 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 16:07:22 +00:00
case T_FLOAT :
2009-03-10 17:19:18 +00:00
{
double d = NUM2DBL ( value ) ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x01 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & d , 8 ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 16:07:22 +00:00
case T_NIL :
2009-03-10 17:19:18 +00:00
{
write_name_and_type ( buffer , key , 0x0A ) ;
break ;
}
2009-03-04 16:07:22 +00:00
case T_HASH :
2009-03-10 17:19:18 +00:00
{
write_name_and_type ( buffer , key , 0x03 ) ;
2009-06-02 13:38:31 +00:00
write_doc ( buffer , value , check_keys ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 16:07:22 +00:00
case T_ARRAY :
2009-03-10 17:19:18 +00:00
{
2009-12-02 20:22:16 +00:00
buffer_position length_location , start_position , obj_length ;
int items , i ;
2009-07-17 16:16:33 +00:00
VALUE * values ;
2009-03-10 17:19:18 +00:00
write_name_and_type ( buffer , key , 0x04 ) ;
2009-12-02 20:22:16 +00:00
start_position = buffer_get_position ( buffer ) ;
2009-03-04 16:07:22 +00:00
2009-03-10 17:19:18 +00:00
// save space for length
2009-12-02 20:22:16 +00:00
length_location = buffer_save_space ( buffer , 4 ) ;
if ( length_location = = - 1 ) {
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " ) ;
}
2009-03-04 16:07:22 +00:00
2009-07-17 16:16:33 +00:00
items = RARRAY_LEN ( value ) ;
values = RARRAY_PTR ( value ) ;
2009-03-10 17:19:18 +00:00
for ( i = 0 ; i < items ; i + + ) {
char * name ;
2009-07-17 16:16:33 +00:00
VALUE key ;
INT2STRING ( & name , i ) ;
key = rb_str_new2 ( name ) ;
2009-06-02 13:38:31 +00:00
write_element ( key , values [ i ] , pack_extra ( buffer , check_keys ) ) ;
2009-03-10 17:19:18 +00:00
free ( name ) ;
}
2009-03-04 16:07:22 +00:00
2009-03-10 17:19:18 +00:00
// write null byte and fill in length
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
obj_length = buffer_get_position ( buffer ) - start_position ;
SAFE_WRITE_AT_POS ( buffer , length_location , ( const char * ) & obj_length , 4 ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 15:05:50 +00:00
case T_STRING :
2009-03-10 17:19:18 +00:00
{
2009-03-12 20:12:52 +00:00
if ( strcmp ( rb_class2name ( RBASIC ( value ) - > klass ) ,
2009-08-20 14:50:48 +00:00
" Mongo::Code " ) = = 0 ) {
2009-12-02 20:22:16 +00:00
buffer_position length_location , start_position , total_length ;
int length ;
2009-03-12 20:12:52 +00:00
write_name_and_type ( buffer , key , 0x0F ) ;
2009-12-02 20:22:16 +00:00
start_position = buffer_get_position ( buffer ) ;
length_location = buffer_save_space ( buffer , 4 ) ;
if ( length_location = = - 1 ) {
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " ) ;
}
2009-03-12 20:12:52 +00:00
2009-07-17 16:16:33 +00:00
length = RSTRING_LEN ( value ) + 1 ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & length , 4 ) ;
SAFE_WRITE ( buffer , RSTRING_PTR ( value ) , length - 1 ) ;
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-06-01 21:38:11 +00:00
write_doc ( buffer , rb_funcall ( value , rb_intern ( " scope " ) , 0 ) , Qfalse ) ;
2009-03-12 20:12:52 +00:00
2009-12-02 20:22:16 +00:00
total_length = buffer_get_position ( buffer ) - start_position ;
SAFE_WRITE_AT_POS ( buffer , length_location , ( const char * ) & total_length , 4 ) ;
2009-03-12 20:12:52 +00:00
break ;
2009-03-10 17:19:18 +00:00
} else {
2009-12-02 20:23:45 +00:00
int length ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x02 ) ;
2009-12-02 20:23:45 +00:00
value = TO_UTF8 ( value ) ;
length = RSTRING_LEN ( value ) + 1 ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & length , 4 ) ;
2009-12-17 17:17:19 +00:00
write_utf8 ( buffer , value , 0 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-03-12 20:12:52 +00:00
break ;
2009-03-10 17:19:18 +00:00
}
2009-03-05 21:08:10 +00:00
}
2009-03-05 16:09:52 +00:00
case T_SYMBOL :
2009-03-10 17:19:18 +00:00
{
const char * str_value = rb_id2name ( SYM2ID ( value ) ) ;
int length = strlen ( str_value ) + 1 ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x0E ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( char * ) & length , 4 ) ;
SAFE_WRITE ( buffer , str_value , length ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 22:38:06 +00:00
case T_OBJECT :
{
// TODO there has to be a better way to do these checks...
const char * cls = rb_class2name ( RBASIC ( value ) - > klass ) ;
2009-08-20 14:50:48 +00:00
if ( strcmp ( cls , " Mongo::Binary " ) = = 0 | |
2009-03-05 14:22:55 +00:00
strcmp ( cls , " ByteBuffer " ) = = 0 ) {
const char subtype = strcmp ( cls , " ByteBuffer " ) ?
( const char ) FIX2INT ( rb_funcall ( value , rb_intern ( " subtype " ) , 0 ) ) : 2 ;
2009-03-04 22:38:06 +00:00
VALUE string_data = rb_funcall ( value , rb_intern ( " to_s " ) , 0 ) ;
2009-03-23 16:14:38 +00:00
int length = RSTRING_LEN ( string_data ) ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x05 ) ;
2009-03-04 22:38:06 +00:00
if ( subtype = = 2 ) {
const int other_length = length + 4 ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( const char * ) & other_length , 4 ) ;
SAFE_WRITE ( buffer , & subtype , 1 ) ;
2009-03-04 22:38:06 +00:00
}
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( const char * ) & length , 4 ) ;
2009-03-04 22:38:06 +00:00
if ( subtype ! = 2 ) {
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & subtype , 1 ) ;
2009-03-04 22:38:06 +00:00
}
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , RSTRING_PTR ( string_data ) , length ) ;
2009-03-04 22:38:06 +00:00
break ;
}
2009-08-20 14:50:48 +00:00
if ( strcmp ( cls , " Mongo::ObjectID " ) = = 0 ) {
2009-03-05 16:38:08 +00:00
VALUE as_array = rb_funcall ( value , rb_intern ( " to_a " ) , 0 ) ;
int i ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x07 ) ;
2009-03-05 16:38:08 +00:00
for ( i = 0 ; i < 12 ; i + + ) {
2009-03-23 16:14:38 +00:00
char byte = ( char ) FIX2INT ( RARRAY_PTR ( as_array ) [ i ] ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & byte , 1 ) ;
2009-03-05 16:38:08 +00:00
}
break ;
}
2009-08-20 14:50:48 +00:00
if ( strcmp ( cls , " Mongo::DBRef " ) = = 0 ) {
2009-12-02 20:22:16 +00:00
buffer_position length_location , start_position , obj_length ;
2009-07-17 16:16:33 +00:00
VALUE ns , oid ;
2009-03-18 17:54:33 +00:00
write_name_and_type ( buffer , key , 0x03 ) ;
2009-12-02 20:22:16 +00:00
start_position = buffer_get_position ( buffer ) ;
2009-03-18 17:54:33 +00:00
// save space for length
2009-12-02 20:22:16 +00:00
length_location = buffer_save_space ( buffer , 4 ) ;
if ( length_location = = - 1 ) {
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " ) ;
}
2009-03-05 16:45:04 +00:00
2009-07-17 16:16:33 +00:00
ns = rb_funcall ( value , rb_intern ( " namespace " ) , 0 ) ;
2009-06-01 21:38:11 +00:00
write_element ( rb_str_new2 ( " $ref " ) , ns , pack_extra ( buffer , Qfalse ) ) ;
2009-07-17 16:16:33 +00:00
oid = rb_funcall ( value , rb_intern ( " object_id " ) , 0 ) ;
2009-06-01 21:38:11 +00:00
write_element ( rb_str_new2 ( " $id " ) , oid , pack_extra ( buffer , Qfalse ) ) ;
2009-03-05 16:45:04 +00:00
2009-03-18 17:54:33 +00:00
// write null byte and fill in length
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
obj_length = buffer_get_position ( buffer ) - start_position ;
SAFE_WRITE_AT_POS ( buffer , length_location , ( const char * ) & obj_length , 4 ) ;
2009-03-05 16:45:04 +00:00
break ;
}
2010-01-20 17:11:58 +00:00
if ( strcmp ( cls , " DateTime " ) = = 0 | | strcmp ( cls , " Date " ) = = 0 | | strcmp ( cls , " ActiveSupport::TimeWithZone " ) = = 0 ) {
2010-01-06 19:30:58 +00:00
buffer_free ( buffer ) ;
2010-01-20 17:11:58 +00:00
rb_raise ( InvalidDocument , " Trying to serialize and instance of Date, DateTime, or TimeWithZone; the MongoDB Ruby driver currently supports Time objects only. " ,
2010-01-06 19:30:58 +00:00
TYPE ( value ) ) ;
}
2009-12-29 17:59:30 +00:00
buffer_free ( buffer ) ;
2010-01-20 17:11:58 +00:00
rb_raise ( InvalidDocument , " Cannot serialize an object of class %s into BSON. " , cls ) ;
2009-12-29 17:59:30 +00:00
break ;
2009-03-04 22:38:06 +00:00
}
2009-03-05 15:58:56 +00:00
case T_DATA :
{
// TODO again, is this really the only way to do this?
const char * cls = rb_class2name ( RBASIC ( value ) - > klass ) ;
if ( strcmp ( cls , " Time " ) = = 0 ) {
double t = NUM2DBL ( rb_funcall ( value , rb_intern ( " to_f " ) , 0 ) ) ;
2009-06-05 18:52:01 +00:00
long long time_since_epoch = ( long long ) round ( t * 1000 ) ;
2009-07-17 16:16:33 +00:00
write_name_and_type ( buffer , key , 0x09 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , ( const char * ) & time_since_epoch , 8 ) ;
2009-03-05 15:58:56 +00:00
break ;
}
}
2009-03-05 18:16:34 +00:00
case T_REGEXP :
2009-03-10 17:19:18 +00:00
{
2009-12-17 17:17:19 +00:00
VALUE pattern = RREGEXP_SRC ( value ) ;
2009-07-17 16:16:33 +00:00
long flags = RREGEXP ( value ) - > ptr - > options ;
VALUE has_extra ;
write_name_and_type ( buffer , key , 0x0B ) ;
2009-12-17 17:17:19 +00:00
pattern = TO_UTF8 ( pattern ) ;
write_utf8 ( buffer , pattern , 1 ) ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-03-05 18:16:34 +00:00
2009-03-23 16:14:38 +00:00
if ( flags & IGNORECASE ) {
2009-03-10 17:19:18 +00:00
char ignorecase = ' i ' ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & ignorecase , 1 ) ;
2009-03-10 17:19:18 +00:00
}
2009-03-23 16:14:38 +00:00
if ( flags & MULTILINE ) {
2009-03-10 17:19:18 +00:00
char multiline = ' m ' ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & multiline , 1 ) ;
2009-03-10 17:19:18 +00:00
}
2009-03-23 16:14:38 +00:00
if ( flags & EXTENDED ) {
2009-03-10 17:19:18 +00:00
char extended = ' x ' ;
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & extended , 1 ) ;
2009-03-10 17:19:18 +00:00
}
2009-03-05 18:16:34 +00:00
2009-07-17 16:16:33 +00:00
has_extra = rb_funcall ( value , rb_intern ( " respond_to? " ) , 1 , rb_str_new2 ( " extra_options_str " ) ) ;
2009-03-10 17:19:18 +00:00
if ( TYPE ( has_extra ) = = T_TRUE ) {
VALUE extra = rb_funcall ( value , rb_intern ( " extra_options_str " ) , 0 ) ;
2009-12-02 20:22:16 +00:00
buffer_position old_position = buffer_get_position ( buffer ) ;
SAFE_WRITE ( buffer , RSTRING_PTR ( extra ) , RSTRING_LEN ( extra ) ) ;
qsort ( buffer_get_buffer ( buffer ) + old_position , RSTRING_LEN ( extra ) , sizeof ( char ) , cmp_char ) ;
2009-03-10 17:19:18 +00:00
}
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
2009-03-05 18:16:34 +00:00
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 15:05:50 +00:00
default :
2009-03-10 17:19:18 +00:00
{
2010-01-20 17:11:58 +00:00
const char * cls = rb_class2name ( RBASIC ( value ) - > klass ) ;
2009-12-02 22:01:49 +00:00
buffer_free ( buffer ) ;
2010-01-20 17:11:58 +00:00
rb_raise ( InvalidDocument , " Cannot serialize an object of class %s into BSON. " , cls ) ;
2009-03-10 17:19:18 +00:00
break ;
}
2009-03-04 15:05:50 +00:00
}
return ST_CONTINUE ;
}
2009-03-05 20:48:40 +00:00
static int write_element ( VALUE key , VALUE value , VALUE extra ) {
return write_element_allow_id ( key , value , extra , 0 ) ;
}
2009-12-02 20:22:16 +00:00
static void write_doc ( buffer_t buffer , VALUE hash , VALUE check_keys ) {
buffer_position start_position = buffer_get_position ( buffer ) ;
buffer_position length_location = buffer_save_space ( buffer , 4 ) ;
buffer_position length ;
2009-10-22 20:20:27 +00:00
VALUE id_str = rb_str_new2 ( " _id " ) ;
VALUE id_sym = ID2SYM ( rb_intern ( " _id " ) ) ;
2009-12-02 20:22:16 +00:00
if ( length_location = = - 1 ) {
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " ) ;
}
2009-10-22 20:20:27 +00:00
if ( rb_funcall ( hash , rb_intern ( " has_key? " ) , 1 , id_str ) = = Qtrue ) {
VALUE id = rb_hash_aref ( hash , id_str ) ;
write_element_allow_id ( id_str , id , pack_extra ( buffer , check_keys ) , 1 ) ;
} else if ( rb_funcall ( hash , rb_intern ( " has_key? " ) , 1 , id_sym ) = = Qtrue ) {
VALUE id = rb_hash_aref ( hash , id_sym ) ;
write_element_allow_id ( id_sym , id , pack_extra ( buffer , check_keys ) , 1 ) ;
2009-03-05 20:48:40 +00:00
}
2009-03-05 19:58:34 +00:00
// we have to check for an OrderedHash and handle that specially
if ( strcmp ( rb_class2name ( RBASIC ( hash ) - > klass ) , " OrderedHash " ) = = 0 ) {
VALUE keys = rb_funcall ( hash , rb_intern ( " keys " ) , 0 ) ;
int i ;
2009-03-23 16:14:38 +00:00
for ( i = 0 ; i < RARRAY_LEN ( keys ) ; i + + ) {
VALUE key = RARRAY_PTR ( keys ) [ i ] ;
2009-03-05 19:58:34 +00:00
VALUE value = rb_hash_aref ( hash , key ) ;
2009-06-01 21:38:11 +00:00
2009-06-02 13:38:31 +00:00
write_element ( key , value , pack_extra ( buffer , check_keys ) ) ;
2009-03-05 19:58:34 +00:00
}
} else {
2009-06-02 13:38:31 +00:00
rb_hash_foreach ( hash , write_element , pack_extra ( buffer , check_keys ) ) ;
2009-03-05 19:58:34 +00:00
}
2009-03-04 15:05:50 +00:00
// write null byte and fill in length
2009-12-02 20:22:16 +00:00
SAFE_WRITE ( buffer , & zero , 1 ) ;
length = buffer_get_position ( buffer ) - start_position ;
2009-12-16 16:32:54 +00:00
// make sure that length doesn't exceed 4MB
if ( length > 4 * 1024 * 1024 ) {
2009-12-16 19:14:15 +00:00
buffer_free ( buffer ) ;
2009-12-16 16:32:54 +00:00
rb_raise ( InvalidDocument , " Document too large: BSON documents are limited to 4MB. " ) ;
return ;
}
2010-01-11 23:01:36 +00:00
SAFE_WRITE_AT_POS ( buffer , length_location , ( const char * ) & length , 4 ) ;
2009-03-04 15:05:50 +00:00
}
2009-06-02 13:38:31 +00:00
static VALUE method_serialize ( VALUE self , VALUE doc , VALUE check_keys ) {
2009-07-17 16:16:33 +00:00
VALUE result ;
2009-12-02 20:22:16 +00:00
buffer_t buffer = buffer_new ( ) ;
if ( buffer = = NULL ) {
rb_raise ( rb_eNoMemError , " failed to allocate memory in buffer.c " ) ;
}
2009-03-04 15:05:50 +00:00
2009-06-02 13:38:31 +00:00
write_doc ( buffer , doc , check_keys ) ;
2009-03-04 15:05:50 +00:00
2009-12-02 20:22:16 +00:00
result = rb_str_new ( buffer_get_buffer ( buffer ) , buffer_get_position ( buffer ) ) ;
if ( buffer_free ( buffer ) ! = 0 ) {
rb_raise ( rb_eRuntimeError , " failed to free buffer " ) ;
}
2009-03-04 15:05:50 +00:00
return result ;
2009-03-03 22:07:22 +00:00
}
2009-03-10 14:23:42 +00:00
static VALUE get_value ( const char * buffer , int * position , int type ) {
VALUE value ;
switch ( type ) {
case 1 :
{
double d ;
memcpy ( & d , buffer + * position , 8 ) ;
2009-03-10 14:45:56 +00:00
value = rb_float_new ( d ) ;
2009-03-10 14:23:42 +00:00
* position + = 8 ;
break ;
}
case 2 :
2009-03-10 15:48:06 +00:00
case 13 :
2009-03-10 14:23:42 +00:00
{
2009-07-17 16:16:33 +00:00
int value_length ;
2009-12-17 17:17:19 +00:00
value_length = * ( int * ) ( buffer + * position ) - 1 ;
2009-03-10 14:23:42 +00:00
* position + = 4 ;
2009-09-04 15:02:04 +00:00
value = STR_NEW ( buffer + * position , value_length ) ;
2009-03-10 14:23:42 +00:00
* position + = value_length + 1 ;
break ;
}
2009-03-10 14:45:56 +00:00
case 3 :
{
int size ;
memcpy ( & size , buffer + * position , 4 ) ;
2009-03-18 17:54:33 +00:00
if ( strcmp ( buffer + * position + 5 , " $ref " ) = = 0 ) { // DBRef
2009-12-17 17:17:19 +00:00
int offset = * position + 10 ;
2009-03-18 17:54:33 +00:00
VALUE argv [ 2 ] ;
2009-12-17 17:17:19 +00:00
int collection_length = * ( int * ) ( buffer + offset ) - 1 ;
2009-07-17 16:16:33 +00:00
char id_type ;
2009-12-17 17:17:19 +00:00
offset + = 4 ;
2009-07-17 16:16:33 +00:00
2009-09-04 15:02:04 +00:00
argv [ 0 ] = STR_NEW ( buffer + offset , collection_length ) ;
2009-03-18 17:54:33 +00:00
offset + = collection_length + 1 ;
2009-07-17 16:16:33 +00:00
id_type = buffer [ offset ] ;
2009-03-18 17:54:33 +00:00
offset + = 5 ;
argv [ 1 ] = get_value ( buffer , & offset , ( int ) id_type ) ;
value = rb_class_new_instance ( 2 , argv , DBRef ) ;
} else {
value = elements_to_hash ( buffer + * position + 4 , size - 5 ) ;
}
2009-03-10 14:45:56 +00:00
* position + = size ;
break ;
}
case 4 :
{
2009-07-17 16:16:33 +00:00
int size , end ;
2009-03-10 14:45:56 +00:00
memcpy ( & size , buffer + * position , 4 ) ;
2009-07-17 16:16:33 +00:00
end = * position + size - 1 ;
2009-03-10 14:45:56 +00:00
* position + = 4 ;
value = rb_ary_new ( ) ;
while ( * position < end ) {
int type = ( int ) buffer [ ( * position ) + + ] ;
int key_size = strlen ( buffer + * position ) ;
2009-07-17 16:16:33 +00:00
VALUE to_append ;
2009-03-10 14:45:56 +00:00
* position + = key_size + 1 ; // just skip the key, they're in order.
2009-07-17 16:16:33 +00:00
to_append = get_value ( buffer , position , type ) ;
2009-03-10 14:45:56 +00:00
rb_ary_push ( value , to_append ) ;
}
( * position ) + + ;
break ;
}
2009-03-10 15:48:06 +00:00
case 5 :
{
2009-07-17 16:16:33 +00:00
int length , subtype ;
VALUE data , st ;
VALUE argv [ 2 ] ;
2009-03-10 15:48:06 +00:00
memcpy ( & length , buffer + * position , 4 ) ;
2009-07-17 16:16:33 +00:00
subtype = ( unsigned char ) buffer [ * position + 4 ] ;
2009-03-10 15:48:06 +00:00
if ( subtype = = 2 ) {
data = rb_str_new ( buffer + * position + 9 , length - 4 ) ;
} else {
data = rb_str_new ( buffer + * position + 5 , length ) ;
}
2009-07-17 16:16:33 +00:00
st = INT2FIX ( subtype ) ;
argv [ 0 ] = data ;
argv [ 1 ] = st ;
2009-03-10 15:48:06 +00:00
value = rb_class_new_instance ( 2 , argv , Binary ) ;
* position + = length + 5 ;
break ;
}
2009-03-10 17:19:18 +00:00
case 6 :
{
2009-08-19 19:18:02 +00:00
value = Qnil ;
2009-03-10 17:19:18 +00:00
break ;
}
case 7 :
{
VALUE str = rb_str_new ( buffer + * position , 12 ) ;
VALUE oid = rb_funcall ( str , rb_intern ( " unpack " ) , 1 , rb_str_new2 ( " C* " ) ) ;
2009-03-10 18:58:20 +00:00
value = rb_class_new_instance ( 1 , & oid , ObjectID ) ;
2009-03-10 17:19:18 +00:00
* position + = 12 ;
break ;
}
2009-03-10 14:23:42 +00:00
case 8 :
{
value = buffer [ ( * position ) + + ] ? Qtrue : Qfalse ;
break ;
}
2009-03-10 17:19:18 +00:00
case 9 :
{
long long millis ;
2009-07-17 16:16:33 +00:00
VALUE seconds , microseconds ;
2009-03-10 17:19:18 +00:00
memcpy ( & millis , buffer + * position , 8 ) ;
2009-12-03 15:07:02 +00:00
seconds = LL2NUM ( millis / 1000 ) ;
2009-07-17 16:16:33 +00:00
microseconds = INT2NUM ( ( millis % 1000 ) * 1000 ) ;
2009-03-10 17:19:18 +00:00
value = rb_funcall ( Time , rb_intern ( " at " ) , 2 , seconds , microseconds ) ;
2009-07-16 20:36:07 +00:00
value = rb_funcall ( value , rb_intern ( " utc " ) , 0 ) ;
2009-03-10 17:19:18 +00:00
* position + = 8 ;
break ;
}
2009-03-10 14:45:56 +00:00
case 10 :
{
value = Qnil ;
break ;
}
2009-03-10 19:33:03 +00:00
case 11 :
{
int pattern_length = strlen ( buffer + * position ) ;
2009-09-04 15:02:04 +00:00
VALUE pattern = STR_NEW ( buffer + * position , pattern_length ) ;
2009-07-17 16:16:33 +00:00
int flags_length , flags = 0 , i = 0 ;
char extra [ 10 ] ;
VALUE argv [ 3 ] ;
2009-03-10 19:33:03 +00:00
* position + = pattern_length + 1 ;
2009-07-17 16:16:33 +00:00
flags_length = strlen ( buffer + * position ) ;
2009-03-10 19:33:03 +00:00
extra [ 0 ] = 0 ;
for ( i = 0 ; i < flags_length ; i + + ) {
char flag = buffer [ * position + i ] ;
2009-03-11 14:49:30 +00:00
if ( flag = = ' i ' ) {
2009-03-23 16:14:38 +00:00
flags | = IGNORECASE ;
2009-03-11 14:49:30 +00:00
}
else if ( flag = = ' m ' ) {
2009-03-23 16:14:38 +00:00
flags | = MULTILINE ;
2009-03-11 14:49:30 +00:00
}
else if ( flag = = ' x ' ) {
2009-03-23 16:14:38 +00:00
flags | = EXTENDED ;
2009-03-10 19:33:03 +00:00
}
else if ( strlen ( extra ) < 9 ) {
strncat ( extra , & flag , 1 ) ;
}
}
2009-07-17 16:16:33 +00:00
argv [ 0 ] = pattern ;
argv [ 1 ] = INT2FIX ( flags ) ;
argv [ 2 ] = rb_str_new2 ( extra ) ;
2009-03-10 19:33:03 +00:00
value = rb_class_new_instance ( 3 , argv , RegexpOfHolding ) ;
* position + = flags_length + 1 ;
break ;
}
2009-03-10 18:58:20 +00:00
case 12 :
{
2009-07-17 16:16:33 +00:00
int collection_length ;
VALUE collection , str , oid , id , argv [ 2 ] ;
2009-12-17 17:17:19 +00:00
collection_length = * ( int * ) ( buffer + * position ) - 1 ;
2009-03-10 18:58:20 +00:00
* position + = 4 ;
2009-09-04 15:02:04 +00:00
collection = STR_NEW ( buffer + * position , collection_length ) ;
2009-03-10 18:58:20 +00:00
* position + = collection_length + 1 ;
2009-07-17 16:16:33 +00:00
str = rb_str_new ( buffer + * position , 12 ) ;
oid = rb_funcall ( str , rb_intern ( " unpack " ) , 1 , rb_str_new2 ( " C* " ) ) ;
id = rb_class_new_instance ( 1 , & oid , ObjectID ) ;
2009-03-10 18:58:20 +00:00
* position + = 12 ;
2009-07-17 16:16:33 +00:00
argv [ 0 ] = collection ;
argv [ 1 ] = id ;
2009-03-10 18:58:20 +00:00
value = rb_class_new_instance ( 2 , argv , DBRef ) ;
break ;
}
2009-03-10 15:48:06 +00:00
case 14 :
{
int value_length ;
memcpy ( & value_length , buffer + * position , 4 ) ;
value = ID2SYM ( rb_intern ( buffer + * position + 4 ) ) ;
2009-03-11 14:49:30 +00:00
* position + = value_length + 4 ;
2009-03-10 15:48:06 +00:00
break ;
}
2009-03-12 20:12:52 +00:00
case 15 :
{
2009-07-17 16:16:33 +00:00
int code_length , scope_size ;
VALUE code , scope , argv [ 2 ] ;
2009-12-17 17:17:19 +00:00
* position + = 4 ;
code_length = * ( int * ) ( buffer + * position ) - 1 ;
* position + = 4 ;
2009-09-04 15:02:04 +00:00
code = STR_NEW ( buffer + * position , code_length ) ;
2009-03-12 20:12:52 +00:00
* position + = code_length + 1 ;
memcpy ( & scope_size , buffer + * position , 4 ) ;
2009-07-17 16:16:33 +00:00
scope = elements_to_hash ( buffer + * position + 4 , scope_size - 5 ) ;
2009-03-12 20:12:52 +00:00
* position + = scope_size ;
2009-07-17 16:16:33 +00:00
argv [ 0 ] = code ;
argv [ 1 ] = scope ;
2009-03-12 20:12:52 +00:00
value = rb_class_new_instance ( 2 , argv , Code ) ;
break ;
}
2009-03-10 14:23:42 +00:00
case 16 :
{
int i ;
memcpy ( & i , buffer + * position , 4 ) ;
2009-03-11 14:49:30 +00:00
value = LL2NUM ( i ) ;
2009-03-10 14:23:42 +00:00
* position + = 4 ;
break ;
}
2009-04-22 17:49:56 +00:00
case 17 :
{
int i ;
int j ;
memcpy ( & i , buffer + * position , 4 ) ;
memcpy ( & j , buffer + * position + 4 , 4 ) ;
value = rb_ary_new3 ( 2 , LL2NUM ( i ) , LL2NUM ( j ) ) ;
* position + = 8 ;
break ;
}
2009-08-04 14:39:25 +00:00
case 18 :
{
long long ll ;
memcpy ( & ll , buffer + * position , 8 ) ;
value = LL2NUM ( ll ) ;
* position + = 8 ;
break ;
}
2009-03-10 14:23:42 +00:00
default :
2009-03-10 17:19:18 +00:00
{
rb_raise ( rb_eTypeError , " no c decoder for this type yet (%d) " , type ) ;
break ;
}
2009-03-10 14:23:42 +00:00
}
return value ;
}
static VALUE elements_to_hash ( const char * buffer , int max ) {
2009-03-10 19:41:28 +00:00
VALUE hash = rb_class_new_instance ( 0 , NULL , OrderedHash ) ;
2009-03-10 14:23:42 +00:00
int position = 0 ;
while ( position < max ) {
int type = ( int ) buffer [ position + + ] ;
int name_length = strlen ( buffer + position ) ;
2009-09-04 15:02:04 +00:00
VALUE name = STR_NEW ( buffer + position , name_length ) ;
2009-07-17 16:16:33 +00:00
VALUE value ;
2009-03-10 14:23:42 +00:00
position + = name_length + 1 ;
2009-07-17 16:16:33 +00:00
value = get_value ( buffer , & position , type ) ;
2009-03-10 19:41:28 +00:00
rb_funcall ( hash , rb_intern ( " []= " ) , 2 , name , value ) ;
2009-03-10 14:23:42 +00:00
}
return hash ;
}
static VALUE method_deserialize ( VALUE self , VALUE bson ) {
2009-03-23 16:14:38 +00:00
const char * buffer = RSTRING_PTR ( bson ) ;
int remaining = RSTRING_LEN ( bson ) ;
2009-03-10 14:23:42 +00:00
// NOTE we just swallow the size and end byte here
buffer + = 4 ;
remaining - = 5 ;
return elements_to_hash ( buffer , remaining ) ;
}
2009-10-29 15:44:07 +00:00
static VALUE fast_pack ( VALUE self )
{
VALUE res ;
long i ;
char c ;
res = rb_str_buf_new ( 0 ) ;
2009-11-13 16:41:50 +00:00
for ( i = 0 ; i < RARRAY_LEN ( self ) ; i + + ) {
c = FIX2LONG ( RARRAY_PTR ( self ) [ i ] ) ;
2009-10-29 15:44:07 +00:00
rb_str_buf_cat ( res , & c , sizeof ( char ) ) ;
}
return res ;
}
static VALUE objectid_generate ( VALUE self )
{
2009-11-13 16:41:50 +00:00
VALUE oid , digest ;
char hostname [ MAX_HOSTNAME_LENGTH ] ;
unsigned char oid_bytes [ 12 ] ;
unsigned long t , inc ;
unsigned short pid ;
2009-10-29 15:44:07 +00:00
int i ;
t = htonl ( time ( NULL ) ) ;
2009-11-13 16:41:50 +00:00
MEMCPY ( & oid_bytes , & t , unsigned char , 4 ) ;
2009-10-29 15:44:07 +00:00
2009-12-02 16:10:30 +00:00
if ( gethostname ( hostname , MAX_HOSTNAME_LENGTH ) ! = 0 ) {
2009-11-13 16:41:50 +00:00
rb_raise ( rb_eRuntimeError , " failed to get hostname " ) ;
}
digest = rb_funcall ( DigestMD5 , rb_intern ( " digest " ) , 1 , rb_str_new2 ( hostname ) ) ;
MEMCPY ( & oid_bytes [ 4 ] , RSTRING_PTR ( digest ) , unsigned char , 3 ) ;
2009-10-29 15:44:07 +00:00
2009-11-13 16:41:50 +00:00
pid = htons ( getpid ( ) ) ;
MEMCPY ( & oid_bytes [ 7 ] , & pid , unsigned char , 2 ) ;
2009-10-29 15:44:07 +00:00
inc = htonl ( FIX2ULONG ( rb_funcall ( self , rb_intern ( " get_inc " ) , 0 ) ) ) ;
2009-11-13 16:41:50 +00:00
MEMCPY ( & oid_bytes [ 9 ] , ( ( unsigned char * ) & inc + 1 ) , unsigned char , 3 ) ;
2009-10-29 15:44:07 +00:00
2009-11-13 16:41:50 +00:00
oid = rb_ary_new2 ( 12 ) ;
for ( i = 0 ; i < 12 ; i + + ) {
rb_ary_store ( oid , i , INT2FIX ( ( unsigned int ) oid_bytes [ i ] ) ) ;
}
return oid ;
2009-10-29 15:44:07 +00:00
}
2009-03-03 22:07:22 +00:00
void Init_cbson ( ) {
2009-12-02 16:53:59 +00:00
VALUE mongo , CBson , Digest , ext_version ;
2009-03-10 17:19:18 +00:00
Time = rb_const_get ( rb_cObject , rb_intern ( " Time " ) ) ;
2009-08-20 14:50:48 +00:00
mongo = rb_const_get ( rb_cObject , rb_intern ( " Mongo " ) ) ;
2009-03-10 17:19:18 +00:00
rb_require ( " mongo/types/binary " ) ;
2009-08-20 14:50:48 +00:00
Binary = rb_const_get ( mongo , rb_intern ( " Binary " ) ) ;
2009-03-10 17:19:18 +00:00
rb_require ( " mongo/types/objectid " ) ;
2009-08-20 14:50:48 +00:00
ObjectID = rb_const_get ( mongo , rb_intern ( " ObjectID " ) ) ;
2009-03-10 18:58:20 +00:00
rb_require ( " mongo/types/dbref " ) ;
2009-08-20 14:50:48 +00:00
DBRef = rb_const_get ( mongo , rb_intern ( " DBRef " ) ) ;
2009-03-12 20:12:52 +00:00
rb_require ( " mongo/types/code " ) ;
2009-08-20 14:50:48 +00:00
Code = rb_const_get ( mongo , rb_intern ( " Code " ) ) ;
2009-03-10 19:33:03 +00:00
rb_require ( " mongo/types/regexp_of_holding " ) ;
2009-08-20 14:50:48 +00:00
RegexpOfHolding = rb_const_get ( mongo , rb_intern ( " RegexpOfHolding " ) ) ;
2010-01-11 16:38:35 +00:00
rb_require ( " mongo/exceptions " ) ;
2009-08-20 14:50:48 +00:00
InvalidName = rb_const_get ( mongo , rb_intern ( " InvalidName " ) ) ;
2009-12-02 20:23:45 +00:00
InvalidStringEncoding = rb_const_get ( mongo , rb_intern ( " InvalidStringEncoding " ) ) ;
2009-12-16 16:32:54 +00:00
InvalidDocument = rb_const_get ( mongo , rb_intern ( " InvalidDocument " ) ) ;
2009-03-10 19:41:28 +00:00
rb_require ( " mongo/util/ordered_hash " ) ;
OrderedHash = rb_const_get ( rb_cObject , rb_intern ( " OrderedHash " ) ) ;
2009-03-10 17:19:18 +00:00
2009-07-17 16:16:33 +00:00
CBson = rb_define_module ( " CBson " ) ;
2009-12-02 16:53:59 +00:00
ext_version = rb_str_new2 ( VERSION ) ;
rb_define_const ( CBson , " VERSION " , ext_version ) ;
2009-06-01 21:38:11 +00:00
rb_define_module_function ( CBson , " serialize " , method_serialize , 2 ) ;
2009-03-10 14:23:42 +00:00
rb_define_module_function ( CBson , " deserialize " , method_deserialize , 1 ) ;
2009-10-29 15:44:07 +00:00
rb_require ( " digest/md5 " ) ;
Digest = rb_const_get ( rb_cObject , rb_intern ( " Digest " ) ) ;
DigestMD5 = rb_const_get ( Digest , rb_intern ( " MD5 " ) ) ;
rb_define_method ( ObjectID , " generate " , objectid_generate , 0 ) ;
rb_define_method ( rb_cArray , " fast_pack " , fast_pack , 0 ) ;
2009-03-03 22:07:22 +00:00
}