Class: RubyAMF::IO::AMFSerializer

Inherits:
Object
  • Object
show all
Includes:
Configuration, BinaryWriter, Constants, VoHelper
Defined in:
lib/revent/amf3/io/amf_serializer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAMFSerializer

Returns a new instance of AMFSerializer.



15
16
17
# File 'lib/revent/amf3/io/amf_serializer.rb', line 15

def initialize
  reset
end

Instance Attribute Details

#streamObject

Returns the value of attribute stream.



13
14
15
# File 'lib/revent/amf3/io/amf_serializer.rb', line 13

def stream
  @stream
end

Instance Method Details

#resetObject



19
20
21
22
# File 'lib/revent/amf3/io/amf_serializer.rb', line 19

def reset
  @stream = ''
  reset_referencables
end

#reset_referencablesObject



24
25
26
27
28
29
30
# File 'lib/revent/amf3/io/amf_serializer.rb', line 24

def reset_referencables
  @stored_strings = {} # hash is way faster than array
  @stored_strings[""] = true # add this in automatically
  @floats_cache = {} # for write_double at read_write.rb
  @write_amf3_integer_results = {} # cache the integers
  @current_strings_index = 0
end

#write_amf3(value) ⇒ Object



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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/revent/amf3/io/amf_serializer.rb', line 32

def write_amf3(value)
  if !value
    @stream << "\001" # represents an amf3 null

  elsif (value.is_a?(TrueClass) || value.is_a?(FalseClass))
    value ? (@stream << "\003")  : (@stream << "\002")   # represents an amf3 true  and  false

  elsif value.is_a?(Numeric)
    if value.is_a?(Integer) # Aryk: This was also incorrect before because you has Bignum check AFTER the Integer check, which means the Bignum's were getting picked up by Integers
      if value.is_a?(Bignum)
        @stream << "\005" # represents an amf3 complex number
        write_double(value)
      else
        write_amf3_number(value)
      end
    elsif value.is_a?(Float)
      @stream << "\005" # represents an amf3 complex number
      write_double(value)
    elsif value.is_a?(BigDecimal) # Aryk: BigDecimal does not relate to Float, so keep it as a seperate check.
      # TODO: Aryk: Not quite sure why you do value.to_s.to_f? can't you just do value.to_f?
      value = value.to_s('F').to_f #this is turning a string into a Ruby Float, but because there are no further operations on it it is safe          
      @stream << "\005" # represents an amf3 complex number
      write_double(value)
    end

  elsif value.is_a?(String)
    @stream << "\006" # represents an amf3 string
    write_amf3_string(value)

  elsif value.is_a?(Array)
    write_amf3_array(value)

  elsif value.is_a?(ByteArray)
    write_amf3_byte_array(value)

  elsif value.is_a?(Hash)
    write_amf3_object(value)

  elsif value.is_a?(Time) || value.is_a?(Date)
    @stream << "\b" # represents an amf3 date
    write_amf3_date(value)

    # I know we can combine this with the last condition, but don't  ; the Rexml and Beautiful Soup test is expensive, and for large record sets with many AR its better to be able to skip the next step
  elsif value.is_a?(ActiveRecord::Base) # Aryk: this way, we can bypass the "['REXML::Document', 'BeautifulSoup'].include?(value.class.to_s) " operation
    write_amf3_object(VoUtil.get_vo_hash_for_outgoing(value))

  elsif ['REXML::Document', 'BeautifulSoup'].include?(value.class.to_s) 
    write_byte(AMF3_XML)
    write_amf3_xml(value)

  elsif value.is_a?(Object)
    write_amf3_object(VoUtil.get_vo_hash_for_outgoing(value) )
  end
end

#write_amf3_array(array) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/revent/amf3/io/amf_serializer.rb', line 152

def write_amf3_array(array)
  num_objects = array.length * 2 + 1
  if ClassMappings.use_array_collection
    @stream << "\n\a" # AMF3_OBJECT and AMF3_XML
    write_amf3_string("flex.messaging.io.ArrayCollection")
  end
  @stream << "\t" # represents an amf3 array
  write_amf3_integer(num_objects)
  @stream << "\001" # represents an amf3 empty string #write empty for string keyed elements here, as it's never allowed from ruby
  array.each{|v| write_amf3(v) }
end

#write_amf3_byte_array(byte_array) ⇒ Object



177
178
179
180
181
182
183
184
# File 'lib/revent/amf3/io/amf_serializer.rb', line 177

