Permalink
Browse files

Add support for deserializing Vectors

  • Loading branch information...
1 parent e22b6c8 commit 8b217aae73031054b15b4482881a51911bb9307c @warhammerkid warhammerkid committed Feb 3, 2013
@@ -30,7 +30,7 @@ int des_read_uint16(AMF_DESERIALIZER *des) {
return ((str[0] << 8) | str[1]);
}
-unsigned long des_read_uint32(AMF_DESERIALIZER *des) {
+unsigned int des_read_uint32(AMF_DESERIALIZER *des) {
DES_BOUNDS_CHECK(des, 4);
const unsigned char *str = (unsigned char*)(des->stream) + des->pos;
des->pos += 4;
@@ -98,7 +98,7 @@ int des_read_int(AMF_DESERIALIZER *des) {
/*
* Read a string and then force the encoding to UTF 8 if running ruby 1.9
*/
-VALUE des_read_string(AMF_DESERIALIZER *des, unsigned long len) {
+VALUE des_read_string(AMF_DESERIALIZER *des, unsigned int len) {
DES_BOUNDS_CHECK(des, len);
VALUE str = rb_str_new(des->stream + des->pos, len);
#ifdef HAVE_RB_STR_ENCODE
@@ -115,7 +115,7 @@ VALUE des_read_string(AMF_DESERIALIZER *des, unsigned long len) {
* C strings, this function does the lookup without requiring any additional
* allocations.
*/
-VALUE des_read_sym(AMF_DESERIALIZER *des, unsigned long len) {
+VALUE des_read_sym(AMF_DESERIALIZER *des, unsigned int len) {
DES_BOUNDS_CHECK(des, len);
char end = des->stream[des->pos+len];
des->stream[des->pos+len] = '\0';
@@ -167,7 +167,7 @@ static VALUE des0_read_amf3(VALUE self) {
* Reads an AMF0 hash, with a configurable key reading function - either
* des_read_string or des_read_sym
*/
-static void des0_read_props(VALUE self, VALUE hash, VALUE(*read_key)(AMF_DESERIALIZER*, unsigned long)) {
+static void des0_read_props(VALUE self, VALUE hash, VALUE(*read_key)(AMF_DESERIALIZER*, unsigned int)) {
AMF_DESERIALIZER *des;
Data_Get_Struct(self, AMF_DESERIALIZER, des);
@@ -234,11 +234,11 @@ static VALUE des0_read_array(VALUE self) {
// Limit size of pre-allocation to force remote user to actually send data,
// rather than just sending a size of 2**32-1 and nothing afterwards to
// crash the server
- unsigned long len = des_read_uint32(des);
+ unsigned int len = des_read_uint32(des);
VALUE ary = rb_ary_new2(len < MAX_ARRAY_PREALLOC ? len : MAX_ARRAY_PREALLOC);
rb_ary_push(des->obj_cache, ary);
- unsigned long i;
+ unsigned int i;
for(i = 0; i < len; i++) {
rb_ary_push(ary, des0_deserialize(self, des_read_byte(des)));
}
@@ -538,6 +538,56 @@ static VALUE des3_read_dict(VALUE self) {
}
}
+static VALUE des3_read_vec(VALUE self, char type) {
+ AMF_DESERIALIZER *des;
+ Data_Get_Struct(self, AMF_DESERIALIZER, des);
+
+ int header = des_read_int(des);
+ if((header & 1) == 0) {
+ header >>= 1;
+ if(header >= RARRAY_LEN(des->obj_cache)) rb_raise(rb_eRangeError, "obj reference index beyond end");
+ return RARRAY_PTR(des->obj_cache)[header];
+ } else {
+ header >>= 1;
+
+ // Limit size of pre-allocation to force remote user to actually send data,
+ // rather than just sending a size of 2**32-1 and nothing afterwards to
+ // crash the server
+ VALUE vec = rb_ary_new2(header < MAX_ARRAY_PREALLOC ? header : MAX_ARRAY_PREALLOC);
+ rb_ary_push(des->obj_cache, vec);
+
+ des_read_byte(des); // Fixed Length: Not supported in ruby
+
+ // On 32-bit ARCH, FIXNUM has a limit of 2**31-1, resulting in truncation of large ints/uints
+ int i;
+ switch(type) {
+ case AMF3_VECTOR_INT_MARKER:
+ for(i = 0; i < header; i++) {
+ int ival = des_read_uint32(des);
+ rb_ary_push(vec, INT2FIX(ival));
+ }
+ break;
+ case AMF3_VECTOR_UINT_MARKER:
+ for(i = 0; i < header; i++) {
+ rb_ary_push(vec, INT2FIX(des_read_uint32(des)));
+ }
+ break;
+ case AMF3_VECTOR_DOUBLE_MARKER:
+ for(i = 0; i < header; i++) {
+ rb_ary_push(vec, rb_float_new(des_read_double(des)));
+ }
+ break;
+ case AMF3_VECTOR_OBJECT_MARKER:
+ des3_read_string(des); // Class name of objects - ignored
+ for(i = 0; i < header; i++) {
+ rb_ary_push(vec, des3_deserialize(self));
+ }
+ break;
+ }
+ return vec;
+ }
+}
+
/*
* Internal deserialize call - unlike des0_deserialize, it reads the type
* itself, due to minor changes in the specs that make that modification
@@ -585,6 +635,12 @@ static VALUE des3_deserialize(VALUE self) {
case AMF3_BYTE_ARRAY_MARKER:
ret = des3_read_byte_array(self);
break;
+ case AMF3_VECTOR_INT_MARKER:
+ case AMF3_VECTOR_UINT_MARKER:
+ case AMF3_VECTOR_DOUBLE_MARKER:
+ case AMF3_VECTOR_OBJECT_MARKER:
+ ret = des3_read_vec(self, type);
+ break;
case AMF3_DICT_MARKER:
ret = des3_read_dict(self);
break;
@@ -17,11 +17,11 @@ typedef struct {
char des_read_byte(AMF_DESERIALIZER *des);
int des_read_uint16(AMF_DESERIALIZER *des);
-unsigned long des_read_uint32(AMF_DESERIALIZER *des);
+unsigned int des_read_uint32(AMF_DESERIALIZER *des);
double des_read_double(AMF_DESERIALIZER *des);
int des_read_int(AMF_DESERIALIZER *des);
-VALUE des_read_string(AMF_DESERIALIZER *des, unsigned long len);
-VALUE des_read_sym(AMF_DESERIALIZER *des, unsigned long len);
+VALUE des_read_string(AMF_DESERIALIZER *des, unsigned int len);
+VALUE des_read_sym(AMF_DESERIALIZER *des, unsigned int len);
void des_set_src(AMF_DESERIALIZER *des, VALUE src);
VALUE des_deserialize(VALUE self, VALUE ver, VALUE src);
@@ -197,6 +197,8 @@ def amf3_deserialize
amf3_read_object
when AMF3_BYTE_ARRAY_MARKER
amf3_read_byte_array
+ when AMF3_VECTOR_INT_MARKER, AMF3_VECTOR_UINT_MARKER, AMF3_VECTOR_DOUBLE_MARKER, AMF3_VECTOR_OBJECT_MARKER
+ amf3_read_vector type
when AMF3_DICT_MARKER
amf3_read_dict
else
@@ -411,6 +413,44 @@ def amf3_read_dict
dict
end
end
+
+ def amf3_read_vector vector_type
+ type = amf3_read_integer
+ is_reference = (type & 0x01) == 0
+ if is_reference
+ reference = type >> 1
+ return @object_cache[reference]
+ else
+ vec = []
+ @object_cache << vec
+ length = type >> 1
+ fixed_vector = read_int8 @source # Ignore
+ case vector_type
+ when AMF3_VECTOR_INT_MARKER
+ 0.upto(length - 1) do |i|
+ int = read_word32_network(@source)
+ int = int - 2**32 if int > MAX_INTEGER
+ vec << int
+ end
+ when AMF3_VECTOR_UINT_MARKER
+ 0.upto(length - 1) do |i|
+ vec << read_word32_network(@source)
+ puts vec[i].to_s(2)
+ end
+ when AMF3_VECTOR_DOUBLE_MARKER
+ 0.upto(length - 1) do |i|
+ vec << amf3_read_number
+ end
+ when AMF3_VECTOR_OBJECT_MARKER
+ vector_class = amf3_read_string # Ignore
+ puts vector_class
+ 0.upto(length - 1) do |i|
+ vec << amf3_deserialize
+ end
+ end
+ vec
+ end
+ end
end
end
end
View
@@ -322,6 +322,32 @@
str_key.should == "bar"
output[str_key].should == "asdf1"
end
+
+ it "should deserialize Vector.<int>" do
+ input = object_fixture('amf3-vector-int.bin')
+ output = RocketAMF.deserialize(input, 3)
+ output.should == [4, -20, 12]
+ end
+
+ it "should deserialize Vector.<uint>" do
+ input = object_fixture('amf3-vector-uint.bin')
+ output = RocketAMF.deserialize(input, 3)
+ output.should == [4, 20, 12]
+ end
+
+ it "should deserialize Vector.<Number>" do
+ input = object_fixture('amf3-vector-double.bin')
+ output = RocketAMF.deserialize(input, 3)
+ output.should == [4.3, -20.6]
+ end
+
+ it "should deserialize Vector.<Object>" do
+ input = object_fixture('amf3-vector-object.bin')
+ output = RocketAMF.deserialize(input, 3)
+ output[0][:foo].should == 'foo'
+ output[1].type.should == 'org.amf.ASClass'
+ output[2][:foo].should == 'baz'
+ end
end
describe "and implementing the AMF Spec" do
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View
@@ -195,7 +195,34 @@ package {
return parentObj;
},
'amf3-complex-encoded-string-array': [5, "Shift テスト", "UTF テスト", 5],
- 'amf3-encoded-string-ref': ["this is a テスト", "this is a テスト"]
+ 'amf3-encoded-string-ref': ["this is a テスト", "this is a テスト"],
+ 'amf3-vector-int': function():Vector.<int> {
+ var v:Vector.<int> = new Vector.<int>();
+ v.push(4);
+ v.push(-20);
+ v.push(12);
+ return v;
+ },
+ 'amf3-vector-uint': function():Vector.<uint> {
+ var v:Vector.<uint> = new Vector.<uint>();
+ v.push(4);
+ v.push(20);
+ v.push(12);
+ return v;
+ },
+ 'amf3-vector-double': function():Vector.<Number> {
+ var v:Vector.<Number> = new Vector.<Number>();
+ v.push(4.3);
+ v.push(-20.6);
+ return v;
+ },
+ 'amf3-vector-object': function():Vector.<ASClass> {
+ var v:Vector.<ASClass> = new Vector.<ASClass>();
+ v.push(new ASClass('foo'));
+ v.push(new ASClass('bar'));
+ v.push(new ASClass('baz'));
+ return v;
+ }
};
var outputDir:File = evt.target as File;
View
@@ -1,33 +1,13 @@
<?xml version ="1.0" encoding="utf-8" ?>
-<application xmlns="http://ns.adobe.com/air/application/1.5">
+<application xmlns="http://ns.adobe.com/air/application/3.1">
<id>com.rubyamf.Encoder</id>
- <version>1.0</version>
<filename>Encoder</filename>
- <description></description>
- <!-- To localize the description, use the following format for the description element.
- <description>
- <text xml:lang="en">English App description goes here</text>
- <text xml:lang="fr">French App description goes here</text>
- <text xml:lang="ja">Japanese App description goes here</text>
- </description>
- -->
<name>Encoder</name>
- <!-- To localize the name, use the following format for the name element.
- <name>
- <text xml:lang="en">English App name goes here</text>
- <text xml:lang="fr">French App name goes here</text>
- <text xml:lang="ja">Japanese App name goes here</text>
- </name>
- -->
- <copyright></copyright>
+ <versionNumber>1.0</versionNumber>
<initialWindow>
<content>Encoder.swf</content>
<systemChrome>standard</systemChrome>
<transparent>false</transparent>
<visible>true</visible>
</initialWindow>
- <customUpdateUI>false</customUpdateUI>
- <allowBrowserInvocation>false</allowBrowserInvocation>
- <icon>
- </icon>
</application>

0 comments on commit 8b217aa

Please sign in to comment.