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