From 064ddacd5e8ff82ad68b4128b1950e9b9d9db4cf Mon Sep 17 00:00:00 2001 From: Mike Dirolf Date: Wed, 4 Mar 2009 10:05:50 -0500 Subject: [PATCH] c encoder for string types --- ext/cbson/cbson.c | 49 ++++++++++++++++++++++++++++++++++++++++-- lib/mongo/util/bson.rb | 5 ++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/ext/cbson/cbson.c b/ext/cbson/cbson.c index 071fb9b..b16a873 100644 --- a/ext/cbson/cbson.c +++ b/ext/cbson/cbson.c @@ -1,4 +1,5 @@ #include "ruby.h" +#include "st.h" #include #define INITIAL_BUFFER_SIZE 256 @@ -9,6 +10,8 @@ typedef struct { int position; } bson_buffer; +static char zero = 0; + static bson_buffer* buffer_new(void) { bson_buffer* buffer; buffer = (bson_buffer*)malloc(sizeof(bson_buffer)); @@ -65,9 +68,51 @@ static void buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size) buffer->position += size; } +static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) { + buffer_write_bytes(buffer, &type, 1); + buffer_write_bytes(buffer, RSTRING(name)->ptr, RSTRING(name)->len); + buffer_write_bytes(buffer, &zero, 1); +} + +static int write_element(VALUE key, VALUE value, VALUE extra) { + bson_buffer* buffer = (bson_buffer*)extra; + + switch(TYPE(value)) { + case T_STRING: + 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; + default: + rb_raise(rb_eTypeError, "no c encoder for this type yet"); + break; + } + return ST_CONTINUE; +} + +static void write_doc(bson_buffer* buffer, VALUE hash) { + int start_position = buffer->position; + int length_location = buffer_save_bytes(buffer, 4); + + rb_hash_foreach(hash, write_element, (VALUE)buffer); + + // write null byte and fill in length + buffer_write_bytes(buffer, &zero, 1); + int length = buffer->position - start_position; + memcpy(buffer->buffer + length_location, &length, 4); +} + static VALUE method_serialize(VALUE self, VALUE doc) { - char data[5] = {0x05, 0x00, 0x00, 0x00, 0x00}; - return rb_str_new(data, 5); + bson_buffer* buffer = buffer_new(); + assert(buffer); + + write_doc(buffer, doc); + + VALUE result = rb_str_new(buffer->buffer, buffer->position); + buffer_free(buffer); + return result; } void Init_cbson() { diff --git a/lib/mongo/util/bson.rb b/lib/mongo/util/bson.rb index 0ea4c79..82bc835 100644 --- a/lib/mongo/util/bson.rb +++ b/lib/mongo/util/bson.rb @@ -255,7 +255,10 @@ class BSON def deserialize_string_data(buf) len = buf.get_int bytes = buf.get(len) - str = bytes[0..-2].pack("C*") + str = bytes[0..-2] + if str.respond_to? "pack" + str = str.pack("C*") + end if RUBY_VERSION >= '1.9' str.force_encoding("utf-8") end