/* * 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)) { AMF_DESERIALIZER *des; Data_Get_Struct(self, AMF_DESERIALIZER, des); while(1) { int len = des_read_uint16(des); if(len == 0) { des_read_byte(des); // Read type byte return; } else { VALUE key = read_key(des, len); char type = des_read_byte(des); rb_hash_aset(hash, key, des0_deserialize(self, type)); } } }
/* * call-seq: * des.deserialize(str) => obj * des.deserialize(StringIO) => obj * * Deserialize the string or StringIO from AMF to a ruby object. */ static VALUE des0_deserialize_rb(int argc, VALUE *argv, VALUE self) { AMF_DESERIALIZER *des; Data_Get_Struct(self, AMF_DESERIALIZER, des); VALUE ret = des0_deserialize(self, des_read_byte(des)); rb_funcall(des->src, rb_intern("pos="), 1, LONG2NUM(des->pos)); // Update source StringIO pos return ret; }
/* * Internal C deserialize call. Takes deserializer and a char for the type * marker. */ static VALUE des0_deserialize(VALUE self, char type) { AMF_DESERIALIZER *des; Data_Get_Struct(self, AMF_DESERIALIZER, des); long tmp; VALUE ret = Qnil; switch(type) { case AMF0_STRING_MARKER: ret = des_read_string(des, des_read_uint16(des)); break; case AMF0_AMF3_MARKER: ret = des0_read_amf3(self); break; case AMF0_NUMBER_MARKER: ret = rb_float_new(des_read_double(des)); break; case AMF0_BOOLEAN_MARKER: ret = des_read_byte(des) == 0 ? Qfalse : Qtrue; break; case AMF0_NULL_MARKER: case AMF0_UNDEFINED_MARKER: case AMF0_UNSUPPORTED_MARKER: ret = Qnil; break; case AMF0_OBJECT_MARKER: ret = des0_read_object(self); break; case AMF0_TYPED_OBJECT_MARKER: ret = des0_read_typed_object(self); break; case AMF0_HASH_MARKER: ret = des0_read_hash(self); break; case AMF0_STRICT_ARRAY_MARKER: ret = des0_read_array(self); break; case AMF0_REFERENCE_MARKER: tmp = des_read_uint16(des); if(tmp >= RARRAY_LEN(des->obj_cache)) rb_raise(rb_eRangeError, "reference index beyond end"); ret = RARRAY_PTR(des->obj_cache)[tmp]; break; case AMF0_DATE_MARKER: ret = des0_read_time(self); break; case AMF0_XML_MARKER: case AMF0_LONG_STRING_MARKER: ret = des_read_string(des, des_read_uint32(des)); break; default: rb_raise(rb_eRuntimeError, "Not supported: %d", type); break; } return ret; }
static VALUE des0_read_array(VALUE self) { AMF_DESERIALIZER *des; Data_Get_Struct(self, AMF_DESERIALIZER, des); // 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); VALUE ary = rb_ary_new2(len < MAX_ARRAY_PREALLOC ? len : MAX_ARRAY_PREALLOC); rb_ary_push(des->obj_cache, ary); long i; for(i = 0; i < len; i++) { rb_ary_push(ary, des0_deserialize(self, des_read_byte(des))); } return ary; }