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