Class: RocketAMF::Pure::AMF3Serializer

Inherits:
Object
  • Object
show all
Includes:
WriteIOHelpers
Defined in:
lib/rocketamf/pure/serializer.rb

Overview

AMF3 implementation of serializer

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from WriteIOHelpers

#byte_order, #byte_order_little?, #pack_double, #pack_int16_network, #pack_int8, #pack_integer, #pack_word32_network

Constructor Details

#initializeAMF3Serializer

Returns a new instance of AMF3Serializer.



137
138
139
140
141
# File 'lib/rocketamf/pure/serializer.rb', line 137

def initialize
  @string_cache = SerializerCache.new :string
  @object_cache = SerializerCache.new :object
  @trait_cache = SerializerCache.new :trait
end

Instance Attribute Details

#string_cacheObject (readonly)

Returns the value of attribute string_cache.



135
136
137
# File 'lib/rocketamf/pure/serializer.rb', line 135

def string_cache
  @string_cache
end

Instance Method Details

#serialize(obj, stream = "") ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/rocketamf/pure/serializer.rb', line 147

def serialize obj, stream = ""
  if obj.respond_to?(:to_amf)
    stream << obj.to_amf(self)
  elsif obj.is_a?(NilClass)
    write_null stream
  elsif obj.is_a?(TrueClass)
    write_true stream
  elsif obj.is_a?(FalseClass)
    write_false stream
  elsif obj.is_a?(Float)
    write_float obj, stream
  elsif obj.is_a?(Integer)
    write_integer obj, stream
  elsif obj.is_a?(Symbol) || obj.is_a?(String)
    write_string obj.to_s, stream
  elsif obj.is_a?(Time)
    write_date obj, stream
  elsif obj.is_a?(StringIO)
    write_byte_array obj, stream
  elsif obj.is_a?(RocketAMF::Values::ArrayCollection)
    write_array_collection obj, stream
  elsif obj.is_a?(Array)
    write_array obj, stream
  elsif obj.is_a?(Hash) || obj.is_a?(Object)
    write_object obj, stream
  end
  stream
end

#versionObject



143
144
145
# File 'lib/rocketamf/pure/serializer.rb', line 143

def version
  3
end

#write_array(array, stream) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/rocketamf/pure/serializer.rb', line 242

def write_array array, stream
  stream << AMF3_ARRAY_MARKER
  if @object_cache[array] != nil
    write_reference @object_cache[array], stream
  else
    # Cache array
    @object_cache.add_obj array

    # Build AMF string
    header = array.length << 1 # make room for a low bit of 1
    header = header | 1 # set the low bit to 1
    stream << pack_integer(header)
    stream << AMF3_CLOSE_DYNAMIC_ARRAY
    array.each do |elem|
      serialize elem, stream
    end
  end
end

#write_array_collection(array, stream) ⇒ Object



238
239
240
# File 'lib/rocketamf/pure/serializer.rb', line 238

def write_array_collection array, stream
  write_object array, stream, {:class_name => RocketAMF::ClassMapper.get_as_class_name(array), :members => [], :externalizable => true, :dynamic => false}
end

#write_byte_array(array, stream) ⇒ Object



228
229
230
231
232
233
234
235
236
# File 'lib/rocketamf/pure/serializer.rb', line 228

def write_byte_array array, stream
  stream << AMF3_BYTE_ARRAY_MARKER
  if @object_cache[array] != nil
    write_reference @object_cache[array], stream
  else
    @object_cache.add_obj array
    write_utf8_vr array.string, stream
  end
end

#write_date(date, stream) ⇒ Object



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/rocketamf/pure/serializer.rb', line 212

def write_date date, stream
  stream << AMF3_DATE_MARKER
  if @object_cache[date] != nil
    write_reference @object_cache[date], stream
  else
    # Cache date
    @object_cache.add_obj date

    # Build AMF string
    date.utc unless date.utc?
    seconds = (date.to_f * 1000).to_i
    stream << pack_integer(AMF3_NULL_MARKER)
    stream << pack_double(seconds)
  end
end

#write_false(stream) ⇒ Object



189
190
191
# File 'lib/rocketamf/pure/serializer.rb', line 189

def write_false stream
  stream << AMF3_FALSE_MARKER
end

#write_float(float, stream) ⇒ Object



202
203
204
205
# File 'lib/rocketamf/pure/serializer.rb', line 202

def write_float float, stream
  stream << AMF3_DOUBLE_MARKER
  stream << pack_double(float)
end

#write_integer(int, stream) ⇒ Object



193
194
195
196
197
198
199
200
# File 'lib/rocketamf/pure/serializer.rb', line 193

def write_integer int, stream
  if int < MIN_INTEGER || int > MAX_INTEGER # Check valid range for 29 bits
    write_float int.to_f, stream
  else
    stream << AMF3_INTEGER_MARKER
    stream << pack_integer(int)
  end
end

#write_null(stream) ⇒ Object



181
182
183
# File 'lib/rocketamf/pure/serializer.rb', line 181

def write_null stream
  stream << AMF3_NULL_MARKER
end

#write_object(obj, stream, traits = nil) ⇒ Object



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/rocketamf/pure/serializer.rb', line 261

def write_object obj, stream, traits=nil
  stream << AMF3_OBJECT_MARKER
  if @object_cache[obj] != nil
    write_reference @object_cache[obj], stream
  else
    # Cache object
    @object_cache.add_obj obj

    # Calculate traits if not given
    if traits.nil?
      traits = {
                :class_name => RocketAMF::ClassMapper.get_as_class_name(obj),
                :members => [],
                :externalizable => false,
                :dynamic => true
               }
    end

    # Write out traits
    if traits[:class_name] && @trait_cache[traits] != nil
      stream << pack_integer(@trait_cache[traits] << 2 | 0x01)
    else
      @trait_cache.add_obj traits if traits[:class_name]

      # Write out trait header
      header = 0x03 # Not object ref and not trait ref
      header |= 0x02 << 2 if traits[:dynamic]
      header |= 0x01 << 2 if traits[:externalizable]
      header |= traits[:members].length << 4
      stream << pack_integer(header)

      # Write out class name
      write_utf8_vr(traits[:class_name].to_s, stream)

      # Write out members
      traits[:members].each {|m| write_utf8_vr(m, stream)}
    end

    # If externalizable, take externalized data shortcut
    if traits[:externalizable]
      serialize obj.externalized_data, stream
      return
    end

    # Write out sealed properties
    props = RocketAMF::ClassMapper.props_for_serialization obj
    traits[:members].each do |m|
      serialize props[m], stream
      props.delete(m)
    end

    if traits[:dynamic]
      # Write out dynamic properties
      props.sort.each do |key, val| # Sort props until Ruby 1.9 becomes common
        write_utf8_vr key.to_s, stream
        serialize val, stream
      end

      # Write close
      stream << AMF3_CLOSE_DYNAMIC_OBJECT
    end
  end
end

#write_reference(index, stream) ⇒ Object



176
177
178
179
# File 'lib/rocketamf/pure/serializer.rb', line 176

def write_reference index, stream
  header = index << 1 # shift value left to leave a low bit of 0
  stream << pack_integer(header)
end

#write_string(str, stream) ⇒ Object



207
208
209
210
# File 'lib/rocketamf/pure/serializer.rb', line 207

def write_string str, stream
  stream << AMF3_STRING_MARKER
  write_utf8_vr str, stream
end

#write_true(stream) ⇒ Object



185
186
187
# File 'lib/rocketamf/pure/serializer.rb', line 185

def write_true stream
  stream << AMF3_TRUE_MARKER
end