RocketAMF-ouvrages 1.0.0

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