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