scotttam-RocketAMF 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +45 -0
- data/Rakefile +54 -0
- data/lib/rocketamf.rb +128 -0
- data/lib/rocketamf/class_mapping.rb +231 -0
- data/lib/rocketamf/constants.rb +46 -0
- data/lib/rocketamf/pure.rb +28 -0
- data/lib/rocketamf/pure/deserializer.rb +419 -0
- data/lib/rocketamf/pure/io_helpers.rb +94 -0
- data/lib/rocketamf/pure/remoting.rb +134 -0
- data/lib/rocketamf/pure/serializer.rb +433 -0
- data/lib/rocketamf/remoting.rb +144 -0
- data/lib/rocketamf/values/array_collection.rb +13 -0
- data/lib/rocketamf/values/messages.rb +133 -0
- data/lib/rocketamf/values/typed_hash.rb +13 -0
- data/spec/amf/class_mapping_spec.rb +150 -0
- data/spec/amf/deserializer_spec.rb +367 -0
- data/spec/amf/remoting_spec.rb +132 -0
- data/spec/amf/serializer_spec.rb +384 -0
- data/spec/amf/values/array_collection_spec.rb +19 -0
- data/spec/amf/values/messages_spec.rb +31 -0
- data/spec/fixtures/objects/amf0-boolean.bin +1 -0
- data/spec/fixtures/objects/amf0-complexEncodedStringArray.bin +0 -0
- data/spec/fixtures/objects/amf0-date.bin +0 -0
- data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
- data/spec/fixtures/objects/amf0-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-null.bin +1 -0
- data/spec/fixtures/objects/amf0-number.bin +0 -0
- data/spec/fixtures/objects/amf0-object.bin +0 -0
- data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
- data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
- data/spec/fixtures/objects/amf0-string.bin +0 -0
- data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
- data/spec/fixtures/objects/amf0-undefined.bin +1 -0
- data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
- data/spec/fixtures/objects/amf0-xmlDoc.bin +0 -0
- data/spec/fixtures/objects/amf3-0.bin +0 -0
- data/spec/fixtures/objects/amf3-arrayCollection.bin +2 -0
- data/spec/fixtures/objects/amf3-arrayRef.bin +1 -0
- data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
- data/spec/fixtures/objects/amf3-byteArray.bin +0 -0
- data/spec/fixtures/objects/amf3-byteArrayRef.bin +1 -0
- data/spec/fixtures/objects/amf3-complexEncodedStringArray.bin +1 -0
- data/spec/fixtures/objects/amf3-date.bin +0 -0
- data/spec/fixtures/objects/amf3-datesRef.bin +0 -0
- data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-dynObject.bin +2 -0
- data/spec/fixtures/objects/amf3-emptyArray.bin +1 -0
- data/spec/fixtures/objects/amf3-emptyArrayRef.bin +1 -0
- data/spec/fixtures/objects/amf3-emptyDictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-emptyStringRef.bin +1 -0
- data/spec/fixtures/objects/amf3-encodedStringRef.bin +0 -0
- data/spec/fixtures/objects/amf3-false.bin +1 -0
- data/spec/fixtures/objects/amf3-float.bin +0 -0
- data/spec/fixtures/objects/amf3-graphMember.bin +0 -0
- data/spec/fixtures/objects/amf3-hash.bin +2 -0
- data/spec/fixtures/objects/amf3-largeMax.bin +0 -0
- data/spec/fixtures/objects/amf3-largeMin.bin +0 -0
- data/spec/fixtures/objects/amf3-max.bin +1 -0
- data/spec/fixtures/objects/amf3-min.bin +0 -0
- data/spec/fixtures/objects/amf3-mixedArray.bin +11 -0
- data/spec/fixtures/objects/amf3-null.bin +1 -0
- data/spec/fixtures/objects/amf3-objRef.bin +0 -0
- data/spec/fixtures/objects/amf3-primArray.bin +1 -0
- data/spec/fixtures/objects/amf3-string.bin +1 -0
- data/spec/fixtures/objects/amf3-stringRef.bin +0 -0
- data/spec/fixtures/objects/amf3-symbol.bin +1 -0
- data/spec/fixtures/objects/amf3-traitRef.bin +3 -0
- data/spec/fixtures/objects/amf3-true.bin +1 -0
- data/spec/fixtures/objects/amf3-typedObject.bin +2 -0
- data/spec/fixtures/objects/amf3-xml.bin +1 -0
- data/spec/fixtures/objects/amf3-xmlDoc.bin +1 -0
- data/spec/fixtures/objects/amf3-xmlRef.bin +1 -0
- data/spec/fixtures/request/acknowledge-response.bin +0 -0
- data/spec/fixtures/request/amf0-error-response.bin +0 -0
- data/spec/fixtures/request/commandMessage.bin +0 -0
- data/spec/fixtures/request/remotingMessage.bin +0 -0
- data/spec/fixtures/request/simple-response.bin +0 -0
- data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +31 -0
- metadata +153 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module RocketAMF
|
2
|
+
# AMF0 Type Markers
|
3
|
+
AMF0_NUMBER_MARKER = 0x00 #"\000"
|
4
|
+
AMF0_BOOLEAN_MARKER = 0x01 #"\001"
|
5
|
+
AMF0_STRING_MARKER = 0x02 #"\002"
|
6
|
+
AMF0_OBJECT_MARKER = 0x03 #"\003"
|
7
|
+
AMF0_MOVIE_CLIP_MARKER = 0x04 #"\004" # Unused
|
8
|
+
AMF0_NULL_MARKER = 0x05 #"\005"
|
9
|
+
AMF0_UNDEFINED_MARKER = 0x06 #"\006"
|
10
|
+
AMF0_REFERENCE_MARKER = 0x07 #"\a"
|
11
|
+
AMF0_HASH_MARKER = 0x08 #"\b"
|
12
|
+
AMF0_OBJECT_END_MARKER = 0x09 #"\t"
|
13
|
+
AMF0_STRICT_ARRAY_MARKER = 0x0A #"\n"
|
14
|
+
AMF0_DATE_MARKER = 0x0B #"\v"
|
15
|
+
AMF0_LONG_STRING_MARKER = 0x0C #"\f"
|
16
|
+
AMF0_UNSUPPORTED_MARKER = 0x0D #"\r"
|
17
|
+
AMF0_RECORDSET_MARKER = 0x0E #"\016" # Unused
|
18
|
+
AMF0_XML_MARKER = 0x0F #"\017"
|
19
|
+
AMF0_TYPED_OBJECT_MARKER = 0x10 #"\020"
|
20
|
+
AMF0_AMF3_MARKER = 0x11 #"\021"
|
21
|
+
|
22
|
+
# AMF3 Type Markers
|
23
|
+
AMF3_UNDEFINED_MARKER = 0x00 #"\000"
|
24
|
+
AMF3_NULL_MARKER = 0x01 #"\001"
|
25
|
+
AMF3_FALSE_MARKER = 0x02 #"\002"
|
26
|
+
AMF3_TRUE_MARKER = 0x03 #"\003"
|
27
|
+
AMF3_INTEGER_MARKER = 0x04 #"\004"
|
28
|
+
AMF3_DOUBLE_MARKER = 0x05 #"\005"
|
29
|
+
AMF3_STRING_MARKER = 0x06 #"\006"
|
30
|
+
AMF3_XML_DOC_MARKER = 0x07 #"\a"
|
31
|
+
AMF3_DATE_MARKER = 0x08 #"\b"
|
32
|
+
AMF3_ARRAY_MARKER = 0x09 #"\t"
|
33
|
+
AMF3_OBJECT_MARKER = 0x0A #"\n"
|
34
|
+
AMF3_XML_MARKER = 0x0B #"\v"
|
35
|
+
AMF3_BYTE_ARRAY_MARKER = 0x0C #"\f"
|
36
|
+
AMF3_DICT_MARKER = 0x11 #"\021"
|
37
|
+
|
38
|
+
# Other AMF3 Markers
|
39
|
+
AMF3_EMPTY_STRING = 0x01
|
40
|
+
AMF3_CLOSE_DYNAMIC_OBJECT = 0x01
|
41
|
+
AMF3_CLOSE_DYNAMIC_ARRAY = 0x01
|
42
|
+
|
43
|
+
# Other Constants
|
44
|
+
MAX_INTEGER = 268435455
|
45
|
+
MIN_INTEGER = -268435456
|
46
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rocketamf/pure/deserializer'
|
2
|
+
require 'rocketamf/pure/serializer'
|
3
|
+
require 'rocketamf/pure/remoting'
|
4
|
+
|
5
|
+
module RocketAMF
|
6
|
+
# This module holds all the modules/classes that implement AMF's functionality
|
7
|
+
# in pure ruby
|
8
|
+
module Pure
|
9
|
+
$DEBUG and warn "Using pure library for RocketAMF."
|
10
|
+
end
|
11
|
+
|
12
|
+
#:stopdoc:
|
13
|
+
# Import deserializer
|
14
|
+
Deserializer = RocketAMF::Pure::Deserializer
|
15
|
+
AMF3Deserializer = RocketAMF::Pure::AMF3Deserializer
|
16
|
+
|
17
|
+
# Import serializer
|
18
|
+
Serializer = RocketAMF::Pure::Serializer
|
19
|
+
AMF3Serializer = RocketAMF::Pure::AMF3Serializer
|
20
|
+
|
21
|
+
# Modify envelope so it can serialize/deserialize
|
22
|
+
class Envelope
|
23
|
+
remove_method :populate_from_stream
|
24
|
+
remove_method :serialize
|
25
|
+
include RocketAMF::Pure::Envelope
|
26
|
+
end
|
27
|
+
#:startdoc:
|
28
|
+
end
|
@@ -0,0 +1,419 @@
|
|
1
|
+
require 'rocketamf/pure/io_helpers'
|
2
|
+
|
3
|
+
module RocketAMF
|
4
|
+
module Pure
|
5
|
+
# Pure ruby deserializer
|
6
|
+
#--
|
7
|
+
# AMF0 deserializer, it switches over to AMF3 when it sees the switch flag
|
8
|
+
class Deserializer
|
9
|
+
def initialize
|
10
|
+
@ref_cache = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def deserialize(source, type=nil)
|
14
|
+
source = StringIO.new(source) unless StringIO === source
|
15
|
+
type = read_int8 source unless type
|
16
|
+
case type
|
17
|
+
when AMF0_NUMBER_MARKER
|
18
|
+
read_number source
|
19
|
+
when AMF0_BOOLEAN_MARKER
|
20
|
+
read_boolean source
|
21
|
+
when AMF0_STRING_MARKER
|
22
|
+
read_string source
|
23
|
+
when AMF0_OBJECT_MARKER
|
24
|
+
read_object source
|
25
|
+
when AMF0_NULL_MARKER
|
26
|
+
nil
|
27
|
+
when AMF0_UNDEFINED_MARKER
|
28
|
+
nil
|
29
|
+
when AMF0_REFERENCE_MARKER
|
30
|
+
read_reference source
|
31
|
+
when AMF0_HASH_MARKER
|
32
|
+
read_hash source
|
33
|
+
when AMF0_STRICT_ARRAY_MARKER
|
34
|
+
read_array source
|
35
|
+
when AMF0_DATE_MARKER
|
36
|
+
read_date source
|
37
|
+
when AMF0_LONG_STRING_MARKER
|
38
|
+
read_string source, true
|
39
|
+
when AMF0_UNSUPPORTED_MARKER
|
40
|
+
nil
|
41
|
+
when AMF0_XML_MARKER
|
42
|
+
read_string source, true
|
43
|
+
when AMF0_TYPED_OBJECT_MARKER
|
44
|
+
read_typed_object source
|
45
|
+
when AMF0_AMF3_MARKER
|
46
|
+
AMF3Deserializer.new.deserialize(source)
|
47
|
+
else
|
48
|
+
raise AMFError, "Invalid type: #{type}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
include RocketAMF::Pure::ReadIOHelpers
|
54
|
+
|
55
|
+
def read_number source
|
56
|
+
res = read_double source
|
57
|
+
res.is_a?(Float)&&res.nan? ? nil : res # check for NaN and convert them to nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def read_boolean source
|
61
|
+
read_int8(source) != 0
|
62
|
+
end
|
63
|
+
|
64
|
+
def read_string source, long=false
|
65
|
+
len = long ? read_word32_network(source) : read_word16_network(source)
|
66
|
+
str = source.read(len)
|
67
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
68
|
+
str
|
69
|
+
end
|
70
|
+
|
71
|
+
def read_object source, add_to_ref_cache=true
|
72
|
+
obj = {}
|
73
|
+
@ref_cache << obj if add_to_ref_cache
|
74
|
+
while true
|
75
|
+
key = read_string source
|
76
|
+
type = read_int8 source
|
77
|
+
break if type == AMF0_OBJECT_END_MARKER
|
78
|
+
obj[key.to_sym] = deserialize(source, type)
|
79
|
+
end
|
80
|
+
obj
|
81
|
+
end
|
82
|
+
|
83
|
+
def read_reference source
|
84
|
+
index = read_word16_network(source)
|
85
|
+
@ref_cache[index]
|
86
|
+
end
|
87
|
+
|
88
|
+
def read_hash source
|
89
|
+
len = read_word32_network(source) # Read and ignore length
|
90
|
+
|
91
|
+
# Read first pair
|
92
|
+
key = read_string source
|
93
|
+
type = read_int8 source
|
94
|
+
return [] if type == AMF0_OBJECT_END_MARKER
|
95
|
+
|
96
|
+
# We need to figure out whether this is a real hash, or whether some stupid serializer gave up
|
97
|
+
if key.to_i.to_s == key
|
98
|
+
# Array
|
99
|
+
obj = []
|
100
|
+
@ref_cache << obj
|
101
|
+
|
102
|
+
obj[key.to_i] = deserialize(source, type)
|
103
|
+
while true
|
104
|
+
key = read_string source
|
105
|
+
type = read_int8 source
|
106
|
+
break if type == AMF0_OBJECT_END_MARKER
|
107
|
+
obj[key.to_i] = deserialize(source, type)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
# Hash
|
111
|
+
obj = {}
|
112
|
+
@ref_cache << obj
|
113
|
+
|
114
|
+
obj[key.to_sym] = deserialize(source, type)
|
115
|
+
while true
|
116
|
+
key = read_string source
|
117
|
+
type = read_int8 source
|
118
|
+
break if type == AMF0_OBJECT_END_MARKER
|
119
|
+
obj[key.to_sym] = deserialize(source, type)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
obj
|
123
|
+
end
|
124
|
+
|
125
|
+
def read_array source
|
126
|
+
len = read_word32_network(source)
|
127
|
+
array = []
|
128
|
+
@ref_cache << array
|
129
|
+
|
130
|
+
0.upto(len - 1) do
|
131
|
+
array << deserialize(source)
|
132
|
+
end
|
133
|
+
array
|
134
|
+
end
|
135
|
+
|
136
|
+
def read_date source
|
137
|
+
seconds = read_double(source).to_f/1000
|
138
|
+
time = Time.at(seconds)
|
139
|
+
tz = read_word16_network(source) # Unused
|
140
|
+
time
|
141
|
+
end
|
142
|
+
|
143
|
+
def read_typed_object source
|
144
|
+
# Create object to add to ref cache
|
145
|
+
class_name = read_string source
|
146
|
+
obj = RocketAMF::ClassMapper.get_ruby_obj class_name
|
147
|
+
@ref_cache << obj
|
148
|
+
|
149
|
+
# Read object props
|
150
|
+
props = read_object source, false
|
151
|
+
|
152
|
+
# Populate object
|
153
|
+
RocketAMF::ClassMapper.populate_ruby_obj obj, props, {}
|
154
|
+
return obj
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# AMF3 implementation of deserializer, loaded automatically by the AMF0
|
159
|
+
# deserializer when needed
|
160
|
+
class AMF3Deserializer
|
161
|
+
def initialize
|
162
|
+
@string_cache = []
|
163
|
+
@object_cache = []
|
164
|
+
@trait_cache = []
|
165
|
+
end
|
166
|
+
|
167
|
+
def deserialize(source, type=nil)
|
168
|
+
source = StringIO.new(source) unless StringIO === source
|
169
|
+
type = read_int8 source unless type
|
170
|
+
case type
|
171
|
+
when AMF3_UNDEFINED_MARKER
|
172
|
+
nil
|
173
|
+
when AMF3_NULL_MARKER
|
174
|
+
nil
|
175
|
+
when AMF3_FALSE_MARKER
|
176
|
+
false
|
177
|
+
when AMF3_TRUE_MARKER
|
178
|
+
true
|
179
|
+
when AMF3_INTEGER_MARKER
|
180
|
+
read_integer source
|
181
|
+
when AMF3_DOUBLE_MARKER
|
182
|
+
read_number source
|
183
|
+
when AMF3_STRING_MARKER
|
184
|
+
read_string source
|
185
|
+
when AMF3_XML_DOC_MARKER, AMF3_XML_MARKER
|
186
|
+
read_xml source
|
187
|
+
when AMF3_DATE_MARKER
|
188
|
+
read_date source
|
189
|
+
when AMF3_ARRAY_MARKER
|
190
|
+
read_array source
|
191
|
+
when AMF3_OBJECT_MARKER
|
192
|
+
read_object source
|
193
|
+
when AMF3_BYTE_ARRAY_MARKER
|
194
|
+
read_amf3_byte_array source
|
195
|
+
when AMF3_DICT_MARKER
|
196
|
+
read_dict source
|
197
|
+
else
|
198
|
+
raise AMFError, "Invalid type: #{type}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
include RocketAMF::Pure::ReadIOHelpers
|
204
|
+
|
205
|
+
def read_integer source
|
206
|
+
n = 0
|
207
|
+
b = read_word8(source) || 0
|
208
|
+
result = 0
|
209
|
+
|
210
|
+
while ((b & 0x80) != 0 && n < 3)
|
211
|
+
result = result << 7
|
212
|
+
result = result | (b & 0x7f)
|
213
|
+
b = read_word8(source) || 0
|
214
|
+
n = n + 1
|
215
|
+
end
|
216
|
+
|
217
|
+
if (n < 3)
|
218
|
+
result = result << 7
|
219
|
+
result = result | b
|
220
|
+
else
|
221
|
+
#Use all 8 bits from the 4th byte
|
222
|
+
result = result << 8
|
223
|
+
result = result | b
|
224
|
+
|
225
|
+
#Check if the integer should be negative
|
226
|
+
if (result > MAX_INTEGER)
|
227
|
+
result -= (1 << 29)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
result
|
231
|
+
end
|
232
|
+
|
233
|
+
def read_number source
|
234
|
+
res = read_double source
|
235
|
+
res.is_a?(Float)&&res.nan? ? nil : res # check for NaN and convert them to nil
|
236
|
+
end
|
237
|
+
|
238
|
+
def read_string source
|
239
|
+
type = read_integer source
|
240
|
+
isReference = (type & 0x01) == 0
|
241
|
+
|
242
|
+
if isReference
|
243
|
+
reference = type >> 1
|
244
|
+
return @string_cache[reference]
|
245
|
+
else
|
246
|
+
length = type >> 1
|
247
|
+
str = ""
|
248
|
+
if length > 0
|
249
|
+
str = source.read(length)
|
250
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
251
|
+
@string_cache << str
|
252
|
+
end
|
253
|
+
return str
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def read_xml source
|
258
|
+
type = read_integer source
|
259
|
+
isReference = (type & 0x01) == 0
|
260
|
+
|
261
|
+
if isReference
|
262
|
+
reference = type >> 1
|
263
|
+
return @object_cache[reference]
|
264
|
+
else
|
265
|
+
length = type >> 1
|
266
|
+
str = ""
|
267
|
+
if length > 0
|
268
|
+
str = source.read(length)
|
269
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
270
|
+
@object_cache << str
|
271
|
+
end
|
272
|
+
return str
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def read_amf3_byte_array source
|
277
|
+
type = read_integer source
|
278
|
+
isReference = (type & 0x01) == 0
|
279
|
+
|
280
|
+
if isReference
|
281
|
+
reference = type >> 1
|
282
|
+
return @object_cache[reference]
|
283
|
+
else
|
284
|
+
length = type >> 1
|
285
|
+
obj = StringIO.new source.read(length)
|
286
|
+
@object_cache << obj
|
287
|
+
obj
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def read_array source
|
292
|
+
type = read_integer source
|
293
|
+
isReference = (type & 0x01) == 0
|
294
|
+
|
295
|
+
if isReference
|
296
|
+
reference = type >> 1
|
297
|
+
return @object_cache[reference]
|
298
|
+
else
|
299
|
+
length = type >> 1
|
300
|
+
propertyName = read_string source
|
301
|
+
if propertyName != ""
|
302
|
+
array = {}
|
303
|
+
@object_cache << array
|
304
|
+
begin
|
305
|
+
while(propertyName.length)
|
306
|
+
value = deserialize(source)
|
307
|
+
array[propertyName] = value
|
308
|
+
propertyName = read_string source
|
309
|
+
end
|
310
|
+
rescue Exception => e #end of object exception, because propertyName.length will be non existent
|
311
|
+
end
|
312
|
+
0.upto(length - 1) do |i|
|
313
|
+
array["" + i.to_s] = deserialize(source)
|
314
|
+
end
|
315
|
+
else
|
316
|
+
array = []
|
317
|
+
@object_cache << array
|
318
|
+
0.upto(length - 1) do
|
319
|
+
array << deserialize(source)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
array
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def read_object source
|
327
|
+
type = read_integer source
|
328
|
+
isReference = (type & 0x01) == 0
|
329
|
+
|
330
|
+
if isReference
|
331
|
+
reference = type >> 1
|
332
|
+
return @object_cache[reference]
|
333
|
+
else
|
334
|
+
class_type = type >> 1
|
335
|
+
class_is_reference = (class_type & 0x01) == 0
|
336
|
+
|
337
|
+
if class_is_reference
|
338
|
+
reference = class_type >> 1
|
339
|
+
traits = @trait_cache[reference]
|
340
|
+
else
|
341
|
+
externalizable = (class_type & 0x02) != 0
|
342
|
+
dynamic = (class_type & 0x04) != 0
|
343
|
+
attribute_count = class_type >> 3
|
344
|
+
class_name = read_string source
|
345
|
+
|
346
|
+
class_attributes = []
|
347
|
+
attribute_count.times{class_attributes << read_string(source)} # Read class members
|
348
|
+
|
349
|
+
traits = {
|
350
|
+
:class_name => class_name,
|
351
|
+
:members => class_attributes,
|
352
|
+
:externalizable => externalizable,
|
353
|
+
:dynamic => dynamic
|
354
|
+
}
|
355
|
+
@trait_cache << traits
|
356
|
+
end
|
357
|
+
|
358
|
+
obj = RocketAMF::ClassMapper.get_ruby_obj traits[:class_name]
|
359
|
+
@object_cache << obj
|
360
|
+
|
361
|
+
if traits[:externalizable]
|
362
|
+
obj.externalized_data = deserialize(source)
|
363
|
+
else
|
364
|
+
props = {}
|
365
|
+
traits[:members].each do |key|
|
366
|
+
value = deserialize(source)
|
367
|
+
props[key.to_sym] = value
|
368
|
+
end
|
369
|
+
|
370
|
+
dynamic_props = nil
|
371
|
+
if traits[:dynamic]
|
372
|
+
dynamic_props = {}
|
373
|
+
while (key = read_string source) && key.length != 0 do # read next key
|
374
|
+
value = deserialize(source)
|
375
|
+
dynamic_props[key.to_sym] = value
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
RocketAMF::ClassMapper.populate_ruby_obj obj, props, dynamic_props
|
380
|
+
end
|
381
|
+
obj
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
def read_date source
|
386
|
+
type = read_integer source
|
387
|
+
isReference = (type & 0x01) == 0
|
388
|
+
if isReference
|
389
|
+
reference = type >> 1
|
390
|
+
return @object_cache[reference]
|
391
|
+
else
|
392
|
+
seconds = read_double(source).to_f/1000
|
393
|
+
time = Time.at(seconds)
|
394
|
+
@object_cache << time
|
395
|
+
time
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def read_dict source
|
400
|
+
type = read_integer source
|
401
|
+
# Currently duplicate dictionaries send false, but I'll leave this in here just in case
|
402
|
+
isReference = (type & 0x01) == 0
|
403
|
+
if isReference
|
404
|
+
reference = type >> 1
|
405
|
+
return @object_cache[reference]
|
406
|
+
else
|
407
|
+
dict = {}
|
408
|
+
@object_cache << dict
|
409
|
+
length = type >> 1
|
410
|
+
skip = read_integer source # TODO: Handle when specs are updated
|
411
|
+
0.upto(length - 1) do |i|
|
412
|
+
dict[deserialize(source)] = deserialize(source)
|
413
|
+
end
|
414
|
+
dict
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|