1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Brad Lafountain <rodif_bl@yahoo.com> |
16 | Shane Caraveo <shane@caraveo.com> |
17 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include <time.h>
22
23 #include "php_soap.h"
24 #include "ext/libxml/php_libxml.h"
25 #include "ext/standard/base64.h"
26 #include <libxml/parserInternals.h>
27 #include "zend_strtod.h"
28 #include "zend_interfaces.h"
29
30 /* zval type decode */
31 static zval *to_zval_double(zval* ret, encodeTypePtr type, xmlNodePtr data);
32 static zval *to_zval_long(zval* ret, encodeTypePtr type, xmlNodePtr data);
33 static zval *to_zval_bool(zval* ret, encodeTypePtr type, xmlNodePtr data);
34 static zval *to_zval_string(zval* ret, encodeTypePtr type, xmlNodePtr data);
35 static zval *to_zval_stringr(zval* ret, encodeTypePtr type, xmlNodePtr data);
36 static zval *to_zval_stringc(zval* ret, encodeTypePtr type, xmlNodePtr data);
37 static zval *to_zval_map(zval* ret, encodeTypePtr type, xmlNodePtr data);
38 static zval *to_zval_null(zval* ret, encodeTypePtr type, xmlNodePtr data);
39 static zval *to_zval_base64(zval* ret, encodeTypePtr type, xmlNodePtr data);
40 static zval *to_zval_hexbin(zval* ret, encodeTypePtr type, xmlNodePtr data);
41
42 static xmlNodePtr to_xml_long(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
43 static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
44 static xmlNodePtr to_xml_bool(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
45
46 /* String encode */
47 static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
48 static xmlNodePtr to_xml_base64(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
49 static xmlNodePtr to_xml_hexbin(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
50
51 /* Null encode */
52 static xmlNodePtr to_xml_null(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
53
54 /* Array encode */
55 static xmlNodePtr guess_array_map(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
56 static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
57
58 static xmlNodePtr to_xml_list(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent);
59 static xmlNodePtr to_xml_list1(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent);
60
61 /* Datetime encode/decode */
62 static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, char *format, int style, xmlNodePtr parent);
63 static xmlNodePtr to_xml_datetime(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
64 static xmlNodePtr to_xml_time(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
65 static xmlNodePtr to_xml_date(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
66 static xmlNodePtr to_xml_gyearmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
67 static xmlNodePtr to_xml_gyear(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
68 static xmlNodePtr to_xml_gmonthday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
69 static xmlNodePtr to_xml_gday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
70 static xmlNodePtr to_xml_gmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
71 static xmlNodePtr to_xml_duration(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
72
73 static zval *to_zval_object(zval *ret, encodeTypePtr type, xmlNodePtr data);
74 static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data);
75
76 static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
77 static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
78
79 static zval *to_zval_any(zval *ret, encodeTypePtr type, xmlNodePtr data);
80 static xmlNodePtr to_xml_any(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
81
82 /* Try and guess for non-wsdl clients and servers */
83 static zval *guess_zval_convert(zval *ret, encodeTypePtr type, xmlNodePtr data);
84 static xmlNodePtr guess_xml_convert(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
85
86 static int is_map(zval *array);
87 static encodePtr get_array_type(xmlNodePtr node, zval *array, smart_str *out_type);
88
89 static xmlNodePtr check_and_resolve_href(xmlNodePtr data);
90
91 static void set_ns_prop(xmlNodePtr node, char *ns, char *name, char *val);
92 static void set_xsi_nil(xmlNodePtr node);
93 static void set_xsi_type(xmlNodePtr node, char *type);
94
95 static void get_type_str(xmlNodePtr node, const char* ns, const char* type, smart_str* ret);
96 static void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type);
97
98 static void set_ns_and_type(xmlNodePtr node, encodeTypePtr type);
99
100 #define FIND_XML_NULL(xml,zval) \
101 { \
102 xmlAttrPtr null; \
103 if (!xml) { \
104 ZVAL_NULL(zval); \
105 return zval; \
106 } \
107 if (xml->properties) { \
108 null = get_attribute(xml->properties, "nil"); \
109 if (null) { \
110 ZVAL_NULL(zval); \
111 return zval; \
112 } \
113 } \
114 }
115
116 #define CHECK_XML_NULL(xml) \
117 { \
118 xmlAttrPtr null; \
119 if (!xml) { \
120 ZVAL_NULL(ret); \
121 return ret; \
122 } \
123 if (xml->properties) { \
124 null = get_attribute(xml->properties, "nil"); \
125 if (null) { \
126 ZVAL_NULL(ret); \
127 return ret; \
128 } \
129 } \
130 }
131
132 #define FIND_ZVAL_NULL(zval, xml, style) \
133 { \
134 if (!zval || Z_TYPE_P(zval) == IS_NULL) { \
135 if (style == SOAP_ENCODED) {\
136 set_xsi_nil(xml); \
137 } \
138 return xml; \
139 } \
140 }
141
142 const encode defaultEncoding[] = {
143 {{UNKNOWN_TYPE, NULL, NULL, NULL, NULL}, guess_zval_convert, guess_xml_convert},
144
145 {{IS_NULL, "nil", XSI_NAMESPACE, NULL, NULL}, to_zval_null, to_xml_null},
146 {{IS_STRING, XSD_STRING_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_string, to_xml_string},
147 {{IS_LONG, XSD_INT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
148 {{IS_DOUBLE, XSD_FLOAT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_double, to_xml_double},
149 {{IS_FALSE, XSD_BOOLEAN_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_bool, to_xml_bool},
150 {{IS_TRUE, XSD_BOOLEAN_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_bool, to_xml_bool},
151 {{IS_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_1_ENC_NAMESPACE, NULL, NULL}, to_zval_array, guess_array_map},
152 {{IS_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_1_ENC_NAMESPACE, NULL, NULL}, to_zval_object, to_xml_object},
153 {{IS_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_2_ENC_NAMESPACE, NULL, NULL}, to_zval_array, guess_array_map},
154 {{IS_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_2_ENC_NAMESPACE, NULL, NULL}, to_zval_object, to_xml_object},
155
156 {{XSD_STRING, XSD_STRING_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_string, to_xml_string},
157 {{XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_bool, to_xml_bool},
158 {{XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
159 {{XSD_FLOAT, XSD_FLOAT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_double, to_xml_double},
160 {{XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_double, to_xml_double},
161
162 {{XSD_DATETIME, XSD_DATETIME_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_datetime},
163 {{XSD_TIME, XSD_TIME_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_time},
164 {{XSD_DATE, XSD_DATE_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_date},
165 {{XSD_GYEARMONTH, XSD_GYEARMONTH_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_gyearmonth},
166 {{XSD_GYEAR, XSD_GYEAR_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_gyear},
167 {{XSD_GMONTHDAY, XSD_GMONTHDAY_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_gmonthday},
168 {{XSD_GDAY, XSD_GDAY_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_gday},
169 {{XSD_GMONTH, XSD_GMONTH_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_gmonth},
170 {{XSD_DURATION, XSD_DURATION_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_duration},
171
172 {{XSD_HEXBINARY, XSD_HEXBINARY_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_hexbin, to_xml_hexbin},
173 {{XSD_BASE64BINARY, XSD_BASE64BINARY_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_base64, to_xml_base64},
174
175 {{XSD_LONG, XSD_LONG_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
176 {{XSD_INT, XSD_INT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
177 {{XSD_SHORT, XSD_SHORT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
178 {{XSD_BYTE, XSD_BYTE_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
179 {{XSD_NONPOSITIVEINTEGER, XSD_NONPOSITIVEINTEGER_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
180 {{XSD_POSITIVEINTEGER, XSD_POSITIVEINTEGER_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
181 {{XSD_NONNEGATIVEINTEGER, XSD_NONNEGATIVEINTEGER_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
182 {{XSD_NEGATIVEINTEGER, XSD_NEGATIVEINTEGER_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
183 {{XSD_UNSIGNEDBYTE, XSD_UNSIGNEDBYTE_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
184 {{XSD_UNSIGNEDSHORT, XSD_UNSIGNEDSHORT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
185 {{XSD_UNSIGNEDINT, XSD_UNSIGNEDINT_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
186 {{XSD_UNSIGNEDLONG, XSD_UNSIGNEDLONG_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
187 {{XSD_INTEGER, XSD_INTEGER_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
188
189 {{XSD_ANYTYPE, XSD_ANYTYPE_STRING, XSD_NAMESPACE, NULL, NULL}, guess_zval_convert, guess_xml_convert},
190 {{XSD_UR_TYPE, XSD_UR_TYPE_STRING, XSD_NAMESPACE, NULL, NULL}, guess_zval_convert, guess_xml_convert},
191 {{XSD_ANYURI, XSD_ANYURI_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
192 {{XSD_QNAME, XSD_QNAME_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
193 {{XSD_NOTATION, XSD_NOTATION_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
194 {{XSD_NORMALIZEDSTRING, XSD_NORMALIZEDSTRING_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringr, to_xml_string},
195 {{XSD_TOKEN, XSD_TOKEN_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
196 {{XSD_LANGUAGE, XSD_LANGUAGE_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
197 {{XSD_NMTOKEN, XSD_NMTOKEN_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
198 {{XSD_NMTOKENS, XSD_NMTOKENS_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_list1},
199 {{XSD_NAME, XSD_NAME_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
200 {{XSD_NCNAME, XSD_NCNAME_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
201 {{XSD_ID, XSD_ID_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
202 {{XSD_IDREF, XSD_IDREF_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
203 {{XSD_IDREFS, XSD_IDREFS_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_list1},
204 {{XSD_ENTITY, XSD_ENTITY_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
205 {{XSD_ENTITIES, XSD_ENTITIES_STRING, XSD_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_list1},
206
207 {{APACHE_MAP, APACHE_MAP_STRING, APACHE_NAMESPACE, NULL, NULL}, to_zval_map, to_xml_map},
208
209 {{SOAP_ENC_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_1_ENC_NAMESPACE, NULL, NULL}, to_zval_object, to_xml_object},
210 {{SOAP_ENC_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_1_ENC_NAMESPACE, NULL, NULL}, to_zval_array, to_xml_array},
211 {{SOAP_ENC_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_2_ENC_NAMESPACE, NULL, NULL}, to_zval_object, to_xml_object},
212 {{SOAP_ENC_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_2_ENC_NAMESPACE, NULL, NULL}, to_zval_array, to_xml_array},
213
214 /* support some of the 1999 data types */
215 {{XSD_STRING, XSD_STRING_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_string, to_xml_string},
216 {{XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_bool, to_xml_bool},
217 {{XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
218 {{XSD_FLOAT, XSD_FLOAT_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_double, to_xml_double},
219 {{XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_double, to_xml_double},
220
221 {{XSD_LONG, XSD_LONG_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
222 {{XSD_INT, XSD_INT_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
223 {{XSD_SHORT, XSD_SHORT_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
224 {{XSD_BYTE, XSD_BYTE_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_long, to_xml_long},
225 {{XSD_1999_TIMEINSTANT, XSD_1999_TIMEINSTANT_STRING, XSD_1999_NAMESPACE, NULL, NULL}, to_zval_stringc, to_xml_string},
226
227 {{XSD_ANYXML, "<anyXML>", "<anyXML>", NULL, NULL}, to_zval_any, to_xml_any},
228
229 {{END_KNOWN_TYPES, NULL, NULL, NULL, NULL}, guess_zval_convert, guess_xml_convert}
230 };
231
232 int numDefaultEncodings = sizeof(defaultEncoding)/sizeof(encode);
233
234
whiteSpace_replace(xmlChar * str)235 void whiteSpace_replace(xmlChar* str)
236 {
237 while (*str != '\0') {
238 if (*str == '\x9' || *str == '\xA' || *str == '\xD') {
239 *str = ' ';
240 }
241 str++;
242 }
243 }
244
whiteSpace_collapse(xmlChar * str)245 void whiteSpace_collapse(xmlChar* str)
246 {
247 xmlChar *pos;
248 xmlChar old;
249
250 pos = str;
251 whiteSpace_replace(str);
252 while (*str == ' ') {
253 str++;
254 }
255 old = '\0';
256 while (*str != '\0') {
257 if (*str != ' ' || old != ' ') {
258 *pos = *str;
259 pos++;
260 }
261 old = *str;
262 str++;
263 }
264 if (old == ' ') {
265 --pos;
266 }
267 *pos = '\0';
268 }
269
find_encoder_by_type_name(sdlPtr sdl,const char * type)270 static encodePtr find_encoder_by_type_name(sdlPtr sdl, const char *type)
271 {
272 if (sdl && sdl->encoders) {
273 encodePtr enc;
274
275 ZEND_HASH_FOREACH_PTR(sdl->encoders, enc) {
276 if (strcmp(enc->details.type_str, type) == 0) {
277 return enc;
278 }
279 } ZEND_HASH_FOREACH_END();
280 }
281 return NULL;
282 }
283
soap_check_zval_ref(zval * data,xmlNodePtr node)284 static zend_bool soap_check_zval_ref(zval *data, xmlNodePtr node) {
285 xmlNodePtr node_ptr;
286
287 if (SOAP_GLOBAL(ref_map)) {
288 if (Z_TYPE_P(data) == IS_OBJECT) {
289 data = (zval*)Z_OBJ_P(data);
290 }
291 if ((node_ptr = zend_hash_index_find_ptr(SOAP_GLOBAL(ref_map), (zend_ulong)data)) != NULL) {
292 xmlAttrPtr attr = node_ptr->properties;
293 char *id;
294 smart_str prefix = {0};
295
296 if (node_ptr == node) {
297 return 0;
298 }
299 if (SOAP_GLOBAL(soap_version) == SOAP_1_1) {
300 while (1) {
301 attr = get_attribute(attr, "id");
302 if (attr == NULL || attr->ns == NULL) {
303 break;
304 }
305 attr = attr->next;
306 }
307 if (attr) {
308 id = (char*)attr->children->content;
309 smart_str_appendc(&prefix, '#');
310 smart_str_appends(&prefix, id);
311 smart_str_0(&prefix);
312 id = ZSTR_VAL(prefix.s);
313 } else {
314 SOAP_GLOBAL(cur_uniq_ref)++;
315 smart_str_appendl(&prefix, "#ref", 4);
316 smart_str_append_long(&prefix, SOAP_GLOBAL(cur_uniq_ref));
317 smart_str_0(&prefix);
318 id = ZSTR_VAL(prefix.s);
319 xmlSetProp(node_ptr, BAD_CAST("id"), BAD_CAST(id+1));
320 }
321 xmlSetProp(node, BAD_CAST("href"), BAD_CAST(id));
322 } else {
323 attr = get_attribute_ex(attr, "id", SOAP_1_2_ENC_NAMESPACE);
324 if (attr) {
325 id = (char*)attr->children->content;
326 smart_str_appendc(&prefix, '#');
327 smart_str_appends(&prefix, id);
328 smart_str_0(&prefix);
329 id = ZSTR_VAL(prefix.s);
330 } else {
331 SOAP_GLOBAL(cur_uniq_ref)++;
332 smart_str_appendl(&prefix, "#ref", 4);
333 smart_str_append_long(&prefix, SOAP_GLOBAL(cur_uniq_ref));
334 smart_str_0(&prefix);
335 id = ZSTR_VAL(prefix.s);
336 set_ns_prop(node_ptr, SOAP_1_2_ENC_NAMESPACE, "id", id+1);
337 }
338 set_ns_prop(node, SOAP_1_2_ENC_NAMESPACE, "ref", id);
339 }
340 smart_str_free(&prefix);
341 return 1;
342 } else {
343 zend_hash_index_update_ptr(SOAP_GLOBAL(ref_map), (zend_ulong)data, node);
344 }
345 }
346 return 0;
347 }
348
soap_check_xml_ref(zval * data,xmlNodePtr node)349 static zend_bool soap_check_xml_ref(zval *data, xmlNodePtr node)
350 {
351 zval *data_ptr;
352
353 if (SOAP_GLOBAL(ref_map)) {
354 if ((data_ptr = zend_hash_index_find(SOAP_GLOBAL(ref_map), (zend_ulong)node)) != NULL) {
355 if (!Z_REFCOUNTED_P(data) ||
356 !Z_REFCOUNTED_P(data_ptr) ||
357 Z_COUNTED_P(data) != Z_COUNTED_P(data_ptr)) {
358 zval_ptr_dtor(data);
359 ZVAL_COPY(data, data_ptr);
360 return 1;
361 }
362 }
363 }
364 return 0;
365 }
366
soap_add_xml_ref(zval * data,xmlNodePtr node)367 static void soap_add_xml_ref(zval *data, xmlNodePtr node)
368 {
369 if (SOAP_GLOBAL(ref_map)) {
370 zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, data);
371 }
372 }
373
master_to_xml_int(encodePtr encode,zval * data,int style,xmlNodePtr parent,int check_class_map)374 static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xmlNodePtr parent, int check_class_map)
375 {
376 xmlNodePtr node = NULL;
377 int add_type = 0;
378
379 if (data) {
380 ZVAL_DEREF(data);
381 }
382
383 /* Special handling of class SoapVar */
384 if (data &&
385 Z_TYPE_P(data) == IS_OBJECT &&
386 Z_OBJCE_P(data) == soap_var_class_entry) {
387 zval *ztype, *zdata, *zns, *zstype, *zname, *znamens;
388 encodePtr enc = NULL;
389 HashTable *ht = Z_OBJPROP_P(data);
390
391 if ((ztype = zend_hash_str_find_deref(ht, "enc_type", sizeof("enc_type")-1)) == NULL ||
392 Z_TYPE_P(ztype) != IS_LONG) {
393 soap_error0(E_ERROR, "Encoding: SoapVar has no 'enc_type' property");
394 }
395
396 if ((zstype = zend_hash_str_find_deref(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
397 Z_TYPE_P(zstype) == IS_STRING) {
398 if ((zns = zend_hash_str_find_deref(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
399 Z_TYPE_P(zns) == IS_STRING) {
400 enc = get_encoder(SOAP_GLOBAL(sdl), Z_STRVAL_P(zns), Z_STRVAL_P(zstype));
401 } else {
402 zns = NULL;
403 enc = get_encoder_ex(SOAP_GLOBAL(sdl), Z_STRVAL_P(zstype), Z_STRLEN_P(zstype));
404 }
405 if (enc == NULL && SOAP_GLOBAL(typemap)) {
406 smart_str nscat = {0};
407
408 if (zns != NULL) {
409 smart_str_appendl(&nscat, Z_STRVAL_P(zns), Z_STRLEN_P(zns));
410 smart_str_appendc(&nscat, ':');
411 }
412 smart_str_appendl(&nscat, Z_STRVAL_P(zstype), Z_STRLEN_P(zstype));
413 smart_str_0(&nscat);
414 enc = zend_hash_find_ptr(SOAP_GLOBAL(typemap), nscat.s);
415 smart_str_free(&nscat);
416 }
417 }
418 if (enc == NULL) {
419 enc = get_conversion(Z_LVAL_P(ztype));
420 }
421 if (enc == NULL) {
422 enc = encode;
423 }
424
425 zdata = zend_hash_str_find_deref(ht, "enc_value", sizeof("enc_value")-1);
426 node = master_to_xml(enc, zdata, style, parent);
427
428 if (style == SOAP_ENCODED || (SOAP_GLOBAL(sdl) && encode != enc)) {
429 if ((zstype = zend_hash_str_find_deref(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
430 Z_TYPE_P(zstype) == IS_STRING) {
431 if ((zns = zend_hash_str_find_deref(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
432 Z_TYPE_P(zns) == IS_STRING) {
433 set_ns_and_type_ex(node, Z_STRVAL_P(zns), Z_STRVAL_P(zstype));
434 } else {
435 set_ns_and_type_ex(node, NULL, Z_STRVAL_P(zstype));
436 }
437 }
438 }
439
440 if ((zname = zend_hash_str_find_deref(ht, "enc_name", sizeof("enc_name")-1)) != NULL &&
441 Z_TYPE_P(zname) == IS_STRING) {
442 xmlNodeSetName(node, BAD_CAST(Z_STRVAL_P(zname)));
443 }
444 if ((znamens = zend_hash_str_find_deref(ht, "enc_namens", sizeof("enc_namens")-1)) != NULL &&
445 Z_TYPE_P(znamens) == IS_STRING) {
446 xmlNsPtr nsp = encode_add_ns(node, Z_STRVAL_P(znamens));
447 xmlSetNs(node, nsp);
448 }
449 } else {
450 if (check_class_map && SOAP_GLOBAL(class_map) && data &&
451 Z_TYPE_P(data) == IS_OBJECT &&
452 !GC_IS_RECURSIVE(Z_OBJPROP_P(data))) {
453 zend_class_entry *ce = Z_OBJCE_P(data);
454 zval *tmp;
455 zend_string *type_name;
456
457 ZEND_HASH_FOREACH_STR_KEY_VAL(SOAP_GLOBAL(class_map), type_name, tmp) {
458 ZVAL_DEREF(tmp);
459 if (Z_TYPE_P(tmp) == IS_STRING &&
460 ZSTR_LEN(ce->name) == Z_STRLEN_P(tmp) &&
461 zend_binary_strncasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), Z_STRVAL_P(tmp), ZSTR_LEN(ce->name), ZSTR_LEN(ce->name)) == 0 &&
462 type_name) {
463
464 /* TODO: namespace isn't stored */
465 encodePtr enc = NULL;
466 if (SOAP_GLOBAL(sdl)) {
467 enc = get_encoder(SOAP_GLOBAL(sdl), SOAP_GLOBAL(sdl)->target_ns, ZSTR_VAL(type_name));
468 if (!enc) {
469 enc = find_encoder_by_type_name(SOAP_GLOBAL(sdl), ZSTR_VAL(type_name));
470 }
471 }
472 if (enc) {
473 if (encode != enc && style == SOAP_LITERAL) {
474 add_type = 1;
475 }
476 encode = enc;
477 }
478 break;
479 }
480 } ZEND_HASH_FOREACH_END();
481 }
482
483 if (encode == NULL) {
484 encode = get_conversion(UNKNOWN_TYPE);
485 }
486 if (SOAP_GLOBAL(typemap) && encode->details.type_str) {
487 smart_str nscat = {0};
488 encodePtr new_enc;
489
490 if (encode->details.ns) {
491 smart_str_appends(&nscat, encode->details.ns);
492 smart_str_appendc(&nscat, ':');
493 }
494 smart_str_appends(&nscat, encode->details.type_str);
495 smart_str_0(&nscat);
496 if ((new_enc = zend_hash_find_ptr(SOAP_GLOBAL(typemap), nscat.s)) != NULL) {
497 encode = new_enc;
498 }
499 smart_str_free(&nscat);
500 }
501 if (encode->to_xml) {
502 node = encode->to_xml(&encode->details, data, style, parent);
503 if (add_type) {
504 set_ns_and_type(node, &encode->details);
505 }
506 }
507 }
508 return node;
509 }
510
master_to_xml(encodePtr encode,zval * data,int style,xmlNodePtr parent)511 xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style, xmlNodePtr parent)
512 {
513 return master_to_xml_int(encode, data, style, parent, 1);
514 }
515
master_to_zval_int(zval * ret,encodePtr encode,xmlNodePtr data)516 static zval *master_to_zval_int(zval *ret, encodePtr encode, xmlNodePtr data)
517 {
518 if (SOAP_GLOBAL(typemap)) {
519 if (encode->details.type_str) {
520 smart_str nscat = {0};
521 encodePtr new_enc;
522
523 if (encode->details.ns) {
524 smart_str_appends(&nscat, encode->details.ns);
525 smart_str_appendc(&nscat, ':');
526 }
527 smart_str_appends(&nscat, encode->details.type_str);
528 smart_str_0(&nscat);
529 if ((new_enc = zend_hash_find_ptr(SOAP_GLOBAL(typemap), nscat.s)) != NULL) {
530 encode = new_enc;
531 }
532 smart_str_free(&nscat);
533 } else {
534 xmlAttrPtr type_attr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
535
536 if (type_attr != NULL) {
537 encodePtr new_enc;
538 xmlNsPtr nsptr;
539 char *ns, *cptype;
540 smart_str nscat = {0};
541
542 parse_namespace(type_attr->children->content, &cptype, &ns);
543 nsptr = xmlSearchNs(data->doc, data, BAD_CAST(ns));
544 if (nsptr != NULL) {
545 smart_str_appends(&nscat, (char*)nsptr->href);
546 smart_str_appendc(&nscat, ':');
547 }
548 smart_str_appends(&nscat, cptype);
549 smart_str_0(&nscat);
550 efree(cptype);
551 if (ns) {efree(ns);}
552 if ((new_enc = zend_hash_find_ptr(SOAP_GLOBAL(typemap), nscat.s)) != NULL) {
553 encode = new_enc;
554 }
555 smart_str_free(&nscat);
556 }
557 }
558 }
559 if (encode->to_zval) {
560 ret = encode->to_zval(ret, &encode->details, data);
561 }
562 return ret;
563 }
564
master_to_zval(zval * ret,encodePtr encode,xmlNodePtr data)565 zval *master_to_zval(zval *ret, encodePtr encode, xmlNodePtr data)
566 {
567 data = check_and_resolve_href(data);
568
569 if (encode == NULL) {
570 encode = get_conversion(UNKNOWN_TYPE);
571 } else {
572 /* Use xsi:type if it is defined */
573 xmlAttrPtr type_attr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
574
575 if (type_attr != NULL) {
576 encodePtr enc = get_encoder_from_prefix(SOAP_GLOBAL(sdl), data, type_attr->children->content);
577
578 if (enc != NULL && enc != encode) {
579 encodePtr tmp = enc;
580 while (tmp &&
581 tmp->details.sdl_type != NULL &&
582 tmp->details.sdl_type->kind != XSD_TYPEKIND_COMPLEX) {
583 if (enc == tmp->details.sdl_type->encode ||
584 tmp == tmp->details.sdl_type->encode) {
585 enc = NULL;
586 break;
587 }
588 tmp = tmp->details.sdl_type->encode;
589 }
590 if (enc != NULL) {
591 encode = enc;
592 }
593 }
594 }
595 }
596 return master_to_zval_int(ret, encode, data);
597 }
598
to_xml_user(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)599 xmlNodePtr to_xml_user(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
600 {
601 xmlNodePtr ret = NULL;
602 zval return_value;
603
604 if (type && type->map && Z_TYPE(type->map->to_xml) != IS_UNDEF) {
605 ZVAL_NULL(&return_value);
606
607 if (call_user_function(EG(function_table), NULL, &type->map->to_xml, &return_value, 1, data) == FAILURE) {
608 soap_error0(E_ERROR, "Encoding: Error calling to_xml callback");
609 }
610 if (Z_TYPE(return_value) == IS_STRING) {
611 xmlDocPtr doc = soap_xmlParseMemory(Z_STRVAL(return_value), Z_STRLEN(return_value));
612 if (doc && doc->children) {
613 ret = xmlDocCopyNode(doc->children, parent->doc, 1);
614 }
615 xmlFreeDoc(doc);
616 }
617
618 zval_ptr_dtor(&return_value);
619 }
620 if (!ret) {
621 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
622 }
623 xmlAddChild(parent, ret);
624 if (style == SOAP_ENCODED) {
625 set_ns_and_type(ret, type);
626 }
627 return ret;
628 }
629
to_zval_user(zval * ret,encodeTypePtr type,xmlNodePtr node)630 zval *to_zval_user(zval *ret, encodeTypePtr type, xmlNodePtr node)
631 {
632 if (type && type->map && Z_TYPE(type->map->to_zval) != IS_UNDEF) {
633 xmlBufferPtr buf;
634 zval data;
635 xmlNodePtr copy;
636
637 copy = xmlCopyNode(node, 1);
638 buf = xmlBufferCreate();
639 xmlNodeDump(buf, NULL, copy, 0, 0);
640 ZVAL_STRING(&data, (char*)xmlBufferContent(buf));
641 xmlBufferFree(buf);
642 xmlFreeNode(copy);
643
644 if (call_user_function(EG(function_table), NULL, &type->map->to_zval, ret, 1, &data) == FAILURE) {
645 soap_error0(E_ERROR, "Encoding: Error calling from_xml callback");
646 } else if (EG(exception)) {
647 ZVAL_NULL(ret);
648 }
649 zval_ptr_dtor(&data);
650 } else {
651 ZVAL_NULL(ret);
652 }
653 return ret;
654 }
655
656 /* TODO: get rid of "bogus".. ither by passing in the already created xmlnode or passing in the node name */
657 /* String encode/decode */
to_zval_string(zval * ret,encodeTypePtr type,xmlNodePtr data)658 static zval *to_zval_string(zval *ret, encodeTypePtr type, xmlNodePtr data)
659 {
660 ZVAL_NULL(ret);
661 FIND_XML_NULL(data, ret);
662 if (data && data->children) {
663 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
664 if (SOAP_GLOBAL(encoding) != NULL) {
665 xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, xmlStrlen(data->children->content));
666 xmlBufferPtr out = xmlBufferCreate();
667 int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
668
669 if (n >= 0) {
670 ZVAL_STRING(ret, (char*)xmlBufferContent(out));
671 } else {
672 ZVAL_STRING(ret, (char*)data->children->content);
673 }
674 xmlBufferFree(out);
675 xmlBufferFree(in);
676 } else {
677 ZVAL_STRING(ret, (char*)data->children->content);
678 }
679 } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) {
680 ZVAL_STRING(ret, (char*)data->children->content);
681 } else {
682 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
683 }
684 } else {
685 ZVAL_EMPTY_STRING(ret);
686 }
687 return ret;
688 }
689
to_zval_stringr(zval * ret,encodeTypePtr type,xmlNodePtr data)690 static zval *to_zval_stringr(zval *ret, encodeTypePtr type, xmlNodePtr data)
691 {
692 ZVAL_NULL(ret);
693 FIND_XML_NULL(data, ret);
694 if (data && data->children) {
695 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
696 whiteSpace_replace(data->children->content);
697 if (SOAP_GLOBAL(encoding) != NULL) {
698 xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, xmlStrlen(data->children->content));
699 xmlBufferPtr out = xmlBufferCreate();
700 int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
701
702 if (n >= 0) {
703 ZVAL_STRING(ret, (char*)xmlBufferContent(out));
704 } else {
705 ZVAL_STRING(ret, (char*)data->children->content);
706 }
707 xmlBufferFree(out);
708 xmlBufferFree(in);
709 } else {
710 ZVAL_STRING(ret, (char*)data->children->content);
711 }
712 } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) {
713 ZVAL_STRING(ret, (char*)data->children->content);
714 } else {
715 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
716 }
717 } else {
718 ZVAL_EMPTY_STRING(ret);
719 }
720 return ret;
721 }
722
to_zval_stringc(zval * ret,encodeTypePtr type,xmlNodePtr data)723 static zval *to_zval_stringc(zval *ret, encodeTypePtr type, xmlNodePtr data)
724 {
725 ZVAL_NULL(ret);
726 FIND_XML_NULL(data, ret);
727 if (data && data->children) {
728 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
729 whiteSpace_collapse(data->children->content);
730 if (SOAP_GLOBAL(encoding) != NULL) {
731 xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, xmlStrlen(data->children->content));
732 xmlBufferPtr out = xmlBufferCreate();
733 int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
734
735 if (n >= 0) {
736 ZVAL_STRING(ret, (char*)xmlBufferContent(out));
737 } else {
738 ZVAL_STRING(ret, (char*)data->children->content);
739 }
740 xmlBufferFree(out);
741 xmlBufferFree(in);
742 } else {
743 ZVAL_STRING(ret, (char*)data->children->content);
744 }
745 } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) {
746 ZVAL_STRING(ret, (char*)data->children->content);
747 } else {
748 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
749 }
750 } else {
751 ZVAL_EMPTY_STRING(ret);
752 }
753 return ret;
754 }
755
to_zval_base64(zval * ret,encodeTypePtr type,xmlNodePtr data)756 static zval *to_zval_base64(zval *ret, encodeTypePtr type, xmlNodePtr data)
757 {
758 zend_string *str;
759
760 ZVAL_NULL(ret);
761 FIND_XML_NULL(data, ret);
762 if (data && data->children) {
763 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
764 whiteSpace_collapse(data->children->content);
765 str = php_base64_decode(data->children->content, strlen((char*)data->children->content));
766 if (!str) {
767 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
768 }
769 ZVAL_STR(ret, str);
770 } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) {
771 str = php_base64_decode(data->children->content, strlen((char*)data->children->content));
772 if (!str) {
773 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
774 }
775 ZVAL_STR(ret, str);
776 } else {
777 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
778 }
779 } else {
780 ZVAL_EMPTY_STRING(ret);
781 }
782 return ret;
783 }
784
to_zval_hexbin(zval * ret,encodeTypePtr type,xmlNodePtr data)785 static zval *to_zval_hexbin(zval *ret, encodeTypePtr type, xmlNodePtr data)
786 {
787 zend_string *str;
788 size_t i, j;
789 unsigned char c;
790
791 ZVAL_NULL(ret);
792 FIND_XML_NULL(data, ret);
793 if (data && data->children) {
794 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
795 whiteSpace_collapse(data->children->content);
796 } else if (data->children->type != XML_CDATA_SECTION_NODE || data->children->next != NULL) {
797 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
798 return ret;
799 }
800 str = zend_string_alloc(strlen((char*)data->children->content) / 2, 0);
801 for (i = j = 0; i < ZSTR_LEN(str); i++) {
802 c = data->children->content[j++];
803 if (c >= '0' && c <= '9') {
804 ZSTR_VAL(str)[i] = (c - '0') << 4;
805 } else if (c >= 'a' && c <= 'f') {
806 ZSTR_VAL(str)[i] = (c - 'a' + 10) << 4;
807 } else if (c >= 'A' && c <= 'F') {
808 ZSTR_VAL(str)[i] = (c - 'A' + 10) << 4;
809 } else {
810 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
811 }
812 c = data->children->content[j++];
813 if (c >= '0' && c <= '9') {
814 ZSTR_VAL(str)[i] |= c - '0';
815 } else if (c >= 'a' && c <= 'f') {
816 ZSTR_VAL(str)[i] |= c - 'a' + 10;
817 } else if (c >= 'A' && c <= 'F') {
818 ZSTR_VAL(str)[i] |= c - 'A' + 10;
819 } else {
820 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
821 }
822 }
823 ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
824 ZVAL_NEW_STR(ret, str);
825 } else {
826 ZVAL_EMPTY_STRING(ret);
827 }
828 return ret;
829 }
830
to_xml_string(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)831 static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
832 {
833 xmlNodePtr ret, text;
834 char *str;
835 int new_len;
836
837 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
838 xmlAddChild(parent, ret);
839 FIND_ZVAL_NULL(data, ret, style);
840
841 if (Z_TYPE_P(data) == IS_STRING) {
842 str = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
843 new_len = Z_STRLEN_P(data);
844 } else {
845 zend_string *tmp = zval_get_string_func(data);
846 str = estrndup(ZSTR_VAL(tmp), ZSTR_LEN(tmp));
847 new_len = ZSTR_LEN(tmp);
848 zend_string_release_ex(tmp, 0);
849 }
850
851 if (SOAP_GLOBAL(encoding) != NULL) {
852 xmlBufferPtr in = xmlBufferCreateStatic(str, new_len);
853 xmlBufferPtr out = xmlBufferCreate();
854 int n = xmlCharEncInFunc(SOAP_GLOBAL(encoding), out, in);
855
856 if (n >= 0) {
857 efree(str);
858 str = estrdup((char*)xmlBufferContent(out));
859 new_len = n;
860 }
861 xmlBufferFree(out);
862 xmlBufferFree(in);
863 }
864
865 if (!php_libxml_xmlCheckUTF8(BAD_CAST(str))) {
866 char *err = emalloc(new_len + 8);
867 char c;
868 int i;
869
870 memcpy(err, str, new_len+1);
871 for (i = 0; (c = err[i++]);) {
872 if ((c & 0x80) == 0) {
873 } else if ((c & 0xe0) == 0xc0) {
874 if ((err[i] & 0xc0) != 0x80) {
875 break;
876 }
877 i++;
878 } else if ((c & 0xf0) == 0xe0) {
879 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80) {
880 break;
881 }
882 i += 2;
883 } else if ((c & 0xf8) == 0xf0) {
884 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80 || (err[i+2] & 0xc0) != 0x80) {
885 break;
886 }
887 i += 3;
888 } else {
889 break;
890 }
891 }
892 if (c) {
893 err[i-1] = '\\';
894 err[i++] = 'x';
895 err[i++] = ((unsigned char)c >> 4) + ((((unsigned char)c >> 4) > 9) ? ('a' - 10) : '0');
896 err[i++] = (c & 15) + (((c & 15) > 9) ? ('a' - 10) : '0');
897 err[i++] = '.';
898 err[i++] = '.';
899 err[i++] = '.';
900 err[i++] = 0;
901 }
902
903 soap_error1(E_ERROR, "Encoding: string '%s' is not a valid utf-8 string", err);
904 }
905
906 text = xmlNewTextLen(BAD_CAST(str), new_len);
907 xmlAddChild(ret, text);
908 efree(str);
909
910 if (style == SOAP_ENCODED) {
911 set_ns_and_type(ret, type);
912 }
913 return ret;
914 }
915
to_xml_base64(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)916 static xmlNodePtr to_xml_base64(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
917 {
918 xmlNodePtr ret, text;
919 zend_string *str;
920
921 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
922 xmlAddChild(parent, ret);
923 FIND_ZVAL_NULL(data, ret, style);
924
925 if (Z_TYPE_P(data) == IS_STRING) {
926 str = php_base64_encode((unsigned char*)Z_STRVAL_P(data), Z_STRLEN_P(data));
927 } else {
928 zend_string *tmp = zval_get_string_func(data);
929 str = php_base64_encode((unsigned char*) ZSTR_VAL(tmp), ZSTR_LEN(tmp));
930 zend_string_release_ex(tmp, 0);
931 }
932
933 text = xmlNewTextLen(BAD_CAST(ZSTR_VAL(str)), ZSTR_LEN(str));
934 xmlAddChild(ret, text);
935 zend_string_release_ex(str, 0);
936
937 if (style == SOAP_ENCODED) {
938 set_ns_and_type(ret, type);
939 }
940 return ret;
941 }
942
to_xml_hexbin(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)943 static xmlNodePtr to_xml_hexbin(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
944 {
945 static char hexconvtab[] = "0123456789ABCDEF";
946 xmlNodePtr ret, text;
947 unsigned char *str;
948 zval tmp;
949 size_t i, j;
950
951 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
952 xmlAddChild(parent, ret);
953 FIND_ZVAL_NULL(data, ret, style);
954
955 if (Z_TYPE_P(data) != IS_STRING) {
956 ZVAL_STR(&tmp, zval_get_string_func(data));
957 data = &tmp;
958 }
959 str = (unsigned char *) safe_emalloc(Z_STRLEN_P(data) * 2, sizeof(char), 1);
960
961 for (i = j = 0; i < Z_STRLEN_P(data); i++) {
962 str[j++] = hexconvtab[((unsigned char)Z_STRVAL_P(data)[i]) >> 4];
963 str[j++] = hexconvtab[((unsigned char)Z_STRVAL_P(data)[i]) & 15];
964 }
965 str[j] = '\0';
966
967 text = xmlNewTextLen(str, Z_STRLEN_P(data) * 2 * sizeof(char));
968 xmlAddChild(ret, text);
969 efree(str);
970 if (data == &tmp) {
971 zval_ptr_dtor_str(&tmp);
972 }
973
974 if (style == SOAP_ENCODED) {
975 set_ns_and_type(ret, type);
976 }
977 return ret;
978 }
979
to_zval_double(zval * ret,encodeTypePtr type,xmlNodePtr data)980 static zval *to_zval_double(zval *ret, encodeTypePtr type, xmlNodePtr data)
981 {
982 ZVAL_NULL(ret);
983 FIND_XML_NULL(data, ret);
984
985 if (data && data->children) {
986 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
987 zend_long lval;
988 double dval;
989
990 whiteSpace_collapse(data->children->content);
991 switch (is_numeric_string((char*)data->children->content, strlen((char*)data->children->content), &lval, &dval, 0)) {
992 case IS_LONG:
993 ZVAL_DOUBLE(ret, lval);
994 break;
995 case IS_DOUBLE:
996 ZVAL_DOUBLE(ret, dval);
997 break;
998 default:
999 if (strncasecmp((char*)data->children->content, "NaN", sizeof("NaN")-1) == 0) {
1000 ZVAL_DOUBLE(ret, php_get_nan());
1001 } else if (strncasecmp((char*)data->children->content, "INF", sizeof("INF")-1) == 0) {
1002 ZVAL_DOUBLE(ret, php_get_inf());
1003 } else if (strncasecmp((char*)data->children->content, "-INF", sizeof("-INF")-1) == 0) {
1004 ZVAL_DOUBLE(ret, -php_get_inf());
1005 } else {
1006 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
1007 }
1008 }
1009 } else {
1010 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
1011 }
1012 } else {
1013 ZVAL_NULL(ret);
1014 }
1015 return ret;
1016 }
1017
to_zval_long(zval * ret,encodeTypePtr type,xmlNodePtr data)1018 static zval *to_zval_long(zval *ret, encodeTypePtr type, xmlNodePtr data)
1019 {
1020 ZVAL_NULL(ret);
1021 FIND_XML_NULL(data, ret);
1022
1023 if (data && data->children) {
1024 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
1025 zend_long lval;
1026 double dval;
1027
1028 whiteSpace_collapse(data->children->content);
1029 errno = 0;
1030
1031 switch (is_numeric_string((char*)data->children->content, strlen((char*)data->children->content), &lval, &dval, 0)) {
1032 case IS_LONG:
1033 ZVAL_LONG(ret, lval);
1034 break;
1035 case IS_DOUBLE:
1036 ZVAL_DOUBLE(ret, dval);
1037 break;
1038 default:
1039 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
1040 }
1041 } else {
1042 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
1043 }
1044 } else {
1045 ZVAL_NULL(ret);
1046 }
1047 return ret;
1048 }
1049
to_xml_long(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1050 static xmlNodePtr to_xml_long(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1051 {
1052 xmlNodePtr ret;
1053
1054 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1055 xmlAddChild(parent, ret);
1056 FIND_ZVAL_NULL(data, ret, style);
1057
1058 if (Z_TYPE_P(data) == IS_DOUBLE) {
1059 char s[256];
1060
1061 snprintf(s, sizeof(s), "%0.0F",floor(Z_DVAL_P(data)));
1062 xmlNodeSetContent(ret, BAD_CAST(s));
1063 } else {
1064 zend_string *str = zend_long_to_str(zval_get_long(data));
1065 xmlNodeSetContentLen(ret, BAD_CAST(ZSTR_VAL(str)), ZSTR_LEN(str));
1066 zend_string_release_ex(str, 0);
1067 }
1068
1069 if (style == SOAP_ENCODED) {
1070 set_ns_and_type(ret, type);
1071 }
1072 return ret;
1073 }
1074
to_xml_double(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1075 static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1076 {
1077 xmlNodePtr ret;
1078 zval tmp;
1079 char *str;
1080
1081 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1082 xmlAddChild(parent, ret);
1083 FIND_ZVAL_NULL(data, ret, style);
1084
1085 ZVAL_DOUBLE(&tmp, zval_get_double(data));
1086
1087 str = (char *) safe_emalloc(EG(precision) >= 0 ? EG(precision) : 17, 1, MAX_LENGTH_OF_DOUBLE + 1);
1088 php_gcvt(Z_DVAL(tmp), EG(precision), '.', 'E', str);
1089 xmlNodeSetContentLen(ret, BAD_CAST(str), strlen(str));
1090 efree(str);
1091
1092 if (style == SOAP_ENCODED) {
1093 set_ns_and_type(ret, type);
1094 }
1095 return ret;
1096 }
1097
to_zval_bool(zval * ret,encodeTypePtr type,xmlNodePtr data)1098 static zval *to_zval_bool(zval *ret, encodeTypePtr type, xmlNodePtr data)
1099 {
1100 ZVAL_NULL(ret);
1101 FIND_XML_NULL(data, ret);
1102
1103 if (data && data->children) {
1104 if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) {
1105 whiteSpace_collapse(data->children->content);
1106 if (stricmp((char*)data->children->content, "true") == 0 ||
1107 stricmp((char*)data->children->content, "t") == 0 ||
1108 strcmp((char*)data->children->content, "1") == 0) {
1109 ZVAL_TRUE(ret);
1110 } else if (stricmp((char*)data->children->content, "false") == 0 ||
1111 stricmp((char*)data->children->content, "f") == 0 ||
1112 strcmp((char*)data->children->content, "0") == 0) {
1113 ZVAL_FALSE(ret);
1114 } else {
1115 ZVAL_STRING(ret, (char*)data->children->content);
1116 convert_to_boolean(ret);
1117 }
1118 } else {
1119 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
1120 }
1121 } else {
1122 ZVAL_NULL(ret);
1123 }
1124 return ret;
1125 }
1126
to_xml_bool(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1127 static xmlNodePtr to_xml_bool(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1128 {
1129 xmlNodePtr ret;
1130
1131 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1132 xmlAddChild(parent, ret);
1133 FIND_ZVAL_NULL(data, ret, style);
1134
1135 if (zend_is_true(data)) {
1136 xmlNodeSetContent(ret, BAD_CAST("true"));
1137 } else {
1138 xmlNodeSetContent(ret, BAD_CAST("false"));
1139 }
1140
1141 if (style == SOAP_ENCODED) {
1142 set_ns_and_type(ret, type);
1143 }
1144 return ret;
1145 }
1146
1147 /* Null encode/decode */
to_zval_null(zval * ret,encodeTypePtr type,xmlNodePtr data)1148 static zval *to_zval_null(zval *ret, encodeTypePtr type, xmlNodePtr data)
1149 {
1150 ZVAL_NULL(ret);
1151 return ret;
1152 }
1153
to_xml_null(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1154 static xmlNodePtr to_xml_null(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1155 {
1156 xmlNodePtr ret;
1157
1158 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1159 xmlAddChild(parent, ret);
1160 if (style == SOAP_ENCODED) {
1161 set_xsi_nil(ret);
1162 }
1163 return ret;
1164 }
1165
set_zval_property(zval * object,char * name,zval * val)1166 static void set_zval_property(zval* object, char* name, zval* val)
1167 {
1168 zend_update_property(Z_OBJCE_P(object), object, name, strlen(name), val);
1169 Z_TRY_DELREF_P(val);
1170 }
1171
get_zval_property(zval * object,char * name,zval * rv)1172 static zval* get_zval_property(zval* object, char* name, zval *rv)
1173 {
1174 if (Z_TYPE_P(object) == IS_OBJECT) {
1175 zval member;
1176 zval *data;
1177 zend_class_entry *old_scope;
1178
1179 ZVAL_STRING(&member, name);
1180 old_scope = EG(fake_scope);
1181 EG(fake_scope) = Z_OBJCE_P(object);
1182 data = Z_OBJ_HT_P(object)->read_property(object, &member, BP_VAR_IS, NULL, rv);
1183 if (data == &EG(uninitialized_zval)) {
1184 /* Hack for bug #32455 */
1185 zend_property_info *property_info;
1186
1187 property_info = zend_get_property_info(Z_OBJCE_P(object), Z_STR(member), 1);
1188 EG(fake_scope) = old_scope;
1189 if (property_info != ZEND_WRONG_PROPERTY_INFO && property_info &&
1190 zend_hash_exists(Z_OBJPROP_P(object), property_info->name)) {
1191 zval_ptr_dtor(&member);
1192 ZVAL_DEREF(data);
1193 return data;
1194 }
1195 zval_ptr_dtor(&member);
1196 return NULL;
1197 }
1198 zval_ptr_dtor(&member);
1199 EG(fake_scope) = old_scope;
1200 ZVAL_DEREF(data);
1201 return data;
1202 } else if (Z_TYPE_P(object) == IS_ARRAY) {
1203 return zend_hash_str_find_deref(Z_ARRVAL_P(object), name, strlen(name));
1204 }
1205 return NULL;
1206 }
1207
unset_zval_property(zval * object,char * name)1208 static void unset_zval_property(zval* object, char* name)
1209 {
1210 if (Z_TYPE_P(object) == IS_OBJECT) {
1211 zval member;
1212 zend_class_entry *old_scope;
1213
1214 ZVAL_STRING(&member, name);
1215 old_scope = EG(fake_scope);
1216 EG(fake_scope) = Z_OBJCE_P(object);
1217 Z_OBJ_HT_P(object)->unset_property(object, &member, NULL);
1218 EG(fake_scope) = old_scope;
1219 zval_ptr_dtor(&member);
1220 } else if (Z_TYPE_P(object) == IS_ARRAY) {
1221 zend_hash_str_del(Z_ARRVAL_P(object), name, strlen(name));
1222 }
1223 }
1224
model_to_zval_any(zval * ret,xmlNodePtr node)1225 static void model_to_zval_any(zval *ret, xmlNodePtr node)
1226 {
1227 zval rv, arr, val, keepVal;
1228 zval* any = NULL;
1229 char* name = NULL;
1230
1231 while (node != NULL) {
1232 if (get_zval_property(ret, (char*)node->name, &rv) == NULL) {
1233
1234 ZVAL_NULL(&val);
1235 master_to_zval(&val, get_conversion(XSD_ANYXML), node);
1236
1237 if (any && Z_TYPE_P(any) != IS_ARRAY) {
1238 /* Convert into array */
1239 array_init(&arr);
1240 if (name) {
1241 add_assoc_zval(&arr, name, any);
1242 } else {
1243 add_next_index_zval(&arr, any);
1244 }
1245 any = &arr;
1246 }
1247
1248 if (Z_TYPE(val) == IS_STRING && *Z_STRVAL(val) == '<') {
1249 name = NULL;
1250 while (node->next != NULL) {
1251 zval val2;
1252
1253 ZVAL_NULL(&val2);
1254 master_to_zval(&val2, get_conversion(XSD_ANYXML), node->next);
1255 if (Z_TYPE(val2) != IS_STRING || *Z_STRVAL(val) != '<') {
1256 Z_TRY_DELREF(val2);
1257 break;
1258 }
1259 concat_function(&val, &val, &val2);
1260 zval_ptr_dtor(&val2);
1261 node = node->next;
1262 }
1263 } else {
1264 name = (char*)node->name;
1265 }
1266
1267 if (any == NULL) {
1268 if (name) {
1269 /* Convert into array */
1270 array_init(&arr);
1271 add_assoc_zval(&arr, name, &val);
1272 any = &arr;
1273 name = NULL;
1274 } else {
1275 ZVAL_COPY_VALUE(&keepVal, &val);
1276 any = &keepVal;
1277 }
1278 } else {
1279 /* Add array element */
1280 if (name) {
1281 zval *el;
1282 if ((el = zend_hash_str_find(Z_ARRVAL_P(any), name, strlen(name))) != NULL) {
1283 if (Z_TYPE_P(el) != IS_ARRAY) {
1284 /* Convert into array */
1285 array_init(&arr);
1286 add_next_index_zval(&arr, el);
1287 el = &arr;
1288 }
1289 add_next_index_zval(el, &val);
1290 } else {
1291 add_assoc_zval(any, name, &val);
1292 }
1293 } else {
1294 add_next_index_zval(any, &val);
1295 }
1296 name = NULL;
1297 }
1298 }
1299 node = node->next;
1300 }
1301 if (any) {
1302 set_zval_property(ret, name ? name : "any", any);
1303 }
1304 }
1305
model_to_zval_object(zval * ret,sdlContentModelPtr model,xmlNodePtr data,sdlPtr sdl)1306 static void model_to_zval_object(zval *ret, sdlContentModelPtr model, xmlNodePtr data, sdlPtr sdl)
1307 {
1308 switch (model->kind) {
1309 case XSD_CONTENT_ELEMENT:
1310 if (model->u.element->name) {
1311 xmlNodePtr node = get_node(data->children, model->u.element->name);
1312
1313 if (node) {
1314 zval val;
1315 xmlNodePtr r_node;
1316
1317 ZVAL_NULL(&val);
1318 r_node = check_and_resolve_href(node);
1319 if (r_node && r_node->children && r_node->children->content) {
1320 if (model->u.element->fixed && strcmp(model->u.element->fixed, (char*)r_node->children->content) != 0) {
1321 soap_error3(E_ERROR, "Encoding: Element '%s' has fixed value '%s' (value '%s' is not allowed)", model->u.element->name, model->u.element->fixed, r_node->children->content);
1322 }
1323 master_to_zval(&val, model->u.element->encode, r_node);
1324 } else if (model->u.element->fixed) {
1325 xmlNodePtr dummy = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1326 xmlNodeSetContent(dummy, BAD_CAST(model->u.element->fixed));
1327 master_to_zval(&val, model->u.element->encode, dummy);
1328 xmlFreeNode(dummy);
1329 } else if (model->u.element->def && !model->u.element->nillable) {
1330 xmlNodePtr dummy = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1331 xmlNodeSetContent(dummy, BAD_CAST(model->u.element->def));
1332 master_to_zval(&val, model->u.element->encode, dummy);
1333 xmlFreeNode(dummy);
1334 } else {
1335 master_to_zval(&val, model->u.element->encode, r_node);
1336 }
1337 if ((node = get_node(node->next, model->u.element->name)) != NULL) {
1338 zval array;
1339
1340 array_init(&array);
1341 add_next_index_zval(&array, &val);
1342 do {
1343 ZVAL_NULL(&val);
1344 if (node && node->children && node->children->content) {
1345 if (model->u.element->fixed && strcmp(model->u.element->fixed, (char*)node->children->content) != 0) {
1346 soap_error3(E_ERROR, "Encoding: Element '%s' has fixed value '%s' (value '%s' is not allowed)", model->u.element->name, model->u.element->fixed, node->children->content);
1347 }
1348 master_to_zval(&val, model->u.element->encode, node);
1349 } else if (model->u.element->fixed) {
1350 xmlNodePtr dummy = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1351 xmlNodeSetContent(dummy, BAD_CAST(model->u.element->fixed));
1352 master_to_zval(&val, model->u.element->encode, dummy);
1353 xmlFreeNode(dummy);
1354 } else if (model->u.element->def && !model->u.element->nillable) {
1355 xmlNodePtr dummy = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1356 xmlNodeSetContent(dummy, BAD_CAST(model->u.element->def));
1357 master_to_zval(&val, model->u.element->encode, dummy);
1358 xmlFreeNode(dummy);
1359 } else {
1360 master_to_zval(&val, model->u.element->encode, node);
1361 }
1362 add_next_index_zval(&array, &val);
1363 } while ((node = get_node(node->next, model->u.element->name)) != NULL);
1364 ZVAL_COPY_VALUE(&val, &array);
1365 } else if ((Z_TYPE(val) != IS_NULL || !model->u.element->nillable) &&
1366 (SOAP_GLOBAL(features) & SOAP_SINGLE_ELEMENT_ARRAYS) &&
1367 (model->max_occurs == -1 || model->max_occurs > 1)) {
1368 zval array;
1369
1370 array_init(&array);
1371 add_next_index_zval(&array, &val);
1372 ZVAL_COPY_VALUE(&val, &array);
1373 }
1374 set_zval_property(ret, model->u.element->name, &val);
1375 }
1376 }
1377 break;
1378 case XSD_CONTENT_ALL:
1379 case XSD_CONTENT_SEQUENCE:
1380 case XSD_CONTENT_CHOICE: {
1381 sdlContentModelPtr tmp;
1382 sdlContentModelPtr any = NULL;
1383
1384 ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1385 if (tmp->kind == XSD_CONTENT_ANY) {
1386 any = tmp;
1387 } else {
1388 model_to_zval_object(ret, tmp, data, sdl);
1389 }
1390 } ZEND_HASH_FOREACH_END();
1391 if (any) {
1392 model_to_zval_any(ret, data->children);
1393 }
1394 break;
1395 }
1396 case XSD_CONTENT_GROUP:
1397 model_to_zval_object(ret, model->u.group->model, data, sdl);
1398 break;
1399 default:
1400 break;
1401 }
1402 }
1403
1404 /* Struct encode/decode */
to_zval_object_ex(zval * ret,encodeTypePtr type,xmlNodePtr data,zend_class_entry * pce)1405 static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, zend_class_entry *pce)
1406 {
1407 xmlNodePtr trav;
1408 sdlPtr sdl;
1409 sdlTypePtr sdlType = type->sdl_type;
1410 zend_class_entry *ce = ZEND_STANDARD_CLASS_DEF_PTR;
1411 zval *redo_any = NULL, rv, arr;
1412
1413 if (pce) {
1414 ce = pce;
1415 } else if (SOAP_GLOBAL(class_map) && type->type_str) {
1416 zval *classname;
1417 zend_class_entry *tmp;
1418
1419 if ((classname = zend_hash_str_find_deref(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str))) != NULL &&
1420 Z_TYPE_P(classname) == IS_STRING &&
1421 (tmp = zend_fetch_class(Z_STR_P(classname), ZEND_FETCH_CLASS_AUTO)) != NULL) {
1422 ce = tmp;
1423 }
1424 }
1425 sdl = SOAP_GLOBAL(sdl);
1426 if (sdlType) {
1427 if (sdlType->kind == XSD_TYPEKIND_RESTRICTION &&
1428 sdlType->encode && type != &sdlType->encode->details) {
1429 encodePtr enc;
1430
1431 enc = sdlType->encode;
1432 while (enc && enc->details.sdl_type &&
1433 enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
1434 enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
1435 enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
1436 enc = enc->details.sdl_type->encode;
1437 }
1438 if (enc) {
1439 zval base;
1440
1441 ZVAL_NULL(ret);
1442 if (soap_check_xml_ref(ret, data)) {
1443 return ret;
1444 }
1445
1446 object_init_ex(ret, ce);
1447 master_to_zval_int(&base, enc, data);
1448 set_zval_property(ret, "_", &base);
1449 } else {
1450 ZVAL_NULL(ret);
1451 FIND_XML_NULL(data, ret);
1452 if (soap_check_xml_ref(ret, data)) {
1453 return ret;
1454 }
1455 object_init_ex(ret, ce);
1456 soap_add_xml_ref(ret, data);
1457 }
1458 } else if (sdlType->kind == XSD_TYPEKIND_EXTENSION &&
1459 sdlType->encode &&
1460 type != &sdlType->encode->details) {
1461 if (sdlType->encode->details.sdl_type &&
1462 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
1463 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
1464 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
1465
1466 CHECK_XML_NULL(data);
1467 if (soap_check_xml_ref(ret, data)) {
1468 return ret;
1469 }
1470
1471 if (ce != ZEND_STANDARD_CLASS_DEF_PTR &&
1472 sdlType->encode->to_zval == sdl_guess_convert_zval &&
1473 sdlType->encode->details.sdl_type != NULL &&
1474 (sdlType->encode->details.sdl_type->kind == XSD_TYPEKIND_COMPLEX ||
1475 sdlType->encode->details.sdl_type->kind == XSD_TYPEKIND_RESTRICTION ||
1476 sdlType->encode->details.sdl_type->kind == XSD_TYPEKIND_EXTENSION) &&
1477 (sdlType->encode->details.sdl_type->encode == NULL ||
1478 (sdlType->encode->details.sdl_type->encode->details.type != IS_ARRAY &&
1479 sdlType->encode->details.sdl_type->encode->details.type != SOAP_ENC_ARRAY))) {
1480 to_zval_object_ex(ret, &sdlType->encode->details, data, ce);
1481 } else {
1482 master_to_zval_int(ret, sdlType->encode, data);
1483 }
1484
1485 soap_add_xml_ref(ret, data);
1486
1487 redo_any = get_zval_property(ret, "any", &rv);
1488 if (Z_TYPE_P(ret) == IS_OBJECT && ce != ZEND_STANDARD_CLASS_DEF_PTR) {
1489 zend_object *zobj = Z_OBJ_P(ret);
1490 zobj->ce = ce;
1491 }
1492 } else {
1493 zval base;
1494
1495 ZVAL_NULL(ret);
1496 if (soap_check_xml_ref(ret, data)) {
1497 return ret;
1498 }
1499
1500 object_init_ex(ret, ce);
1501 soap_add_xml_ref(ret, data);
1502 master_to_zval_int(&base, sdlType->encode, data);
1503 set_zval_property(ret, "_", &base);
1504 }
1505 } else {
1506 ZVAL_NULL(ret);
1507 FIND_XML_NULL(data, ret);
1508 if (soap_check_xml_ref(ret, data)) {
1509 return ret;
1510 }
1511 object_init_ex(ret, ce);
1512 soap_add_xml_ref(ret, data);
1513 }
1514 if (sdlType->model) {
1515 model_to_zval_object(ret, sdlType->model, data, sdl);
1516 if (redo_any) {
1517 if (!get_zval_property(ret, "any", &rv)) {
1518 model_to_zval_any(ret, data->children);
1519 soap_add_xml_ref(ret, data);
1520 } else {
1521 unset_zval_property(ret, "any");
1522 }
1523 }
1524 }
1525 if (sdlType->attributes) {
1526 sdlAttributePtr attr;
1527
1528 ZEND_HASH_FOREACH_PTR(sdlType->attributes, attr) {
1529 if (attr->name) {
1530 xmlAttrPtr val = get_attribute(data->properties, attr->name);
1531 char *str_val = NULL;
1532
1533 if (val && val->children && val->children->content) {
1534 str_val = (char*)val->children->content;
1535 if (attr->fixed && strcmp(attr->fixed, str_val) != 0) {
1536 soap_error3(E_ERROR, "Encoding: Attribute '%s' has fixed value '%s' (value '%s' is not allowed)", attr->name, attr->fixed, str_val);
1537 }
1538 } else if (attr->fixed) {
1539 str_val = attr->fixed;
1540 } else if (attr->def) {
1541 str_val = attr->def;
1542 }
1543 if (str_val) {
1544 xmlNodePtr dummy, text;
1545 zval data;
1546
1547 dummy = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1548 text = xmlNewText(BAD_CAST(str_val));
1549 xmlAddChild(dummy, text);
1550 ZVAL_NULL(&data);
1551 master_to_zval(&data, attr->encode, dummy);
1552 xmlFreeNode(dummy);
1553 set_zval_property(ret, attr->name, &data);
1554 }
1555 }
1556 } ZEND_HASH_FOREACH_END();
1557 }
1558 } else {
1559 ZVAL_NULL(ret);
1560 FIND_XML_NULL(data, ret);
1561 if (soap_check_xml_ref(ret, data)) {
1562 return ret;
1563 }
1564
1565 object_init_ex(ret, ce);
1566 soap_add_xml_ref(ret, data);
1567 trav = data->children;
1568
1569 while (trav != NULL) {
1570 if (trav->type == XML_ELEMENT_NODE) {
1571 zval tmpVal, rv;
1572 zval *prop;
1573
1574 ZVAL_NULL(&tmpVal);
1575 master_to_zval(&tmpVal, NULL, trav);
1576
1577 prop = get_zval_property(ret, (char*)trav->name, &rv);
1578 if (!prop) {
1579 if (!trav->next || !get_node(trav->next, (char*)trav->name)) {
1580 set_zval_property(ret, (char*)trav->name, &tmpVal);
1581 } else {
1582 zval arr;
1583
1584 array_init(&arr);
1585 add_next_index_zval(&arr, &tmpVal);
1586 set_zval_property(ret, (char*)trav->name, &arr);
1587 }
1588 } else {
1589 /* Property already exist - make array */
1590 if (Z_TYPE_P(prop) != IS_ARRAY) {
1591 /* Convert into array */
1592 array_init(&arr);
1593 Z_ADDREF_P(prop);
1594 add_next_index_zval(&arr, prop);
1595 set_zval_property(ret, (char*)trav->name, &arr);
1596 prop = &arr;
1597 }
1598 /* Add array element */
1599 add_next_index_zval(prop, &tmpVal);
1600 }
1601 }
1602 trav = trav->next;
1603 }
1604 }
1605 return ret;
1606 }
1607
to_zval_object(zval * ret,encodeTypePtr type,xmlNodePtr data)1608 static zval *to_zval_object(zval *ret, encodeTypePtr type, xmlNodePtr data)
1609 {
1610 return to_zval_object_ex(ret, type, data, NULL);
1611 }
1612
1613
model_to_xml_object(xmlNodePtr node,sdlContentModelPtr model,zval * object,int style,int strict)1614 static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, zval *object, int style, int strict)
1615 {
1616 switch (model->kind) {
1617 case XSD_CONTENT_ELEMENT: {
1618 zval *data;
1619 xmlNodePtr property;
1620 encodePtr enc;
1621 zval rv;
1622
1623 data = get_zval_property(object, model->u.element->name, &rv);
1624 if (data &&
1625 Z_TYPE_P(data) == IS_NULL &&
1626 !model->u.element->nillable &&
1627 model->min_occurs > 0 &&
1628 !strict) {
1629 return 0;
1630 }
1631 if (data) {
1632 enc = model->u.element->encode;
1633 if ((model->max_occurs == -1 || model->max_occurs > 1) &&
1634 Z_TYPE_P(data) == IS_ARRAY &&
1635 !is_map(data)) {
1636 HashTable *ht = Z_ARRVAL_P(data);
1637 zval *val;
1638
1639 ZEND_HASH_FOREACH_VAL(ht, val) {
1640 ZVAL_DEREF(val);
1641 if (Z_TYPE_P(val) == IS_NULL && model->u.element->nillable) {
1642 property = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1643 xmlAddChild(node, property);
1644 set_xsi_nil(property);
1645 } else {
1646 property = master_to_xml(enc, val, style, node);
1647 if (property->children && property->children->content &&
1648 model->u.element->fixed && strcmp(model->u.element->fixed, (char*)property->children->content) != 0) {
1649 soap_error3(E_ERROR, "Encoding: Element '%s' has fixed value '%s' (value '%s' is not allowed)", model->u.element->name, model->u.element->fixed, property->children->content);
1650 }
1651 }
1652 xmlNodeSetName(property, BAD_CAST(model->u.element->name));
1653 if (style == SOAP_LITERAL &&
1654 model->u.element->namens &&
1655 model->u.element->form == XSD_FORM_QUALIFIED) {
1656 xmlNsPtr nsp = encode_add_ns(property, model->u.element->namens);
1657 xmlSetNs(property, nsp);
1658 }
1659 } ZEND_HASH_FOREACH_END();
1660 } else {
1661 if (Z_TYPE_P(data) == IS_NULL && model->u.element->nillable) {
1662 property = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1663 xmlAddChild(node, property);
1664 set_xsi_nil(property);
1665 } else if (Z_TYPE_P(data) == IS_NULL && model->min_occurs == 0) {
1666 return 1;
1667 } else {
1668 property = master_to_xml(enc, data, style, node);
1669 if (property->children && property->children->content &&
1670 model->u.element->fixed && strcmp(model->u.element->fixed, (char*)property->children->content) != 0) {
1671 soap_error3(E_ERROR, "Encoding: Element '%s' has fixed value '%s' (value '%s' is not allowed)", model->u.element->name, model->u.element->fixed, property->children->content);
1672 }
1673 }
1674 xmlNodeSetName(property, BAD_CAST(model->u.element->name));
1675 if (style == SOAP_LITERAL &&
1676 model->u.element->namens &&
1677 model->u.element->form == XSD_FORM_QUALIFIED) {
1678 xmlNsPtr nsp = encode_add_ns(property, model->u.element->namens);
1679 xmlSetNs(property, nsp);
1680 }
1681 }
1682 return 1;
1683 } else if (strict && model->u.element->nillable && model->min_occurs > 0) {
1684 property = xmlNewNode(NULL, BAD_CAST(model->u.element->name));
1685 xmlAddChild(node, property);
1686 set_xsi_nil(property);
1687 if (style == SOAP_LITERAL &&
1688 model->u.element->namens &&
1689 model->u.element->form == XSD_FORM_QUALIFIED) {
1690 xmlNsPtr nsp = encode_add_ns(property, model->u.element->namens);
1691 xmlSetNs(property, nsp);
1692 }
1693 return 1;
1694 } else if (model->min_occurs == 0) {
1695 return 2;
1696 } else {
1697 if (strict) {
1698 soap_error1(E_ERROR, "Encoding: object has no '%s' property", model->u.element->name);
1699 }
1700 return 0;
1701 }
1702 break;
1703 }
1704 case XSD_CONTENT_ANY: {
1705 zval *data;
1706 encodePtr enc;
1707 zval rv;
1708
1709 data = get_zval_property(object, "any", &rv);
1710 if (data) {
1711 enc = get_conversion(XSD_ANYXML);
1712 if ((model->max_occurs == -1 || model->max_occurs > 1) &&
1713 Z_TYPE_P(data) == IS_ARRAY &&
1714 !is_map(data)) {
1715 HashTable *ht = Z_ARRVAL_P(data);
1716 zval *val;
1717
1718 ZEND_HASH_FOREACH_VAL(ht, val) {
1719 master_to_xml(enc, val, style, node);
1720 } ZEND_HASH_FOREACH_END();
1721 } else {
1722 master_to_xml(enc, data, style, node);
1723 }
1724 return 1;
1725 } else if (model->min_occurs == 0) {
1726 return 2;
1727 } else {
1728 if (strict) {
1729 soap_error0(E_ERROR, "Encoding: object has no 'any' property");
1730 }
1731 return 0;
1732 }
1733 break;
1734 }
1735 case XSD_CONTENT_SEQUENCE:
1736 case XSD_CONTENT_ALL: {
1737 sdlContentModelPtr tmp;
1738
1739 ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1740 if (!model_to_xml_object(node, tmp, object, style, strict && (tmp->min_occurs > 0))) {
1741 if (!strict || tmp->min_occurs > 0) {
1742 return 0;
1743 }
1744 }
1745 strict = 1;
1746 } ZEND_HASH_FOREACH_END();
1747 return 1;
1748 }
1749 case XSD_CONTENT_CHOICE: {
1750 sdlContentModelPtr tmp;
1751 int ret = 0;
1752
1753 ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1754 int tmp_ret = model_to_xml_object(node, tmp, object, style, 0);
1755 if (tmp_ret == 1) {
1756 return 1;
1757 } else if (tmp_ret != 0) {
1758 ret = 1;
1759 }
1760 } ZEND_HASH_FOREACH_END();
1761 return ret;
1762 }
1763 case XSD_CONTENT_GROUP: {
1764 return model_to_xml_object(node, model->u.group->model, object, style, strict && model->min_occurs > 0);
1765 }
1766 default:
1767 break;
1768 }
1769 return 1;
1770 }
1771
model_array_element(sdlContentModelPtr model)1772 static sdlTypePtr model_array_element(sdlContentModelPtr model)
1773 {
1774 switch (model->kind) {
1775 case XSD_CONTENT_ELEMENT: {
1776 if (model->max_occurs == -1 || model->max_occurs > 1) {
1777 return model->u.element;
1778 } else {
1779 return NULL;
1780 }
1781 }
1782 case XSD_CONTENT_SEQUENCE:
1783 case XSD_CONTENT_ALL:
1784 case XSD_CONTENT_CHOICE: {
1785 sdlContentModelPtr tmp;
1786
1787 if (zend_hash_num_elements(model->u.content) != 1) {
1788 return NULL;
1789 }
1790 ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1791 return model_array_element(tmp);
1792 } ZEND_HASH_FOREACH_END();
1793 }
1794 case XSD_CONTENT_GROUP: {
1795 return model_array_element(model->u.group->model);
1796 }
1797 default:
1798 break;
1799 }
1800 return NULL;
1801 }
1802
to_xml_object(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1803 static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1804 {
1805 xmlNodePtr xmlParam;
1806 HashTable *prop = NULL;
1807 sdlTypePtr sdlType = type->sdl_type;
1808
1809 if (!data || Z_TYPE_P(data) == IS_NULL) {
1810 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1811 xmlAddChild(parent, xmlParam);
1812 if (style == SOAP_ENCODED) {
1813 set_xsi_nil(xmlParam);
1814 set_ns_and_type(xmlParam, type);
1815 }
1816 return xmlParam;
1817 }
1818
1819 if (Z_TYPE_P(data) == IS_OBJECT) {
1820 prop = Z_OBJPROP_P(data);
1821 } else if (Z_TYPE_P(data) == IS_ARRAY) {
1822 prop = Z_ARRVAL_P(data);
1823 }
1824
1825 if (sdlType) {
1826 if (sdlType->kind == XSD_TYPEKIND_RESTRICTION &&
1827 sdlType->encode && type != &sdlType->encode->details) {
1828 encodePtr enc;
1829
1830 enc = sdlType->encode;
1831 while (enc && enc->details.sdl_type &&
1832 enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
1833 enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
1834 enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
1835 enc = enc->details.sdl_type->encode;
1836 }
1837 if (enc) {
1838 zval rv;
1839 zval *tmp = get_zval_property(data, "_", &rv);
1840 if (tmp) {
1841 xmlParam = master_to_xml(enc, tmp, style, parent);
1842 } else if (prop == NULL) {
1843 xmlParam = master_to_xml(enc, data, style, parent);
1844 } else {
1845 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1846 xmlAddChild(parent, xmlParam);
1847 }
1848 } else {
1849 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1850 xmlAddChild(parent, xmlParam);
1851 }
1852 } else if (sdlType->kind == XSD_TYPEKIND_EXTENSION &&
1853 sdlType->encode && type != &sdlType->encode->details) {
1854 if (sdlType->encode->details.sdl_type &&
1855 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
1856 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
1857 sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
1858
1859 if (prop) { GC_TRY_PROTECT_RECURSION(prop); }
1860 xmlParam = master_to_xml(sdlType->encode, data, style, parent);
1861 if (prop) { GC_TRY_UNPROTECT_RECURSION(prop); }
1862 } else {
1863 zval rv;
1864 zval *tmp = get_zval_property(data, "_", &rv);
1865
1866 if (tmp) {
1867 xmlParam = master_to_xml(sdlType->encode, tmp, style, parent);
1868 } else if (prop == NULL) {
1869 xmlParam = master_to_xml(sdlType->encode, data, style, parent);
1870 } else {
1871 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1872 xmlAddChild(parent, xmlParam);
1873 }
1874 }
1875 } else {
1876 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1877 xmlAddChild(parent, xmlParam);
1878 }
1879
1880 if (soap_check_zval_ref(data, xmlParam)) {
1881 return xmlParam;
1882 }
1883 if (prop != NULL) {
1884 sdlTypePtr array_el;
1885
1886 if (Z_TYPE_P(data) == IS_ARRAY &&
1887 !is_map(data) &&
1888 sdlType->attributes == NULL &&
1889 sdlType->model != NULL &&
1890 (array_el = model_array_element(sdlType->model)) != NULL) {
1891 zval *val;
1892
1893 ZEND_HASH_FOREACH_VAL(prop, val) {
1894 xmlNodePtr property;
1895 ZVAL_DEREF(val);
1896 if (Z_TYPE_P(val) == IS_NULL && array_el->nillable) {
1897 property = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1898 xmlAddChild(xmlParam, property);
1899 set_xsi_nil(property);
1900 } else {
1901 property = master_to_xml(array_el->encode, val, style, xmlParam);
1902 }
1903 xmlNodeSetName(property, BAD_CAST(array_el->name));
1904 if (style == SOAP_LITERAL &&
1905 array_el->namens &&
1906 array_el->form == XSD_FORM_QUALIFIED) {
1907 xmlNsPtr nsp = encode_add_ns(property, array_el->namens);
1908 xmlSetNs(property, nsp);
1909 }
1910 } ZEND_HASH_FOREACH_END();
1911 } else if (sdlType->model) {
1912 model_to_xml_object(xmlParam, sdlType->model, data, style, 1);
1913 }
1914 if (sdlType->attributes) {
1915 sdlAttributePtr attr;
1916 zval *zattr, rv;
1917
1918 ZEND_HASH_FOREACH_PTR(sdlType->attributes, attr) {
1919 if (attr->name) {
1920 zattr = get_zval_property(data, attr->name, &rv);
1921 if (zattr) {
1922 xmlNodePtr dummy;
1923
1924 dummy = master_to_xml(attr->encode, zattr, SOAP_LITERAL, xmlParam);
1925 if (dummy->children && dummy->children->content) {
1926 if (attr->fixed && strcmp(attr->fixed, (char*)dummy->children->content) != 0) {
1927 soap_error3(E_ERROR, "Encoding: Attribute '%s' has fixed value '%s' (value '%s' is not allowed)", attr->name, attr->fixed, dummy->children->content);
1928 }
1929 /* we need to handle xml: namespace specially, since it is
1930 an implicit schema. Otherwise, use form.
1931 */
1932 if (attr->namens &&
1933 (!strncmp(attr->namens, XML_NAMESPACE, sizeof(XML_NAMESPACE)) ||
1934 attr->form == XSD_FORM_QUALIFIED)) {
1935 xmlNsPtr nsp = encode_add_ns(xmlParam, attr->namens);
1936
1937 xmlSetNsProp(xmlParam, nsp, BAD_CAST(attr->name), dummy->children->content);
1938 } else {
1939 xmlSetProp(xmlParam, BAD_CAST(attr->name), dummy->children->content);
1940 }
1941 }
1942 xmlUnlinkNode(dummy);
1943 xmlFreeNode(dummy);
1944 }
1945 }
1946 } ZEND_HASH_FOREACH_END();
1947 }
1948 }
1949 if (style == SOAP_ENCODED) {
1950 set_ns_and_type(xmlParam, type);
1951 }
1952 } else {
1953 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
1954 xmlAddChild(parent, xmlParam);
1955
1956 if (soap_check_zval_ref(data, xmlParam)) {
1957 return xmlParam;
1958 }
1959 if (prop != NULL) {
1960 zval *zprop;
1961 zend_string *str_key;
1962 xmlNodePtr property;
1963
1964 ZEND_HASH_FOREACH_STR_KEY_VAL_IND(prop, str_key, zprop) {
1965 ZVAL_DEREF(zprop);
1966 property = master_to_xml(get_conversion(Z_TYPE_P(zprop)), zprop, style, xmlParam);
1967
1968 if (str_key) {
1969 const char *prop_name;
1970
1971 if (Z_TYPE_P(data) == IS_OBJECT) {
1972 const char *class_name;
1973
1974 zend_unmangle_property_name(str_key, &class_name, &prop_name);
1975 } else {
1976 prop_name = ZSTR_VAL(str_key);
1977 }
1978 if (prop_name) {
1979 xmlNodeSetName(property, BAD_CAST(prop_name));
1980 }
1981 }
1982 } ZEND_HASH_FOREACH_END();
1983 }
1984 if (style == SOAP_ENCODED) {
1985 set_ns_and_type(xmlParam, type);
1986 }
1987 }
1988 return xmlParam;
1989 }
1990
1991 /* Array encode/decode */
guess_array_map(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)1992 static xmlNodePtr guess_array_map(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
1993 {
1994 encodePtr enc = NULL;
1995
1996 if (data && Z_TYPE_P(data) == IS_ARRAY) {
1997 if (is_map(data)) {
1998 enc = get_conversion(APACHE_MAP);
1999 } else {
2000 enc = get_conversion(SOAP_ENC_ARRAY);
2001 }
2002 }
2003 if (!enc) {
2004 enc = get_conversion(IS_NULL);
2005 }
2006
2007 return master_to_xml(enc, data, style, parent);
2008 }
2009
calc_dimension_12(const char * str)2010 static int calc_dimension_12(const char* str)
2011 {
2012 int i = 0, flag = 0;
2013 while (*str != '\0' && (*str < '0' || *str > '9') && (*str != '*')) {
2014 str++;
2015 }
2016 if (*str == '*') {
2017 i++;
2018 str++;
2019 }
2020 while (*str != '\0') {
2021 if (*str >= '0' && *str <= '9') {
2022 if (flag == 0) {
2023 i++;
2024 flag = 1;
2025 }
2026 } else if (*str == '*') {
2027 soap_error0(E_ERROR, "Encoding: '*' may only be first arraySize value in list");
2028 } else {
2029 flag = 0;
2030 }
2031 str++;
2032 }
2033 return i;
2034 }
2035
get_position_12(int dimension,const char * str)2036 static int* get_position_12(int dimension, const char* str)
2037 {
2038 int *pos;
2039 int i = -1, flag = 0;
2040
2041 pos = safe_emalloc(sizeof(int), dimension, 0);
2042 memset(pos,0,sizeof(int)*dimension);
2043 while (*str != '\0' && (*str < '0' || *str > '9') && (*str != '*')) {
2044 str++;
2045 }
2046 if (*str == '*') {
2047 str++;
2048 i++;
2049 }
2050 while (*str != '\0') {
2051 if (*str >= '0' && *str <= '9') {
2052 if (flag == 0) {
2053 i++;
2054 flag = 1;
2055 }
2056 pos[i] = (pos[i]*10)+(*str-'0');
2057 } else if (*str == '*') {
2058 soap_error0(E_ERROR, "Encoding: '*' may only be first arraySize value in list");
2059 } else {
2060 flag = 0;
2061 }
2062 str++;
2063 }
2064 return pos;
2065 }
2066
calc_dimension(const char * str)2067 static int calc_dimension(const char* str)
2068 {
2069 int i = 1;
2070 while (*str != ']' && *str != '\0') {
2071 if (*str == ',') {
2072 i++;
2073 }
2074 str++;
2075 }
2076 return i;
2077 }
2078
get_position_ex(int dimension,const char * str,int ** pos)2079 static void get_position_ex(int dimension, const char* str, int** pos)
2080 {
2081 int i = 0;
2082
2083 memset(*pos,0,sizeof(int)*dimension);
2084 while (*str != ']' && *str != '\0' && i < dimension) {
2085 if (*str >= '0' && *str <= '9') {
2086 (*pos)[i] = ((*pos)[i]*10)+(*str-'0');
2087 } else if (*str == ',') {
2088 i++;
2089 }
2090 str++;
2091 }
2092 }
2093
get_position(int dimension,const char * str)2094 static int* get_position(int dimension, const char* str)
2095 {
2096 int *pos;
2097
2098 pos = safe_emalloc(sizeof(int), dimension, 0);
2099 get_position_ex(dimension, str, &pos);
2100 return pos;
2101 }
2102
add_xml_array_elements(xmlNodePtr xmlParam,sdlTypePtr type,encodePtr enc,xmlNsPtr ns,int dimension,int * dims,zval * data,int style)2103 static void add_xml_array_elements(xmlNodePtr xmlParam,
2104 sdlTypePtr type,
2105 encodePtr enc,
2106 xmlNsPtr ns,
2107 int dimension ,
2108 int* dims,
2109 zval* data,
2110 int style
2111 )
2112 {
2113 int j = 0;
2114 zval *zdata;
2115 xmlNodePtr xparam;
2116
2117 if (data && Z_TYPE_P(data) == IS_ARRAY) {
2118 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(data), zdata) {
2119 if (j >= dims[0]) {
2120 break;
2121 }
2122 ZVAL_DEREF(zdata);
2123 if (dimension == 1) {
2124 if (enc == NULL) {
2125 xparam = master_to_xml(get_conversion(Z_TYPE_P(zdata)), zdata, style, xmlParam);
2126 } else {
2127 xparam = master_to_xml(enc, zdata, style, xmlParam);
2128 }
2129
2130 if (type) {
2131 xmlNodeSetName(xparam, BAD_CAST(type->name));
2132 } else if (style == SOAP_LITERAL && enc && enc->details.type_str) {
2133 xmlNodeSetName(xparam, BAD_CAST(enc->details.type_str));
2134 xmlSetNs(xparam, ns);
2135 } else {
2136 xmlNodeSetName(xparam, BAD_CAST("item"));
2137 }
2138 } else {
2139 add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1, zdata, style);
2140 }
2141 j++;
2142 } ZEND_HASH_FOREACH_END();
2143
2144 if (dimension == 1) {
2145 while (j < dims[0]) {
2146 xparam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2147 xmlAddChild(xmlParam, xparam);
2148
2149 if (type) {
2150 xmlNodeSetName(xparam, BAD_CAST(type->name));
2151 } else if (style == SOAP_LITERAL && enc && enc->details.type_str) {
2152 xmlNodeSetName(xparam, BAD_CAST(enc->details.type_str));
2153 xmlSetNs(xparam, ns);
2154 } else {
2155 xmlNodeSetName(xparam, BAD_CAST("item"));
2156 }
2157
2158 j++;
2159 }
2160 } else {
2161 while (j < dims[0]) {
2162 add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1, NULL, style);
2163 j++;
2164 }
2165 }
2166 } else {
2167 for (j=0; j<dims[0]; j++) {
2168 if (dimension == 1) {
2169 xmlNodePtr xparam;
2170
2171 xparam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2172 xmlAddChild(xmlParam, xparam);
2173 if (type) {
2174 xmlNodeSetName(xparam, BAD_CAST(type->name));
2175 } else if (style == SOAP_LITERAL && enc && enc->details.type_str) {
2176 xmlNodeSetName(xparam, BAD_CAST(enc->details.type_str));
2177 xmlSetNs(xparam, ns);
2178 } else {
2179 xmlNodeSetName(xparam, BAD_CAST("item"));
2180 }
2181 } else {
2182 add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1, NULL, style);
2183 }
2184 }
2185 }
2186 }
2187
array_num_elements(HashTable * ht)2188 static inline int array_num_elements(HashTable* ht)
2189 {
2190 if (ht->nNumUsed &&
2191 Z_TYPE(ht->arData[ht->nNumUsed-1].val) != IS_UNDEF &&
2192 ht->arData[ht->nNumUsed-1].key == NULL) {
2193 return ht->arData[ht->nNumUsed-1].h - 1;
2194 }
2195 return 0;
2196 }
2197
to_xml_array(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2198 static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2199 {
2200 sdlTypePtr sdl_type = type->sdl_type;
2201 sdlTypePtr element_type = NULL;
2202 smart_str array_type = {0}, array_size = {0};
2203 int i;
2204 xmlNodePtr xmlParam;
2205 encodePtr enc = NULL;
2206 int dimension = 1;
2207 int* dims;
2208 int soap_version;
2209 zval array_copy;
2210
2211 ZVAL_UNDEF(&array_copy);
2212 soap_version = SOAP_GLOBAL(soap_version);
2213
2214 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2215 xmlAddChild(parent, xmlParam);
2216
2217 if (!data || Z_TYPE_P(data) == IS_NULL) {
2218 if (style == SOAP_ENCODED) {
2219 set_xsi_nil(xmlParam);
2220 if (SOAP_GLOBAL(features) & SOAP_USE_XSI_ARRAY_TYPE) {
2221 set_ns_and_type_ex(xmlParam, (soap_version == SOAP_1_1) ? SOAP_1_1_ENC_NAMESPACE : SOAP_1_2_ENC_NAMESPACE, "Array");
2222 } else {
2223 set_ns_and_type(xmlParam, type);
2224 }
2225 }
2226 return xmlParam;
2227 }
2228
2229 if (Z_TYPE_P(data) == IS_OBJECT && instanceof_function(Z_OBJCE_P(data), zend_ce_traversable)) {
2230 zend_object_iterator *iter;
2231 zend_class_entry *ce = Z_OBJCE_P(data);
2232 zval *val;
2233
2234 array_init(&array_copy);
2235
2236 iter = ce->get_iterator(ce, data, 0);
2237
2238 if (EG(exception)) {
2239 goto iterator_done;
2240 }
2241
2242 if (iter->funcs->rewind) {
2243 iter->funcs->rewind(iter);
2244 if (EG(exception)) {
2245 goto iterator_done;
2246 }
2247 }
2248
2249 while (iter->funcs->valid(iter) == SUCCESS) {
2250 if (EG(exception)) {
2251 goto iterator_done;
2252 }
2253
2254 val = iter->funcs->get_current_data(iter);
2255 if (EG(exception)) {
2256 goto iterator_done;
2257 }
2258 if (iter->funcs->get_current_key) {
2259 zval key;
2260 iter->funcs->get_current_key(iter, &key);
2261 if (EG(exception)) {
2262 goto iterator_done;
2263 }
2264 array_set_zval_key(Z_ARRVAL(array_copy), &key, val);
2265 zval_ptr_dtor(val);
2266 zval_ptr_dtor(&key);
2267 } else {
2268 add_next_index_zval(&array_copy, val);
2269 }
2270 Z_TRY_ADDREF_P(val);
2271
2272 iter->funcs->move_forward(iter);
2273 if (EG(exception)) {
2274 goto iterator_done;
2275 }
2276 }
2277 iterator_done:
2278 OBJ_RELEASE(&iter->std);
2279 if (EG(exception)) {
2280 zval_ptr_dtor(&array_copy);
2281 ZVAL_UNDEF(&array_copy);
2282 } else {
2283 data = &array_copy;
2284 }
2285 }
2286
2287 if (Z_TYPE_P(data) == IS_ARRAY) {
2288 sdlAttributePtr arrayType;
2289 sdlExtraAttributePtr ext;
2290 sdlTypePtr elementType;
2291
2292 i = zend_hash_num_elements(Z_ARRVAL_P(data));
2293
2294 if (sdl_type &&
2295 sdl_type->attributes &&
2296 (arrayType = zend_hash_str_find_ptr(sdl_type->attributes, SOAP_1_1_ENC_NAMESPACE":arrayType",
2297 sizeof(SOAP_1_1_ENC_NAMESPACE":arrayType")-1)) != NULL &&
2298 arrayType->extraAttributes &&
2299 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
2300
2301 char *value, *end;
2302 zval *el;
2303
2304 value = estrdup(ext->val);
2305 end = strrchr(value,'[');
2306 if (end) {
2307 *end = '\0';
2308 end++;
2309 dimension = calc_dimension(end);
2310 }
2311 if (ext->ns != NULL) {
2312 enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns, value);
2313 get_type_str(xmlParam, ext->ns, value, &array_type);
2314 } else {
2315 smart_str_appends(&array_type, value);
2316 }
2317
2318 dims = safe_emalloc(sizeof(int), dimension, 0);
2319 dims[0] = i;
2320 el = data;
2321 for (i = 1; i < dimension; i++) {
2322 if (el != NULL && Z_TYPE_P(el) == IS_ARRAY &&
2323 zend_hash_num_elements(Z_ARRVAL_P(el)) > 0) {
2324 ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(el), el) {
2325 break;
2326 } ZEND_HASH_FOREACH_END();
2327 ZVAL_DEREF(el);
2328 if (Z_TYPE_P(el) == IS_ARRAY) {
2329 dims[i] = zend_hash_num_elements(Z_ARRVAL_P(el));
2330 } else {
2331 dims[i] = 0;
2332 }
2333 }
2334 }
2335
2336 smart_str_append_long(&array_size, dims[0]);
2337 for (i=1; i<dimension; i++) {
2338 smart_str_appendc(&array_size, ',');
2339 smart_str_append_long(&array_size, dims[i]);
2340 }
2341
2342 efree(value);
2343
2344 } else if (sdl_type &&
2345 sdl_type->attributes &&
2346 (arrayType = zend_hash_str_find_ptr(sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":itemType",
2347 sizeof(SOAP_1_2_ENC_NAMESPACE":itemType")-1)) != NULL &&
2348 arrayType->extraAttributes &&
2349 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":itemType")-1)) != NULL) {
2350 if (ext->ns != NULL) {
2351 enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns, ext->val);
2352 get_type_str(xmlParam, ext->ns, ext->val, &array_type);
2353 } else {
2354 smart_str_appends(&array_type, ext->val);
2355 }
2356 if ((arrayType = zend_hash_str_find_ptr(sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
2357 sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
2358 arrayType->extraAttributes &&
2359 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arraySize", sizeof(WSDL_NAMESPACE":arraysize")-1)) != NULL) {
2360 dimension = calc_dimension_12(ext->val);
2361 dims = get_position_12(dimension, ext->val);
2362 if (dims[0] == 0) {dims[0] = i;}
2363
2364 smart_str_append_long(&array_size, dims[0]);
2365 for (i=1; i<dimension; i++) {
2366 smart_str_appendc(&array_size, ',');
2367 smart_str_append_long(&array_size, dims[i]);
2368 }
2369 } else {
2370 dims = emalloc(sizeof(int));
2371 *dims = 0;
2372 smart_str_append_long(&array_size, i);
2373 }
2374 } else if (sdl_type &&
2375 sdl_type->attributes &&
2376 (arrayType = zend_hash_str_find_ptr(sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
2377 sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
2378 arrayType->extraAttributes &&
2379 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arraySize", sizeof(WSDL_NAMESPACE":arraySize")-1)) != NULL) {
2380 dimension = calc_dimension_12(ext->val);
2381 dims = get_position_12(dimension, ext->val);
2382 if (dims[0] == 0) {dims[0] = i;}
2383
2384 smart_str_append_long(&array_size, dims[0]);
2385 for (i=1; i<dimension; i++) {
2386 smart_str_appendc(&array_size, ',');
2387 smart_str_append_long(&array_size, dims[i]);
2388 }
2389
2390 if (sdl_type && sdl_type->elements &&
2391 zend_hash_num_elements(sdl_type->elements) == 1 &&
2392 (zend_hash_internal_pointer_reset(sdl_type->elements),
2393 (elementType = zend_hash_get_current_data_ptr(sdl_type->elements)) != NULL) &&
2394 elementType->encode && elementType->encode->details.type_str) {
2395 element_type = elementType;
2396 enc = elementType->encode;
2397 get_type_str(xmlParam, elementType->encode->details.ns, elementType->encode->details.type_str, &array_type);
2398 } else {
2399 enc = get_array_type(xmlParam, data, &array_type);
2400 }
2401 } else if (sdl_type && sdl_type->elements &&
2402 zend_hash_num_elements(sdl_type->elements) == 1 &&
2403 (zend_hash_internal_pointer_reset(sdl_type->elements),
2404 (elementType = zend_hash_get_current_data_ptr(sdl_type->elements)) != NULL) &&
2405 elementType->encode && elementType->encode->details.type_str) {
2406
2407 element_type = elementType;
2408 enc = elementType->encode;
2409 get_type_str(xmlParam, elementType->encode->details.ns, elementType->encode->details.type_str, &array_type);
2410
2411 smart_str_append_long(&array_size, i);
2412
2413 dims = safe_emalloc(sizeof(int), dimension, 0);
2414 dims[0] = i;
2415 } else {
2416
2417 enc = get_array_type(xmlParam, data, &array_type);
2418 smart_str_append_long(&array_size, i);
2419 dims = safe_emalloc(sizeof(int), dimension, 0);
2420 dims[0] = i;
2421 }
2422
2423 if (style == SOAP_ENCODED) {
2424 if (soap_version == SOAP_1_1) {
2425 smart_str_0(&array_type);
2426 if (strcmp(ZSTR_VAL(array_type.s),"xsd:anyType") == 0) {
2427 smart_str_free(&array_type);
2428 smart_str_appendl(&array_type,"xsd:ur-type",sizeof("xsd:ur-type")-1);
2429 }
2430 smart_str_appendc(&array_type, '[');
2431 smart_str_append_smart_str(&array_type, &array_size);
2432 smart_str_appendc(&array_type, ']');
2433 smart_str_0(&array_type);
2434 set_ns_prop(xmlParam, SOAP_1_1_ENC_NAMESPACE, "arrayType", ZSTR_VAL(array_type.s));
2435 } else {
2436 size_t i = 0;
2437 while (i < ZSTR_LEN(array_size.s)) {
2438 if (ZSTR_VAL(array_size.s)[i] == ',') {ZSTR_VAL(array_size.s)[i] = ' ';}
2439 ++i;
2440 }
2441 smart_str_0(&array_type);
2442 smart_str_0(&array_size);
2443 set_ns_prop(xmlParam, SOAP_1_2_ENC_NAMESPACE, "itemType", ZSTR_VAL(array_type.s));
2444 set_ns_prop(xmlParam, SOAP_1_2_ENC_NAMESPACE, "arraySize", ZSTR_VAL(array_size.s));
2445 }
2446 }
2447 smart_str_free(&array_type);
2448 smart_str_free(&array_size);
2449
2450 add_xml_array_elements(xmlParam, element_type, enc, enc?encode_add_ns(xmlParam,enc->details.ns):NULL, dimension, dims, data, style);
2451 efree(dims);
2452 }
2453 if (style == SOAP_ENCODED) {
2454 if (SOAP_GLOBAL(features) & SOAP_USE_XSI_ARRAY_TYPE) {
2455 set_ns_and_type_ex(xmlParam, (soap_version == SOAP_1_1) ? SOAP_1_1_ENC_NAMESPACE : SOAP_1_2_ENC_NAMESPACE, "Array");
2456 } else {
2457 set_ns_and_type(xmlParam, type);
2458 }
2459 }
2460
2461 zval_ptr_dtor(&array_copy);
2462
2463 return xmlParam;
2464 }
2465
to_zval_array(zval * ret,encodeTypePtr type,xmlNodePtr data)2466 static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data)
2467 {
2468 xmlNodePtr trav;
2469 encodePtr enc = NULL;
2470 int dimension = 1;
2471 int* dims = NULL;
2472 int* pos = NULL;
2473 xmlAttrPtr attr;
2474 sdlAttributePtr arrayType;
2475 sdlExtraAttributePtr ext;
2476 sdlTypePtr elementType;
2477
2478 ZVAL_NULL(ret);
2479 FIND_XML_NULL(data, ret);
2480
2481 if (data &&
2482 (attr = get_attribute(data->properties,"arrayType")) &&
2483 attr->children && attr->children->content) {
2484 char *type, *end, *ns;
2485 xmlNsPtr nsptr;
2486
2487 parse_namespace(attr->children->content, &type, &ns);
2488 nsptr = xmlSearchNs(attr->doc, attr->parent, BAD_CAST(ns));
2489
2490 end = strrchr(type,'[');
2491 if (end) {
2492 *end = '\0';
2493 dimension = calc_dimension(end+1);
2494 dims = get_position(dimension, end+1);
2495 }
2496 if (nsptr != NULL) {
2497 enc = get_encoder(SOAP_GLOBAL(sdl), (char*)nsptr->href, type);
2498 }
2499 efree(type);
2500 if (ns) {efree(ns);}
2501
2502 } else if ((attr = get_attribute(data->properties,"itemType")) &&
2503 attr->children &&
2504 attr->children->content) {
2505 char *type, *ns;
2506 xmlNsPtr nsptr;
2507
2508 parse_namespace(attr->children->content, &type, &ns);
2509 nsptr = xmlSearchNs(attr->doc, attr->parent, BAD_CAST(ns));
2510 if (nsptr != NULL) {
2511 enc = get_encoder(SOAP_GLOBAL(sdl), (char*)nsptr->href, type);
2512 }
2513 efree(type);
2514 if (ns) {efree(ns);}
2515
2516 if ((attr = get_attribute(data->properties,"arraySize")) &&
2517 attr->children && attr->children->content) {
2518 dimension = calc_dimension_12((char*)attr->children->content);
2519 dims = get_position_12(dimension, (char*)attr->children->content);
2520 } else {
2521 dims = emalloc(sizeof(int));
2522 *dims = 0;
2523 }
2524
2525 } else if ((attr = get_attribute(data->properties,"arraySize")) &&
2526 attr->children && attr->children->content) {
2527
2528 dimension = calc_dimension_12((char*)attr->children->content);
2529 dims = get_position_12(dimension, (char*)attr->children->content);
2530
2531 } else if (type->sdl_type != NULL &&
2532 type->sdl_type->attributes != NULL &&
2533 (arrayType = zend_hash_str_find_ptr(type->sdl_type->attributes, SOAP_1_1_ENC_NAMESPACE":arrayType",
2534 sizeof(SOAP_1_1_ENC_NAMESPACE":arrayType")-1)) != NULL &&
2535 arrayType->extraAttributes &&
2536 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
2537 char *type, *end;
2538
2539 type = estrdup(ext->val);
2540 end = strrchr(type,'[');
2541 if (end) {
2542 *end = '\0';
2543 }
2544 if (ext->ns != NULL) {
2545 enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns, type);
2546 }
2547 efree(type);
2548
2549 dims = emalloc(sizeof(int));
2550 *dims = 0;
2551
2552 } else if (type->sdl_type != NULL &&
2553 type->sdl_type->attributes != NULL &&
2554 (arrayType = zend_hash_str_find_ptr(type->sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":itemType",
2555 sizeof(SOAP_1_2_ENC_NAMESPACE":itemType")-1)) != NULL &&
2556 arrayType->extraAttributes &&
2557 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":itemType")-1)) != NULL) {
2558
2559 if (ext->ns != NULL) {
2560 enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns, ext->val);
2561 }
2562
2563 if ((arrayType = zend_hash_str_find_ptr(type->sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
2564 sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
2565 arrayType->extraAttributes &&
2566 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arraySize", sizeof(WSDL_NAMESPACE":arraysize")-1)) != NULL) {
2567 dimension = calc_dimension_12(ext->val);
2568 dims = get_position_12(dimension, ext->val);
2569 } else {
2570 dims = emalloc(sizeof(int));
2571 *dims = 0;
2572 }
2573 } else if (type->sdl_type != NULL &&
2574 type->sdl_type->attributes != NULL &&
2575 (arrayType = zend_hash_str_find_ptr(type->sdl_type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
2576 sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
2577 arrayType->extraAttributes &&
2578 (ext = zend_hash_str_find_ptr(arrayType->extraAttributes, WSDL_NAMESPACE":arraySize", sizeof(WSDL_NAMESPACE":arraysize")-1)) != NULL) {
2579
2580 dimension = calc_dimension_12(ext->val);
2581 dims = get_position_12(dimension, ext->val);
2582 if (type->sdl_type && type->sdl_type->elements &&
2583 zend_hash_num_elements(type->sdl_type->elements) == 1 &&
2584 (zend_hash_internal_pointer_reset(type->sdl_type->elements),
2585 (elementType = zend_hash_get_current_data_ptr(type->sdl_type->elements)) != NULL) &&
2586 elementType->encode) {
2587 enc = elementType->encode;
2588 }
2589 } else if (type->sdl_type && type->sdl_type->elements &&
2590 zend_hash_num_elements(type->sdl_type->elements) == 1 &&
2591 (zend_hash_internal_pointer_reset(type->sdl_type->elements),
2592 (elementType = zend_hash_get_current_data_ptr(type->sdl_type->elements)) != NULL) &&
2593 elementType->encode) {
2594 enc = elementType->encode;
2595 }
2596 if (dims == NULL) {
2597 dimension = 1;
2598 dims = emalloc(sizeof(int));
2599 *dims = 0;
2600 }
2601 pos = safe_emalloc(sizeof(int), dimension, 0);
2602 memset(pos,0,sizeof(int)*dimension);
2603 if (data &&
2604 (attr = get_attribute(data->properties,"offset")) &&
2605 attr->children && attr->children->content) {
2606 char* tmp = strrchr((char*)attr->children->content,'[');
2607
2608 if (tmp == NULL) {
2609 tmp = (char*)attr->children->content;
2610 }
2611 get_position_ex(dimension, tmp, &pos);
2612 }
2613
2614 array_init(ret);
2615 trav = data->children;
2616 while (trav) {
2617 if (trav->type == XML_ELEMENT_NODE) {
2618 int i;
2619 zval tmpVal, *ar;
2620 xmlAttrPtr position = get_attribute(trav->properties,"position");
2621
2622 ZVAL_NULL(&tmpVal);
2623 master_to_zval(&tmpVal, enc, trav);
2624 if (position != NULL && position->children && position->children->content) {
2625 char* tmp = strrchr((char*)position->children->content, '[');
2626 if (tmp == NULL) {
2627 tmp = (char*)position->children->content;
2628 }
2629 get_position_ex(dimension, tmp, &pos);
2630 }
2631
2632 /* Get/Create intermediate arrays for multidimensional arrays */
2633 i = 0;
2634 ar = ret;
2635 while (i < dimension-1) {
2636 zval* ar2;
2637 if ((ar2 = zend_hash_index_find(Z_ARRVAL_P(ar), pos[i])) != NULL) {
2638 ar = ar2;
2639 } else {
2640 zval tmpAr;
2641 array_init(&tmpAr);
2642 ar = zend_hash_index_update(Z_ARRVAL_P(ar), pos[i], &tmpAr);
2643 }
2644 i++;
2645 }
2646 zend_hash_index_update(Z_ARRVAL_P(ar), pos[i], &tmpVal);
2647
2648 /* Increment position */
2649 i = dimension;
2650 while (i > 0) {
2651 i--;
2652 pos[i]++;
2653 if (pos[i] >= dims[i]) {
2654 if (i > 0) {
2655 pos[i] = 0;
2656 } else {
2657 /* TODO: Array index overflow */
2658 }
2659 } else {
2660 break;
2661 }
2662 }
2663 }
2664 trav = trav->next;
2665 }
2666 efree(dims);
2667 efree(pos);
2668 return ret;
2669 }
2670
2671 /* Map encode/decode */
to_xml_map(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2672 static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2673 {
2674 zval *temp_data;
2675 zend_string *key_val;
2676 zend_ulong int_val;
2677 xmlNodePtr xmlParam;
2678 xmlNodePtr xparam, item;
2679 xmlNodePtr key;
2680
2681 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2682 xmlAddChild(parent, xmlParam);
2683 FIND_ZVAL_NULL(data, xmlParam, style);
2684
2685 if (Z_TYPE_P(data) == IS_ARRAY) {
2686 ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(data), int_val, key_val, temp_data) {
2687 item = xmlNewNode(NULL, BAD_CAST("item"));
2688 xmlAddChild(xmlParam, item);
2689 key = xmlNewNode(NULL, BAD_CAST("key"));
2690 xmlAddChild(item,key);
2691 if (key_val) {
2692 if (style == SOAP_ENCODED) {
2693 set_xsi_type(key, "xsd:string");
2694 }
2695 xmlNodeSetContent(key, BAD_CAST(ZSTR_VAL(key_val)));
2696 } else {
2697 smart_str tmp = {0};
2698 smart_str_append_long(&tmp, int_val);
2699 smart_str_0(&tmp);
2700
2701 if (style == SOAP_ENCODED) {
2702 set_xsi_type(key, "xsd:int");
2703 }
2704 xmlNodeSetContentLen(key, BAD_CAST(ZSTR_VAL(tmp.s)), ZSTR_LEN(tmp.s));
2705
2706 smart_str_free(&tmp);
2707 }
2708
2709 ZVAL_DEREF(temp_data);
2710 xparam = master_to_xml(get_conversion(Z_TYPE_P(temp_data)), temp_data, style, item);
2711 xmlNodeSetName(xparam, BAD_CAST("value"));
2712 } ZEND_HASH_FOREACH_END();
2713 }
2714 if (style == SOAP_ENCODED) {
2715 set_ns_and_type(xmlParam, type);
2716 }
2717
2718 return xmlParam;
2719 }
2720
to_zval_map(zval * ret,encodeTypePtr type,xmlNodePtr data)2721 static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data)
2722 {
2723 zval key, value;
2724 xmlNodePtr trav, item, xmlKey, xmlValue;
2725
2726 ZVAL_NULL(ret);
2727 FIND_XML_NULL(data, ret);
2728
2729 if (data && data->children) {
2730 array_init(ret);
2731 trav = data->children;
2732
2733 trav = data->children;
2734 FOREACHNODE(trav, "item", item) {
2735 xmlKey = get_node(item->children, "key");
2736 if (!xmlKey) {
2737 soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing key");
2738 }
2739
2740 xmlValue = get_node(item->children, "value");
2741 if (!xmlKey) {
2742 soap_error0(E_ERROR, "Encoding: Can't decode apache map, missing value");
2743 }
2744
2745 ZVAL_NULL(&key);
2746 master_to_zval(&key, NULL, xmlKey);
2747 ZVAL_NULL(&value);
2748 master_to_zval(&value, NULL, xmlValue);
2749
2750 if (Z_TYPE(key) == IS_STRING) {
2751 zend_symtable_update(Z_ARRVAL_P(ret), Z_STR(key), &value);
2752 } else if (Z_TYPE(key) == IS_LONG) {
2753 zend_hash_index_update(Z_ARRVAL_P(ret), Z_LVAL(key), &value);
2754 } else {
2755 soap_error0(E_ERROR, "Encoding: Can't decode apache map, only Strings or Longs are allowd as keys");
2756 }
2757 zval_ptr_dtor(&key);
2758 }
2759 ENDFOREACH(trav);
2760 } else {
2761 ZVAL_NULL(ret);
2762 }
2763 return ret;
2764 }
2765
2766 /* Unknown encode/decode */
guess_xml_convert(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2767 static xmlNodePtr guess_xml_convert(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2768 {
2769 encodePtr enc;
2770 xmlNodePtr ret;
2771
2772 if (data) {
2773 enc = get_conversion(Z_TYPE_P(data));
2774 } else {
2775 enc = get_conversion(IS_NULL);
2776 }
2777 ret = master_to_xml_int(enc, data, style, parent, 0);
2778 /*
2779 if (style == SOAP_LITERAL && SOAP_GLOBAL(sdl)) {
2780 set_ns_and_type(ret, &enc->details);
2781 }
2782 */
2783 return ret;
2784 }
2785
guess_zval_convert(zval * ret,encodeTypePtr type,xmlNodePtr data)2786 static zval *guess_zval_convert(zval *ret, encodeTypePtr type, xmlNodePtr data)
2787 {
2788 encodePtr enc = NULL;
2789 xmlAttrPtr tmpattr;
2790 xmlChar *type_name = NULL;
2791
2792 data = check_and_resolve_href(data);
2793
2794 if (data == NULL) {
2795 enc = get_conversion(IS_NULL);
2796 } else if (data->properties && get_attribute_ex(data->properties, "nil", XSI_NAMESPACE)) {
2797 enc = get_conversion(IS_NULL);
2798 } else {
2799 tmpattr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
2800 if (tmpattr != NULL) {
2801 type_name = tmpattr->children->content;
2802 enc = get_encoder_from_prefix(SOAP_GLOBAL(sdl), data, tmpattr->children->content);
2803 if (enc && type == &enc->details) {
2804 enc = NULL;
2805 }
2806 if (enc != NULL) {
2807 encodePtr tmp = enc;
2808 while (tmp &&
2809 tmp->details.sdl_type != NULL &&
2810 tmp->details.sdl_type->kind != XSD_TYPEKIND_COMPLEX) {
2811 if (enc == tmp->details.sdl_type->encode ||
2812 tmp == tmp->details.sdl_type->encode) {
2813 enc = NULL;
2814 break;
2815 }
2816 tmp = tmp->details.sdl_type->encode;
2817 }
2818 }
2819 }
2820
2821 if (enc == NULL) {
2822 /* Didn't have a type, totally guess here */
2823 /* Logic: has children = IS_OBJECT else IS_STRING */
2824 xmlNodePtr trav;
2825
2826 if (get_attribute(data->properties, "arrayType") ||
2827 get_attribute(data->properties, "itemType") ||
2828 get_attribute(data->properties, "arraySize")) {
2829 enc = get_conversion(SOAP_ENC_ARRAY);
2830 } else {
2831 enc = get_conversion(XSD_STRING);
2832 trav = data->children;
2833 while (trav != NULL) {
2834 if (trav->type == XML_ELEMENT_NODE) {
2835 enc = get_conversion(SOAP_ENC_OBJECT);
2836 break;
2837 }
2838 trav = trav->next;
2839 }
2840 }
2841 }
2842 }
2843 master_to_zval_int(ret, enc, data);
2844 if (SOAP_GLOBAL(sdl) && type_name && enc->details.sdl_type) {
2845 zval soapvar;
2846 char *ns, *cptype;
2847 xmlNsPtr nsptr;
2848
2849 object_init_ex(&soapvar, soap_var_class_entry);
2850 add_property_long(&soapvar, "enc_type", enc->details.type);
2851 Z_TRY_DELREF_P(ret);
2852 add_property_zval(&soapvar, "enc_value", ret);
2853 parse_namespace(type_name, &cptype, &ns);
2854 nsptr = xmlSearchNs(data->doc, data, BAD_CAST(ns));
2855 add_property_string(&soapvar, "enc_stype", cptype);
2856 if (nsptr) {
2857 add_property_string(&soapvar, "enc_ns", (char*)nsptr->href);
2858 }
2859 efree(cptype);
2860 if (ns) {efree(ns);}
2861 ZVAL_COPY_VALUE(ret, &soapvar);
2862 }
2863 return ret;
2864 }
2865
2866 /* Time encode/decode */
to_xml_datetime_ex(encodeTypePtr type,zval * data,char * format,int style,xmlNodePtr parent)2867 static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, char *format, int style, xmlNodePtr parent)
2868 {
2869 /* logic hacked from ext/standard/datetime.c */
2870 struct tm *ta, tmbuf;
2871 time_t timestamp;
2872 int max_reallocs = 5;
2873 size_t buf_len=64, real_len;
2874 char *buf;
2875 char tzbuf[8];
2876
2877 xmlNodePtr xmlParam;
2878
2879 xmlParam = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2880 xmlAddChild(parent, xmlParam);
2881 FIND_ZVAL_NULL(data, xmlParam, style);
2882
2883 if (Z_TYPE_P(data) == IS_LONG) {
2884 timestamp = Z_LVAL_P(data);
2885 ta = php_localtime_r(×tamp, &tmbuf);
2886 /*ta = php_gmtime_r(×tamp, &tmbuf);*/
2887 if (!ta) {
2888 soap_error1(E_ERROR, "Encoding: Invalid timestamp " ZEND_LONG_FMT, Z_LVAL_P(data));
2889 }
2890
2891 buf = (char *) emalloc(buf_len);
2892 while ((real_len = strftime(buf, buf_len, format, ta)) == buf_len || real_len == 0) {
2893 buf_len *= 2;
2894 buf = (char *) erealloc(buf, buf_len);
2895 if (!--max_reallocs) break;
2896 }
2897
2898 /* Time zone support */
2899 #ifdef HAVE_TM_GMTOFF
2900 snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", (ta->tm_gmtoff < 0) ? '-' : '+', abs(ta->tm_gmtoff / 3600), abs( (ta->tm_gmtoff % 3600) / 60 ));
2901 #else
2902 # if defined(__CYGWIN__) || (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900)
2903 snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", ((ta->tm_isdst ? _timezone - 3600:_timezone)>0)?'-':'+', abs((ta->tm_isdst ? _timezone - 3600 : _timezone) / 3600), abs(((ta->tm_isdst ? _timezone - 3600 : _timezone) % 3600) / 60));
2904 # else
2905 snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", ((ta->tm_isdst ? timezone - 3600:timezone)>0)?'-':'+', abs((ta->tm_isdst ? timezone - 3600 : timezone) / 3600), abs(((ta->tm_isdst ? timezone - 3600 : timezone) % 3600) / 60));
2906 # endif
2907 #endif
2908 if (strcmp(tzbuf,"+00:00") == 0) {
2909 strcpy(tzbuf,"Z");
2910 real_len++;
2911 } else {
2912 real_len += 6;
2913 }
2914 if (real_len >= buf_len) {
2915 buf = (char *) erealloc(buf, real_len+1);
2916 }
2917 strcat(buf, tzbuf);
2918
2919 xmlNodeSetContent(xmlParam, BAD_CAST(buf));
2920 efree(buf);
2921 } else if (Z_TYPE_P(data) == IS_STRING) {
2922 xmlNodeSetContentLen(xmlParam, BAD_CAST(Z_STRVAL_P(data)), Z_STRLEN_P(data));
2923 }
2924
2925 if (style == SOAP_ENCODED) {
2926 set_ns_and_type(xmlParam, type);
2927 }
2928 return xmlParam;
2929 }
2930
to_xml_duration(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2931 static xmlNodePtr to_xml_duration(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2932 {
2933 /* TODO: '-'?P([0-9]+Y)?([0-9]+M)?([0-9]+D)?T([0-9]+H)?([0-9]+M)?([0-9]+S)? */
2934 return to_xml_string(type, data, style, parent);
2935 }
2936
to_xml_datetime(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2937 static xmlNodePtr to_xml_datetime(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2938 {
2939 return to_xml_datetime_ex(type, data, "%Y-%m-%dT%H:%M:%S", style, parent);
2940 }
2941
to_xml_time(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2942 static xmlNodePtr to_xml_time(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2943 {
2944 /* TODO: microsecconds */
2945 return to_xml_datetime_ex(type, data, "%H:%M:%S", style, parent);
2946 }
2947
to_xml_date(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2948 static xmlNodePtr to_xml_date(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2949 {
2950 return to_xml_datetime_ex(type, data, "%Y-%m-%d", style, parent);
2951 }
2952
to_xml_gyearmonth(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2953 static xmlNodePtr to_xml_gyearmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2954 {
2955 return to_xml_datetime_ex(type, data, "%Y-%m", style, parent);
2956 }
2957
to_xml_gyear(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2958 static xmlNodePtr to_xml_gyear(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2959 {
2960 return to_xml_datetime_ex(type, data, "%Y", style, parent);
2961 }
2962
to_xml_gmonthday(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2963 static xmlNodePtr to_xml_gmonthday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2964 {
2965 return to_xml_datetime_ex(type, data, "--%m-%d", style, parent);
2966 }
2967
to_xml_gday(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2968 static xmlNodePtr to_xml_gday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2969 {
2970 return to_xml_datetime_ex(type, data, "---%d", style, parent);
2971 }
2972
to_xml_gmonth(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)2973 static xmlNodePtr to_xml_gmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
2974 {
2975 return to_xml_datetime_ex(type, data, "--%m--", style, parent);
2976 }
2977
to_zval_list(zval * ret,encodeTypePtr enc,xmlNodePtr data)2978 static zval* to_zval_list(zval *ret, encodeTypePtr enc, xmlNodePtr data) {
2979 /*FIXME*/
2980 return to_zval_stringc(ret, enc, data);
2981 }
2982
to_xml_list(encodeTypePtr enc,zval * data,int style,xmlNodePtr parent)2983 static xmlNodePtr to_xml_list(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent) {
2984 xmlNodePtr ret;
2985 encodePtr list_enc = NULL;
2986
2987 if (enc->sdl_type && enc->sdl_type->kind == XSD_TYPEKIND_LIST && enc->sdl_type->elements) {
2988 sdlTypePtr type;
2989
2990 ZEND_HASH_FOREACH_PTR(enc->sdl_type->elements, type) {
2991 list_enc = type->encode;
2992 break;
2993 } ZEND_HASH_FOREACH_END();
2994 }
2995
2996 ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
2997 xmlAddChild(parent, ret);
2998 FIND_ZVAL_NULL(data, ret, style);
2999 if (Z_TYPE_P(data) == IS_ARRAY) {
3000 zval *tmp;
3001 smart_str list = {0};
3002 HashTable *ht = Z_ARRVAL_P(data);
3003
3004 ZEND_HASH_FOREACH_VAL(ht, tmp) {
3005 xmlNodePtr dummy = master_to_xml(list_enc, tmp, SOAP_LITERAL, ret);
3006 if (dummy && dummy->children && dummy->children->content) {
3007 if (list.s && ZSTR_LEN(list.s) != 0) {
3008 smart_str_appendc(&list, ' ');
3009 }
3010 smart_str_appends(&list, (char*)dummy->children->content);
3011 } else {
3012 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
3013 }
3014 xmlUnlinkNode(dummy);
3015 xmlFreeNode(dummy);
3016 } ZEND_HASH_FOREACH_END();
3017 smart_str_0(&list);
3018 if (list.s) {
3019 xmlNodeSetContentLen(ret, BAD_CAST(ZSTR_VAL(list.s)), ZSTR_LEN(list.s));
3020 } else {
3021 xmlNodeSetContentLen(ret, BAD_CAST(""), 0);
3022 }
3023 smart_str_free(&list);
3024 } else {
3025 zval tmp;
3026 char *str, *start, *next;
3027 smart_str list = {0};
3028
3029 if (Z_TYPE_P(data) != IS_STRING) {
3030 ZVAL_STR(&tmp, zval_get_string_func(data));
3031 data = &tmp;
3032 }
3033 str = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
3034 whiteSpace_collapse(BAD_CAST(str));
3035 start = str;
3036 while (start != NULL && *start != '\0') {
3037 xmlNodePtr dummy;
3038 zval dummy_zval;
3039
3040 next = strchr(start,' ');
3041 if (next != NULL) {
3042 *next = '\0';
3043 next++;
3044 }
3045 ZVAL_STRING(&dummy_zval, start);
3046 dummy = master_to_xml(list_enc, &dummy_zval, SOAP_LITERAL, ret);
3047 zval_ptr_dtor(&dummy_zval);
3048 if (dummy && dummy->children && dummy->children->content) {
3049 if (list.s && ZSTR_LEN(list.s) != 0) {
3050 smart_str_appendc(&list, ' ');
3051 }
3052 smart_str_appends(&list, (char*)dummy->children->content);
3053 } else {
3054 soap_error0(E_ERROR, "Encoding: Violation of encoding rules");
3055 }
3056 xmlUnlinkNode(dummy);
3057 xmlFreeNode(dummy);
3058
3059 start = next;
3060 }
3061 smart_str_0(&list);
3062 if (list.s) {
3063 xmlNodeSetContentLen(ret, BAD_CAST(ZSTR_VAL(list.s)), ZSTR_LEN(list.s));
3064 } else {
3065 xmlNodeSetContentLen(ret, BAD_CAST(""), 0);
3066 }
3067 smart_str_free(&list);
3068 efree(str);
3069 if (data == &tmp) {
3070 zval_ptr_dtor_str(&tmp);
3071 }
3072 }
3073 return ret;
3074 }
3075
to_xml_list1(encodeTypePtr enc,zval * data,int style,xmlNodePtr parent)3076 static xmlNodePtr to_xml_list1(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent) {
3077 /*FIXME: minLength=1 */
3078 return to_xml_list(enc,data,style, parent);
3079 }
3080
to_zval_union(zval * ret,encodeTypePtr enc,xmlNodePtr data)3081 static zval* to_zval_union(zval *ret, encodeTypePtr enc, xmlNodePtr data) {
3082 /*FIXME*/
3083 return to_zval_list(ret, enc, data);
3084 }
3085
to_xml_union(encodeTypePtr enc,zval * data,int style,xmlNodePtr parent)3086 static xmlNodePtr to_xml_union(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent) {
3087 /*FIXME*/
3088 return to_xml_list(enc,data,style, parent);
3089 }
3090
to_zval_any(zval * ret,encodeTypePtr type,xmlNodePtr data)3091 static zval *to_zval_any(zval *ret, encodeTypePtr type, xmlNodePtr data)
3092 {
3093 xmlBufferPtr buf;
3094
3095 if (SOAP_GLOBAL(sdl) && SOAP_GLOBAL(sdl)->elements && data->name) {
3096 smart_str nscat = {0};
3097 sdlTypePtr sdl_type;
3098
3099 if (data->ns && data->ns->href) {
3100 smart_str_appends(&nscat, (char*)data->ns->href);
3101 smart_str_appendc(&nscat, ':');
3102 }
3103 smart_str_appends(&nscat, (char*)data->name);
3104 smart_str_0(&nscat);
3105
3106 if ((sdl_type = zend_hash_find_ptr(SOAP_GLOBAL(sdl)->elements, nscat.s)) != NULL &&
3107 sdl_type->encode) {
3108 smart_str_free(&nscat);
3109 return master_to_zval_int(ret, sdl_type->encode, data);
3110 }
3111 smart_str_free(&nscat);
3112 }
3113
3114 buf = xmlBufferCreate();
3115 xmlNodeDump(buf, NULL, data, 0, 0);
3116 ZVAL_STRING(ret, (char*)xmlBufferContent(buf));
3117 xmlBufferFree(buf);
3118 return ret;
3119 }
3120
to_xml_any(encodeTypePtr type,zval * data,int style,xmlNodePtr parent)3121 static xmlNodePtr to_xml_any(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
3122 {
3123 xmlNodePtr ret = NULL;
3124
3125 if (Z_TYPE_P(data) == IS_ARRAY) {
3126 zval *el;
3127 encodePtr enc = get_conversion(XSD_ANYXML);
3128 zend_string *name;
3129
3130 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(data), name, el) {
3131 ret = master_to_xml(enc, el, style, parent);
3132 if (ret &&
3133 ret->name != xmlStringTextNoenc) {
3134 xmlNodeSetName(ret, BAD_CAST(ZSTR_VAL(name)));
3135 }
3136 } ZEND_HASH_FOREACH_END();
3137 return ret;
3138 }
3139 if (Z_TYPE_P(data) == IS_STRING) {
3140 ret = xmlNewTextLen(BAD_CAST(Z_STRVAL_P(data)), Z_STRLEN_P(data));
3141 } else {
3142 zend_string *tmp = zval_get_string_func(data);
3143 ret = xmlNewTextLen(BAD_CAST(ZSTR_VAL(tmp)), ZSTR_LEN(tmp));
3144 zend_string_release_ex(tmp, 0);
3145 }
3146
3147 ret->name = xmlStringTextNoenc;
3148 ret->parent = parent;
3149 ret->doc = parent->doc;
3150 ret->prev = parent->last;
3151 ret->next = NULL;
3152 if (parent->last) {
3153 parent->last->next = ret;
3154 } else {
3155 parent->children = ret;
3156 }
3157 parent->last = ret;
3158
3159 return ret;
3160 }
3161
sdl_guess_convert_zval(zval * ret,encodeTypePtr enc,xmlNodePtr data)3162 zval *sdl_guess_convert_zval(zval *ret, encodeTypePtr enc, xmlNodePtr data)
3163 {
3164 sdlTypePtr type;
3165
3166 type = enc->sdl_type;
3167 if (type == NULL) {
3168 return guess_zval_convert(ret, enc, data);
3169 }
3170 /*FIXME: restriction support
3171 if (type && type->restrictions &&
3172 data && data->children && data->children->content) {
3173 if (type->restrictions->whiteSpace && type->restrictions->whiteSpace->value) {
3174 if (strcmp(type->restrictions->whiteSpace->value,"replace") == 0) {
3175 whiteSpace_replace(data->children->content);
3176 } else if (strcmp(type->restrictions->whiteSpace->value,"collapse") == 0) {
3177 whiteSpace_collapse(data->children->content);
3178 }
3179 }
3180 if (type->restrictions->enumeration) {
3181 if (!zend_hash_exists(type->restrictions->enumeration,data->children->content,strlen(data->children->content)+1)) {
3182 soap_error1(E_WARNING, "Encoding: Restriction: invalid enumeration value \"%s\"", data->children->content);
3183 }
3184 }
3185 if (type->restrictions->minLength &&
3186 strlen(data->children->content) < type->restrictions->minLength->value) {
3187 soap_error0(E_WARNING, "Encoding: Restriction: length less than 'minLength'");
3188 }
3189 if (type->restrictions->maxLength &&
3190 strlen(data->children->content) > type->restrictions->maxLength->value) {
3191 soap_error0(E_WARNING, "Encoding: Restriction: length greater than 'maxLength'");
3192 }
3193 if (type->restrictions->length &&
3194 strlen(data->children->content) != type->restrictions->length->value) {
3195 soap_error0(E_WARNING, "Encoding: Restriction: length is not equal to 'length'");
3196 }
3197 }
3198 */
3199 switch (type->kind) {
3200 case XSD_TYPEKIND_SIMPLE:
3201 if (type->encode && enc != &type->encode->details) {
3202 return master_to_zval_int(ret, type->encode, data);
3203 } else {
3204 return guess_zval_convert(ret, enc, data);
3205 }
3206 break;
3207 case XSD_TYPEKIND_LIST:
3208 return to_zval_list(ret, enc, data);
3209 case XSD_TYPEKIND_UNION:
3210 return to_zval_union(ret, enc, data);
3211 case XSD_TYPEKIND_COMPLEX:
3212 case XSD_TYPEKIND_RESTRICTION:
3213 case XSD_TYPEKIND_EXTENSION:
3214 if (type->encode &&
3215 (type->encode->details.type == IS_ARRAY ||
3216 type->encode->details.type == SOAP_ENC_ARRAY)) {
3217 return to_zval_array(ret, enc, data);
3218 }
3219 return to_zval_object(ret, enc, data);
3220 default:
3221 soap_error0(E_ERROR, "Encoding: Internal Error");
3222 return guess_zval_convert(ret, enc, data);
3223 }
3224 }
3225
sdl_guess_convert_xml(encodeTypePtr enc,zval * data,int style,xmlNodePtr parent)3226 xmlNodePtr sdl_guess_convert_xml(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent)
3227 {
3228 sdlTypePtr type;
3229 xmlNodePtr ret = NULL;
3230
3231 type = enc->sdl_type;
3232
3233 if (type == NULL) {
3234 ret = guess_xml_convert(enc, data, style, parent);
3235 if (style == SOAP_ENCODED) {
3236 set_ns_and_type(ret, enc);
3237 }
3238 return ret;
3239 }
3240 /*FIXME: restriction support
3241 if (type) {
3242 if (type->restrictions && Z_TYPE_P(data) == IS_STRING) {
3243 if (type->restrictions->enumeration) {
3244 if (!zend_hash_exists(type->restrictions->enumeration,Z_STRVAL_P(data),Z_STRLEN_P(data)+1)) {
3245 soap_error1(E_WARNING, "Encoding: Restriction: invalid enumeration value \"%s\".", Z_STRVAL_P(data));
3246 }
3247 }
3248 if (type->restrictions->minLength &&
3249 Z_STRLEN_P(data) < type->restrictions->minLength->value) {
3250 soap_error0(E_WARNING, "Encoding: Restriction: length less than 'minLength'");
3251 }
3252 if (type->restrictions->maxLength &&
3253 Z_STRLEN_P(data) > type->restrictions->maxLength->value) {
3254 soap_error0(E_WARNING, "Encoding: Restriction: length greater than 'maxLength'");
3255 }
3256 if (type->restrictions->length &&
3257 Z_STRLEN_P(data) != type->restrictions->length->value) {
3258 soap_error0(E_WARNING, "Encoding: Restriction: length is not equal to 'length'");
3259 }
3260 }
3261 }
3262 */
3263 switch(type->kind) {
3264 case XSD_TYPEKIND_SIMPLE:
3265 if (type->encode && enc != &type->encode->details) {
3266 ret = master_to_xml(type->encode, data, style, parent);
3267 } else {
3268 ret = guess_xml_convert(enc, data, style, parent);
3269 }
3270 break;
3271 case XSD_TYPEKIND_LIST:
3272 ret = to_xml_list(enc, data, style, parent);
3273 break;
3274 case XSD_TYPEKIND_UNION:
3275 ret = to_xml_union(enc, data, style, parent);
3276 break;
3277 case XSD_TYPEKIND_COMPLEX:
3278 case XSD_TYPEKIND_RESTRICTION:
3279 case XSD_TYPEKIND_EXTENSION:
3280 if (type->encode &&
3281 (type->encode->details.type == IS_ARRAY ||
3282 type->encode->details.type == SOAP_ENC_ARRAY)) {
3283 return to_xml_array(enc, data, style, parent);
3284 } else {
3285 return to_xml_object(enc, data, style, parent);
3286 }
3287 break;
3288 default:
3289 soap_error0(E_ERROR, "Encoding: Internal Error");
3290 break;
3291 }
3292 if (style == SOAP_ENCODED) {
3293 set_ns_and_type(ret, enc);
3294 }
3295 return ret;
3296 }
3297
check_and_resolve_href(xmlNodePtr data)3298 static xmlNodePtr check_and_resolve_href(xmlNodePtr data)
3299 {
3300 if (data && data->properties) {
3301 xmlAttrPtr href;
3302
3303 href = data->properties;
3304 while (1) {
3305 href = get_attribute(href, "href");
3306 if (href == NULL || href->ns == NULL) {break;}
3307 href = href->next;
3308 }
3309 if (href) {
3310 /* Internal href try and find node */
3311 if (href->children->content[0] == '#') {
3312 xmlNodePtr ret = get_node_with_attribute_recursive(data->doc->children, NULL, "id", (char*)&href->children->content[1]);
3313 if (!ret) {
3314 soap_error1(E_ERROR, "Encoding: Unresolved reference '%s'", href->children->content);
3315 }
3316 return ret;
3317 } else {
3318 /* TODO: External href....? */
3319 soap_error1(E_ERROR, "Encoding: External reference '%s'", href->children->content);
3320 }
3321 }
3322 /* SOAP 1.2 enc:id enc:ref */
3323 href = get_attribute_ex(data->properties, "ref", SOAP_1_2_ENC_NAMESPACE);
3324 if (href) {
3325 xmlChar* id;
3326 xmlNodePtr ret;
3327
3328 if (href->children->content[0] == '#') {
3329 id = href->children->content+1;
3330 } else {
3331 id = href->children->content;
3332 }
3333 ret = get_node_with_attribute_recursive_ex(data->doc->children, NULL, NULL, "id", (char*)id, SOAP_1_2_ENC_NAMESPACE);
3334 if (!ret) {
3335 soap_error1(E_ERROR, "Encoding: Unresolved reference '%s'", href->children->content);
3336 } else if (ret == data) {
3337 soap_error1(E_ERROR, "Encoding: Violation of id and ref information items '%s'", href->children->content);
3338 }
3339 return ret;
3340 }
3341 }
3342 return data;
3343 }
3344
set_ns_and_type(xmlNodePtr node,encodeTypePtr type)3345 static void set_ns_and_type(xmlNodePtr node, encodeTypePtr type)
3346 {
3347 set_ns_and_type_ex(node, type->ns, type->type_str);
3348 }
3349
set_ns_and_type_ex(xmlNodePtr node,char * ns,char * type)3350 static void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type)
3351 {
3352 smart_str nstype = {0};
3353 get_type_str(node, ns, type, &nstype);
3354 set_xsi_type(node, ZSTR_VAL(nstype.s));
3355 smart_str_free(&nstype);
3356 }
3357
xmlSearchNsPrefixByHref(xmlDocPtr doc,xmlNodePtr node,const xmlChar * href)3358 static xmlNsPtr xmlSearchNsPrefixByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
3359 {
3360 xmlNsPtr cur;
3361 xmlNodePtr orig = node;
3362
3363 while (node) {
3364 if (node->type == XML_ENTITY_REF_NODE ||
3365 node->type == XML_ENTITY_NODE ||
3366 node->type == XML_ENTITY_DECL) {
3367 return NULL;
3368 }
3369 if (node->type == XML_ELEMENT_NODE) {
3370 cur = node->nsDef;
3371 while (cur != NULL) {
3372 if (cur->prefix && cur->href && xmlStrEqual(cur->href, href)) {
3373 if (xmlSearchNs(doc, node, cur->prefix) == cur) {
3374 return cur;
3375 }
3376 }
3377 cur = cur->next;
3378 }
3379 if (orig != node) {
3380 cur = node->ns;
3381 if (cur != NULL) {
3382 if (cur->prefix && cur->href && xmlStrEqual(cur->href, href)) {
3383 if (xmlSearchNs(doc, node, cur->prefix) == cur) {
3384 return cur;
3385 }
3386 }
3387 }
3388 }
3389 }
3390 node = node->parent;
3391 }
3392 return NULL;
3393 }
3394
encode_add_ns(xmlNodePtr node,const char * ns)3395 xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
3396 {
3397 xmlNsPtr xmlns;
3398
3399 if (ns == NULL) {
3400 return NULL;
3401 }
3402
3403 xmlns = xmlSearchNsByHref(node->doc, node, BAD_CAST(ns));
3404 if (xmlns != NULL && xmlns->prefix == NULL) {
3405 xmlns = xmlSearchNsPrefixByHref(node->doc, node, BAD_CAST(ns));
3406 }
3407 if (xmlns == NULL) {
3408 xmlChar* prefix;
3409
3410 if ((prefix = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEncNs), (char*)ns, strlen(ns))) != NULL) {
3411 xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), prefix);
3412 } else {
3413 smart_str prefix = {0};
3414 int num = ++SOAP_GLOBAL(cur_uniq_ns);
3415
3416 while (1) {
3417 smart_str_appendl(&prefix, "ns", 2);
3418 smart_str_append_long(&prefix, num);
3419 smart_str_0(&prefix);
3420 if (xmlSearchNs(node->doc, node, BAD_CAST(ZSTR_VAL(prefix.s))) == NULL) {
3421 break;
3422 }
3423 smart_str_free(&prefix);
3424 prefix.s = NULL;
3425 num = ++SOAP_GLOBAL(cur_uniq_ns);
3426 }
3427
3428 xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
3429 smart_str_free(&prefix);
3430 }
3431 }
3432 return xmlns;
3433 }
3434
set_ns_prop(xmlNodePtr node,char * ns,char * name,char * val)3435 static void set_ns_prop(xmlNodePtr node, char *ns, char *name, char *val)
3436 {
3437 xmlSetNsProp(node, encode_add_ns(node, ns), BAD_CAST(name), BAD_CAST(val));
3438 }
3439
set_xsi_nil(xmlNodePtr node)3440 static void set_xsi_nil(xmlNodePtr node)
3441 {
3442 set_ns_prop(node, XSI_NAMESPACE, "nil", "true");
3443 }
3444
set_xsi_type(xmlNodePtr node,char * type)3445 static void set_xsi_type(xmlNodePtr node, char *type)
3446 {
3447 set_ns_prop(node, XSI_NAMESPACE, "type", type);
3448 }
3449
encode_reset_ns()3450 void encode_reset_ns()
3451 {
3452 SOAP_GLOBAL(cur_uniq_ns) = 0;
3453 SOAP_GLOBAL(cur_uniq_ref) = 0;
3454 if (SOAP_GLOBAL(ref_map)) {
3455 zend_hash_destroy(SOAP_GLOBAL(ref_map));
3456 } else {
3457 SOAP_GLOBAL(ref_map) = emalloc(sizeof(HashTable));
3458 }
3459 zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0);
3460 }
3461
encode_finish()3462 void encode_finish()
3463 {
3464 SOAP_GLOBAL(cur_uniq_ns) = 0;
3465 SOAP_GLOBAL(cur_uniq_ref) = 0;
3466 if (SOAP_GLOBAL(ref_map)) {
3467 zend_hash_destroy(SOAP_GLOBAL(ref_map));
3468 efree(SOAP_GLOBAL(ref_map));
3469 SOAP_GLOBAL(ref_map) = NULL;
3470 }
3471 }
3472
get_conversion(int encode)3473 encodePtr get_conversion(int encode)
3474 {
3475 encodePtr enc;
3476
3477 if ((enc = zend_hash_index_find_ptr(&SOAP_GLOBAL(defEncIndex), encode)) == NULL) {
3478 soap_error0(E_ERROR, "Encoding: Cannot find encoding");
3479 return NULL;
3480 } else {
3481 return enc;
3482 }
3483 }
3484
is_map(zval * array)3485 static int is_map(zval *array)
3486 {
3487 zend_ulong index;
3488 zend_string *key;
3489 zend_ulong i = 0;
3490
3491 if (HT_IS_PACKED(Z_ARRVAL_P(array)) && HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(array))) {
3492 return FALSE;
3493 }
3494
3495 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(array), index, key) {
3496 if (key || index != i) {
3497 return TRUE;
3498 }
3499 i++;
3500 } ZEND_HASH_FOREACH_END();
3501 return FALSE;
3502 }
3503
get_array_type(xmlNodePtr node,zval * array,smart_str * type)3504 static encodePtr get_array_type(xmlNodePtr node, zval *array, smart_str *type)
3505 {
3506 HashTable *ht;
3507 int i, cur_type, prev_type, different;
3508 zval *tmp;
3509 char *prev_stype = NULL, *cur_stype = NULL, *prev_ns = NULL, *cur_ns = NULL;
3510
3511 if (!array || Z_TYPE_P(array) != IS_ARRAY) {
3512 smart_str_appendl(type, "xsd:anyType", sizeof("xsd:anyType")-1);
3513 return get_conversion(XSD_ANYTYPE);
3514 }
3515
3516 i = 0;
3517 different = FALSE;
3518 cur_type = prev_type = 0;
3519 ht = Z_ARRVAL_P(array);
3520
3521 ZEND_HASH_FOREACH_VAL_IND(ht, tmp) {
3522 ZVAL_DEREF(tmp);
3523 if (Z_TYPE_P(tmp) == IS_OBJECT &&
3524 Z_OBJCE_P(tmp) == soap_var_class_entry) {
3525 zval *ztype;
3526
3527 if ((ztype = zend_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_type", sizeof("enc_type")-1)) == NULL ||
3528 Z_TYPE_P(ztype) != IS_LONG) {
3529 soap_error0(E_ERROR, "Encoding: SoapVar has no 'enc_type' property");
3530 }
3531 cur_type = Z_LVAL_P(ztype);
3532
3533 if ((ztype = zend_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_stype", sizeof("enc_stype")-1)) != NULL &&
3534 Z_TYPE_P(ztype) == IS_STRING) {
3535 cur_stype = Z_STRVAL_P(ztype);
3536 } else {
3537 cur_stype = NULL;
3538 }
3539
3540 if ((ztype = zend_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_ns", sizeof("enc_ns")-1)) != NULL &&
3541 Z_TYPE_P(ztype) == IS_STRING) {
3542 cur_ns = Z_STRVAL_P(ztype);
3543 } else {
3544 cur_ns = NULL;
3545 }
3546
3547 } else if (Z_TYPE_P(tmp) == IS_ARRAY && is_map(tmp)) {
3548 cur_type = APACHE_MAP;
3549 cur_stype = NULL;
3550 cur_ns = NULL;
3551 } else {
3552 cur_type = Z_TYPE_P(tmp);
3553 cur_stype = NULL;
3554 cur_ns = NULL;
3555 }
3556
3557 if (i > 0) {
3558 if ((cur_type != prev_type) ||
3559 (cur_stype != NULL && prev_stype != NULL && strcmp(cur_stype,prev_stype) != 0) ||
3560 (cur_stype == NULL && cur_stype != prev_stype) ||
3561 (cur_ns != NULL && prev_ns != NULL && strcmp(cur_ns,prev_ns) != 0) ||
3562 (cur_ns == NULL && cur_ns != prev_ns)) {
3563 different = TRUE;
3564 break;
3565 }
3566 }
3567
3568 prev_type = cur_type;
3569 prev_stype = cur_stype;
3570 prev_ns = cur_ns;
3571 i++;
3572 } ZEND_HASH_FOREACH_END();
3573
3574 if (different || i == 0) {
3575 smart_str_appendl(type, "xsd:anyType", sizeof("xsd:anyType")-1);
3576 return get_conversion(XSD_ANYTYPE);
3577 } else {
3578 encodePtr enc;
3579
3580 if (cur_stype != NULL) {
3581 smart_str array_type = {0};
3582
3583 if (cur_ns) {
3584 xmlNsPtr ns = encode_add_ns(node, cur_ns);
3585
3586 smart_str_appends(type, (char*)ns->prefix);
3587 smart_str_appendc(type, ':');
3588 smart_str_appends(&array_type, cur_ns);
3589 smart_str_appendc(&array_type, ':');
3590 }
3591 smart_str_appends(type, cur_stype);
3592 smart_str_0(type);
3593 smart_str_appends(&array_type, cur_stype);
3594 smart_str_0(&array_type);
3595
3596 enc = get_encoder_ex(SOAP_GLOBAL(sdl), ZSTR_VAL(array_type.s), ZSTR_LEN(array_type.s));
3597 smart_str_free(&array_type);
3598 return enc;
3599 } else {
3600 enc = get_conversion(cur_type);
3601 get_type_str(node, enc->details.ns, enc->details.type_str, type);
3602 return enc;
3603 }
3604 }
3605 return NULL;
3606 }
3607
get_type_str(xmlNodePtr node,const char * ns,const char * type,smart_str * ret)3608 static void get_type_str(xmlNodePtr node, const char* ns, const char* type, smart_str* ret)
3609 {
3610
3611 if (ns) {
3612 xmlNsPtr xmlns;
3613 if (SOAP_GLOBAL(soap_version) == SOAP_1_2 &&
3614 strcmp(ns,SOAP_1_1_ENC_NAMESPACE) == 0) {
3615 ns = SOAP_1_2_ENC_NAMESPACE;
3616 } else if (SOAP_GLOBAL(soap_version) == SOAP_1_1 &&
3617 strcmp(ns,SOAP_1_2_ENC_NAMESPACE) == 0) {
3618 ns = SOAP_1_1_ENC_NAMESPACE;
3619 }
3620 xmlns = encode_add_ns(node, ns);
3621 smart_str_appends(ret, (char*)xmlns->prefix);
3622 smart_str_appendc(ret, ':');
3623 }
3624 smart_str_appendl(ret, type, strlen(type));
3625 smart_str_0(ret);
3626 }
3627
delete_mapping(void * data)3628 static void delete_mapping(void *data)
3629 {
3630 soapMappingPtr map = (soapMappingPtr)data;
3631
3632 zval_ptr_dtor(&map->to_xml);
3633 zval_ptr_dtor(&map->to_zval);
3634 efree(map);
3635 }
3636
delete_encoder(zval * zv)3637 void delete_encoder(zval *zv)
3638 {
3639 encodePtr t = Z_PTR_P(zv);
3640 if (t->details.ns) {
3641 efree(t->details.ns);
3642 }
3643 if (t->details.type_str) {
3644 efree(t->details.type_str);
3645 }
3646 if (t->details.map) {
3647 delete_mapping(t->details.map);
3648 }
3649 efree(t);
3650 }
3651
delete_encoder_persistent(zval * zv)3652 void delete_encoder_persistent(zval *zv)
3653 {
3654 encodePtr t = Z_PTR_P(zv);
3655 if (t->details.ns) {
3656 free(t->details.ns);
3657 }
3658 if (t->details.type_str) {
3659 free(t->details.type_str);
3660 }
3661 /* we should never have mapping in persistent encoder */
3662 assert(t->details.map == NULL);
3663 free(t);
3664 }
3665