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 5                                                        |
   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 "ext/standard/php_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((a)->value.str.val, (a)->value.str.len, (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     NO_VERSION_YET,
 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                         if (((st_entry *)stack->elements[i])->data)     {
 234                                 zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
 235                         }
 236                         if (((st_entry *)stack->elements[i])->varname) {
 237                                 efree(((st_entry *)stack->elements[i])->varname);
 238                         }
 239                         efree(stack->elements[i]);
 240                 }
 241                 efree(stack->elements);
 242         }
 243         return SUCCESS;
 244 }
 245 /* }}} */
 246 
 247 /* {{{ release_wddx_packet_rsrc
 248  */
 249 static void release_wddx_packet_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 250 {
 251         smart_str *str = (smart_str *)rsrc->ptr;
 252         smart_str_free(str);
 253         efree(str);
 254 }
 255 /* }}} */
 256 
 257 #include "ext/session/php_session.h"
 258 
 259 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 260 /* {{{ PS_SERIALIZER_ENCODE_FUNC
 261  */
 262 PS_SERIALIZER_ENCODE_FUNC(wddx)
 263 {
 264         wddx_packet *packet;
 265         PS_ENCODE_VARS;
 266 
 267         packet = php_wddx_constructor();
 268 
 269         php_wddx_packet_start(packet, NULL, 0);
 270         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 271 
 272         PS_ENCODE_LOOP(
 273                 php_wddx_serialize_var(packet, *struc, key, key_length TSRMLS_CC);
 274         );
 275 
 276         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 277         php_wddx_packet_end(packet);
 278         *newstr = php_wddx_gather(packet);
 279         php_wddx_destructor(packet);
 280 
 281         if (newlen) {
 282                 *newlen = strlen(*newstr);
 283         }
 284 
 285         return SUCCESS;
 286 }
 287 /* }}} */
 288 
 289 /* {{{ PS_SERIALIZER_DECODE_FUNC
 290  */
 291 PS_SERIALIZER_DECODE_FUNC(wddx)
 292 {
 293         zval *retval;
 294         zval **ent;
 295         char *key;
 296         uint key_length;
 297         char tmp[128];
 298         ulong idx;
 299         int hash_type;
 300         int ret;
 301 
 302         if (vallen == 0) {
 303                 return SUCCESS;
 304         }
 305 
 306         MAKE_STD_ZVAL(retval);
 307 
 308         if ((ret = php_wddx_deserialize_ex((char *)val, vallen, retval)) == SUCCESS) {
 309                 if (Z_TYPE_P(retval) != IS_ARRAY) {
 310                         zval_ptr_dtor(&retval);
 311                         return FAILURE;
 312                 }
 313                 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(retval));
 314                          zend_hash_get_current_data(Z_ARRVAL_P(retval), (void **) &ent) == SUCCESS;
 315                          zend_hash_move_forward(Z_ARRVAL_P(retval))) {
 316                         hash_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(retval), &key, &key_length, &idx, 0, NULL);
 317 
 318                         switch (hash_type) {
 319                                 case HASH_KEY_IS_LONG:
 320                                         key_length = slprintf(tmp, sizeof(tmp), "%ld", idx) + 1;
 321                                         key = tmp;
 322                                         /* fallthru */
 323                                 case HASH_KEY_IS_STRING:
 324                                         php_set_session_var(key, key_length-1, *ent, NULL TSRMLS_CC);
 325                                         PS_ADD_VAR(key);
 326                         }
 327                 }
 328         }
 329 
 330         zval_ptr_dtor(&retval);
 331 
 332         return ret;
 333 }
 334 /* }}} */
 335 #endif
 336 
 337 /* {{{ PHP_MINIT_FUNCTION
 338  */
 339 PHP_MINIT_FUNCTION(wddx)
 340 {
 341         le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
 342 
 343 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 344         php_session_register_serializer("wddx",
 345                                                                         PS_SERIALIZER_ENCODE_NAME(wddx),
 346                                                                         PS_SERIALIZER_DECODE_NAME(wddx));
 347 #endif
 348 
 349         return SUCCESS;
 350 }
 351 /* }}} */
 352 
 353 /* {{{ PHP_MINFO_FUNCTION
 354  */
 355 PHP_MINFO_FUNCTION(wddx)
 356 {
 357         php_info_print_table_start();
 358 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
 359         php_info_print_table_header(2, "WDDX Support", "enabled" );
 360         php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
 361 #else
 362         php_info_print_table_row(2, "WDDX Support", "enabled" );
 363 #endif
 364         php_info_print_table_end();
 365 }
 366 /* }}} */
 367 
 368 /* {{{ php_wddx_packet_start
 369  */
 370 void php_wddx_packet_start(wddx_packet *packet, char *comment, int comment_len)
 371 {
 372         php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
 373         if (comment) {
 374                 php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
 375                 php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
 376                 php_wddx_add_chunk_ex(packet, comment, comment_len);
 377                 php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
 378                 php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
 379         } else {
 380                 php_wddx_add_chunk_static(packet, WDDX_HEADER);
 381         }
 382         php_wddx_add_chunk_static(packet, WDDX_DATA_S);
 383 }
 384 /* }}} */
 385 
 386 /* {{{ php_wddx_packet_end
 387  */
 388 void php_wddx_packet_end(wddx_packet *packet)
 389 {
 390         php_wddx_add_chunk_static(packet, WDDX_DATA_E);
 391         php_wddx_add_chunk_static(packet, WDDX_PACKET_E);
 392 }
 393 /* }}} */
 394 
 395 #define FLUSH_BUF()                               \
 396         if (l > 0) {                                  \
 397                 php_wddx_add_chunk_ex(packet, buf, l);    \
 398                 l = 0;                                    \
 399         }
 400 
 401 /* {{{ php_wddx_serialize_string
 402  */
 403 static void php_wddx_serialize_string(wddx_packet *packet, zval *var TSRMLS_DC)
 404 {
 405         php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 406 
 407         if (Z_STRLEN_P(var) > 0) {
 408                 char *buf;
 409                 size_t buf_len;
 410 
 411                 buf = php_escape_html_entities(Z_STRVAL_P(var), Z_STRLEN_P(var), &buf_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
 412 
 413                 php_wddx_add_chunk_ex(packet, buf, buf_len);
 414 
 415                 str_efree(buf);
 416         }
 417         php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 418 }
 419 /* }}} */
 420 
 421 /* {{{ php_wddx_serialize_number
 422  */
 423 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
 424 {
 425         char tmp_buf[WDDX_BUF_LEN];
 426         zval tmp;
 427 
 428         tmp = *var;
 429         zval_copy_ctor(&tmp);
 430         convert_to_string(&tmp);
 431         snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, Z_STRVAL(tmp));
 432         zval_dtor(&tmp);
 433 
 434         php_wddx_add_chunk(packet, tmp_buf);
 435 }
 436 /* }}} */
 437 
 438 /* {{{ php_wddx_serialize_boolean
 439  */
 440 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
 441 {
 442         php_wddx_add_chunk(packet, Z_LVAL_P(var) ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
 443 }
 444 /* }}} */
 445 
 446 /* {{{ php_wddx_serialize_unset
 447  */
 448 static void php_wddx_serialize_unset(wddx_packet *packet)
 449 {
 450         php_wddx_add_chunk_static(packet, WDDX_NULL);
 451 }
 452 /* }}} */
 453 
 454 /* {{{ php_wddx_serialize_object
 455  */
 456 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
 457 {
 458 /* OBJECTS_FIXME */
 459         zval **ent, *fname, **varname;
 460         zval *retval = NULL;
 461         const char *key;
 462         ulong idx;
 463         char tmp_buf[WDDX_BUF_LEN];
 464         HashTable *objhash, *sleephash;
 465         TSRMLS_FETCH();
 466 
 467         MAKE_STD_ZVAL(fname);
 468         ZVAL_STRING(fname, "__sleep", 1);
 469 
 470         /*
 471          * We try to call __sleep() method on object. It's supposed to return an
 472          * array of property names to be serialized.
 473          */
 474         if (call_user_function_ex(CG(function_table), &obj, fname, &retval, 0, 0, 1, NULL TSRMLS_CC) == SUCCESS) {
 475                 if (retval && (sleephash = HASH_OF(retval))) {
 476                         PHP_CLASS_ATTRIBUTES;
 477 
 478                         PHP_SET_CLASS_ATTRIBUTES(obj);
 479 
 480                         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 481                         snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
 482                         php_wddx_add_chunk(packet, tmp_buf);
 483                         php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 484                         php_wddx_add_chunk_ex(packet, class_name, name_len);
 485                         php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 486                         php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 487 
 488                         PHP_CLEANUP_CLASS_ATTRIBUTES();
 489 
 490                         objhash = HASH_OF(obj);
 491 
 492                         for (zend_hash_internal_pointer_reset(sleephash);
 493                                  zend_hash_get_current_data(sleephash, (void **)&varname) == SUCCESS;
 494                                  zend_hash_move_forward(sleephash)) {
 495                                 if (Z_TYPE_PP(varname) != IS_STRING) {
 496                                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
 497                                         continue;
 498                                 }
 499 
 500                                 if (zend_hash_find(objhash, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, (void **)&ent) == SUCCESS) {
 501                                         php_wddx_serialize_var(packet, *ent, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) TSRMLS_CC);
 502                                 }
 503                         }
 504 
 505                         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 506                 }
 507         } else {
 508                 uint key_len;
 509 
 510                 PHP_CLASS_ATTRIBUTES;
 511 
 512                 PHP_SET_CLASS_ATTRIBUTES(obj);
 513 
 514                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 515                 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
 516                 php_wddx_add_chunk(packet, tmp_buf);
 517                 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
 518                 php_wddx_add_chunk_ex(packet, class_name, name_len);
 519                 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
 520                 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 521 
 522                 PHP_CLEANUP_CLASS_ATTRIBUTES();
 523 
 524                 objhash = HASH_OF(obj);
 525                 for (zend_hash_internal_pointer_reset(objhash);
 526                          zend_hash_get_current_data(objhash, (void**)&ent) == SUCCESS;
 527                          zend_hash_move_forward(objhash)) {
 528                         if (*ent == obj) {
 529                                 continue;
 530                         }
 531 
 532                         if (zend_hash_get_current_key_ex(objhash, &key, &key_len, &idx, 0, NULL) == HASH_KEY_IS_STRING) {
 533                                 const char *class_name, *prop_name;
 534 
 535                                 zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
 536                                 php_wddx_serialize_var(packet, *ent, prop_name, strlen(prop_name)+1 TSRMLS_CC);
 537                         } else {
 538                                 key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
 539                                 php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
 540                         }
 541                 }
 542                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 543         }
 544 
 545         zval_dtor(fname);
 546         FREE_ZVAL(fname);
 547 
 548         if (retval) {
 549                 zval_ptr_dtor(&retval);
 550         }
 551 }
 552 /* }}} */
 553 
 554 /* {{{ php_wddx_serialize_array
 555  */
 556 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
 557 {
 558         zval **ent;
 559         char *key;
 560         uint key_len;
 561         int is_struct = 0, ent_type;
 562         ulong idx;
 563         HashTable *target_hash;
 564         char tmp_buf[WDDX_BUF_LEN];
 565         ulong ind = 0;
 566         int type;
 567         TSRMLS_FETCH();
 568 
 569         target_hash = HASH_OF(arr);
 570 
 571         for (zend_hash_internal_pointer_reset(target_hash);
 572                  zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
 573                  zend_hash_move_forward(target_hash)) {
 574 
 575                 type = zend_hash_get_current_key(target_hash, &key, &idx, 0);
 576 
 577                 if (type == HASH_KEY_IS_STRING) {
 578                         is_struct = 1;
 579                         break;
 580                 }
 581 
 582                 if (idx != ind) {
 583                         is_struct = 1;
 584                         break;
 585                 }
 586 
 587                 ind++;
 588         }
 589 
 590         if (is_struct) {
 591                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
 592         } else {
 593                 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
 594                 php_wddx_add_chunk(packet, tmp_buf);
 595         }
 596 
 597         for (zend_hash_internal_pointer_reset(target_hash);
 598                  zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
 599                  zend_hash_move_forward(target_hash)) {
 600                 if (*ent == arr) {
 601                         continue;
 602                 }
 603 
 604                 if (is_struct) {
 605                         ent_type = zend_hash_get_current_key_ex(target_hash, &key, &key_len, &idx, 0, NULL);
 606 
 607                         if (ent_type == HASH_KEY_IS_STRING) {
 608                                 php_wddx_serialize_var(packet, *ent, key, key_len TSRMLS_CC);
 609                         } else {
 610                                 key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
 611                                 php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
 612                         }
 613                 } else {
 614                         php_wddx_serialize_var(packet, *ent, NULL, 0 TSRMLS_CC);
 615                 }
 616         }
 617 
 618         if (is_struct) {
 619                 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
 620         } else {
 621                 php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
 622         }
 623 }
 624 /* }}} */
 625 
 626 /* {{{ php_wddx_serialize_var
 627  */
 628 void php_wddx_serialize_var(wddx_packet *packet, zval *var, char *name, int name_len TSRMLS_DC)
 629 {
 630         HashTable *ht;
 631 
 632         if (name) {
 633                 size_t name_esc_len;
 634                 char *tmp_buf, *name_esc;
 635 
 636                 name_esc = php_escape_html_entities(name, name_len, &name_esc_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
 637                 tmp_buf = emalloc(name_esc_len + sizeof(WDDX_VAR_S));
 638                 snprintf(tmp_buf, name_esc_len + sizeof(WDDX_VAR_S), WDDX_VAR_S, name_esc);
 639                 php_wddx_add_chunk(packet, tmp_buf);
 640                 efree(tmp_buf);
 641                 str_efree(name_esc);
 642         }
 643 
 644         switch(Z_TYPE_P(var)) {
 645                 case IS_STRING:
 646                         php_wddx_serialize_string(packet, var TSRMLS_CC);
 647                         break;
 648 
 649                 case IS_LONG:
 650                 case IS_DOUBLE:
 651                         php_wddx_serialize_number(packet, var);
 652                         break;
 653 
 654                 case IS_BOOL:
 655                         php_wddx_serialize_boolean(packet, var);
 656                         break;
 657 
 658                 case IS_NULL:
 659                         php_wddx_serialize_unset(packet);
 660                         break;
 661 
 662                 case IS_ARRAY:
 663                         ht = Z_ARRVAL_P(var);
 664                         if (ht->nApplyCount > 1) {
 665                                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
 666                                 return;
 667                         }
 668                         ht->nApplyCount++;
 669                         php_wddx_serialize_array(packet, var);
 670                         ht->nApplyCount--;
 671                         break;
 672 
 673                 case IS_OBJECT:
 674                         ht = Z_OBJPROP_P(var);
 675                         if (ht->nApplyCount > 1) {
 676                                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
 677                                 return;
 678                         }
 679                         ht->nApplyCount++;
 680                         php_wddx_serialize_object(packet, var);
 681                         ht->nApplyCount--;
 682                         break;
 683         }
 684 
 685         if (name) {
 686                 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
 687         }
 688 }
 689 /* }}} */
 690 
 691 /* {{{ php_wddx_add_var
 692  */
 693 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
 694 {
 695         zval **val;
 696         HashTable *target_hash;
 697         TSRMLS_FETCH();
 698 
 699         if (Z_TYPE_P(name_var) == IS_STRING) {
 700                 if (!EG(active_symbol_table)) {
 701                         zend_rebuild_symbol_table(TSRMLS_C);
 702                 }
 703                 if (zend_hash_find(EG(active_symbol_table), Z_STRVAL_P(name_var),
 704                                                         Z_STRLEN_P(name_var)+1, (void**)&val) != FAILURE) {
 705                         php_wddx_serialize_var(packet, *val, Z_STRVAL_P(name_var), Z_STRLEN_P(name_var) TSRMLS_CC);
 706                 }
 707         } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT)   {
 708                 int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
 709 
 710                 target_hash = HASH_OF(name_var);
 711 
 712                 if (is_array && target_hash->nApplyCount > 1) {
 713                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
 714                         return;
 715                 }
 716 
 717                 zend_hash_internal_pointer_reset(target_hash);
 718 
 719                 while(zend_hash_get_current_data(target_hash, (void**)&val) == SUCCESS) {
 720                         if (is_array) {
 721                                 target_hash->nApplyCount++;
 722                         }
 723 
 724                         php_wddx_add_var(packet, *val);
 725 
 726                         if (is_array) {
 727                                 target_hash->nApplyCount--;
 728                         }
 729                         zend_hash_move_forward(target_hash);
 730                 }
 731         }
 732 }
 733 /* }}} */
 734 
 735 /* {{{ php_wddx_push_element
 736  */
 737 static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
 738 {
 739         st_entry ent;
 740         wddx_stack *stack = (wddx_stack *)user_data;
 741 
 742         if (!strcmp(name, EL_PACKET)) {
 743                 int i;
 744 
 745                 if (atts) for (i=0; atts[i]; i++) {
 746                         if (!strcmp(atts[i], EL_VERSION)) {
 747                                 /* nothing for now */
 748                         }
 749                 }
 750         } else if (!strcmp(name, EL_STRING)) {
 751                 ent.type = ST_STRING;
 752                 SET_STACK_VARNAME;
 753 
 754                 ALLOC_ZVAL(ent.data);
 755                 INIT_PZVAL(ent.data);
 756                 Z_TYPE_P(ent.data) = IS_STRING;
 757                 Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
 758                 Z_STRLEN_P(ent.data) = 0;
 759                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 760         } else if (!strcmp(name, EL_BINARY)) {
 761                 ent.type = ST_BINARY;
 762                 SET_STACK_VARNAME;
 763 
 764                 ALLOC_ZVAL(ent.data);
 765                 INIT_PZVAL(ent.data);
 766                 Z_TYPE_P(ent.data) = IS_STRING;
 767                 Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
 768                 Z_STRLEN_P(ent.data) = 0;
 769                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 770         } else if (!strcmp(name, EL_CHAR)) {
 771                 int i;
 772 
 773                 if (atts) for (i = 0; atts[i]; i++) {
 774                         if (!strcmp(atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
 775                                 char tmp_buf[2];
 776 
 777                                 snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol(atts[i], NULL, 16));
 778                                 php_wddx_process_data(user_data, tmp_buf, strlen(tmp_buf));
 779                                 break;
 780                         }
 781                 }
 782         } else if (!strcmp(name, EL_NUMBER)) {
 783                 ent.type = ST_NUMBER;
 784                 SET_STACK_VARNAME;
 785 
 786                 ALLOC_ZVAL(ent.data);
 787                 INIT_PZVAL(ent.data);
 788                 Z_TYPE_P(ent.data) = IS_LONG;
 789                 Z_LVAL_P(ent.data) = 0;
 790                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 791         } else if (!strcmp(name, EL_BOOLEAN)) {
 792                 int i;
 793 
 794                 if (atts) for (i = 0; atts[i]; i++) {
 795                         if (!strcmp(atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
 796                                 ent.type = ST_BOOLEAN;
 797                                 SET_STACK_VARNAME;
 798 
 799                                 ALLOC_ZVAL(ent.data);
 800                                 INIT_PZVAL(ent.data);
 801                                 Z_TYPE_P(ent.data) = IS_BOOL;
 802                                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 803                                 php_wddx_process_data(user_data, atts[i], strlen(atts[i]));
 804                                 break;
 805                         }
 806                 }
 807         } else if (!strcmp(name, EL_NULL)) {
 808                 ent.type = ST_NULL;
 809                 SET_STACK_VARNAME;
 810 
 811                 ALLOC_ZVAL(ent.data);
 812                 INIT_PZVAL(ent.data);
 813                 ZVAL_NULL(ent.data);
 814 
 815                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 816         } else if (!strcmp(name, EL_ARRAY)) {
 817                 ent.type = ST_ARRAY;
 818                 SET_STACK_VARNAME;
 819 
 820                 ALLOC_ZVAL(ent.data);
 821                 array_init(ent.data);
 822                 INIT_PZVAL(ent.data);
 823                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 824         } else if (!strcmp(name, EL_STRUCT)) {
 825                 ent.type = ST_STRUCT;
 826                 SET_STACK_VARNAME;
 827 
 828                 ALLOC_ZVAL(ent.data);
 829                 array_init(ent.data);
 830                 INIT_PZVAL(ent.data);
 831                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 832         } else if (!strcmp(name, EL_VAR)) {
 833                 int i;
 834 
 835                 if (atts) for (i = 0; atts[i]; i++) {
 836                         if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
 837                                 stack->varname = estrdup(atts[i]);
 838                                 break;
 839                         }
 840                 }
 841         } else if (!strcmp(name, EL_RECORDSET)) {
 842                 int i;
 843 
 844                 ent.type = ST_RECORDSET;
 845                 SET_STACK_VARNAME;
 846                 MAKE_STD_ZVAL(ent.data);
 847                 array_init(ent.data);
 848 
 849                 if (atts) for (i = 0; atts[i]; i++) {
 850                         if (!strcmp(atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
 851                                 zval *tmp;
 852                                 char *key;
 853                                 char *p1, *p2, *endp;
 854 
 855                                 endp = (char *)atts[i] + strlen(atts[i]);
 856                                 p1 = (char *)atts[i];
 857                                 while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
 858                                         key = estrndup(p1, p2 - p1);
 859                                         MAKE_STD_ZVAL(tmp);
 860                                         array_init(tmp);
 861                                         add_assoc_zval_ex(ent.data, key, p2 - p1 + 1, tmp);
 862                                         p1 = p2 + sizeof(",")-1;
 863                                         efree(key);
 864                                 }
 865 
 866                                 if (p1 <= endp) {
 867                                         MAKE_STD_ZVAL(tmp);
 868                                         array_init(tmp);
 869                                         add_assoc_zval_ex(ent.data, p1, endp - p1 + 1, tmp);
 870                                 }
 871 
 872                                 break;
 873                         }
 874                 }
 875 
 876                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 877         } else if (!strcmp(name, EL_FIELD)) {
 878                 int i;
 879                 st_entry ent;
 880 
 881                 ent.type = ST_FIELD;
 882                 ent.varname = NULL;
 883                 ent.data = NULL;
 884 
 885                 if (atts) for (i = 0; atts[i]; i++) {
 886                         if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
 887                                 st_entry *recordset;
 888                                 zval **field;
 889 
 890                                 if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
 891                                         recordset->type == ST_RECORDSET &&
 892                                         zend_hash_find(Z_ARRVAL_P(recordset->data), (char*)atts[i], strlen(atts[i])+1, (void**)&field) == SUCCESS) {
 893                                         ent.data = *field;
 894                                 }
 895 
 896                                 break;
 897                         }
 898                 }
 899 
 900                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 901         } else if (!strcmp(name, EL_DATETIME)) {
 902                 ent.type = ST_DATETIME;
 903                 SET_STACK_VARNAME;
 904 
 905                 ALLOC_ZVAL(ent.data);
 906                 INIT_PZVAL(ent.data);
 907                 Z_TYPE_P(ent.data) = IS_LONG;
 908                 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
 909         }
 910 }
 911 /* }}} */
 912 
 913 /* {{{ php_wddx_pop_element
 914  */
 915 static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 916 {
 917         st_entry                        *ent1, *ent2;
 918         wddx_stack                      *stack = (wddx_stack *)user_data;
 919         HashTable                       *target_hash;
 920         zend_class_entry        **pce;
 921         zval                            *obj;
 922         zval                            *tmp;
 923         TSRMLS_FETCH();
 924 
 925 /* OBJECTS_FIXME */
 926         if (stack->top == 0) {
 927                 return;
 928         }
 929 
 930         if (!strcmp(name, EL_STRING) || !strcmp(name, EL_NUMBER) ||
 931                 !strcmp(name, EL_BOOLEAN) || !strcmp(name, EL_NULL) ||
 932                 !strcmp(name, EL_ARRAY) || !strcmp(name, EL_STRUCT) ||
 933                 !strcmp(name, EL_RECORDSET) || !strcmp(name, EL_BINARY) ||
 934                 !strcmp(name, EL_DATETIME)) {
 935                 wddx_stack_top(stack, (void**)&ent1);
 936 
 937                 if (!ent1->data) {
 938                         if (stack->top > 1) {
 939                                 stack->top--;
 940                         } else {
 941                                 stack->done = 1;
 942                         }
 943                         efree(ent1);
 944                         return;
 945                 }
 946 
 947                 if (!strcmp(name, EL_BINARY)) {
 948                         int new_len=0;
 949                         unsigned char *new_str;
 950 
 951                         new_str = php_base64_decode(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data), &new_len);
 952                         STR_FREE(Z_STRVAL_P(ent1->data));
 953                         Z_STRVAL_P(ent1->data) = new_str;
 954                         Z_STRLEN_P(ent1->data) = new_len;
 955                 }
 956 
 957                 /* Call __wakeup() method on the object. */
 958                 if (Z_TYPE_P(ent1->data) == IS_OBJECT) {
 959                         zval *fname, *retval = NULL;
 960 
 961                         MAKE_STD_ZVAL(fname);
 962                         ZVAL_STRING(fname, "__wakeup", 1);
 963 
 964                         call_user_function_ex(NULL, &ent1->data, fname, &retval, 0, 0, 0, NULL TSRMLS_CC);
 965 
 966                         zval_dtor(fname);
 967                         FREE_ZVAL(fname);
 968                         if (retval) {
 969                                 zval_ptr_dtor(&retval);
 970                         }
 971                 }
 972 
 973                 if (stack->top > 1) {
 974                         stack->top--;
 975                         wddx_stack_top(stack, (void**)&ent2);
 976 
 977                         /* if non-existent field */
 978                         if (ent2->type == ST_FIELD && ent2->data == NULL) {
 979                                 zval_ptr_dtor(&ent1->data);
 980                                 efree(ent1);
 981                                 return;
 982                         }
 983 
 984                         if (Z_TYPE_P(ent2->data) == IS_ARRAY || Z_TYPE_P(ent2->data) == IS_OBJECT) {
 985                                 target_hash = HASH_OF(ent2->data);
 986 
 987                                 if (ent1->varname) {
 988                                         if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
 989                                                 Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data) &&
 990                                                 ent2->type == ST_STRUCT && Z_TYPE_P(ent2->data) == IS_ARRAY) {
 991                                                 zend_bool incomplete_class = 0;
 992 
 993                                                 zend_str_tolower(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
 994                                                 if (zend_hash_find(EG(class_table), Z_STRVAL_P(ent1->data),
 995                                                                                    Z_STRLEN_P(ent1->data)+1, (void **) &pce)==FAILURE) {
 996                                                         incomplete_class = 1;
 997                                                         pce = &PHP_IC_ENTRY;
 998                                                 }
 999 
1000                                                 /* Initialize target object */
1001                                                 MAKE_STD_ZVAL(obj);
1002                                                 object_init_ex(obj, *pce);
1003 
1004                                                 /* Merge current hashtable with object's default properties */
1005                                                 zend_hash_merge(Z_OBJPROP_P(obj),
1006                                                                                 Z_ARRVAL_P(ent2->data),
1007                                                                                 (void (*)(void *)) zval_add_ref,
1008                                                                                 (void *) &tmp, sizeof(zval *), 0);
1009 
1010                                                 if (incomplete_class) {
1011                                                         php_store_class_name(obj, Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
1012                                                 }
1013 
1014                                                 /* Clean up old array entry */
1015                                                 zval_ptr_dtor(&ent2->data);
1016 
1017                                                 /* Set stack entry to point to the newly created object */
1018                                                 ent2->data = obj;
1019 
1020                                                 /* Clean up class name var entry */
1021                                                 zval_ptr_dtor(&ent1->data);
1022                                         } else if (Z_TYPE_P(ent2->data) == IS_OBJECT) {
1023                                                 zend_class_entry *old_scope = EG(scope);
1024 
1025                                                 EG(scope) = Z_OBJCE_P(ent2->data);
1026                                                 Z_DELREF_P(ent1->data);
1027                                                 add_property_zval(ent2->data, ent1->varname, ent1->data);
1028                                                 EG(scope) = old_scope;
1029                                         } else {
1030                                                 zend_symtable_update(target_hash, ent1->varname, strlen(ent1->varname)+1, &ent1->data, sizeof(zval *), NULL);
1031                                         }
1032                                         efree(ent1->varname);
1033                                 } else  {
1034                                         zend_hash_next_index_insert(target_hash, &ent1->data, sizeof(zval *), NULL);
1035                                 }
1036                         }
1037                         efree(ent1);
1038                 } else {
1039                         stack->done = 1;
1040                 }
1041         } else if (!strcmp(name, EL_VAR) && stack->varname) {
1042                 efree(stack->varname);
1043                 stack->varname = NULL;
1044         } else if (!strcmp(name, EL_FIELD)) {
1045                 st_entry *ent;
1046                 wddx_stack_top(stack, (void **)&ent);
1047                 efree(ent);
1048                 stack->top--;
1049         }
1050 }
1051 /* }}} */
1052 
1053 /* {{{ php_wddx_process_data
1054  */
1055 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
1056 {
1057         st_entry *ent;
1058         wddx_stack *stack = (wddx_stack *)user_data;
1059         TSRMLS_FETCH();
1060 
1061         if (!wddx_stack_is_empty(stack) && !stack->done) {
1062                 wddx_stack_top(stack, (void**)&ent);
1063                 switch (ent->type) {
1064                         case ST_STRING:
1065                                 if (Z_STRLEN_P(ent->data) == 0) {
1066                                         STR_FREE(Z_STRVAL_P(ent->data));
1067                                         Z_STRVAL_P(ent->data) = estrndup(s, len);
1068                                         Z_STRLEN_P(ent->data) = len;
1069                                 } else {
1070                                         Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
1071                                         memcpy(Z_STRVAL_P(ent->data) + Z_STRLEN_P(ent->data), s, len);
1072                                         Z_STRLEN_P(ent->data) += len;
1073                                         Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0';
1074                                 }
1075                                 break;
1076 
1077                         case ST_BINARY:
1078                                 if (Z_STRLEN_P(ent->data) == 0) {
1079                                         STR_FREE(Z_STRVAL_P(ent->data));
1080                                         Z_STRVAL_P(ent->data) = estrndup(s, len + 1);
1081                                 } else {
1082                                         Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
1083                                         memcpy(Z_STRVAL_P(ent->data) + Z_STRLEN_P(ent->data), s, len);
1084                                 }
1085                                 Z_STRLEN_P(ent->data) += len;
1086                                 Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0';
1087                                 break;
1088 
1089                         case ST_NUMBER:
1090                                 Z_TYPE_P(ent->data) = IS_STRING;
1091                                 Z_STRLEN_P(ent->data) = len;
1092                                 Z_STRVAL_P(ent->data) = estrndup(s, len);
1093                                 convert_scalar_to_number(ent->data TSRMLS_CC);
1094                                 break;
1095 
1096                         case ST_BOOLEAN:
1097                                 if (!strcmp(s, "true")) {
1098                                         Z_LVAL_P(ent->data) = 1;
1099                                 } else if (!strcmp(s, "false")) {
1100                                         Z_LVAL_P(ent->data) = 0;
1101                                 } else {
1102                                         zval_ptr_dtor(&ent->data);
1103                                         if (ent->varname) {
1104                                                 efree(ent->varname);
1105                                         }
1106                                         ent->data = NULL;
1107                                 }
1108                                 break;
1109 
1110                         case ST_DATETIME: {
1111                                 char *tmp;
1112 
1113                                 tmp = emalloc(len + 1);
1114                                 memcpy(tmp, s, len);
1115                                 tmp[len] = '\0';
1116 
1117                                 Z_LVAL_P(ent->data) = php_parse_date(tmp, NULL);
1118                                 /* date out of range < 1969 or > 2038 */
1119                                 if (Z_LVAL_P(ent->data) == -1) {
1120                                         Z_TYPE_P(ent->data) = IS_STRING;
1121                                         Z_STRLEN_P(ent->data) = len;
1122                                         Z_STRVAL_P(ent->data) = estrndup(s, len);
1123                                 }
1124                                 efree(tmp);
1125                         }
1126                                 break;
1127 
1128                         default:
1129                                 break;
1130                 }
1131         }
1132 }
1133 /* }}} */
1134 
1135 /* {{{ php_wddx_deserialize_ex
1136  */
1137 int php_wddx_deserialize_ex(char *value, int vallen, zval *return_value)
1138 {
1139         wddx_stack stack;
1140         XML_Parser parser;
1141         st_entry *ent;
1142         int retval;
1143 
1144         wddx_stack_init(&stack);
1145         parser = XML_ParserCreate("UTF-8");
1146 
1147         XML_SetUserData(parser, &stack);
1148         XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
1149         XML_SetCharacterDataHandler(parser, php_wddx_process_data);
1150 
1151         XML_Parse(parser, value, vallen, 1);
1152 
1153         XML_ParserFree(parser);
1154 
1155         if (stack.top == 1) {
1156                 wddx_stack_top(&stack, (void**)&ent);
1157                 *return_value = *(ent->data);
1158                 zval_copy_ctor(return_value);
1159                 retval = SUCCESS;
1160         } else {
1161                 retval = FAILURE;
1162         }
1163 
1164         wddx_stack_destroy(&stack);
1165 
1166         return retval;
1167 }
1168 /* }}} */
1169 
1170 /* {{{ proto string wddx_serialize_value(mixed var [, string comment])
1171    Creates a new packet and serializes the given value */
1172 PHP_FUNCTION(wddx_serialize_value)
1173 {
1174         zval *var;
1175         char *comment = NULL;
1176         int comment_len = 0;
1177         wddx_packet *packet;
1178 
1179         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &var, &comment, &comment_len) == FAILURE) {
1180                 return;
1181         }
1182 
1183         packet = php_wddx_constructor();
1184 
1185         php_wddx_packet_start(packet, comment, comment_len);
1186         php_wddx_serialize_var(packet, var, NULL, 0 TSRMLS_CC);
1187         php_wddx_packet_end(packet);
1188 
1189         ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1190         smart_str_free(packet);
1191         efree(packet);
1192 }
1193 /* }}} */
1194 
1195 /* {{{ proto string wddx_serialize_vars(mixed var_name [, mixed ...])
1196    Creates a new packet and serializes given variables into a struct */
1197 PHP_FUNCTION(wddx_serialize_vars)
1198 {
1199         int num_args, i;
1200         wddx_packet *packet;
1201         zval ***args = NULL;
1202 
1203         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
1204                 return;
1205         }
1206 
1207         packet = php_wddx_constructor();
1208 
1209         php_wddx_packet_start(packet, NULL, 0);
1210         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1211 
1212         for (i=0; i<num_args; i++) {
1213                 if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
1214                         convert_to_string_ex(args[i]);
1215                 }
1216                 php_wddx_add_var(packet, *args[i]);
1217         }
1218 
1219         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1220         php_wddx_packet_end(packet);
1221 
1222         efree(args);
1223 
1224         ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1225         smart_str_free(packet);
1226         efree(packet);
1227 }
1228 /* }}} */
1229 
1230 /* {{{ php_wddx_constructor
1231  */
1232 wddx_packet *php_wddx_constructor(void)
1233 {
1234         smart_str *packet;
1235 
1236         packet = (smart_str *)emalloc(sizeof(smart_str));
1237         packet->c = NULL;
1238 
1239         return packet;
1240 }
1241 /* }}} */
1242 
1243 /* {{{ php_wddx_destructor
1244  */
1245 void php_wddx_destructor(wddx_packet *packet)
1246 {
1247         smart_str_free(packet);
1248         efree(packet);
1249 }
1250 /* }}} */
1251 
1252 /* {{{ proto resource wddx_packet_start([string comment])
1253    Starts a WDDX packet with optional comment and returns the packet id */
1254 PHP_FUNCTION(wddx_packet_start)
1255 {
1256         char *comment = NULL;
1257         int comment_len = 0;
1258         wddx_packet *packet;
1259 
1260         comment = NULL;
1261 
1262         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &comment, &comment_len) == FAILURE) {
1263                 return;
1264         }
1265 
1266         packet = php_wddx_constructor();
1267 
1268         php_wddx_packet_start(packet, comment, comment_len);
1269         php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1270 
1271         ZEND_REGISTER_RESOURCE(return_value, packet, le_wddx);
1272 }
1273 /* }}} */
1274 
1275 /* {{{ proto string wddx_packet_end(resource packet_id)
1276    Ends specified WDDX packet and returns the string containing the packet */
1277 PHP_FUNCTION(wddx_packet_end)
1278 {
1279         zval *packet_id;
1280         wddx_packet *packet = NULL;
1281 
1282         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &packet_id) == FAILURE) {
1283                 return;
1284         }
1285 
1286         ZEND_FETCH_RESOURCE(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx);
1287 
1288         php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1289 
1290         php_wddx_packet_end(packet);
1291 
1292         ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1293 
1294         zend_list_delete(Z_LVAL_P(packet_id));
1295 }
1296 /* }}} */
1297 
1298 /* {{{ proto int wddx_add_vars(resource packet_id,  mixed var_names [, mixed ...])
1299    Serializes given variables and adds them to packet given by packet_id */
1300 PHP_FUNCTION(wddx_add_vars)
1301 {
1302         int num_args, i;
1303         zval ***args = NULL;
1304         zval *packet_id;
1305         wddx_packet *packet = NULL;
1306 
1307         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r+", &packet_id, &args, &num_args) == FAILURE) {
1308                 return;
1309         }
1310 
1311         if (!ZEND_FETCH_RESOURCE_NO_RETURN(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx)) {
1312                 efree(args);
1313                 RETURN_FALSE;
1314         }
1315 
1316         if (!packet) {
1317                 efree(args);
1318                 RETURN_FALSE;
1319         }
1320 
1321         for (i=0; i<num_args; i++) {
1322                 if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
1323                         convert_to_string_ex(args[i]);
1324                 }
1325                 php_wddx_add_var(packet, (*args[i]));
1326         }
1327 
1328         efree(args);
1329         RETURN_TRUE;
1330 }
1331 /* }}} */
1332 
1333 /* {{{ proto mixed wddx_deserialize(mixed packet)
1334    Deserializes given packet and returns a PHP value */
1335 PHP_FUNCTION(wddx_deserialize)
1336 {
1337         zval *packet;
1338         char *payload;
1339         int payload_len;
1340         php_stream *stream = NULL;
1341 
1342         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &packet) == FAILURE) {
1343                 return;
1344         }
1345 
1346         if (Z_TYPE_P(packet) == IS_STRING) {
1347                 payload         = Z_STRVAL_P(packet);
1348                 payload_len = Z_STRLEN_P(packet);
1349         } else if (Z_TYPE_P(packet) == IS_RESOURCE) {
1350                 php_stream_from_zval(stream, &packet);
1351                 if (stream) {
1352                         payload_len = php_stream_copy_to_mem(stream, &payload, PHP_STREAM_COPY_ALL, 0);
1353                 }
1354         } else {
1355                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expecting parameter 1 to be a string or a stream");
1356                 return;
1357         }
1358 
1359         if (payload_len == 0) {
1360                 return;
1361         }
1362 
1363         php_wddx_deserialize_ex(payload, payload_len, return_value);
1364 
1365         if (stream) {
1366                 pefree(payload, 0);
1367         }
1368 }
1369 /* }}} */
1370 
1371 #endif /* HAVE_LIBEXPAT */
1372 
1373 /*
1374  * Local variables:
1375  * tab-width: 4
1376  * c-basic-offset: 4
1377  * End:
1378  * vim600: sw=4 ts=4 fdm=marker
1379  * vim<600: sw=4 ts=4
1380  */

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