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