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 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26 
27 #include "php.h"
28 
29 #if HAVE_WDDX
30 
31 #include "ext/xml/expat_compat.h"
32 #include "php_wddx.h"
33 #include "php_wddx_api.h"
34 
35 #define PHP_XML_INTERNAL
36 #include "ext/xml/php_xml.h"
37 #include "ext/standard/php_incomplete_class.h"
38 #include "ext/standard/base64.h"
39 #include "ext/standard/info.h"
40 #include "zend_smart_str.h"
41 #include "ext/standard/html.h"
42 #include "ext/standard/php_string.h"
43 #include "ext/date/php_date.h"
44 #include "zend_globals.h"
45 
46 #define WDDX_BUF_LEN			256
47 #define PHP_CLASS_NAME_VAR		"php_class_name"
48 
49 #define EL_ARRAY				"array"
50 #define EL_BINARY				"binary"
51 #define EL_BOOLEAN				"boolean"
52 #define EL_CHAR					"char"
53 #define EL_CHAR_CODE			"code"
54 #define EL_NULL					"null"
55 #define EL_NUMBER				"number"
56 #define	EL_PACKET				"wddxPacket"
57 #define	EL_STRING				"string"
58 #define EL_STRUCT				"struct"
59 #define EL_VALUE				"value"
60 #define EL_VAR					"var"
61 #define EL_NAME	    			"name"
62 #define EL_VERSION				"version"
63 #define EL_RECORDSET			"recordset"
64 #define EL_FIELD				"field"
65 #define EL_DATETIME				"dateTime"
66 
67 #define php_wddx_deserialize(a,b) \
68 	php_wddx_deserialize_ex(Z_STRVAL_P(a), Z_STRLEN_P(a), (b))
69 
70 #define SET_STACK_VARNAME							\
71 		if (stack->varname) {						\
72 			ent.varname = estrdup(stack->varname);	\
73 			efree(stack->varname);					\
74 			stack->varname = NULL;					\
75 		} else										\
76 			ent.varname = NULL;						\
77 
78 static int le_wddx;
79 
80 typedef struct {
81 	zval data;
82 	enum {
83 		ST_ARRAY,
84 		ST_BOOLEAN,
85 		ST_NULL,
86 		ST_NUMBER,
87 		ST_STRING,
88 		ST_BINARY,
89 		ST_STRUCT,
90 		ST_RECORDSET,
91 		ST_FIELD,
92 		ST_DATETIME
93 	} type;
94 	char *varname;
95 } st_entry;
96 
97 typedef struct {
98 	int top, max;
99 	char *varname;
100 	zend_bool done;
101 	void **elements;
102 } wddx_stack;
103 
104 
105 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len);
106 
107 /* {{{ arginfo */
108 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_value, 0, 0, 1)
109 	ZEND_ARG_INFO(0, var)
110 	ZEND_ARG_INFO(0, comment)
111 ZEND_END_ARG_INFO()
112 
113 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars, 0, 0, 1)
114 	ZEND_ARG_VARIADIC_INFO(0, var_names)
115 ZEND_END_ARG_INFO()
116 
117 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start, 0, 0, 0)
118 	ZEND_ARG_INFO(0, comment)
119 ZEND_END_ARG_INFO()
120 
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end, 0, 0, 1)
122 	ZEND_ARG_INFO(0, packet_id)
123 ZEND_END_ARG_INFO()
124 
125 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars, 0, 0, 2)
126 	ZEND_ARG_INFO(0, packet_id)
127 	ZEND_ARG_VARIADIC_INFO(0, var_names)
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 static 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     PHP_WDDX_VERSION,
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 (Z_TYPE(((st_entry *)stack->elements[i])->data) != IS_UNDEF
236 					&& ((st_entry *)stack->elements[i])->type != ST_FIELD)	{
237 				zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
238 			}
239 			if (((st_entry *)stack->elements[i])->varname) {
240 				efree(((st_entry *)stack->elements[i])->varname);
241 			}
242 			efree(stack->elements[i]);
243 		}
244 		efree(stack->elements);
245 	}
246 	if (stack->varname) {
247 		efree(stack->varname);
248 	}
249 	return SUCCESS;
250 }
251 /* }}} */
252 
253 /* {{{ release_wddx_packet_rsrc
254  */
release_wddx_packet_rsrc(zend_resource * rsrc)255 static void release_wddx_packet_rsrc(zend_resource *rsrc)
256 {
257 	smart_str *str = (smart_str *)rsrc->ptr;
258 	smart_str_free(str);
259 	efree(str);
260 }
261 /* }}} */
262 
263 #include "ext/session/php_session.h"
264 
265 #if HAVE_PHP_SESSION
266 /* {{{ PS_SERIALIZER_ENCODE_FUNC
267  */
PS_SERIALIZER_ENCODE_FUNC(wddx)268 PS_SERIALIZER_ENCODE_FUNC(wddx)
269 {
270 	wddx_packet *packet;
271 	zend_string *str;
272 	PS_ENCODE_VARS;
273 
274 	packet = php_wddx_constructor();
275 
276 	php_wddx_packet_start(packet, NULL, 0);
277 	php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
278 
279 	PS_ENCODE_LOOP(
280 		php_wddx_serialize_var(packet, struc, key);
281 	);
282 
283 	php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
284 	php_wddx_packet_end(packet);
285 	smart_str_0(packet);
286 	str = zend_string_copy(packet->s);
287 	php_wddx_destructor(packet);
288 
289 	return str;
290 }
291 /* }}} */
292 
293 /* {{{ PS_SERIALIZER_DECODE_FUNC
294  */
PS_SERIALIZER_DECODE_FUNC(wddx)295 PS_SERIALIZER_DECODE_FUNC(wddx)
296 {
297 	zval retval;
298 	zval *ent;
299 	zend_string *key;
300 	zend_ulong idx;
301 	int ret;
302 
303 	if (vallen == 0) {
304 		return SUCCESS;
305 	}
306 
307 	ZVAL_UNDEF(&retval);
308 	if ((ret = php_wddx_deserialize_ex(val, vallen, &retval)) == SUCCESS) {
309 		if (Z_TYPE(retval) != IS_ARRAY) {
310 			zval_ptr_dtor_nogc(&retval);
311 			return FAILURE;
312 		}
313 		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(retval), idx, key, ent) {
314 			if (key == NULL) {
315 				key = zend_long_to_str(idx);
316 			} else {
317 				zend_string_addref(key);
318 			}
319 			if (php_set_session_var(key, ent, NULL)) {
320 				Z_TRY_ADDREF_P(ent);
321 			}
322 			PS_ADD_VAR(key);
323 			zend_string_release_ex(key, 0);
324 		} ZEND_HASH_FOREACH_END();
325 	}
326 
327 	zval_ptr_dtor(&retval);
328 
329 	return ret;
330 }
331 /* }}} */
332 #endif
333 
334 /* {{{ PHP_MINIT_FUNCTION
335  */
PHP_MINIT_FUNCTION(wddx)336 PHP_MINIT_FUNCTION(wddx)
337 {
338 	le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
339 
340 #if HAVE_PHP_SESSION
341 	php_session_register_serializer("wddx",
342 									PS_SERIALIZER_ENCODE_NAME(wddx),
343 									PS_SERIALIZER_DECODE_NAME(wddx));
344 #endif
345 
346 	return SUCCESS;
347 }
348 /* }}} */
349 
350 /* {{{ PHP_MINFO_FUNCTION
351  */
PHP_MINFO_FUNCTION(wddx)352 PHP_MINFO_FUNCTION(wddx)
353 {
354 	php_info_print_table_start();
355 #if HAVE_PHP_SESSION
356 	php_info_print_table_header(2, "WDDX Support", "enabled" );
357 	php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
358 #else
359 	php_info_print_table_row(2, "WDDX Support", "enabled" );
360 #endif
361 	php_info_print_table_end();
362 }
363 /* }}} */
364 
365 /* {{{ php_wddx_packet_start
366  */
php_wddx_packet_start(wddx_packet * packet,char * comment,size_t comment_len)367 void php_wddx_packet_start(wddx_packet *packet, char *comment, size_t comment_len)
368 {
369 	php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
370 	if (comment) {
371 		zend_string *escaped = php_escape_html_entities(
372 			comment, comment_len, 0, ENT_QUOTES, NULL);
373 
374 		php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
375 		php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
376 		php_wddx_add_chunk_ex(packet, ZSTR_VAL(escaped), ZSTR_LEN(escaped));
377 		php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
378 		php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
379 
380 		zend_string_release_ex(escaped, 0);
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)405 static void php_wddx_serialize_string(wddx_packet *packet, zval *var)
406 {
407 	php_wddx_add_chunk_static(packet, WDDX_STRING_S);
408 
409 	if (Z_STRLEN_P(var) > 0) {
410 		zend_string *buf = php_escape_html_entities(
411 			(unsigned char *) Z_STRVAL_P(var), Z_STRLEN_P(var), 0, ENT_QUOTES, NULL);
412 
413 		php_wddx_add_chunk_ex(packet, ZSTR_VAL(buf), ZSTR_LEN(buf));
414 
415 		zend_string_release_ex(buf, 0);
416 	}
417 	php_wddx_add_chunk_static(packet, WDDX_STRING_E);
418 }
419 /* }}} */
420 
421 /* {{{ php_wddx_serialize_number
422  */
php_wddx_serialize_number(wddx_packet * packet,zval * var)423 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
424 {
425 	char tmp_buf[WDDX_BUF_LEN], *dec_point;
426 	zend_string *str = zval_get_string_func(var);
427 	snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, ZSTR_VAL(str));
428 	zend_string_release_ex(str, 0);
429 
430 	dec_point = strchr(tmp_buf, ',');
431 	if (dec_point) {
432 		*dec_point = '.';
433 	}
434 	php_wddx_add_chunk(packet, tmp_buf);
435 }
436 /* }}} */
437 
438 /* {{{ php_wddx_serialize_boolean
439  */
php_wddx_serialize_boolean(wddx_packet * packet,zval * var)440 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
441 {
442 	php_wddx_add_chunk(packet, Z_TYPE_P(var) == IS_TRUE ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
443 }
444 /* }}} */
445 
446 /* {{{ php_wddx_serialize_unset
447  */
php_wddx_serialize_unset(wddx_packet * packet)448 static void php_wddx_serialize_unset(wddx_packet *packet)
449 {
450 	php_wddx_add_chunk_static(packet, WDDX_NULL);
451 }
452 /* }}} */
453 
454 /* {{{ php_wddx_serialize_object
455  */
php_wddx_serialize_object(wddx_packet * packet,zval * obj)456 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
457 {
458 /* OBJECTS_FIXME */
459 	zval *ent, fname, *varname;
460 	zval retval;
461 	zend_string *key;
462 	zend_ulong idx;
463 	char tmp_buf[WDDX_BUF_LEN];
464 	HashTable *objhash, *sleephash;
465 	zend_class_entry *ce;
466 	PHP_CLASS_ATTRIBUTES;
467 
468 	PHP_SET_CLASS_ATTRIBUTES(obj);
469 	ce = Z_OBJCE_P(obj);
470 	if (!ce || ce->serialize || ce->unserialize) {
471 		php_error_docref(NULL, E_WARNING, "Class %s can not be serialized", ZSTR_VAL(class_name));
472 		PHP_CLEANUP_CLASS_ATTRIBUTES();
473 		return;
474 	}
475 
476 	ZVAL_STRING(&fname, "__sleep");
477 	/*
478 	 * We try to call __sleep() method on object. It's supposed to return an
479 	 * array of property names to be serialized.
480 	 */
481 	if (call_user_function(CG(function_table), obj, &fname, &retval, 0, 0) == SUCCESS) {
482 		if (!Z_ISUNDEF(retval) && (sleephash = HASH_OF(&retval))) {
483 			php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
484 			snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
485 			php_wddx_add_chunk(packet, tmp_buf);
486 			php_wddx_add_chunk_static(packet, WDDX_STRING_S);
487 			php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
488 			php_wddx_add_chunk_static(packet, WDDX_STRING_E);
489 			php_wddx_add_chunk_static(packet, WDDX_VAR_E);
490 
491 			objhash = Z_OBJPROP_P(obj);
492 
493 			ZEND_HASH_FOREACH_VAL(sleephash, varname) {
494 				if (Z_TYPE_P(varname) != IS_STRING) {
495 					php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
496 					continue;
497 				}
498 
499 				if ((ent = zend_hash_find(objhash, Z_STR_P(varname))) != NULL) {
500 					php_wddx_serialize_var(packet, ent, Z_STR_P(varname));
501 				}
502 			} ZEND_HASH_FOREACH_END();
503 
504 			php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
505 		}
506 	} else {
507 		php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
508 		snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
509 		php_wddx_add_chunk(packet, tmp_buf);
510 		php_wddx_add_chunk_static(packet, WDDX_STRING_S);
511 		php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
512 		php_wddx_add_chunk_static(packet, WDDX_STRING_E);
513 		php_wddx_add_chunk_static(packet, WDDX_VAR_E);
514 
515 		objhash = Z_OBJPROP_P(obj);
516 		ZEND_HASH_FOREACH_KEY_VAL(objhash, idx, key, ent) {
517 			if (ent == obj) {
518 				continue;
519 			}
520 			if (key) {
521 				const char *class_name, *prop_name;
522 				size_t prop_name_len;
523 				zend_string *tmp;
524 
525 				zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
526 				tmp = zend_string_init(prop_name, prop_name_len, 0);
527 				php_wddx_serialize_var(packet, ent, tmp);
528 				zend_string_release_ex(tmp, 0);
529 			} else {
530 				key = zend_long_to_str(idx);
531 				php_wddx_serialize_var(packet, ent, key);
532 				zend_string_release_ex(key, 0);
533 			}
534 		} ZEND_HASH_FOREACH_END();
535 		php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
536 	}
537 
538 	PHP_CLEANUP_CLASS_ATTRIBUTES();
539 
540 	zval_ptr_dtor(&fname);
541 	zval_ptr_dtor(&retval);
542 }
543 /* }}} */
544 
545 /* {{{ php_wddx_serialize_array
546  */
php_wddx_serialize_array(wddx_packet * packet,zval * arr)547 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
548 {
549 	zval *ent;
550 	zend_string *key;
551 	int is_struct = 0;
552 	zend_ulong idx;
553 	HashTable *target_hash;
554 	char tmp_buf[WDDX_BUF_LEN];
555 	zend_ulong ind = 0;
556 
557 	target_hash = Z_ARRVAL_P(arr);
558 	ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
559 		if (key) {
560 			is_struct = 1;
561 			break;
562 		}
563 
564 		if (idx != ind) {
565 			is_struct = 1;
566 			break;
567 		}
568 		ind++;
569 	} ZEND_HASH_FOREACH_END();
570 
571 	if (is_struct) {
572 		php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
573 	} else {
574 		snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
575 		php_wddx_add_chunk(packet, tmp_buf);
576 	}
577 
578 	ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
579 		if (ent == arr) {
580 			continue;
581 		}
582 
583 		if (is_struct) {
584 			if (key) {
585 				php_wddx_serialize_var(packet, ent, key);
586 			} else {
587 				key = zend_long_to_str(idx);
588 				php_wddx_serialize_var(packet, ent, key);
589 				zend_string_release_ex(key, 0);
590 			}
591 		} else {
592 			php_wddx_serialize_var(packet, ent, NULL);
593 		}
594 	} ZEND_HASH_FOREACH_END();
595 
596 	if (is_struct) {
597 		php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
598 	} else {
599 		php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
600 	}
601 }
602 /* }}} */
603 
604 /* {{{ php_wddx_serialize_var
605  */
php_wddx_serialize_var(wddx_packet * packet,zval * var,zend_string * name)606 void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
607 {
608 	HashTable *ht;
609 
610 	if (name) {
611 		char *tmp_buf;
612 		zend_string *name_esc = php_escape_html_entities((unsigned char *) ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES, NULL);
613 		tmp_buf = emalloc(ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S));
614 		snprintf(tmp_buf, ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S), WDDX_VAR_S, ZSTR_VAL(name_esc));
615 		php_wddx_add_chunk(packet, tmp_buf);
616 		efree(tmp_buf);
617 		zend_string_release_ex(name_esc, 0);
618 	}
619 
620 	if (Z_TYPE_P(var) == IS_INDIRECT) {
621 		var = Z_INDIRECT_P(var);
622 	}
623 	ZVAL_DEREF(var);
624 	switch (Z_TYPE_P(var)) {
625 		case IS_STRING:
626 			php_wddx_serialize_string(packet, var);
627 			break;
628 
629 		case IS_LONG:
630 		case IS_DOUBLE:
631 			php_wddx_serialize_number(packet, var);
632 			break;
633 
634 		case IS_TRUE:
635 		case IS_FALSE:
636 			php_wddx_serialize_boolean(packet, var);
637 			break;
638 
639 		case IS_NULL:
640 			php_wddx_serialize_unset(packet);
641 			break;
642 
643 		case IS_ARRAY:
644 			ht = Z_ARRVAL_P(var);
645 			if (Z_REFCOUNTED_P(var)) {
646 				if (GC_IS_RECURSIVE(ht)) {
647 					zend_throw_error(NULL, "WDDX doesn't support circular references");
648 					return;
649 				}
650 				GC_PROTECT_RECURSION(ht);
651 			}
652 			php_wddx_serialize_array(packet, var);
653 			if (Z_REFCOUNTED_P(var)) {
654 				GC_UNPROTECT_RECURSION(ht);
655 			}
656 			break;
657 
658 		case IS_OBJECT:
659 			ht = Z_OBJPROP_P(var);
660 			if (GC_IS_RECURSIVE(ht)) {
661 				zend_throw_error(NULL, "WDDX doesn't support circular references");
662 				return;
663 			}
664 			GC_PROTECT_RECURSION(ht);
665  			php_wddx_serialize_object(packet, var);
666 			GC_UNPROTECT_RECURSION(ht);
667 			break;
668 	}
669 
670 	if (name) {
671 		php_wddx_add_chunk_static(packet, WDDX_VAR_E);
672 	}
673 }
674 /* }}} */
675 
676 /* {{{ php_wddx_add_var
677  */
php_wddx_add_var(wddx_packet * packet,zval * name_var)678 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
679 {
680 	zval *val;
681 	HashTable *target_hash;
682 
683 	if (Z_TYPE_P(name_var) == IS_STRING) {
684 		zend_array *symbol_table = zend_rebuild_symbol_table();
685 		if ((val = zend_hash_find(symbol_table, Z_STR_P(name_var))) != NULL) {
686 			if (Z_TYPE_P(val) == IS_INDIRECT) {
687 				val = Z_INDIRECT_P(val);
688 			}
689 			php_wddx_serialize_var(packet, val, Z_STR_P(name_var));
690 		}
691 	} else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT)	{
692 		int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
693 
694 		target_hash = HASH_OF(name_var);
695 
696 		if (!Z_REFCOUNTED_P(name_var)) {
697 			ZEND_HASH_FOREACH_VAL(target_hash, val) {
698 				php_wddx_add_var(packet, val);
699 			} ZEND_HASH_FOREACH_END();
700 		} else {
701 			if (is_array) {
702 				if (GC_IS_RECURSIVE(target_hash)) {
703 					php_error_docref(NULL, E_WARNING, "recursion detected");
704 					return;
705 				}
706 				GC_PROTECT_RECURSION(target_hash);
707 			}
708 			ZEND_HASH_FOREACH_VAL(target_hash, val) {
709 				ZVAL_DEREF(val);
710 				php_wddx_add_var(packet, val);
711 
712 			} ZEND_HASH_FOREACH_END();
713 			if (is_array) {
714 				GC_UNPROTECT_RECURSION(target_hash);
715 			}
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(NULL, &ent1->data, &fname, &retval, 0, 0);
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 						Z_TRY_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_ptr_dtor_str(&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_ex(str, 0);
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