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