def write_amf3_byte_array(byte_array)
  write_word8(AMF3_BYTE_ARRAY)
  bytes = byte_array.bytes
  length = bytes.length << 1
  length = length | 0x1
  write_amf3_integer(length)
  @stream << bytes
end

#write_amf3_date(datetime) ⇒ Object

Aryk: Dates will almost never be the same, so turn off the storing_objects



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/revent/amf3/io/amf_serializer.rb', line 164

def write_amf3_date(datetime) # Aryk: Dates will almost never be the same, so turn off the storing_objects
  write_amf3_integer(1)
  seconds = if datetime.is_a?(Time)
    datetime.utc unless datetime.utc?
    datetime.to_f
  elsif datetime.is_a?(Date) # this also handles the case for DateTime
    datetime.strftime("%s").to_i
    # datetime = Time.gm( datetime.year, datetime.month, datetime.day )
    # datetime = Time.gm( datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec )      
  end
  write_double((seconds*1000).to_i) # used to be total_milliseconds = datetime.to_i * 1000 + ( datetime.usec/1000 )
end

#write_amf3_integer(int) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/revent/amf3/io/amf_serializer.rb', line 87

def write_amf3_integer(int)
  @stream << (@write_amf3_integer_results[int] ||= (
      int = int & 0x1fffffff
      if int < 0x80
        [int].pack('c')
      elsif int < 0x4000
        [int >> 7 & 0x7f | 0x80].pack('c') +
          [int & 0x7f].pack('c')
      elsif int < 0x200000
        [int >> 14 & 0x7f | 0x80].pack('c') +
          [int >> 7 & 0x7f | 0x80].pack('c') +
          [int & 0x7f].pack('c')
      else
        [int >> 22 & 0x7f | 0x80].pack('c') +
          [int >> 15 & 0x7f | 0x80].pack('c') +
          [int >> 8 & 0x7f | 0x80].pack('c') +
          [int & 0xff].pack('c')
      end
    ))
end

#write_amf3_number(number) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'lib/revent/amf3/io/amf_serializer.rb', line 108

def write_amf3_number(number)
  if(number >= AMF3_INTEGER_MIN && number <= AMF3_INTEGER_MAX) #check valid range for 29bits
    @stream << "\004" # represents an amf3 integer
    write_amf3_integer(number)
  else #overflow condition otherwise
    @stream << "\005" # represents an amf3 complex number
    write_double(number)
  end
end

#write_amf3_object(hash) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/revent/amf3/io/amf_serializer.rb', line 137

def write_amf3_object(hash)   
  not_vo_hash = !hash.is_a?(VoHash) # is this not a vohash - then doesnt have an _explicitType parameter
  @stream << "\n\v" # represents an amf3 object and dynamic object  
  not_vo_hash || !hash._explicitType ? (@stream << "\001") : write_amf3_string(hash._explicitType)
  hash.each do |attr, value| # Aryk: no need to remove any "_explicitType" or "rmember" key since they werent added as keys
    if not_vo_hash # then that means that the attr might not be symbols and it hasn't gone through camelizing if thats needed
      attr = attr.to_s.dup # need this just in case its frozen
      attr.to_camel! if ClassMappings.translate_case 
    end
    write_amf3_string(attr) 
    value ? write_amf3(value) : (@stream << "\001") # represents an amf3 null
  end        
  @stream << "\001" # represents an amf3 empty string #close open object
end

#write_amf3_string(string) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/revent/amf3/io/amf_serializer.rb', line 118

def write_amf3_string(string)
  if index = @stored_strings[string]
    if string == "" # store this initially so it gets caught by the stored_strings check
      @stream << "\001" # represents an amf3 empty string
    else
      reference = index << 1
      write_amf3_integer(reference)
    end
  else
    @stored_strings[string] = @current_strings_index
    @current_strings_index += 1 # increment the index
    reference = string.length
    reference = reference << 1
    reference = reference | 1
    write_amf3_integer(reference)
    writen(string)
  end
end

#write_amf3_xml(value) ⇒ Object



186
187
188
189
190
191
192
193
194
195
# File 'lib/revent/amf3/io/amf_serializer.rb', line 186

def write_amf3_xml(value)
  xml = value.to_s
  a = xml.strip
  if(a != nil)
    b = a.gsub!(/\>(\n|\r|\r\n| |\t)*\</,'><') #clean whitespace
  else
    b = xml.gsub!(/\>(\n|\r|\r\n| |\t)*\</,'><') #clean whitespace
  end
  write_amf3_string(b)
end