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