Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Henry committed Feb 9, 2009
1 parent 445b3e1 commit aa1606d
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 59 deletions.
145 changes: 126 additions & 19 deletions lib/amf/pure/deserializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,23 @@ class Deserializer
def initialize()
@dynamic = false

@string_counter ||= 0
@string_cache ||= {}
@object_counter ||= 0
@object_cache ||= {}
@trait_counter ||= 0
@trait_cache ||= {}
@string_cache = {}
@object_cache = {}
@trait_cache = {}
end

def cache_string str
@string_cache[@string_counter] = str
@string_counter += 1
@string_cache[@string_cache.length] = str
end

def cache_object obj

@object_cache[@object_cache.length] = obj
end

def cache_trait tra

@trait_cache[@trait_cache.length] = tra
end

def deserialize_request()
#request = Request.new()
#request.read(source)
Expand All @@ -56,10 +53,8 @@ def deserialize_request()
end

def deserialize(source, type=nil)
if(type == nil)
source = BinData::IO.new(source)
type = read_int8 source
end
source = BinData::IO.new(source) unless source.instance_of?(BinData::IO)
type = read_int8 source unless type

case type
when UNDEFINED_MARKER
Expand All @@ -77,13 +72,13 @@ def deserialize(source, type=nil)
when STRING_MARKER
read_string source
when XML_DOC_MARKER
#read_amf3_xml_string
#read_xml_string
when DATE_MARKER
#read_amf3_date
when ARRAY_MARKER
#read_amf3_array
read_array source
when OBJECT_MARKER
#read_amf3_object
read_object source
when XML_MARKER
#read_amf3_xml
when BYTE_ARRAY_MARKER
Expand All @@ -96,7 +91,6 @@ def read_int8 source
end

#INTEGER_MARKER

def read_integer source
n = 0
b = read_word8(source) || 0
Expand Down Expand Up @@ -130,7 +124,6 @@ def read_word8 source
end

#DOUBLE_MARKER

def read_number source
res = read_double source
res.is_a?(Float)&&res.nan? ? nil : res # check for NaN and convert them to nil
Expand All @@ -140,6 +133,120 @@ def read_double source
source.readbytes(8).unpack('G').first
end

#STRING_MARKER
def read_string source
type = read_integer source
isReference = type & 0x01 == 0

if isReference
reference = type >> 1
return @string_cache[reference]
else
length = type >> 1
if length > 0
str = readn(source, length)
cache_string(str)
end
return str
end
end

def readn(source, length)
str = source.readbytes(length)
end

#XML_DOC_MARKER

#ARRAY_MARKER
def read_array source
type = read_integer source
isReference = (type & 0x01) == 0

if isReference
reference = type >> 1
return @object_cache[reference]
else
length = type >> 1
propertyName = read_string source
if propertyName != nil
array = {}
cache_object(array)
begin
while(propertyName.length)
value = deserialize(source)
array[propertyName] = value
propertyName = read_string source
end
rescue Exception => e #end of object exception, because propertyName.length will be non existent
end
0.upto(length - 1) do |i|
array["" + i.to_s] = deserialize(source)
end
else
array = []
cache_object(array)
0.upto(length - 1) do
array << deserialize(source)
end
end
array
end
end

#OBJECT_MARKER
def read_object source
type = read_integer source
isReference = (type & 0x01) == 0

if isReference
reference = type >> 1
return @object_cache[reference]
else

class_type = type >> 1
class_is_reference = (class_type & 0x01) == 0

if class_is_reference
class_reference = class_type >> 1
return @trait_cache[reference]
else
actionscript_class_name = read_string source
externalizable = (class_type & 0x02) != 0
dynamic = (class_type & 0x04) != 0
attribute_count = class_type >> 3

class_attributes = []
attribute_count.times{class_attributes << read_string(source)} # Read class members

class_definition = {"as_class_name" => actionscript_class_name, "members" => class_attributes, "externalizable" => externalizable, "dynamic" => dynamic}
cache_trait(class_definition)
end
action_class_name = class_definition['as_class_name'] #get the className according to type

