Back to index

php5  5.3.10
wddx.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Andrei Zmievski <andrei@php.net>                             |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: wddx.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 
00027 #if HAVE_WDDX
00028 
00029 #include "ext/xml/expat_compat.h"
00030 #include "php_wddx.h"
00031 #include "php_wddx_api.h"
00032 
00033 #define PHP_XML_INTERNAL
00034 #include "ext/xml/php_xml.h"
00035 #include "ext/standard/php_incomplete_class.h"
00036 #include "ext/standard/base64.h"
00037 #include "ext/standard/info.h"
00038 #include "ext/standard/php_smart_str.h"
00039 #include "ext/standard/html.h"
00040 #include "ext/standard/php_string.h"
00041 #include "ext/date/php_date.h"
00042 #include "zend_globals.h"
00043 
00044 #define WDDX_BUF_LEN               256
00045 #define PHP_CLASS_NAME_VAR         "php_class_name"
00046 
00047 #define EL_ARRAY                          "array"
00048 #define EL_BINARY                         "binary"
00049 #define EL_BOOLEAN                        "boolean"
00050 #define EL_CHAR                                  "char"
00051 #define EL_CHAR_CODE               "code"
00052 #define EL_NULL                                  "null"
00053 #define EL_NUMBER                         "number"
00054 #define       EL_PACKET                          "wddxPacket"
00055 #define       EL_STRING                          "string"
00056 #define EL_STRUCT                         "struct"
00057 #define EL_VALUE                          "value"
00058 #define EL_VAR                                   "var"
00059 #define EL_NAME                           "name"
00060 #define EL_VERSION                        "version"
00061 #define EL_RECORDSET               "recordset"
00062 #define EL_FIELD                          "field"
00063 #define EL_DATETIME                       "dateTime"
00064 
00065 #define php_wddx_deserialize(a,b) \
00066        php_wddx_deserialize_ex((a)->value.str.val, (a)->value.str.len, (b))
00067 
00068 #define SET_STACK_VARNAME                                             \
00069               if (stack->varname) {                                          \
00070                      ent.varname = estrdup(stack->varname);    \
00071                      efree(stack->varname);                                  \
00072                      stack->varname = NULL;                                  \
00073               } else                                                                \
00074                      ent.varname = NULL;                                     \
00075                      
00076 static int le_wddx;
00077 
00078 typedef struct {
00079        zval *data;
00080        enum {
00081               ST_ARRAY,
00082               ST_BOOLEAN,
00083               ST_NULL,
00084               ST_NUMBER,
00085               ST_STRING,
00086               ST_BINARY,
00087               ST_STRUCT,
00088               ST_RECORDSET,
00089               ST_FIELD,
00090               ST_DATETIME
00091        } type;
00092        char *varname;
00093 } st_entry;
00094 
00095 typedef struct {
00096        int top, max;
00097        char *varname;
00098        zend_bool done;
00099        void **elements;
00100 } wddx_stack;
00101 
00102 
00103 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len);
00104 
00105 /* {{{ arginfo */
00106 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_value, 0, 0, 1)
00107        ZEND_ARG_INFO(0, var)
00108        ZEND_ARG_INFO(0, comment)
00109 ZEND_END_ARG_INFO()
00110 
00111 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars, 0, 0, 1)
00112        ZEND_ARG_INFO(0, var_name)
00113        ZEND_ARG_INFO(0, ...)
00114 ZEND_END_ARG_INFO()
00115 
00116 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start, 0, 0, 0)
00117        ZEND_ARG_INFO(0, comment)
00118 ZEND_END_ARG_INFO()
00119 
00120 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end, 0, 0, 1)
00121        ZEND_ARG_INFO(0, packet_id)
00122 ZEND_END_ARG_INFO()
00123 
00124 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars, 0, 0, 2)
00125        ZEND_ARG_INFO(0, packet_id)
00126        ZEND_ARG_INFO(0, var_name)
00127        ZEND_ARG_INFO(0, ...)
00128 ZEND_END_ARG_INFO()
00129 
00130 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_deserialize, 0, 0, 1)
00131        ZEND_ARG_INFO(0, packet)
00132 ZEND_END_ARG_INFO()
00133 /* }}} */
00134 
00135 /* {{{ wddx_functions[]
00136  */
00137 const zend_function_entry wddx_functions[] = {
00138        PHP_FE(wddx_serialize_value, arginfo_wddx_serialize_value)
00139        PHP_FE(wddx_serialize_vars, arginfo_wddx_serialize_vars)
00140        PHP_FE(wddx_packet_start,   arginfo_wddx_serialize_start)
00141        PHP_FE(wddx_packet_end,            arginfo_wddx_packet_end)
00142        PHP_FE(wddx_add_vars,              arginfo_wddx_add_vars)
00143        PHP_FE(wddx_deserialize,    arginfo_wddx_deserialize)
00144        PHP_FE_END
00145 };
00146 /* }}} */
00147 
00148 PHP_MINIT_FUNCTION(wddx);
00149 PHP_MINFO_FUNCTION(wddx);
00150 
00151 /* {{{ dynamically loadable module stuff */
00152 #ifdef COMPILE_DL_WDDX
00153 ZEND_GET_MODULE(wddx)
00154 #endif /* COMPILE_DL_WDDX */
00155 /* }}} */
00156 
00157 /* {{{ wddx_module_entry
00158  */
00159 zend_module_entry wddx_module_entry = {
00160        STANDARD_MODULE_HEADER,
00161        "wddx",
00162        wddx_functions,
00163        PHP_MINIT(wddx),
00164        NULL,
00165        NULL,
00166        NULL,
00167        PHP_MINFO(wddx),
00168     NO_VERSION_YET,
00169        STANDARD_MODULE_PROPERTIES
00170 };
00171 /* }}} */
00172 
00173 /* {{{ wddx_stack_init
00174  */    
00175 static int wddx_stack_init(wddx_stack *stack)
00176 {
00177        stack->top = 0;
00178        stack->elements = (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE, 0);
00179        stack->max = STACK_BLOCK_SIZE;
00180        stack->varname = NULL;
00181        stack->done = 0;
00182 
00183        return SUCCESS;
00184 }
00185 /* }}} */
00186 
00187 /* {{{ wddx_stack_push
00188  */
00189 static int wddx_stack_push(wddx_stack *stack, void *element, int size)
00190 {
00191        if (stack->top >= stack->max) {           /* we need to allocate more memory */
00192               stack->elements = (void **) erealloc(stack->elements,
00193                                (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)));
00194        }
00195        stack->elements[stack->top] = (void *) emalloc(size);
00196        memcpy(stack->elements[stack->top], element, size);
00197        return stack->top++;
00198 }
00199 /* }}} */
00200 
00201 /* {{{ wddx_stack_top
00202  */
00203 static int wddx_stack_top(wddx_stack *stack, void **element)
00204 {
00205        if (stack->top > 0) {
00206               *element = stack->elements[stack->top - 1];
00207               return SUCCESS;
00208        } else {
00209               *element = NULL;
00210               return FAILURE;
00211        }
00212 }
00213 /* }}} */
00214 
00215 /* {{{ wddx_stack_is_empty
00216  */
00217 static int wddx_stack_is_empty(wddx_stack *stack)
00218 {
00219        if (stack->top == 0) {
00220               return 1;
00221        } else {
00222               return 0;
00223        }
00224 }
00225 /* }}} */
00226 
00227 /* {{{ wddx_stack_destroy
00228  */
00229 static int wddx_stack_destroy(wddx_stack *stack)
00230 {
00231        register int i;
00232 
00233        if (stack->elements) {
00234               for (i = 0; i < stack->top; i++) {
00235                      if (((st_entry *)stack->elements[i])->data)      {
00236                             zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
00237                      }
00238                      if (((st_entry *)stack->elements[i])->varname) {
00239                             efree(((st_entry *)stack->elements[i])->varname);
00240                      }
00241                      efree(stack->elements[i]);
00242               }             
00243               efree(stack->elements);
00244        }
00245        return SUCCESS;
00246 }
00247 /* }}} */
00248 
00249 /* {{{ release_wddx_packet_rsrc
00250  */
00251 static void release_wddx_packet_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00252 {
00253        smart_str *str = (smart_str *)rsrc->ptr;
00254        smart_str_free(str);
00255        efree(str);
00256 }
00257 /* }}} */
00258 
00259 #include "ext/session/php_session.h"
00260 
00261 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
00262 /* {{{ PS_SERIALIZER_ENCODE_FUNC
00263  */
00264 PS_SERIALIZER_ENCODE_FUNC(wddx)
00265 {
00266        wddx_packet *packet;
00267        PS_ENCODE_VARS;
00268 
00269        packet = php_wddx_constructor();
00270 
00271        php_wddx_packet_start(packet, NULL, 0);
00272        php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
00273        
00274        PS_ENCODE_LOOP(
00275               php_wddx_serialize_var(packet, *struc, key, key_length TSRMLS_CC);
00276        );
00277        
00278        php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
00279        php_wddx_packet_end(packet);
00280        *newstr = php_wddx_gather(packet);
00281        php_wddx_destructor(packet);
00282        
00283        if (newlen) {
00284               *newlen = strlen(*newstr);
00285        }
00286 
00287        return SUCCESS;
00288 }
00289 /* }}} */
00290 
00291 /* {{{ PS_SERIALIZER_DECODE_FUNC
00292  */
00293 PS_SERIALIZER_DECODE_FUNC(wddx)
00294 {
00295        zval *retval;
00296        zval **ent;
00297        char *key;
00298        uint key_length;
00299        char tmp[128];
00300        ulong idx;
00301        int hash_type;
00302        int ret;
00303 
00304        if (vallen == 0) {
00305               return SUCCESS;
00306        }
00307        
00308        MAKE_STD_ZVAL(retval);
00309 
00310        if ((ret = php_wddx_deserialize_ex((char *)val, vallen, retval)) == SUCCESS) {
00311 
00312               for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(retval));
00313                       zend_hash_get_current_data(Z_ARRVAL_P(retval), (void **) &ent) == SUCCESS;
00314                       zend_hash_move_forward(Z_ARRVAL_P(retval))) {
00315                      hash_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(retval), &key, &key_length, &idx, 0, NULL);
00316 
00317                      switch (hash_type) {
00318                             case HASH_KEY_IS_LONG:
00319                                    key_length = slprintf(tmp, sizeof(tmp), "%ld", idx) + 1;
00320                                    key = tmp;
00321                                    /* fallthru */
00322                             case HASH_KEY_IS_STRING:
00323                                    php_set_session_var(key, key_length-1, *ent, NULL TSRMLS_CC);
00324                                    PS_ADD_VAR(key);
00325                      }
00326               }
00327        }
00328 
00329        zval_ptr_dtor(&retval);
00330 
00331        return ret;
00332 }
00333 /* }}} */
00334 #endif
00335 
00336 /* {{{ PHP_MINIT_FUNCTION
00337  */
00338 PHP_MINIT_FUNCTION(wddx)
00339 {
00340        le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
00341 
00342 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
00343        php_session_register_serializer("wddx",
00344                                                                PS_SERIALIZER_ENCODE_NAME(wddx),
00345                                                                PS_SERIALIZER_DECODE_NAME(wddx));
00346 #endif 
00347 
00348        return SUCCESS;
00349 }
00350 /* }}} */
00351 
00352 /* {{{ PHP_MINFO_FUNCTION
00353  */
00354 PHP_MINFO_FUNCTION(wddx)
00355 {
00356        php_info_print_table_start();
00357 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
00358        php_info_print_table_header(2, "WDDX Support", "enabled" );
00359        php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
00360 #else
00361        php_info_print_table_row(2, "WDDX Support", "enabled" );
00362 #endif
00363        php_info_print_table_end();
00364 }
00365 /* }}} */
00366 
00367 /* {{{ php_wddx_packet_start
00368  */
00369 void php_wddx_packet_start(wddx_packet *packet, char *comment, int comment_len)
00370 {
00371        php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
00372        if (comment) {
00373               php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
00374               php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
00375               php_wddx_add_chunk_ex(packet, comment, comment_len);
00376               php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
00377               php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
00378        } else {
00379               php_wddx_add_chunk_static(packet, WDDX_HEADER);
00380        }
00381        php_wddx_add_chunk_static(packet, WDDX_DATA_S);
00382 }
00383 /* }}} */
00384 
00385 /* {{{ php_wddx_packet_end
00386  */
00387 void php_wddx_packet_end(wddx_packet *packet)
00388 {
00389        php_wddx_add_chunk_static(packet, WDDX_DATA_E);
00390        php_wddx_add_chunk_static(packet, WDDX_PACKET_E);       
00391 }
00392 /* }}} */
00393 
00394 #define FLUSH_BUF()                               \
00395        if (l > 0) {                                  \
00396               php_wddx_add_chunk_ex(packet, buf, l);    \
00397               l = 0;                                    \
00398        }
00399 
00400 /* {{{ php_wddx_serialize_string
00401  */
00402 static void php_wddx_serialize_string(wddx_packet *packet, zval *var TSRMLS_DC)
00403 {
00404        php_wddx_add_chunk_static(packet, WDDX_STRING_S);
00405 
00406        if (Z_STRLEN_P(var) > 0) {
00407               char *buf;
00408               int buf_len;
00409 
00410               buf = php_escape_html_entities(Z_STRVAL_P(var), Z_STRLEN_P(var), &buf_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
00411 
00412               php_wddx_add_chunk_ex(packet, buf, buf_len);
00413 
00414               efree(buf);
00415        }
00416        php_wddx_add_chunk_static(packet, WDDX_STRING_E);
00417 }
00418 /* }}} */
00419 
00420 /* {{{ php_wddx_serialize_number
00421  */
00422 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
00423 {
00424        char tmp_buf[WDDX_BUF_LEN];
00425        zval tmp;
00426        
00427        tmp = *var;
00428        zval_copy_ctor(&tmp);
00429        convert_to_string(&tmp);
00430        snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, Z_STRVAL(tmp));
00431        zval_dtor(&tmp);
00432 
00433        php_wddx_add_chunk(packet, tmp_buf);      
00434 }
00435 /* }}} */
00436 
00437 /* {{{ php_wddx_serialize_boolean
00438  */
00439 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
00440 {
00441        php_wddx_add_chunk(packet, Z_LVAL_P(var) ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
00442 }
00443 /* }}} */
00444 
00445 /* {{{ php_wddx_serialize_unset
00446  */
00447 static void php_wddx_serialize_unset(wddx_packet *packet)
00448 {
00449        php_wddx_add_chunk_static(packet, WDDX_NULL);
00450 }
00451 /* }}} */
00452 
00453 /* {{{ php_wddx_serialize_object
00454  */
00455 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
00456 {
00457 /* OBJECTS_FIXME */
00458        zval **ent, *fname, **varname;
00459        zval *retval = NULL;
00460        char *key;
00461        ulong idx;
00462        char tmp_buf[WDDX_BUF_LEN];
00463        HashTable *objhash, *sleephash;
00464        TSRMLS_FETCH();
00465 
00466        MAKE_STD_ZVAL(fname);
00467        ZVAL_STRING(fname, "__sleep", 1);
00468 
00469        /*
00470         * We try to call __sleep() method on object. It's supposed to return an
00471         * array of property names to be serialized.
00472         */
00473        if (call_user_function_ex(CG(function_table), &obj, fname, &retval, 0, 0, 1, NULL TSRMLS_CC) == SUCCESS) {
00474               if (retval && (sleephash = HASH_OF(retval))) {
00475                      PHP_CLASS_ATTRIBUTES;
00476                      
00477                      PHP_SET_CLASS_ATTRIBUTES(obj);
00478 
00479                      php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
00480                      snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
00481                      php_wddx_add_chunk(packet, tmp_buf);
00482                      php_wddx_add_chunk_static(packet, WDDX_STRING_S);
00483                      php_wddx_add_chunk_ex(packet, class_name, name_len);
00484                      php_wddx_add_chunk_static(packet, WDDX_STRING_E);
00485                      php_wddx_add_chunk_static(packet, WDDX_VAR_E);
00486 
00487                      PHP_CLEANUP_CLASS_ATTRIBUTES();
00488 
00489                      objhash = HASH_OF(obj);
00490                      
00491                      for (zend_hash_internal_pointer_reset(sleephash);
00492                              zend_hash_get_current_data(sleephash, (void **)&varname) == SUCCESS;
00493                              zend_hash_move_forward(sleephash)) {
00494                             if (Z_TYPE_PP(varname) != IS_STRING) {
00495                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
00496                                    continue;
00497                             }
00498 
00499                             if (zend_hash_find(objhash, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, (void **)&ent) == SUCCESS) {
00500                                    php_wddx_serialize_var(packet, *ent, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) TSRMLS_CC);
00501                             }
00502                      }
00503                      
00504                      php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
00505               }
00506        } else {
00507               uint key_len;
00508 
00509               PHP_CLASS_ATTRIBUTES;
00510 
00511               PHP_SET_CLASS_ATTRIBUTES(obj);
00512 
00513               php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
00514               snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
00515               php_wddx_add_chunk(packet, tmp_buf);
00516               php_wddx_add_chunk_static(packet, WDDX_STRING_S);
00517               php_wddx_add_chunk_ex(packet, class_name, name_len);
00518               php_wddx_add_chunk_static(packet, WDDX_STRING_E);
00519               php_wddx_add_chunk_static(packet, WDDX_VAR_E);
00520 
00521               PHP_CLEANUP_CLASS_ATTRIBUTES();
00522               
00523               objhash = HASH_OF(obj);
00524               for (zend_hash_internal_pointer_reset(objhash);
00525                       zend_hash_get_current_data(objhash, (void**)&ent) == SUCCESS;
00526                       zend_hash_move_forward(objhash)) {
00527                      if (*ent == obj) {
00528                             continue;
00529                      }
00530 
00531                      if (zend_hash_get_current_key_ex(objhash, &key, &key_len, &idx, 0, NULL) == HASH_KEY_IS_STRING) {
00532                             char *class_name, *prop_name;
00533                             
00534                             zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
00535                             php_wddx_serialize_var(packet, *ent, prop_name, strlen(prop_name)+1 TSRMLS_CC);
00536                      } else {
00537                             key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
00538                             php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
00539                      }
00540               }
00541               php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
00542        }
00543 
00544        zval_dtor(fname);
00545        FREE_ZVAL(fname);
00546 
00547        if (retval) {
00548               zval_ptr_dtor(&retval);
00549        }
00550 }
00551 /* }}} */
00552 
00553 /* {{{ php_wddx_serialize_array
00554  */
00555 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
00556 {
00557        zval **ent;
00558        char *key;
00559        uint key_len;
00560        int is_struct = 0, ent_type;
00561        ulong idx;
00562        HashTable *target_hash;
00563        char tmp_buf[WDDX_BUF_LEN];
00564        ulong ind = 0;
00565        int type;
00566        TSRMLS_FETCH();
00567 
00568        target_hash = HASH_OF(arr);
00569 
00570        for (zend_hash_internal_pointer_reset(target_hash);
00571                zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
00572                zend_hash_move_forward(target_hash)) {
00573 
00574               type = zend_hash_get_current_key(target_hash, &key, &idx, 0);
00575 
00576               if (type == HASH_KEY_IS_STRING) {
00577                      is_struct = 1;
00578                      break;
00579               }
00580 
00581               if (idx != ind) {
00582                      is_struct = 1;
00583                      break;
00584               }
00585 
00586               ind++;
00587        }
00588 
00589        if (is_struct) {
00590               php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
00591        } else {
00592               snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
00593               php_wddx_add_chunk(packet, tmp_buf);
00594        }
00595 
00596        for (zend_hash_internal_pointer_reset(target_hash);
00597                zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
00598                zend_hash_move_forward(target_hash)) {
00599               if (*ent == arr) {
00600                      continue;
00601               }
00602 
00603               if (is_struct) {
00604                      ent_type = zend_hash_get_current_key_ex(target_hash, &key, &key_len, &idx, 0, NULL);
00605 
00606                      if (ent_type == HASH_KEY_IS_STRING) {
00607                             php_wddx_serialize_var(packet, *ent, key, key_len TSRMLS_CC);
00608                      } else {
00609                             key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
00610                             php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
00611                      }
00612               } else {
00613                      php_wddx_serialize_var(packet, *ent, NULL, 0 TSRMLS_CC);
00614               }
00615        }
00616        
00617        if (is_struct) {
00618               php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
00619        } else {
00620               php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
00621        }
00622 }
00623 /* }}} */
00624 
00625 /* {{{ php_wddx_serialize_var
00626  */
00627 void php_wddx_serialize_var(wddx_packet *packet, zval *var, char *name, int name_len TSRMLS_DC)
00628 {
00629        char *tmp_buf;
00630        char *name_esc;
00631        int name_esc_len;
00632        HashTable *ht;
00633 
00634        if (name) {
00635               name_esc = php_escape_html_entities(name, name_len, &name_esc_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
00636               tmp_buf = emalloc(name_esc_len + sizeof(WDDX_VAR_S));
00637               snprintf(tmp_buf, name_esc_len + sizeof(WDDX_VAR_S), WDDX_VAR_S, name_esc);
00638               php_wddx_add_chunk(packet, tmp_buf);
00639               efree(tmp_buf);
00640               efree(name_esc);
00641        }
00642        
00643        switch(Z_TYPE_P(var)) {
00644               case IS_STRING:
00645                      php_wddx_serialize_string(packet, var TSRMLS_CC);
00646                      break;
00647                      
00648               case IS_LONG:
00649               case IS_DOUBLE:
00650                      php_wddx_serialize_number(packet, var);
00651                      break;
00652 
00653               case IS_BOOL:
00654                      php_wddx_serialize_boolean(packet, var);
00655                      break;
00656 
00657               case IS_NULL:
00658                      php_wddx_serialize_unset(packet);
00659                      break;
00660               
00661               case IS_ARRAY:
00662                      ht = Z_ARRVAL_P(var);
00663                      if (ht->nApplyCount > 1) {
00664                             php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
00665                             return;
00666                      }
00667                      ht->nApplyCount++;                                                                                                     
00668                      php_wddx_serialize_array(packet, var);
00669                      ht->nApplyCount--;
00670                      break;
00671 
00672               case IS_OBJECT:
00673                      ht = Z_OBJPROP_P(var);
00674                      if (ht->nApplyCount > 1) {
00675                             php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
00676                             return;
00677                      }
00678                      ht->nApplyCount++;
00679                      php_wddx_serialize_object(packet, var);
00680                      ht->nApplyCount--;
00681                      break;
00682        }
00683        
00684        if (name) {
00685               php_wddx_add_chunk_static(packet, WDDX_VAR_E);
00686        }
00687 }
00688 /* }}} */
00689 
00690 /* {{{ php_wddx_add_var
00691  */
00692 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
00693 {
00694        zval **val;
00695        HashTable *target_hash;
00696        TSRMLS_FETCH();
00697 
00698        if (Z_TYPE_P(name_var) == IS_STRING) {
00699               if (!EG(active_symbol_table)) {
00700                      zend_rebuild_symbol_table(TSRMLS_C);
00701               }
00702               if (zend_hash_find(EG(active_symbol_table), Z_STRVAL_P(name_var),
00703                                                  Z_STRLEN_P(name_var)+1, (void**)&val) != FAILURE) {
00704                      php_wddx_serialize_var(packet, *val, Z_STRVAL_P(name_var), Z_STRLEN_P(name_var) TSRMLS_CC);
00705               }             
00706        } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT)       {
00707               int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
00708               
00709               target_hash = HASH_OF(name_var);
00710               
00711               if (is_array && target_hash->nApplyCount > 1) {
00712                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
00713                      return;
00714               }
00715 
00716               zend_hash_internal_pointer_reset(target_hash);
00717 
00718               while(zend_hash_get_current_data(target_hash, (void**)&val) == SUCCESS) {
00719                      if (is_array) {
00720                             target_hash->nApplyCount++;
00721                      }
00722 
00723                      php_wddx_add_var(packet, *val);
00724 
00725                      if (is_array) {
00726                             target_hash->nApplyCount--;
00727                      }
00728                      zend_hash_move_forward(target_hash);
00729               }
00730        }
00731 }
00732 /* }}} */
00733 
00734 /* {{{ php_wddx_push_element
00735  */
00736 static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
00737 {
00738        st_entry ent;
00739        wddx_stack *stack = (wddx_stack *)user_data;
00740        
00741        if (!strcmp(name, EL_PACKET)) {
00742               int i;
00743               
00744               if (atts) for (i=0; atts[i]; i++) {
00745                      if (!strcmp(atts[i], EL_VERSION)) {
00746                             /* nothing for now */
00747                      }
00748               }
00749        } else if (!strcmp(name, EL_STRING)) {
00750               ent.type = ST_STRING;
00751               SET_STACK_VARNAME;
00752               
00753               ALLOC_ZVAL(ent.data);
00754               INIT_PZVAL(ent.data);
00755               Z_TYPE_P(ent.data) = IS_STRING;
00756               Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
00757               Z_STRLEN_P(ent.data) = 0;
00758               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00759        } else if (!strcmp(name, EL_BINARY)) {
00760               ent.type = ST_BINARY;
00761               SET_STACK_VARNAME;
00762               
00763               ALLOC_ZVAL(ent.data);
00764               INIT_PZVAL(ent.data);
00765               Z_TYPE_P(ent.data) = IS_STRING;
00766               Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
00767               Z_STRLEN_P(ent.data) = 0;
00768               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00769        } else if (!strcmp(name, EL_CHAR)) {
00770               int i;
00771               
00772               if (atts) for (i = 0; atts[i]; i++) {
00773                      if (!strcmp(atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
00774                             char tmp_buf[2];
00775 
00776                             snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol(atts[i], NULL, 16));
00777                             php_wddx_process_data(user_data, tmp_buf, strlen(tmp_buf));
00778                             break;
00779                      }
00780               }
00781        } else if (!strcmp(name, EL_NUMBER)) {
00782               ent.type = ST_NUMBER;
00783               SET_STACK_VARNAME;
00784               
00785               ALLOC_ZVAL(ent.data);
00786               INIT_PZVAL(ent.data);
00787               Z_TYPE_P(ent.data) = IS_LONG;
00788               Z_LVAL_P(ent.data) = 0;
00789               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00790        } else if (!strcmp(name, EL_BOOLEAN)) {
00791               int i;
00792 
00793               if (atts) for (i = 0; atts[i]; i++) {
00794                      if (!strcmp(atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
00795                             ent.type = ST_BOOLEAN;
00796                             SET_STACK_VARNAME;
00797 
00798                             ALLOC_ZVAL(ent.data);
00799                             INIT_PZVAL(ent.data);
00800                             Z_TYPE_P(ent.data) = IS_BOOL;
00801                             wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00802                             php_wddx_process_data(user_data, atts[i], strlen(atts[i]));
00803                             break;
00804                      }
00805               }
00806        } else if (!strcmp(name, EL_NULL)) {
00807               ent.type = ST_NULL;
00808               SET_STACK_VARNAME;
00809 
00810               ALLOC_ZVAL(ent.data);
00811               INIT_PZVAL(ent.data);
00812               ZVAL_NULL(ent.data);
00813               
00814               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00815        } else if (!strcmp(name, EL_ARRAY)) {
00816               ent.type = ST_ARRAY;
00817               SET_STACK_VARNAME;
00818               
00819               ALLOC_ZVAL(ent.data);
00820               array_init(ent.data);
00821               INIT_PZVAL(ent.data);
00822               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00823        } else if (!strcmp(name, EL_STRUCT)) {
00824               ent.type = ST_STRUCT;
00825               SET_STACK_VARNAME;
00826               
00827               ALLOC_ZVAL(ent.data);
00828               array_init(ent.data);
00829               INIT_PZVAL(ent.data);
00830               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00831        } else if (!strcmp(name, EL_VAR)) {
00832               int i;
00833               
00834               if (atts) for (i = 0; atts[i]; i++) {
00835                      if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
00836                             stack->varname = estrdup(atts[i]);
00837                             break;
00838                      }
00839               }
00840        } else if (!strcmp(name, EL_RECORDSET)) {
00841               int i;
00842 
00843               ent.type = ST_RECORDSET;
00844               SET_STACK_VARNAME;
00845               MAKE_STD_ZVAL(ent.data);
00846               array_init(ent.data);
00847 
00848               if (atts) for (i = 0; atts[i]; i++) {
00849                      if (!strcmp(atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
00850                             zval *tmp;
00851                             char *key;
00852                             char *p1, *p2, *endp;
00853 
00854                             endp = (char *)atts[i] + strlen(atts[i]);
00855                             p1 = (char *)atts[i];
00856                             while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
00857                                    key = estrndup(p1, p2 - p1);
00858                                    MAKE_STD_ZVAL(tmp);
00859                                    array_init(tmp);
00860                                    add_assoc_zval_ex(ent.data, key, p2 - p1 + 1, tmp);
00861                                    p1 = p2 + sizeof(",")-1;
00862                                    efree(key);
00863                             }
00864 
00865                             if (p1 <= endp) {
00866                                    MAKE_STD_ZVAL(tmp);
00867                                    array_init(tmp);
00868                                    add_assoc_zval_ex(ent.data, p1, endp - p1 + 1, tmp);
00869                             }
00870 
00871                             break;
00872                      }
00873               }
00874 
00875               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00876        } else if (!strcmp(name, EL_FIELD)) {
00877               int i;
00878               st_entry ent;
00879 
00880               ent.type = ST_FIELD;
00881               ent.varname = NULL;
00882               ent.data = NULL;
00883 
00884               if (atts) for (i = 0; atts[i]; i++) {
00885                      if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
00886                             st_entry *recordset;
00887                             zval **field;
00888  
00889                             if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
00890                                    recordset->type == ST_RECORDSET &&
00891                                    zend_hash_find(Z_ARRVAL_P(recordset->data), (char*)atts[i], strlen(atts[i])+1, (void**)&field) == SUCCESS) {
00892                                    ent.data = *field;
00893                             }
00894                             
00895                             break;
00896                      }
00897               }
00898 
00899               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00900        } else if (!strcmp(name, EL_DATETIME)) {
00901               ent.type = ST_DATETIME;
00902               SET_STACK_VARNAME;
00903               
00904               ALLOC_ZVAL(ent.data);
00905               INIT_PZVAL(ent.data);
00906               Z_TYPE_P(ent.data) = IS_LONG;
00907               wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
00908        }
00909 }
00910 /* }}} */
00911 
00912 /* {{{ php_wddx_pop_element
00913  */
00914 static void php_wddx_pop_element(void *user_data, const XML_Char *name)
00915 {
00916        st_entry                    *ent1, *ent2;
00917        wddx_stack                  *stack = (wddx_stack *)user_data;
00918        HashTable                   *target_hash;
00919        zend_class_entry     **pce;
00920        zval                        *obj;
00921        zval                        *tmp;
00922        TSRMLS_FETCH();
00923 
00924 /* OBJECTS_FIXME */
00925        if (stack->top == 0) {
00926               return;
00927        }
00928 
00929        if (!strcmp(name, EL_STRING) || !strcmp(name, EL_NUMBER) ||
00930               !strcmp(name, EL_BOOLEAN) || !strcmp(name, EL_NULL) ||
00931               !strcmp(name, EL_ARRAY) || !strcmp(name, EL_STRUCT) ||
00932               !strcmp(name, EL_RECORDSET) || !strcmp(name, EL_BINARY) ||
00933               !strcmp(name, EL_DATETIME)) {
00934               wddx_stack_top(stack, (void**)&ent1);
00935 
00936               if (!strcmp(name, EL_BINARY)) {
00937                      int new_len=0;
00938                      unsigned char *new_str;
00939 
00940                      new_str = php_base64_decode(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data), &new_len);
00941                      STR_FREE(Z_STRVAL_P(ent1->data));
00942                      Z_STRVAL_P(ent1->data) = new_str;
00943                      Z_STRLEN_P(ent1->data) = new_len;
00944               }
00945 
00946               /* Call __wakeup() method on the object. */
00947               if (Z_TYPE_P(ent1->data) == IS_OBJECT) {
00948                      zval *fname, *retval = NULL;
00949 
00950                      MAKE_STD_ZVAL(fname);
00951                      ZVAL_STRING(fname, "__wakeup", 1);
00952 
00953                      call_user_function_ex(NULL, &ent1->data, fname, &retval, 0, 0, 0, NULL TSRMLS_CC);
00954 
00955                      zval_dtor(fname);
00956                      FREE_ZVAL(fname);
00957                      if (retval) {
00958                             zval_ptr_dtor(&retval);
00959                      }
00960               }
00961 
00962               if (stack->top > 1) {
00963                      stack->top--;
00964                      wddx_stack_top(stack, (void**)&ent2);
00965                      
00966                      /* if non-existent field */
00967                      if (ent2->type == ST_FIELD && ent2->data == NULL) {
00968                             zval_ptr_dtor(&ent1->data);
00969                             efree(ent1);
00970                             return;
00971                      }
00972                      
00973                      if (Z_TYPE_P(ent2->data) == IS_ARRAY || Z_TYPE_P(ent2->data) == IS_OBJECT) {
00974                             target_hash = HASH_OF(ent2->data);
00975 
00976                             if (ent1->varname) {
00977                                    if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
00978                                           Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data)) {
00979                                           zend_bool incomplete_class = 0;
00980 
00981                                           zend_str_tolower(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
00982                                           if (zend_hash_find(EG(class_table), Z_STRVAL_P(ent1->data),
00983                                                                          Z_STRLEN_P(ent1->data)+1, (void **) &pce)==FAILURE) {
00984                                                  incomplete_class = 1;
00985                                                  pce = &PHP_IC_ENTRY;
00986                                           }
00987 
00988                                           /* Initialize target object */
00989                                           MAKE_STD_ZVAL(obj);
00990                                           object_init_ex(obj, *pce);
00991                                           
00992                                           /* Merge current hashtable with object's default properties */
00993                                           zend_hash_merge(Z_OBJPROP_P(obj),
00994                                                                       Z_ARRVAL_P(ent2->data),
00995                                                                       (void (*)(void *)) zval_add_ref,
00996                                                                       (void *) &tmp, sizeof(zval *), 0);
00997 
00998                                           if (incomplete_class) {
00999                                                  php_store_class_name(obj, Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
01000                                           }
01001 
01002                                           /* Clean up old array entry */
01003                                           zval_ptr_dtor(&ent2->data);
01004                                           
01005                                           /* Set stack entry to point to the newly created object */
01006                                           ent2->data = obj;
01007                                           
01008                                           /* Clean up class name var entry */
01009                                           zval_ptr_dtor(&ent1->data);
01010                                    } else if (Z_TYPE_P(ent2->data) == IS_OBJECT) {
01011                                           zend_class_entry *old_scope = EG(scope);
01012        
01013                                           EG(scope) = Z_OBJCE_P(ent2->data);
01014                                           Z_DELREF_P(ent1->data);
01015                                           add_property_zval(ent2->data, ent1->varname, ent1->data);
01016                                           EG(scope) = old_scope;
01017                                    } else {
01018                                           zend_symtable_update(target_hash, ent1->varname, strlen(ent1->varname)+1, &ent1->data, sizeof(zval *), NULL);
01019                                    }
01020                                    efree(ent1->varname);
01021                             } else {
01022                                    zend_hash_next_index_insert(target_hash, &ent1->data, sizeof(zval *), NULL);
01023                             }
01024                      }
01025                      efree(ent1);
01026               } else {
01027                      stack->done = 1;
01028               }
01029        } else if (!strcmp(name, EL_VAR) && stack->varname) {
01030               efree(stack->varname);
01031        } else if (!strcmp(name, EL_FIELD)) {
01032               st_entry *ent;
01033               wddx_stack_top(stack, (void **)&ent);
01034               efree(ent);
01035               stack->top--;
01036        }
01037 }
01038 /* }}} */
01039 
01040 /* {{{ php_wddx_process_data
01041  */
01042 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
01043 {
01044        st_entry *ent;
01045        wddx_stack *stack = (wddx_stack *)user_data;
01046        TSRMLS_FETCH();
01047 
01048        if (!wddx_stack_is_empty(stack) && !stack->done) {
01049               wddx_stack_top(stack, (void**)&ent);
01050               switch (Z_TYPE_P(ent)) {
01051                      case ST_STRING: 
01052                             if (Z_STRLEN_P(ent->data) == 0) {
01053                                    STR_FREE(Z_STRVAL_P(ent->data));
01054                                    Z_STRVAL_P(ent->data) = estrndup(s, len);
01055                                    Z_STRLEN_P(ent->data) = len;
01056                             } else {
01057                                    Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
01058                                    memcpy(Z_STRVAL_P(ent->data) + Z_STRLEN_P(ent->data), s, len);
01059                                    Z_STRLEN_P(ent->data) += len;
01060                                    Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0';
01061                             }
01062                             break;
01063 
01064                      case ST_BINARY:
01065                             if (Z_STRLEN_P(ent->data) == 0) {
01066                                    STR_FREE(Z_STRVAL_P(ent->data));
01067                                    Z_STRVAL_P(ent->data) = estrndup(s, len + 1);
01068                             } else {
01069                                    Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
01070                                    memcpy(Z_STRVAL_P(ent->data) + Z_STRLEN_P(ent->data), s, len);
01071                             }
01072                             Z_STRLEN_P(ent->data) += len;
01073                             Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0';
01074                             break;
01075 
01076                      case ST_NUMBER:
01077                             Z_TYPE_P(ent->data) = IS_STRING;
01078                             Z_STRLEN_P(ent->data) = len;
01079                             Z_STRVAL_P(ent->data) = estrndup(s, len);
01080                             convert_scalar_to_number(ent->data TSRMLS_CC);
01081                             break;
01082 
01083                      case ST_BOOLEAN:
01084                             if (!strcmp(s, "true")) {
01085                                    Z_LVAL_P(ent->data) = 1;
01086                             } else if (!strcmp(s, "false")) {
01087                                    Z_LVAL_P(ent->data) = 0;
01088                             } else {
01089                                    stack->top--;
01090                                    zval_ptr_dtor(&ent->data);
01091                                    if (ent->varname)
01092                                           efree(ent->varname);
01093                                    efree(ent);
01094                             }
01095                             break;
01096 
01097                      case ST_DATETIME: {
01098                             char *tmp;
01099 
01100                             tmp = emalloc(len + 1);
01101                             memcpy(tmp, s, len);
01102                             tmp[len] = '\0';
01103 
01104                             Z_LVAL_P(ent->data) = php_parse_date(tmp, NULL);
01105                             /* date out of range < 1969 or > 2038 */
01106                             if (Z_LVAL_P(ent->data) == -1) {
01107                                    Z_TYPE_P(ent->data) = IS_STRING;
01108                                    Z_STRLEN_P(ent->data) = len;
01109                                    Z_STRVAL_P(ent->data) = estrndup(s, len);
01110                             }
01111                             efree(tmp);
01112                      }
01113                             break;
01114 
01115                      default:
01116                             break;
01117               }
01118        }
01119 }
01120 /* }}} */
01121 
01122 /* {{{ php_wddx_deserialize_ex
01123  */
01124 int php_wddx_deserialize_ex(char *value, int vallen, zval *return_value)
01125 {
01126        wddx_stack stack;
01127        XML_Parser parser;
01128        st_entry *ent;
01129        int retval;
01130        
01131        wddx_stack_init(&stack);
01132        parser = XML_ParserCreate("UTF-8");
01133 
01134        XML_SetUserData(parser, &stack);
01135        XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
01136        XML_SetCharacterDataHandler(parser, php_wddx_process_data);
01137        
01138        XML_Parse(parser, value, vallen, 1);
01139        
01140        XML_ParserFree(parser);
01141 
01142        if (stack.top == 1) {
01143               wddx_stack_top(&stack, (void**)&ent);
01144               *return_value = *(ent->data);
01145               zval_copy_ctor(return_value);
01146               retval = SUCCESS;
01147        } else {
01148               retval = FAILURE;
01149        }
01150               
01151        wddx_stack_destroy(&stack);
01152 
01153        return retval;
01154 }
01155 /* }}} */
01156 
01157 /* {{{ proto string wddx_serialize_value(mixed var [, string comment])
01158    Creates a new packet and serializes the given value */
01159 PHP_FUNCTION(wddx_serialize_value)
01160 {
01161        zval *var;
01162        char *comment = NULL;
01163        int comment_len = 0;
01164        wddx_packet *packet;
01165        
01166        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &var, &comment, &comment_len) == FAILURE) {
01167               return;
01168        }
01169        
01170        packet = php_wddx_constructor();
01171 
01172        php_wddx_packet_start(packet, comment, comment_len);
01173        php_wddx_serialize_var(packet, var, NULL, 0 TSRMLS_CC);
01174        php_wddx_packet_end(packet);
01175                                    
01176        ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
01177        smart_str_free(packet);
01178        efree(packet);
01179 }
01180 /* }}} */
01181 
01182 /* {{{ proto string wddx_serialize_vars(mixed var_name [, mixed ...])
01183    Creates a new packet and serializes given variables into a struct */
01184 PHP_FUNCTION(wddx_serialize_vars)
01185 {
01186        int num_args, i;
01187        wddx_packet *packet;
01188        zval ***args = NULL;
01189 
01190        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
01191               return;
01192        }
01193               
01194        packet = php_wddx_constructor();
01195 
01196        php_wddx_packet_start(packet, NULL, 0);
01197        php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
01198        
01199        for (i=0; i<num_args; i++) {
01200               if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
01201                      convert_to_string_ex(args[i]);
01202               }
01203               php_wddx_add_var(packet, *args[i]);
01204        }      
01205        
01206        php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
01207        php_wddx_packet_end(packet);
01208 
01209        efree(args);
01210 
01211        ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
01212        smart_str_free(packet);
01213        efree(packet);
01214 }
01215 /* }}} */
01216 
01217 /* {{{ php_wddx_constructor
01218  */
01219 wddx_packet *php_wddx_constructor(void)
01220 {
01221        smart_str *packet;
01222 
01223        packet = (smart_str *)emalloc(sizeof(smart_str));
01224        packet->c = NULL;
01225 
01226        return packet;
01227 }
01228 /* }}} */
01229 
01230 /* {{{ php_wddx_destructor
01231  */
01232 void php_wddx_destructor(wddx_packet *packet)
01233 {
01234        smart_str_free(packet);
01235        efree(packet);
01236 }
01237 /* }}} */
01238 
01239 /* {{{ proto resource wddx_packet_start([string comment])
01240    Starts a WDDX packet with optional comment and returns the packet id */
01241 PHP_FUNCTION(wddx_packet_start)
01242 {
01243        char *comment = NULL;
01244        int comment_len = 0;
01245        wddx_packet *packet;
01246 
01247        comment = NULL;
01248 
01249        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &comment, &comment_len) == FAILURE) {
01250               return;
01251        }
01252 
01253        packet = php_wddx_constructor();
01254        
01255        php_wddx_packet_start(packet, comment, comment_len);
01256        php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
01257 
01258        ZEND_REGISTER_RESOURCE(return_value, packet, le_wddx);
01259 }
01260 /* }}} */
01261 
01262 /* {{{ proto string wddx_packet_end(resource packet_id)
01263    Ends specified WDDX packet and returns the string containing the packet */
01264 PHP_FUNCTION(wddx_packet_end)
01265 {
01266        zval *packet_id;
01267        wddx_packet *packet = NULL;
01268        
01269        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &packet_id) == FAILURE) {
01270               return;
01271        }
01272 
01273        ZEND_FETCH_RESOURCE(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx);
01274                      
01275        php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);       
01276        
01277        php_wddx_packet_end(packet);
01278 
01279        ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
01280 
01281        zend_list_delete(Z_LVAL_P(packet_id));
01282 }
01283 /* }}} */
01284 
01285 /* {{{ proto int wddx_add_vars(resource packet_id,  mixed var_names [, mixed ...])
01286    Serializes given variables and adds them to packet given by packet_id */
01287 PHP_FUNCTION(wddx_add_vars)
01288 {
01289        int num_args, i;
01290        zval ***args = NULL;
01291        zval *packet_id;
01292        wddx_packet *packet = NULL;
01293        
01294        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r+", &packet_id, &args, &num_args) == FAILURE) {
01295               return;
01296        }
01297 
01298        if (!ZEND_FETCH_RESOURCE_NO_RETURN(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx)) {
01299               efree(args);
01300               RETURN_FALSE;
01301        }
01302        
01303        if (!packet) {
01304               efree(args);
01305               RETURN_FALSE;
01306        }
01307               
01308        for (i=0; i<num_args; i++) {
01309               if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
01310                      convert_to_string_ex(args[i]);
01311               }
01312               php_wddx_add_var(packet, (*args[i]));
01313        }
01314 
01315        efree(args);
01316        RETURN_TRUE;
01317 }
01318 /* }}} */
01319 
01320 /* {{{ proto mixed wddx_deserialize(mixed packet) 
01321    Deserializes given packet and returns a PHP value */
01322 PHP_FUNCTION(wddx_deserialize)
01323 {
01324        zval *packet;
01325        char *payload;
01326        int payload_len;
01327        php_stream *stream = NULL;
01328        
01329        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &packet) == FAILURE) {
01330               return;
01331        }
01332 
01333        if (Z_TYPE_P(packet) == IS_STRING) {
01334               payload       = Z_STRVAL_P(packet);
01335               payload_len = Z_STRLEN_P(packet);
01336        } else if (Z_TYPE_P(packet) == IS_RESOURCE) {
01337               php_stream_from_zval(stream, &packet);
01338               if (stream) {
01339                      payload_len = php_stream_copy_to_mem(stream, &payload, PHP_STREAM_COPY_ALL, 0);
01340               }
01341        } else {
01342               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expecting parameter 1 to be a string or a stream");
01343               return;
01344        }
01345 
01346        if (payload_len == 0) {
01347               return;
01348        }
01349 
01350        php_wddx_deserialize_ex(payload, payload_len, return_value);
01351               
01352        if (stream) {
01353               pefree(payload, 0);
01354        }
01355 }
01356 /* }}} */
01357 
01358 #endif /* HAVE_LIBEXPAT */
01359 
01360 /*
01361  * Local variables:
01362  * tab-width: 4
01363  * c-basic-offset: 4
01364  * End:
01365  * vim600: sw=4 ts=4 fdm=marker
01366  * vim<600: sw=4 ts=4
01367  */