class AMF::Pure::Deserializer
Pure
ruby deserializer for AMF3 requests
Attributes
Used for read_object
Public Class Methods
Pass in the class mapper instance to use when deserializing. This enables better caching behavior in the class mapper and allows one to change mappings between deserialization attempts.
# File lib/amf/pure/deserializer.rb 25 def initialize(class_mapper) 26 @class_mapper = class_mapper 27 end
Public Instance Methods
Deserialize the source using AMF3. Source should either be a string or StringIO object. If you pass a StringIO object, it will have its position updated to the end of the deserialized data. raise AMFError
if error appeared in deserialize, source is nil raise AMFErrorIncomplete
if source is incomplete return hash {objects: [], incomplete_objects: String}
# File lib/amf/pure/deserializer.rb 37 def deserialize(source) 38 raise AMFError, 'no source to deserialize' if source.nil? 39 40 @source = source.is_a?(StringIO) ? source : StringIO.new(source) 41 42 objects = [] 43 44 incomplete_objects = nil 45 46 until @source.eof? 47 48 @cache_strings = [] 49 @cache_objects = [] 50 @cache_traits = [] 51 52 source_position = @source.pos 53 54 begin 55 objects << amf3_deserialize 56 rescue AMFErrorIncomplete, AMFError => e 57 58 @source.pos = source_position 59 60 incomplete_objects = @source.read 61 62 break 63 end 64 end 65 66 { 67 objects: objects, 68 incomplete_objects: incomplete_objects 69 } 70 end
Reads an object from the deserializer stream and returns it.
# File lib/amf/pure/deserializer.rb 74 def read_object 75 amf3_deserialize 76 end
Private Instance Methods
# File lib/amf/pure/deserializer.rb 79 def amf3_deserialize 80 type = read_int8(@source) 81 82 case type 83 when AMF3_MARKER_UNDEFINED 84 nil 85 when AMF3_MARKER_NULL 86 nil 87 when AMF3_MARKER_FALSE 88 false 89 when AMF3_MARKER_TRUE 90 true 91 when AMF3_MARKER_INTEGER 92 amf3_read_integer 93 when AMF3_MARKER_DOUBLE 94 amf3_read_number 95 when AMF3_MARKER_STRING 96 amf3_read_string 97 when AMF3_MARKER_DATE 98 amf3_read_date 99 when AMF3_MARKER_ARRAY 100 amf3_read_array 101 when AMF3_MARKER_OBJECT 102 amf3_read_object 103 when AMF3_MARKER_BYTE_ARRAY 104 amf3_read_byte_array 105 when AMF3_MARKER_VECTOR_INT, AMF3_MARKER_VECTOR_UINT, AMF3_MARKER_VECTOR_DOUBLE, AMF3_MARKER_VECTOR_OBJECT, AMF3_MARKER_XML_DOC, AMF3_MARKER_XML 106 raise AMFError, "Unsupported type: #{type}" 107 when AMF3_MARKER_DICTIONARY 108 amf3_read_dictionary 109 else 110 raise AMFError, "Invalid type: #{type}" 111 end 112 end
# File lib/amf/pure/deserializer.rb 226 def amf3_read_array 227 result = nil 228 229 type = amf3_read_integer 230 231 result = get_as_reference_object(type) 232 233 if result.nil? 234 length = type >> 1 235 property_name = amf3_read_string 236 result = property_name.length > 0 ? {} : [] 237 @cache_objects << result 238 239 while property_name.length > 0 240 value = amf3_deserialize 241 result[property_name] = value 242 property_name = amf3_read_string 243 end 244 245 0.upto(length - 1) { |i| result[i] = amf3_deserialize } 246 end 247 248 result 249 end
# File lib/amf/pure/deserializer.rb 308 def amf3_read_byte_array 309 result = nil 310 311 type = amf3_read_integer 312 313 result = get_as_reference_object(type) 314 315 if result.nil? 316 length = type >> 1 317 318 if length > (@source.size - @source.pos) 319 raise AMFErrorIncomplete.new 320 end 321 322 result = StringIO.new(@source.read(length)) 323 @cache_objects << result 324 end 325 326 result 327 end
# File lib/amf/pure/deserializer.rb 209 def amf3_read_date 210 result = nil 211 212 type = amf3_read_integer 213 214 result = get_as_reference_object(type) 215 216 if result.nil? 217 seconds = read_double(@source).to_f / 1000 218 result = Time.at(seconds) 219 @cache_objects << result 220 end 221 222 result 223 end
# File lib/amf/pure/deserializer.rb 330 def amf3_read_dictionary 331 result = nil 332 333 type = amf3_read_integer 334 335 result = get_as_reference_object(type) 336 337 if result.nil? 338 result = {} 339 @cache_objects << result 340 length = type >> 1 341 weak_keys = read_int8(@source) # Ignore: Not supported in ruby 342 343 0.upto(length - 1) do |i| 344 result[amf3_deserialize] = amf3_deserialize 345 end 346 347 end 348 349 result 350 end
# File lib/amf/pure/deserializer.rb 139 def amf3_read_integer 140 result = 0 141 142 n = 0 143 b = read_word8(@source) || 0 144 145 while (b & 0x80) != 0 && n < 3 146 result = result << 7 147 result = result | (b & 0x7f) 148 b = read_word8(@source) || 0 149 n = n + 1 150 end 151 152 if n < 3 153 result = result << 7 154 result = result | b 155 else 156 #Use all 8 bits from the 4th byte 157 result = result << 8 158 result = result | b 159 160 #Check if the integer should be negative 161 if result > INTEGER_MAX 162 result -= (1 << 29) 163 end 164 end 165 166 result 167 end
# File lib/amf/pure/deserializer.rb 170 def amf3_read_number 171 result = read_double(@source) 172 173 #check for NaN and convert them to nil 174 if result.is_a?(Float) && result.nan? 175 result = nil 176 end 177 178 result 179 end
dynamic - c an instance of a Class definition with the dynamic trait declared; public variable members can be added and removed from instances dynamically at runtime
# File lib/amf/pure/deserializer.rb 253 def amf3_read_object 254 result = nil 255 256 type = amf3_read_integer 257 258 result = get_as_reference_object(type) 259 260 if result.nil? 261 class_type = type >> 1 262 class_is_reference = (class_type & 0x01) == 0 263 264 if class_is_reference 265 reference = class_type >> 1 266 traits = @cache_traits[reference] 267 else 268 dynamic = (class_type & 0x04) != 0 269 attribute_count = class_type >> 3 270 class_name = amf3_read_string 271 272 class_attributes = [] 273 attribute_count.times { class_attributes << amf3_read_string } # Read class members 274 275 traits = 276 { 277 class_name: class_name, 278 members: class_attributes, 279 dynamic: dynamic 280 } 281 @cache_traits << traits 282 end 283 284 result = @class_mapper.create_object(traits[:class_name]) 285 @cache_objects << result 286 287 properties = {} 288 289 traits[:members].each do |key| 290 value = amf3_deserialize 291 properties[key] = value 292 end 293 294 if traits[:dynamic] 295 while (key = amf3_read_string) && key.length != 0 do # read next key 296 value = amf3_deserialize 297 properties[key] = value 298 end 299 end 300 301 @class_mapper.object_deserialize(result, properties) 302 end 303 304 result 305 end
# File lib/amf/pure/deserializer.rb 182 def amf3_read_string 183 result = nil 184 185 type = amf3_read_integer 186 187 result = get_as_reference_string(type) 188 189 if result.nil? 190 length = type >> 1 191 result = '' 192 193 if length > 0 194 195 if length > (@source.size - @source.pos) 196 raise AMFErrorIncomplete.new 197 end 198 199 result = @source.read(length) 200 result.force_encoding('UTF-8') if result.respond_to?(:force_encoding) 201 @cache_strings << result 202 end 203 end 204 205 result 206 end
# File lib/amf/pure/deserializer.rb 115 def get_as_reference_object(type) 116 result = nil 117 118 if (type & 0x01) == 0 #is reference? 119 reference = type >> 1 120 result = @cache_objects[reference] 121 end 122 123 result 124 end
# File lib/amf/pure/deserializer.rb 127 def get_as_reference_string(type) 128 result = nil 129 130 if (type & 0x01) == 0 #is reference? 131 reference = type >> 1 132 result = @cache_strings[reference] 133 end 134 135 result 136 end