ruby_sol 0.1
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.
- checksums.yaml +7 -0
- data/README.rdoc +90 -0
- data/Rakefile +43 -0
- data/lib/ruby_sol.rb +113 -0
- data/lib/ruby_sol/class_mapping.rb +250 -0
- data/lib/ruby_sol/constants.rb +50 -0
- data/lib/ruby_sol/extensions.rb +22 -0
- data/lib/ruby_sol/pure/deserializer.rb +461 -0
- data/lib/ruby_sol/pure/io_helpers.rb +94 -0
- data/lib/ruby_sol/pure/serializer.rb +490 -0
- data/spec/class_mapping_spec.rb +110 -0
- data/spec/deserializer_spec.rb +449 -0
- data/spec/fixtures/objects/amf0-boolean.bin +1 -0
- data/spec/fixtures/objects/amf0-complex-encoded-string.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-time.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-xml-doc.bin +0 -0
- data/spec/fixtures/objects/amf3-0.bin +0 -0
- data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
- data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
- data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
- data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
- data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
- data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
- data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-date.bin +0 -0
- data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
- data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
- data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-externalizable.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-graph-member.bin +0 -0
- data/spec/fixtures/objects/amf3-hash.bin +2 -0
- data/spec/fixtures/objects/amf3-large-max.bin +0 -0
- data/spec/fixtures/objects/amf3-large-min.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-mixed-array.bin +10 -0
- data/spec/fixtures/objects/amf3-null.bin +1 -0
- data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
- data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-string.bin +1 -0
- data/spec/fixtures/objects/amf3-symbol.bin +1 -0
- data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
- data/spec/fixtures/objects/amf3-true.bin +1 -0
- data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
- data/spec/fixtures/objects/amf3-vector-double.bin +0 -0
- data/spec/fixtures/objects/amf3-vector-int.bin +0 -0
- data/spec/fixtures/objects/amf3-vector-object.bin +0 -0
- data/spec/fixtures/objects/amf3-vector-uint.bin +0 -0
- data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
- data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-xml.bin +1 -0
- data/spec/serializer_spec.rb +503 -0
- data/spec/spec_helper.rb +59 -0
- metadata +128 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module RubySol
|
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_VECTOR_INT_MARKER = 0x0D #"\r"
|
37
|
+
AMF3_VECTOR_UINT_MARKER = 0x0E #"\016"
|
38
|
+
AMF3_VECTOR_DOUBLE_MARKER = 0x0F #"\017"
|
39
|
+
AMF3_VECTOR_OBJECT_MARKER = 0x10 #"\020"
|
40
|
+
AMF3_DICT_MARKER = 0x11 #"\021"
|
41
|
+
|
42
|
+
# Other AMF3 Markers
|
43
|
+
AMF3_EMPTY_STRING = 0x01
|
44
|
+
AMF3_CLOSE_DYNAMIC_OBJECT = 0x01
|
45
|
+
AMF3_CLOSE_DYNAMIC_ARRAY = 0x01
|
46
|
+
|
47
|
+
# Other Constants
|
48
|
+
MAX_INTEGER = 268435455
|
49
|
+
MIN_INTEGER = -268435456
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Joc's monkeypatch for string bytesize (only available in 1.8.7+)
|
2
|
+
if !"amf".respond_to? :bytesize
|
3
|
+
class String #:nodoc:
|
4
|
+
def bytesize
|
5
|
+
self.size
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Add <tt>ArrayCollection</tt> override to arrays
|
11
|
+
class Array
|
12
|
+
# Override <tt>RubySol::ClassMapper.use_array_collection</tt> setting for
|
13
|
+
# this array. Adds <tt>is_array_collection?</tt> method, which is used by the
|
14
|
+
# serializer over the global config if defined.
|
15
|
+
def is_array_collection= a
|
16
|
+
@is_array_collection = a
|
17
|
+
|
18
|
+
def self.is_array_collection? #:nodoc:
|
19
|
+
@is_array_collection
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,461 @@
|
|
1
|
+
require 'ruby_sol/pure/io_helpers'
|
2
|
+
|
3
|
+
module RubySol
|
4
|
+
module Pure
|
5
|
+
# Pure ruby deserializer for AMF0 and AMF3
|
6
|
+
class Deserializer
|
7
|
+
attr_accessor :source
|
8
|
+
|
9
|
+
# Pass in the class mapper instance to use when deserializing. This
|
10
|
+
# enables better caching behavior in the class mapper and allows
|
11
|
+
# one to change mappings between deserialization attempts.
|
12
|
+
def initialize class_mapper
|
13
|
+
@class_mapper = class_mapper
|
14
|
+
reset_caches()
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset_caches
|
18
|
+
@ref_cache = []
|
19
|
+
@string_cache = []
|
20
|
+
@object_cache = []
|
21
|
+
@trait_cache = []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Deserialize the source using AMF0 or AMF3. Source should either
|
25
|
+
# be a string or StringIO object. If you pass a StringIO object,
|
26
|
+
# it will have its position updated to the end of the deserialized
|
27
|
+
# data.
|
28
|
+
def deserialize version, source
|
29
|
+
raise ArgumentError, "unsupported version #{version}" unless [0,3].include?(version)
|
30
|
+
@version = version
|
31
|
+
|
32
|
+
if StringIO === source
|
33
|
+
@source = source
|
34
|
+
elsif source
|
35
|
+
@source = StringIO.new(source)
|
36
|
+
elsif @source.nil?
|
37
|
+
raise AMFError, "no source to deserialize"
|
38
|
+
end
|
39
|
+
|
40
|
+
reset_caches()
|
41
|
+
|
42
|
+
if @version == 0
|
43
|
+
return amf0_deserialize
|
44
|
+
else
|
45
|
+
return amf3_deserialize
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Reads an object from the deserializer's stream and returns it.
|
50
|
+
def read_object
|
51
|
+
if @version == 0
|
52
|
+
return amf0_deserialize
|
53
|
+
else
|
54
|
+
return amf3_deserialize
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# private
|
59
|
+
include RubySol::Pure::ReadIOHelpers
|
60
|
+
|
61
|
+
def amf0_deserialize type=nil
|
62
|
+
type = read_int8 @source unless type
|
63
|
+
case type
|
64
|
+
when AMF0_NUMBER_MARKER
|
65
|
+
amf0_read_number
|
66
|
+
when AMF0_BOOLEAN_MARKER
|
67
|
+
amf0_read_boolean
|
68
|
+
when AMF0_STRING_MARKER
|
69
|
+
amf0_read_string
|
70
|
+
when AMF0_OBJECT_MARKER
|
71
|
+
amf0_read_object
|
72
|
+
when AMF0_NULL_MARKER
|
73
|
+
nil
|
74
|
+
when AMF0_UNDEFINED_MARKER
|
75
|
+
nil
|
76
|
+
when AMF0_REFERENCE_MARKER
|
77
|
+
amf0_read_reference
|
78
|
+
when AMF0_HASH_MARKER
|
79
|
+
amf0_read_hash
|
80
|
+
when AMF0_STRICT_ARRAY_MARKER
|
81
|
+
amf0_read_array
|
82
|
+
when AMF0_DATE_MARKER
|
83
|
+
amf0_read_date
|
84
|
+
when AMF0_LONG_STRING_MARKER
|
85
|
+
amf0_read_string true
|
86
|
+
when AMF0_UNSUPPORTED_MARKER
|
87
|
+
nil
|
88
|
+
when AMF0_XML_MARKER
|
89
|
+
amf0_read_string true
|
90
|
+
when AMF0_TYPED_OBJECT_MARKER
|
91
|
+
amf0_read_typed_object
|
92
|
+
when AMF0_AMF3_MARKER
|
93
|
+
deserialize(3, nil)
|
94
|
+
else
|
95
|
+
raise AMFError, "Invalid type: #{type}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def amf0_read_number
|
100
|
+
res = read_double @source
|
101
|
+
(res.is_a?(Float) && res.nan?) ? nil : res # check for NaN and convert them to nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def amf0_read_boolean
|
105
|
+
read_int8(@source) != 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def amf0_read_string long=false
|
109
|
+
len = long ? read_word32_network(@source) : read_word16_network(@source)
|
110
|
+
str = @source.read(len)
|
111
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
112
|
+
str
|
113
|
+
end
|
114
|
+
|
115
|
+
def amf0_read_reference
|
116
|
+
index = read_word16_network(@source)
|
117
|
+
@ref_cache[index]
|
118
|
+
end
|
119
|
+
|
120
|
+
def amf0_read_array
|
121
|
+
len = read_word32_network(@source)
|
122
|
+
array = []
|
123
|
+
@ref_cache << array
|
124
|
+
|
125
|
+
0.upto(len - 1) do
|
126
|
+
array << amf0_deserialize
|
127
|
+
end
|
128
|
+
array
|
129
|
+
end
|
130
|
+
|
131
|
+
def amf0_read_date
|
132
|
+
seconds = read_double(@source).to_f/1000
|
133
|
+
time = Time.at(seconds)
|
134
|
+
tz = read_word16_network(@source) # Unused
|
135
|
+
time
|
136
|
+
end
|
137
|
+
|
138
|
+
def amf0_read_props obj={}
|
139
|
+
while true
|
140
|
+
key = amf0_read_string
|
141
|
+
type = read_int8 @source
|
142
|
+
break if type == AMF0_OBJECT_END_MARKER
|
143
|
+
obj[key] = amf0_deserialize(type)
|
144
|
+
end
|
145
|
+
obj
|
146
|
+
end
|
147
|
+
|
148
|
+
def amf0_read_hash
|
149
|
+
len = read_word32_network(@source) # Read and ignore length
|
150
|
+
obj = {}
|
151
|
+
@ref_cache << obj
|
152
|
+
amf0_read_props obj
|
153
|
+
end
|
154
|
+
|
155
|
+
def amf0_read_object add_to_ref_cache=true
|
156
|
+
# Create "object" and add to ref cache (it's always a Hash)
|
157
|
+
obj = @class_mapper.get_ruby_obj ""
|
158
|
+
@ref_cache << obj
|
159
|
+
|
160
|
+
# Populate object
|
161
|
+
props = amf0_read_props
|
162
|
+
@class_mapper.populate_ruby_obj obj, props
|
163
|
+
return obj
|
164
|
+
end
|
165
|
+
|
166
|
+
def amf0_read_typed_object
|
167
|
+
# Create object to add to ref cache
|
168
|
+
class_name = amf0_read_string
|
169
|
+
obj = @class_mapper.get_ruby_obj class_name
|
170
|
+
@ref_cache << obj
|
171
|
+
|
172
|
+
# Populate object
|
173
|
+
props = amf0_read_props
|
174
|
+
@class_mapper.populate_ruby_obj obj, props
|
175
|
+
return obj
|
176
|
+
end
|
177
|
+
|
178
|
+
def amf3_deserialize
|
179
|
+
type = read_int8 @source
|
180
|
+
case type
|
181
|
+
when AMF3_UNDEFINED_MARKER
|
182
|
+
nil
|
183
|
+
when AMF3_NULL_MARKER
|
184
|
+
nil
|
185
|
+
when AMF3_FALSE_MARKER
|
186
|
+
false
|
187
|
+
when AMF3_TRUE_MARKER
|
188
|
+
true
|
189
|
+
when AMF3_INTEGER_MARKER
|
190
|
+
amf3_read_integer
|
191
|
+
when AMF3_DOUBLE_MARKER
|
192
|
+
amf3_read_number
|
193
|
+
when AMF3_STRING_MARKER
|
194
|
+
amf3_read_string
|
195
|
+
when AMF3_XML_DOC_MARKER, AMF3_XML_MARKER
|
196
|
+
amf3_read_xml
|
197
|
+
when AMF3_DATE_MARKER
|
198
|
+
amf3_read_date
|
199
|
+
when AMF3_ARRAY_MARKER
|
200
|
+
amf3_read_array
|
201
|
+
when AMF3_OBJECT_MARKER
|
202
|
+
amf3_read_object
|
203
|
+
when AMF3_BYTE_ARRAY_MARKER
|
204
|
+
amf3_read_byte_array
|
205
|
+
when AMF3_VECTOR_INT_MARKER, AMF3_VECTOR_UINT_MARKER, AMF3_VECTOR_DOUBLE_MARKER, AMF3_VECTOR_OBJECT_MARKER
|
206
|
+
amf3_read_vector type
|
207
|
+
when AMF3_DICT_MARKER
|
208
|
+
amf3_read_dict
|
209
|
+
else
|
210
|
+
raise AMFError, "Invalid type: #{type}"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def amf3_read_integer
|
215
|
+
n = 0
|
216
|
+
b = read_word8(@source) || 0
|
217
|
+
result = 0
|
218
|
+
|
219
|
+
while ((b & 0x80) != 0 && n < 3)
|
220
|
+
result = result << 7
|
221
|
+
result = result | (b & 0x7f)
|
222
|
+
b = read_word8(@source) || 0
|
223
|
+
n = n + 1
|
224
|
+
end
|
225
|
+
|
226
|
+
if (n < 3)
|
227
|
+
result = result << 7
|
228
|
+
result = result | b
|
229
|
+
else
|
230
|
+
#Use all 8 bits from the 4th byte
|
231
|
+
result = result << 8
|
232
|
+
result = result | b
|
233
|
+
|
234
|
+
#Check if the integer should be negative
|
235
|
+
if (result > MAX_INTEGER)
|
236
|
+
result -= (1 << 29)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
result
|
240
|
+
end
|
241
|
+
|
242
|
+
def amf3_read_number
|
243
|
+
res = read_double @source
|
244
|
+
(res.is_a?(Float) && res.nan?) ? nil : res # check for NaN and convert them to nil
|
245
|
+
end
|
246
|
+
|
247
|
+
def amf3_read_string
|
248
|
+
type = amf3_read_integer
|
249
|
+
is_reference = (type & 0x01) == 0
|
250
|
+
|
251
|
+
if is_reference
|
252
|
+
reference = type >> 1
|
253
|
+
return @string_cache[reference]
|
254
|
+
else
|
255
|
+
length = type >> 1
|
256
|
+
str = ""
|
257
|
+
if length > 0
|
258
|
+
str = @source.read(length)
|
259
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
260
|
+
@string_cache << str
|
261
|
+
end
|
262
|
+
return str
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def amf3_read_xml
|
267
|
+
type = amf3_read_integer
|
268
|
+
is_reference = (type & 0x01) == 0
|
269
|
+
|
270
|
+
if is_reference
|
271
|
+
reference = type >> 1
|
272
|
+
return @object_cache[reference]
|
273
|
+
else
|
274
|
+
length = type >> 1
|
275
|
+
str = ""
|
276
|
+
if length > 0
|
277
|
+
str = @source.read(length)
|
278
|
+
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
279
|
+
@object_cache << str
|
280
|
+
end
|
281
|
+
return str
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def amf3_read_byte_array
|
286
|
+
type = amf3_read_integer
|
287
|
+
is_reference = (type & 0x01) == 0
|
288
|
+
|
289
|
+
if is_reference
|
290
|
+
reference = type >> 1
|
291
|
+
return @object_cache[reference]
|
292
|
+
else
|
293
|
+
length = type >> 1
|
294
|
+
obj = StringIO.new @source.read(length)
|
295
|
+
@object_cache << obj
|
296
|
+
obj
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def amf3_read_array
|
301
|
+
type = amf3_read_integer
|
302
|
+
is_reference = (type & 0x01) == 0
|
303
|
+
|
304
|
+
if is_reference
|
305
|
+
reference = type >> 1
|
306
|
+
return @object_cache[reference]
|
307
|
+
else
|
308
|
+
length = type >> 1
|
309
|
+
property_name = amf3_read_string
|
310
|
+
array = property_name.length > 0 ? {} : []
|
311
|
+
@object_cache << array
|
312
|
+
|
313
|
+
while property_name.length > 0
|
314
|
+
value = amf3_deserialize
|
315
|
+
array[property_name] = value
|
316
|
+
property_name = amf3_read_string
|
317
|
+
end
|
318
|
+
0.upto(length - 1) {|i| array[i] = amf3_deserialize }
|
319
|
+
|
320
|
+
array
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def amf3_read_object
|
325
|
+
type = amf3_read_integer
|
326
|
+
is_reference = (type & 0x01) == 0
|
327
|
+
|
328
|
+
if is_reference
|
329
|
+
reference = type >> 1
|
330
|
+
return @object_cache[reference]
|
331
|
+
else
|
332
|
+
class_type = type >> 1
|
333
|
+
class_is_reference = (class_type & 0x01) == 0
|
334
|
+
|
335
|
+
if class_is_reference
|
336
|
+
reference = class_type >> 1
|
337
|
+
traits = @trait_cache[reference]
|
338
|
+
else
|
339
|
+
externalizable = (class_type & 0x02) != 0
|
340
|
+
dynamic = (class_type & 0x04) != 0
|
341
|
+
attribute_count = class_type >> 3
|
342
|
+
class_name = amf3_read_string
|
343
|
+
|
344
|
+
class_attributes = []
|
345
|
+
attribute_count.times{class_attributes << amf3_read_string} # Read class members
|
346
|
+
|
347
|
+
traits = {
|
348
|
+
:class_name => class_name,
|
349
|
+
:members => class_attributes,
|
350
|
+
:externalizable => externalizable,
|
351
|
+
:dynamic => dynamic
|
352
|
+
}
|
353
|
+
@trait_cache << traits
|
354
|
+
end
|
355
|
+
|
356
|
+
# Optimization for deserializing ArrayCollection
|
357
|
+
if traits[:class_name] == "flex.messaging.io.ArrayCollection"
|
358
|
+
arr = amf3_deserialize # Adds ArrayCollection array to object cache
|
359
|
+
@object_cache << arr # Add again for ArrayCollection source array
|
360
|
+
return arr
|
361
|
+
end
|
362
|
+
|
363
|
+
obj = @class_mapper.get_ruby_obj traits[:class_name]
|
364
|
+
@object_cache << obj
|
365
|
+
|
366
|
+
if traits[:externalizable]
|
367
|
+
obj.read_external self
|
368
|
+
else
|
369
|
+
props = {}
|
370
|
+
traits[:members].each do |key|
|
371
|
+
value = amf3_deserialize
|
372
|
+
props[key] = value
|
373
|
+
end
|
374
|
+
|
375
|
+
dynamic_props = nil
|
376
|
+
if traits[:dynamic]
|
377
|
+
dynamic_props = {}
|
378
|
+
while (key = amf3_read_string) && key.length != 0 do # read next key
|
379
|
+
value = amf3_deserialize
|
380
|
+
dynamic_props[key] = value
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
@class_mapper.populate_ruby_obj obj, props, dynamic_props
|
385
|
+
end
|
386
|
+
obj
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def amf3_read_date
|
391
|
+
type = amf3_read_integer
|
392
|
+
is_reference = (type & 0x01) == 0
|
393
|
+
if is_reference
|
394
|
+
reference = type >> 1
|
395
|
+
return @object_cache[reference]
|
396
|
+
else
|
397
|
+
seconds = read_double(@source).to_f/1000
|
398
|
+
time = Time.at(seconds)
|
399
|
+
@object_cache << time
|
400
|
+
time
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def amf3_read_dict
|
405
|
+
type = amf3_read_integer
|
406
|
+
is_reference = (type & 0x01) == 0
|
407
|
+
if is_reference
|
408
|
+
reference = type >> 1
|
409
|
+
return @object_cache[reference]
|
410
|
+
else
|
411
|
+
dict = {}
|
412
|
+
@object_cache << dict
|
413
|
+
length = type >> 1
|
414
|
+
weak_keys = read_int8 @source # Ignore: Not supported in ruby
|
415
|
+
0.upto(length - 1) do |i|
|
416
|
+
dict[amf3_deserialize] = amf3_deserialize
|
417
|
+
end
|
418
|
+
dict
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def amf3_read_vector vector_type
|
423
|
+
type = amf3_read_integer
|
424
|
+
is_reference = (type & 0x01) == 0
|
425
|
+
if is_reference
|
426
|
+
reference = type >> 1
|
427
|
+
return @object_cache[reference]
|
428
|
+
else
|
429
|
+
vec = []
|
430
|
+
@object_cache << vec
|
431
|
+
length = type >> 1
|
432
|
+
fixed_vector = read_int8 @source # Ignore
|
433
|
+
case vector_type
|
434
|
+
when AMF3_VECTOR_INT_MARKER
|
435
|
+
0.upto(length - 1) do |i|
|
436
|
+
int = read_word32_network(@source)
|
437
|
+
int = int - 2**32 if int > MAX_INTEGER
|
438
|
+
vec << int
|
439
|
+
end
|
440
|
+
when AMF3_VECTOR_UINT_MARKER
|
441
|
+
0.upto(length - 1) do |i|
|
442
|
+
vec << read_word32_network(@source)
|
443
|
+
# puts vec[i].to_s(2)
|
444
|
+
end
|
445
|
+
when AMF3_VECTOR_DOUBLE_MARKER
|
446
|
+
0.upto(length - 1) do |i|
|
447
|
+
vec << amf3_read_number
|
448
|
+
end
|
449
|
+
when AMF3_VECTOR_OBJECT_MARKER
|
450
|
+
vector_class = amf3_read_string # Ignore
|
451
|
+
# puts vector_class
|
452
|
+
0.upto(length - 1) do |i|
|
453
|
+
vec << amf3_deserialize
|
454
|
+
end
|
455
|
+
end
|
456
|
+
vec
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|