root/ext/wddx/wddx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wddx_stack_init
  2. wddx_stack_push
  3. wddx_stack_top
  4. wddx_stack_is_empty
  5. wddx_stack_destroy
  6. release_wddx_packet_rsrc
  7. PS_SERIALIZER_ENCODE_FUNC
  8. PS_SERIALIZER_DECODE_FUNC
  9. PHP_MINIT_FUNCTION
  10. PHP_MINFO_FUNCTION
  11. php_wddx_packet_start
  12. php_wddx_packet_end
  13. php_wddx_serialize_string
  14. php_wddx_serialize_number
  15. php_wddx_serialize_boolean
  16. php_wddx_serialize_unset
  17. php_wddx_serialize_object
  18. php_wddx_serialize_array
  19. php_wddx_serialize_var
  20. php_wddx_add_var
  21. php_wddx_push_element
  22. php_wddx_pop_element
  23. php_wddx_process_data
  24. php_wddx_deserialize_ex
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. php_wddx_constructor
  28. php_wddx_destructor
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Andrei Zmievski <andrei@php.net>                             |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 
  27 #if HAVE_WDDX
  28 
  29 #include "ext/xml/expat_compat.h"
  30 #include "php_wddx.h"
  31 #include "php_wddx_api.h"
  32 
  33 #define PHP_XML_INTERNAL
  34 #include "ext/xml/php_xml.h"
  35 #include "ext/standard/php_incomplete_class.h"
  36 #include "ext/standard/base64.h"
  37 #include "ext/standard/info.h"
  38 #include "zend_smart_str.h"
  39 #include "ext/standard/html.h"
  40 #include "ext/standard/php_string.h"
  41 #include "ext/date/php_date.h"
  42 #include "zend_globals.h"
  43 
  44 #define WDDX_BUF_LEN                    256
  45 #define PHP_CLASS_NAME_VAR              "php_class_name"
  46 
  47 #define EL_ARRAY                                "array"
  48 #define EL_BINARY                               "binary"
  49 #define EL_BOOLEAN                              "boolean"
  50 #define EL_CHAR                                 "char"
  51 #define EL_CHAR_CODE                    "code"
  52 #define EL_NULL                                 "null"
  53 #define EL_NUMBER                               "number"
  54 #define EL_PACKET                               "wddxPacket"
  55 #define EL_STRING                               "string"
  56 #define EL_STRUCT                               "struct"
  57 #define EL_VALUE                                "value"
  58 #define EL_VAR                                  "var"
  59 #define EL_NAME                         "name"
  60 #define EL_VERSION                              "version"
  61 #define EL_RECORDSET                    "recordset"
  62 #define EL_FIELD                                "field"
  63 #define EL_DATETIME                             "dateTime"
  64 
  65 #define php_wddx_deserialize(a,b) \
  66         php_wddx_deserialize_ex(Z_STRVAL_P(a), Z_STRLEN_P(a), (b))
  67 
  68 #define SET_STACK_VARNAME                                                       \
  69                 if (stack->varname) {                                           \
  70                         ent.varname = estrdup(stack->varname);  \
  71                         efree(stack->varname);                                  \
  72                         stack->varname = NULL;                                  \
  73                 } else                                                                          \
  74                         ent.varname = NULL;                                             \
  75 
  76 static int le_wddx;
  77 
  78 typedef struct {
  79         zval data;
  80         enum {
  81                 ST_ARRAY,
  82                 ST_BOOLEAN,
  83                 ST_NULL,
  84                 ST_NUMBER,
  85                 ST_STRING,
  86                 ST_BINARY,
  87                 ST_STRUCT,
  88                 ST_RECORDSET,
  89                 ST_FIELD,
  90                 ST_DATETIME
  91         } type;
  92         char *varname;
  93 } st_entry;
  94 
  95 typedef struct {
  96         int top, max;
  97         char *varname;
  98         zend_bool done;
  99         void **elements;
 100 } wddx_stack;
 101 
 102 
 103 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len);
 104 
 105 /* {{{ arginfo */
 106 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_value, 0, 0, 1)
 107         ZEND_ARG_INFO(0, var)
 108         ZEND_ARG_INFO(0, comment)
 109 ZEND_END_ARG_INFO()
 110 
 111 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars, 0, 0, 1)
 112         ZEND_ARG_VARIADIC_INFO(0, var_names)
 113 ZEND_END_ARG_INFO()
 114 
 115 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start, 0, 0, 0)
 116         ZEND_ARG_INFO(0, comment)
 117 ZEND_END_ARG_INFO()
 118 
 119 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end, 0, 0, 1)
 120         ZEND_ARG_INFO(0, packet_id)
 121 ZEND_END_ARG_INFO()
 122 
 123 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars, 0, 0, 2)
 124         ZEND_ARG_INFO(0, packet_id)
 125         ZEND_ARG_VARIADIC_INFO(0, var_names)
 126 ZEND_END_ARG_INFO()
 127 
 128 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_deserialize, 0, 0, 1)
 129         ZEND_ARG_INFO(0, packet)
 130 ZEND_END_ARG_INFO()
 131 /* }}} */
 132 
 133 /* {{{ wddx_functions[]
 134  */
 135 const zend_function_entry wddx_functions[] = {
 136         PHP_FE(wddx_serialize_value, arginfo_wddx_serialize_value)
 137         PHP_FE(wddx_serialize_vars,     arginfo_wddx_serialize_vars)
 138         PHP_FE(wddx_packet_start,       arginfo_wddx_serialize_start)
 139         PHP_FE(wddx_packet_end,         arginfo_wddx_packet_end)
 140         PHP_FE(wddx_add_vars,           arginfo_wddx_add_vars)
 141         PHP_FE(wddx_deserialize,        arginfo_wddx_deserialize)
 142         PHP_FE_END
 143 };
 144 /* }}} */
 145 
 146 PHP_MINIT_FUNCTION(wddx);
 147 PHP_MINFO_FUNCTION(wddx);
 148 
 149 /* {{{ dynamically loadable module stuff */
 150 #ifdef COMPILE_DL_WDDX
 151 ZEND_GET_MODULE(wddx)
 152 #endif /* COMPILE_DL_WDDX */
 153 /* }}} */
 154 
 155 /* {{{ wddx_module_entry
 156  */
 157 zend_module_entry wddx_module_entry = {
 158         STANDARD_MODULE_HEADER,
 159         "wddx",
 160         wddx_functions,
 161         PHP_MINIT(wddx),
 162         NULL,
 163         NULL,
 164         NULL,
 165         PHP_MINFO(wddx),
 166     PHP_WDDX_VERSION,
 167         STANDARD_MODULE_PROPERTIES
 168 };
 169 /* }}} */
 170 
 171 /* {{{ wddx_stack_init
 172  */
 173 static int wddx_stack_init(wddx_stack *stack)
 174 {
 175         stack->top = 0;
 176         stack->elements = (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE, 0);
 177         stack->max = STACK_BLOCK_SIZE;
 178         stack->varname = NULL;
 179         stack->done = 0;
 180 
 181         return SUCCESS;
 182 }
 183 /* }}} */
 184 
 185 /* {{{ wddx_stack_push
 186  */
 187 static int wddx_stack_push(wddx_stack *stack, void *element, int size)
 188 {
 189         if (stack->top >= stack->max) {         /* we need to allocate more memory */
 190                 stack->elements = (void **) erealloc(stack->elements,
 191                                    (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)));
 192         }
 193         stack->elements[stack->top] = (void *) emalloc(size);
 194         memcpy(stack->elements[stack->top], element, size);
 195         return stack->top++;
 196 }
 197 /* }}} */
 198 
 199 /* {{{ wddx_stack_top
 200  */
 201 static int wddx_stack_top(wddx_stack *stack, void **element)
 202 {
 203         if (stack->top > 0) {
 204                 *element = stack->elements[stack->top - 1];
 205                 return SUCCESS;
 206         } else {
 207                 *element = NULL;
 208                 return FAILURE;
 209         }
 210 }
 211 /* }}} */
 212 
 213 /* {{{ wddx_stack_is_empty
 214  */
 215 static int wddx_stack_is_empty(wddx_stack *stack)
 216 {
 217         if (stack->top == 0) {
 218                 return 1;
 219         } else {
 220                 return 0;
 221         }
 222 }
 223 /* }}} */
 224 
 225 /* {{{ wddx_stack_destroy
 226  */
 227 static int wddx_stack_destroy(wddx_stack *stack)
 228 {
 229         register int i;
 230 
 231         if (stack->elements) {
 232                 for (i = 0; i < stack->top; i++) {
 233                         zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
 234                         if (((st_entry *)stack->elements[i])->varname) {
 235                                 efree(((st_entry *)stack->elements[i])->varname);
 236                         }
 237                         efree(stack->elements[i]);
 238                 }
 239                 efree(stack->elements);
 240         }
 241         return SUCCESS;
 242 }
 243 /* }}} */
 244 
 245 /* {{{ release_wddx_packet_rsrc
 246  */
 247 static void release_wddx_packet_rsrc(zend_resource *rsrc)
 248 {
 249         smart_str *str = (smart_str *)rsrc->ptr;
 250         smart_str_free(str);
 251         efree(str);
 252 }
 253 /* }}} */
 254 
 255 #include "ext/session/php_session.h"
 256 
 257 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 258 /* {{{ PS_SERIALIZER_ENCODE_FUNC
 259  */
 260 PS_SERIALIZER_ENCODE_FUNC(wddx)
 261 {
 262         wddx_packet *packet;
 263         zend_string *str;
 264         PS_ENCODE_VARS;
 265 
 266         packet = php_wddx_constructor();
 267 
 268         php_wddx_packet_start(packet, NULL, 0);
 269         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 270 
 271         PS_ENCODE_LOOP(
 272                 php_wddx_serialize_var(packet, struc, key);
 273         );
 274 
 275         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 276         php_wddx_packet_end(packet);
 277         smart_str_0(packet);
 278         str = zend_string_copy(packet->s);
 279         php_wddx_destructor(packet);
 280 
 281         return str;
 282 }
 283 /* }}} */
 284 
 285 /* {{{ PS_SERIALIZER_DECODE_FUNC
 286  */
 287 PS_SERIALIZER_DECODE_FUNC(wddx)
 288 {
 289         zval retval;
 290         zval *ent;
 291         zend_string *key;
 292         zend_ulong idx;
 293         int ret;
 294 
 295         if (vallen == 0) {
 296                 return SUCCESS;
 297         }
 298 
 299         ZVAL_UNDEF(&retval);
 300         if ((ret = php_wddx_deserialize_ex(val, vallen, &retval)) == SUCCESS) {
 301                 if (Z_TYPE(retval) != IS_ARRAY) {
 302                         zval_dtor(&retval);
 303                         return FAILURE;
 304                 }
 305                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(retval), idx, key, ent) {
 306                         if (key == NULL) {
 307                                 key = zend_long_to_str(idx);
 308                         } else {
 309                                 zend_string_addref(key);
 310                         }
 311                         if (php_set_session_var(key, ent, NULL)) {
 312                                 if (Z_REFCOUNTED_P(ent)) Z_ADDREF_P(ent);
 313                         }
 314                         PS_ADD_VAR(key);
 315                         zend_string_release(key);
 316                 } ZEND_HASH_FOREACH_END();
 317         }
 318 
 319         zval_ptr_dtor(&retval);
 320 
 321         return ret;
 322 }
 323 /* }}} */
 324 #endif
 325 
 326 /* {{{ PHP_MINIT_FUNCTION
 327  */
 328 PHP_MINIT_FUNCTION(wddx)
 329 {
 330         le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
 331 
 332 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 333         php_session_register_serializer("wddx",
 334                                                                         PS_SERIALIZER_ENCODE_NAME(wddx),
 335                                                                         PS_SERIALIZER_DECODE_NAME(wddx));
 336 #endif
 337 
 338         return SUCCESS;
 339 }
 340 /* }}} */
 341 
 342 /* {{{ PHP_MINFO_FUNCTION
 343  */
 344 PHP_MINFO_FUNCTION(wddx)
 345 {
 346         php_info_print_table_start();
 347 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 348         php_info_print_table_header(2, "WDDX Support", "enabled" );
 349         php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
 350 #else
 351         php_info_print_table_row(2, "WDDX Support", "enabled" );
 352 #endif
 353         php_info_print_table_end();
 354 }
 355 /* }}} */
 356 
 357 /* {{{ php_wddx_packet_start
 358  */
 359 void php_wddx_packet_start(wddx_packet *packet, char *comment, size_t comment_len)
 360 {
 361         php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
 362         if (comment) {
 363                 php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
 364                 php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
 365                 php_wddx_add_chunk_ex(packet, comment, comment_len);
 366                 php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
 367                 php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
 368         } else {
 369                 php_wddx_add_chunk_static(packet, WDDX_HEADER);
 370         }
 371         php_wddx_add_chunk_static(packet, WDDX_DATA_S);
 372 }
 373 /* }}} */
 374 
 375 /* {{{ php_wddx_packet_end
 376  */
 377 void php_wddx_packet_end(wddx_packet *packet)
 378 {
 379         php_wddx_add_chunk_static(packet, WDDX_DATA_E);
 380         php_wddx_add_chunk_static(packet, WDDX_PACKET_E);
 381 }
 382 /* }}} */
 383 
 384 #define FLUSH_BUF()                               \
 385         if (l > 0) {                                  \
 386                 php_wddx_add_chunk_ex(packet, buf, l);    \
 387                 l = 0;                                    \
 388         }
 389 
 390 /* {{{ php_wddx_serialize_string
 391  */
 392 static void php_wddx_serialize_string(wddx_packet *packet, zval *var)
 393 {
 394         php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 395 
 396         if (Z_STRLEN_P(var) > 0) {
 397                 zend_string *buf = php_escape_html_entities(
 398                         (unsigned char *) Z_STRVAL_P(var), Z_STRLEN_P(var), 0, ENT_QUOTES, NULL);
 399 
 400                 php_wddx_add_chunk_ex(packet, ZSTR_VAL(buf), ZSTR_LEN(buf));
 401 
 402                 zend_string_release(buf);
 403         }
 404         php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 405 }
 406 /* }}} */
 407 
 408 /* {{{ php_wddx_serialize_number
 409  */
 410 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
 411 {
 412         char tmp_buf[WDDX_BUF_LEN];
 413         zend_string *str = zval_get_string(var);
 414         snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, ZSTR_VAL(str));
 415         zend_string_release(str);
 416 
 417         php_wddx_add_chunk(packet, tmp_buf);
 418 }
 419 /* }}} */
 420 
 421 /* {{{ php_wddx_serialize_boolean
 422  */
 423 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
 424 {
 425         php_wddx_add_chunk(packet, Z_TYPE_P(var) == IS_TRUE ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
 426 }
 427 /* }}} */
 428 
 429 /* {{{ php_wddx_serialize_unset
 430  */
 431 static void php_wddx_serialize_unset(wddx_packet *packet)
 432 {
 433         php_wddx_add_chunk_static(packet, WDDX_NULL);
 434 }
 435 /* }}} */
 436 
 437 /* {{{ php_wddx_serialize_object
 438  */
 439 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
 440 {
 441 /* OBJECTS_FIXME */
 442         zval *ent, fname, *varname;
 443         zval retval;
 444         zend_string *key;
 445         zend_ulong idx;
 446         char tmp_buf[WDDX_BUF_LEN];
 447         HashTable *objhash, *sleephash;
 448 
 449         ZVAL_STRING(&fname, "__sleep");
 450         /*
 451          * We try to call __sleep() method on object. It's supposed to return an
 452          * array of property names to be serialized.
 453          */
 454         if (call_user_function_ex(CG(function_table), obj, &fname, &retval, 0, 0, 1, NULL) == SUCCESS) {
 455                 if (!Z_ISUNDEF(retval) && (sleephash = HASH_OF(&retval))) {
 456                         PHP_CLASS_ATTRIBUTES;
 457 
 458                         PHP_SET_CLASS_ATTRIBUTES(obj);
 459 
 460                         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 461                         snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
 462                         php_wddx_add_chunk(packet, tmp_buf);
 463                         php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 464                         php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
 465                         php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 466                         php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 467 
 468                         PHP_CLEANUP_CLASS_ATTRIBUTES();
 469 
 470                         objhash = Z_OBJPROP_P(obj);
 471 
 472                         ZEND_HASH_FOREACH_VAL(sleephash, varname) {
 473                                 if (Z_TYPE_P(varname) != IS_STRING) {
 474                                         php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
 475                                         continue;
 476                                 }
 477 
 478                                 if ((ent = zend_hash_find(objhash, Z_STR_P(varname))) != NULL) {
 479                                         php_wddx_serialize_var(packet, ent, Z_STR_P(varname));
 480                                 }
 481                         } ZEND_HASH_FOREACH_END();
 482 
 483                         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 484                 }
 485         } else {
 486                 PHP_CLASS_ATTRIBUTES;
 487 
 488                 PHP_SET_CLASS_ATTRIBUTES(obj);
 489 
 490                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 491                 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
 492                 php_wddx_add_chunk(packet, tmp_buf);
 493                 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 494                 php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
 495                 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 496                 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 497 
 498                 PHP_CLEANUP_CLASS_ATTRIBUTES();
 499 
 500                 objhash = Z_OBJPROP_P(obj);
 501                 ZEND_HASH_FOREACH_KEY_VAL(objhash, idx, key, ent) {
 502                         if (ent == obj) {
 503                                 continue;
 504                         }
 505                         if (key) {
 506                                 const char *class_name, *prop_name;
 507                                 size_t prop_name_len;
 508                                 zend_string *tmp;
 509 
 510                                 zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
 511                                 tmp = zend_string_init(prop_name, prop_name_len, 0);
 512                                 php_wddx_serialize_var(packet, ent, tmp);
 513                                 zend_string_release(tmp);
 514                         } else {
 515                                 key = zend_long_to_str(idx);
 516                                 php_wddx_serialize_var(packet, ent, key);
 517                                 zend_string_release(key);
 518                         }
 519                 } ZEND_HASH_FOREACH_END();
 520                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 521         }
 522 
 523         zval_ptr_dtor(&fname);
 524         zval_ptr_dtor(&retval);
 525 }
 526 /* }}} */
 527 
 528 /* {{{ php_wddx_serialize_array
 529  */
 530 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
 531 {
 532         zval *ent;
 533         zend_string *key;
 534         int is_struct = 0;
 535         zend_ulong idx;
 536         HashTable *target_hash;
 537         char tmp_buf[WDDX_BUF_LEN];
 538         zend_ulong ind = 0;
 539 
 540         target_hash = Z_ARRVAL_P(arr);
 541         ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
 542                 if (key) {
 543                         is_struct = 1;
 544                         break;
 545                 }
 546 
 547                 if (idx != ind) {
 548                         is_struct = 1;
 549                         break;
 550                 }
 551                 ind++;
 552         } ZEND_HASH_FOREACH_END();
 553 
 554         if (is_struct) {
 555                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 556         } else {
 557                 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
 558                 php_wddx_add_chunk(packet, tmp_buf);
 559         }
 560 
 561         ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
 562                 if (ent == arr) {
 563                         continue;
 564                 }
 565 
 566                 if (is_struct) {
 567                         if (key) {
 568                                 php_wddx_serialize_var(packet, ent, key);
 569                         } else {
 570                                 key = zend_long_to_str(idx);
 571                                 php_wddx_serialize_var(packet, ent, key);
 572                                 zend_string_release(key);
 573                         }
 574                 } else {
 575                         php_wddx_serialize_var(packet, ent, NULL);
 576                 }
 577         } ZEND_HASH_FOREACH_END();
 578 
 579         if (is_struct) {
 580                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 581         } else {
 582                 php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
 583         }
 584 }
 585 /* }}} */
 586 
 587 /* {{{ php_wddx_serialize_var
 588  */
 589 void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
 590 {
 591         HashTable *ht;
 592 
 593         if (name) {
 594                 char *tmp_buf;
 595                 zend_string *name_esc = php_escape_html_entities((unsigned char *) ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES, NULL);
 596                 tmp_buf = emalloc(ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S));
 597                 snprintf(tmp_buf, ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S), WDDX_VAR_S, ZSTR_VAL(name_esc));
 598                 php_wddx_add_chunk(packet, tmp_buf);
 599                 efree(tmp_buf);
 600                 zend_string_release(name_esc);
 601         }
 602 
 603         if (Z_TYPE_P(var) == IS_INDIRECT) {
 604                 var = Z_INDIRECT_P(var);
 605         }
 606         ZVAL_DEREF(var);
 607         switch (Z_TYPE_P(var)) {
 608                 case IS_STRING:
 609                         php_wddx_serialize_string(packet, var);
 610                         break;
 611 
 612                 case IS_LONG:
 613                 case IS_DOUBLE:
 614                         php_wddx_serialize_number(packet, var);
 615                         break;
 616 
 617                 case IS_TRUE:
 618                 case IS_FALSE:
 619                         php_wddx_serialize_boolean(packet, var);
 620                         break;
 621 
 622                 case IS_NULL:
 623                         php_wddx_serialize_unset(packet);
 624                         break;
 625 
 626                 case IS_ARRAY:
 627                         ht = Z_ARRVAL_P(var);
 628                         if (ht->u.v.nApplyCount > 1) {
 629                                 php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
 630                                 return;
 631                         }
 632                         if (ZEND_HASH_APPLY_PROTECTION(ht)) {
 633                                 ht->u.v.nApplyCount++;
 634                         }
 635                         php_wddx_serialize_array(packet, var);
 636                         if (ZEND_HASH_APPLY_PROTECTION(ht)) {
 637                                 ht->u.v.nApplyCount--;
 638                         }
 639                         break;
 640 
 641                 case IS_OBJECT:
 642                         ht = Z_OBJPROP_P(var);
 643                         if (ht->u.v.nApplyCount > 1) {
 644                                 php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
 645                                 return;
 646                         }
 647                         ht->u.v.nApplyCount++;
 648                         php_wddx_serialize_object(packet, var);
 649                         ht->u.v.nApplyCount--;
 650                         break;
 651         }
 652 
 653         if (name) {
 654                 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 655         }
 656 }
 657 /* }}} */
 658 
 659 /* {{{ php_wddx_add_var
 660  */
 661 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
 662 {
 663         zval *val;
 664         HashTable *target_hash;
 665 
 666         if (Z_TYPE_P(name_var) == IS_STRING) {
 667                 zend_array *symbol_table = zend_rebuild_symbol_table();
 668                 if ((val = zend_hash_find(symbol_table, Z_STR_P(name_var))) != NULL) {
 669                         if (Z_TYPE_P(val) == IS_INDIRECT) {
 670                                 val = Z_INDIRECT_P(val);
 671                         }
 672                         php_wddx_serialize_var(packet, val, Z_STR_P(name_var));
 673                 }
 674         } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT)   {
 675                 int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
 676 
 677                 target_hash = HASH_OF(name_var);
 678 
 679                 if (is_array && target_hash->u.v.nApplyCount > 1) {
 680                         php_error_docref(NULL, E_WARNING, "recursion detected");
 681                         return;
 682                 }
 683 
 684                 if (Z_IMMUTABLE_P(name_var)) {
 685                         ZEND_HASH_FOREACH_VAL(target_hash, val) {
 686                                 php_wddx_add_var(packet, val);
 687                         } ZEND_HASH_FOREACH_END();
 688                 } else {
 689                         ZEND_HASH_FOREACH_VAL(target_hash, val) {
 690                                 if (is_array) {
 691                                         target_hash->u.v.nApplyCount++;
 692                                 }
 693 
 694                                 ZVAL_DEREF(val);
 695                                 php_wddx_add_var(packet, val);
 696 
 697                                 if (is_array) {
 698                                         target_hash->u.v.nApplyCount--;
 699                                 }
 700                         } ZEND_HASH_FOREACH_END();
 701                 }
 702         }
 703 }
 704 /* }}} */
 705 
 706 /* {{{ php_wddx_push_element
 707  */
 708 static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
 709 {
 710         st_entry ent;
 711         wddx_stack *stack = (wddx_stack *)user_data;
 712         if (!strcmp((char *)name, EL_PACKET)) {
 713                 int i;
 714 
 715                 if (atts) for (i=0; atts[i]; i++) {
 716                         if (!strcmp((char *)atts[i], EL_VERSION)) {
 717                                 /* nothing for now */
 718                         }
 719                 }
 720         } else if (!strcmp((char *)name, EL_STRING)) {
 721                 ent.type = ST_STRING;
 722                 SET_STACK_VARNAME;
 723 
 724                 ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
 725                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 726         } else if (!strcmp((char *)name, EL_BINARY)) {
 727                 ent.type = ST_BINARY;
 728                 SET_STACK_VARNAME;
 729 
 730                 ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
 731                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 732         } else if (!strcmp((char *)name, EL_CHAR)) {
 733                 int i;
 734 
 735                 if (atts) for (i = 0; atts[i]; i++) {
 736                         if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
 737                                 char tmp_buf[2];
 738 
 739                                 snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i], NULL, 16));
 740                                 php_wddx_process_data(user_data, (XML_Char *) tmp_buf, strlen(tmp_buf));
 741                                 break;
 742                         }
 743                 }
 744         } else if (!strcmp((char *)name, EL_NUMBER)) {
 745                 ent.type = ST_NUMBER;
 746                 SET_STACK_VARNAME;
 747 
 748                 ZVAL_LONG(&ent.data, 0);
 749                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 750         } else if (!strcmp((char *)name, EL_BOOLEAN)) {
 751                 int i;
 752 
 753                 if (atts) for (i = 0; atts[i]; i++) {
 754                         if (!strcmp((char *)atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
 755                                 ent.type = ST_BOOLEAN;
 756                                 SET_STACK_VARNAME;
 757 
 758                                 ZVAL_TRUE(&ent.data);
 759                                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 760                                 php_wddx_process_data(user_data, atts[i], strlen((char *)atts[i]));
 761                                 break;
 762                         }
 763                 }
 764         } else if (!strcmp((char *)name, EL_NULL)) {
 765                 ent.type = ST_NULL;
 766                 SET_STACK_VARNAME;
 767 
 768                 ZVAL_NULL(&ent.data);
 769 
 770                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 771         } else if (!strcmp((char *)name, EL_ARRAY)) {
 772                 ent.type = ST_ARRAY;
 773                 SET_STACK_VARNAME;
 774 
 775                 array_init(&ent.data);
 776                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 777         } else if (!strcmp((char *)name, EL_STRUCT)) {
 778                 ent.type = ST_STRUCT;
 779                 SET_STACK_VARNAME;
 780                 array_init(&ent.data);
 781                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 782         } else if (!strcmp((char *)name, EL_VAR)) {
 783                 int i;
 784 
 785                 if (atts) for (i = 0; atts[i]; i++) {
 786                         if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
 787                                 stack->varname = estrdup((char *)atts[i]);
 788                                 break;
 789                         }
 790                 }
 791         } else if (!strcmp((char *)name, EL_RECORDSET)) {
 792                 int i;
 793 
 794                 ent.type = ST_RECORDSET;
 795                 SET_STACK_VARNAME;
 796                 array_init(&ent.data);
 797 
 798                 if (atts) for (i = 0; atts[i]; i++) {
 799                         if (!strcmp((char *)atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
 800                                 zval tmp;
 801                                 char *key;
 802                                 const char *p1, *p2, *endp;
 803 
 804                                 endp = (char *)atts[i] + strlen((char *)atts[i]);
 805                                 p1 = (char *)atts[i];
 806                                 while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
 807                                         key = estrndup(p1, p2 - p1);
 808                                         array_init(&tmp);
 809                                         add_assoc_zval_ex(&ent.data, key, p2 - p1, &tmp);
 810                                         p1 = p2 + sizeof(",")-1;
 811                                         efree(key);
 812                                 }
 813 
 814                                 if (p1 <= endp) {
 815                                         array_init(&tmp);
 816                                         add_assoc_zval_ex(&ent.data, p1, endp - p1, &tmp);
 817                                 }
 818 
 819                                 break;
 820                         }
 821                 }
 822 
 823                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 824         } else if (!strcmp((char *)name, EL_FIELD)) {
 825                 int i;
 826                 st_entry ent;
 827 
 828                 ent.type = ST_FIELD;
 829                 ent.varname = NULL;
 830                 ZVAL_UNDEF(&ent.data);
 831 
 832                 if (atts) for (i = 0; atts[i]; i++) {
 833                         if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
 834                                 st_entry *recordset;
 835                                 zval *field;
 836 
 837                                 if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
 838                                         recordset->type == ST_RECORDSET &&
 839                                         (field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i], strlen((char *)atts[i]))) != NULL) {
 840                                         ZVAL_COPY_VALUE(&ent.data, field);
 841                                 }
 842 
 843                                 break;
 844                         }
 845                 }
 846 
 847                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 848         } else if (!strcmp((char *)name, EL_DATETIME)) {
 849                 ent.type = ST_DATETIME;
 850                 SET_STACK_VARNAME;
 851 
 852                 ZVAL_LONG(&ent.data, 0);
 853                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 854         }
 855 }
 856 /* }}} */
 857 
 858 /* {{{ php_wddx_pop_element
 859  */
 860 static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 861 {
 862         st_entry                        *ent1, *ent2;
 863         wddx_stack                      *stack = (wddx_stack *)user_data;
 864         HashTable                       *target_hash;
 865         zend_class_entry        *pce;
 866         zval                            obj;
 867 
 868 /* OBJECTS_FIXME */
 869         if (stack->top == 0) {
 870                 return;
 871         }
 872 
 873         if (!strcmp((char *)name, EL_STRING) || !strcmp((char *)name, EL_NUMBER) ||
 874                 !strcmp((char *)name, EL_BOOLEAN) || !strcmp((char *)name, EL_NULL) ||
 875                 !strcmp((char *)name, EL_ARRAY) || !strcmp((char *)name, EL_STRUCT) ||
 876                 !strcmp((char *)name, EL_RECORDSET) || !strcmp((char *)name, EL_BINARY) ||
 877                 !strcmp((char *)name, EL_DATETIME)) {
 878                 wddx_stack_top(stack, (void**)&ent1);
 879 
 880                 if (Z_TYPE(ent1->data) == IS_UNDEF) {
 881                         if (stack->top > 1) {
 882                                 stack->top--;
 883                         } else {
 884                                 stack->done = 1;
 885                         }
 886                         efree(ent1);
 887                         return;
 888                 }
 889 
 890                 if (!strcmp((char *)name, EL_BINARY)) {
 891                         zend_string *new_str = php_base64_decode(
 892                                 (unsigned char *)Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
 893                         zval_ptr_dtor(&ent1->data);
 894                         ZVAL_STR(&ent1->data, new_str);
 895                 }
 896 
 897                 /* Call __wakeup() method on the object. */
 898                 if (Z_TYPE(ent1->data) == IS_OBJECT) {
 899                         zval fname, retval;
 900 
 901                         ZVAL_STRING(&fname, "__wakeup");
 902 
 903                         call_user_function_ex(NULL, &ent1->data, &fname, &retval, 0, 0, 0, NULL);
 904 
 905                         zval_ptr_dtor(&fname);
 906                         zval_ptr_dtor(&retval);
 907                 }
 908 
 909                 if (stack->top > 1) {
 910                         stack->top--;
 911                         wddx_stack_top(stack, (void**)&ent2);
 912 
 913                         /* if non-existent field */
 914                         if (ent2->type == ST_FIELD && Z_ISUNDEF(ent2->data)) {
 915                                 zval_ptr_dtor(&ent1->data);
 916                                 efree(ent1);
 917                                 return;
 918                         }
 919 
 920                         if (Z_TYPE(ent2->data) == IS_ARRAY || Z_TYPE(ent2->data) == IS_OBJECT) {
 921                                 target_hash = HASH_OF(&ent2->data);
 922 
 923                                 if (ent1->varname) {
 924                                         if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
 925                                                 Z_TYPE(ent1->data) == IS_STRING && Z_STRLEN(ent1->data) &&
 926                                                 ent2->type == ST_STRUCT && Z_TYPE(ent2->data) == IS_ARRAY) {
 927                                                 zend_bool incomplete_class = 0;
 928 
 929                                                 zend_str_tolower(Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
 930                                                 zend_string_forget_hash_val(Z_STR(ent1->data));
 931                                                 if ((pce = zend_hash_find_ptr(EG(class_table), Z_STR(ent1->data))) == NULL) {
 932                                                         incomplete_class = 1;
 933                                                         pce = PHP_IC_ENTRY;
 934                                                 }
 935 
 936                                                 /* Initialize target object */
 937                                                 object_init_ex(&obj, pce);
 938 
 939                                                 /* Merge current hashtable with object's default properties */
 940                                                 zend_hash_merge(Z_OBJPROP(obj),
 941                                                                                 Z_ARRVAL(ent2->data),
 942                                                                                 zval_add_ref, 0);
 943 
 944                                                 if (incomplete_class) {
 945                                                         php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
 946                                                 }
 947 
 948                                                 /* Clean up old array entry */
 949                                                 zval_ptr_dtor(&ent2->data);
 950 
 951                                                 /* Set stack entry to point to the newly created object */
 952                                                 ZVAL_COPY_VALUE(&ent2->data, &obj);
 953 
 954                                                 /* Clean up class name var entry */
 955                                                 zval_ptr_dtor(&ent1->data);
 956                                         } else if (Z_TYPE(ent2->data) == IS_OBJECT) {
 957                                                 zend_class_entry *old_scope = EG(scope);
 958 
 959                                                 EG(scope) = Z_OBJCE(ent2->data);
 960                                                 add_property_zval(&ent2->data, ent1->varname, &ent1->data);
 961                                                 if Z_REFCOUNTED(ent1->data) Z_DELREF(ent1->data);
 962                                                 EG(scope) = old_scope;
 963                                         } else {
 964                                                 zend_symtable_str_update(target_hash, ent1->varname, strlen(ent1->varname), &ent1->data);
 965                                         }
 966                                         efree(ent1->varname);
 967                                 } else  {
 968                                         zend_hash_next_index_insert(target_hash, &ent1->data);
 969                                 }
 970                         }
 971                         efree(ent1);
 972                 } else {
 973                         stack->done = 1;
 974                 }
 975         } else if (!strcmp((char *)name, EL_VAR) && stack->varname) {
 976                 efree(stack->varname);
 977                 stack->varname = NULL;
 978         } else if (!strcmp((char *)name, EL_FIELD)) {
 979                 st_entry *ent;
 980                 wddx_stack_top(stack, (void **)&ent);
 981                 efree(ent);
 982                 stack->top--;
 983         }
 984 }
 985 /* }}} */
 986 
 987 /* {{{ php_wddx_process_data
 988  */
 989 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
 990 {
 991         st_entry *ent;
 992         wddx_stack *stack = (wddx_stack *)user_data;
 993 
 994         if (!wddx_stack_is_empty(stack) && !stack->done) {
 995                 wddx_stack_top(stack, (void**)&ent);
 996                 switch (ent->type) {
 997                         case ST_BINARY:
 998                         case ST_STRING:
 999                                 if (Z_STRLEN(ent->data) == 0) {
1000                                         zval_ptr_dtor(&ent->data);
1001                                         ZVAL_STRINGL(&ent->data, (char *)s, len);
1002                                 } else {
1003                                         Z_STR(ent->data) = zend_string_extend(Z_STR(ent->data), Z_STRLEN(ent->data) + len, 0);
1004                                         memcpy(Z_STRVAL(ent->data) + Z_STRLEN(ent->data) - len, (char *)s, len);
1005                                         Z_STRVAL(ent->data)[Z_STRLEN(ent->data)] = '\0';
1006                                 }
1007                                 break;
1008                         case ST_NUMBER:
1009                                 ZVAL_STRINGL(&ent->data, (char *)s, len);
1010                                 convert_scalar_to_number(&ent->data);
1011                                 break;
1012 
1013                         case ST_BOOLEAN:
1014                                 if (!strcmp((char *)s, "true")) {
1015                                         Z_LVAL(ent->data) = 1;
1016                                 } else if (!strcmp((char *)s, "false")) {
1017                                         Z_LVAL(ent->data) = 0;
1018                                 } else {
1019                                         zval_ptr_dtor(&ent->data);
1020                                         if (ent->varname) {
1021                                                 efree(ent->varname);
1022                                         }
1023                                         ZVAL_UNDEF(&ent->data);
1024                                 }
1025                                 break;
1026 
1027                         case ST_DATETIME: {
1028                                 char *tmp;
1029 
1030                                 tmp = emalloc(len + 1);
1031                                 memcpy(tmp, (char *)s, len);
1032                                 tmp[len] = '\0';
1033 
1034                                 Z_LVAL(ent->data) = php_parse_date(tmp, NULL);
1035                                 /* date out of range < 1969 or > 2038 */
1036                                 if (Z_LVAL(ent->data) == -1) {
1037                                         ZVAL_STRINGL(&ent->data, (char *)s, len);
1038                                 }
1039                                 efree(tmp);
1040                         }
1041                                 break;
1042 
1043                         default:
1044                                 break;
1045                 }
1046         }
1047 }
1048 /* }}} */
1049 
1050 /* {{{ php_wddx_deserialize_ex
1051  */
1052 int php_wddx_deserialize_ex(const char *value, size_t vallen, zval *return_value)
1053 {
1054         wddx_stack stack;
1055         XML_Parser parser;
1056         st_entry *ent;
1057         int retval;
1058 
1059         wddx_stack_init(&stack);
1060         parser = XML_ParserCreate((XML_Char *) "UTF-8");
1061 
1062         XML_SetUserData(parser, &stack);
1063         XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
1064         XML_SetCharacterDataHandler(parser, php_wddx_process_data);
1065 
1066         /* XXX value should be parsed in the loop to exhaust size_t */
1067         XML_Parse(parser, (const XML_Char *) value, (int)vallen, 1);
1068 
1069         XML_ParserFree(parser);
1070 
1071         if (stack.top == 1) {
1072                 wddx_stack_top(&stack, (void**)&ent);
1073                 ZVAL_COPY(return_value, &ent->data);
1074                 retval = SUCCESS;
1075         } else {
1076                 retval = FAILURE;
1077         }
1078 
1079         wddx_stack_destroy(&stack);
1080 
1081         return retval;
1082 }
1083 /* }}} */
1084 
1085 /* {{{ proto string wddx_serialize_value(mixed var [, string comment])
1086    Creates a new packet and serializes the given value */
1087 PHP_FUNCTION(wddx_serialize_value)
1088 {
1089         zval *var;
1090         char *comment = NULL;
1091         size_t comment_len = 0;
1092         wddx_packet *packet;
1093 
1094         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &var, &comment, &comment_len) == FAILURE) {
1095                 return;
1096         }
1097 
1098         packet = php_wddx_constructor();
1099 
1100         php_wddx_packet_start(packet, comment, comment_len);
1101         php_wddx_serialize_var(packet, var, NULL);
1102         php_wddx_packet_end(packet);
1103         smart_str_0(packet);
1104 
1105         RETVAL_STR_COPY(packet->s);
1106         php_wddx_destructor(packet);
1107 }
1108 /* }}} */
1109 
1110 /* {{{ proto string wddx_serialize_vars(mixed var_name [, mixed ...])
1111    Creates a new packet and serializes given variables into a struct */
1112 PHP_FUNCTION(wddx_serialize_vars)
1113 {
1114         int num_args, i;
1115         wddx_packet *packet;
1116         zval *args = NULL;
1117 
1118         if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) {
1119                 return;
1120         }
1121 
1122         packet = php_wddx_constructor();
1123 
1124         php_wddx_packet_start(packet, NULL, 0);
1125         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1126 
1127         for (i=0; i<num_args; i++) {
1128                 zval *arg;
1129                 if (!Z_ISREF(args[i])) {
1130                         arg = &args[i];
1131                 } else {
1132                         arg = Z_REFVAL(args[i]);
1133                 }
1134                 if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
1135                         convert_to_string_ex(arg);
1136                 }
1137                 php_wddx_add_var(packet, arg);
1138         }
1139 
1140         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1141         php_wddx_packet_end(packet);
1142         smart_str_0(packet);
1143 
1144         RETVAL_STR_COPY(packet->s);
1145         php_wddx_destructor(packet);
1146 }
1147 /* }}} */
1148 
1149 /* {{{ php_wddx_constructor
1150  */
1151 wddx_packet *php_wddx_constructor(void)
1152 {
1153         smart_str *packet;
1154 
1155         packet = ecalloc(1, sizeof(smart_str));
1156 
1157         return packet;
1158 }
1159 /* }}} */
1160 
1161 /* {{{ php_wddx_destructor
1162  */
1163 void php_wddx_destructor(wddx_packet *packet)
1164 {
1165         smart_str_free(packet);
1166         efree(packet);
1167 }
1168 /* }}} */
1169 
1170 /* {{{ proto resource wddx_packet_start([string comment])
1171    Starts a WDDX packet with optional comment and returns the packet id */
1172 PHP_FUNCTION(wddx_packet_start)
1173 {
1174         char *comment = NULL;
1175         size_t comment_len = 0;
1176         wddx_packet *packet;
1177 
1178         comment = NULL;
1179 
1180         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &comment, &comment_len) == FAILURE) {
1181                 return;
1182         }
1183 
1184         packet = php_wddx_constructor();
1185 
1186         php_wddx_packet_start(packet, comment, comment_len);
1187         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1188 
1189         RETURN_RES(zend_register_resource(packet, le_wddx));
1190 }
1191 /* }}} */
1192 
1193 /* {{{ proto string wddx_packet_end(resource packet_id)
1194    Ends specified WDDX packet and returns the string containing the packet */
1195 PHP_FUNCTION(wddx_packet_end)
1196 {
1197         zval *packet_id;
1198         wddx_packet *packet = NULL;
1199 
1200         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &packet_id) == FAILURE) {
1201                 return;
1202         }
1203 
1204         if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
1205                 RETURN_FALSE;
1206         }
1207 
1208         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1209 
1210         php_wddx_packet_end(packet);
1211         smart_str_0(packet);
1212 
1213         RETVAL_STR_COPY(packet->s);
1214 
1215         zend_list_close(Z_RES_P(packet_id));
1216 }
1217 /* }}} */
1218 
1219 /* {{{ proto bool wddx_add_vars(resource packet_id,  mixed var_names [, mixed ...])
1220    Serializes given variables and adds them to packet given by packet_id */
1221 PHP_FUNCTION(wddx_add_vars)
1222 {
1223         int num_args, i;
1224         zval *args = NULL;
1225         zval *packet_id;
1226         wddx_packet *packet = NULL;
1227 
1228         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r+", &packet_id, &args, &num_args) == FAILURE) {
1229                 return;
1230         }
1231 
1232         if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
1233                 RETURN_FALSE;
1234         }
1235 
1236         for (i=0; i<num_args; i++) {
1237                 zval *arg;
1238                 if (!Z_ISREF(args[i])) {
1239                         arg = &args[i];
1240                 } else {
1241                         arg = Z_REFVAL(args[i]);
1242                 }
1243                 if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
1244                         convert_to_string_ex(arg);
1245                 }
1246                 php_wddx_add_var(packet, arg);
1247         }
1248 
1249         RETURN_TRUE;
1250 }
1251 /* }}} */
1252 
1253 /* {{{ proto mixed wddx_deserialize(mixed packet)
1254    Deserializes given packet and returns a PHP value */
1255 PHP_FUNCTION(wddx_deserialize)
1256 {
1257         zval *packet;
1258         php_stream *stream = NULL;
1259         zend_string *payload = NULL;
1260 
1261         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &packet) == FAILURE) {
1262                 return;
1263         }
1264 
1265         if (Z_TYPE_P(packet) == IS_STRING) {
1266                 payload = Z_STR_P(packet);
1267         } else if (Z_TYPE_P(packet) == IS_RESOURCE) {
1268                 php_stream_from_zval(stream, packet);
1269                 if (stream) {
1270                         payload = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
1271                 }
1272         } else {
1273                 php_error_docref(NULL, E_WARNING, "Expecting parameter 1 to be a string or a stream");
1274                 return;
1275         }
1276 
1277         if (payload == NULL) {
1278                 return;
1279         }
1280 
1281         php_wddx_deserialize_ex(ZSTR_VAL(payload), ZSTR_LEN(payload), return_value);
1282 
1283         if (stream) {
1284                 efree(payload);
1285         }
1286 }
1287 /* }}} */
1288 
1289 #endif /* HAVE_LIBEXPAT */
1290 
1291 /*
1292  * Local variables:
1293  * tab-width: 4
1294  * c-basic-offset: 4
1295  * End:
1296  * vim600: sw=4 ts=4 fdm=marker
1297  * vim<600: sw=4 ts=4
1298  */

/* [<][>][^][v][top][bottom][index][help] */