PageRenderTime 45ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Hessian2/Hessian2Writer.php

http://hessianphp.googlecode.com/
PHP | 368 lines | 306 code | 39 blank | 23 comment | 61 complexity | 5f91241e12dbaaff5b24b6c8e51b8dac MD5 | raw file
Possible License(s): ISC
  1. <?php
  2. /*
  3. * This file is part of the HessianPHP package.
  4. * (c) 2004-2011 Manuel Gómez
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. class Hessian2Writer{
  10. var $refmap;
  11. var $typemap;
  12. var $logMsg = array();
  13. var $options;
  14. var $filterContainer;
  15. function __construct($options = null){
  16. $this->refmap = new HessianReferenceMap();
  17. $this->typemap = new HessianTypeMap();
  18. $this->options = $options;
  19. }
  20. function logMsg($msg){
  21. $this->log[] = $msg;
  22. }
  23. function setTypeMap($typemap){
  24. $this->typemap = $typemap;
  25. }
  26. function setFilters($container){
  27. $this->filterContainer = $container;
  28. }
  29. function writeValue($value){
  30. $type = gettype($value);
  31. $dispatch = $this->resolveDispatch($type);
  32. if(is_object($value)){
  33. $filter = $this->filterContainer->getCallback($value);
  34. if($filter) {
  35. $value = $this->filterContainer->doCallback($filter, array($value, $this));
  36. if($value instanceof HessianStreamResult){
  37. return $value->stream;
  38. }
  39. $ntype = gettype($value);
  40. if($type != $ntype)
  41. $dispatch = $this->resolveDispatch($ntype);
  42. }
  43. }
  44. $data = $this->$dispatch($value);
  45. return $data;
  46. }
  47. function resolveDispatch($type){
  48. $dispatch = '';
  49. // TODO usar algun type helper
  50. switch($type){
  51. case 'integer': $dispatch = 'writeInt' ;break;
  52. case 'boolean': $dispatch = 'writeBool' ;break;
  53. case 'string': $dispatch = 'writeString' ; break;
  54. case 'double': $dispatch = 'writeDouble' ; break;
  55. case 'array': $dispatch = 'writeArray' ; break;
  56. case 'object': $dispatch = 'writeObject' ;break;
  57. case 'NULL': $dispatch = 'writeNull';break;
  58. case 'resource': $dispatch = 'writeResource' ; break;
  59. default:
  60. throw new Exception("Handler for type $type not implemented");
  61. }
  62. $this->logMsg("dispatch $dispatch");
  63. return $dispatch;
  64. }
  65. function writeNull(){
  66. return 'N';
  67. }
  68. function writeArray($array){
  69. if(empty($array))
  70. return 'N';
  71. $refindex = $this->refmap->getReference($array);
  72. if($refindex !== false){
  73. return $this->writeReference($refindex);
  74. }
  75. /* ::= x57 value* 'Z' # variable-length untyped list
  76. ::= x58 int value* # fixed-length untyped list
  77. ::= [x78-7f] value* # fixed-length untyped list
  78. */
  79. $total = count($array);
  80. if(HessianUtils::isListFormula($array)){
  81. $this->refmap->objectlist[] = &$array;
  82. $stream = '';
  83. if($total <= 7){
  84. $len = $total + 0x78;
  85. $stream = pack('c', $len);
  86. } else {
  87. $stream = pack('c', 0x58);
  88. $stream .= $this->writeInt($total);
  89. }
  90. foreach($array as $key => $value){
  91. $stream .= $this->writeValue($value);
  92. }
  93. return $stream;
  94. } else{
  95. return $this->writeMap($array);
  96. }
  97. }
  98. function writeMap($map, $type = ''){
  99. if(empty($map))
  100. return 'N';
  101. /*
  102. ::= 'M' type (value value)* 'Z' # key, value map pairs
  103. ::= 'H' (value value)* 'Z' # untyped key, value
  104. */
  105. $refindex = $this->refmap->getReference($map);
  106. if($refindex !== false){
  107. return $this->writeReference($refindex);
  108. }
  109. $this->refmap->objectlist[] = &$map;
  110. if($type == '') {
  111. $stream = 'H';
  112. } else{
  113. $stream = 'M';
  114. $stream .= $this->writeType($type);
  115. }
  116. foreach($map as $key => $value){
  117. $stream .= $this->writeValue($key);
  118. $stream .= $this->writeValue($value);
  119. }
  120. $stream .= 'Z';
  121. return $stream;
  122. }
  123. function writeObjectData($value){
  124. $stream = '';
  125. $class = get_class($value);
  126. $index = $this->refmap->getClassIndex($class);
  127. if($index === false){
  128. $classdef = new HessianClassDef();
  129. $classdef->type = $class;
  130. if($class == 'stdClass'){
  131. $classdef->props = array_keys(get_object_vars($value));
  132. } else
  133. $classdef->props = array_keys(get_class_vars($class));
  134. $index = $this->refmap->addClassDef($classdef);
  135. $total = count($classdef->props);
  136. $type = $this->typemap->getRemoteType($class);
  137. $class = $type ? $type : $class;
  138. $stream .= 'C';
  139. $stream .= $this->writeString($class);
  140. $stream .= $this->writeInt($total);
  141. foreach($classdef->props as $name){
  142. $stream .= $this->writeString($name);
  143. }
  144. }
  145. if($index < 16){
  146. $stream .= pack('c', $index + 0x60);
  147. } else{
  148. $stream .= 'O';
  149. $stream .= $this->writeInt($index);
  150. }
  151. $this->refmap->objectlist[] = $value;
  152. $classdef = $this->refmap->classlist[$index];
  153. foreach($classdef->props as $key){
  154. $val = $value->$key;
  155. $stream .= $this->writeValue($val);
  156. }
  157. return $stream;
  158. }
  159. function writeObject($value){
  160. //if($this->dateAdapter->isDatetime($value))
  161. // return $this->writeDate($value);
  162. $refindex = $this->refmap->getReference($value);
  163. if($refindex !== false){
  164. return $this->writeReference($refindex);
  165. }
  166. return $this->writeObjectData($value);
  167. }
  168. function writeType($type){
  169. $this->logMsg("writeType $type");
  170. $refindex = $this->refmap->getTypeIndex($type);
  171. if($refindex !== false){
  172. return $this->writeInt($refindex);
  173. }
  174. $this->references->typelist[] = $type;
  175. return $this->writeString($type);
  176. }
  177. function writeReference($value){
  178. $this->logMsg("writeReference $value");
  179. $stream = pack('c', 0x51);
  180. $stream .= $this->writeInt($value);
  181. return $stream;
  182. }
  183. function writeDate($value){
  184. //$ts = $this->dateAdapter->toTimestamp($value);
  185. $ts = $value;
  186. $this->logMsg("writeDate $ts");
  187. $stream = '';
  188. if($ts % 60 != 0){
  189. $stream = pack('c', 0x4a);
  190. $ts = $ts * 1000;
  191. $res = $ts / HessianUtils::pow32;
  192. $stream .= pack('N', $res);
  193. $stream .= pack('N', $ts);
  194. } else { // compact date, only minutes
  195. $ts = intval($ts / 60);
  196. $stream = pack('c', 0x4b);
  197. $stream .= pack('c', ($ts >> 24));
  198. $stream .= pack('c', ($ts >> 16));
  199. $stream .= pack('c', ($ts >> 8));
  200. $stream .= pack('c', $ts);
  201. }
  202. return $stream;
  203. }
  204. function writeBool($value){
  205. if($value) return 'T';
  206. else return 'F';
  207. }
  208. function between($value, $min, $max){
  209. return $min <= $value && $value <= $max;
  210. }
  211. function writeInt($value){
  212. if($this->between($value, -16, 47)){
  213. return pack('c', $value + 0x90);
  214. } else
  215. if($this->between($value, -2048, 2047)){
  216. $b0 = 0xc8 + ($value >> 8);
  217. $stream = pack('c', $b0);
  218. $stream .= pack('c', $value);
  219. return $stream;
  220. } else
  221. if($this->between($value, -262144, 262143)){
  222. $b0 = 0xd4 + ($value >> 16);
  223. $b1 = $value >> 8;
  224. $stream = pack('c', $b0);
  225. $stream .= pack('c', $b1);
  226. $stream .= pack('c', $value);
  227. return $stream;
  228. } else {
  229. $stream = 'I';
  230. $stream .= pack('c', ($value >> 24));
  231. $stream .= pack('c', ($value >> 16));
  232. $stream .= pack('c', ($value >> 8));
  233. $stream .= pack('c', $value);
  234. return $stream;
  235. }
  236. }
  237. function writeString($value){
  238. $len = HessianUtils::stringLength($value);
  239. if($len < 32){
  240. return pack('C', $len)
  241. . $this->writeStringData($value);
  242. } else
  243. if($len < 1024){
  244. $b0 = 0x30 + ($len >> 8);
  245. $stream = pack('C', $b0);
  246. $stream .= pack('C', $len);
  247. return $stream . $this->writeStringData($value);
  248. } else {
  249. // TODO :chunks
  250. $total = $len;
  251. $stream = '';
  252. $tag = 'S';
  253. $stream .= $tag . pack('n', $len);
  254. $stream .= $this->writeStringData($value);
  255. return $stream;
  256. }
  257. }
  258. function writeSmallString($value){
  259. $len = HessianUtils::stringLength($value);
  260. if($len < 32){
  261. return pack('C', $len)
  262. . $this->writeStringData($value);
  263. } else
  264. if($len < 1024){
  265. $b0 = 0x30 + ($len >> 8);
  266. $stream .= pack('C', $b0);
  267. $stream .= pack('C', $len);
  268. return $stream . $this->writeStringData($value);
  269. }
  270. }
  271. function writeStringData($string){
  272. return HessianUtils::writeUTF8($string);
  273. }
  274. function writeDouble($value) {
  275. $frac = abs($value) - floor(abs($value));
  276. if($value == 0)
  277. return pack('c', 0x5b);
  278. if($value == 1)
  279. return pack('c', 0x5c);
  280. $intValue = intval($value);
  281. // Issue 10, Fix thanks to nesnnaho...@googlemail.com,
  282. if($frac == 0 && (-128.0 <= $value && $value < 127)) {
  283. return pack('c', 0x5d) . pack('c', $value);
  284. }
  285. if($frac == 0 && (-32768.0 <= $value && $value < 32767.0)) {
  286. $stream = pack('c', 0x5e);
  287. $stream .= HessianUtils::floatBytes($value);
  288. return $stream;
  289. }
  290. // TODO double 4 el del 0.001, revisar
  291. $mills = (int) ($value * 1000);
  292. if (0.001 * $mills == $value) {
  293. $stream = pack('c', 0x5f);
  294. $stream .= pack('c', $mills >> 24);
  295. $stream .= pack('c', $mills >> 16);
  296. $stream .= pack('c', $mills >> 8);
  297. $stream .= pack('c', $mills);
  298. return $stream;
  299. }
  300. // 64 bit double
  301. $stream = 'D';
  302. $stream .= HessianUtils::doubleBytes($value);
  303. return $stream;
  304. }
  305. function writeResource($handle){
  306. $type = get_resource_type($handle);
  307. $stream = '';
  308. if($type == 'file' || $type == 'stream'){
  309. while (!feof($handle)) {
  310. $content = fread($handle, 32768);
  311. $len = count(str_split($content));
  312. if($len < 15){ // short binary
  313. $stream .= pack('C', $len + 0x20);
  314. $stream .= $content;
  315. } else {
  316. $tag = 'b';
  317. if(feof($handle))
  318. $tag = 'B';
  319. $stream .= $tag . pack('n', $len);
  320. $stream .= $content;
  321. }
  322. }
  323. fclose($handle);
  324. } else {
  325. throw new Exception("Cannot handle resource of type '$type'");
  326. }
  327. return $stream;
  328. }
  329. }