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