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