rack-amf 0.0.4 → 1.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.
Files changed (78) hide show
  1. data/README.rdoc +18 -9
  2. data/Rakefile +23 -38
  3. data/lib/rack/amf/environment.rb +5 -8
  4. data/lib/rack/amf/middleware/pass_through.rb +5 -4
  5. data/lib/rack/amf/middleware/service_manager.rb +11 -3
  6. data/lib/rack/amf/middleware.rb +2 -1
  7. data/lib/rack/amf/request.rb +3 -16
  8. data/lib/rack/amf/response.rb +8 -67
  9. data/lib/rack/amf.rb +41 -1
  10. data/spec/{rack/service_manager_spec.rb → service_manager_spec.rb} +1 -2
  11. data/spec/spec.opts +2 -1
  12. data/spec/spec_helper.rb +1 -24
  13. metadata +19 -84
  14. data/lib/amf/class_mapping.rb +0 -211
  15. data/lib/amf/common.rb +0 -28
  16. data/lib/amf/constants.rb +0 -47
  17. data/lib/amf/pure/deserializer.rb +0 -361
  18. data/lib/amf/pure/io_helpers.rb +0 -94
  19. data/lib/amf/pure/remoting.rb +0 -120
  20. data/lib/amf/pure/serializer.rb +0 -327
  21. data/lib/amf/pure.rb +0 -14
  22. data/lib/amf/values/array_collection.rb +0 -9
  23. data/lib/amf/values/messages.rb +0 -133
  24. data/lib/amf/values/typed_hash.rb +0 -13
  25. data/lib/amf/version.rb +0 -9
  26. data/lib/amf.rb +0 -17
  27. data/spec/amf/class_mapping_set_spec.rb +0 -34
  28. data/spec/amf/class_mapping_spec.rb +0 -120
  29. data/spec/amf/deserializer_spec.rb +0 -311
  30. data/spec/amf/remoting_spec.rb +0 -51
  31. data/spec/amf/serializer_spec.rb +0 -328
  32. data/spec/amf/values/array_collection_spec.rb +0 -6
  33. data/spec/amf/values/messages_spec.rb +0 -31
  34. data/spec/fixtures/objects/amf0-boolean.bin +0 -1
  35. data/spec/fixtures/objects/amf0-date.bin +0 -0
  36. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  37. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  38. data/spec/fixtures/objects/amf0-null.bin +0 -1
  39. data/spec/fixtures/objects/amf0-number.bin +0 -0
  40. data/spec/fixtures/objects/amf0-object.bin +0 -0
  41. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  42. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  43. data/spec/fixtures/objects/amf0-string.bin +0 -0
  44. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  45. data/spec/fixtures/objects/amf0-undefined.bin +0 -1
  46. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  47. data/spec/fixtures/objects/amf3-0.bin +0 -0
  48. data/spec/fixtures/objects/amf3-arrayRef.bin +0 -1
  49. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  50. data/spec/fixtures/objects/amf3-date.bin +0 -0
  51. data/spec/fixtures/objects/amf3-datesRef.bin +0 -0
  52. data/spec/fixtures/objects/amf3-dynObject.bin +0 -2
  53. data/spec/fixtures/objects/amf3-emptyArray.bin +0 -1
  54. data/spec/fixtures/objects/amf3-emptyArrayRef.bin +0 -1
  55. data/spec/fixtures/objects/amf3-emptyStringRef.bin +0 -1
  56. data/spec/fixtures/objects/amf3-false.bin +0 -1
  57. data/spec/fixtures/objects/amf3-graphMember.bin +0 -0
  58. data/spec/fixtures/objects/amf3-hash.bin +0 -2
  59. data/spec/fixtures/objects/amf3-largeMax.bin +0 -0
  60. data/spec/fixtures/objects/amf3-largeMin.bin +0 -0
  61. data/spec/fixtures/objects/amf3-max.bin +0 -1
  62. data/spec/fixtures/objects/amf3-min.bin +0 -0
  63. data/spec/fixtures/objects/amf3-mixedArray.bin +0 -11
  64. data/spec/fixtures/objects/amf3-null.bin +0 -1
  65. data/spec/fixtures/objects/amf3-objRef.bin +0 -0
  66. data/spec/fixtures/objects/amf3-primArray.bin +0 -1
  67. data/spec/fixtures/objects/amf3-string.bin +0 -1
  68. data/spec/fixtures/objects/amf3-stringRef.bin +0 -0
  69. data/spec/fixtures/objects/amf3-symbol.bin +0 -1
  70. data/spec/fixtures/objects/amf3-true.bin +0 -1
  71. data/spec/fixtures/objects/amf3-typedObject.bin +0 -2
  72. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  73. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  74. data/spec/fixtures/request/commandMessage.bin +0 -0
  75. data/spec/fixtures/request/remotingMessage.bin +0 -0
  76. data/spec/fixtures/request/simple-response.bin +0 -0
  77. data/spec/rack/request_spec.rb +0 -6
  78. data/spec/rack/response_spec.rb +0 -47
