Package pyamf :: Module amf3
[hide private]
[frames] | no frames]

Source Code for Module pyamf.amf3

   1  # -*- coding: utf-8 -*- 
   2  # 
   3  # Copyright (c) 2007-2009 The PyAMF Project. 
   4  # See LICENSE for details. 
   5   
   6  """ 
   7  AMF3 implementation. 
   8   
   9  C{AMF3} is the default serialization for 
  10  U{ActionScript<http://en.wikipedia.org/wiki/ActionScript>} 3.0 and provides 
  11  various advantages over L{AMF0<pyamf.amf0>}, which is used for ActionScript 1.0 
  12  and 2.0. It adds support for sending C{int} and C{uint} objects as integers and 
  13  supports data types that are available only in ActionScript 3.0, such as 
  14  L{ByteArray} and L{ArrayCollection}. 
  15   
  16  @see: U{Official AMF3 Specification in English (external) 
  17  <http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_121207.pdf>} 
  18  @see: U{Official AMF3 Specification in Japanese (external) 
  19  <http://opensource.adobe.com/wiki/download/attachments/1114283/JP_amf3_spec_121207.pdf>} 
  20  @see: U{AMF3 documentation on OSFlash (external) 
  21  <http://osflash.org/documentation/amf3>} 
  22   
  23  @since: 0.1.0 
  24  """ 
  25   
  26  import types, datetime, zlib 
  27   
  28  import pyamf 
  29  from pyamf import util 
  30  from pyamf.flex import ObjectProxy, ArrayCollection 
  31   
  32  #: If True encode/decode lists/tuples to ArrayCollections 
  33  #: and dicts to ObjectProxy 
  34  use_proxies_default = False 
  35   
  36  try: 
  37      set() 
  38  except NameError: 
  39      from sets import Set as set 
  40   
