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