obj = Hash.new()

cache_object(obj)

if class_definition['externalizable']
if ['flex.messaging.io.ObjectProxy','flex.messaging.io.ArrayCollection'].include?(action_class_name)
obj = deserialize(source)
end
else
class_definition['members'].each do |key|
value = deserialize(source)
obj[key] = value
end

if class_definition['dynamic']
while (key = read_string source) && key.length != 0 do # read next key
value = deserialize(source)
obj[key] = value
end
end
end
obj
end
end
end
end
end
18 changes: 6 additions & 12 deletions lib/amf/pure/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@ def initialize(opts = {})
@dynamic = false
# integer cache and float cache are used to avoid
# processing the numbers multiple times
@integer_cache ||= {}
@float_cache ||= {}
@integer_cache = {}
@float_cache = {}
# string and object cache are used as reference
# tables which are further discussed in the AMF specs
@string_counter ||= 0
@string_cache ||= {}
@object_counter ||= 0
@object_cache ||= {}
@string_cache = {}
@object_cache = {}
end
attr_accessor :dynamic,
:integer_cache,
:float_cache,
:string_counter,
:string_cache,
:object_counter,
:object_cache

# if string has been referenced, returns the index of the reference
Expand All @@ -35,8 +31,7 @@ def initialize(opts = {})
# and returns nil
def string_cache(str)
index = @string_cache.fetch(str) { |str|
@string_cache[str] = @string_counter
@string_counter += 1
@string_cache[str] = @string_cache.length
nil
}
header_for_cache(index) if index
Expand All @@ -48,8 +43,7 @@ def string_cache(str)
# and returns nil.
def object_cache(obj)
index = @object_cache.fetch(obj.amf_id) { |amf_id|
@object_cache[amf_id] = @object_counter
@object_counter += 1
@object_cache[amf_id] = @object_cache.length
nil
}
header_for_cache(index) if index
Expand Down
35 changes: 7 additions & 28 deletions spec/deserializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,28 +123,11 @@ def readBinary(binary_path)
describe "objects" do

it "should deserialize an unmapped object as a dynamic anonymous object" do
# A non-mapped object is any object not explicitly mapped with a AMF
# mapping. It should be encoded as a dynamic anonymous object with
# dynamic properties for all "messages" (public methods)
# that have an arity of 0 - meaning that they take no arguments
class NonMappedObject
attr_accessor :property_one
attr_accessor :property_two
attr_accessor :nil_property
attr_writer :read_only_prop

def another_public_property
'a_public_value'
end

def method_with_arg arg='foo'
arg
end
end
obj = NonMappedObject.new
obj.property_one = 'foo'
obj.property_two = 1
obj.nil_property = nil
obj = {:property_one => 'foo',
:property_two => 1,
:nil_property => nil,
:another_public_property => 'a_public_value'}

expected = obj
input = readBinary("dynObject.bin")
Expand Down Expand Up @@ -183,13 +166,9 @@ def method_with_arg arg='foo'
it "should deserialize an array of mixed objects" do
h1 = {:foo_one => "bar_one"}
h2 = {:foo_two => ""}
class SimpleObj
attr_accessor :foo_three
end
so1 = SimpleObj.new
so1.foo_three = 42
so1 = {:foo_three => 42}

expected = [h1, h2, so1, SimpleObj.new, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
expected = [h1, h2, so1, {:foo_three => nil}, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
input = readBinary("mixedArray.bin")
output = AMF.deserialize(input)
output.should == expected
Expand All @@ -208,7 +187,7 @@ class StringCarrier
foo = "foo"
bar = "str"
sc = StringCarrier.new
sc.str = foo
sc = {bar => foo}

expected = [foo, bar, foo, bar, foo, sc]
input = readBinary("stringRef.bin")
Expand Down

0 comments on commit aa1606d

Please sign in to comment.