Class: RubySol::Pure::Serializer
- Inherits:
-
Object
- Object
- RubySol::Pure::Serializer
show all
- Includes:
- WriteIOHelpers
- Defined in:
- lib/ruby_sol/pure/serializer.rb
Overview
Pure ruby serializer for AMF0 and AMF3
Instance Attribute Summary collapse
Instance Method Summary
collapse
#byte_order, #byte_order_little?, #pack_double, #pack_int16_network, #pack_int8, #pack_integer, #pack_word32_network
Constructor Details
#initialize(class_mapper) ⇒ Serializer
Pass in the class mapper instance to use when serializing. This enables better caching behavior in the class mapper and allows one to change mappings between serialization attempts.
12
13
14
15
16
17
|
# File 'lib/ruby_sol/pure/serializer.rb', line 12
def initialize class_mapper
@class_mapper = class_mapper
@stream = ""
@depth = 0
reset_caches()
end
|
Instance Attribute Details
#stream ⇒ Object
Returns the value of attribute stream.
7
8
9
|
# File 'lib/ruby_sol/pure/serializer.rb', line 7
def stream
@stream
end
|
#version ⇒ Object
Returns the value of attribute version.
7
8
9
|
# File 'lib/ruby_sol/pure/serializer.rb', line 7
def version
@version
end
|
Instance Method Details
#amf0_serialize(obj) ⇒ Object
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
# File 'lib/ruby_sol/pure/serializer.rb', line 90
def amf0_serialize obj
if @ref_cache[obj] != nil
amf0_write_reference @ref_cache[obj]
elsif obj.respond_to?(:encode_amf)
obj.encode_amf(self)
elsif obj.is_a?(NilClass)
amf0_write_null
elsif obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
amf0_write_boolean obj
elsif obj.is_a?(Numeric)
amf0_write_number obj
elsif obj.is_a?(Symbol) || obj.is_a?(String)
amf0_write_string obj.to_s
elsif obj.is_a?(Time)
amf0_write_time obj
elsif obj.is_a?(Date)
amf0_write_date obj
elsif obj.is_a?(Array)
amf0_write_array obj
elsif obj.is_a?(Hash) ||obj.is_a?(Object)
amf0_write_object obj
end
end
|
#amf0_write_array(array) ⇒ Object
170
171
172
173
174
175
176
177
|
# File 'lib/ruby_sol/pure/serializer.rb', line 170
def amf0_write_array array
@ref_cache.add_obj array
@stream << AMF0_STRICT_ARRAY_MARKER
@stream << pack_word32_network(array.length)
array.each do |elem|
amf0_serialize elem
end
end
|
#amf0_write_boolean(bool) ⇒ Object
118
119
120
121
|
# File 'lib/ruby_sol/pure/serializer.rb', line 118
def amf0_write_boolean bool
@stream << AMF0_BOOLEAN_MARKER
@stream << pack_int8(bool ? 1 : 0)
end
|
#amf0_write_date(date) ⇒ Object
159
160
161
162
163
|
# File 'lib/ruby_sol/pure/serializer.rb', line 159
def amf0_write_date date
@stream << AMF0_DATE_MARKER
@stream << pack_double(date.strftime("%Q").to_i)
@stream << pack_int16_network(0) end
|
#amf0_write_null ⇒ Object
114
115
116
|
# File 'lib/ruby_sol/pure/serializer.rb', line 114
def amf0_write_null
@stream << AMF0_NULL_MARKER
end
|
#amf0_write_number(num) ⇒ Object
123
124
125
126
|
# File 'lib/ruby_sol/pure/serializer.rb', line 123
def amf0_write_number num
@stream << AMF0_NUMBER_MARKER
@stream << pack_double(num)
end
|
#amf0_write_object(obj, props = nil) ⇒ Object
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
# File 'lib/ruby_sol/pure/serializer.rb', line 179
def amf0_write_object obj, props=nil
@ref_cache.add_obj obj
props = @class_mapper.props_for_serialization obj if props.nil?
class_name = @class_mapper.get_as_class_name obj
if class_name
class_name = class_name.encode("UTF-8").force_encoding("ASCII-8BIT") if class_name.respond_to?(:encode)
@stream << AMF0_TYPED_OBJECT_MARKER
@stream << pack_int16_network(class_name.bytesize)
@stream << class_name
else
@stream << AMF0_OBJECT_MARKER
end
props.sort.each do |key, value| key = key.encode("UTF-8").force_encoding("ASCII-8BIT") if key.respond_to?(:encode)
@stream << pack_int16_network(key.bytesize)
@stream << key
amf0_serialize value
end
@stream << pack_int16_network(0)
@stream << AMF0_OBJECT_END_MARKER
end
|
#amf0_write_reference(index) ⇒ Object
165
166
167
168
|
# File 'lib/ruby_sol/pure/serializer.rb', line 165
def amf0_write_reference index
@stream << AMF0_REFERENCE_MARKER
@stream << pack_int16_network(index)
end
|
#amf0_write_string(str) ⇒ Object
128
129
130
131
132
133
134
135
136
137
138
139
|
# File 'lib/ruby_sol/pure/serializer.rb', line 128
def amf0_write_string str
str = str.encode("UTF-8").force_encoding("ASCII-8BIT") if str.respond_to?(:encode)
len = str.bytesize
if len > 2**16-1
@stream << AMF0_LONG_STRING_MARKER
@stream << pack_word32_network(len)
else
@stream << AMF0_STRING_MARKER
@stream << pack_int16_network(len)
end
@stream << str
end
|
#amf0_write_string_wo_marker(str) ⇒ Object
141
142
143
144
145
146
147
|
# File 'lib/ruby_sol/pure/serializer.rb', line 141
def amf0_write_string_wo_marker str
str = str.encode("UTF-8").force_encoding("ASCII-8BIT") if str.respond_to?(:encode)
len = str.bytesize
throw SOLError, 'too long string' if len > 2**16-1
@stream << pack_int16_network(len)
@stream << str
end
|
#amf0_write_time(time) ⇒ Object
149
150
151
152
153
154
155
156
157
|
# File 'lib/ruby_sol/pure/serializer.rb', line 149
def amf0_write_time time
@stream << AMF0_DATE_MARKER
time = time.getutc milli = (time.to_f * 1000).to_i
@stream << pack_double(milli)
@stream << pack_int16_network(0) end
|
#amf3_serialize(obj) ⇒ Object
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
# File 'lib/ruby_sol/pure/serializer.rb', line 208
def amf3_serialize obj
if obj.respond_to?(:encode_amf)
obj.encode_amf(self)
elsif obj.is_a?(NilClass)
amf3_write_null
elsif obj.is_a?(TrueClass)
amf3_write_true
elsif obj.is_a?(FalseClass)
amf3_write_false
elsif obj.is_a?(Numeric)
amf3_write_numeric obj
elsif obj.is_a?(Symbol) || obj.is_a?(String)
amf3_write_string obj.to_s
elsif obj.is_a?(Time)
amf3_write_time obj
elsif obj.is_a?(Date)
amf3_write_date obj
elsif obj.is_a?(StringIO)
amf3_write_byte_array obj
elsif obj.is_a?(Array)
amf3_write_array obj
elsif obj.is_a?(Hash) || obj.is_a?(Object)
amf3_write_object obj
end
end
|
#amf3_write_array(array) ⇒ Object
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
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
|
# File 'lib/ruby_sol/pure/serializer.rb', line 308
def amf3_write_array array
is_ac = false
if array.respond_to?(:is_array_collection?)
is_ac = array.is_array_collection?
else
is_ac = @class_mapper.use_array_collection
end
@stream << (is_ac ? AMF3_OBJECT_MARKER : AMF3_ARRAY_MARKER)
if @object_cache[array] != nil
amf3_write_reference @object_cache[array]
return
else
@object_cache.add_obj array
@object_cache.add_obj nil if is_ac end
if is_ac
class_name = "flex.messaging.io.ArrayCollection"
if @trait_cache[class_name] != nil
@stream << pack_integer(@trait_cache[class_name] << 2 | 0x01)
else
@trait_cache.add_obj class_name
@stream << "\a" amf3_write_utf8_vr(class_name)
end
@stream << AMF3_ARRAY_MARKER
end
= array.length << 1 = | 1 @stream << pack_integer()
@stream << AMF3_CLOSE_DYNAMIC_ARRAY
array.each do |elem|
amf3_serialize elem
end
end
|
#amf3_write_byte_array(array) ⇒ Object
296
297
298
299
300
301
302
303
304
305
306
|
# File 'lib/ruby_sol/pure/serializer.rb', line 296
def amf3_write_byte_array array
@stream << AMF3_BYTE_ARRAY_MARKER
if @object_cache[array] != nil
amf3_write_reference @object_cache[array]
else
@object_cache.add_obj array
str = array.string
@stream << pack_integer(str.bytesize << 1 | 1)
@stream << str
end
end
|
#amf3_write_date(date) ⇒ Object
282
283
284
285
286
287
288
289
290
291
292
293
294
|
# File 'lib/ruby_sol/pure/serializer.rb', line 282
def amf3_write_date date
@stream << AMF3_DATE_MARKER
if @object_cache[date] != nil
amf3_write_reference @object_cache[date]
else
@object_cache.add_obj date
@stream << AMF3_NULL_MARKER
@stream << pack_double(date.strftime("%Q").to_i)
end
end
|
#amf3_write_false ⇒ Object
247
248
249
|
# File 'lib/ruby_sol/pure/serializer.rb', line 247
def amf3_write_false
@stream << AMF3_FALSE_MARKER
end
|
#amf3_write_null ⇒ Object
239
240
241
|
# File 'lib/ruby_sol/pure/serializer.rb', line 239
def amf3_write_null
@stream << AMF3_NULL_MARKER
end
|
#amf3_write_numeric(num) ⇒ Object
251
252
253
254
255
256
257
258
259
|
# File 'lib/ruby_sol/pure/serializer.rb', line 251
def amf3_write_numeric num
if !num.integer? || num < MIN_INTEGER || num > MAX_INTEGER @stream << AMF3_DOUBLE_MARKER
@stream << pack_double(num)
else
@stream << AMF3_INTEGER_MARKER
@stream << pack_integer(num)
end
end
|
#amf3_write_object(obj, props = nil, traits = nil) ⇒ Object
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
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
|
# File 'lib/ruby_sol/pure/serializer.rb', line 352
def amf3_write_object obj, props=nil, traits=nil
@stream << AMF3_OBJECT_MARKER
if @object_cache[obj] != nil
amf3_write_reference @object_cache[obj]
return
end
@object_cache.add_obj obj
is_default = false
if traits.nil?
traits = {
:class_name => @class_mapper.get_as_class_name(obj),
:members => [],
:externalizable => false,
:dynamic => true
}
is_default = true unless traits[:class_name]
end
class_name = is_default ? "__default__" : traits[:class_name]
if (class_name && @trait_cache[class_name] != nil)
@stream << pack_integer(@trait_cache[class_name] << 2 | 0x01)
else
@trait_cache.add_obj class_name if class_name
= 0x03 |= 0x02 << 2 if traits[:dynamic]
|= 0x01 << 2 if traits[:externalizable]
|= traits[:members].length << 4
@stream << pack_integer()
if class_name == "__default__"
amf3_write_utf8_vr("")
else
amf3_write_utf8_vr(class_name.to_s)
end
traits[:members].each {|m| amf3_write_utf8_vr(m)}
end
if traits[:externalizable]
obj.write_external(self)
return
end
props = @class_mapper.props_for_serialization(obj) if props.nil?
traits[:members].each do |m|
amf3_serialize props[m]
props.delete(m)
end
if traits[:dynamic]
props.sort.each do |key, val| amf3_write_utf8_vr key.to_s
amf3_serialize val
end
@stream << AMF3_CLOSE_DYNAMIC_OBJECT
end
end
|
#amf3_write_reference(index) ⇒ Object
234
235
236
237
|
# File 'lib/ruby_sol/pure/serializer.rb', line 234
def amf3_write_reference index
= index << 1 @stream << pack_integer()
end
|
#amf3_write_string(str) ⇒ Object
261
262
263
264
|
# File 'lib/ruby_sol/pure/serializer.rb', line 261
def amf3_write_string str
@stream << AMF3_STRING_MARKER
amf3_write_utf8_vr str
end
|
#amf3_write_time(time) ⇒ Object
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
# File 'lib/ruby_sol/pure/serializer.rb', line 266
def amf3_write_time time
@stream << AMF3_DATE_MARKER
if @object_cache[time] != nil
amf3_write_reference @object_cache[time]
else
@object_cache.add_obj time
time = time.getutc milli = (time.to_f * 1000).to_i
@stream << AMF3_NULL_MARKER
@stream << pack_double(milli)
end
end
|
#amf3_write_true ⇒ Object
243
244
245
|
# File 'lib/ruby_sol/pure/serializer.rb', line 243
def amf3_write_true
@stream << AMF3_TRUE_MARKER
end
|
#amf3_write_utf8_vr(str, encode = true) ⇒ Object
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
|
# File 'lib/ruby_sol/pure/serializer.rb', line 427
def amf3_write_utf8_vr str, encode=true
if str.respond_to?(:encode)
if encode
str = str.encode("UTF-8")
else
str = str.dup if str.frozen?
end
str.force_encoding("ASCII-8BIT")
end
if str == ''
@stream << AMF3_EMPTY_STRING
elsif @string_cache[str] != nil
amf3_write_reference @string_cache[str]
else
@string_cache.add_obj str
@stream << pack_integer(str.bytesize << 1 | 1)
@stream << str
end
end
|
#serialize(version, obj) ⇒ Object
Serialize the given object using AMF0 or AMF3. Can be called from inside encode_amf, but make sure to pass in the proper version or it may not be possible to decode. Use the serializer version attribute for this.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/ruby_sol/pure/serializer.rb', line 29
def serialize version, obj
raise ArgumentError, "unsupported version #{version}" unless [0,3].include?(version)
@version = version
if @depth == 0
if @version == 0
@ref_cache = SerializerCache.new :object
else
@string_cache = SerializerCache.new :string
@object_cache = SerializerCache.new :object
@trait_cache = SerializerCache.new :string
end
end
@depth += 1
if @version == 0
amf0_serialize(obj)
else
amf3_serialize(obj)
end
@depth -= 1
if @depth == 0
@ref_cache = nil
@string_cache = nil
@object_cache = nil
@trait_cache = nil
end
return @stream
end
|
#write_array(arr) ⇒ Object
Helper for writing arrays inside encode_amf. It uses the current AMF version to write the array.
66
67
68
69
70
71
72
|
# File 'lib/ruby_sol/pure/serializer.rb', line 66
def write_array arr
if @version == 0
amf0_write_array arr
else
amf3_write_array arr
end
end
|
#write_object(obj, props = nil, traits = nil) ⇒ Object
Helper for writing objects inside encode_amf. It uses the current AMF version to write the object. If you pass in a property hash, it will use it rather than having the class mapper determine properties. For AMF3, you can also specify a traits hash, which can be used to reduce serialized data size or serialize things as externalizable.
79
80
81
82
83
84
85
|
# File 'lib/ruby_sol/pure/serializer.rb', line 79
def write_object obj, props=nil, traits=nil
if @version == 0
amf0_write_object obj, props
else
amf3_write_object obj, props, traits
end
end
|