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