41 -class ASTypes:
42 """ 43 All AMF3 data types used in ActionScript 3.0. 44 45 AMF represents ActionScript objects by a single byte representing type, and 46 then by a type-specific byte array that may be of fixed length, may contain 47 length information, or may come with its own end code. 48 49 @see: U{AMF3 data types on OSFlash (external) 50 <http://osflash.org/documentation/amf3#data_types>} 51 """ 52 #: The undefined type is represented by the undefined type marker. 53 #: No further information is encoded for this value. 54 UNDEFINED = 0x00 55 #: The undefined type is represented by the undefined type marker. 56 #: No further information is encoded for this value. 57 NULL = 0x01 58 #: The false type is represented by the false type marker and is 59 #: used to encode a Boolean value of C{false}. No further information 60 #: is encoded for this value. 61 #: @note: In ActionScript 3.0 the concept of a primitive and Object 62 #: form of Boolean does not exist. 63 BOOL_FALSE = 0x02 64 #: The true type is represented by the true type marker and is 65 #: used to encode a Boolean value of C{true}. No further information 66 #: is encoded for this value. 67 #: @note: In ActionScript 3.0 the concept of a primitive and Object 68 #: form of Boolean does not exist. 69 BOOL_TRUE = 0x03 70 #: In AMF 3 integers are serialized using a variable length unsigned 71 #: 29-bit integer. 72 #: @see: U{Parsing Integers on OSFlash (external) 73 #: <http://osflash.org/documentation/amf3/parsing_integers>} 74 INTEGER = 0x04 75 #: This type is used to encode an ActionScript Number 76 #: or an ActionScript C{int} of value greater than or equal to 2^28 77 #: or an ActionScript uint of value greater than or equal to 2^29. 78 #: The encoded value is is always an 8 byte IEEE-754 double precision 79 #: floating point value in network byte order (sign bit in low memory). 80 #: The AMF 3 number type is encoded in the same manner as the 81 #: AMF 0 L{Number<pyamf.amf0.ASTypes.NUMBER>} type. 82 NUMBER = 0x05 83 #: ActionScript String values are represented using a single string 84 #: type in AMF 3 - the concept of string and long string types from 85 #: AMF 0 is not used. Strings can be sent as a reference to a previously 86 #: occurring String by using an index to the implicit string reference 87 #: table. 88 #: Strings are encoding using UTF-8 - however the header may either 89 #: describe a string literal or a string reference. 90 STRING = 0x06 91 #: ActionScript 3.0 introduced a new XML type however the legacy 92 #: C{XMLDocument} type from ActionScript 1.0 and 2.0.is retained 93 #: in the language as C{flash.xml.XMLDocument}. Similar to AMF 0, the 94 #: structure of an C{XMLDocument} needs to be flattened into a string 95 #: representation for serialization. As with other strings in AMF, 96 #: the content is encoded in UTF-8. XMLDocuments can be sent as a reference 97 #: to a previously occurring C{XMLDocument} instance by using an index to 98 #: the implicit object reference table. 99 #: @see: U{OSFlash documentation (external) 100 #: <http://osflash.org/documentation/amf3#x07_-_xml_legacy_flash.xml.xmldocument_class>} 101 XML = 0x07 102 #: In AMF 3 an ActionScript Date is serialized simply as the number of 103 #: milliseconds elapsed since the epoch of midnight, 1st Jan 1970 in the 104 #: UTC time zone. Local time zone information is not sent. 105 DATE = 0x08 106 #: ActionScript Arrays are described based on the nature of their indices, 107 #: i.e. their type and how they are positioned in the Array. 108 ARRAY = 0x09 109 #: A single AMF 3 type handles ActionScript Objects and custom user classes. 110 OBJECT = 0x0a 111 #: ActionScript 3.0 introduces a new top-level XML class that supports 112 #: U{E4X<http://en.wikipedia.org/wiki/E4X>} syntax. 113 #: For serialization purposes the XML type needs to be flattened into a 114 #: string representation. As with other strings in AMF, the content is 115 #: encoded using UTF-8. 116 XMLSTRING = 0x0b 117 #: ActionScript 3.0 introduces the L{ByteArray} type to hold an Array 118 #: of bytes. AMF 3 serializes this type using a variable length encoding 119 #: 29-bit integer for the byte-length prefix followed by the raw bytes 120 #: of the L{ByteArray}. 121 #: @see: U{Parsing ByteArrays on OSFlash (external) 122 #: <http://osflash.org/documentation/amf3/parsing_byte_arrays>} 123 BYTEARRAY = 0x0c
124 125 #: List of available ActionScript types in AMF3. 126 ACTIONSCRIPT_TYPES = [] 127 128 for x in ASTypes.__dict__: 129 if not x.startswith('_'): 130 ACTIONSCRIPT_TYPES.append(ASTypes.__dict__[x]) 131 del x 132 133 #: Reference bit. 134 REFERENCE_BIT = 0x01 135
136 -class ObjectEncoding:
137 """ 138 AMF object encodings. 139 """ 140 #: Property list encoding. 141 #: The remaining integer-data represents the number of class members that 142 #: exist. The property names are read as string-data. The values are then 143 #: read as AMF3-data. 144 STATIC = 0x00 145 146 #: Externalizable object. 147 #: What follows is the value of the "inner" object, including type code. 148 #: This value appears for objects that implement IExternalizable, such as 149 #: L{ArrayCollection} and L{ObjectProxy}. 150 EXTERNAL = 0x01 151 152 #: Name-value encoding. 153 #: The property names and values are encoded as string-data followed by 154 #: AMF3-data until there is an empty string property name. If there is a 155 #: class-def reference there are no property names and the number of values 156 #: is equal to the number of properties in the class-def. 157 DYNAMIC = 0x02 158 159 #: Proxy object. 160 PROXY = 0x03
161
162 -class DataOutput(object):
163 """ 164 I am a C{StringIO} type object containing byte data from the AMF stream. 165 ActionScript 3.0 introduced the C{flash.utils.ByteArray} class to support 166 the manipulation of raw data in the form of an Array of bytes. 167 I provide a set of methods for writing binary data with ActionScript 3.0. 168 169 This class is the I/O counterpart to the L{DataInput} class, which reads 170 binary data. 171 172 @see: U{IDataOutput on Livedocs (external) 173 <http://livedocs.adobe.com/flex/201/langref/flash/utils/IDataOutput.html>} 174 """
175 - def __init__(self, encoder):
176 """ 177 @param encoder: Encoder containing the stream. 178 @type encoder: L{amf3.Encoder<pyamf.amf3.Encoder>} 179 """ 180 assert isinstance(encoder, Encoder) 181 182 self.encoder = encoder 183 self.stream = encoder.stream
184
185 - def writeBoolean(self, value):
186 """ 187 Writes a Boolean value. 188 189 @type value: C{bool} 190 @param value: A C{Boolean} value determining which byte is written. 191 If the parameter is C{True}, C{1} is written; if C{False}, C{0} is 192 written. 193 194 @raise ValueError: Non-boolean value found. 195 """ 196 if isinstance(value, bool): 197 if value is True: 198 self.stream.write_uchar(1) 199 else: 200 self.stream.write_uchar(0) 201 else: 202 raise ValueError("Non-boolean value found")
203
204 - def writeByte(self, value):
205 """ 206 Writes a byte. 207 208 @type value: C{int} 209 """ 210 self.stream.write_char(value)
211
212 - def writeDouble(self, value):
213 """ 214 Writes an IEEE 754 double-precision (64-bit) floating 215 point number. 216 217 @type value: C{number} 218 """ 219 self.stream.write_double(value)
220
221 - def writeFloat(self, value):
222 """ 223 Writes an IEEE 754 single-precision (32-bit) floating 224 point number. 225 226 @type value: C{float} 227 """ 228 self.stream.write_float(value)
229
230 - def writeInt(self, value):
231 """ 232 Writes a 32-bit signed integer. 233 234 @type value: C{int} 235 """ 236 self.stream.write_long(value)
237
238 - def writeMultiByte(self, value, charset):
239 """ 240 Writes a multibyte string to the datastream using the 241 specified character set. 242 243 @type value: C{str} 244 @param value: The string value to be written. 245 @type charset: C{str} 246 @param charset: The string denoting the character 247 set to use. Possible character set strings include 248 C{shift-jis}, C{cn-gb}, C{iso-8859-1} and others. 249 @see: U{Supported character sets on Livedocs (external) 250 <http://livedocs.adobe.com/flex/201/langref/charset-codes.html>} 251 """ 252 self.stream.write(unicode(value).encode(charset))
253
254 - def writeObject(self, value, use_references=True):
255 """ 256 Writes an object to data stream in AMF serialized format. 257 258 @param value: The object to be serialized. 259 @type use_references: C{bool} 260 @param use_references: 261 """ 262 self.encoder.writeElement(value, use_references)
263
264 - def writeShort(self, value):
265 """ 266 Writes a 16-bit integer. 267 268 @type value: C{int} 269 @param value: A byte value as an integer. 270 """ 271 self.stream.write_short(value)
272
273 - def writeUnsignedInt(self, value):
274 """ 275 Writes a 32-bit unsigned integer. 276 277 @type value: C{int} 278 @param value: A byte value as an unsigned integer. 279 """ 280 self.stream.write_ulong(value)
281
282 - def writeUTF(self, value):
283 """ 284 Writes a UTF-8 string to the data stream. 285 286 The length of the UTF-8 string in bytes is written first, 287 as a 16-bit integer, followed by the bytes representing the 288 characters of the string. 289 290 @type value: C{str} 291 @param value: The string value to be written. 292 """ 293 if not isinstance(value, unicode): 294 value = unicode(value, 'utf8') 295 296 buf = util.BufferedByteStream() 297 buf.write_utf8_string(value) 298 bytes = buf.getvalue() 299 300 self.stream.write_ushort(len(bytes)) 301 self.stream.write(bytes)
302
303 - def writeUTFBytes(self, value):
304 """ 305 Writes a UTF-8 string. Similar to L{writeUTF}, but does 306 not prefix the string with a 16-bit length word. 307 308 @type value: C{str} 309 @param value: The string value to be written. 310 """ 311 val = None 312 313 if isinstance(value, unicode): 314 val = value 315 else: 316 val = unicode(value, 'utf8') 317 318 self.stream.write_utf8_string(val)
319
320 -class DataInput(object):
321 """ 322 I provide a set of methods for reading binary data with ActionScript 3.0. 323 324 This class is the I/O counterpart to the L{DataOutput} class, 325 which writes binary data. 326 327 @see: U{IDataInput on Livedocs (external) 328 <http://livedocs.adobe.com/flex/201/langref/flash/utils/IDataInput.html>} 329 """
330 - def __init__(self, decoder):
331 """ 332 @param decoder: AMF3 decoder containing the stream. 333 @type decoder: L{amf3.Decoder<pyamf.amf3.Decoder>} 334 """ 335 assert isinstance(decoder, Decoder) 336 337 self.decoder = decoder 338 self.stream = decoder.stream
339
340 - def readBoolean(self):
341 """ 342 Read C{Boolean}. 343 344 @raise ValueError: Error reading Boolean. 345 @rtype: C{bool} 346 @return: A Boolean value, C{True} if the byte 347 is nonzero, C{False} otherwise. 348 """ 349 byte = self.stream.read(1) 350 351 if byte == '\x00': 352 return False 353 elif byte == '\x01': 354 return True 355 else: 356 raise ValueError("Error reading boolean")
357
358 - def readByte(self):
359 """ 360 Reads a signed byte. 361 362 @rtype: C{int} 363 @return: The returned value is in the range -128 to 127. 364 """ 365 return self.stream.read_char()
366
367 - def readDouble(self):
368 """ 369 Reads an IEEE 754 double-precision floating point number from the 370 data stream. 371 372 @rtype: C{number} 373 @return: An IEEE 754 double-precision floating point number. 374 """ 375 return self.stream.read_double()
376
377 - def readFloat(self):
378 """ 379 Reads an IEEE 754 single-precision floating point number from the 380 data stream. 381 382 @rtype: C{number} 383 @return: An IEEE 754 single-precision floating point number. 384 """ 385 return self.stream.read_float()
386
387 - def readInt(self):
388 """ 389 Reads a signed 32-bit integer from the data stream. 390 391 @rtype: C{int} 392 @return: The returned value is in the range -2147483648 to 2147483647. 393 """ 394 return self.stream.read_long()
395
396 - def readMultiByte(self, length, charset):
397 """ 398 Reads a multibyte string of specified length from the data stream 399 using the specified character set. 400 401 @type length: C{int} 402 @param length: The number of bytes from the data stream to read. 403 @type charset: C{str} 404 @param charset: The string denoting the character set to use. 405 406 @rtype: C{str} 407 @return: UTF-8 encoded string. 408 """ 409 #FIXME nick: how to work out the code point byte size (on the fly)? 410 bytes = self.stream.read(length) 411 412 return unicode(bytes, charset)
413
414 - def readObject(self):
415 """ 416 Reads an object from the data stream. 417 418 @return: The deserialized object. 419 """ 420 return self.decoder.readElement()
421
422 - def readShort(self):
423 """ 424 Reads a signed 16-bit integer from the data stream. 425 426 @rtype: C{uint} 427 @return: The returned value is in the range -32768 to 32767. 428 """ 429 return self.stream.read_short()
430
431 - def readUnsignedByte(self):
432 """ 433 Reads an unsigned byte from the data stream. 434 435 @rtype: C{uint} 436 @return: The returned value is in the range 0 to 255. 437 """ 438 return self.stream.read_uchar()
439
440 - def readUnsignedInt(self):
441 """ 442 Reads an unsigned 32-bit integer from the data stream. 443 444 @rtype: C{uint} 445 @return: The returned value is in the range 0 to 4294967295. 446 """ 447 return self.stream.read_ulong()
448
449 - def readUnsignedShort(self):
450 """ 451 Reads an unsigned 16-bit integer from the data stream. 452 453 @rtype: C{uint} 454 @return: The returned value is in the range 0 to 65535. 455 """ 456 return self.stream.read_ushort()
457
458 - def readUTF(self):
459 """ 460 Reads a UTF-8 string from the data stream. 461 462 The string is assumed to be prefixed with an unsigned 463 short indicating the length in bytes. 464 465 @rtype: C{str} 466 @return: A UTF-8 string produced by the byte 467 representation of characters. 468 """ 469 length = self.stream.read_ushort() 470 return self.stream.read_utf8_string(length)
471
472 - def readUTFBytes(self, length):
473 """ 474 Reads a sequence of C{length} UTF-8 bytes from the data 475 stream and returns a string. 476 477 @type length: C{int} 478 @param length: The number of bytes from the data stream to read. 479 @rtype: C{str} 480 @return: A UTF-8 string produced by the byte representation of 481 characters of specified C{length}. 482 """ 483 return self.readMultiByte(length, 'utf-8')
484
485 -class ByteArray(util.BufferedByteStream, DataInput, DataOutput):
486 """ 487 I am a C{StringIO} type object containing byte data from the AMF stream. 488 ActionScript 3.0 introduced the C{flash.utils.ByteArray} class to support 489 the manipulation of raw data in the form of an Array of bytes. 490 491 Supports C{zlib} compression. 492 493 Possible uses of the C{ByteArray} class: 494 - Creating a custom protocol to connect to a client. 495 - Writing your own AMF/Remoting packet. 496 - Optimizing the size of your data by using custom data types. 497 498 @see: U{ByteArray on Livedocs (external) 499 <http://livedocs.adobe.com/flex/201/langref/flash/utils/ByteArray.html>} 500 """
501 - def __init__(self, *args, **kwargs):
502 self.context = kwargs.pop('context', Context()) 503 504 util.BufferedByteStream.__init__(self, *args, **kwargs) 505 DataInput.__init__(self