xref: /reactos/dll/win32/msxml3/xdr.c (revision bab6b90f)
1 /*
2  * XDR (XML-Data Reduced) -> XSD (XML Schema Document) conversion
3  *
4  * Copyright 2010 Adam Martinson for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include "config.h"
23 
24 #include <assert.h>
25 #ifdef HAVE_LIBXML2
26 # include <libxml/tree.h>
27 #endif
28 
29 #include "wine/debug.h"
30 
31 /* Both XDR and XSD are valid XML
32  * We just convert the doc tree, no need for a parser.
33  */
34 
35 #ifdef HAVE_LIBXML2
36 
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
38 
39 static const xmlChar DT_prefix[] = "dt";
40 static const xmlChar DT_href[] = "urn:schemas-microsoft-com:datatypes";
41 static const xmlChar XDR_href[] = "urn:schemas-microsoft-com:xml-data";
42 static const xmlChar XSD_prefix[] = "xsd";
43 static const xmlChar XSD_href[] = "http://www.w3.org/2001/XMLSchema";
44 
45 static const xmlChar xs_all[] = "all";
46 static const xmlChar xs_annotation[] = "annotation";
47 static const xmlChar xs_any[] = "any";
48 static const xmlChar xs_anyAttribute[] = "anyAttribute";
49 static const xmlChar xs_attribute[] = "attribute";
50 static const xmlChar xs_AttributeType[] = "AttributeType";
51 static const xmlChar xs_base[] = "base";
52 static const xmlChar xs_choice[] = "choice";
53 static const xmlChar xs_complexType[] = "complexType";
54 static const xmlChar xs_content[] = "content";
55 static const xmlChar xs_datatype[] = "datatype";
56 static const xmlChar xs_default[] = "default";
57 static const xmlChar xs_description[] = "description";
58 static const xmlChar xs_documentation[] = "documentation";
59 static const xmlChar xs_element[] = "element";
60 static const xmlChar xs_ElementType[] = "ElementType";
61 static const xmlChar xs_eltOnly[] = "eltOnly";
62 static const xmlChar xs_enumeration[] = "enumeration";
63 static const xmlChar xs_extension[] = "extension";
64 static const xmlChar xs_group[] = "group";
65 static const xmlChar xs_lax[] = "lax";
66 static const xmlChar xs_length[] = "length";
67 static const xmlChar xs_many[] = "many";
68 static const xmlChar xs_maxOccurs[] = "maxOccurs";
69 static const xmlChar xs_minOccurs[] = "minOccurs";
70 static const xmlChar xs_mixed[] = "mixed";
71 static const xmlChar xs_model[] = "model";
72 static const xmlChar xs_name[] = "name";
73 static const xmlChar xs_namespace[] = "namespace";
74 static const xmlChar xs_no[] = "no";
75 static const xmlChar xs_open[] = "open";
76 static const xmlChar xs_optional[] = "optional";
77 static const xmlChar xs_order[] = "order";
78 static const xmlChar xs_processContents[] = "processContents";
79 static const xmlChar xs_ref[] = "ref";
80 static const xmlChar xs_required[] = "required";
81 static const xmlChar xs_restriction[] = "restriction";
82 static const xmlChar xs_schema[] = "schema";
83 static const xmlChar xs_seq[] = "seq";
84 static const xmlChar xs_sequence[] = "sequence";
85 static const xmlChar xs_simpleContent[] = "simpleContent";
86 static const xmlChar xs_simpleType[] = "simpleType";
87 static const xmlChar xs_strict[] = "strict";
88 static const xmlChar xs_targetNamespace[] = "targetNamespace";
89 static const xmlChar xs_textOnly[] = "textOnly";
90 static const xmlChar xs_true[] = "true";
91 static const xmlChar xs_type[] = "type";
92 static const xmlChar xs_unbounded[] = "unbounded";
93 static const xmlChar xs_use[] = "use";
94 static const xmlChar xs_value[] = "value";
95 static const xmlChar xs_values[] = "values";
96 static const xmlChar xs_xsd_string[] = "xsd:string";
97 
98 typedef enum _CONTENT_TYPE
99 {
100     CONTENT_EMPTY,
101     CONTENT_TEXTONLY,
102     CONTENT_ELTONLY,
103     CONTENT_MIXED
104 } CONTENT_TYPE;
105 
106 typedef enum _ORDER_TYPE
107 {
108     ORDER_SEQ,
109     ORDER_MANY,
110     ORDER_ONE
111 } ORDER_TYPE;
112 
113 #define FOREACH_CHILD(node, child) \
114     for (child = node->children; child != NULL; child = child->next) \
115         if (child->type == XML_ELEMENT_NODE)
116 
117 #define FOREACH_ATTR(node, attr) \
118     for (attr = node->properties; attr != NULL; attr = attr->next)
119 
120 #define FOREACH_NS(node, ns) \
121     for (ns = node->nsDef; ns != NULL; ns = ns->next)
122 
get_schema(xmlNodePtr node)123 static inline xmlNodePtr get_schema(xmlNodePtr node)
124 {
125     return xmlDocGetRootElement(node->doc);
126 }
127 
get_child(xmlNodePtr node,xmlChar const * name)128 static inline xmlNodePtr get_child(xmlNodePtr node, xmlChar const* name)
129 {
130     xmlNodePtr child = NULL;
131     if (node)
132     {
133         FOREACH_CHILD(node, child)
134         {
135             if (xmlStrEqual(child->name, name))
136                 break;
137         }
138     }
139 
140     return child;
141 }
142 
get_child_with_attr(xmlNodePtr node,xmlChar const * name,xmlChar const * attr_ns,xmlChar const * attr_name,xmlChar const * attr_val)143 static inline xmlNodePtr get_child_with_attr(xmlNodePtr node, xmlChar const* name,
144                                              xmlChar const* attr_ns, xmlChar const* attr_name,
145                                              xmlChar const* attr_val)
146 {
147     xmlChar* str;
148     if (node)
149     {
150         FOREACH_CHILD(node, node)
151         {
152             if (xmlStrEqual(node->name, name))
153             {
154                 str = (attr_ns != NULL)? xmlGetNsProp(node, attr_name, attr_ns) :
155                                                   xmlGetProp(node, attr_name);
156                 if (str)
157                 {
158                     if (xmlStrEqual(str, attr_val))
159                     {
160                         xmlFree(str);
161                         return node;
162                     }
163                     xmlFree(str);
164                 }
165             }
166         }
167     }
168 
169     return NULL;
170 }
171 
get_dt_ns(xmlNodePtr node)172 static inline xmlNsPtr get_dt_ns(xmlNodePtr node)
173 {
174     xmlNsPtr ns;
175 
176     node = get_schema(node);
177     assert(node != NULL);
178 
179     FOREACH_NS(node, ns)
180     {
181         if (xmlStrEqual(ns->href, DT_href))
182             break;
183     }
184 
185     return ns;
186 }
187 
get_dt_type(xmlNodePtr xdr)188 static inline xmlChar* get_dt_type(xmlNodePtr xdr)
189 {
190     xmlChar* str = xmlGetNsProp(xdr, xs_type, DT_href);
191     if (!str)
192     {
193         xmlNodePtr datatype = get_child(xdr, xs_datatype);
194         if (datatype)
195             str = xmlGetNsProp(datatype, xs_type, DT_href);
196     }
197     return str;
198 }
199 
get_attr_val(xmlAttrPtr attr)200 static inline xmlChar* get_attr_val(xmlAttrPtr attr)
201 {
202     return xmlNodeGetContent((xmlNodePtr)attr);
203 }
204 
add_any_child(xmlNodePtr parent,BOOL set_occurs)205 static inline xmlNodePtr add_any_child(xmlNodePtr parent, BOOL set_occurs)
206 {
207     xmlNodePtr child = xmlNewChild(parent, NULL, xs_any, NULL);
208     if (set_occurs)
209     {
210         xmlSetProp(child, xs_minOccurs, BAD_CAST "0");
211         xmlSetProp(child, xs_maxOccurs, xs_unbounded);
212     }
213     xmlSetProp(child, xs_processContents, xs_strict);
214     return child;
215 }
216 
add_anyAttribute_child(xmlNodePtr parent)217 static inline xmlNodePtr add_anyAttribute_child(xmlNodePtr parent)
218 {
219     xmlNodePtr child = xmlNewChild(parent, NULL, xs_anyAttribute, NULL);
220     xmlSetProp(child, xs_processContents, xs_lax);
221     return child;
222 }
223 
copy_prop_ignore_ns(xmlAttrPtr xdr_attr,xmlNodePtr node)224 static inline xmlAttrPtr copy_prop_ignore_ns(xmlAttrPtr xdr_attr, xmlNodePtr node)
225 {
226     xmlChar* str = get_attr_val(xdr_attr);
227     xmlAttrPtr attr = xmlSetProp(node, xdr_attr->name, str);
228     xmlFree(str);
229     return attr;
230 }
XDR_A_default(xmlAttrPtr xdr_attr,xmlNodePtr node)231 static inline xmlAttrPtr XDR_A_default(xmlAttrPtr xdr_attr, xmlNodePtr node)
232 {
233     TRACE("(%p, %p)\n", xdr_attr, node);
234 
235     return copy_prop_ignore_ns(xdr_attr, node);
236 }
237 
XDR_A_dt_type(xmlAttrPtr xdr_attr,xmlNodePtr node)238 static inline xmlAttrPtr XDR_A_dt_type(xmlAttrPtr xdr_attr, xmlNodePtr node)
239 {
240     xmlChar* str = get_attr_val(xdr_attr);
241     xmlAttrPtr attr;
242 
243     TRACE("(%p, %p)\n", xdr_attr, node);
244 
245     if (xmlStrEqual(str, xs_enumeration))
246         attr = NULL;
247     else
248         attr = xmlSetNsProp(node, get_dt_ns(node), DT_prefix, str);
249     xmlFree(str);
250     return attr;
251 }
252 
XDR_A_maxOccurs(xmlAttrPtr xdr_attr,xmlNodePtr node)253 static xmlAttrPtr XDR_A_maxOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node)
254 {
255     xmlChar* str = get_attr_val(xdr_attr);
256     xmlAttrPtr attr;
257 
258     TRACE("(%p, %p)\n", xdr_attr, node);
259 
260     if (xmlStrEqual(str, BAD_CAST "*"))
261         attr = xmlSetProp(node, xs_maxOccurs, xs_unbounded);
262     else
263         attr = copy_prop_ignore_ns(xdr_attr, node);
264 
265     xmlFree(str);
266     return attr;
267 }
268 
XDR_A_minOccurs(xmlAttrPtr xdr_attr,xmlNodePtr node)269 static inline xmlAttrPtr XDR_A_minOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node)
270 {
271     TRACE("(%p, %p)\n", xdr_attr, node);
272 
273     return copy_prop_ignore_ns(xdr_attr, node);
274 }
275 
XDR_A_name(xmlAttrPtr xdr_attr,xmlNodePtr node)276 static inline xmlAttrPtr XDR_A_name(xmlAttrPtr xdr_attr, xmlNodePtr node)
277 {
278     TRACE("(%p, %p)\n", xdr_attr, node);
279 
280     return copy_prop_ignore_ns(xdr_attr, node);
281 }
282 
XDR_A_type(xmlAttrPtr xdr_attr,xmlNodePtr node)283 static xmlAttrPtr XDR_A_type(xmlAttrPtr xdr_attr, xmlNodePtr node)
284 {
285     xmlChar* str = get_attr_val(xdr_attr);
286     xmlAttrPtr attr = xmlSetProp(node, xs_ref, str);
287 
288     TRACE("(%p, %p)\n", xdr_attr, node);
289 
290     xmlFree(str);
291     return attr;
292 }
293 
XDR_A_required(xmlAttrPtr xdr_attr,xmlNodePtr node)294 static xmlAttrPtr XDR_A_required(xmlAttrPtr xdr_attr, xmlNodePtr node)
295 {
296     xmlChar* str = get_attr_val(xdr_attr);
297     xmlAttrPtr attr;
298 
299     TRACE("(%p, %p)\n", xdr_attr, node);
300 
301     if (xmlStrEqual(str, xs_no))
302         attr = xmlSetProp(node, xs_use, xs_optional);
303     else /* yes */
304         attr = xmlSetProp(node, xs_use, xs_required);
305     xmlFree(str);
306     return attr;
307 }
308 
XDR_E_description(xmlNodePtr xdr,xmlNodePtr parent)309 static xmlNodePtr XDR_E_description(xmlNodePtr xdr, xmlNodePtr parent)
310 {
311     xmlNodePtr xsd_node = xmlNewChild(parent, NULL, xs_annotation, NULL);
312     xmlAttrPtr xdr_attr;
313 
314     TRACE("(%p, %p)\n", xdr, parent);
315 
316     xmlNewChild(xsd_node, NULL, xs_documentation, xdr->content);
317 
318     FOREACH_ATTR(xdr, xdr_attr)
319     {
320         xmlCopyProp(xsd_node, xdr_attr);
321     }
322     return xsd_node;
323 }
324 
XDR_E_AttributeType(xmlNodePtr xdr,xmlNodePtr parent)325 static xmlNodePtr XDR_E_AttributeType(xmlNodePtr xdr, xmlNodePtr parent)
326 {
327     xmlChar *str, *type = get_dt_type(xdr);
328     xmlNodePtr xsd_node, xsd_child, xdr_child;
329     xmlAttrPtr xdr_attr;
330 
331     TRACE("(%p, %p)\n", xdr, parent);
332 
333     xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL);
334 
335     if (type && xmlStrEqual(type, xs_enumeration))
336     {
337         xmlChar *tmp, *tokBegin, *tokEnd = NULL;
338         xmlNodePtr xsd_enum;
339         xsd_child = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL);
340         xsd_child = xmlNewChild(xsd_child, NULL, xs_restriction, NULL);
341         xmlSetProp(xsd_child, xs_base, xs_xsd_string);
342 
343         tokBegin = str = xmlGetNsProp(xdr, xs_values, DT_href);
344         while (tokBegin && *tokBegin)
345         {
346             while (*tokBegin && isspace(*tokBegin))
347                 ++tokBegin;
348             tokEnd = tokBegin;
349             while (*tokEnd && !isspace(*tokEnd))
350                 ++tokEnd;
351             if (tokEnd == tokBegin)
352                 break;
353             xsd_enum = xmlNewChild(xsd_child, NULL, xs_enumeration, NULL);
354             tmp = xmlStrndup(tokBegin, tokEnd-tokBegin);
355             xmlSetProp(xsd_enum, xs_value, tmp);
356             xmlFree(tmp);
357             tokBegin = tokEnd;
358         }
359         xmlFree(str);
360 
361     }
362     else if (type)
363     {
364         str = xmlStrdup(DT_prefix);
365         str = xmlStrcat(str, BAD_CAST ":");
366         str = xmlStrcat(str, type);
367         xmlSetProp(xsd_node, xs_type, str);
368         xmlFree(str);
369     }
370     xmlFree(type);
371 
372     FOREACH_ATTR(xdr, xdr_attr)
373     {
374         if (xmlStrEqual(xdr_attr->name, xs_default))
375             XDR_A_default(xdr_attr, xsd_node);
376         else if (xmlStrEqual(xdr_attr->name, xs_name))
377             XDR_A_name(xdr_attr, xsd_node);
378         else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr))
379             XDR_A_dt_type(xdr_attr, xsd_node);
380         else if (xmlStrEqual(xdr_attr->name, xs_values) && xdr_attr->ns == get_dt_ns(xdr))
381             ; /* already handled */
382         else if (xmlStrEqual(xdr_attr->name, xs_required))
383             XDR_A_required(xdr_attr, xsd_node);
384         else
385             xmlCopyProp(xsd_node, xdr_attr);
386     }
387 
388     FOREACH_CHILD(xdr, xdr_child)
389     {
390         if (xmlStrEqual(xdr_child->name, xs_datatype))
391             ; /* already handled */
392         else if (xmlStrEqual(xdr_child->name, xs_description))
393             XDR_E_description(xdr_child, xsd_node);
394         else
395             FIXME("unexpected child <%s>\n", xdr_child->name);
396     }
397 
398     return xsd_node;
399 }
400 
XDR_E_attribute(xmlNodePtr xdr,xmlNodePtr parent)401 static xmlNodePtr XDR_E_attribute(xmlNodePtr xdr, xmlNodePtr parent)
402 {
403     xmlChar* str = xmlGetProp(xdr, xs_type);
404     xmlNodePtr xsd_node, xdr_child, xdr_attrType;
405     xmlAttrPtr xdr_attr;
406 
407     TRACE("(%p, %p)\n", xdr, parent);
408 
409     xdr_attrType = get_child_with_attr(xdr->parent, xs_AttributeType, NULL, xs_name, str);
410     xmlFree(str);
411 
412     if (xdr_attrType)
413         xsd_node = XDR_E_AttributeType(xdr_attrType, parent);
414     else
415         xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL);
416 
417     FOREACH_ATTR(xdr, xdr_attr)
418     {
419         if (xmlStrEqual(xdr_attr->name, xs_default))
420             XDR_A_default(xdr_attr, xsd_node);
421         else if (xmlStrEqual(xdr_attr->name, xs_type) && !xdr_attrType)
422             XDR_A_type(xdr_attr, xsd_node);
423         else if (xmlStrEqual(xdr_attr->name, xs_required))
424             XDR_A_required(xdr_attr, xsd_node);
425         else
426             xmlCopyProp(xsd_node, xdr_attr);
427     }
428 
429     FOREACH_CHILD(xdr, xdr_child)
430     {
431         FIXME("unexpected child <%s>\n", xdr_child->name);
432     }
433 
434     return xsd_node;
435 }
436 
XDR_E_element(xmlNodePtr xdr,xmlNodePtr parent)437 static xmlNodePtr XDR_E_element(xmlNodePtr xdr, xmlNodePtr parent)
438 {
439     xmlNodePtr xdr_child, xsd_node = xmlNewChild(parent, NULL, xs_element, NULL);
440     xmlAttrPtr xdr_attr;
441 
442     FOREACH_ATTR(xdr, xdr_attr)
443     {
444         if (xmlStrEqual(xdr_attr->name, xs_type))
445             XDR_A_type(xdr_attr, xsd_node);
446         else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs))
447             XDR_A_maxOccurs(xdr_attr, xsd_node);
448         else if (xmlStrEqual(xdr_attr->name, xs_minOccurs))
449             XDR_A_minOccurs(xdr_attr, xsd_node);
450         else
451             xmlCopyProp(xsd_node, xdr_attr);
452     }
453 
454     FOREACH_CHILD(xdr, xdr_child)
455     {
456         FIXME("unexpected child <%s>\n", xdr_child->name);
457     }
458 
459     return xsd_node;
460 }
461 
XDR_E_group(xmlNodePtr xdr,xmlNodePtr parent)462 static xmlNodePtr XDR_E_group(xmlNodePtr xdr, xmlNodePtr parent)
463 {
464     xmlNodePtr xdr_child, xsd_node;
465     xmlChar* str = xmlGetProp(xdr, xs_order);
466     xmlAttrPtr xdr_attr;
467 
468     TRACE("(%p, %p)\n", xdr, parent);
469 
470     if (!str || xmlStrEqual(str, xs_seq))
471         xsd_node = xmlNewChild(parent, NULL, xs_sequence, NULL);
472     else if (xmlStrEqual(str, xs_many))
473         xsd_node = xmlNewChild(parent, NULL, xs_choice, NULL);
474     else /* one */
475         xsd_node = xmlNewChild(parent, NULL, xs_all, NULL);
476     xmlFree(str);
477 
478     FOREACH_ATTR(xdr, xdr_attr)
479     {
480         if (xmlStrEqual(xdr_attr->name, xs_order))
481             ; /* already handled */
482         else if (xmlStrEqual(xdr_attr->name, xs_model))
483             ; /* ignored */
484         else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs))
485             XDR_A_maxOccurs(xdr_attr, xsd_node);
486         else if (xmlStrEqual(xdr_attr->name, xs_minOccurs))
487             XDR_A_minOccurs(xdr_attr, xsd_node);
488         else
489             xmlCopyProp(xsd_node, xdr_attr);
490     }
491 
492     FOREACH_CHILD(xdr, xdr_child)
493     {
494         if (xmlStrEqual(xdr_child->name, xs_description))
495             XDR_E_description(xdr_child, xsd_node);
496         else if (xmlStrEqual(xdr_child->name, xs_element))
497             XDR_E_element(xdr_child, xsd_node);
498     }
499 
500     return xsd_node;
501 }
502 
XDR_E_ElementType(xmlNodePtr xdr,xmlNodePtr parent)503 static xmlNodePtr XDR_E_ElementType(xmlNodePtr xdr, xmlNodePtr parent)
504 {
505     xmlChar *str, *type = get_dt_type(xdr);
506     BOOL is_open = TRUE;
507     int n_attributes = 0, n_elements = 0, n_groups = 0;
508     CONTENT_TYPE content;
509     ORDER_TYPE order;
510     xmlNodePtr xsd_node, xsd_type, xsd_child, xdr_child;
511     xmlAttrPtr xdr_attr;
512     xmlNsPtr dt_ns = get_dt_ns(parent);
513 
514     TRACE("(%p, %p)\n", xdr, parent);
515 
516     str = xmlGetProp(xdr, xs_model);
517     if (str && !xmlStrEqual(str, xs_open))
518         is_open = FALSE;
519     xmlFree(str);
520 
521     if (type)
522     {
523         content = CONTENT_TEXTONLY;
524     }
525     else
526     {
527         str = xmlGetProp(xdr, xs_content);
528         if (!str || xmlStrEqual(str, xs_mixed))
529             content = CONTENT_MIXED;
530         else if (xmlStrEqual(str, xs_eltOnly))
531             content = CONTENT_ELTONLY;
532         else if (xmlStrEqual(str, xs_textOnly))
533             content = CONTENT_TEXTONLY;
534         else /* empty */
535             content = CONTENT_EMPTY;
536         xmlFree(str);
537     }
538 
539     str = xmlGetProp(xdr, xs_order);
540     if (!str || xmlStrEqual(str, xs_seq))
541     {
542         order = ORDER_SEQ;
543     }
544     else if (xmlStrEqual(str, xs_many))
545     {
546         order = ORDER_MANY;
547     }
548     else /* one */
549     {
550         order = ORDER_ONE;
551         is_open = FALSE;
552     }
553     xmlFree(str);
554 
555     FOREACH_CHILD(xdr, xdr_child)
556     {
557         if (xmlStrEqual(xdr_child->name, xs_element))
558             ++n_elements;
559         else if (xmlStrEqual(xdr_child->name, xs_group))
560             ++n_groups;
561         else if (xmlStrEqual(xdr_child->name, xs_attribute))
562             ++n_attributes;
563     }
564 
565     xsd_node = xmlNewChild(parent, NULL, xs_element, NULL);
566     assert(xsd_node != NULL);
567     switch (content)
568     {
569         case CONTENT_MIXED:
570         case CONTENT_ELTONLY:
571             {
572                 xmlNodePtr xsd_base;
573                 xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
574 
575                 if (content == CONTENT_MIXED)
576                     xmlSetProp(xsd_type, xs_mixed, xs_true);
577 
578                 if (is_open)
579                     xsd_base = xmlNewChild(xsd_type, NULL, xs_sequence, NULL);
580                 else
581                     xsd_base = xsd_type;
582 
583                 if (is_open && n_elements < 2 && !n_groups)
584                 {/* no specific sequence of elements we need,
585                     just has to start with the right one, if any */
586                     if ((xdr_child = get_child(xdr, xs_element)))
587                     {
588                         xsd_child = XDR_E_element(xdr_child, xsd_base);
589                         xmlUnsetProp(xsd_child, xs_maxOccurs);
590                     }
591                 }
592                 else
593                 {
594                     switch (order)
595                     {
596                         case ORDER_SEQ:
597                             xsd_child = xmlNewChild(xsd_base, NULL, xs_sequence, NULL);
598                             break;
599                         case ORDER_MANY:
600                             xsd_child = xmlNewChild(xsd_base, NULL, xs_choice, NULL);
601                             xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded);
602                             break;
603                         case ORDER_ONE:
604                             xsd_child = xmlNewChild(xsd_base, NULL, xs_all, NULL);
605                             break;
606                     }
607 
608                     FOREACH_CHILD(xdr, xdr_child)
609                     {
610                         if (xmlStrEqual(xdr_child->name, xs_element))
611                             XDR_E_element(xdr_child, xsd_child);
612                         else if (xmlStrEqual(xdr_child->name, xs_group))
613                             XDR_E_group(xdr_child, xsd_child);
614                     }
615                 }
616 
617                 if (n_attributes)
618                 {
619                     FOREACH_CHILD(xdr, xdr_child)
620                     {
621                         if (xmlStrEqual(xdr_child->name, xs_attribute))
622                             XDR_E_attribute(xdr_child, xsd_type);
623                     }
624                 }
625 
626                 if (is_open)
627                 {
628                     add_any_child(xsd_base, TRUE);
629                     add_anyAttribute_child(xsd_type);
630                 }
631             }
632             break;
633         case CONTENT_TEXTONLY:
634             {
635                 if (is_open)
636                 {
637                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
638                     if (type)
639                     {
640                         xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL);
641                         xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL);
642                         str = xmlStrdup(DT_prefix);
643                         str = xmlStrcat(str, BAD_CAST ":");
644                         str = xmlStrcat(str, type);
645                         xmlSetProp(xsd_child, xs_base, str);
646                         xmlFree(str);
647                         assert(dt_ns != NULL);
648                         xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type);
649                     }
650                     else
651                     {
652                         xmlSetProp(xsd_type, xs_mixed, xs_true);
653                         xsd_child = xmlNewChild(xsd_type, NULL, xs_choice, NULL);
654                         xmlSetProp(xsd_child, xs_minOccurs, BAD_CAST "0");
655                         xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded);
656                         xsd_child = add_any_child(xsd_child, FALSE);
657                         xmlSetProp(xsd_child, xs_namespace, BAD_CAST "##other");
658                         xsd_child = xsd_type;
659                     }
660 
661                     if (n_attributes)
662                         FOREACH_CHILD(xdr, xdr_child)
663                         {
664                             if (xmlStrEqual(xdr_child->name, xs_attribute))
665                                 XDR_E_attribute(xdr_child, xsd_child);
666                         }
667 
668                     xmlNewChild(xsd_child, NULL, xs_anyAttribute, NULL);
669                 }
670                 else if (!n_attributes)
671                 {
672                     if (type)
673                     {
674                         str = xmlStrdup(DT_prefix);
675                         str = xmlStrcat(str, BAD_CAST ":");
676                         str = xmlStrcat(str, type);
677                         xmlSetProp(xsd_node, xs_type, str);
678                         xmlFree(str);
679                         str = NULL;
680                         xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type);
681                     }
682                     else
683                     {
684                         xmlSetProp(xsd_node, xs_type, xs_xsd_string);
685                     }
686                 }
687                 else
688                 {
689                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
690                     xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL);
691                     xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL);
692                     xmlSetProp(xsd_child, xs_base, xs_xsd_string);
693 
694                     FOREACH_CHILD(xdr, xdr_child)
695                     {
696                         if (xmlStrEqual(xdr_child->name, xs_attribute))
697                             XDR_E_attribute(xdr_child, xsd_child);
698                     }
699                 }
700             }
701             break;
702         case CONTENT_EMPTY: /* not allowed with model="open" */
703             {
704                 if (n_attributes)
705                 {
706                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
707 
708                     FOREACH_CHILD(xdr, xdr_child)
709                     {
710                         if (xmlStrEqual(xdr_child->name, xs_attribute))
711                             XDR_E_attribute(xdr_child, xsd_type);
712                     }
713                 }
714                 else
715                 {
716                     xsd_type = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL);
717                     xsd_child = xmlNewChild(xsd_type, NULL, xs_restriction, NULL);
718                     xmlSetProp(xsd_child, xs_base, xs_xsd_string);
719                     xsd_child = xmlNewChild(xsd_child, NULL, xs_length, NULL);
720                     xmlSetProp(xsd_child, xs_value, BAD_CAST "0");
721                 }
722             }
723             break;
724     }
725     xmlFree(type);
726 
727     FOREACH_ATTR(xdr, xdr_attr)
728     {
729         if (xmlStrEqual(xdr_attr->name, xs_content))
730             ; /* already handled */
731         else if (xmlStrEqual(xdr_attr->name, xs_name))
732             XDR_A_name(xdr_attr, xsd_node);
733         else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr))
734             XDR_A_dt_type(xdr_attr, xsd_node);
735         else if (xmlStrEqual(xdr_attr->name, xs_model))
736             ; /* already handled */
737         else if (xmlStrEqual(xdr_attr->name, xs_order))
738             ; /* already handled */
739         else
740             xmlCopyProp(xsd_node, xdr_attr);
741 
742     }
743 
744     FOREACH_CHILD(xdr, xdr_child)
745     {
746         if (xmlStrEqual(xdr_child->name, xs_attribute))
747             ; /* already handled */
748         else if (xmlStrEqual(xdr_child->name, xs_AttributeType))
749             ; /* handled through XDR_E_attribute when parent is not <Schema> */
750         else if (xmlStrEqual(xdr_child->name, xs_datatype))
751             ; /* already handled */
752         else if (xmlStrEqual(xdr_child->name, xs_description))
753             XDR_E_description(xdr_child, xsd_node);
754         else if (xmlStrEqual(xdr_child->name, xs_element))
755             ; /* already handled */
756         else if (xmlStrEqual(xdr_child->name, xs_group))
757             ; /* already handled */
758         else
759             FIXME("unexpected child <%s>\n", xdr_child->name);
760     }
761 
762     return xsd_node;
763 }
764 
XDR_E_Schema(xmlNodePtr xdr,xmlNodePtr parent,xmlChar const * nsURI)765 static xmlNodePtr XDR_E_Schema(xmlNodePtr xdr, xmlNodePtr parent, xmlChar const* nsURI)
766 {
767     xmlNodePtr xsd_node, xdr_child;
768     xmlNsPtr ns, xdr_ns;
769     xmlAttrPtr xdr_attr;
770 
771     TRACE("(%p, %p)\n", xdr, parent);
772 
773     xsd_node = xmlNewDocNode((xmlDocPtr)parent, NULL, xs_schema, NULL);
774     xmlDocSetRootElement((xmlDocPtr)parent, xsd_node);
775     assert(xsd_node != NULL);
776 
777     if (nsURI && *nsURI) xmlNewNs(xsd_node, nsURI, NULL);
778     ns = xmlNewNs(xsd_node, XSD_href, XSD_prefix);
779     assert(ns != NULL);
780 
781     xmlSetNs(xsd_node, ns);
782 
783     if (nsURI && *nsURI) xmlSetProp(xsd_node, xs_targetNamespace, nsURI);
784 
785     FOREACH_NS(xdr, xdr_ns)
786     {
787         /* TODO: special handling for dt namespace? */
788         assert(xdr_ns->href != NULL);
789         if (xmlStrEqual(xdr_ns->href, XDR_href))
790             ; /* ignored */
791         else if (xdr_ns->prefix != NULL)
792             xmlNewNs(xsd_node, xdr_ns->href, xdr_ns->prefix);
793         else
794             FIXME("unexpected default xmlns: %s\n", xdr_ns->href);
795     }
796 
797     FOREACH_ATTR(xdr, xdr_attr)
798     {
799         xmlCopyProp(xsd_node, xdr_attr);
800     }
801 
802     FOREACH_CHILD(xdr, xdr_child)
803     {
804         if (xmlStrEqual(xdr_child->name, xs_AttributeType))
805             XDR_E_AttributeType(xdr_child, xsd_node);
806         else if (xmlStrEqual(xdr_child->name, xs_description))
807             XDR_E_description(xdr_child, xsd_node);
808         else if (xmlStrEqual(xdr_child->name, xs_ElementType))
809             XDR_E_ElementType(xdr_child, xsd_node);
810         else
811             FIXME("unexpected child <%s>\n", xdr_child->name);
812     }
813 
814     return xsd_node;
815 }
816 
XDR_to_XSD_doc(xmlDocPtr xdr_doc,xmlChar const * nsURI)817 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI)
818 {
819     xmlDocPtr xsd_doc = xmlNewDoc(NULL);
820 
821     TRACE("(%p)\n", xdr_doc);
822 
823     XDR_E_Schema(get_schema((xmlNodePtr)xdr_doc), (xmlNodePtr)xsd_doc, nsURI);
824 
825     return xsd_doc;
826 }
827 
828 #endif /* HAVE_LIBXML2 */
829