@@ -1,211 +0,0 @@
1
- require 'amf/values/typed_hash'
2
- require 'amf/values/array_collection'
3
- require 'amf/values/messages'
4
-
5
- module AMF
6
- # == Class Mapping
7
- #
8
- # Handles class name mapping between actionscript and ruby and assists in
9
- # serializing and deserializing data between them. Simply map an AS class to a
10
- # ruby class and when the object is (de)serialized it will end up as the
11
- # appropriate class.
12
- #
13
- # Example:
14
- #
15
- # AMF::ClassMapper.define do |m|
16
- # m.map :as => 'AsClass', :ruby => 'RubyClass'
17
- # m.map :as => 'vo.User', :ruby => 'User'
18
- # end
19
- #
20
- # == Object Population/Serialization
21
- #
22
- # In addition to handling class name mapping, it also provides helper methods
23
- # for populating ruby objects from AMF and extracting properties from ruby objects
24
- # for serialization. Support for hash-like objects and objects using
25
- # <tt>attr_accessor</tt> for properties is currently built in, but custom classes
26
- # may need custom support. As such, it is possible to create a custom populator
27
- # or serializer.
28
- #
29
- # Populators are processed in insert order and must respond to the <tt>can_handle?</tt>
30
- # and <tt>populate</tt> methods.
31
- #
32
- # Example:
33
- #
34
- # class CustomPopulator
35
- # def can_handle? obj
36
- # true
37
- # end
38
- #
39
- # def populate obj, props, dynamic_props
40
- # obj.merge! props
41
- # obj.merge!(dynamic_props) if dynamic_props
42
- # end
43
- # end
44
- # AMF::ClassMapper.object_populators << CustomPopulator.new
45
- #
46
- # Serializers are also processed in insert order and must respond to the
47
- # <tt>can_handle?</tt> and <tt>serialize</tt> methods.
48
- #
49
- # Example:
50
- #
51
- # class CustomSerializer
52
- # def can_handle? obj
53
- # true
54
- # end
55
- #
56
- # def serialize obj
57
- # {}
58
- # end
59
- # end
60
- # AMF::ClassMapper.object_serializers << CustomSerializer.new
61
- class ClassMapping
62
- # Container for all mapped classes
63
- class MappingSet
64
- def initialize #:nodoc:
65
- @as_mappings = {}
66
- @ruby_mappings = {}
67
-
68
- # Map defaults
69
- map :as => 'flex.messaging.messages.AbstractMessage', :ruby => 'AMF::Values::AbstractMessage'
70
- map :as => 'flex.messaging.messages.RemotingMessage', :ruby => 'AMF::Values::RemotingMessage'
71
- map :as => 'flex.messaging.messages.AsyncMessage', :ruby => 'AMF::Values::AsyncMessage'
72
- map :as => 'flex.messaging.messages.CommandMessage', :ruby => 'AMF::Values::CommandMessage'
73
- map :as => 'flex.messaging.messages.AcknowledgeMessage', :ruby => 'AMF::Values::AcknowledgeMessage'
74
- map :as => 'flex.messaging.messages.ErrorMessage', :ruby => 'AMF::Values::ErrorMessage'
75
- map :as => 'flex.messaging.io.ArrayCollection', :ruby => 'AMF::Values::ArrayCollection'
76
- end
77
-
78
- # Map a given AS class to a ruby class.
79
- #
80
- # Use fully qualified names for both.
81
- #
82
- # Example:
83
- #
84
- # m.map :as 'com.example.Date', :ruby => 'Example::Date'
85
- def map params
86
- [:as, :ruby].each {|k| params[k] = params[k].to_s} # Convert params to strings
87
- @as_mappings[params[:as]] = params[:ruby]
88
- @ruby_mappings[params[:ruby]] = params[:as]
89
- end
90
-
91
- # Returns the AS class name for the given ruby class name, returing nil if
92
- # not found
93
- def get_as_class_name class_name #:nodoc:
94
- @ruby_mappings[class_name.to_s]
95
- end
96
-
97
- # Returns the ruby class name for the given AS class name, returing nil if
98
- # not found
99
- def get_ruby_class_name class_name #:nodoc:
100
- @as_mappings[class_name.to_s]
101
- end
102
- end
103
-
104
- # Array of custom object populators.
105
- attr_reader :object_populators
106
-
107
- # Array of custom object serializers.
108
- attr_reader :object_serializers
109
-
110
- def initialize #:nodoc:
111
- @object_populators = []
112
- @object_serializers = []
113
- end
114
-
115
- # Define class mappings in the block. Block is passed a MappingSet object as
116
- # the first parameter.
117
- #
118
- # Example:
119
- #
120
- # AMF::ClassMapper.define do |m|
121
- # m.map :as => 'AsClass', :ruby => 'RubyClass'
122
- # end
123
- def define #:yields: mapping_set
124
- yield mappings
125
- end
126
-
127
- # Returns the AS class name for the given ruby object. Will also take a string
128
- # containing the ruby class name
129
- def get_as_class_name obj
130
- # Get class name
131
- if obj.is_a?(String)
132
- ruby_class_name = obj
133
- elsif obj.is_a?(Values::TypedHash)
134
- ruby_class_name = obj.type
135
- else
136
- ruby_class_name = obj.class.name
137
- end
138
-
139
- # Get mapped AS class name
140
- mappings.get_as_class_name ruby_class_name
141
- end
142
-
143
- # Instantiates a ruby object using the mapping configuration based on the
144
- # source AS class name. If there is no mapping defined, it returns a hash.
145
- def get_ruby_obj as_class_name
146
- ruby_class_name = mappings.get_ruby_class_name as_class_name
147
- if ruby_class_name.nil?
148
- # Populate a simple hash, since no mapping
149
- return Values::TypedHash.new(as_class_name)
150
- else
151
- ruby_class = ruby_class_name.split('::').inject(Kernel) {|scope, const_name| scope.const_get(const_name)}
152
- return ruby_class.new
153
- end
154
- end
155
-
156
- # Populates the ruby object using the given properties
157
- def populate_ruby_obj obj, props, dynamic_props=nil
158
- # Process custom populators
159
- @object_populators.each do |p|
160
- next unless p.can_handle?(obj)
161
- p.populate obj, props, dynamic_props
162
- return obj
163
- end
164
-
165
- # Fallback populator
166
- props.merge! dynamic_props if dynamic_props
167
- hash_like = obj.respond_to?("[]=")
168
- props.each do |key, value|
169
- if obj.respond_to?("#{key}=")
170
- obj.send("#{key}=", value)
171
- elsif hash_like
172
- obj[key.to_sym] = value
173
- end
174
- end
175
- obj
176
- end
177
-
178
- # Extracts all exportable properties from the given ruby object and returns
179
- # them in a hash
180
- def props_for_serialization ruby_obj
181
- # Proccess custom serializers
182
- @object_serializers.each do |s|
183
- next unless s.can_handle?(ruby_obj)
184
- return s.serialize(ruby_obj)
185
- end
186
-
187
- # Handle hashes
188
- if ruby_obj.is_a?(Hash)
189
- # Stringify keys to make it easier later on and allow sorting
190
- h = {}
191
- ruby_obj.each {|k,v| h[k.to_s] = v}
192
- return h
193
- end
194
-
195
- # Fallback serializer
196
- props = {}
197
- @ignored_props ||= Object.new.public_methods
198
- (ruby_obj.public_methods - @ignored_props).each do |method_name|
199
- # Add them to the prop hash if they take no arguments
200
- method_def = ruby_obj.method(method_name)
201
- props[method_name] = ruby_obj.send(method_name) if method_def.arity == 0
202
- end
203
- props
204
- end
205
-
206
- private
207
- def mappings
208
- @mappings ||= MappingSet.new
209
- end
210
- end
211
- end
data/lib/amf/common.rb DELETED
@@ -1,28 +0,0 @@
1
- module AMF
2
- class << self
3
- # Deserialize the AMF string _source_ into a Ruby data structure and return it.
4
- def deserialize source, amf_version = 0
5
- if amf_version == 0
6
- AMF::Deserializer.new.deserialize(source)
7
- elsif amf_version == 3
8
- AMF::AMF3Deserializer.new.deserialize(source)
9
- else
10
- raise AMFError, "unsupported version #{amf_version}"
11
- end
12
- end
13
-
14
- # Serialize the given Ruby data structure _obj_ into an AMF stream
15
- def serialize obj, amf_version = 0
16
- if amf_version == 0
17
- AMF::Serializer.new.serialize(obj)
18
- elsif amf_version == 3
19
- AMF::AMF3Serializer.new.serialize(obj)
20
- else
21
- raise AMFError, "unsupported version #{amf_version}"
22
- end
23
- end
24
- end
25
-
26
- # The base exception for AMF errors.
27
- class AMFError < StandardError; end
28
- end
data/lib/amf/constants.rb DELETED
@@ -1,47 +0,0 @@
1
- module AMF
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
-
37
- # Other AMF3 Markers
38
- AMF3_EMPTY_STRING = 0x01
39
- AMF3_ANONYMOUS_OBJECT = 0x01
40
- AMF3_DYNAMIC_OBJECT = 0x0B
41
- AMF3_CLOSE_DYNAMIC_OBJECT = 0x01
42
- AMF3_CLOSE_DYNAMIC_ARRAY = 0x01
43
-
44
- # Other Constants
45
- MAX_INTEGER = 268435455
46
- MIN_INTEGER = -268435456
47
- end
@@ -1,361 +0,0 @@
1
- require 'amf/pure/io_helpers'
2
-
3
- module AMF
4
- module Pure
5
- # Pure ruby deserializer
6
- #--
7
- # AMF0 deserializer, it switches over to AMF3 when it sees the switch flag
8
- class Deserializer
9
- def initialize
10
- @ref_cache = []
11
- end
12
-
13
- def deserialize(source, type=nil)
14
- source = StringIO.new(source) unless StringIO === source
15
- type = read_int8 source unless type
16
- case type
17
- when AMF0_NUMBER_MARKER
18
- read_number source
19
- when AMF0_BOOLEAN_MARKER
20
- read_boolean source
21
- when AMF0_STRING_MARKER
22
- read_string source
23
- when AMF0_OBJECT_MARKER
24
- read_object source
25
- when AMF0_NULL_MARKER
26
- nil
27
- when AMF0_UNDEFINED_MARKER
28
- nil
29
- when AMF0_REFERENCE_MARKER
30
- read_reference source
31
- when AMF0_HASH_MARKER
32
- read_hash source
33
- when AMF0_STRICT_ARRAY_MARKER
34
- read_array source
35
- when AMF0_DATE_MARKER
36
- read_date source
37
- when AMF0_LONG_STRING_MARKER
38
- read_string source, true
39
- when AMF0_UNSUPPORTED_MARKER
40
- nil
41
- when AMF0_XML_MARKER
42
- #read_xml source
43
- when AMF0_TYPED_OBJECT_MARKER
44
- read_typed_object source
45
- when AMF0_AMF3_MARKER
46
- AMF3Deserializer.new.deserialize(source)
47
- end
48
- end
49
-
50
- private
51
- include AMF::Pure::ReadIOHelpers
52
-
53
- def read_number source
54
- res = read_double source
55
- res.is_a?(Float)&&res.nan? ? nil : res # check for NaN and convert them to nil
56
- end
57
-
58
- def read_boolean source
59
- read_int8(source) != 0
60
- end
61
-
62
- def read_string source, long=false
63
- len = long ? read_word32_network(source) : read_word16_network(source)
64
- source.read(len)
65
- end
66
-
67
- def read_object source, add_to_ref_cache=true
68
- obj = {}
69
- @ref_cache << obj if add_to_ref_cache
70
- while true
71
- key = read_string source
72
- type = read_int8 source
73
- break if type == AMF0_OBJECT_END_MARKER
74
- obj[key.to_sym] = deserialize(source, type)
75
- end
76
- obj
77
- end
78
-
79
- def read_reference source
80
- index = read_word16_network(source)
81
- @ref_cache[index]
82
- end
83
-
84
- def read_hash source
85
- len = read_word32_network(source) # Read and ignore length
86
-
87
- # Read first pair
88
- key = read_string source
89
- type = read_int8 source
90
- return [] if type == AMF0_OBJECT_END_MARKER
91
-
92
- # We need to figure out whether this is a real hash, or whether some stupid serializer gave up
93
- if key.to_i.to_s == key
94
- # Array
95
- obj = []
96
- @ref_cache << obj
97
-
98
- obj[key.to_i] = deserialize(source, type)
99
- while true
100
- key = read_string source
101
- type = read_int8 source
102
- break if type == AMF0_OBJECT_END_MARKER
103
- obj[key.to_i] = deserialize(source, type)
104
- end
105
- else
106
- # Hash
107
- obj = {}
108
- @ref_cache << obj
109
-
110
- obj[key.to_sym] = deserialize(source, type)
111
- while true
112
- key = read_string source
113
- type = read_int8 source
114
- break if type == AMF0_OBJECT_END_MARKER
115
- obj[key.to_sym] = deserialize(source, type)
116
- end
117
- end
118
- obj
119
- end
120
-
121
- def read_array source
122
- len = read_word32_network(source)
123
- array = []
124
- @ref_cache << array
125
-
126
- 0.upto(len - 1) do
127
- array << deserialize(source)
128
- end
129
- array
130
- end
131
-
132
- def read_date source
133
- seconds = read_double(source).to_f/1000
134
- time = Time.at(seconds)
135
- tz = read_word16_network(source) # Unused
136
- time
137
- end
138
-
139
- def read_typed_object source
140
- # Create object to add to ref cache
141
- class_name = read_string source
142
- obj = ClassMapper.get_ruby_obj class_name
143
- @ref_cache << obj
144
-
145
- # Read object props
146
- props = read_object source, false
147
-
148
- # Populate object
149
- ClassMapper.populate_ruby_obj obj, props, {}
150
- return obj
151
- end
152
- end
153
-
154
- # AMF3 implementation of deserializer, loaded automatically by the AMF0
155
- # deserializer when needed
156
- class AMF3Deserializer
157
- def initialize
158
- @string_cache = []
159
- @object_cache = []
160
- @trait_cache = []
161
- end
162
-
163
- def deserialize(source, type=nil)
164
- source = StringIO.new(source) unless StringIO === source
165
- type = read_int8 source unless type
166
- case type
167
- when AMF3_UNDEFINED_MARKER
168
- nil
169
- when AMF3_NULL_MARKER
170
- nil
171
- when AMF3_FALSE_MARKER
172
- false
173
- when AMF3_TRUE_MARKER
174
- true
175
- when AMF3_INTEGER_MARKER
176
- read_integer source
177
- when AMF3_DOUBLE_MARKER
178
- read_number source
179
- when AMF3_STRING_MARKER
180
- read_string source
181
- when AMF3_XML_DOC_MARKER
182
- #read_xml_string
183
- when AMF3_DATE_MARKER
184
- read_date source
185
- when AMF3_ARRAY_MARKER
186
- read_array source
187
- when AMF3_OBJECT_MARKER
188
- read_object source
189
- when AMF3_XML_MARKER
190
- #read_amf3_xml
191
- when AMF3_BYTE_ARRAY_MARKER
192
- #read_amf3_byte_array
193
- end
194
- end
195
-
196
- private
197
- include AMF::Pure::ReadIOHelpers
198
-
199
- def read_integer source
200
- n = 0
201
- b = read_word8(source) || 0
202
- result = 0
203
-
204
- while ((b & 0x80) != 0 && n < 3)
205
- result = result << 7
206
- result = result | (b & 0x7f)
207
- b = read_word8(source) || 0
208
- n = n + 1
209
- end
210
-
211
- if (n < 3)
212
- result = result << 7
213
- result = result | b
214
- else
215
- #Use all 8 bits from the 4th byte
216
- result = result << 8
217
- result = result | b
218
-
219
- #Check if the integer should be negative
220
- if (result > MAX_INTEGER)
221
- result -= (1 << 29)
222
- end
223
- end
224
- result
225
- end
226
-
227
- def read_number source
228
- res = read_double source
229
- res.is_a?(Float)&&res.nan? ? nil : res # check for NaN and convert them to nil
230
- end
231
-
232
- def read_string source
233
- type = read_integer source
234
- isReference = (type & 0x01) == 0
235
-
236
- if isReference
237
- reference = type >> 1
238
- return @string_cache[reference]
239
- else
240
- length = type >> 1
241
- #HACK needed for ['',''] array of empty strings
242
- #It may be better to take one more parameter that
243
- #would specify whether or not they expect us to return
244
- #a string
245
- str = "" #if stringRequest
246
- if length > 0
247
- str = source.read(length)
248
- @string_cache << str
249
- end
250
- return str
251
- end
252
- end
253
-
254
- def read_array source
255
- type = read_integer source
256
- isReference = (type & 0x01) == 0
257
-
258
- if isReference
259
- reference = type >> 1
260
- return @object_cache[reference]
261
- else
262
- length = type >> 1
263
- propertyName = read_string source
264
- if propertyName != ""
265
- array = {}
266
- @object_cache << array
267
- begin
268
- while(propertyName.length)
269
- value = deserialize(source)
270
- array[propertyName] = value
271
- propertyName = read_string source
272
- end
273
- rescue Exception => e #end of object exception, because propertyName.length will be non existent
274
- end
275
- 0.upto(length - 1) do |i|
276
- array["" + i.to_s] = deserialize(source)
277
- end
278
- else
279
- array = []
280
- @object_cache << array
281
- 0.upto(length - 1) do
282
- array << deserialize(source)
283
- end
284
- end
285
- array
286
- end
287
- end
288
-
289
- def read_object source
290
- type = read_integer source
291
- isReference = (type & 0x01) == 0
292
-
293
- if isReference
294
- reference = type >> 1
295
- return @object_cache[reference]
296
- else
297
- class_type = type >> 1
298
- class_is_reference = (class_type & 0x01) == 0
299
-
300
- if class_is_reference
301
- reference = class_type >> 1
302
- class_definition = @trait_cache[reference]
303
- else
304
- class_name = read_string source
305
- externalizable = (class_type & 0x02) != 0
306
- dynamic = (class_type & 0x04) != 0
307
- attribute_count = class_type >> 3
308
-
309
- class_attributes = []
310
- attribute_count.times{class_attributes << read_string(source)} # Read class members
311
-
312
- class_definition = {"class_name" => class_name,
313
- "members" => class_attributes,
314
- "externalizable" => externalizable,
315
- "dynamic" => dynamic}
316
- @trait_cache << class_definition
317
- end
318
-
319
- obj = ClassMapper.get_ruby_obj class_definition["class_name"]
320
- @object_cache << obj
321
-
322
- if class_definition['externalizable']
323
- obj.externalized_data = deserialize(source)
324
- else
325
- props = {}
326
- class_definition['members'].each do |key|
327
- value = deserialize(source)
328
- props[key.to_sym] = value
329
- end
330
-
331
- dynamic_props = nil
332
- if class_definition['dynamic']
333
- dynamic_props = {}
334
- while (key = read_string source) && key.length != 0 do # read next key
335
- value = deserialize(source)
336
- dynamic_props[key.to_sym] = value
337
- end
338
- end
339
-
340
- ClassMapper.populate_ruby_obj obj, props, dynamic_props
341
- end
342
- obj
343
- end
344
- end
345
-
346
- def read_date source
347
- type = read_integer source
348
- isReference = (type & 0x01) == 0
349
- if isReference
350
- reference = type >> 1
351
- return @object_cache[reference]
352
- else
353
- seconds = read_double(source).to_f/1000
354
- time = Time.at(seconds)
355
- @object_cache << time
356
- time
357
- end
358
- end
359
- end
360
- end
361
- end