Annotation of embedaddon/php/ext/wddx/wddx.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>