Class: RubySol::Pure::Deserializer
- Inherits:
-
Object
- Object
- RubySol::Pure::Deserializer
show all
- Includes:
- ReadIOHelpers
- Defined in:
- lib/ruby_sol/pure/deserializer.rb
Overview
Pure ruby deserializer for AMF0 and AMF3
Instance Attribute Summary collapse
Instance Method Summary
collapse
#byte_order, #byte_order_little?, #read_double, #read_int16_network, #read_int8, #read_word16_network, #read_word32_network, #read_word8
Constructor Details
#initialize(class_mapper) ⇒ Deserializer
Pass in the class mapper instance to use when deserializing. This enables better caching behavior in the class mapper and allows one to change mappings between deserialization attempts.
12
13
14
15
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 12
def initialize class_mapper
@class_mapper = class_mapper
reset_caches()
end
|
Instance Attribute Details
#source ⇒ Object
Returns the value of attribute source.
7
8
9
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 7
def source
@source
end
|
Instance Method Details
#amf0_deserialize(type = nil) ⇒ Object
#amf0_read_array ⇒ Object
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 120
def amf0_read_array
len = read_word32_network(@source)
array = []
@ref_cache << array
0.upto(len - 1) do
array << amf0_deserialize
end
array
end
|
#amf0_read_boolean ⇒ Object
104
105
106
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 104
def amf0_read_boolean
read_int8(@source) != 0
end
|
#amf0_read_date ⇒ Object
131
132
133
134
135
136
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 131
def amf0_read_date
seconds = read_double(@source).to_f/1000
time = Time.at(seconds)
tz = read_word16_network(@source) time
end
|
#amf0_read_hash ⇒ Object
148
149
150
151
152
153
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 148
def amf0_read_hash
len = read_word32_network(@source) obj = {}
@ref_cache << obj
amf0_read_props obj
end
|
#amf0_read_number ⇒ Object
99
100
101
102
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 99
def amf0_read_number
res = read_double @source
(res.is_a?(Float) && res.nan?) ? nil : res end
|
#amf0_read_object(add_to_ref_cache = true) ⇒ Object
155
156
157
158
159
160
161
162
163
164
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 155
def amf0_read_object add_to_ref_cache=true
obj = @class_mapper.get_ruby_obj ""
@ref_cache << obj
props = amf0_read_props
@class_mapper.populate_ruby_obj obj, props
return obj
end
|
#amf0_read_props(obj = {}) ⇒ Object
138
139
140
141
142
143
144
145
146
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 138
def amf0_read_props obj={}
while true
key = amf0_read_string
type = read_int8 @source
break if type == AMF0_OBJECT_END_MARKER
obj[key] = amf0_deserialize(type)
end
obj
end
|
#amf0_read_reference ⇒ Object
115
116
117
118
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 115
def amf0_read_reference
index = read_word16_network(@source)
@ref_cache[index]
end
|
#amf0_read_string(long = false) ⇒ Object
108
109
110
111
112
113
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 108
def amf0_read_string long=false
len = long ? read_word32_network(@source) : read_word16_network(@source)
str = @source.read(len)
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
str
end
|
#amf0_read_typed_object ⇒ Object
166
167
168
169
170
171
172
173
174
175
176
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 166
def amf0_read_typed_object
class_name = amf0_read_string
obj = @class_mapper.get_ruby_obj class_name
@ref_cache << obj
props = amf0_read_props
@class_mapper.populate_ruby_obj obj, props
return obj
end
|
#amf3_deserialize ⇒ Object
#amf3_read_array ⇒ Object
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 300
def amf3_read_array
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
length = type >> 1
property_name = amf3_read_string
array = property_name.length > 0 ? {} : []
@object_cache << array
while property_name.length > 0
value = amf3_deserialize
array[property_name] = value
property_name = amf3_read_string
end
0.upto(length - 1) {|i| array[i] = amf3_deserialize }
array
end
end
|
#amf3_read_byte_array ⇒ Object
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 285
def amf3_read_byte_array
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
length = type >> 1
obj = StringIO.new @source.read(length)
@object_cache << obj
obj
end
end
|
#amf3_read_date ⇒ Object
390
391
392
393
394
395
396
397
398
399
400
401
402
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 390
def amf3_read_date
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
seconds = read_double(@source).to_f/1000
time = Time.at(seconds)
@object_cache << time
time
end
end
|
#amf3_read_dict ⇒ Object
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 404
def amf3_read_dict
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
dict = {}
@object_cache << dict
length = type >> 1
weak_keys = read_int8 @source 0.upto(length - 1) do |i|
dict[amf3_deserialize] = amf3_deserialize
end
dict
end
end
|
#amf3_read_integer ⇒ Object
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 214
def amf3_read_integer
n = 0
b = read_word8(@source) || 0
result = 0
while ((b & 0x80) != 0 && n < 3)
result = result << 7
result = result | (b & 0x7f)
b = read_word8(@source) || 0
n = n + 1
end
if (n < 3)
result = result << 7
result = result | b
else
result = result << 8
result = result | b
if (result > MAX_INTEGER)
result -= (1 << 29)
end
end
result
end
|
#amf3_read_number ⇒ Object
242
243
244
245
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 242
def amf3_read_number
res = read_double @source
(res.is_a?(Float) && res.nan?) ? nil : res end
|
#amf3_read_object ⇒ Object
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 324
def amf3_read_object
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
class_type = type >> 1
class_is_reference = (class_type & 0x01) == 0
if class_is_reference
reference = class_type >> 1
traits = @trait_cache[reference]
else
externalizable = (class_type & 0x02) != 0
dynamic = (class_type & 0x04) != 0
attribute_count = class_type >> 3
class_name = amf3_read_string
class_attributes = []
attribute_count.times{class_attributes << amf3_read_string}
traits = {
:class_name => class_name,
:members => class_attributes,
:externalizable => externalizable,
:dynamic => dynamic
}
@trait_cache << traits
end
if traits[:class_name] == "flex.messaging.io.ArrayCollection"
arr = amf3_deserialize @object_cache << arr return arr
end
obj = @class_mapper.get_ruby_obj traits[:class_name]
@object_cache << obj
if traits[:externalizable]
obj.read_external self
else
props = {}
traits[:members].each do |key|
value = amf3_deserialize
props[key] = value
end
dynamic_props = nil
if traits[:dynamic]
dynamic_props = {}
while (key = amf3_read_string) && key.length != 0 do value = amf3_deserialize
dynamic_props[key] = value
end
end
@class_mapper.populate_ruby_obj obj, props, dynamic_props
end
obj
end
end
|
#amf3_read_string ⇒ Object
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 247
def amf3_read_string
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @string_cache[reference]
else
length = type >> 1
str = ""
if length > 0
str = @source.read(length)
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
@string_cache << str
end
return str
end
end
|
#amf3_read_vector(vector_type) ⇒ Object
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 422
def amf3_read_vector vector_type
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
vec = []
@object_cache << vec
length = type >> 1
fixed_vector = read_int8 @source case vector_type
when AMF3_VECTOR_INT_MARKER
0.upto(length - 1) do |i|
int = read_word32_network(@source)
int = int - 2**32 if int > MAX_INTEGER
vec << int
end
when AMF3_VECTOR_UINT_MARKER
0.upto(length - 1) do |i|
vec << read_word32_network(@source)
end
when AMF3_VECTOR_DOUBLE_MARKER
0.upto(length - 1) do |i|
vec << amf3_read_number
end
when AMF3_VECTOR_OBJECT_MARKER
vector_class = amf3_read_string 0.upto(length - 1) do |i|
vec << amf3_deserialize
end
end
vec
end
end
|
#amf3_read_xml ⇒ Object
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 266
def amf3_read_xml
type = amf3_read_integer
is_reference = (type & 0x01) == 0
if is_reference
reference = type >> 1
return @object_cache[reference]
else
length = type >> 1
str = ""
if length > 0
str = @source.read(length)
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
@object_cache << str
end
return str
end
end
|
#deserialize(version, source) ⇒ Object
Deserialize the source using AMF0 or AMF3. Source should either be a string or StringIO object. If you pass a StringIO object, it will have its position updated to the end of the deserialized data.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 28
def deserialize version, source
raise ArgumentError, "unsupported version #{version}" unless [0,3].include?(version)
@version = version
if StringIO === source
@source = source
elsif source
@source = StringIO.new(source)
elsif @source.nil?
raise AMFError, "no source to deserialize"
end
reset_caches()
if @version == 0
return amf0_deserialize
else
return amf3_deserialize
end
end
|
#read_object ⇒ Object
Reads an object from the deserializer’s stream and returns it.
50
51
52
53
54
55
56
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 50
def read_object
if @version == 0
return amf0_deserialize
else
return amf3_deserialize
end
end
|
#reset_caches ⇒ Object
17
18
19
20
21
22
|
# File 'lib/ruby_sol/pure/deserializer.rb', line 17
def reset_caches
@ref_cache = []
@string_cache = []
@object_cache = []
@trait_cache = []
end
|