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