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