towards c decoder
This commit is contained in:
parent
66cb1d492c
commit
d0d043323f
|
@ -353,7 +353,72 @@ static VALUE method_serialize(VALUE self, VALUE doc) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE get_value(const char* buffer, int* position, int type) {
|
||||||
|
VALUE value;
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
memcpy(&d, buffer + *position, 8);
|
||||||
|
value = DBL2NUM(d);
|
||||||
|
*position += 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
*position += 4;
|
||||||
|
int value_length = strlen(buffer + *position);
|
||||||
|
value = rb_str_new(buffer+ *position, value_length);
|
||||||
|
*position += value_length + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
value = buffer[(*position)++] ? Qtrue : Qfalse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16:
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memcpy(&i, buffer + *position, 4);
|
||||||
|
value = INT2FIX(i);
|
||||||
|
*position += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE elements_to_hash(const char* buffer, int max) {
|
||||||
|
VALUE hash = rb_hash_new();
|
||||||
|
int position = 0;
|
||||||
|
while (position < max) {
|
||||||
|
int type = (int)buffer[position++];
|
||||||
|
int name_length = strlen(buffer + position);
|
||||||
|
VALUE name = rb_str_new(buffer + position, name_length);
|
||||||
|
position += name_length + 1;
|
||||||
|
VALUE value = get_value(buffer, &position, type);
|
||||||
|
rb_hash_aset(hash, name, value);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE method_deserialize(VALUE self, VALUE bson) {
|
||||||
|
const char* buffer = RSTRING(bson)->ptr;
|
||||||
|
int remaining = RSTRING(bson)->len;
|
||||||
|
|
||||||
|
// NOTE we just swallow the size and end byte here
|
||||||
|
buffer += 4;
|
||||||
|
remaining -= 5;
|
||||||
|
|
||||||
|
return elements_to_hash(buffer, remaining);
|
||||||
|
}
|
||||||
|
|
||||||
void Init_cbson() {
|
void Init_cbson() {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,73 +131,86 @@ class BSON
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def deserialize(buf=nil, parent=nil)
|
begin
|
||||||
# If buf is nil, use @buf, assumed to contain already-serialized BSON.
|
require 'mongo/ext/cbson'
|
||||||
# This is only true during testing.
|
def deserialize(buf=nil, parent=nil)
|
||||||
if buf.is_a? String
|
if buf.is_a? String
|
||||||
@buf = ByteBuffer.new(buf) if buf
|
@buf = ByteBuffer.new(buf) if buf
|
||||||
else
|
|
||||||
@buf = ByteBuffer.new(buf.to_a) if buf
|
|
||||||
end
|
|
||||||
@buf.rewind
|
|
||||||
@buf.get_int # eat message size
|
|
||||||
doc = OrderedHash.new
|
|
||||||
while @buf.more?
|
|
||||||
type = @buf.get
|
|
||||||
case type
|
|
||||||
when STRING, CODE
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_string_data(@buf)
|
|
||||||
when SYMBOL
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_string_data(@buf).intern
|
|
||||||
when NUMBER
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_number_data(@buf)
|
|
||||||
when NUMBER_INT
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_number_int_data(@buf)
|
|
||||||
when OID
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_oid_data(@buf)
|
|
||||||
when ARRAY
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_array_data(@buf, doc)
|
|
||||||
when REGEX
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_regex_data(@buf)
|
|
||||||
when OBJECT
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_object_data(@buf, doc)
|
|
||||||
when BOOLEAN
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_boolean_data(@buf)
|
|
||||||
when DATE
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_date_data(@buf)
|
|
||||||
when NULL
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = nil
|
|
||||||
when UNDEFINED
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = Undefined.new
|
|
||||||
when REF
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_dbref_data(@buf, key, parent)
|
|
||||||
when BINARY
|
|
||||||
key = deserialize_cstr(@buf)
|
|
||||||
doc[key] = deserialize_binary_data(@buf)
|
|
||||||
when CODE_W_SCOPE
|
|
||||||
# TODO CODE_W_SCOPE unimplemented; may be removed
|
|
||||||
raise "unimplemented type #{type}"
|
|
||||||
when EOO
|
|
||||||
break
|
|
||||||
else
|
else
|
||||||
raise "Unknown type #{type}, key = #{key}"
|
@buf = ByteBuffer.new(buf.to_a) if buf
|
||||||
end
|
end
|
||||||
|
@buf.rewind
|
||||||
|
CBson.deserialize(@buf.to_s)
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
def deserialize(buf=nil, parent=nil)
|
||||||
|
# If buf is nil, use @buf, assumed to contain already-serialized BSON.
|
||||||
|
# This is only true during testing.
|
||||||
|
if buf.is_a? String
|
||||||
|
@buf = ByteBuffer.new(buf) if buf
|
||||||
|
else
|
||||||
|
@buf = ByteBuffer.new(buf.to_a) if buf
|
||||||
|
end
|
||||||
|
@buf.rewind
|
||||||
|
@buf.get_int # eat message size
|
||||||
|
doc = OrderedHash.new
|
||||||
|
while @buf.more?
|
||||||
|
type = @buf.get
|
||||||
|
case type
|
||||||
|
when STRING, CODE
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_string_data(@buf)
|
||||||
|
when SYMBOL
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_string_data(@buf).intern
|
||||||
|
when NUMBER
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_number_data(@buf)
|
||||||
|
when NUMBER_INT
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_number_int_data(@buf)
|
||||||
|
when OID
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_oid_data(@buf)
|
||||||
|
when ARRAY
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_array_data(@buf, doc)
|
||||||
|
when REGEX
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_regex_data(@buf)
|
||||||
|
when OBJECT
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_object_data(@buf, doc)
|
||||||
|
when BOOLEAN
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_boolean_data(@buf)
|
||||||
|
when DATE
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_date_data(@buf)
|
||||||
|
when NULL
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = nil
|
||||||
|
when UNDEFINED
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = Undefined.new
|
||||||
|
when REF
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_dbref_data(@buf, key, parent)
|
||||||
|
when BINARY
|
||||||
|
key = deserialize_cstr(@buf)
|
||||||
|
doc[key] = deserialize_binary_data(@buf)
|
||||||
|
when CODE_W_SCOPE
|
||||||
|
# TODO CODE_W_SCOPE unimplemented; may be removed
|
||||||
|
raise "unimplemented type #{type}"
|
||||||
|
when EOO
|
||||||
|
break
|
||||||
|
else
|
||||||
|
raise "Unknown type #{type}, key = #{key}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@buf.rewind
|
||||||
|
doc
|
||||||
end
|
end
|
||||||
@buf.rewind
|
|
||||||
doc
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# For debugging.
|
# For debugging.
|
||||||
|
|
Loading…
Reference in New Issue