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