diff -r 5b37998e522e -r 162c1de6545a web/lib/Zend/Amf/Parse/Amf3/Deserializer.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/Zend/Amf/Parse/Amf3/Deserializer.php Fri Mar 11 15:05:35 2011 +0100 @@ -0,0 +1,421 @@ +_stream->readByte(); + } + + switch($typeMarker) { + case Zend_Amf_Constants::AMF3_UNDEFINED: + return null; + case Zend_Amf_Constants::AMF3_NULL: + return null; + case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE: + return false; + case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE: + return true; + case Zend_Amf_Constants::AMF3_INTEGER: + return $this->readInteger(); + case Zend_Amf_Constants::AMF3_NUMBER: + return $this->_stream->readDouble(); + case Zend_Amf_Constants::AMF3_STRING: + return $this->readString(); + case Zend_Amf_Constants::AMF3_DATE: + return $this->readDate(); + case Zend_Amf_Constants::AMF3_ARRAY: + return $this->readArray(); + case Zend_Amf_Constants::AMF3_OBJECT: + return $this->readObject(); + case Zend_Amf_Constants::AMF3_XML: + case Zend_Amf_Constants::AMF3_XMLSTRING: + return $this->readXmlString(); + case Zend_Amf_Constants::AMF3_BYTEARRAY: + return $this->readString(); + default: + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker); + } + } + + /** + * Read and deserialize an integer + * + * AMF 3 represents smaller integers with fewer bytes using the most + * significant bit of each byte. The worst case uses 32-bits + * to represent a 29-bit number, which is what we would have + * done with no compression. + * - 0x00000000 - 0x0000007F : 0xxxxxxx + * - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx + * - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx + * - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx + * - 0x40000000 - 0xFFFFFFFF : throw range exception + * + * 0x04 -> integer type code, followed by up to 4 bytes of data. + * + * Parsing integers on OSFlash for the AMF3 integer data format: + * @link http://osflash.org/amf3/parsing_integers + * @return int|float + */ + public function readInteger() + { + $count = 1; + $intReference = $this->_stream->readByte(); + $result = 0; + while ((($intReference & 0x80) != 0) && $count < 4) { + $result <<= 7; + $result |= ($intReference & 0x7f); + $intReference = $this->_stream->readByte(); + $count++; + } + if ($count < 4) { + $result <<= 7; + $result |= $intReference; + } else { + // Use all 8 bits from the 4th byte + $result <<= 8; + $result |= $intReference; + + // Check if the integer should be negative + if (($result & 0x10000000) != 0) { + //and extend the sign bit + $result |= ~0xFFFFFFF; + } + } + return $result; + } + + /** + * Read and deserialize a string + * + * Strings can be sent as a reference to a previously + * occurring String by using an index to the implicit string reference table. + * Strings are encoding using UTF-8 - however the header may either + * describe a string literal or a string reference. + * + * - string = 0x06 string-data + * - string-data = integer-data [ modified-utf-8 ] + * - modified-utf-8 = *OCTET + * + * @return String + */ + public function readString() + { + $stringReference = $this->readInteger(); + + //Check if this is a reference string + if (($stringReference & 0x01) == 0) { + // reference string + $stringReference = $stringReference >> 1; + if ($stringReference >= count($this->_referenceStrings)) { + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference); + } + // reference string found + return $this->_referenceStrings[$stringReference]; + } + + $length = $stringReference >> 1; + if ($length) { + $string = $this->_stream->readBytes($length); + $this->_referenceStrings[] = $string; + } else { + $string = ""; + } + return $string; + } + + /** + * Read and deserialize a date + * + * Data is the number of milliseconds elapsed since the epoch + * of midnight, 1st Jan 1970 in the UTC time zone. + * Local time zone information is not sent to flash. + * + * - date = 0x08 integer-data [ number-data ] + * + * @return Zend_Date + */ + public function readDate() + { + $dateReference = $this->readInteger(); + if (($dateReference & 0x01) == 0) { + $dateReference = $dateReference >> 1; + if ($dateReference>=count($this->_referenceObjects)) { + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference); + } + return $this->_referenceObjects[$dateReference]; + } + + $timestamp = floor($this->_stream->readDouble() / 1000); + + require_once 'Zend/Date.php'; + $dateTime = new Zend_Date((int) $timestamp); + $this->_referenceObjects[] = $dateTime; + return $dateTime; + } + + /** + * Read amf array to PHP array + * + * - array = 0x09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] ) + * + * @return array + */ + public function readArray() + { + $arrayReference = $this->readInteger(); + if (($arrayReference & 0x01)==0){ + $arrayReference = $arrayReference >> 1; + if ($arrayReference>=count($this->_referenceObjects)) { + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference); + } + return $this->_referenceObjects[$arrayReference]; + } + + // Create a holder for the array in the reference list + $data = array(); + $this->_referenceObjects[] =& $data; + $key = $this->readString(); + + // Iterating for string based keys. + while ($key != '') { + $data[$key] = $this->readTypeMarker(); + $key = $this->readString(); + } + + $arrayReference = $arrayReference >>1; + + //We have a dense array + for ($i=0; $i < $arrayReference; $i++) { + $data[] = $this->readTypeMarker(); + } + + return $data; + } + + /** + * Read an object from the AMF stream and convert it into a PHP object + * + * @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo + * @return object|array + */ + public function readObject() + { + $traitsInfo = $this->readInteger(); + $storedObject = ($traitsInfo & 0x01)==0; + $traitsInfo = $traitsInfo >> 1; + + // Check if the Object is in the stored Objects reference table + if ($storedObject) { + $ref = $traitsInfo; + if (!isset($this->_referenceObjects[$ref])) { + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref); + } + $returnObject = $this->_referenceObjects[$ref]; + } else { + // Check if the Object is in the stored Definitions reference table + $storedClass = ($traitsInfo & 0x01) == 0; + $traitsInfo = $traitsInfo >> 1; + if ($storedClass) { + $ref = $traitsInfo; + if (!isset($this->_referenceDefinitions[$ref])) { + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref); + } + // Populate the reference attributes + $className = $this->_referenceDefinitions[$ref]['className']; + $encoding = $this->_referenceDefinitions[$ref]['encoding']; + $propertyNames = $this->_referenceDefinitions[$ref]['propertyNames']; + } else { + // The class was not in the reference tables. Start reading rawdata to build traits. + // Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal + $className = $this->readString(); + $encoding = $traitsInfo & 0x03; + $propertyNames = array(); + $traitsInfo = $traitsInfo >> 2; + } + + // We now have the object traits defined in variables. Time to go to work: + if (!$className) { + // No class name generic object + $returnObject = new stdClass(); + } else { + // Defined object + // Typed object lookup against registered classname maps + if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) { + $returnObject = new $loader(); + } else { + //user defined typed object + require_once 'Zend/Amf/Exception.php'; + throw new Zend_Amf_Exception('Typed object not found: '. $className . ' '); + } + } + + // Add the Object to the reference table + $this->_referenceObjects[] = $returnObject; + + $properties = array(); // clear value + // Check encoding types for additional processing. + switch ($encoding) { + case (Zend_Amf_Constants::ET_EXTERNAL): + // Externalizable object such as {ArrayCollection} and {ObjectProxy} + if (!$storedClass) { + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + $returnObject->externalizedData = $this->readTypeMarker(); + break; + case (Zend_Amf_Constants::ET_DYNAMIC): + // used for Name-value encoding + if (!$storedClass) { + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + // not a reference object read name value properties from byte stream + do { + $property = $this->readString(); + if ($property != "") { + $propertyNames[] = $property; + $properties[$property] = $this->readTypeMarker(); + } + } while ($property !=""); + break; + default: + // basic property list object. + if (!$storedClass) { + $count = $traitsInfo; // Number of properties in the list + for($i=0; $i< $count; $i++) { + $propertyNames[] = $this->readString(); + } + // Add a reference to the class. + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + foreach ($propertyNames as $property) { + $properties[$property] = $this->readTypeMarker(); + } + break; + } + + // Add properties back to the return object. + foreach($properties as $key=>$value) { + if($key) { + $returnObject->$key = $value; + } + } + + + } + + if ($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) { + if (isset($returnObject->externalizedData)) { + $returnObject = $returnObject->externalizedData; + } else { + $returnObject = get_object_vars($returnObject); + } + } + + return $returnObject; + } + + /** + * Convert XML to SimpleXml + * If user wants DomDocument they can use dom_import_simplexml + * + * @return SimpleXml Object + */ + public function readXmlString() + { + $xmlReference = $this->readInteger(); + $length = $xmlReference >> 1; + $string = $this->_stream->readBytes($length); + return simplexml_load_string($string); + } +}