PageRenderTime 25ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/SabreAMF/AMF3/Serializer.php

https://github.com/evert/SabreAMF
PHP | 269 lines | 144 code | 64 blank | 61 comment | 42 complexity | 1c972f22c01eefe0ffe53eb9448467a1 MD5 | raw file
  1. <?php
  2. /**
  3. * SabreAMF_AMF3_Serializer
  4. *
  5. * @package SabreAMF
  6. * @subpackage AMF3
  7. * @version $Id$
  8. * @copyright Copyright (C) 2006-2009 Rooftop Solutions. All rights reserved.
  9. * @author Evert Pot (http://www.rooftopsolutions.nl/)
  10. * @author Karl von Randow http://xk72.com/
  11. * @author Develar
  12. * @licence http://www.freebsd.org/copyright/license.html BSD License (4 Clause)
  13. * @uses SabreAMF_Const
  14. * @uses SabreAMF_AMF3_Const
  15. * @uses SabreAMF_ITypedObject
  16. */
  17. class SabreAMF_AMF3_Serializer extends SabreAMF_Serializer {
  18. /**
  19. * writeAMFData
  20. *
  21. * @param mixed $data
  22. * @param int $forcetype
  23. * @return mixed
  24. */
  25. public function writeAMFData($data,$forcetype=null) {
  26. if (is_null($forcetype)) {
  27. // Autodetecting data type
  28. $type=false;
  29. if (!$type && is_null($data)) $type = SabreAMF_AMF3_Const::DT_NULL;
  30. if (!$type && is_bool($data)) {
  31. $type = $data?SabreAMF_AMF3_Const::DT_BOOL_TRUE:SabreAMF_AMF3_Const::DT_BOOL_FALSE;
  32. }
  33. if (!$type && is_int($data)) {
  34. // We essentially only got 29 bits for integers
  35. if ($data > 0xFFFFFFF || $data < -268435456) {
  36. $type = SabreAMF_AMF3_Const::DT_NUMBER;
  37. } else {
  38. $type = SabreAMF_AMF3_Const::DT_INTEGER;
  39. }
  40. }
  41. if (!$type && is_float($data)) $type = SabreAMF_AMF3_Const::DT_NUMBER;
  42. if (!$type && is_int($data)) $type = SabreAMF_AMF3_Const::DT_INTEGER;
  43. if (!$type && is_string($data)) $type = SabreAMF_AMF3_Const::DT_STRING;
  44. if (!$type && is_array($data)) $type = SabreAMF_AMF3_Const::DT_ARRAY;
  45. if (!$type && is_object($data)) {
  46. if ($data instanceof SabreAMF_ByteArray)
  47. $type = SabreAMF_AMF3_Const::DT_BYTEARRAY;
  48. elseif ($data instanceof DateTime)
  49. $type = SabreAMF_AMF3_Const::DT_DATE;
  50. else
  51. $type = SabreAMF_AMF3_Const::DT_OBJECT;
  52. }
  53. if ($type===false) {
  54. throw new Exception('Unhandled data-type: ' . gettype($data));
  55. return null;
  56. }
  57. if ($type == SabreAMF_AMF3_Const::DT_INTEGER && ($data > 268435455 || $data < -268435456)) {
  58. $type = SabreAMF_AMF3_Const::DT_NUMBER;
  59. }
  60. } else $type = $forcetype;
  61. $this->stream->writeByte($type);
  62. switch ($type) {
  63. case SabreAMF_AMF3_Const::DT_NULL : break;
  64. case SabreAMF_AMF3_Const::DT_BOOL_FALSE : break;
  65. case SabreAMF_AMF3_Const::DT_BOOL_TRUE : break;
  66. case SabreAMF_AMF3_Const::DT_INTEGER : $this->writeInt($data); break;
  67. case SabreAMF_AMF3_Const::DT_NUMBER : $this->stream->writeDouble($data); break;
  68. case SabreAMF_AMF3_Const::DT_STRING : $this->writeString($data); break;
  69. case SabreAMF_AMF3_Const::DT_DATE : $this->writeDate($data); break;
  70. case SabreAMF_AMF3_Const::DT_ARRAY : $this->writeArray($data); break;
  71. case SabreAMF_AMF3_Const::DT_OBJECT : $this->writeObject($data); break;
  72. case SabreAMF_AMF3_Const::DT_BYTEARRAY : $this->writeByteArray($data); break;
  73. default : throw new Exception('Unsupported type: ' . gettype($data)); return null;
  74. }
  75. }
  76. /**
  77. * writeObject
  78. *
  79. * @param mixed $data
  80. * @return void
  81. */
  82. public function writeObject($data) {
  83. $encodingType = SabreAMF_AMF3_Const::ET_PROPLIST;
  84. if ($data instanceof SabreAMF_ITypedObject) {
  85. $classname = $data->getAMFClassName();
  86. $data = $data->getAMFData();
  87. } else if (!$classname = $this->getRemoteClassName(get_class($data))) {
  88. $classname = '';
  89. } else {
  90. if ($data instanceof SabreAMF_Externalized) {
  91. $encodingType = SabreAMF_AMF3_Const::ET_EXTERNALIZED;
  92. }
  93. }
  94. $objectInfo = 0x03;
  95. $objectInfo |= $encodingType << 2;
  96. switch($encodingType) {
  97. case SabreAMF_AMF3_Const::ET_PROPLIST :
  98. $propertyCount=0;
  99. foreach($data as $k=>$v) {
  100. $propertyCount++;
  101. }
  102. $objectInfo |= ($propertyCount << 4);
  103. $this->writeInt($objectInfo);
  104. $this->writeString($classname);
  105. foreach($data as $k=>$v) {
  106. $this->writeString($k);
  107. }
  108. foreach($data as $k=>$v) {
  109. $this->writeAMFData($v);
  110. }
  111. break;
  112. case SabreAMF_AMF3_Const::ET_EXTERNALIZED :
  113. $this->writeInt($objectInfo);
  114. $this->writeString($classname);
  115. $this->writeAMFData($data->writeExternal());
  116. break;
  117. }
  118. }
  119. /**
  120. * writeInt
  121. *
  122. * @param int $int
  123. * @return void
  124. */
  125. public function writeInt($int) {
  126. // Note that this is simply a sanity check of the conversion algorithm;
  127. // when live this sanity check should be disabled (overflow check handled in this.writeAMFData).
  128. /*if ( ( ( $int & 0x70000000 ) != 0 ) && ( ( $int & 0x80000000 ) == 0 ) )
  129. throw new Exception ( 'Integer overflow during Int32 to AMF3 conversion' );*/
  130. if ( ( $int & 0xffffff80 ) == 0 )
  131. {
  132. $this->stream->writeByte ( $int & 0x7f );
  133. return;
  134. }
  135. if ( ( $int & 0xffffc000 ) == 0 )
  136. {
  137. $this->stream->writeByte ( ( $int >> 7 ) | 0x80 );
  138. $this->stream->writeByte ( $int & 0x7f );
  139. return;
  140. }
  141. if ( ( $int & 0xffe00000 ) == 0 )
  142. {
  143. $this->stream->writeByte ( ( $int >> 14 ) | 0x80 );
  144. $this->stream->writeByte ( ( $int >> 7 ) | 0x80 );
  145. $this->stream->writeByte ( $int & 0x7f );
  146. return;
  147. }
  148. $this->stream->writeByte ( ( $int >> 22 ) | 0x80 );
  149. $this->stream->writeByte ( ( $int >> 15 ) | 0x80 );
  150. $this->stream->writeByte ( ( $int >> 8 ) | 0x80 );
  151. $this->stream->writeByte ( $int & 0xff );
  152. return;
  153. }
  154. public function writeByteArray(SabreAMF_ByteArray $data) {
  155. $this->writeString($data->getData());
  156. }
  157. /**
  158. * writeString
  159. *
  160. * @param string $str
  161. * @return void
  162. */
  163. public function writeString($str) {
  164. $strref = strlen($str) << 1 | 0x01;
  165. $this->writeInt($strref);
  166. $this->stream->writeBuffer($str);
  167. }
  168. /**
  169. * writeArray
  170. *
  171. * @param array $arr
  172. * @return void
  173. */
  174. public function writeArray(array $arr) {
  175. //Check if this is an associative array or not.
  176. if ( $this->isPureArray( $arr ) ) {
  177. // Writing the length for the numeric keys in the array
  178. $arrLen = count($arr);
  179. $arrId = ($arrLen << 1) | 0x01;
  180. $this->writeInt($arrId);
  181. $this->writeString('');
  182. foreach($arr as $v) {
  183. $this->writeAMFData($v);
  184. }
  185. } else {
  186. $this->writeInt(1);
  187. foreach($arr as $key=>$value) {
  188. $this->writeString($key);
  189. $this->writeAMFData($value);
  190. }
  191. $this->writeString('');
  192. }
  193. }
  194. /**
  195. * Writes a date object
  196. *
  197. * @param DateTime $data
  198. * @return void
  199. */
  200. public function writeDate(DateTime $data) {
  201. // We're always sending actual date objects, never references
  202. $this->writeInt(0x01);
  203. $this->stream->writeDouble($data->format('U')*1000);
  204. }
  205. }