xref: /PHP-7.4/ext/soap/php_sdl.c (revision 51d76c34)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) The PHP Group                                          |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
16   |          Shane Caraveo <shane@caraveo.com>                           |
17   |          Dmitry Stogov <dmitry@php.net>                              |
18   +----------------------------------------------------------------------+
19 */
20 
21 #include "php_soap.h"
22 #include "ext/libxml/php_libxml.h"
23 #include "libxml/uri.h"
24 
25 #include "ext/standard/md5.h"
26 #include "zend_virtual_cwd.h"
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 
32 #ifndef O_BINARY
33 # define O_BINARY 0
34 #endif
35 
36 static void delete_fault(zval *zv);
37 static void delete_fault_persistent(zval *zv);
38 static void delete_binding(zval *zv);
39 static void delete_binding_persistent(zval *zv);
40 static void delete_function(zval *zv);
41 static void delete_function_persistent(zval *zv);
42 static void delete_parameter(zval *zv);
43 static void delete_parameter_persistent(zval *zv);
44 static void delete_header(zval *header);
45 static void delete_header_int(sdlSoapBindingFunctionHeaderPtr hdr);
46 static void delete_header_persistent(zval *zv);
47 static void delete_document(zval *zv);
48 
get_encoder_from_prefix(sdlPtr sdl,xmlNodePtr node,const xmlChar * type)49 encodePtr get_encoder_from_prefix(sdlPtr sdl, xmlNodePtr node, const xmlChar *type)
50 {
51 	encodePtr enc = NULL;
52 	xmlNsPtr nsptr;
53 	char *ns, *cptype;
54 
55 	parse_namespace(type, &cptype, &ns);
56 	nsptr = xmlSearchNs(node->doc, node, BAD_CAST(ns));
57 	if (nsptr != NULL) {
58 		enc = get_encoder(sdl, (char*)nsptr->href, cptype);
59 		if (enc == NULL) {
60 			enc = get_encoder_ex(sdl, cptype, strlen(cptype));
61 		}
62 	} else {
63 		enc = get_encoder_ex(sdl, (char*)type, xmlStrlen(type));
64 	}
65 	efree(cptype);
66 	if (ns) {efree(ns);}
67 	return enc;
68 }
69 
get_element(sdlPtr sdl,xmlNodePtr node,const xmlChar * type)70 static sdlTypePtr get_element(sdlPtr sdl, xmlNodePtr node, const xmlChar *type)
71 {
72 	sdlTypePtr ret = NULL;
73 
74 	if (sdl->elements) {
75 		xmlNsPtr nsptr;
76 		char *ns, *cptype;
77 		sdlTypePtr sdl_type;
78 
79 		parse_namespace(type, &cptype, &ns);
80 		nsptr = xmlSearchNs(node->doc, node, BAD_CAST(ns));
81 		if (nsptr != NULL) {
82 			int ns_len = xmlStrlen(nsptr->href);
83 			int type_len = strlen(cptype);
84 			int len = ns_len + type_len + 1;
85 			char *nscat = emalloc(len + 1);
86 
87 			memcpy(nscat, nsptr->href, ns_len);
88 			nscat[ns_len] = ':';
89 			memcpy(nscat+ns_len+1, cptype, type_len);
90 			nscat[len] = '\0';
91 
92 			if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, nscat, len)) != NULL) {
93 				ret = sdl_type;
94 			} else if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, (char*)type, type_len)) != NULL) {
95 				ret = sdl_type;
96 			}
97 			efree(nscat);
98 		} else {
99 			if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, (char*)type, xmlStrlen(type))) != NULL) {
100 				ret = sdl_type;
101 			}
102 		}
103 
104 		efree(cptype);
105 		if (ns) {efree(ns);}
106 	}
107 	return ret;
108 }
109 
get_encoder(sdlPtr sdl,const char * ns,const char * type)110 encodePtr get_encoder(sdlPtr sdl, const char *ns, const char *type)
111 {
112 	encodePtr enc = NULL;
113 	char *nscat;
114 	int ns_len = ns ? strlen(ns) : 0;
115 	int type_len = strlen(type);
116 	int len = ns_len + type_len + 1;
117 
118 	nscat = emalloc(len + 1);
119 	if (ns) {
120 		memcpy(nscat, ns, ns_len);
121 	}
122 	nscat[ns_len] = ':';
123 	memcpy(nscat+ns_len+1, type, type_len);
124 	nscat[len] = '\0';
125 
126 	enc = get_encoder_ex(sdl, nscat, len);
127 
128 	if (enc == NULL &&
129 	    ((ns_len == sizeof(SOAP_1_1_ENC_NAMESPACE)-1 &&
130 	      memcmp(ns, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1) == 0) ||
131 	     (ns_len == sizeof(SOAP_1_2_ENC_NAMESPACE)-1 &&
132 	      memcmp(ns, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1) == 0))) {
133 		char *enc_nscat;
134 		int enc_ns_len;
135 		int enc_len;
136 
137 		enc_ns_len = sizeof(XSD_NAMESPACE)-1;
138 		enc_len = enc_ns_len + type_len + 1;
139 		enc_nscat = emalloc(enc_len + 1);
140 		memcpy(enc_nscat, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1);
141 		enc_nscat[enc_ns_len] = ':';
142 		memcpy(enc_nscat+enc_ns_len+1, type, type_len);
143 		enc_nscat[enc_len] = '\0';
144 
145 		enc = get_encoder_ex(NULL, enc_nscat, enc_len);
146 		efree(enc_nscat);
147 		if (enc && sdl) {
148 			encodePtr new_enc	= pemalloc(sizeof(encode), sdl->is_persistent);
149 			memcpy(new_enc, enc, sizeof(encode));
150 			if (sdl->is_persistent) {
151 				new_enc->details.ns = zend_strndup(ns, ns_len);
152 				new_enc->details.type_str = strdup(new_enc->details.type_str);
153 			} else {
154 				new_enc->details.ns = estrndup(ns, ns_len);
155 				new_enc->details.type_str = estrdup(new_enc->details.type_str);
156 			}
157 			if (sdl->encoders == NULL) {
158 				sdl->encoders = pemalloc(sizeof(HashTable), sdl->is_persistent);
159 				zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, sdl->is_persistent);
160 			}
161 			zend_hash_str_update_ptr(sdl->encoders, nscat, len, new_enc);
162 			enc = new_enc;
163 		}
164 	}
165 	efree(nscat);
166 	return enc;
167 }
168 
get_encoder_ex(sdlPtr sdl,const char * nscat,int len)169 encodePtr get_encoder_ex(sdlPtr sdl, const char *nscat, int len)
170 {
171 	encodePtr enc;
172 
173 	if ((enc = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEnc), (char*)nscat, len)) != NULL) {
174 		return enc;
175 	} else if (sdl && sdl->encoders && (enc = zend_hash_str_find_ptr(sdl->encoders, (char*)nscat, len)) != NULL) {
176 		return enc;
177 	}
178 	return NULL;
179 }
180 
get_binding_from_type(sdlPtr sdl,sdlBindingType type)181 sdlBindingPtr get_binding_from_type(sdlPtr sdl, sdlBindingType type)
182 {
183 	sdlBindingPtr binding;
184 
185 	if (sdl == NULL) {
186 		return NULL;
187 	}
188 
189 	ZEND_HASH_FOREACH_PTR(sdl->bindings, binding) {
190 		if (binding->bindingType == type) {
191 			return binding;
192 		}
193 	} ZEND_HASH_FOREACH_END();
194 	return NULL;
195 }
196 
get_binding_from_name(sdlPtr sdl,char * name,char * ns)197 sdlBindingPtr get_binding_from_name(sdlPtr sdl, char *name, char *ns)
198 {
199 	sdlBindingPtr binding;
200 	smart_str key = {0};
201 
202 	smart_str_appends(&key, ns);
203 	smart_str_appendc(&key, ':');
204 	smart_str_appends(&key, name);
205 	smart_str_0(&key);
206 
207 	binding = zend_hash_find_ptr(sdl->bindings, key.s);
208 
209 	smart_str_free(&key);
210 	return binding;
211 }
212 
is_wsdl_element(xmlNodePtr node)213 static int is_wsdl_element(xmlNodePtr node)
214 {
215 	if (node->ns && strcmp((char*)node->ns->href, WSDL_NAMESPACE) != 0) {
216 		xmlAttrPtr attr;
217 		if ((attr = get_attribute_ex(node->properties, "required", WSDL_NAMESPACE)) != NULL &&
218 		     attr->children && attr->children->content &&
219 		     (strcmp((char*)attr->children->content, "1") == 0 ||
220 		      strcmp((char*)attr->children->content, "true") == 0)) {
221 			soap_error1(E_ERROR, "Parsing WSDL: Unknown required WSDL extension '%s'", node->ns->href);
222 		}
223 		return 0;
224 	}
225 	return 1;
226 }
227 
sdl_set_uri_credentials(sdlCtx * ctx,char * uri)228 void sdl_set_uri_credentials(sdlCtx *ctx, char *uri)
229 {
230 	char *s;
231 	size_t l1, l2;
232 	zval context;
233 	zval *header = NULL;
234 
235 	/* check if we load xsd from the same server */
236 	s = strstr(ctx->sdl->source, "://");
237 	if (!s) return;
238 	s = strchr(s+3, '/');
239 	l1 = s ? (size_t)(s - ctx->sdl->source) : strlen(ctx->sdl->source);
240 	s = strstr((char*)uri, "://");
241 	if (!s) return;
242 	s = strchr(s+3, '/');
243 	l2 = s ? (size_t)(s - (char*)uri) : strlen((char*)uri);
244 	if (l1 != l2) {
245 		/* check for http://...:80/ */
246 		if (l1 > 11 &&
247 		    ctx->sdl->source[4] == ':' &&
248 		    ctx->sdl->source[l1-3] == ':' &&
249 		    ctx->sdl->source[l1-2] == '8' &&
250 		    ctx->sdl->source[l1-1] == '0') {
251 			l1 -= 3;
252 		}
253 		if (l2 > 11 &&
254 		    uri[4] == ':' &&
255 		    uri[l2-3] == ':' &&
256 		    uri[l2-2] == '8' &&
257 		    uri[l2-1] == '0') {
258 			l2 -= 3;
259 		}
260 		/* check for https://...:443/ */
261 		if (l1 > 13 &&
262 		    ctx->sdl->source[4] == 's' &&
263 		    ctx->sdl->source[l1-4] == ':' &&
264 		    ctx->sdl->source[l1-3] == '4' &&
265 		    ctx->sdl->source[l1-2] == '4' &&
266 		    ctx->sdl->source[l1-1] == '3') {
267 			l1 -= 4;
268 		}
269 		if (l2 > 13 &&
270 		    uri[4] == 's' &&
271 		    uri[l2-4] == ':' &&
272 		    uri[l2-3] == '4' &&
273 		    uri[l2-2] == '4' &&
274 		    uri[l2-1] == '3') {
275 			l2 -= 4;
276 		}
277 	}
278 	if (l1 != l2 || memcmp(ctx->sdl->source, uri, l1) != 0) {
279 		/* another server. clear authentication credentals */
280 		php_libxml_switch_context(NULL, &context);
281 		php_libxml_switch_context(&context, NULL);
282 		if (Z_TYPE(context) != IS_UNDEF) {
283 			zval *context_ptr = &context;
284 			ctx->context = php_stream_context_from_zval(context_ptr, 1);
285 
286 			if (ctx->context &&
287 			    (header = php_stream_context_get_option(ctx->context, "http", "header")) != NULL) {
288 				s = strstr(Z_STRVAL_P(header), "Authorization: Basic");
289 				if (s && (s == Z_STRVAL_P(header) || *(s-1) == '\n' || *(s-1) == '\r')) {
290 					char *rest = strstr(s, "\r\n");
291 					if (rest) {
292 						zval new_header;
293 
294 						rest += 2;
295 						ZVAL_NEW_STR(&new_header, zend_string_alloc(Z_STRLEN_P(header) - (rest - s), 0));
296 						memcpy(Z_STRVAL(new_header), Z_STRVAL_P(header), s - Z_STRVAL_P(header));
297 						memcpy(Z_STRVAL(new_header) + (s - Z_STRVAL_P(header)), rest, Z_STRLEN_P(header) - (rest - Z_STRVAL_P(header)) + 1);
298 						ZVAL_COPY(&ctx->old_header, header);
299 						php_stream_context_set_option(ctx->context, "http", "header", &new_header);
300 						zval_ptr_dtor(&new_header);
301 					}
302 				}
303 			}
304 		}
305 	}
306 }
307 
sdl_restore_uri_credentials(sdlCtx * ctx)308 void sdl_restore_uri_credentials(sdlCtx *ctx)
309 {
310 	if (Z_TYPE(ctx->old_header) != IS_UNDEF) {
311 	    php_stream_context_set_option(ctx->context, "http", "header", &ctx->old_header);
312 	    zval_ptr_dtor(&ctx->old_header);
313 		ZVAL_UNDEF(&ctx->old_header);
314 	}
315 	ctx->context = NULL;
316 }
317 
318 #define SAFE_STR(a) ((a)?((const char *)a):"")
319 
load_wsdl_ex(zval * this_ptr,char * struri,sdlCtx * ctx,int include)320 static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
321 {
322 	sdlPtr tmpsdl = ctx->sdl;
323 	xmlDocPtr wsdl;
324 	xmlNodePtr root, definitions, trav;
325 	xmlAttrPtr targetNamespace;
326 
327 	if (zend_hash_str_exists(&ctx->docs, struri, strlen(struri))) {
328 		return;
329 	}
330 
331 	sdl_set_uri_credentials(ctx, struri);
332 	wsdl = soap_xmlParseFile(struri);
333 	sdl_restore_uri_credentials(ctx);
334 
335 	if (!wsdl) {
336 		xmlErrorPtr xmlErrorPtr = xmlGetLastError();
337 
338 		if (xmlErrorPtr) {
339 			soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);
340 		} else {
341 			soap_error1(E_ERROR, "Parsing WSDL: Couldn't load from '%s'", struri);
342 		}
343 	}
344 
345 	zend_hash_str_add_ptr(&ctx->docs, struri, strlen(struri), wsdl);
346 
347 	root = wsdl->children;
348 	definitions = get_node_ex(root, "definitions", WSDL_NAMESPACE);
349 	if (!definitions) {
350 		if (include) {
351 			xmlNodePtr schema = get_node_ex(root, "schema", XSD_NAMESPACE);
352 			if (schema) {
353 				load_schema(ctx, schema);
354 				return;
355 			}
356 		}
357 		soap_error1(E_ERROR, "Parsing WSDL: Couldn't find <definitions> in '%s'", struri);
358 	}
359 
360 	if (!include) {
361 		targetNamespace = get_attribute(definitions->properties, "targetNamespace");
362 		if (targetNamespace) {
363 			tmpsdl->target_ns = estrdup((char*)targetNamespace->children->content);
364 		}
365 	}
366 
367 	trav = definitions->children;
368 	while (trav != NULL) {
369 		if (!is_wsdl_element(trav)) {
370 			trav = trav->next;
371 			continue;
372 		}
373 		if (node_is_equal(trav,"types")) {
374 			/* TODO: Only one "types" is allowed */
375 			xmlNodePtr trav2 = trav->children;
376 
377 			while (trav2 != NULL) {
378 				if (node_is_equal_ex(trav2, "schema", XSD_NAMESPACE)) {
379 					load_schema(ctx, trav2);
380 				} else if (is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
381 					soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
382 				}
383 				trav2 = trav2->next;
384 			}
385 		} else if (node_is_equal(trav,"import")) {
386 			/* TODO: namespace ??? */
387 			xmlAttrPtr tmp = get_attribute(trav->properties, "location");
388 			if (tmp) {
389 				xmlChar *uri;
390 				xmlChar *base = xmlNodeGetBase(trav->doc, trav);
391 
392 				if (base == NULL) {
393 					uri = xmlBuildURI(tmp->children->content, trav->doc->URL);
394 				} else {
395 					uri = xmlBuildURI(tmp->children->content, base);
396 					xmlFree(base);
397 				}
398 				load_wsdl_ex(this_ptr, (char*)uri, ctx, 1);
399 				xmlFree(uri);
400 			}
401 
402 		} else if (node_is_equal(trav,"message")) {
403 			xmlAttrPtr name = get_attribute(trav->properties, "name");
404 			if (name && name->children && name->children->content) {
405 				if (zend_hash_str_add_ptr(&ctx->messages, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
406 					soap_error1(E_ERROR, "Parsing WSDL: <message> '%s' already defined", name->children->content);
407 				}
408 			} else {
409 				soap_error0(E_ERROR, "Parsing WSDL: <message> has no name attribute");
410 			}
411 
412 		} else if (node_is_equal(trav,"portType")) {
413 			xmlAttrPtr name = get_attribute(trav->properties, "name");
414 			if (name && name->children && name->children->content) {
415 				if (zend_hash_str_add_ptr(&ctx->portTypes, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
416 					soap_error1(E_ERROR, "Parsing WSDL: <portType> '%s' already defined", name->children->content);
417 				}
418 			} else {
419 				soap_error0(E_ERROR, "Parsing WSDL: <portType> has no name attribute");
420 			}
421 
422 		} else if (node_is_equal(trav,"binding")) {
423 			xmlAttrPtr name = get_attribute(trav->properties, "name");
424 			if (name && name->children && name->children->content) {
425 				if (zend_hash_str_add_ptr(&ctx->bindings, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
426 					soap_error1(E_ERROR, "Parsing WSDL: <binding> '%s' already defined", name->children->content);
427 				}
428 			} else {
429 				soap_error0(E_ERROR, "Parsing WSDL: <binding> has no name attribute");
430 			}
431 
432 		} else if (node_is_equal(trav,"service")) {
433 			xmlAttrPtr name = get_attribute(trav->properties, "name");
434 			if (name && name->children && name->children->content) {
435 				if (zend_hash_str_add_ptr(&ctx->services, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
436 					soap_error1(E_ERROR, "Parsing WSDL: <service> '%s' already defined", name->children->content);
437 				}
438 			} else {
439 				soap_error0(E_ERROR, "Parsing WSDL: <service> has no name attribute");
440 			}
441 		} else if (!node_is_equal(trav,"documentation")) {
442 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
443 		}
444 		trav = trav->next;
445 	}
446 }
447 
wsdl_soap_binding_header(sdlCtx * ctx,xmlNodePtr header,char * wsdl_soap_namespace,int fault)448 static sdlSoapBindingFunctionHeaderPtr wsdl_soap_binding_header(sdlCtx* ctx, xmlNodePtr header, char* wsdl_soap_namespace, int fault)
449 {
450 	xmlAttrPtr tmp;
451 	xmlNodePtr message, part;
452 	char *ctype;
453 	sdlSoapBindingFunctionHeaderPtr h;
454 
455 	tmp = get_attribute(header->properties, "message");
456 	if (!tmp) {
457 		soap_error0(E_ERROR, "Parsing WSDL: Missing message attribute for <header>");
458 	}
459 
460 	ctype = strrchr((char*)tmp->children->content,':');
461 	if (ctype == NULL) {
462 		ctype = (char*)tmp->children->content;
463 	} else {
464 		++ctype;
465 	}
466 	if ((message = zend_hash_str_find_ptr(&ctx->messages, ctype, strlen(ctype))) == NULL) {
467 		soap_error1(E_ERROR, "Parsing WSDL: Missing <message> with name '%s'", tmp->children->content);
468 	}
469 
470 	tmp = get_attribute(header->properties, "part");
471 	if (!tmp) {
472 		soap_error0(E_ERROR, "Parsing WSDL: Missing part attribute for <header>");
473 	}
474 	part = get_node_with_attribute_ex(message->children, "part", WSDL_NAMESPACE, "name", (char*)tmp->children->content, NULL);
475 	if (!part) {
476 		soap_error1(E_ERROR, "Parsing WSDL: Missing part '%s' in <message>", tmp->children->content);
477 	}
478 
479 	h = emalloc(sizeof(sdlSoapBindingFunctionHeader));
480 	memset(h, 0, sizeof(sdlSoapBindingFunctionHeader));
481 	h->name = estrdup((char*)tmp->children->content);
482 
483 	tmp = get_attribute(header->properties, "use");
484 	if (tmp && !strncmp((char*)tmp->children->content, "encoded", sizeof("encoded"))) {
485 		h->use = SOAP_ENCODED;
486 	} else {
487 		h->use = SOAP_LITERAL;
488 	}
489 
490 	tmp = get_attribute(header->properties, "namespace");
491 	if (tmp) {
492 		h->ns = estrdup((char*)tmp->children->content);
493 	}
494 
495 	if (h->use == SOAP_ENCODED) {
496 		tmp = get_attribute(header->properties, "encodingStyle");
497 		if (tmp) {
498 			if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
499 				h->encodingStyle = SOAP_ENCODING_1_1;
500 			} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
501 				h->encodingStyle = SOAP_ENCODING_1_2;
502 			} else {
503 				soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
504 			}
505 		} else {
506 			soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
507 		}
508 	}
509 
510 	tmp = get_attribute(part->properties, "type");
511 	if (tmp != NULL) {
512 		h->encode = get_encoder_from_prefix(ctx->sdl, part, tmp->children->content);
513 	} else {
514 		tmp = get_attribute(part->properties, "element");
515 		if (tmp != NULL) {
516 			h->element = get_element(ctx->sdl, part, tmp->children->content);
517 			if (h->element) {
518 				h->encode = h->element->encode;
519 				if (!h->ns && h->element->namens) {
520 					h->ns = estrdup(h->element->namens);
521 				}
522 				if (h->element->name) {
523 					efree(h->name);
524 					h->name = estrdup(h->element->name);
525 				}
526 			}
527 		}
528 	}
529 	if (!fault) {
530 		xmlNodePtr trav = header->children;
531 		while (trav != NULL) {
532 			if (node_is_equal_ex(trav, "headerfault", wsdl_soap_namespace)) {
533 				sdlSoapBindingFunctionHeaderPtr hf = wsdl_soap_binding_header(ctx, trav, wsdl_soap_namespace, 1);
534 				smart_str key = {0};
535 
536 				if (h->headerfaults == NULL) {
537 					h->headerfaults = emalloc(sizeof(HashTable));
538 					zend_hash_init(h->headerfaults, 0, NULL, delete_header, 0);
539 				}
540 
541 				if (hf->ns) {
542 					smart_str_appends(&key,hf->ns);
543 					smart_str_appendc(&key,':');
544 				}
545 				smart_str_appends(&key,hf->name);
546 				smart_str_0(&key);
547 				if (zend_hash_add_ptr(h->headerfaults, key.s, hf) == NULL) {
548 					delete_header_int(hf);
549 				}
550 				smart_str_free(&key);
551 			} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
552 				soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
553 			}
554 			trav = trav->next;
555 		}
556 	}
557 	return h;
558 }
559 
wsdl_soap_binding_body(sdlCtx * ctx,xmlNodePtr node,char * wsdl_soap_namespace,sdlSoapBindingFunctionBody * binding,HashTable * params)560 static void wsdl_soap_binding_body(sdlCtx* ctx, xmlNodePtr node, char* wsdl_soap_namespace, sdlSoapBindingFunctionBody *binding, HashTable* params)
561 {
562 	xmlNodePtr body, trav;
563 	xmlAttrPtr tmp;
564 
565 	trav = node->children;
566 	while (trav != NULL) {
567 		if (node_is_equal_ex(trav, "body", wsdl_soap_namespace)) {
568 			body = trav;
569 
570 			tmp = get_attribute(body->properties, "use");
571 			if (tmp && !strncmp((char*)tmp->children->content, "literal", sizeof("literal"))) {
572 				binding->use = SOAP_LITERAL;
573 			} else {
574 				binding->use = SOAP_ENCODED;
575 			}
576 
577 			tmp = get_attribute(body->properties, "namespace");
578 			if (tmp) {
579 				binding->ns = estrdup((char*)tmp->children->content);
580 			}
581 
582 			tmp = get_attribute(body->properties, "parts");
583 			if (tmp) {
584 				HashTable    ht;
585 				char *parts = (char*)tmp->children->content;
586 
587 				/* Delete all parts those are not in the "parts" attribute */
588 				zend_hash_init(&ht, 0, NULL, delete_parameter, 0);
589 				while (*parts) {
590 					sdlParamPtr param;
591 					int found = 0;
592 					char *end;
593 
594 					while (*parts == ' ') ++parts;
595 					if (*parts == '\0') break;
596 					end = strchr(parts, ' ');
597 					if (end) *end = '\0';
598 					ZEND_HASH_FOREACH_PTR(params, param) {
599 						if (param->paramName &&
600 						    strcmp(parts, param->paramName) == 0) {
601 					  	sdlParamPtr x_param;
602 					  	x_param = emalloc(sizeof(sdlParam));
603 					  	*x_param = *param;
604 					  	param->paramName = NULL;
605 					  	zend_hash_next_index_insert_ptr(&ht, x_param);
606 					  	found = 1;
607 					  	break;
608 						}
609 					} ZEND_HASH_FOREACH_END();
610 					if (!found) {
611 						soap_error1(E_ERROR, "Parsing WSDL: Missing part '%s' in <message>", parts);
612 					}
613 					parts += strlen(parts);
614 					if (end) *end = ' ';
615 				}
616 				zend_hash_destroy(params);
617 				*params = ht;
618 			}
619 
620 			if (binding->use == SOAP_ENCODED) {
621 				tmp = get_attribute(body->properties, "encodingStyle");
622 				if (tmp) {
623 					if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
624 						binding->encodingStyle = SOAP_ENCODING_1_1;
625 					} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
626 						binding->encodingStyle = SOAP_ENCODING_1_2;
627 					} else {
628 						soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
629 					}
630 				} else {
631 					soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
632 				}
633 			}
634 		} else if (node_is_equal_ex(trav, "header", wsdl_soap_namespace)) {
635 			sdlSoapBindingFunctionHeaderPtr h = wsdl_soap_binding_header(ctx, trav, wsdl_soap_namespace, 0);
636 			smart_str key = {0};
637 
638 			if (binding->headers == NULL) {
639 				binding->headers = emalloc(sizeof(HashTable));
640 				zend_hash_init(binding->headers, 0, NULL, delete_header, 0);
641 			}
642 
643 			if (h->ns) {
644 				smart_str_appends(&key,h->ns);
645 				smart_str_appendc(&key,':');
646 			}
647 			smart_str_appends(&key,h->name);
648 			smart_str_0(&key);
649 			if (zend_hash_add_ptr(binding->headers, key.s, h) == NULL) {
650 				delete_header_int(h);
651 			}
652 			smart_str_free(&key);
653 		} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
654 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
655 		}
656 		trav = trav->next;
657 	}
658 }
659 
wsdl_message(sdlCtx * ctx,xmlChar * message_name)660 static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name)
661 {
662 	xmlNodePtr trav, part, message = NULL, tmp;
663 	HashTable* parameters = NULL;
664 	char *ctype;
665 
666 	ctype = strrchr((char*)message_name,':');
667 	if (ctype == NULL) {
668 		ctype = (char*)message_name;
669 	} else {
670 		++ctype;
671 	}
672 	if ((tmp = zend_hash_str_find_ptr(&ctx->messages, ctype, strlen(ctype))) == NULL) {
673 		soap_error1(E_ERROR, "Parsing WSDL: Missing <message> with name '%s'", message_name);
674 	}
675 	message = tmp;
676 
677 	parameters = emalloc(sizeof(HashTable));
678 	zend_hash_init(parameters, 0, NULL, delete_parameter, 0);
679 
680 	trav = message->children;
681 	while (trav != NULL) {
682 		xmlAttrPtr element, type, name;
683 		sdlParamPtr param;
684 
685 		if (trav->ns != NULL && strcmp((char*)trav->ns->href, WSDL_NAMESPACE) != 0) {
686 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>",  SAFE_STR(trav->name));
687 		}
688 		if (node_is_equal(trav,"documentation")) {
689 			trav = trav->next;
690 			continue;
691 		}
692 		if (!node_is_equal(trav,"part")) {
693 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
694 		}
695 		part = trav;
696 		param = emalloc(sizeof(sdlParam));
697 		memset(param,0,sizeof(sdlParam));
698 		param->order = 0;
699 
700 		name = get_attribute(part->properties, "name");
701 		if (name == NULL) {
702 			soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'",  SAFE_STR(message->name));
703 		}
704 
705 		param->paramName = estrdup((char*)name->children->content);
706 
707 		type = get_attribute(part->properties, "type");
708 		if (type != NULL) {
709 			param->encode = get_encoder_from_prefix(ctx->sdl, part, type->children->content);
710 		} else {
711 			element = get_attribute(part->properties, "element");
712 			if (element != NULL) {
713 				param->element = get_element(ctx->sdl, part, element->children->content);
714 				if (param->element) {
715 					param->encode = param->element->encode;
716 				}
717 			}
718 		}
719 
720 		zend_hash_next_index_insert_ptr(parameters, param);
721 
722 		trav = trav->next;
723 	}
724 	return parameters;
725 }
726 
load_wsdl(zval * this_ptr,char * struri)727 static sdlPtr load_wsdl(zval *this_ptr, char *struri)
728 {
729 	sdlCtx ctx;
730 	int i,n;
731 
732 	memset(&ctx,0,sizeof(ctx));
733 	ctx.sdl = emalloc(sizeof(sdl));
734 	memset(ctx.sdl, 0, sizeof(sdl));
735 	ctx.sdl->source = estrdup(struri);
736 	zend_hash_init(&ctx.sdl->functions, 0, NULL, delete_function, 0);
737 
738 	zend_hash_init(&ctx.docs, 0, NULL, delete_document, 0);
739 	zend_hash_init(&ctx.messages, 0, NULL, NULL, 0);
740 	zend_hash_init(&ctx.bindings, 0, NULL, NULL, 0);
741 	zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0);
742 	zend_hash_init(&ctx.services,  0, NULL, NULL, 0);
743 
744 	zend_try {
745 	load_wsdl_ex(this_ptr, struri, &ctx, 0);
746 	schema_pass2(&ctx);
747 
748 	n = zend_hash_num_elements(&ctx.services);
749 	if (n > 0) {
750 		zend_hash_internal_pointer_reset(&ctx.services);
751 		for (i = 0; i < n; i++) {
752 			xmlNodePtr service, tmp;
753 			xmlNodePtr trav, port;
754 			int has_soap_port = 0;
755 
756 			service = tmp = zend_hash_get_current_data_ptr(&ctx.services);
757 
758 			trav = service->children;
759 			while (trav != NULL) {
760 				xmlAttrPtr type, name, bindingAttr, location;
761 				xmlNodePtr portType, operation;
762 				xmlNodePtr address, binding, trav2;
763 				char *ctype;
764 				sdlBindingPtr tmpbinding;
765 				char *wsdl_soap_namespace = NULL;
766 
767 				if (!is_wsdl_element(trav) || node_is_equal(trav,"documentation")) {
768 					trav = trav->next;
769 					continue;
770 				}
771 				if (!node_is_equal(trav,"port")) {
772 					soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
773 				}
774 
775 				port = trav;
776 
777 				tmpbinding = emalloc(sizeof(sdlBinding));
778 				memset(tmpbinding, 0, sizeof(sdlBinding));
779 
780 				bindingAttr = get_attribute(port->properties, "binding");
781 				if (bindingAttr == NULL) {
782 					soap_error0(E_ERROR, "Parsing WSDL: No binding associated with <port>");
783 				}
784 
785 				/* find address and figure out binding type */
786 				address = NULL;
787 				trav2 = port->children;
788 				while (trav2 != NULL) {
789 					if (node_is_equal(trav2,"address") && trav2->ns) {
790 						if (!strncmp((char*)trav2->ns->href, WSDL_SOAP11_NAMESPACE, sizeof(WSDL_SOAP11_NAMESPACE))) {
791 							address = trav2;
792 							wsdl_soap_namespace = WSDL_SOAP11_NAMESPACE;
793 							tmpbinding->bindingType = BINDING_SOAP;
794 						} else if (!strncmp((char*)trav2->ns->href, WSDL_SOAP12_NAMESPACE, sizeof(WSDL_SOAP12_NAMESPACE))) {
795 							address = trav2;
796 							wsdl_soap_namespace = WSDL_SOAP12_NAMESPACE;
797 							tmpbinding->bindingType = BINDING_SOAP;
798 						} else if (!strncmp((char*)trav2->ns->href, RPC_SOAP12_NAMESPACE, sizeof(RPC_SOAP12_NAMESPACE))) {
799 							address = trav2;
800 							wsdl_soap_namespace = RPC_SOAP12_NAMESPACE;
801 							tmpbinding->bindingType = BINDING_SOAP;
802 						} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP11_NAMESPACE, sizeof(WSDL_HTTP11_NAMESPACE))) {
803 							address = trav2;
804 							tmpbinding->bindingType = BINDING_HTTP;
805 						} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP12_NAMESPACE, sizeof(WSDL_HTTP12_NAMESPACE))) {
806 							address = trav2;
807 							tmpbinding->bindingType = BINDING_HTTP;
808 						}
809 					}
810 					if (trav2 != address && is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
811 						soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav2->name));
812 					}
813 				  trav2 = trav2->next;
814 				}
815 				if (!address || tmpbinding->bindingType == BINDING_HTTP) {
816 					if (has_soap_port || trav->next || i < n-1) {
817 						efree(tmpbinding);
818 						trav = trav->next;
819 						continue;
820 					} else if (!address) {
821 						soap_error0(E_ERROR, "Parsing WSDL: No address associated with <port>");
822 					}
823 				}
824 				has_soap_port = 1;
825 
826 				location = get_attribute(address->properties, "location");
827 				if (!location) {
828 					soap_error0(E_ERROR, "Parsing WSDL: No location associated with <port>");
829 				}
830 
831 				tmpbinding->location = estrdup((char*)location->children->content);
832 
833 				ctype = strrchr((char*)bindingAttr->children->content,':');
834 				if (ctype == NULL) {
835 					ctype = (char*)bindingAttr->children->content;
836 				} else {
837 					++ctype;
838 				}
839 				if ((tmp = zend_hash_str_find_ptr(&ctx.bindings, ctype, strlen(ctype))) == NULL) {
840 					soap_error1(E_ERROR, "Parsing WSDL: No <binding> element with name '%s'", ctype);
841 				}
842 				binding = tmp;
843 
844 				if (tmpbinding->bindingType == BINDING_SOAP) {
845 					sdlSoapBindingPtr soapBinding;
846 					xmlNodePtr soapBindingNode;
847 					xmlAttrPtr tmp;
848 
849 					soapBinding = emalloc(sizeof(sdlSoapBinding));
850 					memset(soapBinding, 0, sizeof(sdlSoapBinding));
851 					soapBinding->style = SOAP_DOCUMENT;
852 
853 					soapBindingNode = get_node_ex(binding->children, "binding", wsdl_soap_namespace);
854 					if (soapBindingNode) {
855 						tmp = get_attribute(soapBindingNode->properties, "style");
856 						if (tmp && !strncmp((char*)tmp->children->content, "rpc", sizeof("rpc"))) {
857 							soapBinding->style = SOAP_RPC;
858 						}
859 
860 						tmp = get_attribute(soapBindingNode->properties, "transport");
861 						if (tmp) {
862 							if (strncmp((char*)tmp->children->content, WSDL_HTTP_TRANSPORT, sizeof(WSDL_HTTP_TRANSPORT)) == 0) {
863 								soapBinding->transport = SOAP_TRANSPORT_HTTP;
864 							} else {
865 								/* try the next binding */
866 								efree(soapBinding);
867 								efree(tmpbinding->location);
868 								efree(tmpbinding);
869 								trav = trav->next;
870 								continue;
871 							}
872 						}
873 					}
874 					tmpbinding->bindingAttributes = (void *)soapBinding;
875 				}
876 
877 				name = get_attribute(binding->properties, "name");
878 				if (name == NULL) {
879 					soap_error0(E_ERROR, "Parsing WSDL: Missing 'name' attribute for <binding>");
880 				}
881 				tmpbinding->name = estrdup((char*)name->children->content);
882 
883 				type = get_attribute(binding->properties, "type");
884 				if (type == NULL) {
885 					soap_error0(E_ERROR, "Parsing WSDL: Missing 'type' attribute for <binding>");
886 				}
887 
888 				ctype = strrchr((char*)type->children->content,':');
889 				if (ctype == NULL) {
890 					ctype = (char*)type->children->content;
891 				} else {
892 					++ctype;
893 				}
894 				if ((tmp = zend_hash_str_find_ptr(&ctx.portTypes, ctype, strlen(ctype))) == NULL) {
895 					soap_error1(E_ERROR, "Parsing WSDL: Missing <portType> with name '%s'", name->children->content);
896 				}
897 				portType = tmp;
898 
899 				trav2 = binding->children;
900 				while (trav2 != NULL) {
901 					sdlFunctionPtr function;
902 					xmlNodePtr input, output, fault, portTypeOperation, trav3;
903 					xmlAttrPtr op_name, paramOrder;
904 
905 					if ((tmpbinding->bindingType == BINDING_SOAP &&
906 					    node_is_equal_ex(trav2, "binding", wsdl_soap_namespace)) ||
907 					    !is_wsdl_element(trav2) ||
908 					    node_is_equal(trav2,"documentation")) {
909 						trav2 = trav2->next;
910 						continue;
911 					}
912 					if (!node_is_equal(trav2,"operation")) {
913 						soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav2->name));
914 					}
915 
916 					operation = trav2;
917 
918 					op_name = get_attribute(operation->properties, "name");
919 					if (op_name == NULL) {
920 						soap_error0(E_ERROR, "Parsing WSDL: Missing 'name' attribute for <operation>");
921 					}
922 
923 					trav3 = operation->children;
924 					while  (trav3 != NULL) {
925 						if (tmpbinding->bindingType == BINDING_SOAP &&
926 						    node_is_equal_ex(trav3, "operation", wsdl_soap_namespace)) {
927 						} else if (is_wsdl_element(trav3) &&
928 						           !node_is_equal(trav3,"input") &&
929 						           !node_is_equal(trav3,"output") &&
930 						           !node_is_equal(trav3,"fault") &&
931 						           !node_is_equal(trav3,"documentation")) {
932 							soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav3->name));
933 						}
934 						trav3 = trav3->next;
935 					}
936 
937 					portTypeOperation = get_node_with_attribute_ex(portType->children, "operation", WSDL_NAMESPACE, "name", (char*)op_name->children->content, NULL);
938 					if (portTypeOperation == NULL) {
939 						soap_error1(E_ERROR, "Parsing WSDL: Missing <portType>/<operation> with name '%s'", op_name->children->content);
940 					}
941 
942 					function = emalloc(sizeof(sdlFunction));
943 					memset(function, 0, sizeof(sdlFunction));
944 					function->functionName = estrdup((char*)op_name->children->content);
945 
946 					if (tmpbinding->bindingType == BINDING_SOAP) {
947 						sdlSoapBindingFunctionPtr soapFunctionBinding;
948 						sdlSoapBindingPtr soapBinding;
949 						xmlNodePtr soapOperation;
950 						xmlAttrPtr tmp;
951 
952 						soapFunctionBinding = emalloc(sizeof(sdlSoapBindingFunction));
953 						memset(soapFunctionBinding, 0, sizeof(sdlSoapBindingFunction));
954 						soapBinding = (sdlSoapBindingPtr)tmpbinding->bindingAttributes;
955 						soapFunctionBinding->style = soapBinding->style;
956 
957 						soapOperation = get_node_ex(operation->children, "operation", wsdl_soap_namespace);
958 						if (soapOperation) {
959 							tmp = get_attribute(soapOperation->properties, "soapAction");
960 							if (tmp) {
961 								soapFunctionBinding->soapAction = estrdup((char*)tmp->children->content);
962 							}
963 
964 							tmp = get_attribute(soapOperation->properties, "style");
965 							if (tmp) {
966 								if (!strncmp((char*)tmp->children->content, "rpc", sizeof("rpc"))) {
967 									soapFunctionBinding->style = SOAP_RPC;
968 								} else {
969 									soapFunctionBinding->style = SOAP_DOCUMENT;
970 								}
971 							} else {
972 								soapFunctionBinding->style = soapBinding->style;
973 							}
974 						}
975 
976 						function->bindingAttributes = (void *)soapFunctionBinding;
977 					}
978 
979 					input = get_node_ex(portTypeOperation->children, "input", WSDL_NAMESPACE);
980 					if (input != NULL) {
981 						xmlAttrPtr message;
982 
983 						message = get_attribute(input->properties, "message");
984 						if (message == NULL) {
985 							soap_error1(E_ERROR, "Parsing WSDL: Missing name for <input> of '%s'", op_name->children->content);
986 						}
987 						function->requestParameters = wsdl_message(&ctx, message->children->content);
988 
989 /* FIXME
990 						xmlAttrPtr name = get_attribute(input->properties, "name");
991 						if (name != NULL) {
992 							function->requestName = estrdup(name->children->content);
993 						} else {
994 */
995 						{
996 							function->requestName = estrdup(function->functionName);
997 						}
998 
999 						if (tmpbinding->bindingType == BINDING_SOAP) {
1000 							input = get_node_ex(operation->children, "input", WSDL_NAMESPACE);
1001 							if (input != NULL) {
1002 								sdlSoapBindingFunctionPtr soapFunctionBinding = function->bindingAttributes;
1003 								wsdl_soap_binding_body(&ctx, input, wsdl_soap_namespace, &soapFunctionBinding->input, function->requestParameters);
1004 							}
1005 						}
1006 					}
1007 
1008 					output = get_node_ex(portTypeOperation->children, "output", WSDL_NAMESPACE);
1009 					if (output != NULL) {
1010 						xmlAttrPtr message;
1011 
1012 						message = get_attribute(output->properties, "message");
1013 						if (message == NULL) {
1014 							soap_error1(E_ERROR, "Parsing WSDL: Missing name for <output> of '%s'", op_name->children->content);
1015 						}
1016 						function->responseParameters = wsdl_message(&ctx, message->children->content);
1017 
1018 /* FIXME
1019 						xmlAttrPtr name = get_attribute(output->properties, "name");
1020 						if (name != NULL) {
1021 							function->responseName = estrdup(name->children->content);
1022 						} else if (input == NULL) {
1023 							function->responseName = estrdup(function->functionName);
1024 						} else {
1025 */
1026 						{
1027 							int len = strlen(function->functionName);
1028 							function->responseName = emalloc(len + sizeof("Response"));
1029 							memcpy(function->responseName, function->functionName, len);
1030 							memcpy(function->responseName+len, "Response", sizeof("Response"));
1031 						}
1032 
1033 						if (tmpbinding->bindingType == BINDING_SOAP) {
1034 							output = get_node_ex(operation->children, "output", WSDL_NAMESPACE);
1035 							if (output != NULL) {
1036 								sdlSoapBindingFunctionPtr soapFunctionBinding = function->bindingAttributes;
1037 								wsdl_soap_binding_body(&ctx, output, wsdl_soap_namespace, &soapFunctionBinding->output, function->responseParameters);
1038 							}
1039 						}
1040 					}
1041 
1042 					paramOrder = get_attribute(portTypeOperation->properties, "parameterOrder");
1043 					if (paramOrder) {
1044 						/* FIXME: */
1045 					}
1046 
1047 					fault = portTypeOperation->children;
1048 					while (fault != NULL) {
1049 						if (node_is_equal_ex(fault, "fault", WSDL_NAMESPACE)) {
1050 							xmlAttrPtr message, name;
1051 							sdlFaultPtr f;
1052 
1053 							name = get_attribute(fault->properties, "name");
1054 							if (name == NULL) {
1055 								soap_error1(E_ERROR, "Parsing WSDL: Missing name for <fault> of '%s'", op_name->children->content);
1056 							}
1057 							message = get_attribute(fault->properties, "message");
1058 							if (message == NULL) {
1059 								soap_error1(E_ERROR, "Parsing WSDL: Missing name for <output> of '%s'", op_name->children->content);
1060 							}
1061 
1062 							f = emalloc(sizeof(sdlFault));
1063 							memset(f, 0, sizeof(sdlFault));
1064 
1065 							f->name = estrdup((char*)name->children->content);
1066 							f->details = wsdl_message(&ctx, message->children->content);
1067 							if (f->details == NULL || zend_hash_num_elements(f->details) > 1) {
1068 								soap_error1(E_ERROR, "Parsing WSDL: The fault message '%s' must have a single part", message->children->content);
1069 							}
1070 
1071 							if (tmpbinding->bindingType == BINDING_SOAP) {
1072 								xmlNodePtr soap_fault = get_node_with_attribute_ex(operation->children, "fault", WSDL_NAMESPACE, "name", f->name, NULL);
1073 								if (soap_fault != NULL) {
1074 									xmlNodePtr trav = soap_fault->children;
1075 									while (trav != NULL) {
1076 										if (node_is_equal_ex(trav, "fault", wsdl_soap_namespace)) {
1077 											xmlAttrPtr tmp;
1078 										  sdlSoapBindingFunctionFaultPtr binding;
1079 
1080 											binding = f->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunctionFault));
1081 											memset(f->bindingAttributes, 0, sizeof(sdlSoapBindingFunctionFault));
1082 
1083 											tmp = get_attribute(trav->properties, "use");
1084 											if (tmp && !strncmp((char*)tmp->children->content, "encoded", sizeof("encoded"))) {
1085 												binding->use = SOAP_ENCODED;
1086 											} else {
1087 												binding->use = SOAP_LITERAL;
1088 											}
1089 
1090 											tmp = get_attribute(trav->properties, "namespace");
1091 											if (tmp) {
1092 												binding->ns = estrdup((char*)tmp->children->content);
1093 											}
1094 
1095 											if (binding->use == SOAP_ENCODED) {
1096 												tmp = get_attribute(trav->properties, "encodingStyle");
1097 												if (tmp) {
1098 													if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
1099 														binding->encodingStyle = SOAP_ENCODING_1_1;
1100 													} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
1101 														binding->encodingStyle = SOAP_ENCODING_1_2;
1102 													} else {
1103 														soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
1104 													}
1105 												} else {
1106 													soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
1107 												}
1108 											}
1109 										} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
1110 											soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
1111 										}
1112 										trav = trav->next;
1113 									}
1114 								}
1115 							}
1116 							if (function->faults == NULL) {
1117 								function->faults = emalloc(sizeof(HashTable));
1118 								zend_hash_init(function->faults, 0, NULL, delete_fault, 0);
1119 							}
1120 							if (zend_hash_str_add_ptr(function->faults, f->name, strlen(f->name), f) == NULL) {
1121 								soap_error2(E_ERROR, "Parsing WSDL: <fault> with name '%s' already defined in '%s'", f->name, op_name->children->content);
1122 							}
1123 						}
1124 						fault = fault->next;
1125 					}
1126 
1127 					function->binding = tmpbinding;
1128 
1129 					{
1130 						char *tmp = estrdup(function->functionName);
1131 						int  len = strlen(tmp);
1132 
1133 						if (zend_hash_str_add_ptr(&ctx.sdl->functions, php_strtolower(tmp, len), len, function) == NULL) {
1134 							zend_hash_next_index_insert_ptr(&ctx.sdl->functions, function);
1135 						}
1136 						efree(tmp);
1137 						if (function->requestName != NULL && strcmp(function->requestName,function->functionName) != 0) {
1138 							if (ctx.sdl->requests == NULL) {
1139 								ctx.sdl->requests = emalloc(sizeof(HashTable));
1140 								zend_hash_init(ctx.sdl->requests, 0, NULL, NULL, 0);
1141 							}
1142 							tmp = estrdup(function->requestName);
1143 							len = strlen(tmp);
1144 							zend_hash_str_add_ptr(ctx.sdl->requests, php_strtolower(tmp, len), len, function);
1145 							efree(tmp);
1146 						}
1147 					}
1148 					trav2 = trav2->next;
1149 				}
1150 
1151 				if (!ctx.sdl->bindings) {
1152 					ctx.sdl->bindings = emalloc(sizeof(HashTable));
1153 					zend_hash_init(ctx.sdl->bindings, 0, NULL, delete_binding, 0);
1154 				}
1155 
1156 				if (!zend_hash_str_add_ptr(ctx.sdl->bindings, tmpbinding->name, strlen(tmpbinding->name), tmpbinding)) {
1157 					zend_hash_next_index_insert_ptr(ctx.sdl->bindings, tmpbinding);
1158 				}
1159 				trav= trav->next;
1160 			}
1161 
1162 			zend_hash_move_forward(&ctx.services);
1163 		}
1164 	} else {
1165 		soap_error0(E_ERROR, "Parsing WSDL: Couldn't bind to service");
1166 	}
1167 
1168 	if (ctx.sdl->bindings == NULL || ctx.sdl->bindings->nNumOfElements == 0) {
1169 		soap_error0(E_ERROR, "Parsing WSDL: Could not find any usable binding services in WSDL.");
1170 	}
1171 
1172 	} zend_catch {
1173 		/* Avoid persistent memory leak. */
1174 		zend_hash_destroy(&ctx.docs);
1175 		zend_bailout();
1176 	} zend_end_try();
1177 
1178 	zend_hash_destroy(&ctx.messages);
1179 	zend_hash_destroy(&ctx.bindings);
1180 	zend_hash_destroy(&ctx.portTypes);
1181 	zend_hash_destroy(&ctx.services);
1182 	zend_hash_destroy(&ctx.docs);
1183 
1184 	return ctx.sdl;
1185 }
1186 
1187 #define WSDL_CACHE_VERSION 0x10
1188 
1189 #define WSDL_CACHE_GET(ret,type,buf)   memcpy(&ret,*buf,sizeof(type)); *buf += sizeof(type);
1190 #define WSDL_CACHE_GET_INT(ret,buf)    ret = ((unsigned char)(*buf)[0])|((unsigned char)(*buf)[1]<<8)|((unsigned char)(*buf)[2]<<16)|((unsigned)(*buf)[3]<<24); *buf += 4;
1191 #define WSDL_CACHE_GET_1(ret,type,buf) ret = (type)(**buf); (*buf)++;
1192 #define WSDL_CACHE_GET_N(ret,n,buf)    memcpy(ret,*buf,n); *buf += n;
1193 #define WSDL_CACHE_SKIP(n,buf)         *buf += n;
1194 
1195 #define WSDL_CACHE_PUT_INT(val,buf)    smart_str_appendc(buf,(char)(val & 0xff)); \
1196                                        smart_str_appendc(buf,(char)((val >> 8) & 0xff)); \
1197                                        smart_str_appendc(buf,(char)((val >> 16) & 0xff)); \
1198                                        smart_str_appendc(buf,(char)((val >> 24) & 0xff));
1199 #define WSDL_CACHE_PUT_1(val,buf)      smart_str_appendc(buf,val);
1200 #define WSDL_CACHE_PUT_N(val,n,buf)    smart_str_appendl(buf,(char*)val,n);
1201 
1202 #define WSDL_NO_STRING_MARKER 0x7fffffff
1203 
sdl_deserialize_string(char ** in)1204 static char* sdl_deserialize_string(char **in)
1205 {
1206 	char *s;
1207 	int len;
1208 
1209 	WSDL_CACHE_GET_INT(len, in);
1210 	if (len == WSDL_NO_STRING_MARKER) {
1211 		return NULL;
1212 	} else {
1213 		s = emalloc(len+1);
1214 		WSDL_CACHE_GET_N(s, len, in);
1215 		s[len] = '\0';
1216 		return s;
1217 	}
1218 }
1219 
sdl_deserialize_key(HashTable * ht,void * data,char ** in)1220 static void sdl_deserialize_key(HashTable* ht, void* data, char **in)
1221 {
1222 	int len;
1223 
1224 	WSDL_CACHE_GET_INT(len, in);
1225 	if (len == WSDL_NO_STRING_MARKER) {
1226 		zend_hash_next_index_insert_ptr(ht, data);
1227 	} else {
1228 		zend_hash_str_add_ptr(ht, *in, len, data);
1229 		WSDL_CACHE_SKIP(len, in);
1230 	}
1231 }
1232 
sdl_deserialize_attribute(sdlAttributePtr attr,encodePtr * encoders,char ** in)1233 static void sdl_deserialize_attribute(sdlAttributePtr attr, encodePtr *encoders, char **in)
1234 {
1235 	int i;
1236 
1237 	attr->name = sdl_deserialize_string(in);
1238 	attr->namens = sdl_deserialize_string(in);
1239 	attr->ref = sdl_deserialize_string(in);
1240 	attr->def = sdl_deserialize_string(in);
1241 	attr->fixed = sdl_deserialize_string(in);
1242 	WSDL_CACHE_GET_1(attr->form, sdlForm, in);
1243 	WSDL_CACHE_GET_1(attr->use, sdlUse, in);
1244 	WSDL_CACHE_GET_INT(i, in);
1245 	attr->encode = encoders[i];
1246 	WSDL_CACHE_GET_INT(i, in);
1247 	if (i > 0) {
1248 		attr->extraAttributes = emalloc(sizeof(HashTable));
1249 		zend_hash_init(attr->extraAttributes, i, NULL, delete_extra_attribute, 0);
1250 		while (i > 0) {
1251 			sdlExtraAttributePtr x = emalloc(sizeof(sdlExtraAttribute));
1252 			sdl_deserialize_key(attr->extraAttributes, x, in);
1253 			x->ns = sdl_deserialize_string(in);
1254 			x->val = sdl_deserialize_string(in);
1255 			--i;
1256 		}
1257 	}
1258 }
1259 
sdl_deserialize_resriction_int(char ** in)1260 static sdlRestrictionIntPtr sdl_deserialize_resriction_int(char **in)
1261 {
1262 	if (**in == 1) {
1263 		sdlRestrictionIntPtr x = emalloc(sizeof(sdlRestrictionInt));
1264 		WSDL_CACHE_SKIP(1, in);
1265 		WSDL_CACHE_GET_INT(x->value, in);
1266 		WSDL_CACHE_GET_1(x->fixed, char, in);
1267 		return x;
1268 	} else {
1269 		WSDL_CACHE_SKIP(1, in);
1270 		return NULL;
1271 	}
1272 }
1273 
sdl_deserialize_resriction_char(char ** in)1274 static sdlRestrictionCharPtr sdl_deserialize_resriction_char(char **in)
1275 {
1276 	if (**in == 1) {
1277 		sdlRestrictionCharPtr x = emalloc(sizeof(sdlRestrictionChar));
1278 		WSDL_CACHE_SKIP(1, in);
1279 		x->value = sdl_deserialize_string(in);
1280 		WSDL_CACHE_GET_1(x->fixed, char, in);
1281 		return x;
1282 	} else {
1283 		WSDL_CACHE_SKIP(1, in);
1284 		return NULL;
1285 	}
1286 }
1287 
sdl_deserialize_model(sdlTypePtr * types,sdlTypePtr * elements,char ** in)1288 static sdlContentModelPtr sdl_deserialize_model(sdlTypePtr *types, sdlTypePtr *elements, char **in)
1289 {
1290 	int i;
1291 	sdlContentModelPtr model = emalloc(sizeof(sdlContentModel));
1292 
1293 	WSDL_CACHE_GET_1(model->kind, sdlContentKind, in);
1294 	WSDL_CACHE_GET_INT(model->min_occurs, in);
1295 	WSDL_CACHE_GET_INT(model->max_occurs, in);
1296 	switch (model->kind) {
1297 		case XSD_CONTENT_ELEMENT:
1298 			WSDL_CACHE_GET_INT(i, in);
1299 			model->u.element = elements[i];
1300 			break;
1301 		case XSD_CONTENT_SEQUENCE:
1302 		case XSD_CONTENT_ALL:
1303 		case XSD_CONTENT_CHOICE:
1304 			WSDL_CACHE_GET_INT(i, in);
1305 			model->u.content = emalloc(sizeof(HashTable));
1306 			zend_hash_init(model->u.content, i, NULL, delete_model, 0);
1307 			while (i > 0) {
1308 				sdlContentModelPtr x = sdl_deserialize_model(types, elements, in);
1309 				zend_hash_next_index_insert_ptr(model->u.content, x);
1310 				i--;
1311 			}
1312 			break;
1313 		case XSD_CONTENT_GROUP_REF:
1314 			model->u.group_ref = sdl_deserialize_string(in);
1315 			break;
1316 		case XSD_CONTENT_GROUP:
1317 			WSDL_CACHE_GET_INT(i, in);
1318 			model->u.group = types[i];
1319 			break;
1320 		default:
1321 			break;
1322 	}
1323 	return model;
1324 }
1325 
sdl_deserialize_type(sdlTypePtr type,sdlTypePtr * types,encodePtr * encoders,char ** in)1326 static void sdl_deserialize_type(sdlTypePtr type, sdlTypePtr *types, encodePtr *encoders, char **in)
1327 {
1328 	int i;
1329 	sdlTypePtr *elements = NULL;
1330 
1331 	WSDL_CACHE_GET_1(type->kind, sdlTypeKind, in);
1332 	type->name = sdl_deserialize_string(in);
1333 	type->namens = sdl_deserialize_string(in);
1334 	type->def = sdl_deserialize_string(in);
1335 	type->fixed = sdl_deserialize_string(in);
1336 	type->ref = sdl_deserialize_string(in);
1337 	WSDL_CACHE_GET_1(type->nillable, char, in);
1338 	WSDL_CACHE_GET_1(type->form, sdlForm, in);
1339 
1340 	WSDL_CACHE_GET_INT(i, in);
1341 	type->encode = encoders[i];
1342 
1343 	if (**in == 1) {
1344 		WSDL_CACHE_SKIP(1, in);
1345 		type->restrictions = emalloc(sizeof(sdlRestrictions));
1346 		/*memset(type->restrictions, 0, sizeof(sdlRestrictions));*/
1347 		type->restrictions->minExclusive = sdl_deserialize_resriction_int(in);
1348 		type->restrictions->minInclusive = sdl_deserialize_resriction_int(in);
1349 		type->restrictions->maxExclusive = sdl_deserialize_resriction_int(in);
1350 		type->restrictions->maxInclusive = sdl_deserialize_resriction_int(in);
1351 		type->restrictions->totalDigits = sdl_deserialize_resriction_int(in);
1352 		type->restrictions->fractionDigits = sdl_deserialize_resriction_int(in);
1353 		type->restrictions->length = sdl_deserialize_resriction_int(in);
1354 		type->restrictions->minLength = sdl_deserialize_resriction_int(in);
1355 		type->restrictions->maxLength = sdl_deserialize_resriction_int(in);
1356 		type->restrictions->whiteSpace = sdl_deserialize_resriction_char(in);
1357 		type->restrictions->pattern = sdl_deserialize_resriction_char(in);
1358 		WSDL_CACHE_GET_INT(i, in);
1359 		if (i > 0) {
1360 			type->restrictions->enumeration = emalloc(sizeof(HashTable));
1361 			zend_hash_init(type->restrictions->enumeration, i, NULL, delete_restriction_var_char, 0);
1362 			while (i > 0) {
1363 				sdlRestrictionCharPtr x = sdl_deserialize_resriction_char(in);
1364 				sdl_deserialize_key(type->restrictions->enumeration, x, in);
1365 				--i;
1366 			}
1367 		} else {
1368 			type->restrictions->enumeration = NULL;
1369 		}
1370 	} else {
1371 		WSDL_CACHE_SKIP(1, in);
1372 	}
1373 
1374 	WSDL_CACHE_GET_INT(i, in);
1375 	if (i > 0) {
1376 		elements = safe_emalloc((i+1), sizeof(sdlTypePtr), 0);
1377 		elements[0] = NULL;
1378 		type->elements = emalloc(sizeof(HashTable));
1379 		zend_hash_init(type->elements, i, NULL, delete_type, 0);
1380 		while (i > 0) {
1381 			sdlTypePtr t = emalloc(sizeof(sdlType));
1382 			memset(t, 0, sizeof(sdlType));
1383 			sdl_deserialize_key(type->elements, t, in);
1384 			sdl_deserialize_type(t, types, encoders, in);
1385 			elements[i] = t;
1386 			--i;
1387 		}
1388 	}
1389 
1390 	WSDL_CACHE_GET_INT(i, in);
1391 	if (i > 0) {
1392 		type->attributes = emalloc(sizeof(HashTable));
1393 		zend_hash_init(type->attributes, i, NULL, delete_attribute, 0);
1394 		while (i > 0) {
1395 			sdlAttributePtr attr = emalloc(sizeof(sdlAttribute));
1396 			memset(attr, 0, sizeof(sdlAttribute));
1397 			sdl_deserialize_key(type->attributes, attr, in);
1398 			sdl_deserialize_attribute(attr, encoders, in);
1399 			--i;
1400 		}
1401 	}
1402 
1403 	if (**in != 0) {
1404 		WSDL_CACHE_SKIP(1, in);
1405 		type->model = sdl_deserialize_model(types, elements, in);
1406 	} else {
1407 		WSDL_CACHE_SKIP(1, in);
1408 	}
1409 	if (elements != NULL) {
1410 		efree(elements);
1411 	}
1412 }
1413 
sdl_deserialize_encoder(encodePtr enc,sdlTypePtr * types,char ** in)1414 static void sdl_deserialize_encoder(encodePtr enc, sdlTypePtr *types, char **in)
1415 {
1416 	int i;
1417 
1418 	WSDL_CACHE_GET_INT(enc->details.type, in);
1419 	enc->details.type_str = sdl_deserialize_string(in);
1420 	enc->details.ns = sdl_deserialize_string(in);
1421 	WSDL_CACHE_GET_INT(i, in);
1422 	enc->details.sdl_type = types[i];
1423 	enc->to_xml = sdl_guess_convert_xml;
1424 	enc->to_zval = sdl_guess_convert_zval;
1425 
1426 	if (enc->details.sdl_type == NULL) {
1427 		int ns_len = strlen(enc->details.ns);
1428 		int type_len = strlen(enc->details.type_str);
1429 
1430 		if (((ns_len == sizeof(SOAP_1_1_ENC_NAMESPACE)-1 &&
1431 		      memcmp(enc->details.ns, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1) == 0) ||
1432 		     (ns_len == sizeof(SOAP_1_2_ENC_NAMESPACE)-1 &&
1433 		      memcmp(enc->details.ns, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1) == 0))) {
1434 			char *enc_nscat;
1435 			int enc_ns_len;
1436 			int enc_len;
1437 			encodePtr real_enc;
1438 
1439 			enc_ns_len = sizeof(XSD_NAMESPACE)-1;
1440 			enc_len = enc_ns_len + type_len + 1;
1441 			enc_nscat = emalloc(enc_len + 1);
1442 			memcpy(enc_nscat, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1);
1443 			enc_nscat[enc_ns_len] = ':';
1444 			memcpy(enc_nscat+enc_ns_len+1, enc->details.type_str, type_len);
1445 			enc_nscat[enc_len] = '\0';
1446 
1447 			real_enc = get_encoder_ex(NULL, enc_nscat, enc_len);
1448 			efree(enc_nscat);
1449 			if (real_enc) {
1450 				enc->to_zval = real_enc->to_zval;
1451 				enc->to_xml = real_enc->to_xml;
1452 			}
1453 		}
1454 	}
1455 }
1456 
sdl_deserialize_soap_body(sdlSoapBindingFunctionBodyPtr body,encodePtr * encoders,sdlTypePtr * types,char ** in)1457 static void sdl_deserialize_soap_body(sdlSoapBindingFunctionBodyPtr body, encodePtr *encoders, sdlTypePtr *types, char **in)
1458 {
1459 	int i, j, n;
1460 
1461 	WSDL_CACHE_GET_1(body->use, sdlEncodingUse, in);
1462 	if (body->use == SOAP_ENCODED) {
1463 		WSDL_CACHE_GET_1(body->encodingStyle, sdlRpcEncodingStyle, in);
1464 	} else {
1465 		body->encodingStyle = SOAP_ENCODING_DEFAULT;
1466 	}
1467 	body->ns = sdl_deserialize_string(in);
1468 	WSDL_CACHE_GET_INT(i, in);
1469 	if (i > 0) {
1470 		body->headers = emalloc(sizeof(HashTable));
1471 		zend_hash_init(body->headers, i, NULL, delete_header, 0);
1472 		while (i > 0) {
1473 			sdlSoapBindingFunctionHeaderPtr tmp = emalloc(sizeof(sdlSoapBindingFunctionHeader));
1474 			memset(tmp, 0, sizeof(sdlSoapBindingFunctionHeader));
1475 			sdl_deserialize_key(body->headers, tmp, in);
1476 			WSDL_CACHE_GET_1(tmp->use, sdlEncodingUse, in);
1477 			if (tmp->use == SOAP_ENCODED) {
1478 				WSDL_CACHE_GET_1(tmp->encodingStyle, sdlRpcEncodingStyle, in);
1479 			} else {
1480 				tmp->encodingStyle = SOAP_ENCODING_DEFAULT;
1481 			}
1482 			tmp->name = sdl_deserialize_string(in);
1483 			tmp->ns = sdl_deserialize_string(in);
1484 			WSDL_CACHE_GET_INT(n, in);
1485 			tmp->encode = encoders[n];
1486 			WSDL_CACHE_GET_INT(n, in);
1487 			tmp->element = types[n];
1488 			--i;
1489 			WSDL_CACHE_GET_INT(j, in);
1490 			if (j > 0) {
1491 				tmp->headerfaults = emalloc(sizeof(HashTable));
1492 				zend_hash_init(tmp->headerfaults, i, NULL, delete_header, 0);
1493 				while (j > 0) {
1494 					sdlSoapBindingFunctionHeaderPtr tmp2 = emalloc(sizeof(sdlSoapBindingFunctionHeader));
1495 					memset(tmp2, 0, sizeof(sdlSoapBindingFunctionHeader));
1496 					sdl_deserialize_key(tmp->headerfaults, tmp2, in);
1497 					WSDL_CACHE_GET_1(tmp2->use, sdlEncodingUse, in);
1498 					if (tmp2->use == SOAP_ENCODED) {
1499 						WSDL_CACHE_GET_1(tmp2->encodingStyle, sdlRpcEncodingStyle, in);
1500 					} else {
1501 						tmp2->encodingStyle = SOAP_ENCODING_DEFAULT;
1502 					}
1503 					tmp2->name = sdl_deserialize_string(in);
1504 					tmp2->ns = sdl_deserialize_string(in);
1505 					WSDL_CACHE_GET_INT(n, in);
1506 					tmp2->encode = encoders[n];
1507 					WSDL_CACHE_GET_INT(n, in);
1508 					tmp2->element = types[n];
1509 					--j;
1510 				}
1511 			}
1512 		}
1513 	}
1514 }
1515 
sdl_deserialize_parameters(encodePtr * encoders,sdlTypePtr * types,char ** in)1516 static HashTable* sdl_deserialize_parameters(encodePtr *encoders, sdlTypePtr *types, char **in)
1517 {
1518 	int i, n;
1519 	HashTable *ht;
1520 
1521 	WSDL_CACHE_GET_INT(i, in);
1522 	if (i == 0) {return NULL;}
1523 	ht = emalloc(sizeof(HashTable));
1524 	zend_hash_init(ht, i, NULL, delete_parameter, 0);
1525 	while (i > 0) {
1526 		sdlParamPtr param = emalloc(sizeof(sdlParam));
1527 		sdl_deserialize_key(ht, param, in);
1528 		param->paramName = sdl_deserialize_string(in);
1529 		WSDL_CACHE_GET_INT(param->order, in);
1530 		WSDL_CACHE_GET_INT(n, in);
1531 		param->encode = encoders[n];
1532 		WSDL_CACHE_GET_INT(n, in);
1533 		param->element = types[n];
1534 		--i;
1535 	}
1536 	return ht;
1537 }
1538 
get_sdl_from_cache(const char * fn,const char * uri,time_t t,time_t * cached)1539 static sdlPtr get_sdl_from_cache(const char *fn, const char *uri, time_t t, time_t *cached)
1540 {
1541 	sdlPtr sdl;
1542 	time_t old_t;
1543 	int  i, num_groups, num_types, num_elements, num_encoders, num_bindings, num_func;
1544 	sdlFunctionPtr *functions = NULL;
1545 	sdlBindingPtr *bindings;
1546 	sdlTypePtr *types;
1547 	encodePtr *encoders;
1548 	const encode *enc;
1549 
1550 	int f;
1551 	struct stat st;
1552 	char *in, *buf;
1553 
1554 	f = open(fn, O_RDONLY|O_BINARY);
1555 	if (f < 0) {
1556 		return NULL;
1557 	}
1558 	if (fstat(f, &st) != 0) {
1559 		close(f);
1560 		return NULL;
1561 	}
1562 	buf = in = emalloc(st.st_size);
1563 	if (read(f, in, st.st_size) != st.st_size) {
1564 		close(f);
1565 		efree(in);
1566 		return NULL;
1567 	}
1568 	close(f);
1569 
1570 	if (strncmp(in,"wsdl",4) != 0 || in[4] != WSDL_CACHE_VERSION || in[5] != '\0') {
1571 		unlink(fn);
1572 		efree(buf);
1573 		return NULL;
1574 	}
1575 	in += 6;
1576 
1577 	WSDL_CACHE_GET(old_t, time_t, &in);
1578 	if (old_t < t) {
1579 		unlink(fn);
1580 		efree(buf);
1581 		return NULL;
1582 	}
1583 	*cached = old_t;
1584 
1585 	WSDL_CACHE_GET_INT(i, &in);
1586 	if (i == 0 && strncmp(in, uri, i) != 0) {
1587 		unlink(fn);
1588 		efree(buf);
1589 		return NULL;
1590 	}
1591 	WSDL_CACHE_SKIP(i, &in);
1592 
1593 	sdl = emalloc(sizeof(*sdl));
1594 	memset(sdl, 0, sizeof(*sdl));
1595 
1596 	sdl->source = sdl_deserialize_string(&in);
1597 	sdl->target_ns = sdl_deserialize_string(&in);
1598 
1599 	WSDL_CACHE_GET_INT(num_groups, &in);
1600 	WSDL_CACHE_GET_INT(num_types, &in);
1601 	WSDL_CACHE_GET_INT(num_elements, &in);
1602 	WSDL_CACHE_GET_INT(num_encoders, &in);
1603 
1604 	i = num_groups+num_types+num_elements;
1605 	types = safe_emalloc((i+1), sizeof(sdlTypePtr), 0);
1606 	types[0] = NULL;
1607 	while (i > 0) {
1608 		types[i] = emalloc(sizeof(sdlType));
1609 		memset(types[i], 0, sizeof(sdlType));
1610 		i--;
1611 	}
1612 
1613 	i = num_encoders;
1614 	enc = defaultEncoding;
1615 	while (enc->details.type != END_KNOWN_TYPES) {
1616 		i++; enc++;
1617 	}
1618 	encoders = safe_emalloc((i+1), sizeof(encodePtr), 0);
1619 	i = num_encoders;
1620 	encoders[0] = NULL;
1621 	while (i > 0) {
1622 		encoders[i] = emalloc(sizeof(encode));
1623 		memset(encoders[i], 0, sizeof(encode));
1624 		i--;
1625 	}
1626 	i = num_encoders;
1627 	enc = defaultEncoding;
1628 	while (enc->details.type != END_KNOWN_TYPES) {
1629 		encoders[++i] = (encodePtr)enc++;
1630 	}
1631 
1632 	i = 1;
1633 	if (num_groups > 0) {
1634 		sdl->groups = emalloc(sizeof(HashTable));
1635 		zend_hash_init(sdl->groups, num_groups, NULL, delete_type, 0);
1636 		while (i < num_groups+1) {
1637 			sdl_deserialize_key(sdl->groups, types[i], &in);
1638 			sdl_deserialize_type(types[i], types, encoders, &in);
1639 			i++;
1640 		}
1641 	}
1642 
1643 	if (num_types > 0) {
1644 		sdl->types = emalloc(sizeof(HashTable));
1645 		zend_hash_init(sdl->types, num_types, NULL, delete_type, 0);
1646 		while (i < num_groups+num_types+1) {
1647 			sdl_deserialize_key(sdl->types, types[i], &in);
1648 			sdl_deserialize_type(types[i], types, encoders, &in);
1649 			i++;
1650 		}
1651 	}
1652 
1653 	if (num_elements > 0) {
1654 		sdl->elements = emalloc(sizeof(HashTable));
1655 		zend_hash_init(sdl->elements, num_elements, NULL, delete_type, 0);
1656 		while (i < num_groups+num_types+num_elements+1) {
1657 			sdl_deserialize_key(sdl->elements, types[i], &in);
1658 			sdl_deserialize_type(types[i], types, encoders, &in);
1659 			i++;
1660 		}
1661 	}
1662 
1663 	i = 1;
1664 	if (num_encoders > 0) {
1665 		sdl->encoders = emalloc(sizeof(HashTable));
1666 		zend_hash_init(sdl->encoders, num_encoders, NULL, delete_encoder, 0);
1667 		while (i < num_encoders+1) {
1668 			sdl_deserialize_key(sdl->encoders, encoders[i], &in);
1669 			sdl_deserialize_encoder(encoders[i], types, &in);
1670 			i++;
1671 		}
1672 	}
1673 
1674 	/* deserialize bindings */
1675 	WSDL_CACHE_GET_INT(num_bindings, &in);
1676 	bindings = safe_emalloc(num_bindings, sizeof(sdlBindingPtr), 0);
1677 	if (num_bindings > 0) {
1678 		sdl->bindings = emalloc(sizeof(HashTable));
1679 		zend_hash_init(sdl->bindings, num_bindings, NULL, delete_binding, 0);
1680 		for (i = 0; i < num_bindings; i++) {
1681 			sdlBindingPtr binding = emalloc(sizeof(sdlBinding));
1682 			memset(binding, 0, sizeof(sdlBinding));
1683 			sdl_deserialize_key(sdl->bindings, binding, &in);
1684 			binding->name = sdl_deserialize_string(&in);
1685 			binding->location = sdl_deserialize_string(&in);
1686 			WSDL_CACHE_GET_1(binding->bindingType,sdlBindingType,&in);
1687 			if (binding->bindingType == BINDING_SOAP && *in != 0) {
1688 			  sdlSoapBindingPtr soap_binding = binding->bindingAttributes = emalloc(sizeof(sdlSoapBinding));
1689 				WSDL_CACHE_GET_1(soap_binding->style,sdlEncodingStyle,&in);
1690 				WSDL_CACHE_GET_1(soap_binding->transport,sdlTransport,&in);
1691 			} else {
1692 				WSDL_CACHE_SKIP(1,&in);
1693 			}
1694 			bindings[i] = binding;
1695 		}
1696 	}
1697 
1698 	/* deserialize functions */
1699 	WSDL_CACHE_GET_INT(num_func, &in);
1700 	zend_hash_init(&sdl->functions, num_func, NULL, delete_function, 0);
1701 	if (num_func > 0) {
1702 		functions = safe_emalloc(num_func, sizeof(sdlFunctionPtr), 0);
1703 		for (i = 0; i < num_func; i++) {
1704 			int binding_num, num_faults;
1705 			sdlFunctionPtr func = emalloc(sizeof(sdlFunction));
1706 			sdl_deserialize_key(&sdl->functions, func, &in);
1707 			func->functionName = sdl_deserialize_string(&in);
1708 			func->requestName = sdl_deserialize_string(&in);
1709 			func->responseName = sdl_deserialize_string(&in);
1710 
1711 			WSDL_CACHE_GET_INT(binding_num, &in);
1712 			if (binding_num == 0) {
1713 				func->binding = NULL;
1714 			} else {
1715 				func->binding = bindings[binding_num-1];
1716 			}
1717 			if (func->binding && func->binding->bindingType == BINDING_SOAP && *in != 0) {
1718 				sdlSoapBindingFunctionPtr binding = func->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunction));
1719 				memset(binding, 0, sizeof(sdlSoapBindingFunction));
1720 				WSDL_CACHE_GET_1(binding->style,sdlEncodingStyle,&in);
1721 				binding->soapAction = sdl_deserialize_string(&in);
1722 				sdl_deserialize_soap_body(&binding->input, encoders, types, &in);
1723 				sdl_deserialize_soap_body(&binding->output, encoders, types, &in);
1724 			} else {
1725 				WSDL_CACHE_SKIP(1, &in);
1726 				func->bindingAttributes = NULL;
1727 			}
1728 
1729 			func->requestParameters = sdl_deserialize_parameters(encoders, types, &in);
1730 			func->responseParameters = sdl_deserialize_parameters(encoders, types, &in);
1731 
1732 			WSDL_CACHE_GET_INT(num_faults, &in);
1733 			if (num_faults > 0) {
1734 			  int j;
1735 
1736 				func->faults = emalloc(sizeof(HashTable));
1737 				zend_hash_init(func->faults, num_faults, NULL, delete_fault, 0);
1738 
1739 				for (j = 0; j < num_faults; j++) {
1740 					sdlFaultPtr fault = emalloc(sizeof(sdlFault));
1741 
1742 					sdl_deserialize_key(func->faults, fault, &in);
1743 					fault->name =sdl_deserialize_string(&in);
1744 					fault->details =sdl_deserialize_parameters(encoders, types, &in);
1745 					if (*in != 0) {
1746 						sdlSoapBindingFunctionFaultPtr binding = fault->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunctionFault));
1747 						memset(binding, 0, sizeof(sdlSoapBindingFunctionFault));
1748 						WSDL_CACHE_GET_1(binding->use,sdlEncodingUse,&in);
1749 						if (binding->use == SOAP_ENCODED) {
1750 							WSDL_CACHE_GET_1(binding->encodingStyle, sdlRpcEncodingStyle, &in);
1751 						} else {
1752 							binding->encodingStyle = SOAP_ENCODING_DEFAULT;
1753 						}
1754 						binding->ns = sdl_deserialize_string(&in);
1755 					} else {
1756 						WSDL_CACHE_SKIP(1, &in);
1757 						fault->bindingAttributes = NULL;
1758 					}
1759 				}
1760 			} else {
1761 				func->faults = NULL;
1762 			}
1763 			functions[i] = func;
1764 		}
1765 	}
1766 
1767 	/* deserialize requests */
1768 	WSDL_CACHE_GET_INT(i, &in);
1769 	if (i > 0) {
1770 		sdl->requests = emalloc(sizeof(HashTable));
1771 		zend_hash_init(sdl->requests, i, NULL, NULL, 0);
1772 		while (i > 0) {
1773 			int function_num;
1774 
1775 			WSDL_CACHE_GET_INT(function_num, &in);
1776 			sdl_deserialize_key(sdl->requests, functions[function_num-1], &in);
1777 			i--;
1778 		}
1779 	}
1780 
1781 	if (functions) {
1782 		efree(functions);
1783 	}
1784 	efree(bindings);
1785 	efree(encoders);
1786 	efree(types);
1787 	efree(buf);
1788 	return sdl;
1789 }
1790 
sdl_serialize_string(const char * str,smart_str * out)1791 static void sdl_serialize_string(const char *str, smart_str *out)
1792 {
1793 	if (str) {
1794 		int i = strlen(str);
1795 		WSDL_CACHE_PUT_INT(i, out);
1796 		if (i > 0) {
1797 			WSDL_CACHE_PUT_N(str, i, out);
1798 		}
1799 	} else {
1800 		WSDL_CACHE_PUT_INT(WSDL_NO_STRING_MARKER, out);
1801 	}
1802 }
1803 
1804 // TODO: refactor it
sdl_serialize_key(zend_string * key,smart_str * out)1805 static void sdl_serialize_key(zend_string *key, smart_str *out)
1806 {
1807 	if (key) {
1808 		WSDL_CACHE_PUT_INT(ZSTR_LEN(key), out);
1809 		WSDL_CACHE_PUT_N(ZSTR_VAL(key), ZSTR_LEN(key), out);
1810 	} else {
1811 		WSDL_CACHE_PUT_INT(WSDL_NO_STRING_MARKER, out);
1812 	}
1813 }
1814 
sdl_serialize_encoder_ref(encodePtr enc,HashTable * tmp_encoders,smart_str * out)1815 static void sdl_serialize_encoder_ref(encodePtr enc, HashTable *tmp_encoders, smart_str *out) {
1816 	if (enc) {
1817 		zval *encoder_num;
1818 		if ((encoder_num = zend_hash_str_find(tmp_encoders, (char*)&enc, sizeof(enc))) != 0) {
1819 			WSDL_CACHE_PUT_INT(Z_LVAL_P(encoder_num), out);
1820 		} else {
1821 			WSDL_CACHE_PUT_INT(0, out);
1822 		}
1823 	} else {
1824 		WSDL_CACHE_PUT_INT(0, out);
1825 	}
1826 }
1827 
sdl_serialize_type_ref(sdlTypePtr type,HashTable * tmp_types,smart_str * out)1828 static void sdl_serialize_type_ref(sdlTypePtr type, HashTable *tmp_types, smart_str *out) {
1829 	if (type) {
1830 		zval *type_num;
1831 		if ((type_num = zend_hash_str_find(tmp_types, (char*)&type, sizeof(type))) != NULL) {
1832 			WSDL_CACHE_PUT_INT(Z_LVAL_P(type_num), out);
1833 		} else {
1834 			WSDL_CACHE_PUT_INT(0, out);
1835 		}
1836 	} else {
1837 		WSDL_CACHE_PUT_INT(0,out);
1838 	}
1839 }
1840 
sdl_serialize_attribute(sdlAttributePtr attr,HashTable * tmp_encoders,smart_str * out)1841 static void sdl_serialize_attribute(sdlAttributePtr attr, HashTable *tmp_encoders, smart_str *out)
1842 {
1843 	int i;
1844 
1845 	sdl_serialize_string(attr->name, out);
1846 	sdl_serialize_string(attr->namens, out);
1847 	sdl_serialize_string(attr->ref, out);
1848 	sdl_serialize_string(attr->def, out);
1849 	sdl_serialize_string(attr->fixed, out);
1850 	WSDL_CACHE_PUT_1(attr->form, out);
1851 	WSDL_CACHE_PUT_1(attr->use, out);
1852 	sdl_serialize_encoder_ref(attr->encode, tmp_encoders, out);
1853 	if (attr->extraAttributes) {
1854 		i = zend_hash_num_elements(attr->extraAttributes);
1855 	} else {
1856 		i = 0;
1857 	}
1858 	WSDL_CACHE_PUT_INT(i, out);
1859 	if (i > 0) {
1860 		sdlExtraAttributePtr tmp;
1861 		zend_string *key;
1862 
1863 		ZEND_HASH_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
1864 			sdl_serialize_key(key, out);
1865 			sdl_serialize_string(tmp->ns, out);
1866 			sdl_serialize_string(tmp->val, out);
1867 		} ZEND_HASH_FOREACH_END();
1868 	}
1869 }
1870 
sdl_serialize_model(sdlContentModelPtr model,HashTable * tmp_types,HashTable * tmp_elements,smart_str * out)1871 static void sdl_serialize_model(sdlContentModelPtr model, HashTable *tmp_types, HashTable *tmp_elements, smart_str *out)
1872 {
1873 	WSDL_CACHE_PUT_1(model->kind, out);
1874 	WSDL_CACHE_PUT_INT(model->min_occurs, out);
1875 	WSDL_CACHE_PUT_INT(model->max_occurs, out);
1876 	switch (model->kind) {
1877 		case XSD_CONTENT_ELEMENT:
1878 			sdl_serialize_type_ref(model->u.element, tmp_elements, out);
1879 			break;
1880 		case XSD_CONTENT_SEQUENCE:
1881 		case XSD_CONTENT_ALL:
1882 		case XSD_CONTENT_CHOICE: {
1883 				sdlContentModelPtr tmp;
1884 				int i = zend_hash_num_elements(model->u.content);
1885 
1886 				WSDL_CACHE_PUT_INT(i, out);
1887 				ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1888 					sdl_serialize_model(tmp, tmp_types, tmp_elements, out);
1889 				} ZEND_HASH_FOREACH_END();
1890 			}
1891 			break;
1892 		case XSD_CONTENT_GROUP_REF:
1893 			sdl_serialize_string(model->u.group_ref,out);
1894 			break;
1895 		case XSD_CONTENT_GROUP:
1896 			sdl_serialize_type_ref(model->u.group, tmp_types, out);
1897 			break;
1898 		default:
1899 			break;
1900 	}
1901 }
1902 
sdl_serialize_resriction_int(sdlRestrictionIntPtr x,smart_str * out)1903 static void sdl_serialize_resriction_int(sdlRestrictionIntPtr x, smart_str *out)
1904 {
1905 	if (x) {
1906 		WSDL_CACHE_PUT_1(1, out);
1907 		WSDL_CACHE_PUT_INT(x->value, out);
1908 		WSDL_CACHE_PUT_1(x->fixed, out);
1909 	} else {
1910 		WSDL_CACHE_PUT_1(0, out);
1911 	}
1912 }
1913 
sdl_serialize_resriction_char(sdlRestrictionCharPtr x,smart_str * out)1914 static void sdl_serialize_resriction_char(sdlRestrictionCharPtr x, smart_str *out)
1915 {
1916 	if (x) {
1917 		WSDL_CACHE_PUT_1(1, out);
1918 		sdl_serialize_string(x->value, out);
1919 		WSDL_CACHE_PUT_1(x->fixed, out);
1920 	} else {
1921 		WSDL_CACHE_PUT_1(0, out);
1922 	}
1923 }
1924 
sdl_serialize_type(sdlTypePtr type,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)1925 static void sdl_serialize_type(sdlTypePtr type, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
1926 {
1927 	int i;
1928 	HashTable *tmp_elements = NULL;
1929 
1930 	WSDL_CACHE_PUT_1(type->kind, out);
1931 	sdl_serialize_string(type->name, out);
1932 	sdl_serialize_string(type->namens, out);
1933 	sdl_serialize_string(type->def, out);
1934 	sdl_serialize_string(type->fixed, out);
1935 	sdl_serialize_string(type->ref, out);
1936 	WSDL_CACHE_PUT_1(type->nillable, out);
1937 	WSDL_CACHE_PUT_1(type->form, out);
1938 	sdl_serialize_encoder_ref(type->encode, tmp_encoders, out);
1939 
1940 	if (type->restrictions) {
1941 		WSDL_CACHE_PUT_1(1, out);
1942 		sdl_serialize_resriction_int(type->restrictions->minExclusive,out);
1943 		sdl_serialize_resriction_int(type->restrictions->minInclusive,out);
1944 		sdl_serialize_resriction_int(type->restrictions->maxExclusive,out);
1945 		sdl_serialize_resriction_int(type->restrictions->maxInclusive,out);
1946 		sdl_serialize_resriction_int(type->restrictions->totalDigits,out);
1947 		sdl_serialize_resriction_int(type->restrictions->fractionDigits,out);
1948 		sdl_serialize_resriction_int(type->restrictions->length,out);
1949 		sdl_serialize_resriction_int(type->restrictions->minLength,out);
1950 		sdl_serialize_resriction_int(type->restrictions->maxLength,out);
1951 		sdl_serialize_resriction_char(type->restrictions->whiteSpace,out);
1952 		sdl_serialize_resriction_char(type->restrictions->pattern,out);
1953 		if (type->restrictions->enumeration) {
1954 			i = zend_hash_num_elements(type->restrictions->enumeration);
1955 		} else {
1956 			i = 0;
1957 		}
1958 		WSDL_CACHE_PUT_INT(i, out);
1959 		if (i > 0) {
1960 			sdlRestrictionCharPtr tmp;
1961 			zend_string *key;
1962 
1963 			ZEND_HASH_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
1964 				sdl_serialize_resriction_char(tmp, out);
1965 				sdl_serialize_key(key, out);
1966 			} ZEND_HASH_FOREACH_END();
1967 		}
1968 	} else {
1969 		WSDL_CACHE_PUT_1(0, out);
1970 	}
1971 	if (type->elements) {
1972 		i = zend_hash_num_elements(type->elements);
1973 	} else {
1974 		i = 0;
1975 	}
1976 	WSDL_CACHE_PUT_INT(i, out);
1977 	if (i > 0) {
1978 		sdlTypePtr tmp;
1979 		zend_string *key;
1980 		zval zv;
1981 
1982 		tmp_elements = emalloc(sizeof(HashTable));
1983 		zend_hash_init(tmp_elements, i, NULL, NULL, 0);
1984 
1985 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->elements, key, tmp) {
1986 			sdl_serialize_key(key, out);
1987 			sdl_serialize_type(tmp, tmp_encoders, tmp_types, out);
1988 			ZVAL_LONG(&zv, i);
1989 			zend_hash_str_add(tmp_elements, (char*)&tmp, sizeof(tmp), &zv);
1990 			i--;
1991 		} ZEND_HASH_FOREACH_END();
1992 	}
1993 
1994 	if (type->attributes) {
1995 		i = zend_hash_num_elements(type->attributes);
1996 	} else {
1997 		i = 0;
1998 	}
1999 	WSDL_CACHE_PUT_INT(i, out);
2000 	if (i > 0) {
2001 		sdlAttributePtr tmp;
2002 		zend_string *key;
2003 
2004 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->attributes, key, tmp) {
2005 			sdl_serialize_key(key, out);
2006 			sdl_serialize_attribute(tmp, tmp_encoders, out);
2007 		} ZEND_HASH_FOREACH_END();
2008 	}
2009 	if (type->model) {
2010 		WSDL_CACHE_PUT_1(1, out);
2011 		sdl_serialize_model(type->model, tmp_types, tmp_elements, out);
2012 	} else {
2013 		WSDL_CACHE_PUT_1(0, out);
2014 	}
2015 	if (tmp_elements != NULL) {
2016 		zend_hash_destroy(tmp_elements);
2017 		efree(tmp_elements);
2018 	}
2019 }
2020 
sdl_serialize_encoder(encodePtr enc,HashTable * tmp_types,smart_str * out)2021 static void sdl_serialize_encoder(encodePtr enc, HashTable *tmp_types, smart_str *out)
2022 {
2023 	WSDL_CACHE_PUT_INT(enc->details.type, out);
2024 	sdl_serialize_string(enc->details.type_str, out);
2025 	sdl_serialize_string(enc->details.ns, out);
2026 	sdl_serialize_type_ref(enc->details.sdl_type, tmp_types, out);
2027 }
2028 
sdl_serialize_parameters(HashTable * ht,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)2029 static void sdl_serialize_parameters(HashTable *ht, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
2030 {
2031 	int i;
2032 
2033 	if (ht) {
2034 		i = zend_hash_num_elements(ht);
2035 	} else {
2036 		i = 0;
2037 	}
2038 	WSDL_CACHE_PUT_INT(i, out);
2039 	if (i > 0) {
2040 		sdlParamPtr tmp;
2041 		zend_string *key;
2042 
2043 		ZEND_HASH_FOREACH_STR_KEY_PTR(ht, key, tmp) {
2044 			sdl_serialize_key(key, out);
2045 			sdl_serialize_string(tmp->paramName, out);
2046 			WSDL_CACHE_PUT_INT(tmp->order, out);
2047 			sdl_serialize_encoder_ref(tmp->encode, tmp_encoders, out);
2048 			sdl_serialize_type_ref(tmp->element, tmp_types, out);
2049 		} ZEND_HASH_FOREACH_END();
2050 	}
2051 }
2052 
sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)2053 static void sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
2054 {
2055 	int i, j;
2056 
2057 	WSDL_CACHE_PUT_1(body->use, out);
2058 	if (body->use == SOAP_ENCODED) {
2059 		WSDL_CACHE_PUT_1(body->encodingStyle, out);
2060 	}
2061 	sdl_serialize_string(body->ns, out);
2062 	if (body->headers) {
2063 		i = zend_hash_num_elements(body->headers);
2064 	} else {
2065 		i = 0;
2066 	}
2067 	WSDL_CACHE_PUT_INT(i, out);
2068 	if (i > 0) {
2069 		sdlSoapBindingFunctionHeaderPtr tmp;
2070 		zend_string *key;
2071 
2072 		ZEND_HASH_FOREACH_STR_KEY_PTR(body->headers, key, tmp) {
2073 			sdl_serialize_key(key, out);
2074 			WSDL_CACHE_PUT_1(tmp->use, out);
2075 			if (tmp->use == SOAP_ENCODED) {
2076 				WSDL_CACHE_PUT_1(tmp->encodingStyle, out);
2077 			}
2078 			sdl_serialize_string(tmp->name, out);
2079 			sdl_serialize_string(tmp->ns, out);
2080 			sdl_serialize_encoder_ref(tmp->encode, tmp_encoders, out);
2081 			sdl_serialize_type_ref(tmp->element, tmp_types, out);
2082 			if (tmp->headerfaults) {
2083 				j = zend_hash_num_elements(tmp->headerfaults);
2084 			} else {
2085 				j = 0;
2086 			}
2087 			WSDL_CACHE_PUT_INT(j, out);
2088 			if (j > 0) {
2089 				sdlSoapBindingFunctionHeaderPtr tmp2;
2090 				zend_string *key;
2091 
2092 				ZEND_HASH_FOREACH_STR_KEY_PTR(body->headers, key, tmp2) {
2093 					sdl_serialize_key(key, out);
2094 					WSDL_CACHE_PUT_1(tmp2->use, out);
2095 					if (tmp2->use == SOAP_ENCODED) {
2096 						WSDL_CACHE_PUT_1(tmp2->encodingStyle, out);
2097 					}
2098 					sdl_serialize_string(tmp2->name, out);
2099 					sdl_serialize_string(tmp2->ns, out);
2100 					sdl_serialize_encoder_ref(tmp2->encode, tmp_encoders, out);
2101 					sdl_serialize_type_ref(tmp2->element, tmp_types, out);
2102 				} ZEND_HASH_FOREACH_END();
2103 			}
2104 		} ZEND_HASH_FOREACH_END();
2105 	}
2106 }
2107 
add_sdl_to_cache(const char * fn,const char * uri,time_t t,sdlPtr sdl)2108 static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr sdl)
2109 {
2110 	smart_str buf = {0};
2111 	smart_str *out = &buf;
2112 	int i;
2113 	int type_num = 1;
2114 	int encoder_num = 1;
2115 	int f;
2116 	const encode *enc;
2117 	HashTable tmp_types;
2118 	HashTable tmp_encoders;
2119 	HashTable tmp_bindings;
2120 	HashTable tmp_functions;
2121 
2122 #ifdef ZEND_WIN32
2123 	f = open(fn,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,S_IREAD|S_IWRITE);
2124 #else
2125 	f = open(fn,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,S_IREAD|S_IWRITE);
2126 #endif
2127 	if (f < 0) {return;}
2128 
2129 	zend_hash_init(&tmp_types, 0, NULL, NULL, 0);
2130 	zend_hash_init(&tmp_encoders, 0, NULL, NULL, 0);
2131 	zend_hash_init(&tmp_bindings, 0, NULL, NULL, 0);
2132 	zend_hash_init(&tmp_functions, 0, NULL, NULL, 0);
2133 
2134 	WSDL_CACHE_PUT_N("wsdl", 4, out);
2135 	WSDL_CACHE_PUT_1(WSDL_CACHE_VERSION,out);
2136 	WSDL_CACHE_PUT_1(0,out);
2137 	WSDL_CACHE_PUT_N(&t, sizeof(t), out);
2138 
2139 	sdl_serialize_string(uri, out);
2140 	sdl_serialize_string(sdl->source, out);
2141 	sdl_serialize_string(sdl->target_ns, out);
2142 
2143 	if (sdl->groups) {
2144 		i = zend_hash_num_elements(sdl->groups);
2145 	} else {
2146 		i = 0;
2147 	}
2148 	WSDL_CACHE_PUT_INT(i, out);
2149 	if (i > 0) {
2150 		sdlTypePtr tmp;
2151 		zval zv;
2152 
2153 		ZEND_HASH_FOREACH_PTR(sdl->groups, tmp) {
2154 			ZVAL_LONG(&zv, type_num);
2155 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2156 			++type_num;
2157 		} ZEND_HASH_FOREACH_END();
2158 	}
2159 
2160 	if (sdl->types) {
2161 		i = zend_hash_num_elements(sdl->types);
2162 	} else {
2163 		i = 0;
2164 	}
2165 	WSDL_CACHE_PUT_INT(i, out);
2166 	if (i > 0) {
2167 		sdlTypePtr tmp;
2168 		zval zv;
2169 
2170 		ZEND_HASH_FOREACH_PTR(sdl->types, tmp) {
2171 			ZVAL_LONG(&zv,  type_num);
2172 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2173 			++type_num;
2174 		} ZEND_HASH_FOREACH_END();
2175 	}
2176 
2177 	if (sdl->elements) {
2178 		i = zend_hash_num_elements(sdl->elements);
2179 	} else {
2180 		i = 0;
2181 	}
2182 	WSDL_CACHE_PUT_INT(i, out);
2183 	if (i > 0) {
2184 		sdlTypePtr tmp;
2185 		zval zv;
2186 
2187 		ZEND_HASH_FOREACH_PTR(sdl->elements, tmp) {
2188 			ZVAL_LONG(&zv, type_num);
2189 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2190 			++type_num;
2191 		} ZEND_HASH_FOREACH_END();
2192 	}
2193 
2194 	if (sdl->encoders) {
2195 		i = zend_hash_num_elements(sdl->encoders);
2196 	} else {
2197 		i = 0;
2198 	}
2199 	WSDL_CACHE_PUT_INT(i, out);
2200 	if (i > 0) {
2201 		encodePtr tmp;
2202 		zval zv;
2203 
2204 		ZEND_HASH_FOREACH_PTR(sdl->encoders, tmp) {
2205 			ZVAL_LONG(&zv, encoder_num);
2206 			zend_hash_str_add(&tmp_encoders, (char*)&tmp, sizeof(tmp), &zv);
2207 			++encoder_num;
2208 		} ZEND_HASH_FOREACH_END();
2209 	}
2210 	enc = defaultEncoding;
2211 	while (enc->details.type != END_KNOWN_TYPES) {
2212 		zval zv;
2213 
2214 		ZVAL_LONG(&zv, encoder_num);
2215 		zend_hash_str_add(&tmp_encoders, (char*)&enc, sizeof(encodePtr), &zv);
2216 		enc++;
2217 		++encoder_num;
2218 	}
2219 
2220 	if (sdl->groups) {
2221 		sdlTypePtr tmp;
2222 		zend_string *key;
2223 
2224 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
2225 			sdl_serialize_key(key, out);
2226 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2227 		} ZEND_HASH_FOREACH_END();
2228 	}
2229 
2230 	if (sdl->types) {
2231 		sdlTypePtr tmp;
2232 		zend_string *key;
2233 
2234 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
2235 			sdl_serialize_key(key, out);
2236 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2237 		} ZEND_HASH_FOREACH_END();
2238 	}
2239 
2240 	if (sdl->elements) {
2241 		sdlTypePtr tmp;
2242 		zend_string *key;
2243 
2244 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
2245 			sdl_serialize_key(key, out);
2246 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2247 		} ZEND_HASH_FOREACH_END();
2248 	}
2249 
2250 	if (sdl->encoders) {
2251 		encodePtr tmp;
2252 		zend_string *key;
2253 
2254 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
2255 			sdl_serialize_key(key, out);
2256 			sdl_serialize_encoder(tmp, &tmp_types, out);
2257 		} ZEND_HASH_FOREACH_END();
2258 	}
2259 
2260 	/* serialize bindings */
2261 	if (sdl->bindings) {
2262 		i = zend_hash_num_elements(sdl->bindings);
2263 	} else {
2264 		i = 0;
2265 	}
2266 	WSDL_CACHE_PUT_INT(i, out);
2267 	if (i > 0) {
2268 		sdlBindingPtr tmp;
2269 		int binding_num = 1;
2270 		zval zv;
2271 		zend_string *key;
2272 
2273 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
2274 			sdl_serialize_key(key, out);
2275 			sdl_serialize_string(tmp->name, out);
2276 			sdl_serialize_string(tmp->location, out);
2277 			WSDL_CACHE_PUT_1(tmp->bindingType,out);
2278 			if (tmp->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
2279 				sdlSoapBindingPtr binding = (sdlSoapBindingPtr)tmp->bindingAttributes;
2280 				WSDL_CACHE_PUT_1(binding->style, out);
2281 				WSDL_CACHE_PUT_1(binding->transport, out);
2282 			} else {
2283 				WSDL_CACHE_PUT_1(0,out);
2284 			}
2285 
2286 			ZVAL_LONG(&zv, binding_num);
2287 			zend_hash_str_add(&tmp_bindings, (char*)&tmp, sizeof(tmp), &zv);
2288 			binding_num++;
2289 		} ZEND_HASH_FOREACH_END();
2290 	}
2291 
2292 	/* serialize functions */
2293 	i = zend_hash_num_elements(&sdl->functions);
2294 	WSDL_CACHE_PUT_INT(i, out);
2295 	if (i > 0) {
2296 		sdlFunctionPtr tmp;
2297 		zval *binding_num, zv;
2298 		int function_num = 1;
2299 		zend_string *key;
2300 
2301 		ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
2302 			sdl_serialize_key(key, out);
2303 			sdl_serialize_string(tmp->functionName, out);
2304 			sdl_serialize_string(tmp->requestName, out);
2305 			sdl_serialize_string(tmp->responseName, out);
2306 
2307 			if (tmp->binding) {
2308 				binding_num = zend_hash_str_find(&tmp_bindings,(char*)&tmp->binding, sizeof(tmp->binding));
2309 				if (binding_num) {
2310 					WSDL_CACHE_PUT_INT(Z_LVAL_P(binding_num), out);
2311 					if (Z_LVAL_P(binding_num) >= 0) {
2312 						if (tmp->binding->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
2313 							sdlSoapBindingFunctionPtr binding = (sdlSoapBindingFunctionPtr)tmp->bindingAttributes;
2314 							WSDL_CACHE_PUT_1(binding->style, out);
2315 							sdl_serialize_string(binding->soapAction, out);
2316 							sdl_serialize_soap_body(&binding->input, &tmp_encoders, &tmp_types, out);
2317 							sdl_serialize_soap_body(&binding->output, &tmp_encoders, &tmp_types, out);
2318 						} else {
2319 							WSDL_CACHE_PUT_1(0,out);
2320 						}
2321 					}
2322 				}
2323 			}
2324 			sdl_serialize_parameters(tmp->requestParameters, &tmp_encoders, &tmp_types, out);
2325 			sdl_serialize_parameters(tmp->responseParameters, &tmp_encoders, &tmp_types, out);
2326 
2327 			if (tmp->faults) {
2328 				sdlFaultPtr fault;
2329 				zend_string *key;
2330 
2331 				WSDL_CACHE_PUT_INT(zend_hash_num_elements(tmp->faults), out);
2332 
2333 				ZEND_HASH_FOREACH_STR_KEY_PTR(tmp->faults, key, fault) {
2334 					sdl_serialize_key(key, out);
2335 					sdl_serialize_string(fault->name, out);
2336 					sdl_serialize_parameters(fault->details, &tmp_encoders, &tmp_types, out);
2337 					if (tmp->binding->bindingType == BINDING_SOAP && fault->bindingAttributes != NULL) {
2338 						sdlSoapBindingFunctionFaultPtr binding = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
2339 						WSDL_CACHE_PUT_1(binding->use, out);
2340 						if (binding->use == SOAP_ENCODED) {
2341 							WSDL_CACHE_PUT_1(binding->encodingStyle, out);
2342 						}
2343 						sdl_serialize_string(binding->ns, out);
2344 					} else {
2345 						WSDL_CACHE_PUT_1(0, out);
2346 					}
2347 				} ZEND_HASH_FOREACH_END();
2348 			} else {
2349 				WSDL_CACHE_PUT_INT(0, out);
2350 			}
2351 
2352 			ZVAL_LONG(&zv, function_num);
2353 			zend_hash_str_add(&tmp_functions, (char*)&tmp, sizeof(tmp), &zv);
2354 			function_num++;
2355 		} ZEND_HASH_FOREACH_END();
2356 	}
2357 
2358 	/* serialize requests */
2359 	if (sdl->requests) {
2360 		i = zend_hash_num_elements(sdl->requests);
2361 	} else {
2362 		i = 0;
2363 	}
2364 	WSDL_CACHE_PUT_INT(i, out);
2365 	if (i > 0) {
2366 		sdlFunctionPtr tmp;
2367 		zval *function_num;
2368 		zend_string *key;
2369 
2370 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->requests, key, tmp) {
2371 			function_num = zend_hash_str_find(&tmp_functions, (char*)&tmp, sizeof(tmp));
2372 			WSDL_CACHE_PUT_INT(Z_LVAL_P(function_num), out);
2373 			sdl_serialize_key(key, out);
2374 		} ZEND_HASH_FOREACH_END();
2375 	}
2376 
2377 	php_ignore_value(write(f, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)));
2378 	close(f);
2379 	smart_str_free(&buf);
2380 	zend_hash_destroy(&tmp_functions);
2381 	zend_hash_destroy(&tmp_bindings);
2382 	zend_hash_destroy(&tmp_encoders);
2383 	zend_hash_destroy(&tmp_types);
2384 }
2385 
2386 
make_persistent_restriction_int(void * data)2387 static void make_persistent_restriction_int(void *data)
2388 {
2389 	sdlRestrictionIntPtr *rest = (sdlRestrictionIntPtr *)data;
2390 	sdlRestrictionIntPtr prest = NULL;
2391 
2392 	prest = malloc(sizeof(sdlRestrictionInt));
2393 	*prest = **rest;
2394 	*rest = prest;
2395 }
2396 
2397 
make_persistent_restriction_char_int(sdlRestrictionCharPtr * rest)2398 static void make_persistent_restriction_char_int(sdlRestrictionCharPtr *rest)
2399 {
2400 	sdlRestrictionCharPtr prest = NULL;
2401 
2402 	prest = malloc(sizeof(sdlRestrictionChar));
2403 	memset(prest, 0, sizeof(sdlRestrictionChar));
2404 	prest->value = strdup((*rest)->value);
2405 	prest->fixed = (*rest)->fixed;
2406 	*rest = prest;
2407 }
2408 
2409 
make_persistent_sdl_type_ref(sdlTypePtr * type,HashTable * ptr_map,HashTable * bp_types)2410 static void make_persistent_sdl_type_ref(sdlTypePtr *type, HashTable *ptr_map, HashTable *bp_types)
2411 {
2412 	sdlTypePtr tmp;
2413 
2414 	if ((tmp = zend_hash_str_find_ptr(ptr_map, (char *)type, sizeof(sdlTypePtr))) != NULL) {
2415 		*type = tmp;
2416 	} else {
2417 		zend_hash_next_index_insert_ptr(bp_types, *type);
2418 	}
2419 }
2420 
2421 
make_persistent_sdl_encoder_ref(encodePtr * enc,HashTable * ptr_map,HashTable * bp_encoders)2422 static void make_persistent_sdl_encoder_ref(encodePtr *enc, HashTable *ptr_map, HashTable *bp_encoders)
2423 {
2424 	encodePtr tmp;
2425 
2426 	/* do not process defaultEncoding's here */
2427 	if ((*enc) >= defaultEncoding && (*enc) < defaultEncoding + numDefaultEncodings) {
2428 		return;
2429 	}
2430 
2431 	if ((tmp = zend_hash_str_find_ptr(ptr_map, (char *)enc, sizeof(encodePtr))) != NULL) {
2432 		*enc = tmp;
2433 	} else {
2434 		zend_hash_next_index_insert_ptr(bp_encoders, enc);
2435 	}
2436 }
2437 
2438 
make_persistent_sdl_function_headers(HashTable * headers,HashTable * ptr_map)2439 static HashTable* make_persistent_sdl_function_headers(HashTable *headers, HashTable *ptr_map)
2440 {
2441 	HashTable *pheaders;
2442 	sdlSoapBindingFunctionHeaderPtr tmp, pheader;
2443 	encodePtr penc;
2444 	sdlTypePtr ptype;
2445 	zend_string *key;
2446 
2447 	pheaders = malloc(sizeof(HashTable));
2448 	zend_hash_init(pheaders, zend_hash_num_elements(headers), NULL, delete_header_persistent, 1);
2449 
2450 	ZEND_HASH_FOREACH_STR_KEY_PTR(headers, key, tmp) {
2451 		pheader = malloc(sizeof(sdlSoapBindingFunctionHeader));
2452 		memset(pheader, 0, sizeof(sdlSoapBindingFunctionHeader));
2453 		*pheader = *tmp;
2454 
2455 		if (pheader->name) {
2456 			pheader->name = strdup(pheader->name);
2457 		}
2458 		if (pheader->ns) {
2459 			pheader->ns = strdup(pheader->ns);
2460 		}
2461 
2462 		if (pheader->encode && pheader->encode->details.sdl_type) {
2463 			if ((penc = zend_hash_str_find_ptr(ptr_map, (char*)&pheader->encode, sizeof(encodePtr))) == NULL) {
2464 				assert(0);
2465 			}
2466 			pheader->encode = penc;
2467 		}
2468 		if (pheader->element) {
2469 			if ((ptype = zend_hash_str_find_ptr(ptr_map, (char*)&pheader->element, sizeof(sdlTypePtr))) == NULL) {
2470 				assert(0);
2471 			}
2472 			pheader->element = ptype;
2473 		}
2474 
2475 		if (pheader->headerfaults) {
2476 			pheader->headerfaults = make_persistent_sdl_function_headers(pheader->headerfaults, ptr_map);
2477 		}
2478 
2479 		if (key) {
2480 			/* We have to duplicate key emalloc->malloc */
2481 			zend_hash_str_add_ptr(pheaders, ZSTR_VAL(key), ZSTR_LEN(key), pheader);
2482 		} else {
2483 			zend_hash_next_index_insert_ptr(pheaders, pheader);
2484 		}
2485 	} ZEND_HASH_FOREACH_END();
2486 
2487 	return pheaders;
2488 }
2489 
2490 
make_persistent_sdl_soap_body(sdlSoapBindingFunctionBodyPtr body,HashTable * ptr_map)2491 static void make_persistent_sdl_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTable *ptr_map)
2492 {
2493 	if (body->ns) {
2494 		body->ns = strdup(body->ns);
2495 	}
2496 
2497 	if (body->headers) {
2498 		body->headers = make_persistent_sdl_function_headers(body->headers, ptr_map);
2499 	}
2500 }
2501 
2502 
make_persistent_sdl_parameters(HashTable * params,HashTable * ptr_map)2503 static HashTable* make_persistent_sdl_parameters(HashTable *params, HashTable *ptr_map)
2504 {
2505 	HashTable *pparams;
2506 	sdlParamPtr tmp, pparam;
2507 	sdlTypePtr ptype;
2508 	encodePtr penc;
2509 	zend_string *key;
2510 
2511 	pparams = malloc(sizeof(HashTable));
2512 	zend_hash_init(pparams, zend_hash_num_elements(params), NULL, delete_parameter_persistent, 1);
2513 
2514 	ZEND_HASH_FOREACH_STR_KEY_PTR(params, key, tmp) {
2515 		pparam = malloc(sizeof(sdlParam));
2516 		memset(pparam, 0, sizeof(sdlParam));
2517 		*pparam = *tmp;
2518 
2519 		if (pparam->paramName) {
2520 			pparam->paramName = strdup(pparam->paramName);
2521 		}
2522 
2523 		if (pparam->encode && pparam->encode->details.sdl_type) {
2524 			if ((penc = zend_hash_str_find_ptr(ptr_map, (char*)&pparam->encode, sizeof(encodePtr))) == NULL) {
2525 				assert(0);
2526 			}
2527 			pparam->encode = penc;
2528 		}
2529 		if (pparam->element) {
2530 			if ((ptype = zend_hash_str_find_ptr(ptr_map, (char*)&pparam->element, sizeof(sdlTypePtr))) == NULL) {
2531 				assert(0);
2532 			}
2533 			pparam->element = ptype;
2534 		}
2535 
2536 		if (key) {
2537 			/* We have to duplicate key emalloc->malloc */
2538 			zend_hash_str_add_ptr(pparams, ZSTR_VAL(key), ZSTR_LEN(key), pparam);
2539 		} else {
2540 			zend_hash_next_index_insert_ptr(pparams, pparam);
2541 		}
2542 	} ZEND_HASH_FOREACH_END();
2543 
2544 	return pparams;
2545 }
2546 
make_persistent_sdl_function_faults(sdlFunctionPtr func,HashTable * faults,HashTable * ptr_map)2547 static HashTable* make_persistent_sdl_function_faults(sdlFunctionPtr func, HashTable *faults, HashTable *ptr_map)
2548 {
2549 	HashTable *pfaults;
2550 	sdlFaultPtr tmp, pfault;
2551 	zend_string *key;
2552 
2553 	pfaults = malloc(sizeof(HashTable));
2554 	zend_hash_init(pfaults, zend_hash_num_elements(faults), NULL, delete_fault_persistent, 1);
2555 
2556 	ZEND_HASH_FOREACH_STR_KEY_PTR(faults, key, tmp) {
2557 		pfault = malloc(sizeof(sdlFault));
2558 		memset(pfault, 0, sizeof(sdlFault));
2559 		*pfault = *tmp;
2560 
2561 		if (pfault->name) {
2562 			pfault->name = strdup(pfault->name);
2563 		}
2564 		if (pfault->details) {
2565 			pfault->details = make_persistent_sdl_parameters(pfault->details, ptr_map);
2566 		}
2567 
2568 		if (func->binding->bindingType == BINDING_SOAP && pfault->bindingAttributes) {
2569 			sdlSoapBindingFunctionFaultPtr soap_binding;
2570 
2571 		   	soap_binding = malloc(sizeof(sdlSoapBindingFunctionFault));
2572 			memset(soap_binding, 0, sizeof(sdlSoapBindingFunctionFault));
2573 			*soap_binding = *(sdlSoapBindingFunctionFaultPtr)pfault->bindingAttributes;
2574 			if (soap_binding->ns) {
2575 				soap_binding->ns = strdup(soap_binding->ns);
2576 			}
2577 			pfault->bindingAttributes = soap_binding;
2578 		}
2579 
2580 		if (key) {
2581 			/* We have to duplicate key emalloc->malloc */
2582 			zend_hash_str_add_ptr(pfaults, ZSTR_VAL(key), ZSTR_LEN(key), pfault);
2583 		} else {
2584 			zend_hash_next_index_insert_ptr(pfaults, pfault);
2585 		}
2586 
2587 	} ZEND_HASH_FOREACH_END();
2588 
2589 	return pfaults;
2590 }
2591 
2592 
make_persistent_sdl_attribute(sdlAttributePtr attr,HashTable * ptr_map,HashTable * bp_types,HashTable * bp_encoders)2593 static sdlAttributePtr make_persistent_sdl_attribute(sdlAttributePtr attr, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
2594 {
2595 	sdlAttributePtr pattr;
2596 	zend_string *key;
2597 
2598 	pattr = malloc(sizeof(sdlAttribute));
2599 	memset(pattr, 0, sizeof(sdlAttribute));
2600 
2601 	*pattr = *attr;
2602 
2603 	if (pattr->name) {
2604 		pattr->name =