mrpin-rocketamf 1.0.4 → 2.0.0
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 +4 -4
- data/README.rdoc +1 -1
- data/Rakefile +7 -7
- data/benchmark.rb +44 -37
- data/ext/rocketamf_ext/class_mapping.c +11 -11
- data/ext/rocketamf_ext/remoting.c +1 -1
- data/lib/rocketamf.rb +41 -98
- data/lib/rocketamf/constants.rb +20 -20
- data/lib/rocketamf/errors.rb +2 -0
- data/lib/rocketamf/errors/amf_error.rb +5 -0
- data/lib/rocketamf/errors/amf_error_incomplete.rb +5 -0
- data/lib/rocketamf/ext.rb +0 -6
- data/lib/rocketamf/extensions.rb +4 -4
- data/lib/rocketamf/{class_mapping.rb → mapping/class_mapping.rb} +70 -103
- data/lib/rocketamf/mapping/mapping_set.rb +63 -0
- data/lib/rocketamf/pure.rb +1 -9
- data/lib/rocketamf/pure/deserializer.rb +234 -262
- data/lib/rocketamf/pure/helpers/io_helper_base.rb +19 -0
- data/lib/rocketamf/pure/helpers/io_helper_read.rb +67 -0
- data/lib/rocketamf/pure/helpers/io_helper_write.rb +48 -0
- data/lib/rocketamf/pure/helpers/object_cache.rb +20 -0
- data/lib/rocketamf/pure/helpers/string_cache.rb +14 -0
- data/lib/rocketamf/pure/serializer.rb +138 -271
- data/lib/rocketamf/types.rb +1 -0
- data/lib/rocketamf/{values → types}/typed_hash.rb +12 -2
- data/mrpin-rocketamf.gemspec +27 -16
- data/spec/class_mapping_spec.rb +59 -52
- data/spec/deserializer_spec.rb +164 -328
- data/spec/fast_class_mapping_spec.rb +52 -46
- data/spec/helpers/class_mapping_test.rb +4 -0
- data/spec/helpers/class_mapping_test2.rb +3 -0
- data/spec/helpers/externalizable_test.rb +24 -0
- data/spec/helpers/fixtures.rb +28 -0
- data/spec/helpers/other_class.rb +4 -0
- data/spec/helpers/ruby_class.rb +4 -0
- data/spec/helpers/test_ruby_class.rb +4 -0
- data/spec/serializer_spec.rb +248 -339
- data/spec/spec_helper.rb +4 -49
- metadata +47 -53
- data/lib/rocketamf/pure/io_helpers.rb +0 -94
- data/lib/rocketamf/pure/remoting.rb +0 -117
- data/lib/rocketamf/remoting.rb +0 -196
- data/lib/rocketamf/values/messages.rb +0 -214
- data/spec/fixtures/objects/amf0-boolean.bin +0 -1
- 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-empty-string-key-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-null.bin +0 -1
- 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 +0 -1
- data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
- data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
- data/spec/messages_spec.rb +0 -39
- data/spec/remoting_spec.rb +0 -196
@@ -0,0 +1,19 @@
|
|
1
|
+
module RocketAMF
|
2
|
+
module Pure
|
3
|
+
module IOHelperBase
|
4
|
+
|
5
|
+
def byte_order
|
6
|
+
if [0x12345678].pack('L') == "\x12\x34\x56\x78"
|
7
|
+
:BigEndian
|
8
|
+
else
|
9
|
+
:LittleEndian
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def byte_order_little?
|
14
|
+
byte_order == :LittleEndian
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rocketamf/pure/helpers/io_helper_base'
|
2
|
+
|
3
|
+
module RocketAMF
|
4
|
+
module Pure
|
5
|
+
module IOHelperRead #:nodoc:
|
6
|
+
|
7
|
+
include IOHelperBase
|
8
|
+
|
9
|
+
#
|
10
|
+
# Methods
|
11
|
+
#
|
12
|
+
|
13
|
+
public
|
14
|
+
def read_int8(source)
|
15
|
+
raise AMFErrorIncomplete.new if source.eof?
|
16
|
+
|
17
|
+
source.read(1).unpack('c').first
|
18
|
+
end
|
19
|
+
|
20
|
+
public
|
21
|
+
def read_word8(source)
|
22
|
+
raise AMFErrorIncomplete.new if source.eof?
|
23
|
+
|
24
|
+
source.read(1).unpack('C').first
|
25
|
+
end
|
26
|
+
|
27
|
+
public
|
28
|
+
def read_double(source)
|
29
|
+
bytes_to_read = 8
|
30
|
+
|
31
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
32
|
+
|
33
|
+
source.read(bytes_to_read).unpack('G').first
|
34
|
+
end
|
35
|
+
|
36
|
+
public
|
37
|
+
def read_word16_network(source)
|
38
|
+
bytes_to_read = 2
|
39
|
+
|
40
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
41
|
+
|
42
|
+
source.read(2).unpack('n').first
|
43
|
+
end
|
44
|
+
|
45
|
+
public
|
46
|
+
def read_int16_network(source)
|
47
|
+
bytes_to_read = 2
|
48
|
+
|
49
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
50
|
+
|
51
|
+
result = source.read(bytes_to_read)
|
52
|
+
result.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
53
|
+
result.unpack('s').first
|
54
|
+
end
|
55
|
+
|
56
|
+
public
|
57
|
+
def read_word32_network(source)
|
58
|
+
bytes_to_read = 4
|
59
|
+
|
60
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
61
|
+
|
62
|
+
source.read(bytes_to_read).unpack('N').first
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rocketamf/pure/helpers/io_helper_base'
|
2
|
+
|
3
|
+
module RocketAMF
|
4
|
+
module Pure
|
5
|
+
module IOHelperWrite #:nodoc:
|
6
|
+
|
7
|
+
include IOHelperBase
|
8
|
+
|
9
|
+
def pack_integer(integer)
|
10
|
+
integer = integer & 0x1fffffff
|
11
|
+
if integer < 0x80
|
12
|
+
[integer].pack('c')
|
13
|
+
elsif integer < 0x4000
|
14
|
+
[integer >> 7 & 0x7f | 0x80].pack('c')+
|
15
|
+
[integer & 0x7f].pack('c')
|
16
|
+
elsif integer < 0x200000
|
17
|
+
[integer >> 14 & 0x7f | 0x80].pack('c') +
|
18
|
+
[integer >> 7 & 0x7f | 0x80].pack('c') +
|
19
|
+
[integer & 0x7f].pack('c')
|
20
|
+
else
|
21
|
+
[integer >> 22 & 0x7f | 0x80].pack('c')+
|
22
|
+
[integer >> 15 & 0x7f | 0x80].pack('c')+
|
23
|
+
[integer >> 8 & 0x7f | 0x80].pack('c')+
|
24
|
+
[integer & 0xff].pack('c')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def pack_double(double)
|
29
|
+
[double].pack('G')
|
30
|
+
end
|
31
|
+
|
32
|
+
def pack_int8(val)
|
33
|
+
[val].pack('c')
|
34
|
+
end
|
35
|
+
|
36
|
+
def pack_int16_network(val)
|
37
|
+
[val].pack('n')
|
38
|
+
end
|
39
|
+
|
40
|
+
def pack_word32_network(val)
|
41
|
+
result = [val].pack('L')
|
42
|
+
result.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RocketAMF
|
2
|
+
module Pure
|
3
|
+
class ObjectCache < Hash #:nodoc:
|
4
|
+
def initialize
|
5
|
+
@cache_index = 0
|
6
|
+
@obj_references = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](obj)
|
10
|
+
super(obj.object_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_obj(obj)
|
14
|
+
@obj_references << obj
|
15
|
+
self[obj.object_id] = @cache_index
|
16
|
+
@cache_index += 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,195 +1,78 @@
|
|
1
|
-
require 'rocketamf/pure/
|
1
|
+
require 'rocketamf/pure/helpers/io_helper_write'
|
2
|
+
require 'rocketamf/pure/helpers/object_cache'
|
3
|
+
require 'rocketamf/pure/helpers/string_cache'
|
2
4
|
|
3
5
|
module RocketAMF
|
4
6
|
module Pure
|
5
|
-
# Pure ruby serializer for
|
7
|
+
# Pure ruby serializer for AMF3
|
6
8
|
class Serializer
|
7
|
-
|
9
|
+
|
10
|
+
#
|
11
|
+
# Modules
|
12
|
+
#
|
13
|
+
|
14
|
+
private
|
15
|
+
include RocketAMF::Pure::IOHelperWrite
|
16
|
+
|
17
|
+
#
|
18
|
+
# Properties
|
19
|
+
#
|
20
|
+
|
21
|
+
public
|
22
|
+
attr_reader :stream
|
8
23
|
|
9
24
|
# Pass in the class mapper instance to use when serializing. This enables
|
10
25
|
# better caching behavior in the class mapper and allows one to change
|
11
26
|
# mappings between serialization attempts.
|
12
|
-
|
27
|
+
public
|
28
|
+
def initialize(class_mapper)
|
13
29
|
@class_mapper = class_mapper
|
14
|
-
@stream
|
15
|
-
@depth
|
30
|
+
@stream = ''
|
31
|
+
@depth = 0
|
16
32
|
end
|
17
33
|
|
18
|
-
# Serialize the given object using
|
19
|
-
# encode_amf
|
20
|
-
|
21
|
-
def serialize version, obj
|
22
|
-
raise ArgumentError, "unsupported version #{version}" unless [0,3].include?(version)
|
23
|
-
@version = version
|
24
|
-
|
34
|
+
# Serialize the given object using AMF3. Can be called from inside
|
35
|
+
# encode_amf.
|
36
|
+
def serialize(obj)
|
25
37
|
# Initialize caches
|
26
38
|
if @depth == 0
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@string_cache = SerializerCache.new :string
|
31
|
-
@object_cache = SerializerCache.new :object
|
32
|
-
@trait_cache = SerializerCache.new :string
|
33
|
-
end
|
39
|
+
@string_cache = StringCache.new
|
40
|
+
@object_cache = ObjectCache.new
|
41
|
+
@trait_cache = StringCache.new
|
34
42
|
end
|
35
43
|
@depth += 1
|
36
44
|
|
37
45
|
# Perform serialization
|
38
|
-
|
39
|
-
amf0_serialize(obj)
|
40
|
-
else
|
41
|
-
amf3_serialize(obj)
|
42
|
-
end
|
46
|
+
amf3_serialize(obj)
|
43
47
|
|
44
48
|
# Cleanup
|
45
49
|
@depth -= 1
|
46
50
|
if @depth == 0
|
47
|
-
@ref_cache
|
51
|
+
@ref_cache = nil
|
48
52
|
@string_cache = nil
|
49
53
|
@object_cache = nil
|
50
|
-
@trait_cache
|
54
|
+
@trait_cache = nil
|
51
55
|
end
|
52
56
|
|
53
|
-
|
57
|
+
@stream
|
54
58
|
end
|
55
59
|
|
56
|
-
# Helper for writing arrays inside encode_amf.
|
57
|
-
|
58
|
-
|
59
|
-
if @version == 0
|
60
|
-
amf0_write_array arr
|
61
|
-
else
|
62
|
-
amf3_write_array arr
|
63
|
-
end
|
60
|
+
# Helper for writing arrays inside encode_amf.
|
61
|
+
def write_array(value)
|
62
|
+
amf3_write_array value
|
64
63
|
end
|
65
64
|
|
66
|
-
# Helper for writing objects inside encode_amf.
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# you can also specify a traits hash, which can be used to reduce serialized
|
65
|
+
# Helper for writing objects inside encode_amf. If you pass in a property hash, it will use
|
66
|
+
# it rather than having the class mapper determine properties.
|
67
|
+
# You can also specify a traits hash, which can be used to reduce serialized
|
70
68
|
# data size or serialize things as externalizable.
|
71
|
-
def write_object
|
72
|
-
|
73
|
-
amf0_write_object obj, props
|
74
|
-
else
|
75
|
-
amf3_write_object obj, props, traits
|
76
|
-
end
|
69
|
+
def write_object(obj, props = nil, traits = nil)
|
70
|
+
amf3_write_object(obj, props, traits)
|
77
71
|
end
|
78
72
|
|
79
|
-
private
|
80
|
-
include RocketAMF::Pure::WriteIOHelpers
|
81
73
|
|
82
|
-
|
83
|
-
|
84
|
-
amf0_write_reference @ref_cache[obj]
|
85
|
-
elsif obj.respond_to?(:encode_amf)
|
86
|
-
obj.encode_amf(self)
|
87
|
-
elsif obj.is_a?(NilClass)
|
88
|
-
amf0_write_null
|
89
|
-
elsif obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
|
90
|
-
amf0_write_boolean obj
|
91
|
-
elsif obj.is_a?(Numeric)
|
92
|
-
amf0_write_number obj
|
93
|
-
elsif obj.is_a?(Symbol) || obj.is_a?(String)
|
94
|
-
amf0_write_string obj.to_s
|
95
|
-
elsif obj.is_a?(Time)
|
96
|
-
amf0_write_time obj
|
97
|
-
elsif obj.is_a?(Date)
|
98
|
-
amf0_write_date obj
|
99
|
-
elsif obj.is_a?(Array)
|
100
|
-
amf0_write_array obj
|
101
|
-
elsif obj.is_a?(Hash) ||obj.is_a?(Object)
|
102
|
-
amf0_write_object obj
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def amf0_write_null
|
107
|
-
@stream << AMF0_NULL_MARKER
|
108
|
-
end
|
109
|
-
|
110
|
-
def amf0_write_boolean bool
|
111
|
-
@stream << AMF0_BOOLEAN_MARKER
|
112
|
-
@stream << pack_int8(bool ? 1 : 0)
|
113
|
-
end
|
114
|
-
|
115
|
-
def amf0_write_number num
|
116
|
-
@stream << AMF0_NUMBER_MARKER
|
117
|
-
@stream << pack_double(num)
|
118
|
-
end
|
119
|
-
|
120
|
-
def amf0_write_string str
|
121
|
-
str = str.encode("UTF-8").force_encoding("ASCII-8BIT") if str.respond_to?(:encode)
|
122
|
-
len = str.bytesize
|
123
|
-
if len > 2**16-1
|
124
|
-
@stream << AMF0_LONG_STRING_MARKER
|
125
|
-
@stream << pack_word32_network(len)
|
126
|
-
else
|
127
|
-
@stream << AMF0_STRING_MARKER
|
128
|
-
@stream << pack_int16_network(len)
|
129
|
-
end
|
130
|
-
@stream << str
|
131
|
-
end
|
132
|
-
|
133
|
-
def amf0_write_time time
|
134
|
-
@stream << AMF0_DATE_MARKER
|
135
|
-
|
136
|
-
time = time.getutc # Dup and convert to UTC
|
137
|
-
milli = (time.to_f * 1000).to_i
|
138
|
-
@stream << pack_double(milli)
|
139
|
-
|
140
|
-
@stream << pack_int16_network(0) # Time zone
|
141
|
-
end
|
142
|
-
|
143
|
-
def amf0_write_date date
|
144
|
-
@stream << AMF0_DATE_MARKER
|
145
|
-
@stream << pack_double(date.strftime("%Q").to_i)
|
146
|
-
@stream << pack_int16_network(0) # Time zone
|
147
|
-
end
|
148
|
-
|
149
|
-
def amf0_write_reference index
|
150
|
-
@stream << AMF0_REFERENCE_MARKER
|
151
|
-
@stream << pack_int16_network(index)
|
152
|
-
end
|
153
|
-
|
154
|
-
def amf0_write_array array
|
155
|
-
@ref_cache.add_obj array
|
156
|
-
@stream << AMF0_STRICT_ARRAY_MARKER
|
157
|
-
@stream << pack_word32_network(array.length)
|
158
|
-
array.each do |elem|
|
159
|
-
amf0_serialize elem
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def amf0_write_object obj, props=nil
|
164
|
-
@ref_cache.add_obj obj
|
165
|
-
|
166
|
-
props = @class_mapper.props_for_serialization obj if props.nil?
|
167
|
-
|
168
|
-
# Is it a typed object?
|
169
|
-
class_name = @class_mapper.get_as_class_name obj
|
170
|
-
if class_name
|
171
|
-
class_name = class_name.encode("UTF-8").force_encoding("ASCII-8BIT") if class_name.respond_to?(:encode)
|
172
|
-
@stream << AMF0_TYPED_OBJECT_MARKER
|
173
|
-
@stream << pack_int16_network(class_name.bytesize)
|
174
|
-
@stream << class_name
|
175
|
-
else
|
176
|
-
@stream << AMF0_OBJECT_MARKER
|
177
|
-
end
|
178
|
-
|
179
|
-
# Write prop list
|
180
|
-
props.sort.each do |key, value| # Sort keys before writing
|
181
|
-
key = key.encode("UTF-8").force_encoding("ASCII-8BIT") if key.respond_to?(:encode)
|
182
|
-
@stream << pack_int16_network(key.bytesize)
|
183
|
-
@stream << key
|
184
|
-
amf0_serialize value
|
185
|
-
end
|
186
|
-
|
187
|
-
# Write end
|
188
|
-
@stream << pack_int16_network(0)
|
189
|
-
@stream << AMF0_OBJECT_END_MARKER
|
190
|
-
end
|
191
|
-
|
192
|
-
def amf3_serialize obj
|
74
|
+
private
|
75
|
+
def amf3_serialize(obj)
|
193
76
|
if obj.respond_to?(:encode_amf)
|
194
77
|
obj.encode_amf(self)
|
195
78
|
elsif obj.is_a?(NilClass)
|
@@ -199,124 +82,139 @@ module RocketAMF
|
|
199
82
|
elsif obj.is_a?(FalseClass)
|
200
83
|
amf3_write_false
|
201
84
|
elsif obj.is_a?(Numeric)
|
202
|
-
amf3_write_numeric
|
85
|
+
amf3_write_numeric(obj)
|
203
86
|
elsif obj.is_a?(Symbol) || obj.is_a?(String)
|
204
|
-
amf3_write_string
|
87
|
+
amf3_write_string(obj.to_s)
|
205
88
|
elsif obj.is_a?(Time)
|
206
89
|
amf3_write_time obj
|
207
90
|
elsif obj.is_a?(Date)
|
208
|
-
amf3_write_date
|
91
|
+
amf3_write_date(obj)
|
209
92
|
elsif obj.is_a?(StringIO)
|
210
|
-
amf3_write_byte_array
|
93
|
+
amf3_write_byte_array(obj)
|
211
94
|
elsif obj.is_a?(Array)
|
212
|
-
amf3_write_array
|
95
|
+
amf3_write_array(obj)
|
213
96
|
elsif obj.is_a?(Hash) || obj.is_a?(Object)
|
214
|
-
amf3_write_object
|
97
|
+
amf3_write_object(obj)
|
215
98
|
end
|
216
99
|
end
|
217
100
|
|
218
|
-
|
101
|
+
private
|
102
|
+
def amf3_write_reference(index)
|
219
103
|
header = index << 1 # shift value left to leave a low bit of 0
|
220
104
|
@stream << pack_integer(header)
|
221
105
|
end
|
222
106
|
|
107
|
+
private
|
223
108
|
def amf3_write_null
|
224
109
|
@stream << AMF3_NULL_MARKER
|
225
110
|
end
|
226
111
|
|
112
|
+
private
|
227
113
|
def amf3_write_true
|
228
114
|
@stream << AMF3_TRUE_MARKER
|
229
115
|
end
|
230
116
|
|
117
|
+
private
|
231
118
|
def amf3_write_false
|
232
119
|
@stream << AMF3_FALSE_MARKER
|
233
120
|
end
|
234
121
|
|
235
|
-
|
236
|
-
|
122
|
+
private
|
123
|
+
def amf3_write_numeric(value)
|
124
|
+
if !value.integer? || value < MIN_INTEGER || value > MAX_INTEGER # Check valid range for 29 bits
|
237
125
|
@stream << AMF3_DOUBLE_MARKER
|
238
|
-
@stream << pack_double(
|
126
|
+
@stream << pack_double(value)
|
239
127
|
else
|
240
128
|
@stream << AMF3_INTEGER_MARKER
|
241
|
-
@stream << pack_integer(
|
129
|
+
@stream << pack_integer(value)
|
242
130
|
end
|
243
131
|
end
|
244
132
|
|
245
|
-
|
133
|
+
private
|
134
|
+
def amf3_write_string(value)
|
246
135
|
@stream << AMF3_STRING_MARKER
|
247
|
-
amf3_write_utf8_vr
|
136
|
+
amf3_write_utf8_vr value
|
248
137
|
end
|
249
138
|
|
250
|
-
|
139
|
+
private
|
140
|
+
def amf3_write_time(value)
|
251
141
|
@stream << AMF3_DATE_MARKER
|
252
|
-
|
253
|
-
|
142
|
+
|
143
|
+
if @object_cache[value] != nil
|
144
|
+
amf3_write_reference(@object_cache[value])
|
254
145
|
else
|
255
146
|
# Cache time
|
256
|
-
@object_cache.add_obj
|
147
|
+
@object_cache.add_obj(value)
|
257
148
|
|
258
149
|
# Build AMF string
|
259
|
-
|
260
|
-
milli = (
|
150
|
+
value = value.getutc # Dup and convert to UTC
|
151
|
+
milli = (value.to_f * 1000).to_i
|
261
152
|
@stream << AMF3_NULL_MARKER
|
262
153
|
@stream << pack_double(milli)
|
263
154
|
end
|
264
155
|
end
|
265
156
|
|
266
|
-
|
157
|
+
private
|
158
|
+
def amf3_write_date(value)
|
267
159
|
@stream << AMF3_DATE_MARKER
|
268
|
-
|
269
|
-
|
160
|
+
|
161
|
+
if @object_cache[value] != nil
|
162
|
+
amf3_write_reference(@object_cache[value])
|
270
163
|
else
|
271
164
|
# Cache date
|
272
|
-
@object_cache.add_obj
|
165
|
+
@object_cache.add_obj(value)
|
273
166
|
|
274
167
|
# Build AMF string
|
275
168
|
@stream << AMF3_NULL_MARKER
|
276
|
-
@stream << pack_double(
|
169
|
+
@stream << pack_double(value.strftime('%Q').to_i)
|
277
170
|
end
|
278
171
|
end
|
279
172
|
|
280
|
-
|
173
|
+
private
|
174
|
+
def amf3_write_byte_array(value)
|
281
175
|
@stream << AMF3_BYTE_ARRAY_MARKER
|
282
|
-
|
283
|
-
|
176
|
+
|
177
|
+
if @object_cache[value] != nil
|
178
|
+
amf3_write_reference(@object_cache[value])
|
284
179
|
else
|
285
|
-
@object_cache.add_obj
|
286
|
-
str =
|
180
|
+
@object_cache.add_obj(value)
|
181
|
+
str = value.string
|
287
182
|
@stream << pack_integer(str.bytesize << 1 | 1)
|
288
183
|
@stream << str
|
289
184
|
end
|
290
185
|
end
|
291
186
|
|
292
|
-
|
187
|
+
private
|
188
|
+
def amf3_write_array(value)
|
293
189
|
# Is it an array collection?
|
294
|
-
|
295
|
-
|
296
|
-
|
190
|
+
is_array_collection = false
|
191
|
+
|
192
|
+
if value.respond_to?(:is_array_collection?)
|
193
|
+
is_array_collection = value.is_array_collection?
|
297
194
|
else
|
298
|
-
|
195
|
+
is_array_collection = @class_mapper.use_array_collection
|
299
196
|
end
|
300
197
|
|
301
198
|
# Write type marker
|
302
|
-
@stream << (
|
199
|
+
@stream << (is_array_collection ? AMF3_OBJECT_MARKER : AMF3_ARRAY_MARKER)
|
303
200
|
|
304
201
|
# Write reference or cache array
|
305
|
-
if @object_cache[
|
306
|
-
amf3_write_reference
|
202
|
+
if @object_cache[value] != nil
|
203
|
+
amf3_write_reference(@object_cache[value])
|
307
204
|
return
|
308
205
|
else
|
309
|
-
@object_cache.add_obj
|
310
|
-
@object_cache.add_obj
|
206
|
+
@object_cache.add_obj(value)
|
207
|
+
@object_cache.add_obj(nil) if is_array_collection # The array collection source array
|
311
208
|
end
|
312
209
|
|
313
210
|
# Write out traits and array marker if it's an array collection
|
314
|
-
if
|
315
|
-
class_name =
|
211
|
+
if is_array_collection
|
212
|
+
class_name = 'flex.messaging.io.ArrayCollection'
|
213
|
+
|
316
214
|
if @trait_cache[class_name] != nil
|
317
215
|
@stream << pack_integer(@trait_cache[class_name] << 2 | 0x01)
|
318
216
|
else
|
319
|
-
@trait_cache.add_obj
|
217
|
+
@trait_cache.add_obj(class_name)
|
320
218
|
@stream << "\a" # Externalizable, non-dynamic
|
321
219
|
amf3_write_utf8_vr(class_name)
|
322
220
|
end
|
@@ -324,43 +222,47 @@ module RocketAMF
|
|
324
222
|
end
|
325
223
|
|
326
224
|
# Build AMF string for array
|
327
|
-
header =
|
225
|
+
header = value.length << 1 # make room for a low bit of 1
|
328
226
|
header = header | 1 # set the low bit to 1
|
329
227
|
@stream << pack_integer(header)
|
330
228
|
@stream << AMF3_CLOSE_DYNAMIC_ARRAY
|
331
|
-
|
229
|
+
value.each do |elem|
|
332
230
|
amf3_serialize elem
|
333
231
|
end
|
334
232
|
end
|
335
233
|
|
336
|
-
|
234
|
+
private
|
235
|
+
def amf3_write_object(obj, properties = nil, traits = nil)
|
337
236
|
@stream << AMF3_OBJECT_MARKER
|
338
237
|
|
339
238
|
# Caching...
|
340
239
|
if @object_cache[obj] != nil
|
341
|
-
amf3_write_reference
|
240
|
+
amf3_write_reference(@object_cache[obj])
|
342
241
|
return
|
343
242
|
end
|
344
|
-
|
243
|
+
|
244
|
+
@object_cache.add_obj(obj)
|
345
245
|
|
346
246
|
# Calculate traits if not given
|
347
247
|
is_default = false
|
348
248
|
if traits.nil?
|
349
|
-
traits
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
249
|
+
traits =
|
250
|
+
{
|
251
|
+
class_name: @class_mapper.get_as_class_name(obj),
|
252
|
+
members: [],
|
253
|
+
externalizable: false,
|
254
|
+
dynamic: true
|
255
|
+
}
|
355
256
|
is_default = true unless traits[:class_name]
|
356
257
|
end
|
357
|
-
|
258
|
+
|
259
|
+
class_name = is_default ? '__default__' : traits[:class_name]
|
358
260
|
|
359
261
|
# Write out traits
|
360
262
|
if class_name && @trait_cache[class_name] != nil
|
361
263
|
@stream << pack_integer(@trait_cache[class_name] << 2 | 0x01)
|
362
264
|
else
|
363
|
-
@trait_cache.add_obj
|
265
|
+
@trait_cache.add_obj(class_name) if class_name
|
364
266
|
|
365
267
|
# Write out trait header
|
366
268
|
header = 0x03 # Not object ref and not trait ref
|
@@ -377,7 +279,7 @@ module RocketAMF
|
|
377
279
|
end
|
378
280
|
|
379
281
|
# Write out members
|
380
|
-
traits[:members].each {|m| amf3_write_utf8_vr(m)}
|
282
|
+
traits[:members].each { |m| amf3_write_utf8_vr(m) }
|
381
283
|
end
|
382
284
|
|
383
285
|
# If externalizable, take externalized data shortcut
|
@@ -387,20 +289,20 @@ module RocketAMF
|
|
387
289
|
end
|
388
290
|
|
389
291
|
# Extract properties if not given
|
390
|
-
|
292
|
+
properties = @class_mapper.props_for_serialization(obj) if properties.nil?
|
391
293
|
|
392
294
|
# Write out sealed properties
|
393
295
|
traits[:members].each do |m|
|
394
|
-
amf3_serialize
|
395
|
-
|
296
|
+
amf3_serialize(properties[m])
|
297
|
+
properties.delete(m)
|
396
298
|
end
|
397
299
|
|
398
300
|
# Write out dynamic properties
|
399
301
|
if traits[:dynamic]
|
400
302
|
# Write out dynamic properties
|
401
|
-
|
402
|
-
amf3_write_utf8_vr
|
403
|
-
amf3_serialize
|
303
|
+
properties.sort.each do |key, val| # Sort props until Ruby 1.9 becomes common
|
304
|
+
amf3_write_utf8_vr(key.to_s)
|
305
|
+
amf3_serialize(val)
|
404
306
|
end
|
405
307
|
|
406
308
|
# Write close
|
@@ -408,67 +310,32 @@ module RocketAMF
|
|
408
310
|
end
|
409
311
|
end
|
410
312
|
|
411
|
-
|
412
|
-
|
313
|
+
private
|
314
|
+
def amf3_write_utf8_vr(value, encode = true)
|
315
|
+
if value.respond_to?(:encode)
|
413
316
|
if encode
|
414
|
-
|
317
|
+
value = value.encode('UTF-8')
|
415
318
|
else
|
416
|
-
|
319
|
+
value = value.dup if value.frozen?
|
417
320
|
end
|
418
|
-
|
321
|
+
value.force_encoding('ASCII-8BIT')
|
419
322
|
end
|
420
323
|
|
421
|
-
if
|
324
|
+
if value == ''
|
422
325
|
@stream << AMF3_EMPTY_STRING
|
423
|
-
elsif @string_cache[
|
424
|
-
amf3_write_reference
|
326
|
+
elsif @string_cache[value] != nil
|
327
|
+
amf3_write_reference(@string_cache[value])
|
425
328
|
else
|
426
329
|
# Cache string
|
427
|
-
@string_cache.add_obj
|
330
|
+
@string_cache.add_obj(value)
|
428
331
|
|
429
332
|
# Build AMF string
|
430
|
-
@stream << pack_integer(
|
431
|
-
@stream <<
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
class SerializerCache #:nodoc:
|
437
|
-
def self.new type
|
438
|
-
if type == :string
|
439
|
-
StringCache.new
|
440
|
-
elsif type == :object
|
441
|
-
ObjectCache.new
|
333
|
+
@stream << pack_integer(value.bytesize << 1 | 1)
|
334
|
+
@stream << value
|
442
335
|
end
|
443
336
|
end
|
444
337
|
|
445
|
-
|
446
|
-
def initialize
|
447
|
-
@cache_index = 0
|
448
|
-
end
|
449
|
-
|
450
|
-
def add_obj str
|
451
|
-
self[str] = @cache_index
|
452
|
-
@cache_index += 1
|
453
|
-
end
|
454
|
-
end
|
338
|
+
end # Serializer
|
455
339
|
|
456
|
-
|
457
|
-
|
458
|
-
@cache_index = 0
|
459
|
-
@obj_references = []
|
460
|
-
end
|
461
|
-
|
462
|
-
def [] obj
|
463
|
-
super(obj.object_id)
|
464
|
-
end
|
465
|
-
|
466
|
-
def add_obj obj
|
467
|
-
@obj_references << obj
|
468
|
-
self[obj.object_id] = @cache_index
|
469
|
-
@cache_index += 1
|
470
|
-
end
|
471
|
-
end
|
472
|
-
end
|
473
|
-
end
|
474
|
-
end
|
340
|
+
end #Pure
|
341
|
+
end #RocketAMF
|