undefined, oid, date decoders

This commit is contained in:
Mike Dirolf 2009-03-10 13:19:18 -04:00
parent 5bbbd0b1cd
commit a3f4e4565a

View File

@ -28,6 +28,9 @@
#define INITIAL_BUFFER_SIZE 256 #define INITIAL_BUFFER_SIZE 256
static VALUE Binary; static VALUE Binary;
static VALUE Undefined;
static VALUE Time;
static VALUE ObjectID;
typedef struct { typedef struct {
char* buffer; char* buffer;
@ -129,77 +132,97 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
switch(TYPE(value)) { switch(TYPE(value)) {
case T_BIGNUM: case T_BIGNUM:
write_name_and_type(buffer, key, 0x10); {
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0); write_name_and_type(buffer, key, 0x10);
int int_value = NUM2LL(as_f); VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
buffer_write_bytes(buffer, (char*)&int_value, 4); int int_value = NUM2LL(as_f);
break; buffer_write_bytes(buffer, (char*)&int_value, 4);
break;
}
case T_FIXNUM: case T_FIXNUM:
write_name_and_type(buffer, key, 0x10); {
int_value = FIX2INT(value); write_name_and_type(buffer, key, 0x10);
buffer_write_bytes(buffer, (char*)&int_value, 4); int int_value = FIX2INT(value);
break; buffer_write_bytes(buffer, (char*)&int_value, 4);
break;
}
case T_TRUE: case T_TRUE:
write_name_and_type(buffer, key, 0x08); {
buffer_write_bytes(buffer, &one, 1); write_name_and_type(buffer, key, 0x08);
break; buffer_write_bytes(buffer, &one, 1);
break;
}
case T_FALSE: case T_FALSE:
write_name_and_type(buffer, key, 0x08); {
buffer_write_bytes(buffer, &zero, 1); write_name_and_type(buffer, key, 0x08);
break; buffer_write_bytes(buffer, &zero, 1);
break;
}
case T_FLOAT: case T_FLOAT:
write_name_and_type(buffer, key, 0x01); {
double d = NUM2DBL(value); write_name_and_type(buffer, key, 0x01);
buffer_write_bytes(buffer, (char*)&d, 8); double d = NUM2DBL(value);
break; buffer_write_bytes(buffer, (char*)&d, 8);
break;
}
case T_NIL: case T_NIL:
write_name_and_type(buffer, key, 0x0A); {
break; write_name_and_type(buffer, key, 0x0A);
break;
}
case T_HASH: case T_HASH:
write_name_and_type(buffer, key, 0x03); {
write_doc(buffer, value); write_name_and_type(buffer, key, 0x03);
break; write_doc(buffer, value);
break;
}
case T_ARRAY: case T_ARRAY:
write_name_and_type(buffer, key, 0x04); {
int start_position = buffer->position; write_name_and_type(buffer, key, 0x04);
int start_position = buffer->position;
// save space for length // save space for length
int length_location = buffer_save_bytes(buffer, 4); int length_location = buffer_save_bytes(buffer, 4);
int items = RARRAY_LEN(value); int items = RARRAY_LEN(value);
VALUE* values = RARRAY_PTR(value); VALUE* values = RARRAY_PTR(value);
int i; int i;
for(i = 0; i < items; i++) { for(i = 0; i < items; i++) {
char* name; char* name;
asprintf(&name, "%d", i); asprintf(&name, "%d", i);
VALUE key = rb_str_new2(name); VALUE key = rb_str_new2(name);
write_element(key, values[i], (VALUE)buffer); write_element(key, values[i], (VALUE)buffer);
free(name); free(name);
}
// write null byte and fill in length
buffer_write_bytes(buffer, &zero, 1);
int obj_length = buffer->position - start_position;
memcpy(buffer->buffer + length_location, &obj_length, 4);
break;
} }
// write null byte and fill in length
buffer_write_bytes(buffer, &zero, 1);
int obj_length = buffer->position - start_position;
memcpy(buffer->buffer + length_location, &obj_length, 4);
break;
case T_STRING: case T_STRING:
if (is_code) { {
write_name_and_type(buffer, key, 0x0D); if (is_code) {
} else { write_name_and_type(buffer, key, 0x0D);
write_name_and_type(buffer, key, 0x02); } else {
write_name_and_type(buffer, key, 0x02);
}
int length = RSTRING(value)->len + 1;
buffer_write_bytes(buffer, (char*)&length, 4);
buffer_write_bytes(buffer, RSTRING(value)->ptr, length - 1);
buffer_write_bytes(buffer, &zero, 1);
break;
} }
int length = RSTRING(value)->len + 1;
buffer_write_bytes(buffer, (char*)&length, 4);
buffer_write_bytes(buffer, RSTRING(value)->ptr, length - 1);
buffer_write_bytes(buffer, &zero, 1);
break;
case T_SYMBOL: case T_SYMBOL:
write_name_and_type(buffer, key, 0x0E); {
const char* str_value = rb_id2name(SYM2ID(value)); write_name_and_type(buffer, key, 0x0E);
length = strlen(str_value) + 1; const char* str_value = rb_id2name(SYM2ID(value));
buffer_write_bytes(buffer, (char*)&length, 4); int length = strlen(str_value) + 1;
buffer_write_bytes(buffer, str_value, length); buffer_write_bytes(buffer, (char*)&length, 4);
break; buffer_write_bytes(buffer, str_value, length);
break;
}
case T_OBJECT: case T_OBJECT:
{ {
// TODO there has to be a better way to do these checks... // TODO there has to be a better way to do these checks...
@ -244,6 +267,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
VALUE oid_as_array = rb_funcall(rb_funcall(value, rb_intern("object_id"), 0), VALUE oid_as_array = rb_funcall(rb_funcall(value, rb_intern("object_id"), 0),
rb_intern("to_a"), 0); rb_intern("to_a"), 0);
int i;
for (i = 0; i < 12; i++) { for (i = 0; i < 12; i++) {
char byte = (char)FIX2INT(RARRAY(oid_as_array)->ptr[i]); char byte = (char)FIX2INT(RARRAY(oid_as_array)->ptr[i]);
buffer_write_bytes(buffer, &byte, 1); buffer_write_bytes(buffer, &byte, 1);
@ -268,40 +292,44 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
} }
} }
case T_REGEXP: case T_REGEXP:
write_name_and_type(buffer, key, 0x0B); {
write_name_and_type(buffer, key, 0x0B);
length = RREGEXP(value)->len; int length = RREGEXP(value)->len;
char* pattern = RREGEXP(value)->str; char* pattern = RREGEXP(value)->str;
buffer_write_bytes(buffer, pattern, length); buffer_write_bytes(buffer, pattern, length);
buffer_write_bytes(buffer, &zero, 1); buffer_write_bytes(buffer, &zero, 1);
long flags = RREGEXP(value)->ptr->options; long flags = RREGEXP(value)->ptr->options;
if (flags & RE_OPTION_IGNORECASE) { if (flags & RE_OPTION_IGNORECASE) {
char ignorecase = 'i'; char ignorecase = 'i';
buffer_write_bytes(buffer, &ignorecase, 1); buffer_write_bytes(buffer, &ignorecase, 1);
} }
if (flags & RE_OPTION_MULTILINE) { if (flags & RE_OPTION_MULTILINE) {
char multiline = 'm'; char multiline = 'm';
buffer_write_bytes(buffer, &multiline, 1); buffer_write_bytes(buffer, &multiline, 1);
} }
if (flags & RE_OPTION_EXTENDED) { if (flags & RE_OPTION_EXTENDED) {
char extended = 'x'; char extended = 'x';
buffer_write_bytes(buffer, &extended, 1); buffer_write_bytes(buffer, &extended, 1);
} }
VALUE has_extra = rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("extra_options_str")); VALUE has_extra = rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("extra_options_str"));
if (TYPE(has_extra) == T_TRUE) { if (TYPE(has_extra) == T_TRUE) {
VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0); VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
int old_position = buffer->position; int old_position = buffer->position;
buffer_write_bytes(buffer, RSTRING(extra)->ptr, RSTRING(extra)->len); buffer_write_bytes(buffer, RSTRING(extra)->ptr, RSTRING(extra)->len);
qsort(buffer->buffer + old_position, RSTRING(extra)->len, sizeof(char), cmp_char); qsort(buffer->buffer + old_position, RSTRING(extra)->len, sizeof(char), cmp_char);
} }
buffer_write_bytes(buffer, &zero, 1); buffer_write_bytes(buffer, &zero, 1);
break; break;
}
default: default:
rb_raise(rb_eTypeError, "no c encoder for this type yet (%d)", TYPE(value)); {
break; rb_raise(rb_eTypeError, "no c encoder for this type yet (%d)", TYPE(value));
break;
}
} }
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -419,11 +447,37 @@ static VALUE get_value(const char* buffer, int* position, int type) {
*position += length + 5; *position += length + 5;
break; break;
} }
case 6:
{
VALUE* argv;
value = rb_class_new_instance(0, argv, Undefined);
break;
}
case 7:
{
VALUE str = rb_str_new(buffer + *position, 12);
VALUE oid = rb_funcall(str, rb_intern("unpack"), 1, rb_str_new2("C*"));
VALUE argv[1] = {oid};
value = rb_class_new_instance(1, argv, ObjectID);
*position += 12;
break;
}
case 8: case 8:
{ {
value = buffer[(*position)++] ? Qtrue : Qfalse; value = buffer[(*position)++] ? Qtrue : Qfalse;
break; break;
} }
case 9:
{
long long millis;
memcpy(&millis, buffer + *position, 8);
VALUE seconds = INT2NUM(millis / 1000);
VALUE microseconds = INT2NUM((millis % 1000) * 1000);
value = rb_funcall(Time, rb_intern("at"), 2, seconds, microseconds);
*position += 8;
break;
}
case 10: case 10:
{ {
value = Qnil; value = Qnil;
@ -446,8 +500,10 @@ static VALUE get_value(const char* buffer, int* position, int type) {
break; break;
} }
default: default:
rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type); {
break; rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type);
break;
}
} }
return value; return value;
} }
@ -478,12 +534,19 @@ static VALUE method_deserialize(VALUE self, VALUE bson) {
} }
void Init_cbson() { void Init_cbson() {
rb_require("mongo/types/binary"); Time = rb_const_get(rb_cObject, rb_intern("Time"));
VALUE driver = rb_const_get(rb_const_get(rb_const_get(rb_cObject, VALUE driver = rb_const_get(rb_const_get(rb_const_get(rb_cObject,
rb_intern("XGen")), rb_intern("XGen")),
rb_intern("Mongo")), rb_intern("Mongo")),
rb_intern("Driver")); rb_intern("Driver"));
rb_require("mongo/types/binary");
Binary = rb_const_get(driver, rb_intern("Binary")); Binary = rb_const_get(driver, rb_intern("Binary"));
rb_require("mongo/types/undefined");
Undefined = rb_const_get(driver, rb_intern("Undefined"));
rb_require("mongo/types/objectid");
ObjectID = rb_const_get(driver, rb_intern("ObjectID"));
VALUE CBson = rb_define_module("CBson"); VALUE CBson = rb_define_module("CBson");
rb_define_module_function(CBson, "serialize", method_serialize, 1); rb_define_module_function(CBson, "serialize", method_serialize, 1);
rb_define_module_function(CBson, "deserialize", method_deserialize, 1); rb_define_module_function(CBson, "deserialize", method_deserialize, 1);