undefined, oid, date decoders
This commit is contained in:
parent
5bbbd0b1cd
commit
a3f4e4565a
|
@ -28,6 +28,9 @@
|
|||
#define INITIAL_BUFFER_SIZE 256
|
||||
|
||||
static VALUE Binary;
|
||||
static VALUE Undefined;
|
||||
static VALUE Time;
|
||||
static VALUE ObjectID;
|
||||
|
||||
typedef struct {
|
||||
char* buffer;
|
||||
|
@ -129,77 +132,97 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|||
|
||||
switch(TYPE(value)) {
|
||||
case T_BIGNUM:
|
||||
write_name_and_type(buffer, key, 0x10);
|
||||
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
|
||||
int int_value = NUM2LL(as_f);
|
||||
buffer_write_bytes(buffer, (char*)&int_value, 4);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x10);
|
||||
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
|
||||
int int_value = NUM2LL(as_f);
|
||||
buffer_write_bytes(buffer, (char*)&int_value, 4);
|
||||
break;
|
||||
}
|
||||
case T_FIXNUM:
|
||||
write_name_and_type(buffer, key, 0x10);
|
||||
int_value = FIX2INT(value);
|
||||
buffer_write_bytes(buffer, (char*)&int_value, 4);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x10);
|
||||
int int_value = FIX2INT(value);
|
||||
buffer_write_bytes(buffer, (char*)&int_value, 4);
|
||||
break;
|
||||
}
|
||||
case T_TRUE:
|
||||
write_name_and_type(buffer, key, 0x08);
|
||||
buffer_write_bytes(buffer, &one, 1);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x08);
|
||||
buffer_write_bytes(buffer, &one, 1);
|
||||
break;
|
||||
}
|
||||
case T_FALSE:
|
||||
write_name_and_type(buffer, key, 0x08);
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x08);
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
break;
|
||||
}
|
||||
case T_FLOAT:
|
||||
write_name_and_type(buffer, key, 0x01);
|
||||
double d = NUM2DBL(value);
|
||||
buffer_write_bytes(buffer, (char*)&d, 8);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x01);
|
||||
double d = NUM2DBL(value);
|
||||
buffer_write_bytes(buffer, (char*)&d, 8);
|
||||
break;
|
||||
}
|
||||
case T_NIL:
|
||||
write_name_and_type(buffer, key, 0x0A);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x0A);
|
||||
break;
|
||||
}
|
||||
case T_HASH:
|
||||
write_name_and_type(buffer, key, 0x03);
|
||||
write_doc(buffer, value);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x03);
|
||||
write_doc(buffer, value);
|
||||
break;
|
||||
}
|
||||
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
|
||||
int length_location = buffer_save_bytes(buffer, 4);
|
||||
// save space for length
|
||||
int length_location = buffer_save_bytes(buffer, 4);
|
||||
|
||||
int items = RARRAY_LEN(value);
|
||||
VALUE* values = RARRAY_PTR(value);
|
||||
int i;
|
||||
for(i = 0; i < items; i++) {
|
||||
char* name;
|
||||
asprintf(&name, "%d", i);
|
||||
VALUE key = rb_str_new2(name);
|
||||
write_element(key, values[i], (VALUE)buffer);
|
||||
free(name);
|
||||
int items = RARRAY_LEN(value);
|
||||
VALUE* values = RARRAY_PTR(value);
|
||||
int i;
|
||||
for(i = 0; i < items; i++) {
|
||||
char* name;
|
||||
asprintf(&name, "%d", i);
|
||||
VALUE key = rb_str_new2(name);
|
||||
write_element(key, values[i], (VALUE)buffer);
|
||||
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:
|
||||
if (is_code) {
|
||||
write_name_and_type(buffer, key, 0x0D);
|
||||
} else {
|
||||
write_name_and_type(buffer, key, 0x02);
|
||||
{
|
||||
if (is_code) {
|
||||
write_name_and_type(buffer, key, 0x0D);
|
||||
} 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:
|
||||
write_name_and_type(buffer, key, 0x0E);
|
||||
const char* str_value = rb_id2name(SYM2ID(value));
|
||||
length = strlen(str_value) + 1;
|
||||
buffer_write_bytes(buffer, (char*)&length, 4);
|
||||
buffer_write_bytes(buffer, str_value, length);
|
||||
break;
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x0E);
|
||||
const char* str_value = rb_id2name(SYM2ID(value));
|
||||
int length = strlen(str_value) + 1;
|
||||
buffer_write_bytes(buffer, (char*)&length, 4);
|
||||
buffer_write_bytes(buffer, str_value, length);
|
||||
break;
|
||||
}
|
||||
case T_OBJECT:
|
||||
{
|
||||
// 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),
|
||||
rb_intern("to_a"), 0);
|
||||
int i;
|
||||
for (i = 0; i < 12; i++) {
|
||||
char byte = (char)FIX2INT(RARRAY(oid_as_array)->ptr[i]);
|
||||
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:
|
||||
write_name_and_type(buffer, key, 0x0B);
|
||||
{
|
||||
write_name_and_type(buffer, key, 0x0B);
|
||||
|
||||
length = RREGEXP(value)->len;
|
||||
char* pattern = RREGEXP(value)->str;
|
||||
buffer_write_bytes(buffer, pattern, length);
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
int length = RREGEXP(value)->len;
|
||||
char* pattern = RREGEXP(value)->str;
|
||||
buffer_write_bytes(buffer, pattern, length);
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
|
||||
long flags = RREGEXP(value)->ptr->options;
|
||||
if (flags & RE_OPTION_IGNORECASE) {
|
||||
char ignorecase = 'i';
|
||||
buffer_write_bytes(buffer, &ignorecase, 1);
|
||||
}
|
||||
if (flags & RE_OPTION_MULTILINE) {
|
||||
char multiline = 'm';
|
||||
buffer_write_bytes(buffer, &multiline, 1);
|
||||
}
|
||||
if (flags & RE_OPTION_EXTENDED) {
|
||||
char extended = 'x';
|
||||
buffer_write_bytes(buffer, &extended, 1);
|
||||
}
|
||||
long flags = RREGEXP(value)->ptr->options;
|
||||
if (flags & RE_OPTION_IGNORECASE) {
|
||||
char ignorecase = 'i';
|
||||
buffer_write_bytes(buffer, &ignorecase, 1);
|
||||
}
|
||||
if (flags & RE_OPTION_MULTILINE) {
|
||||
char multiline = 'm';
|
||||
buffer_write_bytes(buffer, &multiline, 1);
|
||||
}
|
||||
if (flags & RE_OPTION_EXTENDED) {
|
||||
char extended = 'x';
|
||||
buffer_write_bytes(buffer, &extended, 1);
|
||||
}
|
||||
|
||||
VALUE has_extra = rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("extra_options_str"));
|
||||
if (TYPE(has_extra) == T_TRUE) {
|
||||
VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
|
||||
int old_position = buffer->position;
|
||||
buffer_write_bytes(buffer, RSTRING(extra)->ptr, RSTRING(extra)->len);
|
||||
qsort(buffer->buffer + old_position, RSTRING(extra)->len, sizeof(char), cmp_char);
|
||||
}
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
VALUE has_extra = rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("extra_options_str"));
|
||||
if (TYPE(has_extra) == T_TRUE) {
|
||||
VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
|
||||
int old_position = buffer->position;
|
||||
buffer_write_bytes(buffer, RSTRING(extra)->ptr, RSTRING(extra)->len);
|
||||
qsort(buffer->buffer + old_position, RSTRING(extra)->len, sizeof(char), cmp_char);
|
||||
}
|
||||
buffer_write_bytes(buffer, &zero, 1);
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -419,11 +447,37 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|||
*position += length + 5;
|
||||
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:
|
||||
{
|
||||
value = buffer[(*position)++] ? Qtrue : Qfalse;
|
||||
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:
|
||||
{
|
||||
value = Qnil;
|
||||
|
@ -446,8 +500,10 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -478,12 +534,19 @@ static VALUE method_deserialize(VALUE self, VALUE bson) {
|
|||
}
|
||||
|
||||
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,
|
||||
rb_intern("XGen")),
|
||||
rb_intern("Mongo")),
|
||||
rb_intern("Driver"));
|
||||
rb_require("mongo/types/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");
|
||||
rb_define_module_function(CBson, "serialize", method_serialize, 1);
|
||||
rb_define_module_function(CBson, "deserialize", method_deserialize, 1);
|
||||
|
|
Loading…
Reference in New Issue