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