xref: /reactos/sdk/lib/3rdparty/libxml2/relaxng.c (revision 279107d5)
1 /*
2  * relaxng.c : implementation of the Relax-NG handling and validity checking
3  *
4  * See Copyright for the status of this software.
5  *
6  * Daniel Veillard <veillard@redhat.com>
7  */
8 
9 /**
10  * TODO:
11  * - add support for DTD compatibility spec
12  *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13  * - report better mem allocations pbms at runtime and abort immediately.
14  */
15 
16 #define IN_LIBXML
17 #include "libxml.h"
18 
19 #ifdef LIBXML_SCHEMAS_ENABLED
20 
21 #include <string.h>
22 #include <stdio.h>
23 #include <stddef.h>
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26 #include <libxml/parserInternals.h>
27 #include <libxml/hash.h>
28 #include <libxml/uri.h>
29 
30 #include <libxml/relaxng.h>
31 
32 #include <libxml/xmlschemastypes.h>
33 #include <libxml/xmlautomata.h>
34 #include <libxml/xmlregexp.h>
35 #include <libxml/xmlschemastypes.h>
36 
37 /*
38  * The Relax-NG namespace
39  */
40 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
41     "http://relaxng.org/ns/structure/1.0";
42 
43 #define IS_RELAXNG(node, typ)						\
44    ((node != NULL) && (node->ns != NULL) &&				\
45     (node->type == XML_ELEMENT_NODE) &&					\
46     (xmlStrEqual(node->name, (const xmlChar *) typ)) &&		\
47     (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
48 
49 
50 #if 0
51 #define DEBUG 1
52 
53 #define DEBUG_GRAMMAR 1
54 
55 #define DEBUG_CONTENT 1
56 
57 #define DEBUG_TYPE 1
58 
59 #define DEBUG_VALID 1
60 
61 #define DEBUG_INTERLEAVE 1
62 
63 #define DEBUG_LIST 1
64 
65 #define DEBUG_INCLUDE 1
66 
67 #define DEBUG_ERROR 1
68 
69 #define DEBUG_COMPILE 1
70 
71 #define DEBUG_PROGRESSIVE 1
72 #endif
73 
74 #define MAX_ERROR 5
75 
76 #define TODO								\
77     xmlGenericError(xmlGenericErrorContext,				\
78 	    "Unimplemented block at %s:%d\n",				\
79             __FILE__, __LINE__);
80 
81 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
82 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
83 
84 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
85 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
86 
87 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
88 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
89 
90 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
91 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
92 
93 typedef enum {
94     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
95     XML_RELAXNG_COMBINE_CHOICE, /* choice */
96     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
97 } xmlRelaxNGCombine;
98 
99 typedef enum {
100     XML_RELAXNG_CONTENT_ERROR = -1,
101     XML_RELAXNG_CONTENT_EMPTY = 0,
102     XML_RELAXNG_CONTENT_SIMPLE,
103     XML_RELAXNG_CONTENT_COMPLEX
104 } xmlRelaxNGContentType;
105 
106 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
107 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
108 
109 struct _xmlRelaxNGGrammar {
110     xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */
111     xmlRelaxNGGrammarPtr children;      /* the children grammar if any */
112     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
113     xmlRelaxNGDefinePtr start;  /* <start> content */
114     xmlRelaxNGCombine combine;  /* the default combine value */
115     xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */
116     xmlHashTablePtr defs;       /* define* */
117     xmlHashTablePtr refs;       /* references */
118 };
119 
120 
121 typedef enum {
122     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
123     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
124     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
125     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
126     XML_RELAXNG_TEXT,           /* textual content */
127     XML_RELAXNG_ELEMENT,        /* an element */
128     XML_RELAXNG_DATATYPE,       /* extenal data type definition */
129     XML_RELAXNG_PARAM,          /* extenal data type parameter */
130     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
131     XML_RELAXNG_LIST,           /* a list of patterns */
132     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
133     XML_RELAXNG_DEF,            /* a definition */
134     XML_RELAXNG_REF,            /* reference to a definition */
135     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
136     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
137     XML_RELAXNG_OPTIONAL,       /* optional patterns */
138     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
139     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
140     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
141     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
142     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
143     XML_RELAXNG_START           /* Used to keep track of starts on grammars */
144 } xmlRelaxNGType;
145 
146 #define IS_NULLABLE		(1 << 0)
147 #define IS_NOT_NULLABLE		(1 << 1)
148 #define IS_INDETERMINIST	(1 << 2)
149 #define IS_MIXED		(1 << 3)
150 #define IS_TRIABLE		(1 << 4)
151 #define IS_PROCESSED		(1 << 5)
152 #define IS_COMPILABLE		(1 << 6)
153 #define IS_NOT_COMPILABLE	(1 << 7)
154 #define IS_EXTERNAL_REF	        (1 << 8)
155 
156 struct _xmlRelaxNGDefine {
157     xmlRelaxNGType type;        /* the type of definition */
158     xmlNodePtr node;            /* the node in the source */
159     xmlChar *name;              /* the element local name if present */
160     xmlChar *ns;                /* the namespace local name if present */
161     xmlChar *value;             /* value when available */
162     void *data;                 /* data lib or specific pointer */
163     xmlRelaxNGDefinePtr content;        /* the expected content */
164     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
165     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
166     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
167     xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */
168     xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */
169     short depth;                /* used for the cycle detection */
170     short dflags;               /* define related flags */
171     xmlRegexpPtr contModel;     /* a compiled content model if available */
172 };
173 
174 /**
175  * _xmlRelaxNG:
176  *
177  * A RelaxNGs definition
178  */
179 struct _xmlRelaxNG {
180     void *_private;             /* unused by the library for users or bindings */
181     xmlRelaxNGGrammarPtr topgrammar;
182     xmlDocPtr doc;
183 
184     int idref;                  /* requires idref checking */
185 
186     xmlHashTablePtr defs;       /* define */
187     xmlHashTablePtr refs;       /* references */
188     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
189     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
190     int defNr;                  /* number of defines used */
191     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
192 
193 };
194 
195 #define XML_RELAXNG_IN_ATTRIBUTE	(1 << 0)
196 #define XML_RELAXNG_IN_ONEORMORE	(1 << 1)
197 #define XML_RELAXNG_IN_LIST		(1 << 2)
198 #define XML_RELAXNG_IN_DATAEXCEPT	(1 << 3)
199 #define XML_RELAXNG_IN_START		(1 << 4)
200 #define XML_RELAXNG_IN_OOMGROUP		(1 << 5)
201 #define XML_RELAXNG_IN_OOMINTERLEAVE	(1 << 6)
202 #define XML_RELAXNG_IN_EXTERNALREF	(1 << 7)
203 #define XML_RELAXNG_IN_ANYEXCEPT	(1 << 8)
204 #define XML_RELAXNG_IN_NSEXCEPT		(1 << 9)
205 
206 struct _xmlRelaxNGParserCtxt {
207     void *userData;             /* user specific data block */
208     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
209     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
210     xmlStructuredErrorFunc serror;
211     xmlRelaxNGValidErr err;
212 
213     xmlRelaxNGPtr schema;       /* The schema in use */
214     xmlRelaxNGGrammarPtr grammar;       /* the current grammar */
215     xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
216     int flags;                  /* parser flags */
217     int nbErrors;               /* number of errors at parse time */
218     int nbWarnings;             /* number of warnings at parse time */
219     const xmlChar *define;      /* the current define scope */
220     xmlRelaxNGDefinePtr def;    /* the current define */
221 
222     int nbInterleaves;
223     xmlHashTablePtr interleaves;        /* keep track of all the interleaves */
224 
225     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
226     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
227     xmlChar *URL;
228     xmlDocPtr document;
229 
230     int defNr;                  /* number of defines used */
231     int defMax;                 /* number of defines aloocated */
232     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
233 
234     const char *buffer;
235     int size;
236 
237     /* the document stack */
238     xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */
239     int docNr;                  /* Depth of the parsing stack */
240     int docMax;                 /* Max depth of the parsing stack */
241     xmlRelaxNGDocumentPtr *docTab;      /* array of docs */
242 
243     /* the include stack */
244     xmlRelaxNGIncludePtr inc;   /* Current parsed include */
245     int incNr;                  /* Depth of the include parsing stack */
246     int incMax;                 /* Max depth of the parsing stack */
247     xmlRelaxNGIncludePtr *incTab;       /* array of incs */
248 
249     int idref;                  /* requires idref checking */
250 
251     /* used to compile content models */
252     xmlAutomataPtr am;          /* the automata */
253     xmlAutomataStatePtr state;  /* used to build the automata */
254 
255     int crng;			/* compact syntax and other flags */
256     int freedoc;		/* need to free the document */
257 };
258 
259 #define FLAGS_IGNORABLE		1
260 #define FLAGS_NEGATIVE		2
261 #define FLAGS_MIXED_CONTENT	4
262 #define FLAGS_NOERROR		8
263 
264 /**
265  * xmlRelaxNGInterleaveGroup:
266  *
267  * A RelaxNGs partition set associated to lists of definitions
268  */
269 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
270 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
271 struct _xmlRelaxNGInterleaveGroup {
272     xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */
273     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
274     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
275 };
276 
277 #define IS_DETERMINIST		1
278 #define IS_NEEDCHECK		2
279 
280 /**
281  * xmlRelaxNGPartitions:
282  *
283  * A RelaxNGs partition associated to an interleave group
284  */
285 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
286 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
287 struct _xmlRelaxNGPartition {
288     int nbgroups;               /* number of groups in the partitions */
289     xmlHashTablePtr triage;     /* hash table used to direct nodes to the
290                                  * right group when possible */
291     int flags;                  /* determinist ? */
292     xmlRelaxNGInterleaveGroupPtr *groups;
293 };
294 
295 /**
296  * xmlRelaxNGValidState:
297  *
298  * A RelaxNGs validation state
299  */
300 #define MAX_ATTR 20
301 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
302 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
303 struct _xmlRelaxNGValidState {
304     xmlNodePtr node;            /* the current node */
305     xmlNodePtr seq;             /* the sequence of children left to validate */
306     int nbAttrs;                /* the number of attributes */
307     int maxAttrs;               /* the size of attrs */
308     int nbAttrLeft;             /* the number of attributes left to validate */
309     xmlChar *value;             /* the value when operating on string */
310     xmlChar *endvalue;          /* the end value when operating on string */
311     xmlAttrPtr *attrs;          /* the array of attributes */
312 };
313 
314 /**
315  * xmlRelaxNGStates:
316  *
317  * A RelaxNGs container for validation state
318  */
319 typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
320 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
321 struct _xmlRelaxNGStates {
322     int nbState;                /* the number of states */
323     int maxState;               /* the size of the array */
324     xmlRelaxNGValidStatePtr *tabState;
325 };
326 
327 #define ERROR_IS_DUP	1
328 
329 /**
330  * xmlRelaxNGValidError:
331  *
332  * A RelaxNGs validation error
333  */
334 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
335 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
336 struct _xmlRelaxNGValidError {
337     xmlRelaxNGValidErr err;     /* the error number */
338     int flags;                  /* flags */
339     xmlNodePtr node;            /* the current node */
340     xmlNodePtr seq;             /* the current child */
341     const xmlChar *arg1;        /* first arg */
342     const xmlChar *arg2;        /* second arg */
343 };
344 
345 /**
346  * xmlRelaxNGValidCtxt:
347  *
348  * A RelaxNGs validation context
349  */
350 
351 struct _xmlRelaxNGValidCtxt {
352     void *userData;             /* user specific data block */
353     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
354     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
355     xmlStructuredErrorFunc serror;
356     int nbErrors;               /* number of errors in validation */
357 
358     xmlRelaxNGPtr schema;       /* The schema in use */
359     xmlDocPtr doc;              /* the document being validated */
360     int flags;                  /* validation flags */
361     int depth;                  /* validation depth */
362     int idref;                  /* requires idref checking */
363     int errNo;                  /* the first error found */
364 
365     /*
366      * Errors accumulated in branches may have to be stacked to be
367      * provided back when it's sure they affect validation.
368      */
369     xmlRelaxNGValidErrorPtr err;        /* Last error */
370     int errNr;                  /* Depth of the error stack */
371     int errMax;                 /* Max depth of the error stack */
372     xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
373 
374     xmlRelaxNGValidStatePtr state;      /* the current validation state */
375     xmlRelaxNGStatesPtr states; /* the accumulated state list */
376 
377     xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */
378     int freeStatesNr;
379     int freeStatesMax;
380     xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */
381 
382     /*
383      * This is used for "progressive" validation
384      */
385     xmlRegExecCtxtPtr elem;     /* the current element regexp */
386     int elemNr;                 /* the number of element validated */
387     int elemMax;                /* the max depth of elements */
388     xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
389     int pstate;                 /* progressive state */
390     xmlNodePtr pnode;           /* the current node */
391     xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */
392     int perr;                   /* signal error in content model
393                                  * outside the regexp */
394 };
395 
396 /**
397  * xmlRelaxNGInclude:
398  *
399  * Structure associated to a RelaxNGs document element
400  */
401 struct _xmlRelaxNGInclude {
402     xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
403     xmlChar *href;              /* the normalized href value */
404     xmlDocPtr doc;              /* the associated XML document */
405     xmlRelaxNGDefinePtr content;        /* the definitions */
406     xmlRelaxNGPtr schema;       /* the schema */
407 };
408 
409 /**
410  * xmlRelaxNGDocument:
411  *
412  * Structure associated to a RelaxNGs document element
413  */
414 struct _xmlRelaxNGDocument {
415     xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
416     xmlChar *href;              /* the normalized href value */
417     xmlDocPtr doc;              /* the associated XML document */
418     xmlRelaxNGDefinePtr content;        /* the definitions */
419     xmlRelaxNGPtr schema;       /* the schema */
420     int externalRef;            /* 1 if an external ref */
421 };
422 
423 
424 /************************************************************************
425  *									*
426  *		Some factorized error routines				*
427  *									*
428  ************************************************************************/
429 
430 /**
431  * xmlRngPErrMemory:
432  * @ctxt:  an Relax-NG parser context
433  * @extra:  extra informations
434  *
435  * Handle a redefinition of attribute error
436  */
437 static void
438 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
439 {
440     xmlStructuredErrorFunc schannel = NULL;
441     xmlGenericErrorFunc channel = NULL;
442     void *data = NULL;
443 
444     if (ctxt != NULL) {
445         if (ctxt->serror != NULL)
446 	    schannel = ctxt->serror;
447 	else
448 	    channel = ctxt->error;
449         data = ctxt->userData;
450         ctxt->nbErrors++;
451     }
452     if (extra)
453         __xmlRaiseError(schannel, channel, data,
454                         NULL, NULL, XML_FROM_RELAXNGP,
455                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
456                         NULL, NULL, 0, 0,
457                         "Memory allocation failed : %s\n", extra);
458     else
459         __xmlRaiseError(schannel, channel, data,
460                         NULL, NULL, XML_FROM_RELAXNGP,
461                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
462                         NULL, NULL, 0, 0, "Memory allocation failed\n");
463 }
464 
465 /**
466  * xmlRngVErrMemory:
467  * @ctxt:  a Relax-NG validation context
468  * @extra:  extra informations
469  *
470  * Handle a redefinition of attribute error
471  */
472 static void
473 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
474 {
475     xmlStructuredErrorFunc schannel = NULL;
476     xmlGenericErrorFunc channel = NULL;
477     void *data = NULL;
478 
479     if (ctxt != NULL) {
480         if (ctxt->serror != NULL)
481 	    schannel = ctxt->serror;
482 	else
483 	    channel = ctxt->error;
484         data = ctxt->userData;
485         ctxt->nbErrors++;
486     }
487     if (extra)
488         __xmlRaiseError(schannel, channel, data,
489                         NULL, NULL, XML_FROM_RELAXNGV,
490                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
491                         NULL, NULL, 0, 0,
492                         "Memory allocation failed : %s\n", extra);
493     else
494         __xmlRaiseError(schannel, channel, data,
495                         NULL, NULL, XML_FROM_RELAXNGV,
496                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
497                         NULL, NULL, 0, 0, "Memory allocation failed\n");
498 }
499 
500 /**
501  * xmlRngPErr:
502  * @ctxt:  a Relax-NG parser context
503  * @node:  the node raising the error
504  * @error:  the error code
505  * @msg:  message
506  * @str1:  extra info
507  * @str2:  extra info
508  *
509  * Handle a Relax NG Parsing error
510  */
511 static void LIBXML_ATTR_FORMAT(4,0)
512 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
513            const char *msg, const xmlChar * str1, const xmlChar * str2)
514 {
515     xmlStructuredErrorFunc schannel = NULL;
516     xmlGenericErrorFunc channel = NULL;
517     void *data = NULL;
518 
519     if (ctxt != NULL) {
520         if (ctxt->serror != NULL)
521 	    schannel = ctxt->serror;
522 	else
523 	    channel = ctxt->error;
524         data = ctxt->userData;
525         ctxt->nbErrors++;
526     }
527     __xmlRaiseError(schannel, channel, data,
528                     NULL, node, XML_FROM_RELAXNGP,
529                     error, XML_ERR_ERROR, NULL, 0,
530                     (const char *) str1, (const char *) str2, NULL, 0, 0,
531                     msg, str1, str2);
532 }
533 
534 /**
535  * xmlRngVErr:
536  * @ctxt:  a Relax-NG validation context
537  * @node:  the node raising the error
538  * @error:  the error code
539  * @msg:  message
540  * @str1:  extra info
541  * @str2:  extra info
542  *
543  * Handle a Relax NG Validation error
544  */
545 static void LIBXML_ATTR_FORMAT(4,0)
546 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
547            const char *msg, const xmlChar * str1, const xmlChar * str2)
548 {
549     xmlStructuredErrorFunc schannel = NULL;
550     xmlGenericErrorFunc channel = NULL;
551     void *data = NULL;
552 
553     if (ctxt != NULL) {
554         if (ctxt->serror != NULL)
555 	    schannel = ctxt->serror;
556 	else
557 	    channel = ctxt->error;
558         data = ctxt->userData;
559         ctxt->nbErrors++;
560     }
561     __xmlRaiseError(schannel, channel, data,
562                     NULL, node, XML_FROM_RELAXNGV,
563                     error, XML_ERR_ERROR, NULL, 0,
564                     (const char *) str1, (const char *) str2, NULL, 0, 0,
565                     msg, str1, str2);
566 }
567 
568 /************************************************************************
569  *									*
570  *		Preliminary type checking interfaces			*
571  *									*
572  ************************************************************************/
573 
574 /**
575  * xmlRelaxNGTypeHave:
576  * @data:  data needed for the library
577  * @type:  the type name
578  * @value:  the value to check
579  *
580  * Function provided by a type library to check if a type is exported
581  *
582  * Returns 1 if yes, 0 if no and -1 in case of error.
583  */
584 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
585 
586 /**
587  * xmlRelaxNGTypeCheck:
588  * @data:  data needed for the library
589  * @type:  the type name
590  * @value:  the value to check
591  * @result:  place to store the result if needed
592  *
593  * Function provided by a type library to check if a value match a type
594  *
595  * Returns 1 if yes, 0 if no and -1 in case of error.
596  */
597 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
598                                     const xmlChar * value, void **result,
599                                     xmlNodePtr node);
600 
601 /**
602  * xmlRelaxNGFacetCheck:
603  * @data:  data needed for the library
604  * @type:  the type name
605  * @facet:  the facet name
606  * @val:  the facet value
607  * @strval:  the string value
608  * @value:  the value to check
609  *
610  * Function provided by a type library to check a value facet
611  *
612  * Returns 1 if yes, 0 if no and -1 in case of error.
613  */
614 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
615                                      const xmlChar * facet,
616                                      const xmlChar * val,
617                                      const xmlChar * strval, void *value);
618 
619 /**
620  * xmlRelaxNGTypeFree:
621  * @data:  data needed for the library
622  * @result:  the value to free
623  *
624  * Function provided by a type library to free a returned result
625  */
626 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
627 
628 /**
629  * xmlRelaxNGTypeCompare:
630  * @data:  data needed for the library
631  * @type:  the type name
632  * @value1:  the first value
633  * @value2:  the second value
634  *
635  * Function provided by a type library to compare two values accordingly
636  * to a type.
637  *
638  * Returns 1 if yes, 0 if no and -1 in case of error.
639  */
640 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
641                                       const xmlChar * value1,
642                                       xmlNodePtr ctxt1,
643                                       void *comp1,
644                                       const xmlChar * value2,
645                                       xmlNodePtr ctxt2);
646 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
647 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
648 struct _xmlRelaxNGTypeLibrary {
649     const xmlChar *namespace;   /* the datatypeLibrary value */
650     void *data;                 /* data needed for the library */
651     xmlRelaxNGTypeHave have;    /* the export function */
652     xmlRelaxNGTypeCheck check;  /* the checking function */
653     xmlRelaxNGTypeCompare comp; /* the compare function */
654     xmlRelaxNGFacetCheck facet; /* the facet check function */
655     xmlRelaxNGTypeFree freef;   /* the freeing function */
656 };
657 
658 /************************************************************************
659  *									*
660  *			Allocation functions				*
661  *									*
662  ************************************************************************/
663 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
664 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
665 static void xmlRelaxNGNormExtSpace(xmlChar * value);
666 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
667 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
668                                      ATTRIBUTE_UNUSED,
669                                      xmlRelaxNGValidStatePtr state1,
670                                      xmlRelaxNGValidStatePtr state2);
671 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
672                                      xmlRelaxNGValidStatePtr state);
673 
674 /**
675  * xmlRelaxNGFreeDocument:
676  * @docu:  a document structure
677  *
678  * Deallocate a RelaxNG document structure.
679  */
680 static void
681 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
682 {
683     if (docu == NULL)
684         return;
685 
686     if (docu->href != NULL)
687         xmlFree(docu->href);
688     if (docu->doc != NULL)
689         xmlFreeDoc(docu->doc);
690     if (docu->schema != NULL)
691         xmlRelaxNGFreeInnerSchema(docu->schema);
692     xmlFree(docu);
693 }
694 
695 /**
696  * xmlRelaxNGFreeDocumentList:
697  * @docu:  a list of  document structure
698  *
699  * Deallocate a RelaxNG document structures.
700  */
701 static void
702 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
703 {
704     xmlRelaxNGDocumentPtr next;
705 
706     while (docu != NULL) {
707         next = docu->next;
708         xmlRelaxNGFreeDocument(docu);
709         docu = next;
710     }
711 }
712 
713 /**
714  * xmlRelaxNGFreeInclude:
715  * @incl:  a include structure
716  *
717  * Deallocate a RelaxNG include structure.
718  */
719 static void
720 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
721 {
722     if (incl == NULL)
723         return;
724 
725     if (incl->href != NULL)
726         xmlFree(incl->href);
727     if (incl->doc != NULL)
728         xmlFreeDoc(incl->doc);
729     if (incl->schema != NULL)
730         xmlRelaxNGFree(incl->schema);
731     xmlFree(incl);
732 }
733 
734 /**
735  * xmlRelaxNGFreeIncludeList:
736  * @incl:  a include structure list
737  *
738  * Deallocate a RelaxNG include structure.
739  */
740 static void
741 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
742 {
743     xmlRelaxNGIncludePtr next;
744 
745     while (incl != NULL) {
746         next = incl->next;
747         xmlRelaxNGFreeInclude(incl);
748         incl = next;
749     }
750 }
751 
752 /**
753  * xmlRelaxNGNewRelaxNG:
754  * @ctxt:  a Relax-NG validation context (optional)
755  *
756  * Allocate a new RelaxNG structure.
757  *
758  * Returns the newly allocated structure or NULL in case or error
759  */
760 static xmlRelaxNGPtr
761 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
762 {
763     xmlRelaxNGPtr ret;
764 
765     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
766     if (ret == NULL) {
767         xmlRngPErrMemory(ctxt, NULL);
768         return (NULL);
769     }
770     memset(ret, 0, sizeof(xmlRelaxNG));
771 
772     return (ret);
773 }
774 
775 /**
776  * xmlRelaxNGFreeInnerSchema:
777  * @schema:  a schema structure
778  *
779  * Deallocate a RelaxNG schema structure.
780  */
781 static void
782 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
783 {
784     if (schema == NULL)
785         return;
786 
787     if (schema->doc != NULL)
788         xmlFreeDoc(schema->doc);
789     if (schema->defTab != NULL) {
790         int i;
791 
792         for (i = 0; i < schema->defNr; i++)
793             xmlRelaxNGFreeDefine(schema->defTab[i]);
794         xmlFree(schema->defTab);
795     }
796 
797     xmlFree(schema);
798 }
799 
800 /**
801  * xmlRelaxNGFree:
802  * @schema:  a schema structure
803  *
804  * Deallocate a RelaxNG structure.
805  */
806 void
807 xmlRelaxNGFree(xmlRelaxNGPtr schema)
808 {
809     if (schema == NULL)
810         return;
811 
812     if (schema->topgrammar != NULL)
813         xmlRelaxNGFreeGrammar(schema->topgrammar);
814     if (schema->doc != NULL)
815         xmlFreeDoc(schema->doc);
816     if (schema->documents != NULL)
817         xmlRelaxNGFreeDocumentList(schema->documents);
818     if (schema->includes != NULL)
819         xmlRelaxNGFreeIncludeList(schema->includes);
820     if (schema->defTab != NULL) {
821         int i;
822 
823         for (i = 0; i < schema->defNr; i++)
824             xmlRelaxNGFreeDefine(schema->defTab[i]);
825         xmlFree(schema->defTab);
826     }
827 
828     xmlFree(schema);
829 }
830 
831 /**
832  * xmlRelaxNGNewGrammar:
833  * @ctxt:  a Relax-NG validation context (optional)
834  *
835  * Allocate a new RelaxNG grammar.
836  *
837  * Returns the newly allocated structure or NULL in case or error
838  */
839 static xmlRelaxNGGrammarPtr
840 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
841 {
842     xmlRelaxNGGrammarPtr ret;
843 
844     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
845     if (ret == NULL) {
846         xmlRngPErrMemory(ctxt, NULL);
847         return (NULL);
848     }
849     memset(ret, 0, sizeof(xmlRelaxNGGrammar));
850 
851     return (ret);
852 }
853 
854 /**
855  * xmlRelaxNGFreeGrammar:
856  * @grammar:  a grammar structure
857  *
858  * Deallocate a RelaxNG grammar structure.
859  */
860 static void
861 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
862 {
863     if (grammar == NULL)
864         return;
865 
866     if (grammar->children != NULL) {
867         xmlRelaxNGFreeGrammar(grammar->children);
868     }
869     if (grammar->next != NULL) {
870         xmlRelaxNGFreeGrammar(grammar->next);
871     }
872     if (grammar->refs != NULL) {
873         xmlHashFree(grammar->refs, NULL);
874     }
875     if (grammar->defs != NULL) {
876         xmlHashFree(grammar->defs, NULL);
877     }
878 
879     xmlFree(grammar);
880 }
881 
882 /**
883  * xmlRelaxNGNewDefine:
884  * @ctxt:  a Relax-NG validation context
885  * @node:  the node in the input document.
886  *
887  * Allocate a new RelaxNG define.
888  *
889  * Returns the newly allocated structure or NULL in case or error
890  */
891 static xmlRelaxNGDefinePtr
892 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
893 {
894     xmlRelaxNGDefinePtr ret;
895 
896     if (ctxt->defMax == 0) {
897         ctxt->defMax = 16;
898         ctxt->defNr = 0;
899         ctxt->defTab = (xmlRelaxNGDefinePtr *)
900             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
901         if (ctxt->defTab == NULL) {
902             xmlRngPErrMemory(ctxt, "allocating define\n");
903             return (NULL);
904         }
905     } else if (ctxt->defMax <= ctxt->defNr) {
906         xmlRelaxNGDefinePtr *tmp;
907 
908         ctxt->defMax *= 2;
909         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
910                                                  ctxt->defMax *
911                                                  sizeof
912                                                  (xmlRelaxNGDefinePtr));
913         if (tmp == NULL) {
914             xmlRngPErrMemory(ctxt, "allocating define\n");
915             return (NULL);
916         }
917         ctxt->defTab = tmp;
918     }
919     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
920     if (ret == NULL) {
921         xmlRngPErrMemory(ctxt, "allocating define\n");
922         return (NULL);
923     }
924     memset(ret, 0, sizeof(xmlRelaxNGDefine));
925     ctxt->defTab[ctxt->defNr++] = ret;
926     ret->node = node;
927     ret->depth = -1;
928     return (ret);
929 }
930 
931 /**
932  * xmlRelaxNGFreePartition:
933  * @partitions:  a partition set structure
934  *
935  * Deallocate RelaxNG partition set structures.
936  */
937 static void
938 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
939 {
940     xmlRelaxNGInterleaveGroupPtr group;
941     int j;
942 
943     if (partitions != NULL) {
944         if (partitions->groups != NULL) {
945             for (j = 0; j < partitions->nbgroups; j++) {
946                 group = partitions->groups[j];
947                 if (group != NULL) {
948                     if (group->defs != NULL)
949                         xmlFree(group->defs);
950                     if (group->attrs != NULL)
951                         xmlFree(group->attrs);
952                     xmlFree(group);
953                 }
954             }
955             xmlFree(partitions->groups);
956         }
957         if (partitions->triage != NULL) {
958             xmlHashFree(partitions->triage, NULL);
959         }
960         xmlFree(partitions);
961     }
962 }
963 
964 /**
965  * xmlRelaxNGFreeDefine:
966  * @define:  a define structure
967  *
968  * Deallocate a RelaxNG define structure.
969  */
970 static void
971 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
972 {
973     if (define == NULL)
974         return;
975 
976     if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
977         xmlRelaxNGTypeLibraryPtr lib;
978 
979         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
980         if ((lib != NULL) && (lib->freef != NULL))
981             lib->freef(lib->data, (void *) define->attrs);
982     }
983     if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
984         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
985     if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
986         xmlHashFree((xmlHashTablePtr) define->data, NULL);
987     if (define->name != NULL)
988         xmlFree(define->name);
989     if (define->ns != NULL)
990         xmlFree(define->ns);
991     if (define->value != NULL)
992         xmlFree(define->value);
993     if (define->contModel != NULL)
994         xmlRegFreeRegexp(define->contModel);
995     xmlFree(define);
996 }
997 
998 /**
999  * xmlRelaxNGNewStates:
1000  * @ctxt:  a Relax-NG validation context
1001  * @size:  the default size for the container
1002  *
1003  * Allocate a new RelaxNG validation state container
1004  *
1005  * Returns the newly allocated structure or NULL in case or error
1006  */
1007 static xmlRelaxNGStatesPtr
1008 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1009 {
1010     xmlRelaxNGStatesPtr ret;
1011 
1012     if ((ctxt != NULL) &&
1013         (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
1014         ctxt->freeStatesNr--;
1015         ret = ctxt->freeStates[ctxt->freeStatesNr];
1016         ret->nbState = 0;
1017         return (ret);
1018     }
1019     if (size < 16)
1020         size = 16;
1021 
1022     ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
1023                                           (size -
1024                                            1) *
1025                                           sizeof(xmlRelaxNGValidStatePtr));
1026     if (ret == NULL) {
1027         xmlRngVErrMemory(ctxt, "allocating states\n");
1028         return (NULL);
1029     }
1030     ret->nbState = 0;
1031     ret->maxState = size;
1032     ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1033                                                           sizeof
1034                                                           (xmlRelaxNGValidStatePtr));
1035     if (ret->tabState == NULL) {
1036         xmlRngVErrMemory(ctxt, "allocating states\n");
1037         xmlFree(ret);
1038         return (NULL);
1039     }
1040     return (ret);
1041 }
1042 
1043 /**
1044  * xmlRelaxNGAddStateUniq:
1045  * @ctxt:  a Relax-NG validation context
1046  * @states:  the states container
1047  * @state:  the validation state
1048  *
1049  * Add a RelaxNG validation state to the container without checking
1050  * for unicity.
1051  *
1052  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1053  */
1054 static int
1055 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
1056                         xmlRelaxNGStatesPtr states,
1057                         xmlRelaxNGValidStatePtr state)
1058 {
1059     if (state == NULL) {
1060         return (-1);
1061     }
1062     if (states->nbState >= states->maxState) {
1063         xmlRelaxNGValidStatePtr *tmp;
1064         int size;
1065 
1066         size = states->maxState * 2;
1067         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1068                                                      (size) *
1069                                                      sizeof
1070                                                      (xmlRelaxNGValidStatePtr));
1071         if (tmp == NULL) {
1072             xmlRngVErrMemory(ctxt, "adding states\n");
1073             return (-1);
1074         }
1075         states->tabState = tmp;
1076         states->maxState = size;
1077     }
1078     states->tabState[states->nbState++] = state;
1079     return (1);
1080 }
1081 
1082 /**
1083  * xmlRelaxNGAddState:
1084  * @ctxt:  a Relax-NG validation context
1085  * @states:  the states container
1086  * @state:  the validation state
1087  *
1088  * Add a RelaxNG validation state to the container
1089  *
1090  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1091  */
1092 static int
1093 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1094                     xmlRelaxNGStatesPtr states,
1095                     xmlRelaxNGValidStatePtr state)
1096 {
1097     int i;
1098 
1099     if (state == NULL || states == NULL) {
1100         return (-1);
1101     }
1102     if (states->nbState >= states->maxState) {
1103         xmlRelaxNGValidStatePtr *tmp;
1104         int size;
1105 
1106         size = states->maxState * 2;
1107         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1108                                                      (size) *
1109                                                      sizeof
1110                                                      (xmlRelaxNGValidStatePtr));
1111         if (tmp == NULL) {
1112             xmlRngVErrMemory(ctxt, "adding states\n");
1113             return (-1);
1114         }
1115         states->tabState = tmp;
1116         states->maxState = size;
1117     }
1118     for (i = 0; i < states->nbState; i++) {
1119         if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1120             xmlRelaxNGFreeValidState(ctxt, state);
1121             return (0);
1122         }
1123     }
1124     states->tabState[states->nbState++] = state;
1125     return (1);
1126 }
1127 
1128 /**
1129  * xmlRelaxNGFreeStates:
1130  * @ctxt:  a Relax-NG validation context
1131  * @states:  teh container
1132  *
1133  * Free a RelaxNG validation state container
1134  */
1135 static void
1136 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
1137                      xmlRelaxNGStatesPtr states)
1138 {
1139     if (states == NULL)
1140         return;
1141     if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
1142         ctxt->freeStatesMax = 40;
1143         ctxt->freeStatesNr = 0;
1144         ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1145             xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1146         if (ctxt->freeStates == NULL) {
1147             xmlRngVErrMemory(ctxt, "storing states\n");
1148         }
1149     } else if ((ctxt != NULL)
1150                && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1151         xmlRelaxNGStatesPtr *tmp;
1152 
1153         tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1154                                                  2 * ctxt->freeStatesMax *
1155                                                  sizeof
1156                                                  (xmlRelaxNGStatesPtr));
1157         if (tmp == NULL) {
1158             xmlRngVErrMemory(ctxt, "storing states\n");
1159             xmlFree(states->tabState);
1160             xmlFree(states);
1161             return;
1162         }
1163         ctxt->freeStates = tmp;
1164         ctxt->freeStatesMax *= 2;
1165     }
1166     if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
1167         xmlFree(states->tabState);
1168         xmlFree(states);
1169     } else {
1170         ctxt->freeStates[ctxt->freeStatesNr++] = states;
1171     }
1172 }
1173 
1174 /**
1175  * xmlRelaxNGNewValidState:
1176  * @ctxt:  a Relax-NG validation context
1177  * @node:  the current node or NULL for the document
1178  *
1179  * Allocate a new RelaxNG validation state
1180  *
1181  * Returns the newly allocated structure or NULL in case or error
1182  */
1183 static xmlRelaxNGValidStatePtr
1184 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1185 {
1186     xmlRelaxNGValidStatePtr ret;
1187     xmlAttrPtr attr;
1188     xmlAttrPtr attrs[MAX_ATTR];
1189     int nbAttrs = 0;
1190     xmlNodePtr root = NULL;
1191 
1192     if (node == NULL) {
1193         root = xmlDocGetRootElement(ctxt->doc);
1194         if (root == NULL)
1195             return (NULL);
1196     } else {
1197         attr = node->properties;
1198         while (attr != NULL) {
1199             if (nbAttrs < MAX_ATTR)
1200                 attrs[nbAttrs++] = attr;
1201             else
1202                 nbAttrs++;
1203             attr = attr->next;
1204         }
1205     }
1206     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1207         ctxt->freeState->nbState--;
1208         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1209     } else {
1210         ret =
1211             (xmlRelaxNGValidStatePtr)
1212             xmlMalloc(sizeof(xmlRelaxNGValidState));
1213         if (ret == NULL) {
1214             xmlRngVErrMemory(ctxt, "allocating states\n");
1215             return (NULL);
1216         }
1217         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1218     }
1219     ret->value = NULL;
1220     ret->endvalue = NULL;
1221     if (node == NULL) {
1222         ret->node = (xmlNodePtr) ctxt->doc;
1223         ret->seq = root;
1224     } else {
1225         ret->node = node;
1226         ret->seq = node->children;
1227     }
1228     ret->nbAttrs = 0;
1229     if (nbAttrs > 0) {
1230         if (ret->attrs == NULL) {
1231             if (nbAttrs < 4)
1232                 ret->maxAttrs = 4;
1233             else
1234                 ret->maxAttrs = nbAttrs;
1235             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1236                                                   sizeof(xmlAttrPtr));
1237             if (ret->attrs == NULL) {
1238                 xmlRngVErrMemory(ctxt, "allocating states\n");
1239                 return (ret);
1240             }
1241         } else if (ret->maxAttrs < nbAttrs) {
1242             xmlAttrPtr *tmp;
1243 
1244             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1245                                             sizeof(xmlAttrPtr));
1246             if (tmp == NULL) {
1247                 xmlRngVErrMemory(ctxt, "allocating states\n");
1248                 return (ret);
1249             }
1250             ret->attrs = tmp;
1251             ret->maxAttrs = nbAttrs;
1252         }
1253         ret->nbAttrs = nbAttrs;
1254         if (nbAttrs < MAX_ATTR) {
1255             memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1256         } else {
1257             attr = node->properties;
1258             nbAttrs = 0;
1259             while (attr != NULL) {
1260                 ret->attrs[nbAttrs++] = attr;
1261                 attr = attr->next;
1262             }
1263         }
1264     }
1265     ret->nbAttrLeft = ret->nbAttrs;
1266     return (ret);
1267 }
1268 
1269 /**
1270  * xmlRelaxNGCopyValidState:
1271  * @ctxt:  a Relax-NG validation context
1272  * @state:  a validation state
1273  *
1274  * Copy the validation state
1275  *
1276  * Returns the newly allocated structure or NULL in case or error
1277  */
1278 static xmlRelaxNGValidStatePtr
1279 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1280                          xmlRelaxNGValidStatePtr state)
1281 {
1282     xmlRelaxNGValidStatePtr ret;
1283     unsigned int maxAttrs;
1284     xmlAttrPtr *attrs;
1285 
1286     if (state == NULL)
1287         return (NULL);
1288     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1289         ctxt->freeState->nbState--;
1290         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1291     } else {
1292         ret =
1293             (xmlRelaxNGValidStatePtr)
1294             xmlMalloc(sizeof(xmlRelaxNGValidState));
1295         if (ret == NULL) {
1296             xmlRngVErrMemory(ctxt, "allocating states\n");
1297             return (NULL);
1298         }
1299         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1300     }
1301     attrs = ret->attrs;
1302     maxAttrs = ret->maxAttrs;
1303     memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1304     ret->attrs = attrs;
1305     ret->maxAttrs = maxAttrs;
1306     if (state->nbAttrs > 0) {
1307         if (ret->attrs == NULL) {
1308             ret->maxAttrs = state->maxAttrs;
1309             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1310                                                   sizeof(xmlAttrPtr));
1311             if (ret->attrs == NULL) {
1312                 xmlRngVErrMemory(ctxt, "allocating states\n");
1313                 ret->nbAttrs = 0;
1314                 return (ret);
1315             }
1316         } else if (ret->maxAttrs < state->nbAttrs) {
1317             xmlAttrPtr *tmp;
1318 
1319             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1320                                             sizeof(xmlAttrPtr));
1321             if (tmp == NULL) {
1322                 xmlRngVErrMemory(ctxt, "allocating states\n");
1323                 ret->nbAttrs = 0;
1324                 return (ret);
1325             }
1326             ret->maxAttrs = state->maxAttrs;
1327             ret->attrs = tmp;
1328         }
1329         memcpy(ret->attrs, state->attrs,
1330                state->nbAttrs * sizeof(xmlAttrPtr));
1331     }
1332     return (ret);
1333 }
1334 
1335 /**
1336  * xmlRelaxNGEqualValidState:
1337  * @ctxt:  a Relax-NG validation context
1338  * @state1:  a validation state
1339  * @state2:  a validation state
1340  *
1341  * Compare the validation states for equality
1342  *
1343  * Returns 1 if equald, 0 otherwise
1344  */
1345 static int
1346 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1347                           xmlRelaxNGValidStatePtr state1,
1348                           xmlRelaxNGValidStatePtr state2)
1349 {
1350     int i;
1351 
1352     if ((state1 == NULL) || (state2 == NULL))
1353         return (0);
1354     if (state1 == state2)
1355         return (1);
1356     if (state1->node != state2->node)
1357         return (0);
1358     if (state1->seq != state2->seq)
1359         return (0);
1360     if (state1->nbAttrLeft != state2->nbAttrLeft)
1361         return (0);
1362     if (state1->nbAttrs != state2->nbAttrs)
1363         return (0);
1364     if (state1->endvalue != state2->endvalue)
1365         return (0);
1366     if ((state1->value != state2->value) &&
1367         (!xmlStrEqual(state1->value, state2->value)))
1368         return (0);
1369     for (i = 0; i < state1->nbAttrs; i++) {
1370         if (state1->attrs[i] != state2->attrs[i])
1371             return (0);
1372     }
1373     return (1);
1374 }
1375 
1376 /**
1377  * xmlRelaxNGFreeValidState:
1378  * @state:  a validation state structure
1379  *
1380  * Deallocate a RelaxNG validation state structure.
1381  */
1382 static void
1383 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1384                          xmlRelaxNGValidStatePtr state)
1385 {
1386     if (state == NULL)
1387         return;
1388 
1389     if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1390         ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1391     }
1392     if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1393         if (state->attrs != NULL)
1394             xmlFree(state->attrs);
1395         xmlFree(state);
1396     } else {
1397         xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1398     }
1399 }
1400 
1401 /************************************************************************
1402  *									*
1403  *			Semi internal functions				*
1404  *									*
1405  ************************************************************************/
1406 
1407 /**
1408  * xmlRelaxParserSetFlag:
1409  * @ctxt: a RelaxNG parser context
1410  * @flags: a set of flags values
1411  *
1412  * Semi private function used to pass informations to a parser context
1413  * which are a combination of xmlRelaxNGParserFlag .
1414  *
1415  * Returns 0 if success and -1 in case of error
1416  */
1417 int
1418 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1419 {
1420     if (ctxt == NULL) return(-1);
1421     if (flags & XML_RELAXNGP_FREE_DOC) {
1422         ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1423 	flags -= XML_RELAXNGP_FREE_DOC;
1424     }
1425     if (flags & XML_RELAXNGP_CRNG) {
1426         ctxt->crng |= XML_RELAXNGP_CRNG;
1427 	flags -= XML_RELAXNGP_CRNG;
1428     }
1429     if (flags != 0) return(-1);
1430     return(0);
1431 }
1432 
1433 /************************************************************************
1434  *									*
1435  *			Document functions				*
1436  *									*
1437  ************************************************************************/
1438 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1439                                       xmlDocPtr doc);
1440 
1441 /**
1442  * xmlRelaxNGIncludePush:
1443  * @ctxt:  the parser context
1444  * @value:  the element doc
1445  *
1446  * Pushes a new include on top of the include stack
1447  *
1448  * Returns 0 in case of error, the index in the stack otherwise
1449  */
1450 static int
1451 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1452                       xmlRelaxNGIncludePtr value)
1453 {
1454     if (ctxt->incTab == NULL) {
1455         ctxt->incMax = 4;
1456         ctxt->incNr = 0;
1457         ctxt->incTab =
1458             (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1459                                                sizeof(ctxt->incTab[0]));
1460         if (ctxt->incTab == NULL) {
1461             xmlRngPErrMemory(ctxt, "allocating include\n");
1462             return (0);
1463         }
1464     }
1465     if (ctxt->incNr >= ctxt->incMax) {
1466         ctxt->incMax *= 2;
1467         ctxt->incTab =
1468             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1469                                                 ctxt->incMax *
1470                                                 sizeof(ctxt->incTab[0]));
1471         if (ctxt->incTab == NULL) {
1472             xmlRngPErrMemory(ctxt, "allocating include\n");
1473             return (0);
1474         }
1475     }
1476     ctxt->incTab[ctxt->incNr] = value;
1477     ctxt->inc = value;
1478     return (ctxt->incNr++);
1479 }
1480 
1481 /**
1482  * xmlRelaxNGIncludePop:
1483  * @ctxt: the parser context
1484  *
1485  * Pops the top include from the include stack
1486  *
1487  * Returns the include just removed
1488  */
1489 static xmlRelaxNGIncludePtr
1490 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1491 {
1492     xmlRelaxNGIncludePtr ret;
1493 
1494     if (ctxt->incNr <= 0)
1495         return (NULL);
1496     ctxt->incNr--;
1497     if (ctxt->incNr > 0)
1498         ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1499     else
1500         ctxt->inc = NULL;
1501     ret = ctxt->incTab[ctxt->incNr];
1502     ctxt->incTab[ctxt->incNr] = NULL;
1503     return (ret);
1504 }
1505 
1506 /**
1507  * xmlRelaxNGRemoveRedefine:
1508  * @ctxt: the parser context
1509  * @URL:  the normalized URL
1510  * @target:  the included target
1511  * @name:  the define name to eliminate
1512  *
1513  * Applies the elimination algorithm of 4.7
1514  *
1515  * Returns 0 in case of error, 1 in case of success.
1516  */
1517 static int
1518 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1519                          const xmlChar * URL ATTRIBUTE_UNUSED,
1520                          xmlNodePtr target, const xmlChar * name)
1521 {
1522     int found = 0;
1523     xmlNodePtr tmp, tmp2;
1524     xmlChar *name2;
1525 
1526 #ifdef DEBUG_INCLUDE
1527     if (name == NULL)
1528         xmlGenericError(xmlGenericErrorContext,
1529                         "Elimination of <include> start from %s\n", URL);
1530     else
1531         xmlGenericError(xmlGenericErrorContext,
1532                         "Elimination of <include> define %s from %s\n",
1533                         name, URL);
1534 #endif
1535     tmp = target;
1536     while (tmp != NULL) {
1537         tmp2 = tmp->next;
1538         if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1539             found = 1;
1540             xmlUnlinkNode(tmp);
1541             xmlFreeNode(tmp);
1542         } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1543             name2 = xmlGetProp(tmp, BAD_CAST "name");
1544             xmlRelaxNGNormExtSpace(name2);
1545             if (name2 != NULL) {
1546                 if (xmlStrEqual(name, name2)) {
1547                     found = 1;
1548                     xmlUnlinkNode(tmp);
1549                     xmlFreeNode(tmp);
1550                 }
1551                 xmlFree(name2);
1552             }
1553         } else if (IS_RELAXNG(tmp, "include")) {
1554             xmlChar *href = NULL;
1555             xmlRelaxNGDocumentPtr inc = tmp->psvi;
1556 
1557             if ((inc != NULL) && (inc->doc != NULL) &&
1558                 (inc->doc->children != NULL)) {
1559 
1560                 if (xmlStrEqual
1561                     (inc->doc->children->name, BAD_CAST "grammar")) {
1562 #ifdef DEBUG_INCLUDE
1563                     href = xmlGetProp(tmp, BAD_CAST "href");
1564 #endif
1565                     if (xmlRelaxNGRemoveRedefine(ctxt, href,
1566                                                  xmlDocGetRootElement(inc->doc)->children,
1567                                                  name) == 1) {
1568                         found = 1;
1569                     }
1570 #ifdef DEBUG_INCLUDE
1571                     if (href != NULL)
1572                         xmlFree(href);
1573 #endif
1574                 }
1575             }
1576         }
1577         tmp = tmp2;
1578     }
1579     return (found);
1580 }
1581 
1582 /**
1583  * xmlRelaxNGLoadInclude:
1584  * @ctxt: the parser context
1585  * @URL:  the normalized URL
1586  * @node: the include node.
1587  * @ns:  the namespace passed from the context.
1588  *
1589  * First lookup if the document is already loaded into the parser context,
1590  * check against recursion. If not found the resource is loaded and
1591  * the content is preprocessed before being returned back to the caller.
1592  *
1593  * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1594  */
1595 static xmlRelaxNGIncludePtr
1596 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1597                       xmlNodePtr node, const xmlChar * ns)
1598 {
1599     xmlRelaxNGIncludePtr ret = NULL;
1600     xmlDocPtr doc;
1601     int i;
1602     xmlNodePtr root, cur;
1603 
1604 #ifdef DEBUG_INCLUDE
1605     xmlGenericError(xmlGenericErrorContext,
1606                     "xmlRelaxNGLoadInclude(%s)\n", URL);
1607 #endif
1608 
1609     /*
1610      * check against recursion in the stack
1611      */
1612     for (i = 0; i < ctxt->incNr; i++) {
1613         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1614             xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1615                        "Detected an Include recursion for %s\n", URL,
1616                        NULL);
1617             return (NULL);
1618         }
1619     }
1620 
1621     /*
1622      * load the document
1623      */
1624     doc = xmlReadFile((const char *) URL,NULL,0);
1625     if (doc == NULL) {
1626         xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1627                    "xmlRelaxNG: could not load %s\n", URL, NULL);
1628         return (NULL);
1629     }
1630 #ifdef DEBUG_INCLUDE
1631     xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
1632 #endif
1633 
1634     /*
1635      * Allocate the document structures and register it first.
1636      */
1637     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1638     if (ret == NULL) {
1639         xmlRngPErrMemory(ctxt, "allocating include\n");
1640         xmlFreeDoc(doc);
1641         return (NULL);
1642     }
1643     memset(ret, 0, sizeof(xmlRelaxNGInclude));
1644     ret->doc = doc;
1645     ret->href = xmlStrdup(URL);
1646     ret->next = ctxt->includes;
1647     ctxt->includes = ret;
1648 
1649     /*
1650      * transmit the ns if needed
1651      */
1652     if (ns != NULL) {
1653         root = xmlDocGetRootElement(doc);
1654         if (root != NULL) {
1655             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1656                 xmlSetProp(root, BAD_CAST "ns", ns);
1657             }
1658         }
1659     }
1660 
1661     /*
1662      * push it on the stack
1663      */
1664     xmlRelaxNGIncludePush(ctxt, ret);
1665 
1666     /*
1667      * Some preprocessing of the document content, this include recursing
1668      * in the include stack.
1669      */
1670 #ifdef DEBUG_INCLUDE
1671     xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
1672 #endif
1673 
1674     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1675     if (doc == NULL) {
1676         ctxt->inc = NULL;
1677         return (NULL);
1678     }
1679 
1680     /*
1681      * Pop up the include from the stack
1682      */
1683     xmlRelaxNGIncludePop(ctxt);
1684 
1685 #ifdef DEBUG_INCLUDE
1686     xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
1687 #endif
1688     /*
1689      * Check that the top element is a grammar
1690      */
1691     root = xmlDocGetRootElement(doc);
1692     if (root == NULL) {
1693         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1694                    "xmlRelaxNG: included document is empty %s\n", URL,
1695                    NULL);
1696         return (NULL);
1697     }
1698     if (!IS_RELAXNG(root, "grammar")) {
1699         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1700                    "xmlRelaxNG: included document %s root is not a grammar\n",
1701                    URL, NULL);
1702         return (NULL);
1703     }
1704 
1705     /*
1706      * Elimination of redefined rules in the include.
1707      */
1708     cur = node->children;
1709     while (cur != NULL) {
1710         if (IS_RELAXNG(cur, "start")) {
1711             int found = 0;
1712 
1713             found =
1714                 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1715             if (!found) {
1716                 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1717                            "xmlRelaxNG: include %s has a start but not the included grammar\n",
1718                            URL, NULL);
1719             }
1720         } else if (IS_RELAXNG(cur, "define")) {
1721             xmlChar *name;
1722 
1723             name = xmlGetProp(cur, BAD_CAST "name");
1724             if (name == NULL) {
1725                 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1726                            "xmlRelaxNG: include %s has define without name\n",
1727                            URL, NULL);
1728             } else {
1729                 int found;
1730 
1731                 xmlRelaxNGNormExtSpace(name);
1732                 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1733                                                  root->children, name);
1734                 if (!found) {
1735                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1736                                "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1737                                URL, name);
1738                 }
1739                 xmlFree(name);
1740             }
1741         }
1742         cur = cur->next;
1743     }
1744 
1745 
1746     return (ret);
1747 }
1748 
1749 /**
1750  * xmlRelaxNGValidErrorPush:
1751  * @ctxt:  the validation context
1752  * @err:  the error code
1753  * @arg1:  the first string argument
1754  * @arg2:  the second string argument
1755  * @dup:  arg need to be duplicated
1756  *
1757  * Pushes a new error on top of the error stack
1758  *
1759  * Returns 0 in case of error, the index in the stack otherwise
1760  */
1761 static int
1762 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1763                          xmlRelaxNGValidErr err, const xmlChar * arg1,
1764                          const xmlChar * arg2, int dup)
1765 {
1766     xmlRelaxNGValidErrorPtr cur;
1767 
1768 #ifdef DEBUG_ERROR
1769     xmlGenericError(xmlGenericErrorContext,
1770                     "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1771 #endif
1772     if (ctxt->errTab == NULL) {
1773         ctxt->errMax = 8;
1774         ctxt->errNr = 0;
1775         ctxt->errTab =
1776             (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1777                                                 sizeof
1778                                                 (xmlRelaxNGValidError));
1779         if (ctxt->errTab == NULL) {
1780             xmlRngVErrMemory(ctxt, "pushing error\n");
1781             return (0);
1782         }
1783         ctxt->err = NULL;
1784     }
1785     if (ctxt->errNr >= ctxt->errMax) {
1786         ctxt->errMax *= 2;
1787         ctxt->errTab =
1788             (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1789                                                  ctxt->errMax *
1790                                                  sizeof
1791                                                  (xmlRelaxNGValidError));
1792         if (ctxt->errTab == NULL) {
1793             xmlRngVErrMemory(ctxt, "pushing error\n");
1794             return (0);
1795         }
1796         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1797     }
1798     if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1799         (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1800         return (ctxt->errNr);
1801     cur = &ctxt->errTab[ctxt->errNr];
1802     cur->err = err;
1803     if (dup) {
1804         cur->arg1 = xmlStrdup(arg1);
1805         cur->arg2 = xmlStrdup(arg2);
1806         cur->flags = ERROR_IS_DUP;
1807     } else {
1808         cur->arg1 = arg1;
1809         cur->arg2 = arg2;
1810         cur->flags = 0;
1811     }
1812     if (ctxt->state != NULL) {
1813         cur->node = ctxt->state->node;
1814         cur->seq = ctxt->state->seq;
1815     } else {
1816         cur->node = NULL;
1817         cur->seq = NULL;
1818     }
1819     ctxt->err = cur;
1820     return (ctxt->errNr++);
1821 }
1822 
1823 /**
1824  * xmlRelaxNGValidErrorPop:
1825  * @ctxt: the validation context
1826  *
1827  * Pops the top error from the error stack
1828  */
1829 static void
1830 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1831 {
1832     xmlRelaxNGValidErrorPtr cur;
1833 
1834     if (ctxt->errNr <= 0) {
1835         ctxt->err = NULL;
1836         return;
1837     }
1838     ctxt->errNr--;
1839     if (ctxt->errNr > 0)
1840         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1841     else
1842         ctxt->err = NULL;
1843     cur = &ctxt->errTab[ctxt->errNr];
1844     if (cur->flags & ERROR_IS_DUP) {
1845         if (cur->arg1 != NULL)
1846             xmlFree((xmlChar *) cur->arg1);
1847         cur->arg1 = NULL;
1848         if (cur->arg2 != NULL)
1849             xmlFree((xmlChar *) cur->arg2);
1850         cur->arg2 = NULL;
1851         cur->flags = 0;
1852     }
1853 }
1854 
1855 /**
1856  * xmlRelaxNGDocumentPush:
1857  * @ctxt:  the parser context
1858  * @value:  the element doc
1859  *
1860  * Pushes a new doc on top of the doc stack
1861  *
1862  * Returns 0 in case of error, the index in the stack otherwise
1863  */
1864 static int
1865 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1866                        xmlRelaxNGDocumentPtr value)
1867 {
1868     if (ctxt->docTab == NULL) {
1869         ctxt->docMax = 4;
1870         ctxt->docNr = 0;
1871         ctxt->docTab =
1872             (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1873                                                 sizeof(ctxt->docTab[0]));
1874         if (ctxt->docTab == NULL) {
1875             xmlRngPErrMemory(ctxt, "adding document\n");
1876             return (0);
1877         }
1878     }
1879     if (ctxt->docNr >= ctxt->docMax) {
1880         ctxt->docMax *= 2;
1881         ctxt->docTab =
1882             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1883                                                  ctxt->docMax *
1884                                                  sizeof(ctxt->docTab[0]));
1885         if (ctxt->docTab == NULL) {
1886             xmlRngPErrMemory(ctxt, "adding document\n");
1887             return (0);
1888         }
1889     }
1890     ctxt->docTab[ctxt->docNr] = value;
1891     ctxt->doc = value;
1892     return (ctxt->docNr++);
1893 }
1894 
1895 /**
1896  * xmlRelaxNGDocumentPop:
1897  * @ctxt: the parser context
1898  *
1899  * Pops the top doc from the doc stack
1900  *
1901  * Returns the doc just removed
1902  */
1903 static xmlRelaxNGDocumentPtr
1904 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1905 {
1906     xmlRelaxNGDocumentPtr ret;
1907 
1908     if (ctxt->docNr <= 0)
1909         return (NULL);
1910     ctxt->docNr--;
1911     if (ctxt->docNr > 0)
1912         ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1913     else
1914         ctxt->doc = NULL;
1915     ret = ctxt->docTab[ctxt->docNr];
1916     ctxt->docTab[ctxt->docNr] = NULL;
1917     return (ret);
1918 }
1919 
1920 /**
1921  * xmlRelaxNGLoadExternalRef:
1922  * @ctxt: the parser context
1923  * @URL:  the normalized URL
1924  * @ns:  the inherited ns if any
1925  *
1926  * First lookup if the document is already loaded into the parser context,
1927  * check against recursion. If not found the resource is loaded and
1928  * the content is preprocessed before being returned back to the caller.
1929  *
1930  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1931  */
1932 static xmlRelaxNGDocumentPtr
1933 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1934                           const xmlChar * URL, const xmlChar * ns)
1935 {
1936     xmlRelaxNGDocumentPtr ret = NULL;
1937     xmlDocPtr doc;
1938     xmlNodePtr root;
1939     int i;
1940 
1941     /*
1942      * check against recursion in the stack
1943      */
1944     for (i = 0; i < ctxt->docNr; i++) {
1945         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1946             xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1947                        "Detected an externalRef recursion for %s\n", URL,
1948                        NULL);
1949             return (NULL);
1950         }
1951     }
1952 
1953     /*
1954      * load the document
1955      */
1956     doc = xmlReadFile((const char *) URL,NULL,0);
1957     if (doc == NULL) {
1958         xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1959                    "xmlRelaxNG: could not load %s\n", URL, NULL);
1960         return (NULL);
1961     }
1962 
1963     /*
1964      * Allocate the document structures and register it first.
1965      */
1966     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1967     if (ret == NULL) {
1968         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1969                    "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1970         xmlFreeDoc(doc);
1971         return (NULL);
1972     }
1973     memset(ret, 0, sizeof(xmlRelaxNGDocument));
1974     ret->doc = doc;
1975     ret->href = xmlStrdup(URL);
1976     ret->next = ctxt->documents;
1977     ret->externalRef = 1;
1978     ctxt->documents = ret;
1979 
1980     /*
1981      * transmit the ns if needed
1982      */
1983     if (ns != NULL) {
1984         root = xmlDocGetRootElement(doc);
1985         if (root != NULL) {
1986             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1987                 xmlSetProp(root, BAD_CAST "ns", ns);
1988             }
1989         }
1990     }
1991 
1992     /*
1993      * push it on the stack and register it in the hash table
1994      */
1995     xmlRelaxNGDocumentPush(ctxt, ret);
1996 
1997     /*
1998      * Some preprocessing of the document content
1999      */
2000     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
2001     if (doc == NULL) {
2002         ctxt->doc = NULL;
2003         return (NULL);
2004     }
2005 
2006     xmlRelaxNGDocumentPop(ctxt);
2007 
2008     return (ret);
2009 }
2010 
2011 /************************************************************************
2012  *									*
2013  *			Error functions					*
2014  *									*
2015  ************************************************************************/
2016 
2017 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2018 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2019 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2020 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2021 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2022 
2023 static const char *
2024 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2025 {
2026     if (def == NULL)
2027         return ("none");
2028     switch (def->type) {
2029         case XML_RELAXNG_EMPTY:
2030             return ("empty");
2031         case XML_RELAXNG_NOT_ALLOWED:
2032             return ("notAllowed");
2033         case XML_RELAXNG_EXCEPT:
2034             return ("except");
2035         case XML_RELAXNG_TEXT:
2036             return ("text");
2037         case XML_RELAXNG_ELEMENT:
2038             return ("element");
2039         case XML_RELAXNG_DATATYPE:
2040             return ("datatype");
2041         case XML_RELAXNG_VALUE:
2042             return ("value");
2043         case XML_RELAXNG_LIST:
2044             return ("list");
2045         case XML_RELAXNG_ATTRIBUTE:
2046             return ("attribute");
2047         case XML_RELAXNG_DEF:
2048             return ("def");
2049         case XML_RELAXNG_REF:
2050             return ("ref");
2051         case XML_RELAXNG_EXTERNALREF:
2052             return ("externalRef");
2053         case XML_RELAXNG_PARENTREF:
2054             return ("parentRef");
2055         case XML_RELAXNG_OPTIONAL:
2056             return ("optional");
2057         case XML_RELAXNG_ZEROORMORE:
2058             return ("zeroOrMore");
2059         case XML_RELAXNG_ONEORMORE:
2060             return ("oneOrMore");
2061         case XML_RELAXNG_CHOICE:
2062             return ("choice");
2063         case XML_RELAXNG_GROUP:
2064             return ("group");
2065         case XML_RELAXNG_INTERLEAVE:
2066             return ("interleave");
2067         case XML_RELAXNG_START:
2068             return ("start");
2069         case XML_RELAXNG_NOOP:
2070             return ("noop");
2071         case XML_RELAXNG_PARAM:
2072             return ("param");
2073     }
2074     return ("unknown");
2075 }
2076 
2077 /**
2078  * xmlRelaxNGGetErrorString:
2079  * @err:  the error code
2080  * @arg1:  the first string argument
2081  * @arg2:  the second string argument
2082  *
2083  * computes a formatted error string for the given error code and args
2084  *
2085  * Returns the error string, it must be deallocated by the caller
2086  */
2087 static xmlChar *
2088 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2089                          const xmlChar * arg2)
2090 {
2091     char msg[1000];
2092     xmlChar *result;
2093 
2094     if (arg1 == NULL)
2095         arg1 = BAD_CAST "";
2096     if (arg2 == NULL)
2097         arg2 = BAD_CAST "";
2098 
2099     msg[0] = 0;
2100     switch (err) {
2101         case XML_RELAXNG_OK:
2102             return (NULL);
2103         case XML_RELAXNG_ERR_MEMORY:
2104             return (xmlCharStrdup("out of memory\n"));
2105         case XML_RELAXNG_ERR_TYPE:
2106             snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2107             break;
2108         case XML_RELAXNG_ERR_TYPEVAL:
2109             snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2110                      arg2);
2111             break;
2112         case XML_RELAXNG_ERR_DUPID:
2113             snprintf(msg, 1000, "ID %s redefined\n", arg1);
2114             break;
2115         case XML_RELAXNG_ERR_TYPECMP:
2116             snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2117             break;
2118         case XML_RELAXNG_ERR_NOSTATE:
2119             return (xmlCharStrdup("Internal error: no state\n"));
2120         case XML_RELAXNG_ERR_NODEFINE:
2121             return (xmlCharStrdup("Internal error: no define\n"));
2122         case XML_RELAXNG_ERR_INTERNAL:
2123             snprintf(msg, 1000, "Internal error: %s\n", arg1);
2124             break;
2125         case XML_RELAXNG_ERR_LISTEXTRA:
2126             snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2127             break;
2128         case XML_RELAXNG_ERR_INTERNODATA:
2129             return (xmlCharStrdup
2130                     ("Internal: interleave block has no data\n"));
2131         case XML_RELAXNG_ERR_INTERSEQ:
2132             return (xmlCharStrdup("Invalid sequence in interleave\n"));
2133         case XML_RELAXNG_ERR_INTEREXTRA:
2134             snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2135             break;
2136         case XML_RELAXNG_ERR_ELEMNAME:
2137             snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2138                      arg2);
2139             break;
2140         case XML_RELAXNG_ERR_ELEMNONS:
2141             snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2142                      arg1);
2143             break;
2144         case XML_RELAXNG_ERR_ELEMWRONGNS:
2145             snprintf(msg, 1000,
2146                      "Element %s has wrong namespace: expecting %s\n", arg1,
2147                      arg2);
2148             break;
2149         case XML_RELAXNG_ERR_ELEMWRONG:
2150             snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2151             break;
2152         case XML_RELAXNG_ERR_TEXTWRONG:
2153             snprintf(msg, 1000,
2154                      "Did not expect text in element %s content\n", arg1);
2155             break;
2156         case XML_RELAXNG_ERR_ELEMEXTRANS:
2157             snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2158                      arg1);
2159             break;
2160         case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2161             snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2162             break;
2163         case XML_RELAXNG_ERR_NOELEM:
2164             snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2165                      arg1);
2166             break;
2167         case XML_RELAXNG_ERR_NOTELEM:
2168             return (xmlCharStrdup("Expecting an element got text\n"));
2169         case XML_RELAXNG_ERR_ATTRVALID:
2170             snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2171                      arg1);
2172             break;
2173         case XML_RELAXNG_ERR_CONTENTVALID:
2174             snprintf(msg, 1000, "Element %s failed to validate content\n",
2175                      arg1);
2176             break;
2177         case XML_RELAXNG_ERR_EXTRACONTENT:
2178             snprintf(msg, 1000, "Element %s has extra content: %s\n",
2179                      arg1, arg2);
2180             break;
2181         case XML_RELAXNG_ERR_INVALIDATTR:
2182             snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2183                      arg1, arg2);
2184             break;
2185         case XML_RELAXNG_ERR_LACKDATA:
2186             snprintf(msg, 1000, "Datatype element %s contains no data\n",
2187                      arg1);
2188             break;
2189         case XML_RELAXNG_ERR_DATAELEM:
2190             snprintf(msg, 1000, "Datatype element %s has child elements\n",
2191                      arg1);
2192             break;
2193         case XML_RELAXNG_ERR_VALELEM:
2194             snprintf(msg, 1000, "Value element %s has child elements\n",
2195                      arg1);
2196             break;
2197         case XML_RELAXNG_ERR_LISTELEM:
2198             snprintf(msg, 1000, "List element %s has child elements\n",
2199                      arg1);
2200             break;
2201         case XML_RELAXNG_ERR_DATATYPE:
2202             snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2203             break;
2204         case XML_RELAXNG_ERR_VALUE:
2205             snprintf(msg, 1000, "Error validating value %s\n", arg1);
2206             break;
2207         case XML_RELAXNG_ERR_LIST:
2208             return (xmlCharStrdup("Error validating list\n"));
2209         case XML_RELAXNG_ERR_NOGRAMMAR:
2210             return (xmlCharStrdup("No top grammar defined\n"));
2211         case XML_RELAXNG_ERR_EXTRADATA:
2212             return (xmlCharStrdup("Extra data in the document\n"));
2213         default:
2214             return (xmlCharStrdup("Unknown error !\n"));
2215     }
2216     if (msg[0] == 0) {
2217         snprintf(msg, 1000, "Unknown error code %d\n", err);
2218     }
2219     msg[1000 - 1] = 0;
2220     result = xmlCharStrdup(msg);
2221     return (xmlEscapeFormatString(&result));
2222 }
2223 
2224 /**
2225  * xmlRelaxNGShowValidError:
2226  * @ctxt:  the validation context
2227  * @err:  the error number
2228  * @node:  the node
2229  * @child:  the node child generating the problem.
2230  * @arg1:  the first argument
2231  * @arg2:  the second argument
2232  *
2233  * Show a validation error.
2234  */
2235 static void
2236 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2237                          xmlRelaxNGValidErr err, xmlNodePtr node,
2238                          xmlNodePtr child, const xmlChar * arg1,
2239                          const xmlChar * arg2)
2240 {
2241     xmlChar *msg;
2242 
2243     if (ctxt->flags & FLAGS_NOERROR)
2244         return;
2245 
2246 #ifdef DEBUG_ERROR
2247     xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
2248 #endif
2249     msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2250     if (msg == NULL)
2251         return;
2252 
2253     if (ctxt->errNo == XML_RELAXNG_OK)
2254         ctxt->errNo = err;
2255     xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2256                (const char *) msg, arg1, arg2);
2257     xmlFree(msg);
2258 }
2259 
2260 /**
2261  * xmlRelaxNGPopErrors:
2262  * @ctxt:  the validation context
2263  * @level:  the error level in the stack
2264  *
2265  * pop and discard all errors until the given level is reached
2266  */
2267 static void
2268 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2269 {
2270     int i;
2271     xmlRelaxNGValidErrorPtr err;
2272 
2273 #ifdef DEBUG_ERROR
2274     xmlGenericError(xmlGenericErrorContext,
2275                     "Pop errors till level %d\n", level);
2276 #endif
2277     for (i = level; i < ctxt->errNr; i++) {
2278         err = &ctxt->errTab[i];
2279         if (err->flags & ERROR_IS_DUP) {
2280             if (err->arg1 != NULL)
2281                 xmlFree((xmlChar *) err->arg1);
2282             err->arg1 = NULL;
2283             if (err->arg2 != NULL)
2284                 xmlFree((xmlChar *) err->arg2);
2285             err->arg2 = NULL;
2286             err->flags = 0;
2287         }
2288     }
2289     ctxt->errNr = level;
2290     if (ctxt->errNr <= 0)
2291         ctxt->err = NULL;
2292 }
2293 
2294 /**
2295  * xmlRelaxNGDumpValidError:
2296  * @ctxt:  the validation context
2297  *
2298  * Show all validation error over a given index.
2299  */
2300 static void
2301 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2302 {
2303     int i, j, k;
2304     xmlRelaxNGValidErrorPtr err, dup;
2305 
2306 #ifdef DEBUG_ERROR
2307     xmlGenericError(xmlGenericErrorContext,
2308                     "Dumping error stack %d errors\n", ctxt->errNr);
2309 #endif
2310     for (i = 0, k = 0; i < ctxt->errNr; i++) {
2311         err = &ctxt->errTab[i];
2312         if (k < MAX_ERROR) {
2313             for (j = 0; j < i; j++) {
2314                 dup = &ctxt->errTab[j];
2315                 if ((err->err == dup->err) && (err->node == dup->node) &&
2316                     (xmlStrEqual(err->arg1, dup->arg1)) &&
2317                     (xmlStrEqual(err->arg2, dup->arg2))) {
2318                     goto skip;
2319                 }
2320             }
2321             xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2322                                      err->arg1, err->arg2);
2323             k++;
2324         }
2325       skip:
2326         if (err->flags & ERROR_IS_DUP) {
2327             if (err->arg1 != NULL)
2328                 xmlFree((xmlChar *) err->arg1);
2329             err->arg1 = NULL;
2330             if (err->arg2 != NULL)
2331                 xmlFree((xmlChar *) err->arg2);
2332             err->arg2 = NULL;
2333             err->flags = 0;
2334         }
2335     }
2336     ctxt->errNr = 0;
2337 }
2338 
2339 /**
2340  * xmlRelaxNGAddValidError:
2341  * @ctxt:  the validation context
2342  * @err:  the error number
2343  * @arg1:  the first argument
2344  * @arg2:  the second argument
2345  * @dup:  need to dup the args
2346  *
2347  * Register a validation error, either generating it if it's sure
2348  * or stacking it for later handling if unsure.
2349  */
2350 static void
2351 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2352                         xmlRelaxNGValidErr err, const xmlChar * arg1,
2353                         const xmlChar * arg2, int dup)
2354 {
2355     if (ctxt == NULL)
2356         return;
2357     if (ctxt->flags & FLAGS_NOERROR)
2358         return;
2359 
2360 #ifdef DEBUG_ERROR
2361     xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
2362 #endif
2363     /*
2364      * generate the error directly
2365      */
2366     if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2367 	 (ctxt->flags & FLAGS_NEGATIVE)) {
2368         xmlNodePtr node, seq;
2369 
2370         /*
2371          * Flush first any stacked error which might be the
2372          * real cause of the problem.
2373          */
2374         if (ctxt->errNr != 0)
2375             xmlRelaxNGDumpValidError(ctxt);
2376         if (ctxt->state != NULL) {
2377             node = ctxt->state->node;
2378             seq = ctxt->state->seq;
2379         } else {
2380             node = seq = NULL;
2381         }
2382         if ((node == NULL) && (seq == NULL)) {
2383             node = ctxt->pnode;
2384         }
2385         xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2386     }
2387     /*
2388      * Stack the error for later processing if needed
2389      */
2390     else {
2391         xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2392     }
2393 }
2394 
2395 
2396 /************************************************************************
2397  *									*
2398  *			Type library hooks				*
2399  *									*
2400  ************************************************************************/
2401 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2402                                     const xmlChar * str);
2403 
2404 /**
2405  * xmlRelaxNGSchemaTypeHave:
2406  * @data:  data needed for the library
2407  * @type:  the type name
2408  *
2409  * Check if the given type is provided by
2410  * the W3C XMLSchema Datatype library.
2411  *
2412  * Returns 1 if yes, 0 if no and -1 in case of error.
2413  */
2414 static int
2415 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2416 {
2417     xmlSchemaTypePtr typ;
2418 
2419     if (type == NULL)
2420         return (-1);
2421     typ = xmlSchemaGetPredefinedType(type,
2422                                      BAD_CAST
2423                                      "http://www.w3.org/2001/XMLSchema");
2424     if (typ == NULL)
2425         return (0);
2426     return (1);
2427 }
2428 
2429 /**
2430  * xmlRelaxNGSchemaTypeCheck:
2431  * @data:  data needed for the library
2432  * @type:  the type name
2433  * @value:  the value to check
2434  * @node:  the node
2435  *
2436  * Check if the given type and value are validated by
2437  * the W3C XMLSchema Datatype library.
2438  *
2439  * Returns 1 if yes, 0 if no and -1 in case of error.
2440  */
2441 static int
2442 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2443                           const xmlChar * type,
2444                           const xmlChar * value,
2445                           void **result, xmlNodePtr node)
2446 {
2447     xmlSchemaTypePtr typ;
2448     int ret;
2449 
2450     if ((type == NULL) || (value == NULL))
2451         return (-1);
2452     typ = xmlSchemaGetPredefinedType(type,
2453                                      BAD_CAST
2454                                      "http://www.w3.org/2001/XMLSchema");
2455     if (typ == NULL)
2456         return (-1);
2457     ret = xmlSchemaValPredefTypeNode(typ, value,
2458                                      (xmlSchemaValPtr *) result, node);
2459     if (ret == 2)               /* special ID error code */
2460         return (2);
2461     if (ret == 0)
2462         return (1);
2463     if (ret > 0)
2464         return (0);
2465     return (-1);
2466 }
2467 
2468 /**
2469  * xmlRelaxNGSchemaFacetCheck:
2470  * @data:  data needed for the library
2471  * @type:  the type name
2472  * @facet:  the facet name
2473  * @val:  the facet value
2474  * @strval:  the string value
2475  * @value:  the value to check
2476  *
2477  * Function provided by a type library to check a value facet
2478  *
2479  * Returns 1 if yes, 0 if no and -1 in case of error.
2480  */
2481 static int
2482 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2483                            const xmlChar * type, const xmlChar * facetname,
2484                            const xmlChar * val, const xmlChar * strval,
2485                            void *value)
2486 {
2487     xmlSchemaFacetPtr facet;
2488     xmlSchemaTypePtr typ;
2489     int ret;
2490 
2491     if ((type == NULL) || (strval == NULL))
2492         return (-1);
2493     typ = xmlSchemaGetPredefinedType(type,
2494                                      BAD_CAST
2495                                      "http://www.w3.org/2001/XMLSchema");
2496     if (typ == NULL)
2497         return (-1);
2498 
2499     facet = xmlSchemaNewFacet();
2500     if (facet == NULL)
2501         return (-1);
2502 
2503     if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2504         facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2505     } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2506         facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2507     } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2508         facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2509     } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2510         facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2511     } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2512         facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2513     } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2514         facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2515     } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2516         facet->type = XML_SCHEMA_FACET_PATTERN;
2517     } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2518         facet->type = XML_SCHEMA_FACET_ENUMERATION;
2519     } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2520         facet->type = XML_SCHEMA_FACET_WHITESPACE;
2521     } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2522         facet->type = XML_SCHEMA_FACET_LENGTH;
2523     } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2524         facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2525     } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2526         facet->type = XML_SCHEMA_FACET_MINLENGTH;
2527     } else {
2528         xmlSchemaFreeFacet(facet);
2529         return (-1);
2530     }
2531     facet->value = val;
2532     ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2533     if (ret != 0) {
2534         xmlSchemaFreeFacet(facet);
2535         return (-1);
2536     }
2537     ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2538     xmlSchemaFreeFacet(facet);
2539     if (ret != 0)
2540         return (-1);
2541     return (0);
2542 }
2543 
2544 /**
2545  * xmlRelaxNGSchemaFreeValue:
2546  * @data:  data needed for the library
2547  * @value:  the value to free
2548  *
2549  * Function provided by a type library to free a Schemas value
2550  *
2551  * Returns 1 if yes, 0 if no and -1 in case of error.
2552  */
2553 static void
2554 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2555 {
2556     xmlSchemaFreeValue(value);
2557 }
2558 
2559 /**
2560  * xmlRelaxNGSchemaTypeCompare:
2561  * @data:  data needed for the library
2562  * @type:  the type name
2563  * @value1:  the first value
2564  * @value2:  the second value
2565  *
2566  * Compare two values for equality accordingly a type from the W3C XMLSchema
2567  * Datatype library.
2568  *
2569  * Returns 1 if equal, 0 if no and -1 in case of error.
2570  */
2571 static int
2572 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2573                             const xmlChar * type,
2574                             const xmlChar * value1,
2575                             xmlNodePtr ctxt1,
2576                             void *comp1,
2577                             const xmlChar * value2, xmlNodePtr ctxt2)
2578 {
2579     int ret;
2580     xmlSchemaTypePtr typ;
2581     xmlSchemaValPtr res1 = NULL, res2 = NULL;
2582 
2583     if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2584         return (-1);
2585     typ = xmlSchemaGetPredefinedType(type,
2586                                      BAD_CAST
2587                                      "http://www.w3.org/2001/XMLSchema");
2588     if (typ == NULL)
2589         return (-1);
2590     if (comp1 == NULL) {
2591         ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2592         if (ret != 0)
2593             return (-1);
2594         if (res1 == NULL)
2595             return (-1);
2596     } else {
2597         res1 = (xmlSchemaValPtr) comp1;
2598     }
2599     ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2600     if (ret != 0) {
2601 	if (res1 != (xmlSchemaValPtr) comp1)
2602 	    xmlSchemaFreeValue(res1);
2603         return (-1);
2604     }
2605     ret = xmlSchemaCompareValues(res1, res2);
2606     if (res1 != (xmlSchemaValPtr) comp1)
2607         xmlSchemaFreeValue(res1);
2608     xmlSchemaFreeValue(res2);
2609     if (ret == -2)
2610         return (-1);
2611     if (ret == 0)
2612         return (1);
2613     return (0);
2614 }
2615 
2616 /**
2617  * xmlRelaxNGDefaultTypeHave:
2618  * @data:  data needed for the library
2619  * @type:  the type name
2620  *
2621  * Check if the given type is provided by
2622  * the default datatype library.
2623  *
2624  * Returns 1 if yes, 0 if no and -1 in case of error.
2625  */
2626 static int
2627 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2628                           const xmlChar * type)
2629 {
2630     if (type == NULL)
2631         return (-1);
2632     if (xmlStrEqual(type, BAD_CAST "string"))
2633         return (1);
2634     if (xmlStrEqual(type, BAD_CAST "token"))
2635         return (1);
2636     return (0);
2637 }
2638 
2639 /**
2640  * xmlRelaxNGDefaultTypeCheck:
2641  * @data:  data needed for the library
2642  * @type:  the type name
2643  * @value:  the value to check
2644  * @node:  the node
2645  *
2646  * Check if the given type and value are validated by
2647  * the default datatype library.
2648  *
2649  * Returns 1 if yes, 0 if no and -1 in case of error.
2650  */
2651 static int
2652 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2653                            const xmlChar * type ATTRIBUTE_UNUSED,
2654                            const xmlChar * value ATTRIBUTE_UNUSED,
2655                            void **result ATTRIBUTE_UNUSED,
2656                            xmlNodePtr node ATTRIBUTE_UNUSED)
2657 {
2658     if (value == NULL)
2659         return (-1);
2660     if (xmlStrEqual(type, BAD_CAST "string"))
2661         return (1);
2662     if (xmlStrEqual(type, BAD_CAST "token")) {
2663         return (1);
2664     }
2665 
2666     return (0);
2667 }
2668 
2669 /**
2670  * xmlRelaxNGDefaultTypeCompare:
2671  * @data:  data needed for the library
2672  * @type:  the type name
2673  * @value1:  the first value
2674  * @value2:  the second value
2675  *
2676  * Compare two values accordingly a type from the default
2677  * datatype library.
2678  *
2679  * Returns 1 if yes, 0 if no and -1 in case of error.
2680  */
2681 static int
2682 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2683                              const xmlChar * type,
2684                              const xmlChar * value1,
2685                              xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2686                              void *comp1 ATTRIBUTE_UNUSED,
2687                              const xmlChar * value2,
2688                              xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2689 {
2690     int ret = -1;
2691 
2692     if (xmlStrEqual(type, BAD_CAST "string")) {
2693         ret = xmlStrEqual(value1, value2);
2694     } else if (xmlStrEqual(type, BAD_CAST "token")) {
2695         if (!xmlStrEqual(value1, value2)) {
2696             xmlChar *nval, *nvalue;
2697 
2698             /*
2699              * TODO: trivial optimizations are possible by
2700              * computing at compile-time
2701              */
2702             nval = xmlRelaxNGNormalize(NULL, value1);
2703             nvalue = xmlRelaxNGNormalize(NULL, value2);
2704 
2705             if ((nval == NULL) || (nvalue == NULL))
2706                 ret = -1;
2707             else if (xmlStrEqual(nval, nvalue))
2708                 ret = 1;
2709             else
2710                 ret = 0;
2711             if (nval != NULL)
2712                 xmlFree(nval);
2713             if (nvalue != NULL)
2714                 xmlFree(nvalue);
2715         } else
2716             ret = 1;
2717     }
2718     return (ret);
2719 }
2720 
2721 static int xmlRelaxNGTypeInitialized = 0;
2722 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2723 
2724 /**
2725  * xmlRelaxNGFreeTypeLibrary:
2726  * @lib:  the type library structure
2727  * @namespace:  the URI bound to the library
2728  *
2729  * Free the structure associated to the type library
2730  */
2731 static void
2732 xmlRelaxNGFreeTypeLibrary(void *payload,
2733                           const xmlChar * namespace ATTRIBUTE_UNUSED)
2734 {
2735     xmlRelaxNGTypeLibraryPtr lib = (xmlRelaxNGTypeLibraryPtr) payload;
2736     if (lib == NULL)
2737         return;
2738     if (lib->namespace != NULL)
2739         xmlFree((xmlChar *) lib->namespace);
2740     xmlFree(lib);
2741 }
2742 
2743 /**
2744  * xmlRelaxNGRegisterTypeLibrary:
2745  * @namespace:  the URI bound to the library
2746  * @data:  data associated to the library
2747  * @have:  the provide function
2748  * @check:  the checking function
2749  * @comp:  the comparison function
2750  *
2751  * Register a new type library
2752  *
2753  * Returns 0 in case of success and -1 in case of error.
2754  */
2755 static int
2756 xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2757                               xmlRelaxNGTypeHave have,
2758                               xmlRelaxNGTypeCheck check,
2759                               xmlRelaxNGTypeCompare comp,
2760                               xmlRelaxNGFacetCheck facet,
2761                               xmlRelaxNGTypeFree freef)
2762 {
2763     xmlRelaxNGTypeLibraryPtr lib;
2764     int ret;
2765 
2766     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2767         (check == NULL) || (comp == NULL))
2768         return (-1);
2769     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2770         xmlGenericError(xmlGenericErrorContext,
2771                         "Relax-NG types library '%s' already registered\n",
2772                         namespace);
2773         return (-1);
2774     }
2775     lib =
2776         (xmlRelaxNGTypeLibraryPtr)
2777         xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2778     if (lib == NULL) {
2779         xmlRngVErrMemory(NULL, "adding types library\n");
2780         return (-1);
2781     }
2782     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2783     lib->namespace = xmlStrdup(namespace);
2784     lib->data = data;
2785     lib->have = have;
2786     lib->comp = comp;
2787     lib->check = check;
2788     lib->facet = facet;
2789     lib->freef = freef;
2790     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2791     if (ret < 0) {
2792         xmlGenericError(xmlGenericErrorContext,
2793                         "Relax-NG types library failed to register '%s'\n",
2794                         namespace);
2795         xmlRelaxNGFreeTypeLibrary(lib, namespace);
2796         return (-1);
2797     }
2798     return (0);
2799 }
2800 
2801 /**
2802  * xmlRelaxNGInitTypes:
2803  *
2804  * Initilize the default type libraries.
2805  *
2806  * Returns 0 in case of success and -1 in case of error.
2807  */
2808 int
2809 xmlRelaxNGInitTypes(void)
2810 {
2811     if (xmlRelaxNGTypeInitialized != 0)
2812         return (0);
2813     xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2814     if (xmlRelaxNGRegisteredTypes == NULL) {
2815         xmlGenericError(xmlGenericErrorContext,
2816                         "Failed to allocate sh table for Relax-NG types\n");
2817         return (-1);
2818     }
2819     xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2820                                   "http://www.w3.org/2001/XMLSchema-datatypes",
2821                                   NULL, xmlRelaxNGSchemaTypeHave,
2822                                   xmlRelaxNGSchemaTypeCheck,
2823                                   xmlRelaxNGSchemaTypeCompare,
2824                                   xmlRelaxNGSchemaFacetCheck,
2825                                   xmlRelaxNGSchemaFreeValue);
2826     xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2827                                   xmlRelaxNGDefaultTypeHave,
2828                                   xmlRelaxNGDefaultTypeCheck,
2829                                   xmlRelaxNGDefaultTypeCompare, NULL,
2830                                   NULL);
2831     xmlRelaxNGTypeInitialized = 1;
2832     return (0);
2833 }
2834 
2835 /**
2836  * xmlRelaxNGCleanupTypes:
2837  *
2838  * Cleanup the default Schemas type library associated to RelaxNG
2839  */
2840 void
2841 xmlRelaxNGCleanupTypes(void)
2842 {
2843     xmlSchemaCleanupTypes();
2844     if (xmlRelaxNGTypeInitialized == 0)
2845         return;
2846     xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary);
2847     xmlRelaxNGTypeInitialized = 0;
2848 }
2849 
2850 /************************************************************************
2851  *									*
2852  *		Compiling element content into regexp			*
2853  *									*
2854  * Sometime the element content can be compiled into a pure regexp,	*
2855  * This allows a faster execution and streamability at that level	*
2856  *									*
2857  ************************************************************************/
2858 
2859 /* from automata.c but not exported */
2860 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
2861 
2862 
2863 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2864                                 xmlRelaxNGDefinePtr def);
2865 
2866 /**
2867  * xmlRelaxNGIsCompileable:
2868  * @define:  the definition to check
2869  *
2870  * Check if a definition is nullable.
2871  *
2872  * Returns 1 if yes, 0 if no and -1 in case of error
2873  */
2874 static int
2875 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2876 {
2877     int ret = -1;
2878 
2879     if (def == NULL) {
2880         return (-1);
2881     }
2882     if ((def->type != XML_RELAXNG_ELEMENT) &&
2883         (def->dflags & IS_COMPILABLE))
2884         return (1);
2885     if ((def->type != XML_RELAXNG_ELEMENT) &&
2886         (def->dflags & IS_NOT_COMPILABLE))
2887         return (0);
2888     switch (def->type) {
2889         case XML_RELAXNG_NOOP:
2890             ret = xmlRelaxNGIsCompileable(def->content);
2891             break;
2892         case XML_RELAXNG_TEXT:
2893         case XML_RELAXNG_EMPTY:
2894             ret = 1;
2895             break;
2896         case XML_RELAXNG_ELEMENT:
2897             /*
2898              * Check if the element content is compileable
2899              */
2900             if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2901                 ((def->dflags & IS_COMPILABLE) == 0)) {
2902                 xmlRelaxNGDefinePtr list;
2903 
2904                 list = def->content;
2905                 while (list != NULL) {
2906                     ret = xmlRelaxNGIsCompileable(list);
2907                     if (ret != 1)
2908                         break;
2909                     list = list->next;
2910                 }
2911 		/*
2912 		 * Because the routine is recursive, we must guard against
2913 		 * discovering both COMPILABLE and NOT_COMPILABLE
2914 		 */
2915                 if (ret == 0) {
2916 		    def->dflags &= ~IS_COMPILABLE;
2917                     def->dflags |= IS_NOT_COMPILABLE;
2918 		}
2919                 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2920                     def->dflags |= IS_COMPILABLE;
2921 #ifdef DEBUG_COMPILE
2922                 if (ret == 1) {
2923                     xmlGenericError(xmlGenericErrorContext,
2924                                     "element content for %s is compilable\n",
2925                                     def->name);
2926                 } else if (ret == 0) {
2927                     xmlGenericError(xmlGenericErrorContext,
2928                                     "element content for %s is not compilable\n",
2929                                     def->name);
2930                 } else {
2931                     xmlGenericError(xmlGenericErrorContext,
2932                                     "Problem in RelaxNGIsCompileable for element %s\n",
2933                                     def->name);
2934                 }
2935 #endif
2936             }
2937             /*
2938              * All elements return a compileable status unless they
2939              * are generic like anyName
2940              */
2941             if ((def->nameClass != NULL) || (def->name == NULL))
2942                 ret = 0;
2943             else
2944                 ret = 1;
2945             return (ret);
2946         case XML_RELAXNG_REF:
2947         case XML_RELAXNG_EXTERNALREF:
2948         case XML_RELAXNG_PARENTREF:
2949             if (def->depth == -20) {
2950                 return (1);
2951             } else {
2952                 xmlRelaxNGDefinePtr list;
2953 
2954                 def->depth = -20;
2955                 list = def->content;
2956                 while (list != NULL) {
2957                     ret = xmlRelaxNGIsCompileable(list);
2958                     if (ret != 1)
2959                         break;
2960                     list = list->next;
2961                 }
2962             }
2963             break;
2964         case XML_RELAXNG_START:
2965         case XML_RELAXNG_OPTIONAL:
2966         case XML_RELAXNG_ZEROORMORE:
2967         case XML_RELAXNG_ONEORMORE:
2968         case XML_RELAXNG_CHOICE:
2969         case XML_RELAXNG_GROUP:
2970         case XML_RELAXNG_DEF:{
2971                 xmlRelaxNGDefinePtr list;
2972 
2973                 list = def->content;
2974                 while (list != NULL) {
2975                     ret = xmlRelaxNGIsCompileable(list);
2976                     if (ret != 1)
2977                         break;
2978                     list = list->next;
2979                 }
2980                 break;
2981             }
2982         case XML_RELAXNG_EXCEPT:
2983         case XML_RELAXNG_ATTRIBUTE:
2984         case XML_RELAXNG_INTERLEAVE:
2985         case XML_RELAXNG_DATATYPE:
2986         case XML_RELAXNG_LIST:
2987         case XML_RELAXNG_PARAM:
2988         case XML_RELAXNG_VALUE:
2989         case XML_RELAXNG_NOT_ALLOWED:
2990             ret = 0;
2991             break;
2992     }
2993     if (ret == 0)
2994         def->dflags |= IS_NOT_COMPILABLE;
2995     if (ret == 1)
2996         def->dflags |= IS_COMPILABLE;
2997 #ifdef DEBUG_COMPILE
2998     if (ret == 1) {
2999         xmlGenericError(xmlGenericErrorContext,
3000                         "RelaxNGIsCompileable %s : true\n",
3001                         xmlRelaxNGDefName(def));
3002     } else if (ret == 0) {
3003         xmlGenericError(xmlGenericErrorContext,
3004                         "RelaxNGIsCompileable %s : false\n",
3005                         xmlRelaxNGDefName(def));
3006     } else {
3007         xmlGenericError(xmlGenericErrorContext,
3008                         "Problem in RelaxNGIsCompileable %s\n",
3009                         xmlRelaxNGDefName(def));
3010     }
3011 #endif
3012     return (ret);
3013 }
3014 
3015 /**
3016  * xmlRelaxNGCompile:
3017  * ctxt:  the RelaxNG parser context
3018  * @define:  the definition tree to compile
3019  *
3020  * Compile the set of definitions, it works recursively, till the
3021  * element boundaries, where it tries to compile the content if possible
3022  *
3023  * Returns 0 if success and -1 in case of error
3024  */
3025 static int
3026 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3027 {
3028     int ret = 0;
3029     xmlRelaxNGDefinePtr list;
3030 
3031     if ((ctxt == NULL) || (def == NULL))
3032         return (-1);
3033 
3034     switch (def->type) {
3035         case XML_RELAXNG_START:
3036             if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
3037                 xmlAutomataPtr oldam = ctxt->am;
3038                 xmlAutomataStatePtr oldstate = ctxt->state;
3039 
3040                 def->depth = -25;
3041 
3042                 list = def->content;
3043                 ctxt->am = xmlNewAutomata();
3044                 if (ctxt->am == NULL)
3045                     return (-1);
3046 
3047                 /*
3048                  * assume identical strings but not same pointer are different
3049                  * atoms, needed for non-determinism detection
3050                  * That way if 2 elements with the same name are in a choice
3051                  * branch the automata is found non-deterministic and
3052                  * we fallback to the normal validation which does the right
3053                  * thing of exploring both choices.
3054                  */
3055                 xmlAutomataSetFlags(ctxt->am, 1);
3056 
3057                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3058                 while (list != NULL) {
3059                     xmlRelaxNGCompile(ctxt, list);
3060                     list = list->next;
3061                 }
3062                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3063                 if (xmlAutomataIsDeterminist(ctxt->am))
3064                     def->contModel = xmlAutomataCompile(ctxt->am);
3065 
3066                 xmlFreeAutomata(ctxt->am);
3067                 ctxt->state = oldstate;
3068                 ctxt->am = oldam;
3069             }
3070             break;
3071         case XML_RELAXNG_ELEMENT:
3072             if ((ctxt->am != NULL) && (def->name != NULL)) {
3073                 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3074                                                         ctxt->state, NULL,
3075                                                         def->name, def->ns,
3076                                                         def);
3077             }
3078             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3079                 xmlAutomataPtr oldam = ctxt->am;
3080                 xmlAutomataStatePtr oldstate = ctxt->state;
3081 
3082                 def->depth = -25;
3083 
3084                 list = def->content;
3085                 ctxt->am = xmlNewAutomata();
3086                 if (ctxt->am == NULL)
3087                     return (-1);
3088                 xmlAutomataSetFlags(ctxt->am, 1);
3089                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3090                 while (list != NULL) {
3091                     xmlRelaxNGCompile(ctxt, list);
3092                     list = list->next;
3093                 }
3094                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3095                 def->contModel = xmlAutomataCompile(ctxt->am);
3096                 if (!xmlRegexpIsDeterminist(def->contModel)) {
3097 #ifdef DEBUG_COMPILE
3098                     xmlGenericError(xmlGenericErrorContext,
3099                         "Content model not determinist %s\n",
3100                                     def->name);
3101 #endif
3102                     /*
3103                      * we can only use the automata if it is determinist
3104                      */
3105                     xmlRegFreeRegexp(def->contModel);
3106                     def->contModel = NULL;
3107                 }
3108                 xmlFreeAutomata(ctxt->am);
3109                 ctxt->state = oldstate;
3110                 ctxt->am = oldam;
3111             } else {
3112                 xmlAutomataPtr oldam = ctxt->am;
3113 
3114                 /*
3115                  * we can't build the content model for this element content
3116                  * but it still might be possible to build it for some of its
3117                  * children, recurse.
3118                  */
3119                 ret = xmlRelaxNGTryCompile(ctxt, def);
3120                 ctxt->am = oldam;
3121             }
3122             break;
3123         case XML_RELAXNG_NOOP:
3124             ret = xmlRelaxNGCompile(ctxt, def->content);
3125             break;
3126         case XML_RELAXNG_OPTIONAL:{
3127                 xmlAutomataStatePtr oldstate = ctxt->state;
3128 
3129                 list = def->content;
3130                 while (list != NULL) {
3131                     xmlRelaxNGCompile(ctxt, list);
3132                     list = list->next;
3133                 }
3134                 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3135                 break;
3136             }
3137         case XML_RELAXNG_ZEROORMORE:{
3138                 xmlAutomataStatePtr oldstate;
3139 
3140                 ctxt->state =
3141                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3142                 oldstate = ctxt->state;
3143                 list = def->content;
3144                 while (list != NULL) {
3145                     xmlRelaxNGCompile(ctxt, list);
3146                     list = list->next;
3147                 }
3148                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3149                 ctxt->state =
3150                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3151                 break;
3152             }
3153         case XML_RELAXNG_ONEORMORE:{
3154                 xmlAutomataStatePtr oldstate;
3155 
3156                 list = def->content;
3157                 while (list != NULL) {
3158                     xmlRelaxNGCompile(ctxt, list);
3159                     list = list->next;
3160                 }
3161                 oldstate = ctxt->state;
3162                 list = def->content;
3163                 while (list != NULL) {
3164                     xmlRelaxNGCompile(ctxt, list);
3165                     list = list->next;
3166                 }
3167                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3168                 ctxt->state =
3169                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3170                 break;
3171             }
3172         case XML_RELAXNG_CHOICE:{
3173                 xmlAutomataStatePtr target = NULL;
3174                 xmlAutomataStatePtr oldstate = ctxt->state;
3175 
3176                 list = def->content;
3177                 while (list != NULL) {
3178                     ctxt->state = oldstate;
3179                     ret = xmlRelaxNGCompile(ctxt, list);
3180                     if (ret != 0)
3181                         break;
3182                     if (target == NULL)
3183                         target = ctxt->state;
3184                     else {
3185                         xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3186                                               target);
3187                     }
3188                     list = list->next;
3189                 }
3190                 ctxt->state = target;
3191 
3192                 break;
3193             }
3194         case XML_RELAXNG_REF:
3195         case XML_RELAXNG_EXTERNALREF:
3196         case XML_RELAXNG_PARENTREF:
3197         case XML_RELAXNG_GROUP:
3198         case XML_RELAXNG_DEF:
3199             list = def->content;
3200             while (list != NULL) {
3201                 ret = xmlRelaxNGCompile(ctxt, list);
3202                 if (ret != 0)
3203                     break;
3204                 list = list->next;
3205             }
3206             break;
3207         case XML_RELAXNG_TEXT:{
3208                 xmlAutomataStatePtr oldstate;
3209 
3210                 ctxt->state =
3211                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3212                 oldstate = ctxt->state;
3213                 xmlRelaxNGCompile(ctxt, def->content);
3214                 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3215                                          ctxt->state, BAD_CAST "#text",
3216                                          NULL);
3217                 ctxt->state =
3218                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3219                 break;
3220             }
3221         case XML_RELAXNG_EMPTY:
3222             ctxt->state =
3223                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3224             break;
3225         case XML_RELAXNG_EXCEPT:
3226         case XML_RELAXNG_ATTRIBUTE:
3227         case XML_RELAXNG_INTERLEAVE:
3228         case XML_RELAXNG_NOT_ALLOWED:
3229         case XML_RELAXNG_DATATYPE:
3230         case XML_RELAXNG_LIST:
3231         case XML_RELAXNG_PARAM:
3232         case XML_RELAXNG_VALUE:
3233             /* This should not happen and generate an internal error */
3234             fprintf(stderr, "RNG internal error trying to compile %s\n",
3235                     xmlRelaxNGDefName(def));
3236             break;
3237     }
3238     return (ret);
3239 }
3240 
3241 /**
3242  * xmlRelaxNGTryCompile:
3243  * ctxt:  the RelaxNG parser context
3244  * @define:  the definition tree to compile
3245  *
3246  * Try to compile the set of definitions, it works recursively,
3247  * possibly ignoring parts which cannot be compiled.
3248  *
3249  * Returns 0 if success and -1 in case of error
3250  */
3251 static int
3252 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3253 {
3254     int ret = 0;
3255     xmlRelaxNGDefinePtr list;
3256 
3257     if ((ctxt == NULL) || (def == NULL))
3258         return (-1);
3259 
3260     if ((def->type == XML_RELAXNG_START) ||
3261         (def->type == XML_RELAXNG_ELEMENT)) {
3262         ret = xmlRelaxNGIsCompileable(def);
3263         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3264             ctxt->am = NULL;
3265             ret = xmlRelaxNGCompile(ctxt, def);
3266 #ifdef DEBUG_PROGRESSIVE
3267             if (ret == 0) {
3268                 if (def->type == XML_RELAXNG_START)
3269                     xmlGenericError(xmlGenericErrorContext,
3270                                     "compiled the start\n");
3271                 else
3272                     xmlGenericError(xmlGenericErrorContext,
3273                                     "compiled element %s\n", def->name);
3274             } else {
3275                 if (def->type == XML_RELAXNG_START)
3276                     xmlGenericError(xmlGenericErrorContext,
3277                                     "failed to compile the start\n");
3278                 else
3279                     xmlGenericError(xmlGenericErrorContext,
3280                                     "failed to compile element %s\n",
3281                                     def->name);
3282             }
3283 #endif
3284             return (ret);
3285         }
3286     }
3287     switch (def->type) {
3288         case XML_RELAXNG_NOOP:
3289             ret = xmlRelaxNGTryCompile(ctxt, def->content);
3290             break;
3291         case XML_RELAXNG_TEXT:
3292         case XML_RELAXNG_DATATYPE:
3293         case XML_RELAXNG_LIST:
3294         case XML_RELAXNG_PARAM:
3295         case XML_RELAXNG_VALUE:
3296         case XML_RELAXNG_EMPTY:
3297         case XML_RELAXNG_ELEMENT:
3298             ret = 0;
3299             break;
3300         case XML_RELAXNG_OPTIONAL:
3301         case XML_RELAXNG_ZEROORMORE:
3302         case XML_RELAXNG_ONEORMORE:
3303         case XML_RELAXNG_CHOICE:
3304         case XML_RELAXNG_GROUP:
3305         case XML_RELAXNG_DEF:
3306         case XML_RELAXNG_START:
3307         case XML_RELAXNG_REF:
3308         case XML_RELAXNG_EXTERNALREF:
3309         case XML_RELAXNG_PARENTREF:
3310             list = def->content;
3311             while (list != NULL) {
3312                 ret = xmlRelaxNGTryCompile(ctxt, list);
3313                 if (ret != 0)
3314                     break;
3315                 list = list->next;
3316             }
3317             break;
3318         case XML_RELAXNG_EXCEPT:
3319         case XML_RELAXNG_ATTRIBUTE:
3320         case XML_RELAXNG_INTERLEAVE:
3321         case XML_RELAXNG_NOT_ALLOWED:
3322             ret = 0;
3323             break;
3324     }
3325     return (ret);
3326 }
3327 
3328 /************************************************************************
3329  *									*
3330  *			Parsing functions				*
3331  *									*
3332  ************************************************************************/
3333 
3334 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3335                                                     ctxt, xmlNodePtr node);
3336 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3337                                                   ctxt, xmlNodePtr node);
3338 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3339                                                    ctxt, xmlNodePtr nodes,
3340                                                    int group);
3341 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3342                                                   ctxt, xmlNodePtr node);
3343 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3344                                              xmlNodePtr node);
3345 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3346                                          xmlNodePtr nodes);
3347 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3348                                                     ctxt, xmlNodePtr node,
3349                                                     xmlRelaxNGDefinePtr
3350                                                     def);
3351 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3352                                                    ctxt, xmlNodePtr nodes);
3353 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3354                                   xmlRelaxNGDefinePtr define,
3355                                   xmlNodePtr elem);
3356 
3357 
3358 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3359 
3360 /**
3361  * xmlRelaxNGIsNullable:
3362  * @define:  the definition to verify
3363  *
3364  * Check if a definition is nullable.
3365  *
3366  * Returns 1 if yes, 0 if no and -1 in case of error
3367  */
3368 static int
3369 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3370 {
3371     int ret;
3372 
3373     if (define == NULL)
3374         return (-1);
3375 
3376     if (define->dflags & IS_NULLABLE)
3377         return (1);
3378     if (define->dflags & IS_NOT_NULLABLE)
3379         return (0);
3380     switch (define->type) {
3381         case XML_RELAXNG_EMPTY:
3382         case XML_RELAXNG_TEXT:
3383             ret = 1;
3384             break;
3385         case XML_RELAXNG_NOOP:
3386         case XML_RELAXNG_DEF:
3387         case XML_RELAXNG_REF:
3388         case XML_RELAXNG_EXTERNALREF:
3389         case XML_RELAXNG_PARENTREF:
3390         case XML_RELAXNG_ONEORMORE:
3391             ret = xmlRelaxNGIsNullable(define->content);
3392             break;
3393         case XML_RELAXNG_EXCEPT:
3394         case XML_RELAXNG_NOT_ALLOWED:
3395         case XML_RELAXNG_ELEMENT:
3396         case XML_RELAXNG_DATATYPE:
3397         case XML_RELAXNG_PARAM:
3398         case XML_RELAXNG_VALUE:
3399         case XML_RELAXNG_LIST:
3400         case XML_RELAXNG_ATTRIBUTE:
3401             ret = 0;
3402             break;
3403         case XML_RELAXNG_CHOICE:{
3404                 xmlRelaxNGDefinePtr list = define->content;
3405 
3406                 while (list != NULL) {
3407                     ret = xmlRelaxNGIsNullable(list);
3408                     if (ret != 0)
3409                         goto done;
3410                     list = list->next;
3411                 }
3412                 ret = 0;
3413                 break;
3414             }
3415         case XML_RELAXNG_START:
3416         case XML_RELAXNG_INTERLEAVE:
3417         case XML_RELAXNG_GROUP:{
3418                 xmlRelaxNGDefinePtr list = define->content;
3419 
3420                 while (list != NULL) {
3421                     ret = xmlRelaxNGIsNullable(list);
3422                     if (ret != 1)
3423                         goto done;
3424                     list = list->next;
3425                 }
3426                 return (1);
3427             }
3428         default:
3429             return (-1);
3430     }
3431   done:
3432     if (ret == 0)
3433         define->dflags |= IS_NOT_NULLABLE;
3434     if (ret == 1)
3435         define->dflags |= IS_NULLABLE;
3436     return (ret);
3437 }
3438 
3439 /**
3440  * xmlRelaxNGIsBlank:
3441  * @str:  a string
3442  *
3443  * Check if a string is ignorable c.f. 4.2. Whitespace
3444  *
3445  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3446  */
3447 static int
3448 xmlRelaxNGIsBlank(xmlChar * str)
3449 {
3450     if (str == NULL)
3451         return (1);
3452     while (*str != 0) {
3453         if (!(IS_BLANK_CH(*str)))
3454             return (0);
3455         str++;
3456     }
3457     return (1);
3458 }
3459 
3460 /**
3461  * xmlRelaxNGGetDataTypeLibrary:
3462  * @ctxt:  a Relax-NG parser context
3463  * @node:  the current data or value element
3464  *
3465  * Applies algorithm from 4.3. datatypeLibrary attribute
3466  *
3467  * Returns the datatypeLibary value or NULL if not found
3468  */
3469 static xmlChar *
3470 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3471                              xmlNodePtr node)
3472 {
3473     xmlChar *ret, *escape;
3474 
3475     if (node == NULL)
3476         return(NULL);
3477 
3478     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3479         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3480         if (ret != NULL) {
3481             if (ret[0] == 0) {
3482                 xmlFree(ret);
3483                 return (NULL);
3484             }
3485             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3486             if (escape == NULL) {
3487                 return (ret);
3488             }
3489             xmlFree(ret);
3490             return (escape);
3491         }
3492     }
3493     node = node->parent;
3494     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3495         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3496         if (ret != NULL) {
3497             if (ret[0] == 0) {
3498                 xmlFree(ret);
3499                 return (NULL);
3500             }
3501             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3502             if (escape == NULL) {
3503                 return (ret);
3504             }
3505             xmlFree(ret);
3506             return (escape);
3507         }
3508         node = node->parent;
3509     }
3510     return (NULL);
3511 }
3512 
3513 /**
3514  * xmlRelaxNGParseValue:
3515  * @ctxt:  a Relax-NG parser context
3516  * @node:  the data node.
3517  *
3518  * parse the content of a RelaxNG value node.
3519  *
3520  * Returns the definition pointer or NULL in case of error
3521  */
3522 static xmlRelaxNGDefinePtr
3523 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3524 {
3525     xmlRelaxNGDefinePtr def = NULL;
3526     xmlRelaxNGTypeLibraryPtr lib = NULL;
3527     xmlChar *type;
3528     xmlChar *library;
3529     int success = 0;
3530 
3531     def = xmlRelaxNGNewDefine(ctxt, node);
3532     if (def == NULL)
3533         return (NULL);
3534     def->type = XML_RELAXNG_VALUE;
3535 
3536     type = xmlGetProp(node, BAD_CAST "type");
3537     if (type != NULL) {
3538         xmlRelaxNGNormExtSpace(type);
3539         if (xmlValidateNCName(type, 0)) {
3540             xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3541                        "value type '%s' is not an NCName\n", type, NULL);
3542         }
3543         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3544         if (library == NULL)
3545             library =
3546                 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3547 
3548         def->name = type;
3549         def->ns = library;
3550 
3551         lib = (xmlRelaxNGTypeLibraryPtr)
3552             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3553         if (lib == NULL) {
3554             xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3555                        "Use of unregistered type library '%s'\n", library,
3556                        NULL);
3557             def->data = NULL;
3558         } else {
3559             def->data = lib;
3560             if (lib->have == NULL) {
3561                 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3562                            "Internal error with type library '%s': no 'have'\n",
3563                            library, NULL);
3564             } else {
3565                 success = lib->have(lib->data, def->name);
3566                 if (success != 1) {
3567                     xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3568                                "Error type '%s' is not exported by type library '%s'\n",
3569                                def->name, library);
3570                 }
3571             }
3572         }
3573     }
3574     if (node->children == NULL) {
3575         def->value = xmlStrdup(BAD_CAST "");
3576     } else if (((node->children->type != XML_TEXT_NODE) &&
3577                 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3578                (node->children->next != NULL)) {
3579         xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3580                    "Expecting a single text value for <value>content\n",
3581                    NULL, NULL);
3582     } else if (def != NULL) {
3583         def->value = xmlNodeGetContent(node);
3584         if (def->value == NULL) {
3585             xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3586                        "Element <value> has no content\n", NULL, NULL);
3587         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3588             void *val = NULL;
3589 
3590             success =
3591                 lib->check(lib->data, def->name, def->value, &val, node);
3592             if (success != 1) {
3593                 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3594                            "Value '%s' is not acceptable for type '%s'\n",
3595                            def->value, def->name);
3596             } else {
3597                 if (val != NULL)
3598                     def->attrs = val;
3599             }
3600         }
3601     }
3602     return (def);
3603 }
3604 
3605 /**
3606  * xmlRelaxNGParseData:
3607  * @ctxt:  a Relax-NG parser context
3608  * @node:  the data node.
3609  *
3610  * parse the content of a RelaxNG data node.
3611  *
3612  * Returns the definition pointer or NULL in case of error
3613  */
3614 static xmlRelaxNGDefinePtr
3615 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3616 {
3617     xmlRelaxNGDefinePtr def = NULL, except;
3618     xmlRelaxNGDefinePtr param, lastparam = NULL;
3619     xmlRelaxNGTypeLibraryPtr lib;
3620     xmlChar *type;
3621     xmlChar *library;
3622     xmlNodePtr content;
3623     int tmp;
3624 
3625     type = xmlGetProp(node, BAD_CAST "type");
3626     if (type == NULL) {
3627         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3628                    NULL);
3629         return (NULL);
3630     }
3631     xmlRelaxNGNormExtSpace(type);
3632     if (xmlValidateNCName(type, 0)) {
3633         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3634                    "data type '%s' is not an NCName\n", type, NULL);
3635     }
3636     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3637     if (library == NULL)
3638         library =
3639             xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3640 
3641     def = xmlRelaxNGNewDefine(ctxt, node);
3642     if (def == NULL) {
3643         xmlFree(type);
3644         return (NULL);
3645     }
3646     def->type = XML_RELAXNG_DATATYPE;
3647     def->name = type;
3648     def->ns = library;
3649 
3650     lib = (xmlRelaxNGTypeLibraryPtr)
3651         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3652     if (lib == NULL) {
3653         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3654                    "Use of unregistered type library '%s'\n", library,
3655                    NULL);
3656         def->data = NULL;
3657     } else {
3658         def->data = lib;
3659         if (lib->have == NULL) {
3660             xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3661                        "Internal error with type library '%s': no 'have'\n",
3662                        library, NULL);
3663         } else {
3664             tmp = lib->have(lib->data, def->name);
3665             if (tmp != 1) {
3666                 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3667                            "Error type '%s' is not exported by type library '%s'\n",
3668                            def->name, library);
3669             } else
3670                 if ((xmlStrEqual
3671                      (library,
3672                       BAD_CAST
3673                       "http://www.w3.org/2001/XMLSchema-datatypes"))
3674                     && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3675                         || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3676                 ctxt->idref = 1;
3677             }
3678         }
3679     }
3680     content = node->children;
3681 
3682     /*
3683      * Handle optional params
3684      */
3685     while (content != NULL) {
3686         if (!xmlStrEqual(content->name, BAD_CAST "param"))
3687             break;
3688         if (xmlStrEqual(library,
3689                         BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3690             xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3691                        "Type library '%s' does not allow type parameters\n",
3692                        library, NULL);
3693             content = content->next;
3694             while ((content != NULL) &&
3695                    (xmlStrEqual(content->name, BAD_CAST "param")))
3696                 content = content->next;
3697         } else {
3698             param = xmlRelaxNGNewDefine(ctxt, node);
3699             if (param != NULL) {
3700                 param->type = XML_RELAXNG_PARAM;
3701                 param->name = xmlGetProp(content, BAD_CAST "name");
3702                 if (param->name == NULL) {
3703                     xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3704                                "param has no name\n", NULL, NULL);
3705                 }
3706                 param->value = xmlNodeGetContent(content);
3707                 if (lastparam == NULL) {
3708                     def->attrs = lastparam = param;
3709                 } else {
3710                     lastparam->next = param;
3711                     lastparam = param;
3712                 }
3713                 if (lib != NULL) {
3714                 }
3715             }
3716             content = content->next;
3717         }
3718     }
3719     /*
3720      * Handle optional except
3721      */
3722     if ((content != NULL)
3723         && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3724         xmlNodePtr child;
3725         xmlRelaxNGDefinePtr tmp2, last = NULL;
3726 
3727         except = xmlRelaxNGNewDefine(ctxt, node);
3728         if (except == NULL) {
3729             return (def);
3730         }
3731         except->type = XML_RELAXNG_EXCEPT;
3732         child = content->children;
3733 	def->content = except;
3734         if (child == NULL) {
3735             xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3736                        "except has no content\n", NULL, NULL);
3737         }
3738         while (child != NULL) {
3739             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3740             if (tmp2 != NULL) {
3741                 if (last == NULL) {
3742                     except->content = last = tmp2;
3743                 } else {
3744                     last->next = tmp2;
3745                     last = tmp2;
3746                 }
3747             }
3748             child = child->next;
3749         }
3750         content = content->next;
3751     }
3752     /*
3753      * Check there is no unhandled data
3754      */
3755     if (content != NULL) {
3756         xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3757                    "Element data has unexpected content %s\n",
3758                    content->name, NULL);
3759     }
3760 
3761     return (def);
3762 }
3763 
3764 static const xmlChar *invalidName = BAD_CAST "\1";
3765 
3766 /**
3767  * xmlRelaxNGCompareNameClasses:
3768  * @defs1:  the first element/attribute defs
3769  * @defs2:  the second element/attribute defs
3770  * @name:  the restriction on the name
3771  * @ns:  the restriction on the namespace
3772  *
3773  * Compare the 2 lists of element definitions. The comparison is
3774  * that if both lists do not accept the same QNames, it returns 1
3775  * If the 2 lists can accept the same QName the comparison returns 0
3776  *
3777  * Returns 1 disttinct, 0 if equal
3778  */
3779 static int
3780 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3781                              xmlRelaxNGDefinePtr def2)
3782 {
3783     int ret = 1;
3784     xmlNode node;
3785     xmlNs ns;
3786     xmlRelaxNGValidCtxt ctxt;
3787 
3788     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3789 
3790     ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3791 
3792     if ((def1->type == XML_RELAXNG_ELEMENT) ||
3793         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3794         if (def2->type == XML_RELAXNG_TEXT)
3795             return (1);
3796         if (def1->name != NULL) {
3797             node.name = def1->name;
3798         } else {
3799             node.name = invalidName;
3800         }
3801         if (def1->ns != NULL) {
3802             if (def1->ns[0] == 0) {
3803                 node.ns = NULL;
3804             } else {
3805 	        node.ns = &ns;
3806                 ns.href = def1->ns;
3807             }
3808         } else {
3809             node.ns = NULL;
3810         }
3811         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3812             if (def1->nameClass != NULL) {
3813                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3814             } else {
3815                 ret = 0;
3816             }
3817         } else {
3818             ret = 1;
3819         }
3820     } else if (def1->type == XML_RELAXNG_TEXT) {
3821         if (def2->type == XML_RELAXNG_TEXT)
3822             return (0);
3823         return (1);
3824     } else if (def1->type == XML_RELAXNG_EXCEPT) {
3825         ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
3826 	if (ret == 0)
3827 	    ret = 1;
3828 	else if (ret == 1)
3829 	    ret = 0;
3830     } else {
3831         TODO ret = 0;
3832     }
3833     if (ret == 0)
3834         return (ret);
3835     if ((def2->type == XML_RELAXNG_ELEMENT) ||
3836         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3837         if (def2->name != NULL) {
3838             node.name = def2->name;
3839         } else {
3840             node.name = invalidName;
3841         }
3842         node.ns = &ns;
3843         if (def2->ns != NULL) {
3844             if (def2->ns[0] == 0) {
3845                 node.ns = NULL;
3846             } else {
3847                 ns.href = def2->ns;
3848             }
3849         } else {
3850             ns.href = invalidName;
3851         }
3852         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3853             if (def2->nameClass != NULL) {
3854                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3855             } else {
3856                 ret = 0;
3857             }
3858         } else {
3859             ret = 1;
3860         }
3861     } else {
3862         TODO ret = 0;
3863     }
3864 
3865     return (ret);
3866 }
3867 
3868 /**
3869  * xmlRelaxNGCompareElemDefLists:
3870  * @ctxt:  a Relax-NG parser context
3871  * @defs1:  the first list of element/attribute defs
3872  * @defs2:  the second list of element/attribute defs
3873  *
3874  * Compare the 2 lists of element or attribute definitions. The comparison
3875  * is that if both lists do not accept the same QNames, it returns 1
3876  * If the 2 lists can accept the same QName the comparison returns 0
3877  *
3878  * Returns 1 disttinct, 0 if equal
3879  */
3880 static int
3881 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3882                               ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3883                               xmlRelaxNGDefinePtr * def2)
3884 {
3885     xmlRelaxNGDefinePtr *basedef2 = def2;
3886 
3887     if ((def1 == NULL) || (def2 == NULL))
3888         return (1);
3889     if ((*def1 == NULL) || (*def2 == NULL))
3890         return (1);
3891     while (*def1 != NULL) {
3892         while ((*def2) != NULL) {
3893             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3894                 return (0);
3895             def2++;
3896         }
3897         def2 = basedef2;
3898         def1++;
3899     }
3900     return (1);
3901 }
3902 
3903 /**
3904  * xmlRelaxNGGenerateAttributes:
3905  * @ctxt:  a Relax-NG parser context
3906  * @def:  the definition definition
3907  *
3908  * Check if the definition can only generate attributes
3909  *
3910  * Returns 1 if yes, 0 if no and -1 in case of error.
3911  */
3912 static int
3913 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3914                              xmlRelaxNGDefinePtr def)
3915 {
3916     xmlRelaxNGDefinePtr parent, cur, tmp;
3917 
3918     /*
3919      * Don't run that check in case of error. Infinite recursion
3920      * becomes possible.
3921      */
3922     if (ctxt->nbErrors != 0)
3923         return (-1);
3924 
3925     parent = NULL;
3926     cur = def;
3927     while (cur != NULL) {
3928         if ((cur->type == XML_RELAXNG_ELEMENT) ||
3929             (cur->type == XML_RELAXNG_TEXT) ||
3930             (cur->type == XML_RELAXNG_DATATYPE) ||
3931             (cur->type == XML_RELAXNG_PARAM) ||
3932             (cur->type == XML_RELAXNG_LIST) ||
3933             (cur->type == XML_RELAXNG_VALUE) ||
3934             (cur->type == XML_RELAXNG_EMPTY))
3935             return (0);
3936         if ((cur->type == XML_RELAXNG_CHOICE) ||
3937             (cur->type == XML_RELAXNG_INTERLEAVE) ||
3938             (cur->type == XML_RELAXNG_GROUP) ||
3939             (cur->type == XML_RELAXNG_ONEORMORE) ||
3940             (cur->type == XML_RELAXNG_ZEROORMORE) ||
3941             (cur->type == XML_RELAXNG_OPTIONAL) ||
3942             (cur->type == XML_RELAXNG_PARENTREF) ||
3943             (cur->type == XML_RELAXNG_EXTERNALREF) ||
3944             (cur->type == XML_RELAXNG_REF) ||
3945             (cur->type == XML_RELAXNG_DEF)) {
3946             if (cur->content != NULL) {
3947                 parent = cur;
3948                 cur = cur->content;
3949                 tmp = cur;
3950                 while (tmp != NULL) {
3951                     tmp->parent = parent;
3952                     tmp = tmp->next;
3953                 }
3954                 continue;
3955             }
3956         }
3957         if (cur == def)
3958             break;
3959         if (cur->next != NULL) {
3960             cur = cur->next;
3961             continue;
3962         }
3963         do {
3964             cur = cur->parent;
3965             if (cur == NULL)
3966                 break;
3967             if (cur == def)
3968                 return (1);
3969             if (cur->next != NULL) {
3970                 cur = cur->next;
3971                 break;
3972             }
3973         } while (cur != NULL);
3974     }
3975     return (1);
3976 }
3977 
3978 /**
3979  * xmlRelaxNGGetElements:
3980  * @ctxt:  a Relax-NG parser context
3981  * @def:  the definition definition
3982  * @eora:  gather elements (0) or attributes (1)
3983  *
3984  * Compute the list of top elements a definition can generate
3985  *
3986  * Returns a list of elements or NULL if none was found.
3987  */
3988 static xmlRelaxNGDefinePtr *
3989 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
3990                       xmlRelaxNGDefinePtr def, int eora)
3991 {
3992     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
3993     int len = 0;
3994     int max = 0;
3995 
3996     /*
3997      * Don't run that check in case of error. Infinite recursion
3998      * becomes possible.
3999      */
4000     if (ctxt->nbErrors != 0)
4001         return (NULL);
4002 
4003     parent = NULL;
4004     cur = def;
4005     while (cur != NULL) {
4006         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
4007                              (cur->type == XML_RELAXNG_TEXT))) ||
4008             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
4009             if (ret == NULL) {
4010                 max = 10;
4011                 ret = (xmlRelaxNGDefinePtr *)
4012                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
4013                 if (ret == NULL) {
4014                     xmlRngPErrMemory(ctxt, "getting element list\n");
4015                     return (NULL);
4016                 }
4017             } else if (max <= len) {
4018 	        xmlRelaxNGDefinePtr *temp;
4019 
4020                 max *= 2;
4021                 temp = xmlRealloc(ret,
4022                                (max + 1) * sizeof(xmlRelaxNGDefinePtr));
4023                 if (temp == NULL) {
4024                     xmlRngPErrMemory(ctxt, "getting element list\n");
4025 		    xmlFree(ret);
4026                     return (NULL);
4027                 }
4028 		ret = temp;
4029             }
4030             ret[len++] = cur;
4031             ret[len] = NULL;
4032         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
4033                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
4034                    (cur->type == XML_RELAXNG_GROUP) ||
4035                    (cur->type == XML_RELAXNG_ONEORMORE) ||
4036                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
4037                    (cur->type == XML_RELAXNG_OPTIONAL) ||
4038                    (cur->type == XML_RELAXNG_PARENTREF) ||
4039                    (cur->type == XML_RELAXNG_REF) ||
4040                    (cur->type == XML_RELAXNG_DEF) ||
4041 		   (cur->type == XML_RELAXNG_EXTERNALREF)) {
4042             /*
4043              * Don't go within elements or attributes or string values.
4044              * Just gather the element top list
4045              */
4046             if (cur->content != NULL) {
4047                 parent = cur;
4048                 cur = cur->content;
4049                 tmp = cur;
4050                 while (tmp != NULL) {
4051                     tmp->parent = parent;
4052                     tmp = tmp->next;
4053                 }
4054                 continue;
4055             }
4056         }
4057         if (cur == def)
4058             break;
4059         if (cur->next != NULL) {
4060             cur = cur->next;
4061             continue;
4062         }
4063         do {
4064             cur = cur->parent;
4065             if (cur == NULL)
4066                 break;
4067             if (cur == def)
4068                 return (ret);
4069             if (cur->next != NULL) {
4070                 cur = cur->next;
4071                 break;
4072             }
4073         } while (cur != NULL);
4074     }
4075     return (ret);
4076 }
4077 
4078 /**
4079  * xmlRelaxNGCheckChoiceDeterminism:
4080  * @ctxt:  a Relax-NG parser context
4081  * @def:  the choice definition
4082  *
4083  * Also used to find indeterministic pattern in choice
4084  */
4085 static void
4086 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
4087                                  xmlRelaxNGDefinePtr def)
4088 {
4089     xmlRelaxNGDefinePtr **list;
4090     xmlRelaxNGDefinePtr cur;
4091     int nbchild = 0, i, j, ret;
4092     int is_nullable = 0;
4093     int is_indeterminist = 0;
4094     xmlHashTablePtr triage = NULL;
4095     int is_triable = 1;
4096 
4097     if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4098         return;
4099 
4100     if (def->dflags & IS_PROCESSED)
4101         return;
4102 
4103     /*
4104      * Don't run that check in case of error. Infinite recursion
4105      * becomes possible.
4106      */
4107     if (ctxt->nbErrors != 0)
4108         return;
4109 
4110     is_nullable = xmlRelaxNGIsNullable(def);
4111 
4112     cur = def->content;
4113     while (cur != NULL) {
4114         nbchild++;
4115         cur = cur->next;
4116     }
4117 
4118     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4119                                               sizeof(xmlRelaxNGDefinePtr
4120                                                      *));
4121     if (list == NULL) {
4122         xmlRngPErrMemory(ctxt, "building choice\n");
4123         return;
4124     }
4125     i = 0;
4126     /*
4127      * a bit strong but safe
4128      */
4129     if (is_nullable == 0) {
4130         triage = xmlHashCreate(10);
4131     } else {
4132         is_triable = 0;
4133     }
4134     cur = def->content;
4135     while (cur != NULL) {
4136         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4137         if ((list[i] == NULL) || (list[i][0] == NULL)) {
4138             is_triable = 0;
4139         } else if (is_triable == 1) {
4140             xmlRelaxNGDefinePtr *tmp;
4141             int res;
4142 
4143             tmp = list[i];
4144             while ((*tmp != NULL) && (is_triable == 1)) {
4145                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4146                     res = xmlHashAddEntry2(triage,
4147                                            BAD_CAST "#text", NULL,
4148                                            (void *) cur);
4149                     if (res != 0)
4150                         is_triable = -1;
4151                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4152                            ((*tmp)->name != NULL)) {
4153                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4154                         res = xmlHashAddEntry2(triage,
4155                                                (*tmp)->name, NULL,
4156                                                (void *) cur);
4157                     else
4158                         res = xmlHashAddEntry2(triage,
4159                                                (*tmp)->name, (*tmp)->ns,
4160                                                (void *) cur);
4161                     if (res != 0)
4162                         is_triable = -1;
4163                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4164                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4165                         res = xmlHashAddEntry2(triage,
4166                                                BAD_CAST "#any", NULL,
4167                                                (void *) cur);
4168                     else
4169                         res = xmlHashAddEntry2(triage,
4170                                                BAD_CAST "#any", (*tmp)->ns,
4171                                                (void *) cur);
4172                     if (res != 0)
4173                         is_triable = -1;
4174                 } else {
4175                     is_triable = -1;
4176                 }
4177                 tmp++;
4178             }
4179         }
4180         i++;
4181         cur = cur->next;
4182     }
4183 
4184     for (i = 0; i < nbchild; i++) {
4185         if (list[i] == NULL)
4186             continue;
4187         for (j = 0; j < i; j++) {
4188             if (list[j] == NULL)
4189                 continue;
4190             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4191             if (ret == 0) {
4192                 is_indeterminist = 1;
4193             }
4194         }
4195     }
4196     for (i = 0; i < nbchild; i++) {
4197         if (list[i] != NULL)
4198             xmlFree(list[i]);
4199     }
4200 
4201     xmlFree(list);
4202     if (is_indeterminist) {
4203         def->dflags |= IS_INDETERMINIST;
4204     }
4205     if (is_triable == 1) {
4206         def->dflags |= IS_TRIABLE;
4207         def->data = triage;
4208     } else if (triage != NULL) {
4209         xmlHashFree(triage, NULL);
4210     }
4211     def->dflags |= IS_PROCESSED;
4212 }
4213 
4214 /**
4215  * xmlRelaxNGCheckGroupAttrs:
4216  * @ctxt:  a Relax-NG parser context
4217  * @def:  the group definition
4218  *
4219  * Detects violations of rule 7.3
4220  */
4221 static void
4222 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4223                           xmlRelaxNGDefinePtr def)
4224 {
4225     xmlRelaxNGDefinePtr **list;
4226     xmlRelaxNGDefinePtr cur;
4227     int nbchild = 0, i, j, ret;
4228 
4229     if ((def == NULL) ||
4230         ((def->type != XML_RELAXNG_GROUP) &&
4231          (def->type != XML_RELAXNG_ELEMENT)))
4232         return;
4233 
4234     if (def->dflags & IS_PROCESSED)
4235         return;
4236 
4237     /*
4238      * Don't run that check in case of error. Infinite recursion
4239      * becomes possible.
4240      */
4241     if (ctxt->nbErrors != 0)
4242         return;
4243 
4244     cur = def->attrs;
4245     while (cur != NULL) {
4246         nbchild++;
4247         cur = cur->next;
4248     }
4249     cur = def->content;
4250     while (cur != NULL) {
4251         nbchild++;
4252         cur = cur->next;
4253     }
4254 
4255     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4256                                               sizeof(xmlRelaxNGDefinePtr
4257                                                      *));
4258     if (list == NULL) {
4259         xmlRngPErrMemory(ctxt, "building group\n");
4260         return;
4261     }
4262     i = 0;
4263     cur = def->attrs;
4264     while (cur != NULL) {
4265         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4266         i++;
4267         cur = cur->next;
4268     }
4269     cur = def->content;
4270     while (cur != NULL) {
4271         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4272         i++;
4273         cur = cur->next;
4274     }
4275 
4276     for (i = 0; i < nbchild; i++) {
4277         if (list[i] == NULL)
4278             continue;
4279         for (j = 0; j < i; j++) {
4280             if (list[j] == NULL)
4281                 continue;
4282             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4283             if (ret == 0) {
4284                 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4285                            "Attributes conflicts in group\n", NULL, NULL);
4286             }
4287         }
4288     }
4289     for (i = 0; i < nbchild; i++) {
4290         if (list[i] != NULL)
4291             xmlFree(list[i]);
4292     }
4293 
4294     xmlFree(list);
4295     def->dflags |= IS_PROCESSED;
4296 }
4297 
4298 /**
4299  * xmlRelaxNGComputeInterleaves:
4300  * @def:  the interleave definition
4301  * @ctxt:  a Relax-NG parser context
4302  * @name:  the definition name
4303  *
4304  * A lot of work for preprocessing interleave definitions
4305  * is potentially needed to get a decent execution speed at runtime
4306  *   - trying to get a total order on the element nodes generated
4307  *     by the interleaves, order the list of interleave definitions
4308  *     following that order.
4309  *   - if <text/> is used to handle mixed content, it is better to
4310  *     flag this in the define and simplify the runtime checking
4311  *     algorithm
4312  */
4313 static void
4314 xmlRelaxNGComputeInterleaves(void *payload, void *data,
4315                              const xmlChar * name ATTRIBUTE_UNUSED)
4316 {
4317     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4318     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4319     xmlRelaxNGDefinePtr cur, *tmp;
4320 
4321     xmlRelaxNGPartitionPtr partitions = NULL;
4322     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4323     xmlRelaxNGInterleaveGroupPtr group;
4324     int i, j, ret, res;
4325     int nbgroups = 0;
4326     int nbchild = 0;
4327     int is_mixed = 0;
4328     int is_determinist = 1;
4329 
4330     /*
4331      * Don't run that check in case of error. Infinite recursion
4332      * becomes possible.
4333      */
4334     if (ctxt->nbErrors != 0)
4335         return;
4336 
4337 #ifdef DEBUG_INTERLEAVE
4338     xmlGenericError(xmlGenericErrorContext,
4339                     "xmlRelaxNGComputeInterleaves(%s)\n", name);
4340 #endif
4341     cur = def->content;
4342     while (cur != NULL) {
4343         nbchild++;
4344         cur = cur->next;
4345     }
4346 
4347 #ifdef DEBUG_INTERLEAVE
4348     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4349 #endif
4350     groups = (xmlRelaxNGInterleaveGroupPtr *)
4351         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4352     if (groups == NULL)
4353         goto error;
4354     cur = def->content;
4355     while (cur != NULL) {
4356         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4357             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4358         if (groups[nbgroups] == NULL)
4359             goto error;
4360         if (cur->type == XML_RELAXNG_TEXT)
4361             is_mixed++;
4362         groups[nbgroups]->rule = cur;
4363         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4364         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4365         nbgroups++;
4366         cur = cur->next;
4367     }
4368 #ifdef DEBUG_INTERLEAVE
4369     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4370 #endif
4371 
4372     /*
4373      * Let's check that all rules makes a partitions according to 7.4
4374      */
4375     partitions = (xmlRelaxNGPartitionPtr)
4376         xmlMalloc(sizeof(xmlRelaxNGPartition));
4377     if (partitions == NULL)
4378         goto error;
4379     memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4380     partitions->nbgroups = nbgroups;
4381     partitions->triage = xmlHashCreate(nbgroups);
4382     for (i = 0; i < nbgroups; i++) {
4383         group = groups[i];
4384         for (j = i + 1; j < nbgroups; j++) {
4385             if (groups[j] == NULL)
4386                 continue;
4387 
4388             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4389                                                 groups[j]->defs);
4390             if (ret == 0) {
4391                 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4392                            "Element or text conflicts in interleave\n",
4393                            NULL, NULL);
4394             }
4395             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4396                                                 groups[j]->attrs);
4397             if (ret == 0) {
4398                 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4399                            "Attributes conflicts in interleave\n", NULL,
4400                            NULL);
4401             }
4402         }
4403         tmp = group->defs;
4404         if ((tmp != NULL) && (*tmp != NULL)) {
4405             while (*tmp != NULL) {
4406                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4407                     res = xmlHashAddEntry2(partitions->triage,
4408                                            BAD_CAST "#text", NULL,
4409                                            (void *) (ptrdiff_t) (i + 1));
4410                     if (res != 0)
4411                         is_determinist = -1;
4412                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4413                            ((*tmp)->name != NULL)) {
4414                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4415                         res = xmlHashAddEntry2(partitions->triage,
4416                                                (*tmp)->name, NULL,
4417                                                (void *) (ptrdiff_t) (i + 1));
4418                     else
4419                         res = xmlHashAddEntry2(partitions->triage,
4420                                                (*tmp)->name, (*tmp)->ns,
4421                                                (void *) (ptrdiff_t) (i + 1));
4422                     if (res != 0)
4423                         is_determinist = -1;
4424                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4425                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4426                         res = xmlHashAddEntry2(partitions->triage,
4427                                                BAD_CAST "#any", NULL,
4428                                                (void *) (ptrdiff_t) (i + 1));
4429                     else
4430                         res = xmlHashAddEntry2(partitions->triage,
4431                                                BAD_CAST "#any", (*tmp)->ns,
4432                                                (void *) (ptrdiff_t) (i + 1));
4433                     if ((*tmp)->nameClass != NULL)
4434                         is_determinist = 2;
4435                     if (res != 0)
4436                         is_determinist = -1;
4437                 } else {
4438                     is_determinist = -1;
4439                 }
4440                 tmp++;
4441             }
4442         } else {
4443             is_determinist = 0;
4444         }
4445     }
4446     partitions->groups = groups;
4447 
4448     /*
4449      * and save the partition list back in the def
4450      */
4451     def->data = partitions;
4452     if (is_mixed != 0)
4453         def->dflags |= IS_MIXED;
4454     if (is_determinist == 1)
4455         partitions->flags = IS_DETERMINIST;
4456     if (is_determinist == 2)
4457         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4458     return;
4459 
4460   error:
4461     xmlRngPErrMemory(ctxt, "in interleave computation\n");
4462     if (groups != NULL) {
4463         for (i = 0; i < nbgroups; i++)
4464             if (groups[i] != NULL) {
4465                 if (groups[i]->defs != NULL)
4466                     xmlFree(groups[i]->defs);
4467                 xmlFree(groups[i]);
4468             }
4469         xmlFree(groups);
4470     }
4471     xmlRelaxNGFreePartition(partitions);
4472 }
4473 
4474 /**
4475  * xmlRelaxNGParseInterleave:
4476  * @ctxt:  a Relax-NG parser context
4477  * @node:  the data node.
4478  *
4479  * parse the content of a RelaxNG interleave node.
4480  *
4481  * Returns the definition pointer or NULL in case of error
4482  */
4483 static xmlRelaxNGDefinePtr
4484 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4485 {
4486     xmlRelaxNGDefinePtr def = NULL;
4487     xmlRelaxNGDefinePtr last = NULL, cur;
4488     xmlNodePtr child;
4489 
4490     def = xmlRelaxNGNewDefine(ctxt, node);
4491     if (def == NULL) {
4492         return (NULL);
4493     }
4494     def->type = XML_RELAXNG_INTERLEAVE;
4495 
4496     if (ctxt->interleaves == NULL)
4497         ctxt->interleaves = xmlHashCreate(10);
4498     if (ctxt->interleaves == NULL) {
4499         xmlRngPErrMemory(ctxt, "create interleaves\n");
4500     } else {
4501         char name[32];
4502 
4503         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4504         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4505             xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4506                        "Failed to add %s to hash table\n",
4507 		       (const xmlChar *) name, NULL);
4508         }
4509     }
4510     child = node->children;
4511     if (child == NULL) {
4512         xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4513                    "Element interleave is empty\n", NULL, NULL);
4514     }
4515     while (child != NULL) {
4516         if (IS_RELAXNG(child, "element")) {
4517             cur = xmlRelaxNGParseElement(ctxt, child);
4518         } else {
4519             cur = xmlRelaxNGParsePattern(ctxt, child);
4520         }
4521         if (cur != NULL) {
4522             cur->parent = def;
4523             if (last == NULL) {
4524                 def->content = last = cur;
4525             } else {
4526                 last->next = cur;
4527                 last = cur;
4528             }
4529         }
4530         child = child->next;
4531     }
4532 
4533     return (def);
4534 }
4535 
4536 /**
4537  * xmlRelaxNGParseInclude:
4538  * @ctxt:  a Relax-NG parser context
4539  * @node:  the include node
4540  *
4541  * Integrate the content of an include node in the current grammar
4542  *
4543  * Returns 0 in case of success or -1 in case of error
4544  */
4545 static int
4546 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4547 {
4548     xmlRelaxNGIncludePtr incl;
4549     xmlNodePtr root;
4550     int ret = 0, tmp;
4551 
4552     incl = node->psvi;
4553     if (incl == NULL) {
4554         xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4555                    "Include node has no data\n", NULL, NULL);
4556         return (-1);
4557     }
4558     root = xmlDocGetRootElement(incl->doc);
4559     if (root == NULL) {
4560         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4561                    NULL, NULL);
4562         return (-1);
4563     }
4564     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4565         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4566                    "Include document root is not a grammar\n", NULL, NULL);
4567         return (-1);
4568     }
4569 
4570     /*
4571      * Merge the definition from both the include and the internal list
4572      */
4573     if (root->children != NULL) {
4574         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4575         if (tmp != 0)
4576             ret = -1;
4577     }
4578     if (node->children != NULL) {
4579         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4580         if (tmp != 0)
4581             ret = -1;
4582     }
4583     return (ret);
4584 }
4585 
4586 /**
4587  * xmlRelaxNGParseDefine:
4588  * @ctxt:  a Relax-NG parser context
4589  * @node:  the define node
4590  *
4591  * parse the content of a RelaxNG define element node.
4592  *
4593  * Returns 0 in case of success or -1 in case of error
4594  */
4595 static int
4596 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4597 {
4598     xmlChar *name;
4599     int ret = 0, tmp;
4600     xmlRelaxNGDefinePtr def;
4601     const xmlChar *olddefine;
4602 
4603     name = xmlGetProp(node, BAD_CAST "name");
4604     if (name == NULL) {
4605         xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4606                    "define has no name\n", NULL, NULL);
4607     } else {
4608         xmlRelaxNGNormExtSpace(name);
4609         if (xmlValidateNCName(name, 0)) {
4610             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4611                        "define name '%s' is not an NCName\n", name, NULL);
4612         }
4613         def = xmlRelaxNGNewDefine(ctxt, node);
4614         if (def == NULL) {
4615             xmlFree(name);
4616             return (-1);
4617         }
4618         def->type = XML_RELAXNG_DEF;
4619         def->name = name;
4620         if (node->children == NULL) {
4621             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4622                        "define has no children\n", NULL, NULL);
4623         } else {
4624             olddefine = ctxt->define;
4625             ctxt->define = name;
4626             def->content =
4627                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4628             ctxt->define = olddefine;
4629         }
4630         if (ctxt->grammar->defs == NULL)
4631             ctxt->grammar->defs = xmlHashCreate(10);
4632         if (ctxt->grammar->defs == NULL) {
4633             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4634                        "Could not create definition hash\n", NULL, NULL);
4635             ret = -1;
4636         } else {
4637             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4638             if (tmp < 0) {
4639                 xmlRelaxNGDefinePtr prev;
4640 
4641                 prev = xmlHashLookup(ctxt->grammar->defs, name);
4642                 if (prev == NULL) {
4643                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4644                                "Internal error on define aggregation of %s\n",
4645                                name, NULL);
4646                     ret = -1;
4647                 } else {
4648                     while (prev->nextHash != NULL)
4649                         prev = prev->nextHash;
4650                     prev->nextHash = def;
4651                 }
4652             }
4653         }
4654     }
4655     return (ret);
4656 }
4657 
4658 /**
4659  * xmlRelaxNGParseImportRef:
4660  * @payload: the parser context
4661  * @data: the current grammar
4662  * @name: the reference name
4663  *
4664  * Import import one references into the current grammar
4665  */
4666 static void
4667 xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) {
4668     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4669     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4670     int tmp;
4671 
4672     def->dflags |= IS_EXTERNAL_REF;
4673 
4674     tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4675     if (tmp < 0) {
4676         xmlRelaxNGDefinePtr prev;
4677 
4678         prev = (xmlRelaxNGDefinePtr)
4679             xmlHashLookup(ctxt->grammar->refs, def->name);
4680         if (prev == NULL) {
4681             if (def->name != NULL) {
4682                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4683                            "Error refs definitions '%s'\n",
4684                            def->name, NULL);
4685             } else {
4686                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4687                            "Error refs definitions\n",
4688                            NULL, NULL);
4689             }
4690         } else {
4691             def->nextHash = prev->nextHash;
4692             prev->nextHash = def;
4693         }
4694     }
4695 }
4696 
4697 /**
4698  * xmlRelaxNGParseImportRefs:
4699  * @ctxt: the parser context
4700  * @grammar: the sub grammar
4701  *
4702  * Import references from the subgrammar into the current grammar
4703  *
4704  * Returns 0 in case of success, -1 in case of failure
4705  */
4706 static int
4707 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4708                           xmlRelaxNGGrammarPtr grammar) {
4709     if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4710         return(-1);
4711     if (grammar->refs == NULL)
4712         return(0);
4713     if (ctxt->grammar->refs == NULL)
4714         ctxt->grammar->refs = xmlHashCreate(10);
4715     if (ctxt->grammar->refs == NULL) {
4716         xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4717                    "Could not create references hash\n", NULL, NULL);
4718         return(-1);
4719     }
4720     xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
4721     return(0);
4722 }
4723 
4724 /**
4725  * xmlRelaxNGProcessExternalRef:
4726  * @ctxt: the parser context
4727  * @node:  the externlRef node
4728  *
4729  * Process and compile an externlRef node
4730  *
4731  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4732  */
4733 static xmlRelaxNGDefinePtr
4734 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4735 {
4736     xmlRelaxNGDocumentPtr docu;
4737     xmlNodePtr root, tmp;
4738     xmlChar *ns;
4739     int newNs = 0, oldflags;
4740     xmlRelaxNGDefinePtr def;
4741 
4742     docu = node->psvi;
4743     if (docu != NULL) {
4744         def = xmlRelaxNGNewDefine(ctxt, node);
4745         if (def == NULL)
4746             return (NULL);
4747         def->type = XML_RELAXNG_EXTERNALREF;
4748 
4749         if (docu->content == NULL) {
4750             /*
4751              * Then do the parsing for good
4752              */
4753             root = xmlDocGetRootElement(docu->doc);
4754             if (root == NULL) {
4755                 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4756                            "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4757                            NULL);
4758                 return (NULL);
4759             }
4760             /*
4761              * ns transmission rules
4762              */
4763             ns = xmlGetProp(root, BAD_CAST "ns");
4764             if (ns == NULL) {
4765                 tmp = node;
4766                 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4767                     ns = xmlGetProp(tmp, BAD_CAST "ns");
4768                     if (ns != NULL) {
4769                         break;
4770                     }
4771                     tmp = tmp->parent;
4772                 }
4773                 if (ns != NULL) {
4774                     xmlSetProp(root, BAD_CAST "ns", ns);
4775                     newNs = 1;
4776                     xmlFree(ns);
4777                 }
4778             } else {
4779                 xmlFree(ns);
4780             }
4781 
4782             /*
4783              * Parsing to get a precompiled schemas.
4784              */
4785             oldflags = ctxt->flags;
4786             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4787             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4788             ctxt->flags = oldflags;
4789             if ((docu->schema != NULL) &&
4790                 (docu->schema->topgrammar != NULL)) {
4791                 docu->content = docu->schema->topgrammar->start;
4792                 if (docu->schema->topgrammar->refs)
4793                     xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
4794             }
4795 
4796             /*
4797              * the externalRef may be reused in a different ns context
4798              */
4799             if (newNs == 1) {
4800                 xmlUnsetProp(root, BAD_CAST "ns");
4801             }
4802         }
4803         def->content = docu->content;
4804     } else {
4805         def = NULL;
4806     }
4807     return (def);
4808 }
4809 
4810 /**
4811  * xmlRelaxNGParsePattern:
4812  * @ctxt:  a Relax-NG parser context
4813  * @node:  the pattern node.
4814  *
4815  * parse the content of a RelaxNG pattern node.
4816  *
4817  * Returns the definition pointer or NULL in case of error or if no
4818  *     pattern is generated.
4819  */
4820 static xmlRelaxNGDefinePtr
4821 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4822 {
4823     xmlRelaxNGDefinePtr def = NULL;
4824 
4825     if (node == NULL) {
4826         return (NULL);
4827     }
4828     if (IS_RELAXNG(node, "element")) {
4829         def = xmlRelaxNGParseElement(ctxt, node);
4830     } else if (IS_RELAXNG(node, "attribute")) {
4831         def = xmlRelaxNGParseAttribute(ctxt, node);
4832     } else if (IS_RELAXNG(node, "empty")) {
4833         def = xmlRelaxNGNewDefine(ctxt, node);
4834         if (def == NULL)
4835             return (NULL);
4836         def->type = XML_RELAXNG_EMPTY;
4837         if (node->children != NULL) {
4838             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4839                        "empty: had a child node\n", NULL, NULL);
4840         }
4841     } else if (IS_RELAXNG(node, "text")) {
4842         def = xmlRelaxNGNewDefine(ctxt, node);
4843         if (def == NULL)
4844             return (NULL);
4845         def->type = XML_RELAXNG_TEXT;
4846         if (node->children != NULL) {
4847             xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4848                        "text: had a child node\n", NULL, NULL);
4849         }
4850     } else if (IS_RELAXNG(node, "zeroOrMore")) {
4851         def = xmlRelaxNGNewDefine(ctxt, node);
4852         if (def == NULL)
4853             return (NULL);
4854         def->type = XML_RELAXNG_ZEROORMORE;
4855         if (node->children == NULL) {
4856             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4857                        "Element %s is empty\n", node->name, NULL);
4858         } else {
4859             def->content =
4860                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4861         }
4862     } else if (IS_RELAXNG(node, "oneOrMore")) {
4863         def = xmlRelaxNGNewDefine(ctxt, node);
4864         if (def == NULL)
4865             return (NULL);
4866         def->type = XML_RELAXNG_ONEORMORE;
4867         if (node->children == NULL) {
4868             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4869                        "Element %s is empty\n", node->name, NULL);
4870         } else {
4871             def->content =
4872                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4873         }
4874     } else if (IS_RELAXNG(node, "optional")) {
4875         def = xmlRelaxNGNewDefine(ctxt, node);
4876         if (def == NULL)
4877             return (NULL);
4878         def->type = XML_RELAXNG_OPTIONAL;
4879         if (node->children == NULL) {
4880             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4881                        "Element %s is empty\n", node->name, NULL);
4882         } else {
4883             def->content =
4884                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4885         }
4886     } else if (IS_RELAXNG(node, "choice")) {
4887         def = xmlRelaxNGNewDefine(ctxt, node);
4888         if (def == NULL)
4889             return (NULL);
4890         def->type = XML_RELAXNG_CHOICE;
4891         if (node->children == NULL) {
4892             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4893                        "Element %s is empty\n", node->name, NULL);
4894         } else {
4895             def->content =
4896                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4897         }
4898     } else if (IS_RELAXNG(node, "group")) {
4899         def = xmlRelaxNGNewDefine(ctxt, node);
4900         if (def == NULL)
4901             return (NULL);
4902         def->type = XML_RELAXNG_GROUP;
4903         if (node->children == NULL) {
4904             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4905                        "Element %s is empty\n", node->name, NULL);
4906         } else {
4907             def->content =
4908                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4909         }
4910     } else if (IS_RELAXNG(node, "ref")) {
4911         def = xmlRelaxNGNewDefine(ctxt, node);
4912         if (def == NULL)
4913             return (NULL);
4914         def->type = XML_RELAXNG_REF;
4915         def->name = xmlGetProp(node, BAD_CAST "name");
4916         if (def->name == NULL) {
4917             xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4918                        NULL, NULL);
4919         } else {
4920             xmlRelaxNGNormExtSpace(def->name);
4921             if (xmlValidateNCName(def->name, 0)) {
4922                 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4923                            "ref name '%s' is not an NCName\n", def->name,
4924                            NULL);
4925             }
4926         }
4927         if (node->children != NULL) {
4928             xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4929                        NULL, NULL);
4930         }
4931         if (ctxt->grammar->refs == NULL)
4932             ctxt->grammar->refs = xmlHashCreate(10);
4933         if (ctxt->grammar->refs == NULL) {
4934             xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4935                        "Could not create references hash\n", NULL, NULL);
4936             def = NULL;
4937         } else {
4938             int tmp;
4939 
4940             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4941             if (tmp < 0) {
4942                 xmlRelaxNGDefinePtr prev;
4943 
4944                 prev = (xmlRelaxNGDefinePtr)
4945                     xmlHashLookup(ctxt->grammar->refs, def->name);
4946                 if (prev == NULL) {
4947                     if (def->name != NULL) {
4948 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4949 				   "Error refs definitions '%s'\n",
4950 				   def->name, NULL);
4951                     } else {
4952 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4953 				   "Error refs definitions\n",
4954 				   NULL, NULL);
4955                     }
4956                     def = NULL;
4957                 } else {
4958                     def->nextHash = prev->nextHash;
4959                     prev->nextHash = def;
4960                 }
4961             }
4962         }
4963     } else if (IS_RELAXNG(node, "data")) {
4964         def = xmlRelaxNGParseData(ctxt, node);
4965     } else if (IS_RELAXNG(node, "value")) {
4966         def = xmlRelaxNGParseValue(ctxt, node);
4967     } else if (IS_RELAXNG(node, "list")) {
4968         def = xmlRelaxNGNewDefine(ctxt, node);
4969         if (def == NULL)
4970             return (NULL);
4971         def->type = XML_RELAXNG_LIST;
4972         if (node->children == NULL) {
4973             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4974                        "Element %s is empty\n", node->name, NULL);
4975         } else {
4976             def->content =
4977                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4978         }
4979     } else if (IS_RELAXNG(node, "interleave")) {
4980         def = xmlRelaxNGParseInterleave(ctxt, node);
4981     } else if (IS_RELAXNG(node, "externalRef")) {
4982         def = xmlRelaxNGProcessExternalRef(ctxt, node);
4983     } else if (IS_RELAXNG(node, "notAllowed")) {
4984         def = xmlRelaxNGNewDefine(ctxt, node);
4985         if (def == NULL)
4986             return (NULL);
4987         def->type = XML_RELAXNG_NOT_ALLOWED;
4988         if (node->children != NULL) {
4989             xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4990                        "xmlRelaxNGParse: notAllowed element is not empty\n",
4991                        NULL, NULL);
4992         }
4993     } else if (IS_RELAXNG(node, "grammar")) {
4994         xmlRelaxNGGrammarPtr grammar, old;
4995         xmlRelaxNGGrammarPtr oldparent;
4996 
4997 #ifdef DEBUG_GRAMMAR
4998         xmlGenericError(xmlGenericErrorContext,
4999                         "Found <grammar> pattern\n");
5000 #endif
5001 
5002         oldparent = ctxt->parentgrammar;
5003         old = ctxt->grammar;
5004         ctxt->parentgrammar = old;
5005         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5006         if (old != NULL) {
5007             ctxt->grammar = old;
5008             ctxt->parentgrammar = oldparent;
5009 #if 0
5010             if (grammar != NULL) {
5011                 grammar->next = old->next;
5012                 old->next = grammar;
5013             }
5014 #endif
5015         }
5016         if (grammar != NULL)
5017             def = grammar->start;
5018         else
5019             def = NULL;
5020     } else if (IS_RELAXNG(node, "parentRef")) {
5021         if (ctxt->parentgrammar == NULL) {
5022             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
5023                        "Use of parentRef without a parent grammar\n", NULL,
5024                        NULL);
5025             return (NULL);
5026         }
5027         def = xmlRelaxNGNewDefine(ctxt, node);
5028         if (def == NULL)
5029             return (NULL);
5030         def->type = XML_RELAXNG_PARENTREF;
5031         def->name = xmlGetProp(node, BAD_CAST "name");
5032         if (def->name == NULL) {
5033             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
5034                        "parentRef has no name\n", NULL, NULL);
5035         } else {
5036             xmlRelaxNGNormExtSpace(def->name);
5037             if (xmlValidateNCName(def->name, 0)) {
5038                 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
5039                            "parentRef name '%s' is not an NCName\n",
5040                            def->name, NULL);
5041             }
5042         }
5043         if (node->children != NULL) {
5044             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
5045                        "parentRef is not empty\n", NULL, NULL);
5046         }
5047         if (ctxt->parentgrammar->refs == NULL)
5048             ctxt->parentgrammar->refs = xmlHashCreate(10);
5049         if (ctxt->parentgrammar->refs == NULL) {
5050             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5051                        "Could not create references hash\n", NULL, NULL);
5052             def = NULL;
5053         } else if (def->name != NULL) {
5054             int tmp;
5055 
5056             tmp =
5057                 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
5058             if (tmp < 0) {
5059                 xmlRelaxNGDefinePtr prev;
5060 
5061                 prev = (xmlRelaxNGDefinePtr)
5062                     xmlHashLookup(ctxt->parentgrammar->refs, def->name);
5063                 if (prev == NULL) {
5064                     xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5065                                "Internal error parentRef definitions '%s'\n",
5066                                def->name, NULL);
5067                     def = NULL;
5068                 } else {
5069                     def->nextHash = prev->nextHash;
5070                     prev->nextHash = def;
5071                 }
5072             }
5073         }
5074     } else if (IS_RELAXNG(node, "mixed")) {
5075         if (node->children == NULL) {
5076             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
5077                        NULL, NULL);
5078             def = NULL;
5079         } else {
5080             def = xmlRelaxNGParseInterleave(ctxt, node);
5081             if (def != NULL) {
5082                 xmlRelaxNGDefinePtr tmp;
5083 
5084                 if ((def->content != NULL) && (def->content->next != NULL)) {
5085                     tmp = xmlRelaxNGNewDefine(ctxt, node);
5086                     if (tmp != NULL) {
5087                         tmp->type = XML_RELAXNG_GROUP;
5088                         tmp->content = def->content;
5089                         def->content = tmp;
5090                     }
5091                 }
5092 
5093                 tmp = xmlRelaxNGNewDefine(ctxt, node);
5094                 if (tmp == NULL)
5095                     return (def);
5096                 tmp->type = XML_RELAXNG_TEXT;
5097                 tmp->next = def->content;
5098                 def->content = tmp;
5099             }
5100         }
5101     } else {
5102         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5103                    "Unexpected node %s is not a pattern\n", node->name,
5104                    NULL);
5105         def = NULL;
5106     }
5107     return (def);
5108 }
5109 
5110 /**
5111  * xmlRelaxNGParseAttribute:
5112  * @ctxt:  a Relax-NG parser context
5113  * @node:  the element node
5114  *
5115  * parse the content of a RelaxNG attribute node.
5116  *
5117  * Returns the definition pointer or NULL in case of error.
5118  */
5119 static xmlRelaxNGDefinePtr
5120 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5121 {
5122     xmlRelaxNGDefinePtr ret, cur;
5123     xmlNodePtr child;
5124     int old_flags;
5125 
5126     ret = xmlRelaxNGNewDefine(ctxt, node);
5127     if (ret == NULL)
5128         return (NULL);
5129     ret->type = XML_RELAXNG_ATTRIBUTE;
5130     ret->parent = ctxt->def;
5131     child = node->children;
5132     if (child == NULL) {
5133         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5134                    "xmlRelaxNGParseattribute: attribute has no children\n",
5135                    NULL, NULL);
5136         return (ret);
5137     }
5138     old_flags = ctxt->flags;
5139     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
5140     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5141     if (cur != NULL)
5142         child = child->next;
5143 
5144     if (child != NULL) {
5145         cur = xmlRelaxNGParsePattern(ctxt, child);
5146         if (cur != NULL) {
5147             switch (cur->type) {
5148                 case XML_RELAXNG_EMPTY:
5149                 case XML_RELAXNG_NOT_ALLOWED:
5150                 case XML_RELAXNG_TEXT:
5151                 case XML_RELAXNG_ELEMENT:
5152                 case XML_RELAXNG_DATATYPE:
5153                 case XML_RELAXNG_VALUE:
5154                 case XML_RELAXNG_LIST:
5155                 case XML_RELAXNG_REF:
5156                 case XML_RELAXNG_PARENTREF:
5157                 case XML_RELAXNG_EXTERNALREF:
5158                 case XML_RELAXNG_DEF:
5159                 case XML_RELAXNG_ONEORMORE:
5160                 case XML_RELAXNG_ZEROORMORE:
5161                 case XML_RELAXNG_OPTIONAL:
5162                 case XML_RELAXNG_CHOICE:
5163                 case XML_RELAXNG_GROUP:
5164                 case XML_RELAXNG_INTERLEAVE:
5165                 case XML_RELAXNG_ATTRIBUTE:
5166                     ret->content = cur;
5167                     cur->parent = ret;
5168                     break;
5169                 case XML_RELAXNG_START:
5170                 case XML_RELAXNG_PARAM:
5171                 case XML_RELAXNG_EXCEPT:
5172                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5173                                "attribute has invalid content\n", NULL,
5174                                NULL);
5175                     break;
5176                 case XML_RELAXNG_NOOP:
5177                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5178                                "RNG Internal error, noop found in attribute\n",
5179                                NULL, NULL);
5180                     break;
5181             }
5182         }
5183         child = child->next;
5184     }
5185     if (child != NULL) {
5186         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5187                    "attribute has multiple children\n", NULL, NULL);
5188     }
5189     ctxt->flags = old_flags;
5190     return (ret);
5191 }
5192 
5193 /**
5194  * xmlRelaxNGParseExceptNameClass:
5195  * @ctxt:  a Relax-NG parser context
5196  * @node:  the except node
5197  * @attr:  1 if within an attribute, 0 if within an element
5198  *
5199  * parse the content of a RelaxNG nameClass node.
5200  *
5201  * Returns the definition pointer or NULL in case of error.
5202  */
5203 static xmlRelaxNGDefinePtr
5204 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
5205                                xmlNodePtr node, int attr)
5206 {
5207     xmlRelaxNGDefinePtr ret, cur, last = NULL;
5208     xmlNodePtr child;
5209 
5210     if (!IS_RELAXNG(node, "except")) {
5211         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5212                    "Expecting an except node\n", NULL, NULL);
5213         return (NULL);
5214     }
5215     if (node->next != NULL) {
5216         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5217                    "exceptNameClass allows only a single except node\n",
5218                    NULL, NULL);
5219     }
5220     if (node->children == NULL) {
5221         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5222                    NULL, NULL);
5223         return (NULL);
5224     }
5225 
5226     ret = xmlRelaxNGNewDefine(ctxt, node);
5227     if (ret == NULL)
5228         return (NULL);
5229     ret->type = XML_RELAXNG_EXCEPT;
5230     child = node->children;
5231     while (child != NULL) {
5232         cur = xmlRelaxNGNewDefine(ctxt, child);
5233         if (cur == NULL)
5234             break;
5235         if (attr)
5236             cur->type = XML_RELAXNG_ATTRIBUTE;
5237         else
5238             cur->type = XML_RELAXNG_ELEMENT;
5239 
5240         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5241             if (last == NULL) {
5242                 ret->content = cur;
5243             } else {
5244                 last->next = cur;
5245             }
5246             last = cur;
5247         }
5248         child = child->next;
5249     }
5250 
5251     return (ret);
5252 }
5253 
5254 /**
5255  * xmlRelaxNGParseNameClass:
5256  * @ctxt:  a Relax-NG parser context
5257  * @node:  the nameClass node
5258  * @def:  the current definition
5259  *
5260  * parse the content of a RelaxNG nameClass node.
5261  *
5262  * Returns the definition pointer or NULL in case of error.
5263  */
5264 static xmlRelaxNGDefinePtr
5265 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5266                          xmlRelaxNGDefinePtr def)
5267 {
5268     xmlRelaxNGDefinePtr ret, tmp;
5269     xmlChar *val;
5270 
5271     ret = def;
5272     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5273         (IS_RELAXNG(node, "nsName"))) {
5274         if ((def->type != XML_RELAXNG_ELEMENT) &&
5275             (def->type != XML_RELAXNG_ATTRIBUTE)) {
5276             ret = xmlRelaxNGNewDefine(ctxt, node);
5277             if (ret == NULL)
5278                 return (NULL);
5279             ret->parent = def;
5280             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5281                 ret->type = XML_RELAXNG_ATTRIBUTE;
5282             else
5283                 ret->type = XML_RELAXNG_ELEMENT;
5284         }
5285     }
5286     if (IS_RELAXNG(node, "name")) {
5287         val = xmlNodeGetContent(node);
5288         xmlRelaxNGNormExtSpace(val);
5289         if (xmlValidateNCName(val, 0)) {
5290 	    if (node->parent != NULL)
5291 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5292 			   "Element %s name '%s' is not an NCName\n",
5293 			   node->parent->name, val);
5294 	    else
5295 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5296 			   "name '%s' is not an NCName\n",
5297 			   val, NULL);
5298         }
5299         ret->name = val;
5300         val = xmlGetProp(node, BAD_CAST "ns");
5301         ret->ns = val;
5302         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5303             (val != NULL) &&
5304             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5305 	    xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5306                         "Attribute with namespace '%s' is not allowed\n",
5307                         val, NULL);
5308         }
5309         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5310             (val != NULL) &&
5311             (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5312 	    xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5313                        "Attribute with QName 'xmlns' is not allowed\n",
5314                        val, NULL);
5315         }
5316     } else if (IS_RELAXNG(node, "anyName")) {
5317         ret->name = NULL;
5318         ret->ns = NULL;
5319         if (node->children != NULL) {
5320             ret->nameClass =
5321                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5322                                                (def->type ==
5323                                                 XML_RELAXNG_ATTRIBUTE));
5324         }
5325     } else if (IS_RELAXNG(node, "nsName")) {
5326         ret->name = NULL;
5327         ret->ns = xmlGetProp(node, BAD_CAST "ns");
5328         if (ret->ns == NULL) {
5329             xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5330                        "nsName has no ns attribute\n", NULL, NULL);
5331         }
5332         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5333             (ret->ns != NULL) &&
5334             (xmlStrEqual
5335              (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5336             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5337                        "Attribute with namespace '%s' is not allowed\n",
5338                        ret->ns, NULL);
5339         }
5340         if (node->children != NULL) {
5341             ret->nameClass =
5342                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5343                                                (def->type ==
5344                                                 XML_RELAXNG_ATTRIBUTE));
5345         }
5346     } else if (IS_RELAXNG(node, "choice")) {
5347         xmlNodePtr child;
5348         xmlRelaxNGDefinePtr last = NULL;
5349 
5350         ret = xmlRelaxNGNewDefine(ctxt, node);
5351         if (ret == NULL)
5352             return (NULL);
5353         ret->parent = def;
5354         ret->type = XML_RELAXNG_CHOICE;
5355 
5356         if (node->children == NULL) {
5357             xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5358                        "Element choice is empty\n", NULL, NULL);
5359         } else {
5360 
5361             child = node->children;
5362             while (child != NULL) {
5363                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5364                 if (tmp != NULL) {
5365                     if (last == NULL) {
5366                         last = ret->nameClass = tmp;
5367                     } else {
5368                         last->next = tmp;
5369                         last = tmp;
5370                     }
5371                 }
5372                 child = child->next;
5373             }
5374         }
5375     } else {
5376         xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5377                    "expecting name, anyName, nsName or choice : got %s\n",
5378                    (node == NULL ? (const xmlChar *) "nothing" : node->name),
5379 		   NULL);
5380         return (NULL);
5381     }
5382     if (ret != def) {
5383         if (def->nameClass == NULL) {
5384             def->nameClass = ret;
5385         } else {
5386             tmp = def->nameClass;
5387             while (tmp->next != NULL) {
5388                 tmp = tmp->next;
5389             }
5390             tmp->next = ret;
5391         }
5392     }
5393     return (ret);
5394 }
5395 
5396 /**
5397  * xmlRelaxNGParseElement:
5398  * @ctxt:  a Relax-NG parser context
5399  * @node:  the element node
5400  *
5401  * parse the content of a RelaxNG element node.
5402  *
5403  * Returns the definition pointer or NULL in case of error.
5404  */
5405 static xmlRelaxNGDefinePtr
5406 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5407 {
5408     xmlRelaxNGDefinePtr ret, cur, last;
5409     xmlNodePtr child;
5410     const xmlChar *olddefine;
5411 
5412     ret = xmlRelaxNGNewDefine(ctxt, node);
5413     if (ret == NULL)
5414         return (NULL);
5415     ret->type = XML_RELAXNG_ELEMENT;
5416     ret->parent = ctxt->def;
5417     child = node->children;
5418     if (child == NULL) {
5419         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5420                    "xmlRelaxNGParseElement: element has no children\n",
5421                    NULL, NULL);
5422         return (ret);
5423     }
5424     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5425     if (cur != NULL)
5426         child = child->next;
5427 
5428     if (child == NULL) {
5429         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5430                    "xmlRelaxNGParseElement: element has no content\n",
5431                    NULL, NULL);
5432         return (ret);
5433     }
5434     olddefine = ctxt->define;
5435     ctxt->define = NULL;
5436     last = NULL;
5437     while (child != NULL) {
5438         cur = xmlRelaxNGParsePattern(ctxt, child);
5439         if (cur != NULL) {
5440             cur->parent = ret;
5441             switch (cur->type) {
5442                 case XML_RELAXNG_EMPTY:
5443                 case XML_RELAXNG_NOT_ALLOWED:
5444                 case XML_RELAXNG_TEXT:
5445                 case XML_RELAXNG_ELEMENT:
5446                 case XML_RELAXNG_DATATYPE:
5447                 case XML_RELAXNG_VALUE:
5448                 case XML_RELAXNG_LIST:
5449                 case XML_RELAXNG_REF:
5450                 case XML_RELAXNG_PARENTREF:
5451                 case XML_RELAXNG_EXTERNALREF:
5452                 case XML_RELAXNG_DEF:
5453                 case XML_RELAXNG_ZEROORMORE:
5454                 case XML_RELAXNG_ONEORMORE:
5455                 case XML_RELAXNG_OPTIONAL:
5456                 case XML_RELAXNG_CHOICE:
5457                 case XML_RELAXNG_GROUP:
5458                 case XML_RELAXNG_INTERLEAVE:
5459                     if (last == NULL) {
5460                         ret->content = last = cur;
5461                     } else {
5462                         if ((last->type == XML_RELAXNG_ELEMENT) &&
5463                             (ret->content == last)) {
5464                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
5465                             if (ret->content != NULL) {
5466                                 ret->content->type = XML_RELAXNG_GROUP;
5467                                 ret->content->content = last;
5468                             } else {
5469                                 ret->content = last;
5470                             }
5471                         }
5472                         last->next = cur;
5473                         last = cur;
5474                     }
5475                     break;
5476                 case XML_RELAXNG_ATTRIBUTE:
5477                     cur->next = ret->attrs;
5478                     ret->attrs = cur;
5479                     break;
5480                 case XML_RELAXNG_START:
5481                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5482                                "RNG Internal error, start found in element\n",
5483                                NULL, NULL);
5484                     break;
5485                 case XML_RELAXNG_PARAM:
5486                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5487                                "RNG Internal error, param found in element\n",
5488                                NULL, NULL);
5489                     break;
5490                 case XML_RELAXNG_EXCEPT:
5491                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5492                                "RNG Internal error, except found in element\n",
5493                                NULL, NULL);
5494                     break;
5495                 case XML_RELAXNG_NOOP:
5496                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5497                                "RNG Internal error, noop found in element\n",
5498                                NULL, NULL);
5499                     break;
5500             }
5501         }
5502         child = child->next;
5503     }
5504     ctxt->define = olddefine;
5505     return (ret);
5506 }
5507 
5508 /**
5509  * xmlRelaxNGParsePatterns:
5510  * @ctxt:  a Relax-NG parser context
5511  * @nodes:  list of nodes
5512  * @group:  use an implicit <group> for elements
5513  *
5514  * parse the content of a RelaxNG start node.
5515  *
5516  * Returns the definition pointer or NULL in case of error.
5517  */
5518 static xmlRelaxNGDefinePtr
5519 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5520                         int group)
5521 {
5522     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5523 
5524     parent = ctxt->def;
5525     while (nodes != NULL) {
5526         if (IS_RELAXNG(nodes, "element")) {
5527             cur = xmlRelaxNGParseElement(ctxt, nodes);
5528             if (def == NULL) {
5529                 def = last = cur;
5530             } else {
5531                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5532                     (def == last)) {
5533                     def = xmlRelaxNGNewDefine(ctxt, nodes);
5534                     def->type = XML_RELAXNG_GROUP;
5535                     def->content = last;
5536                 }
5537                 last->next = cur;
5538                 last = cur;
5539             }
5540             cur->parent = parent;
5541         } else {
5542             cur = xmlRelaxNGParsePattern(ctxt, nodes);
5543             if (cur != NULL) {
5544                 if (def == NULL) {
5545                     def = last = cur;
5546                 } else {
5547                     last->next = cur;
5548                     last = cur;
5549                 }
5550             }
5551         }
5552         nodes = nodes->next;
5553     }
5554     return (def);
5555 }
5556 
5557 /**
5558  * xmlRelaxNGParseStart:
5559  * @ctxt:  a Relax-NG parser context
5560  * @nodes:  start children nodes
5561  *
5562  * parse the content of a RelaxNG start node.
5563  *
5564  * Returns 0 in case of success, -1 in case of error
5565  */
5566 static int
5567 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5568 {
5569     int ret = 0;
5570     xmlRelaxNGDefinePtr def = NULL, last;
5571 
5572     if (nodes == NULL) {
5573         xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5574                    NULL, NULL);
5575         return (-1);
5576     }
5577     if (IS_RELAXNG(nodes, "empty")) {
5578         def = xmlRelaxNGNewDefine(ctxt, nodes);
5579         if (def == NULL)
5580             return (-1);
5581         def->type = XML_RELAXNG_EMPTY;
5582         if (nodes->children != NULL) {
5583             xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5584                        "element empty is not empty\n", NULL, NULL);
5585         }
5586     } else if (IS_RELAXNG(nodes, "notAllowed")) {
5587         def = xmlRelaxNGNewDefine(ctxt, nodes);
5588         if (def == NULL)
5589             return (-1);
5590         def->type = XML_RELAXNG_NOT_ALLOWED;
5591         if (nodes->children != NULL) {
5592             xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5593                        "element notAllowed is not empty\n", NULL, NULL);
5594         }
5595     } else {
5596         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5597     }
5598     if (ctxt->grammar->start != NULL) {
5599         last = ctxt->grammar->start;
5600         while (last->next != NULL)
5601             last = last->next;
5602         last->next = def;
5603     } else {
5604         ctxt->grammar->start = def;
5605     }
5606     nodes = nodes->next;
5607     if (nodes != NULL) {
5608         xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5609                    "start more than one children\n", NULL, NULL);
5610         return (-1);
5611     }
5612     return (ret);
5613 }
5614 
5615 /**
5616  * xmlRelaxNGParseGrammarContent:
5617  * @ctxt:  a Relax-NG parser context
5618  * @nodes:  grammar children nodes
5619  *
5620  * parse the content of a RelaxNG grammar node.
5621  *
5622  * Returns 0 in case of success, -1 in case of error
5623  */
5624 static int
5625 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5626                               xmlNodePtr nodes)
5627 {
5628     int ret = 0, tmp;
5629 
5630     if (nodes == NULL) {
5631         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5632                    "grammar has no children\n", NULL, NULL);
5633         return (-1);
5634     }
5635     while (nodes != NULL) {
5636         if (IS_RELAXNG(nodes, "start")) {
5637             if (nodes->children == NULL) {
5638                 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5639                            "start has no children\n", NULL, NULL);
5640             } else {
5641                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5642                 if (tmp != 0)
5643                     ret = -1;
5644             }
5645         } else if (IS_RELAXNG(nodes, "define")) {
5646             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5647             if (tmp != 0)
5648                 ret = -1;
5649         } else if (IS_RELAXNG(nodes, "include")) {
5650             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5651             if (tmp != 0)
5652                 ret = -1;
5653         } else {
5654             xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5655                        "grammar has unexpected child %s\n", nodes->name,
5656                        NULL);
5657             ret = -1;
5658         }
5659         nodes = nodes->next;
5660     }
5661     return (ret);
5662 }
5663 
5664 /**
5665  * xmlRelaxNGCheckReference:
5666  * @ref:  the ref
5667  * @ctxt:  a Relax-NG parser context
5668  * @name:  the name associated to the defines
5669  *
5670  * Applies the 4.17. combine attribute rule for all the define
5671  * element of a given grammar using the same name.
5672  */
5673 static void
5674 xmlRelaxNGCheckReference(void *payload, void *data, const xmlChar * name)
5675 {
5676     xmlRelaxNGDefinePtr ref = (xmlRelaxNGDefinePtr) payload;
5677     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5678     xmlRelaxNGGrammarPtr grammar;
5679     xmlRelaxNGDefinePtr def, cur;
5680 
5681     /*
5682      * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5683      */
5684     if (ref->dflags & IS_EXTERNAL_REF)
5685         return;
5686 
5687     grammar = ctxt->grammar;
5688     if (grammar == NULL) {
5689         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5690                    "Internal error: no grammar in CheckReference %s\n",
5691                    name, NULL);
5692         return;
5693     }
5694     if (ref->content != NULL) {
5695         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5696                    "Internal error: reference has content in CheckReference %s\n",
5697                    name, NULL);
5698         return;
5699     }
5700     if (grammar->defs != NULL) {
5701         def = xmlHashLookup(grammar->defs, name);
5702         if (def != NULL) {
5703             cur = ref;
5704             while (cur != NULL) {
5705                 cur->content = def;
5706                 cur = cur->nextHash;
5707             }
5708         } else {
5709             xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5710                        "Reference %s has no matching definition\n", name,
5711                        NULL);
5712         }
5713     } else {
5714         xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5715                    "Reference %s has no matching definition\n", name,
5716                    NULL);
5717     }
5718 }
5719 
5720 /**
5721  * xmlRelaxNGCheckCombine:
5722  * @define:  the define(s) list
5723  * @ctxt:  a Relax-NG parser context
5724  * @name:  the name associated to the defines
5725  *
5726  * Applies the 4.17. combine attribute rule for all the define
5727  * element of a given grammar using the same name.
5728  */
5729 static void
5730 xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name)
5731 {
5732     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) payload;
5733     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5734     xmlChar *combine;
5735     int choiceOrInterleave = -1;
5736     int missing = 0;
5737     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5738 
5739     if (define->nextHash == NULL)
5740         return;
5741     cur = define;
5742     while (cur != NULL) {
5743         combine = xmlGetProp(cur->node, BAD_CAST "combine");
5744         if (combine != NULL) {
5745             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5746                 if (choiceOrInterleave == -1)
5747                     choiceOrInterleave = 1;
5748                 else if (choiceOrInterleave == 0) {
5749                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5750                                "Defines for %s use both 'choice' and 'interleave'\n",
5751                                name, NULL);
5752                 }
5753             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5754                 if (choiceOrInterleave == -1)
5755                     choiceOrInterleave = 0;
5756                 else if (choiceOrInterleave == 1) {
5757                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5758                                "Defines for %s use both 'choice' and 'interleave'\n",
5759                                name, NULL);
5760                 }
5761             } else {
5762                 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5763                            "Defines for %s use unknown combine value '%s''\n",
5764                            name, combine);
5765             }
5766             xmlFree(combine);
5767         } else {
5768             if (missing == 0)
5769                 missing = 1;
5770             else {
5771                 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5772                            "Some defines for %s needs the combine attribute\n",
5773                            name, NULL);
5774             }
5775         }
5776 
5777         cur = cur->nextHash;
5778     }
5779 #ifdef DEBUG
5780     xmlGenericError(xmlGenericErrorContext,
5781                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5782                     name, choiceOrInterleave);
5783 #endif
5784     if (choiceOrInterleave == -1)
5785         choiceOrInterleave = 0;
5786     cur = xmlRelaxNGNewDefine(ctxt, define->node);
5787     if (cur == NULL)
5788         return;
5789     if (choiceOrInterleave == 0)
5790         cur->type = XML_RELAXNG_INTERLEAVE;
5791     else
5792         cur->type = XML_RELAXNG_CHOICE;
5793     tmp = define;
5794     last = NULL;
5795     while (tmp != NULL) {
5796         if (tmp->content != NULL) {
5797             if (tmp->content->next != NULL) {
5798                 /*
5799                  * we need first to create a wrapper.
5800                  */
5801                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5802                 if (tmp2 == NULL)
5803                     break;
5804                 tmp2->type = XML_RELAXNG_GROUP;
5805                 tmp2->content = tmp->content;
5806             } else {
5807                 tmp2 = tmp->content;
5808             }
5809             if (last == NULL) {
5810                 cur->content = tmp2;
5811             } else {
5812                 last->next = tmp2;
5813             }
5814             last = tmp2;
5815         }
5816         tmp->content = cur;
5817         tmp = tmp->nextHash;
5818     }
5819     define->content = cur;
5820     if (choiceOrInterleave == 0) {
5821         if (ctxt->interleaves == NULL)
5822             ctxt->interleaves = xmlHashCreate(10);
5823         if (ctxt->interleaves == NULL) {
5824             xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5825                        "Failed to create interleaves hash table\n", NULL,
5826                        NULL);
5827         } else {
5828             char tmpname[32];
5829 
5830             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5831             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5832                 0) {
5833                 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5834                            "Failed to add %s to hash table\n",
5835 			   (const xmlChar *) tmpname, NULL);
5836             }
5837         }
5838     }
5839 }
5840 
5841 /**
5842  * xmlRelaxNGCombineStart:
5843  * @ctxt:  a Relax-NG parser context
5844  * @grammar:  the grammar
5845  *
5846  * Applies the 4.17. combine rule for all the start
5847  * element of a given grammar.
5848  */
5849 static void
5850 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5851                        xmlRelaxNGGrammarPtr grammar)
5852 {
5853     xmlRelaxNGDefinePtr starts;
5854     xmlChar *combine;
5855     int choiceOrInterleave = -1;
5856     int missing = 0;
5857     xmlRelaxNGDefinePtr cur;
5858 
5859     starts = grammar->start;
5860     if ((starts == NULL) || (starts->next == NULL))
5861         return;
5862     cur = starts;
5863     while (cur != NULL) {
5864         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5865             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5866             combine = NULL;
5867             xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5868                        "Internal error: start element not found\n", NULL,
5869                        NULL);
5870         } else {
5871             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5872         }
5873 
5874         if (combine != NULL) {
5875             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5876                 if (choiceOrInterleave == -1)
5877                     choiceOrInterleave = 1;
5878                 else if (choiceOrInterleave == 0) {
5879                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5880                                "<start> use both 'choice' and 'interleave'\n",
5881                                NULL, NULL);
5882                 }
5883             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5884                 if (choiceOrInterleave == -1)
5885                     choiceOrInterleave = 0;
5886                 else if (choiceOrInterleave == 1) {
5887                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5888                                "<start> use both 'choice' and 'interleave'\n",
5889                                NULL, NULL);
5890                 }
5891             } else {
5892                 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5893                            "<start> uses unknown combine value '%s''\n",
5894                            combine, NULL);
5895             }
5896             xmlFree(combine);
5897         } else {
5898             if (missing == 0)
5899                 missing = 1;
5900             else {
5901                 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5902                            "Some <start> element miss the combine attribute\n",
5903                            NULL, NULL);
5904             }
5905         }
5906 
5907         cur = cur->next;
5908     }
5909 #ifdef DEBUG
5910     xmlGenericError(xmlGenericErrorContext,
5911                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5912                     choiceOrInterleave);
5913 #endif
5914     if (choiceOrInterleave == -1)
5915         choiceOrInterleave = 0;
5916     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5917     if (cur == NULL)
5918         return;
5919     if (choiceOrInterleave == 0)
5920         cur->type = XML_RELAXNG_INTERLEAVE;
5921     else
5922         cur->type = XML_RELAXNG_CHOICE;
5923     cur->content = grammar->start;
5924     grammar->start = cur;
5925     if (choiceOrInterleave == 0) {
5926         if (ctxt->interleaves == NULL)
5927             ctxt->interleaves = xmlHashCreate(10);
5928         if (ctxt->interleaves == NULL) {
5929             xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5930                        "Failed to create interleaves hash table\n", NULL,
5931                        NULL);
5932         } else {
5933             char tmpname[32];
5934 
5935             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5936             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5937                 0) {
5938                 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5939                            "Failed to add %s to hash table\n",
5940 			   (const xmlChar *) tmpname, NULL);
5941             }
5942         }
5943     }
5944 }
5945 
5946 /**
5947  * xmlRelaxNGCheckCycles:
5948  * @ctxt:  a Relax-NG parser context
5949  * @nodes:  grammar children nodes
5950  * @depth:  the counter
5951  *
5952  * Check for cycles.
5953  *
5954  * Returns 0 if check passed, and -1 in case of error
5955  */
5956 static int
5957 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5958                       xmlRelaxNGDefinePtr cur, int depth)
5959 {
5960     int ret = 0;
5961 
5962     while ((ret == 0) && (cur != NULL)) {
5963         if ((cur->type == XML_RELAXNG_REF) ||
5964             (cur->type == XML_RELAXNG_PARENTREF)) {
5965             if (cur->depth == -1) {
5966                 cur->depth = depth;
5967                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5968                 cur->depth = -2;
5969             } else if (depth == cur->depth) {
5970                 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5971                            "Detected a cycle in %s references\n",
5972                            cur->name, NULL);
5973                 return (-1);
5974             }
5975         } else if (cur->type == XML_RELAXNG_ELEMENT) {
5976             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5977         } else {
5978             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5979         }
5980         cur = cur->next;
5981     }
5982     return (ret);
5983 }
5984 
5985 /**
5986  * xmlRelaxNGTryUnlink:
5987  * @ctxt:  a Relax-NG parser context
5988  * @cur:  the definition to unlink
5989  * @parent:  the parent definition
5990  * @prev:  the previous sibling definition
5991  *
5992  * Try to unlink a definition. If not possble make it a NOOP
5993  *
5994  * Returns the new prev definition
5995  */
5996 static xmlRelaxNGDefinePtr
5997 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5998                     xmlRelaxNGDefinePtr cur,
5999                     xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
6000 {
6001     if (prev != NULL) {
6002         prev->next = cur->next;
6003     } else {
6004         if (parent != NULL) {
6005             if (parent->content == cur)
6006                 parent->content = cur->next;
6007             else if (parent->attrs == cur)
6008                 parent->attrs = cur->next;
6009             else if (parent->nameClass == cur)
6010                 parent->nameClass = cur->next;
6011         } else {
6012             cur->type = XML_RELAXNG_NOOP;
6013             prev = cur;
6014         }
6015     }
6016     return (prev);
6017 }
6018 
6019 /**
6020  * xmlRelaxNGSimplify:
6021  * @ctxt:  a Relax-NG parser context
6022  * @nodes:  grammar children nodes
6023  *
6024  * Check for simplification of empty and notAllowed
6025  */
6026 static void
6027 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
6028                    xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
6029 {
6030     xmlRelaxNGDefinePtr prev = NULL;
6031 
6032     while (cur != NULL) {
6033         if ((cur->type == XML_RELAXNG_REF) ||
6034             (cur->type == XML_RELAXNG_PARENTREF)) {
6035             if (cur->depth != -3) {
6036                 cur->depth = -3;
6037                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6038             }
6039         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6040             cur->parent = parent;
6041             if ((parent != NULL) &&
6042                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6043                  (parent->type == XML_RELAXNG_LIST) ||
6044                  (parent->type == XML_RELAXNG_GROUP) ||
6045                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
6046                  (parent->type == XML_RELAXNG_ONEORMORE) ||
6047                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6048                 parent->type = XML_RELAXNG_NOT_ALLOWED;
6049                 break;
6050             }
6051             if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
6052                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6053             } else
6054                 prev = cur;
6055         } else if (cur->type == XML_RELAXNG_EMPTY) {
6056             cur->parent = parent;
6057             if ((parent != NULL) &&
6058                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6059                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6060                 parent->type = XML_RELAXNG_EMPTY;
6061                 break;
6062             }
6063             if ((parent != NULL) &&
6064                 ((parent->type == XML_RELAXNG_GROUP) ||
6065                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
6066                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6067             } else
6068                 prev = cur;
6069         } else {
6070             cur->parent = parent;
6071             if (cur->content != NULL)
6072                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6073             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
6074                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
6075             if (cur->nameClass != NULL)
6076                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
6077             /*
6078              * On Elements, try to move attribute only generating rules on
6079              * the attrs rules.
6080              */
6081             if (cur->type == XML_RELAXNG_ELEMENT) {
6082                 int attronly;
6083                 xmlRelaxNGDefinePtr tmp, pre;
6084 
6085                 while (cur->content != NULL) {
6086                     attronly =
6087                         xmlRelaxNGGenerateAttributes(ctxt, cur->content);
6088                     if (attronly == 1) {
6089                         /*
6090                          * migrate cur->content to attrs
6091                          */
6092                         tmp = cur->content;
6093                         cur->content = tmp->next;
6094                         tmp->next = cur->attrs;
6095                         cur->attrs = tmp;
6096                     } else {
6097                         /*
6098                          * cur->content can generate elements or text
6099                          */
6100                         break;
6101                     }
6102                 }
6103                 pre = cur->content;
6104                 while ((pre != NULL) && (pre->next != NULL)) {
6105                     tmp = pre->next;
6106                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6107                     if (attronly == 1) {
6108                         /*
6109                          * migrate tmp to attrs
6110                          */
6111                         pre->next = tmp->next;
6112                         tmp->next = cur->attrs;
6113                         cur->attrs = tmp;
6114                     } else {
6115                         pre = tmp;
6116                     }
6117                 }
6118             }
6119             /*
6120              * This may result in a simplification
6121              */
6122             if ((cur->type == XML_RELAXNG_GROUP) ||
6123                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6124                 if (cur->content == NULL)
6125                     cur->type = XML_RELAXNG_EMPTY;
6126                 else if (cur->content->next == NULL) {
6127                     if ((parent == NULL) && (prev == NULL)) {
6128                         cur->type = XML_RELAXNG_NOOP;
6129                     } else if (prev == NULL) {
6130                         parent->content = cur->content;
6131                         cur->content->next = cur->next;
6132                         cur = cur->content;
6133                     } else {
6134                         cur->content->next = cur->next;
6135                         prev->next = cur->content;
6136                         cur = cur->content;
6137                     }
6138                 }
6139             }
6140             /*
6141              * the current node may have been transformed back
6142              */
6143             if ((cur->type == XML_RELAXNG_EXCEPT) &&
6144                 (cur->content != NULL) &&
6145                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6146                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6147             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6148                 if ((parent != NULL) &&
6149                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6150                      (parent->type == XML_RELAXNG_LIST) ||
6151                      (parent->type == XML_RELAXNG_GROUP) ||
6152                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6153                      (parent->type == XML_RELAXNG_ONEORMORE) ||
6154                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6155                     parent->type = XML_RELAXNG_NOT_ALLOWED;
6156                     break;
6157                 }
6158                 if ((parent != NULL) &&
6159                     (parent->type == XML_RELAXNG_CHOICE)) {
6160                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6161                 } else
6162                     prev = cur;
6163             } else if (cur->type == XML_RELAXNG_EMPTY) {
6164                 if ((parent != NULL) &&
6165                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
6166                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6167                     parent->type = XML_RELAXNG_EMPTY;
6168                     break;
6169                 }
6170                 if ((parent != NULL) &&
6171                     ((parent->type == XML_RELAXNG_GROUP) ||
6172                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6173                      (parent->type == XML_RELAXNG_CHOICE))) {
6174                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6175                 } else
6176                     prev = cur;
6177             } else {
6178                 prev = cur;
6179             }
6180         }
6181         cur = cur->next;
6182     }
6183 }
6184 
6185 /**
6186  * xmlRelaxNGGroupContentType:
6187  * @ct1:  the first content type
6188  * @ct2:  the second content type
6189  *
6190  * Try to group 2 content types
6191  *
6192  * Returns the content type
6193  */
6194 static xmlRelaxNGContentType
6195 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6196                            xmlRelaxNGContentType ct2)
6197 {
6198     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6199         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6200         return (XML_RELAXNG_CONTENT_ERROR);
6201     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6202         return (ct2);
6203     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6204         return (ct1);
6205     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6206         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6207         return (XML_RELAXNG_CONTENT_COMPLEX);
6208     return (XML_RELAXNG_CONTENT_ERROR);
6209 }
6210 
6211 /**
6212  * xmlRelaxNGMaxContentType:
6213  * @ct1:  the first content type
6214  * @ct2:  the second content type
6215  *
6216  * Compute the max content-type
6217  *
6218  * Returns the content type
6219  */
6220 static xmlRelaxNGContentType
6221 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6222                          xmlRelaxNGContentType ct2)
6223 {
6224     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6225         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6226         return (XML_RELAXNG_CONTENT_ERROR);
6227     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6228         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6229         return (XML_RELAXNG_CONTENT_SIMPLE);
6230     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6231         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6232         return (XML_RELAXNG_CONTENT_COMPLEX);
6233     return (XML_RELAXNG_CONTENT_EMPTY);
6234 }
6235 
6236 /**
6237  * xmlRelaxNGCheckRules:
6238  * @ctxt:  a Relax-NG parser context
6239  * @cur:  the current definition
6240  * @flags:  some accumulated flags
6241  * @ptype:  the parent type
6242  *
6243  * Check for rules in section 7.1 and 7.2
6244  *
6245  * Returns the content type of @cur
6246  */
6247 static xmlRelaxNGContentType
6248 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6249                      xmlRelaxNGDefinePtr cur, int flags,
6250                      xmlRelaxNGType ptype)
6251 {
6252     int nflags;
6253     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6254 
6255     while (cur != NULL) {
6256         ret = XML_RELAXNG_CONTENT_EMPTY;
6257         if ((cur->type == XML_RELAXNG_REF) ||
6258             (cur->type == XML_RELAXNG_PARENTREF)) {
6259            /*
6260             * This should actually be caught by list//element(ref) at the
6261             * element boundaries, c.f. Bug #159968 local refs are dropped
6262             * in step 4.19.
6263             */
6264 #if 0
6265             if (flags & XML_RELAXNG_IN_LIST) {
6266                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6267                            "Found forbidden pattern list//ref\n", NULL,
6268                            NULL);
6269             }
6270 #endif
6271             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6272                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6273                            "Found forbidden pattern data/except//ref\n",
6274                            NULL, NULL);
6275             }
6276             if (cur->content == NULL) {
6277                 if (cur->type == XML_RELAXNG_PARENTREF)
6278                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6279                                "Internal found no define for parent refs\n",
6280                                NULL, NULL);
6281                 else
6282                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6283                                "Internal found no define for ref %s\n",
6284                                (cur->name ? cur->name: BAD_CAST "null"), NULL);
6285             }
6286             if (cur->depth > -4) {
6287                 cur->depth = -4;
6288                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6289                                            flags, cur->type);
6290                 cur->depth = ret - 15;
6291             } else if (cur->depth == -4) {
6292                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6293             } else {
6294                 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6295             }
6296         } else if (cur->type == XML_RELAXNG_ELEMENT) {
6297             /*
6298              * The 7.3 Attribute derivation rule for groups is plugged there
6299              */
6300             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6301             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6302                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6303                            "Found forbidden pattern data/except//element(ref)\n",
6304                            NULL, NULL);
6305             }
6306             if (flags & XML_RELAXNG_IN_LIST) {
6307                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6308                            "Found forbidden pattern list//element(ref)\n",
6309                            NULL, NULL);
6310             }
6311             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6312                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6313                            "Found forbidden pattern attribute//element(ref)\n",
6314                            NULL, NULL);
6315             }
6316             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6317                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6318                            "Found forbidden pattern attribute//element(ref)\n",
6319                            NULL, NULL);
6320             }
6321             /*
6322              * reset since in the simple form elements are only child
6323              * of grammar/define
6324              */
6325             nflags = 0;
6326             ret =
6327                 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6328             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6329                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6330                            "Element %s attributes have a content type error\n",
6331                            cur->name, NULL);
6332             }
6333             ret =
6334                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6335                                      cur->type);
6336             if (ret == XML_RELAXNG_CONTENT_ERROR) {
6337                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6338                            "Element %s has a content type error\n",
6339                            cur->name, NULL);
6340             } else {
6341                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6342             }
6343         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6344             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6345                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6346                            "Found forbidden pattern attribute//attribute\n",
6347                            NULL, NULL);
6348             }
6349             if (flags & XML_RELAXNG_IN_LIST) {
6350                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6351                            "Found forbidden pattern list//attribute\n",
6352                            NULL, NULL);
6353             }
6354             if (flags & XML_RELAXNG_IN_OOMGROUP) {
6355                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6356                            "Found forbidden pattern oneOrMore//group//attribute\n",
6357                            NULL, NULL);
6358             }
6359             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6360                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6361                            "Found forbidden pattern oneOrMore//interleave//attribute\n",
6362                            NULL, NULL);
6363             }
6364             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6365                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6366                            "Found forbidden pattern data/except//attribute\n",
6367                            NULL, NULL);
6368             }
6369             if (flags & XML_RELAXNG_IN_START) {
6370                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6371                            "Found forbidden pattern start//attribute\n",
6372                            NULL, NULL);
6373             }
6374             if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6375                 && (cur->name == NULL)) {
6376                 if (cur->ns == NULL) {
6377                     xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6378                                "Found anyName attribute without oneOrMore ancestor\n",
6379                                NULL, NULL);
6380                 } else {
6381                     xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6382                                "Found nsName attribute without oneOrMore ancestor\n",
6383                                NULL, NULL);
6384                 }
6385             }
6386             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6387             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6388             ret = XML_RELAXNG_CONTENT_EMPTY;
6389         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6390                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
6391             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6392                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6393                            "Found forbidden pattern data/except//oneOrMore\n",
6394                            NULL, NULL);
6395             }
6396             if (flags & XML_RELAXNG_IN_START) {
6397                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6398                            "Found forbidden pattern start//oneOrMore\n",
6399                            NULL, NULL);
6400             }
6401             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6402             ret =
6403                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6404                                      cur->type);
6405             ret = xmlRelaxNGGroupContentType(ret, ret);
6406         } else if (cur->type == XML_RELAXNG_LIST) {
6407             if (flags & XML_RELAXNG_IN_LIST) {
6408                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6409                            "Found forbidden pattern list//list\n", NULL,
6410                            NULL);
6411             }
6412             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6413                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6414                            "Found forbidden pattern data/except//list\n",
6415                            NULL, NULL);
6416             }
6417             if (flags & XML_RELAXNG_IN_START) {
6418                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6419                            "Found forbidden pattern start//list\n", NULL,
6420                            NULL);
6421             }
6422             nflags = flags | XML_RELAXNG_IN_LIST;
6423             ret =
6424                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6425                                      cur->type);
6426         } else if (cur->type == XML_RELAXNG_GROUP) {
6427             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6428                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6429                            "Found forbidden pattern data/except//group\n",
6430                            NULL, NULL);
6431             }
6432             if (flags & XML_RELAXNG_IN_START) {
6433                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6434                            "Found forbidden pattern start//group\n", NULL,
6435                            NULL);
6436             }
6437             if (flags & XML_RELAXNG_IN_ONEORMORE)
6438                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6439             else
6440                 nflags = flags;
6441             ret =
6442                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6443                                      cur->type);
6444             /*
6445              * The 7.3 Attribute derivation rule for groups is plugged there
6446              */
6447             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6448         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6449             if (flags & XML_RELAXNG_IN_LIST) {
6450                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6451                            "Found forbidden pattern list//interleave\n",
6452                            NULL, NULL);
6453             }
6454             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6455                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6456                            "Found forbidden pattern data/except//interleave\n",
6457                            NULL, NULL);
6458             }
6459             if (flags & XML_RELAXNG_IN_START) {
6460                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6461                            "Found forbidden pattern start//interleave\n",
6462                            NULL, NULL);
6463             }
6464             if (flags & XML_RELAXNG_IN_ONEORMORE)
6465                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6466             else
6467                 nflags = flags;
6468             ret =
6469                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6470                                      cur->type);
6471         } else if (cur->type == XML_RELAXNG_EXCEPT) {
6472             if ((cur->parent != NULL) &&
6473                 (cur->parent->type == XML_RELAXNG_DATATYPE))
6474                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6475             else
6476                 nflags = flags;
6477             ret =
6478                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6479                                      cur->type);
6480         } else if (cur->type == XML_RELAXNG_DATATYPE) {
6481             if (flags & XML_RELAXNG_IN_START) {
6482                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6483                            "Found forbidden pattern start//data\n", NULL,
6484                            NULL);
6485             }
6486             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6487             ret = XML_RELAXNG_CONTENT_SIMPLE;
6488         } else if (cur->type == XML_RELAXNG_VALUE) {
6489             if (flags & XML_RELAXNG_IN_START) {
6490                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6491                            "Found forbidden pattern start//value\n", NULL,
6492                            NULL);
6493             }
6494             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6495             ret = XML_RELAXNG_CONTENT_SIMPLE;
6496         } else if (cur->type == XML_RELAXNG_TEXT) {
6497             if (flags & XML_RELAXNG_IN_LIST) {
6498                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6499                            "Found forbidden pattern list//text\n", NULL,
6500                            NULL);
6501             }
6502             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6503                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6504                            "Found forbidden pattern data/except//text\n",
6505                            NULL, NULL);
6506             }
6507             if (flags & XML_RELAXNG_IN_START) {
6508                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6509                            "Found forbidden pattern start//text\n", NULL,
6510                            NULL);
6511             }
6512             ret = XML_RELAXNG_CONTENT_COMPLEX;
6513         } else if (cur->type == XML_RELAXNG_EMPTY) {
6514             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6515                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6516                            "Found forbidden pattern data/except//empty\n",
6517                            NULL, NULL);
6518             }
6519             if (flags & XML_RELAXNG_IN_START) {
6520                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6521                            "Found forbidden pattern start//empty\n", NULL,
6522                            NULL);
6523             }
6524             ret = XML_RELAXNG_CONTENT_EMPTY;
6525         } else if (cur->type == XML_RELAXNG_CHOICE) {
6526             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6527             ret =
6528                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6529         } else {
6530             ret =
6531                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6532         }
6533         cur = cur->next;
6534         if (ptype == XML_RELAXNG_GROUP) {
6535             val = xmlRelaxNGGroupContentType(val, ret);
6536         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6537             /*
6538              * TODO: scan complain that tmp is never used, seems on purpose
6539              *       need double-checking
6540              */
6541             tmp = xmlRelaxNGGroupContentType(val, ret);
6542             if (tmp != XML_RELAXNG_CONTENT_ERROR)
6543                 tmp = xmlRelaxNGMaxContentType(val, ret);
6544         } else if (ptype == XML_RELAXNG_CHOICE) {
6545             val = xmlRelaxNGMaxContentType(val, ret);
6546         } else if (ptype == XML_RELAXNG_LIST) {
6547             val = XML_RELAXNG_CONTENT_SIMPLE;
6548         } else if (ptype == XML_RELAXNG_EXCEPT) {
6549             if (ret == XML_RELAXNG_CONTENT_ERROR)
6550                 val = XML_RELAXNG_CONTENT_ERROR;
6551             else
6552                 val = XML_RELAXNG_CONTENT_SIMPLE;
6553         } else {
6554             val = xmlRelaxNGGroupContentType(val, ret);
6555         }
6556 
6557     }
6558     return (val);
6559 }
6560 
6561 /**
6562  * xmlRelaxNGParseGrammar:
6563  * @ctxt:  a Relax-NG parser context
6564  * @nodes:  grammar children nodes
6565  *
6566  * parse a Relax-NG <grammar> node
6567  *
6568  * Returns the internal xmlRelaxNGGrammarPtr built or
6569  *         NULL in case of error
6570  */
6571 static xmlRelaxNGGrammarPtr
6572 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6573 {
6574     xmlRelaxNGGrammarPtr ret, tmp, old;
6575 
6576 #ifdef DEBUG_GRAMMAR
6577     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6578 #endif
6579 
6580     ret = xmlRelaxNGNewGrammar(ctxt);
6581     if (ret == NULL)
6582         return (NULL);
6583 
6584     /*
6585      * Link the new grammar in the tree
6586      */
6587     ret->parent = ctxt->grammar;
6588     if (ctxt->grammar != NULL) {
6589         tmp = ctxt->grammar->children;
6590         if (tmp == NULL) {
6591             ctxt->grammar->children = ret;
6592         } else {
6593             while (tmp->next != NULL)
6594                 tmp = tmp->next;
6595             tmp->next = ret;
6596         }
6597     }
6598 
6599     old = ctxt->grammar;
6600     ctxt->grammar = ret;
6601     xmlRelaxNGParseGrammarContent(ctxt, nodes);
6602     ctxt->grammar = ret;
6603     if (ctxt->grammar == NULL) {
6604         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6605                    "Failed to parse <grammar> content\n", NULL, NULL);
6606     } else if (ctxt->grammar->start == NULL) {
6607         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6608                    "Element <grammar> has no <start>\n", NULL, NULL);
6609     }
6610 
6611     /*
6612      * Apply 4.17 merging rules to defines and starts
6613      */
6614     xmlRelaxNGCombineStart(ctxt, ret);
6615     if (ret->defs != NULL) {
6616         xmlHashScan(ret->defs, xmlRelaxNGCheckCombine, ctxt);
6617     }
6618 
6619     /*
6620      * link together defines and refs in this grammar
6621      */
6622     if (ret->refs != NULL) {
6623         xmlHashScan(ret->refs, xmlRelaxNGCheckReference, ctxt);
6624     }
6625 
6626 
6627     /* @@@@ */
6628 
6629     ctxt->grammar = old;
6630     return (ret);
6631 }
6632 
6633 /**
6634  * xmlRelaxNGParseDocument:
6635  * @ctxt:  a Relax-NG parser context
6636  * @node:  the root node of the RelaxNG schema
6637  *
6638  * parse a Relax-NG definition resource and build an internal
6639  * xmlRelaxNG struture which can be used to validate instances.
6640  *
6641  * Returns the internal XML RelaxNG structure built or
6642  *         NULL in case of error
6643  */
6644 static xmlRelaxNGPtr
6645 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6646 {
6647     xmlRelaxNGPtr schema = NULL;
6648     const xmlChar *olddefine;
6649     xmlRelaxNGGrammarPtr old;
6650 
6651     if ((ctxt == NULL) || (node == NULL))
6652         return (NULL);
6653 
6654     schema = xmlRelaxNGNewRelaxNG(ctxt);
6655     if (schema == NULL)
6656         return (NULL);
6657 
6658     olddefine = ctxt->define;
6659     ctxt->define = NULL;
6660     if (IS_RELAXNG(node, "grammar")) {
6661         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6662         if (schema->topgrammar == NULL) {
6663             xmlRelaxNGFree(schema);
6664             return (NULL);
6665         }
6666     } else {
6667         xmlRelaxNGGrammarPtr tmp, ret;
6668 
6669         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6670         if (schema->topgrammar == NULL) {
6671             xmlRelaxNGFree(schema);
6672             return (NULL);
6673         }
6674         /*
6675          * Link the new grammar in the tree
6676          */
6677         ret->parent = ctxt->grammar;
6678         if (ctxt->grammar != NULL) {
6679             tmp = ctxt->grammar->children;
6680             if (tmp == NULL) {
6681                 ctxt->grammar->children = ret;
6682             } else {
6683                 while (tmp->next != NULL)
6684                     tmp = tmp->next;
6685                 tmp->next = ret;
6686             }
6687         }
6688         old = ctxt->grammar;
6689         ctxt->grammar = ret;
6690         xmlRelaxNGParseStart(ctxt, node);
6691         if (old != NULL)
6692             ctxt->grammar = old;
6693     }
6694     ctxt->define = olddefine;
6695     if (schema->topgrammar->start != NULL) {
6696         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6697         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6698             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6699             while ((schema->topgrammar->start != NULL) &&
6700                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6701                    (schema->topgrammar->start->next != NULL))
6702                 schema->topgrammar->start =
6703                     schema->topgrammar->start->content;
6704             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6705                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6706         }
6707     }
6708 #ifdef DEBUG
6709     if (schema == NULL)
6710         xmlGenericError(xmlGenericErrorContext,
6711                         "xmlRelaxNGParseDocument() failed\n");
6712 #endif
6713 
6714     return (schema);
6715 }
6716 
6717 /************************************************************************
6718  *									*
6719  *			Reading RelaxNGs				*
6720  *									*
6721  ************************************************************************/
6722 
6723 /**
6724  * xmlRelaxNGNewParserCtxt:
6725  * @URL:  the location of the schema
6726  *
6727  * Create an XML RelaxNGs parse context for that file/resource expected
6728  * to contain an XML RelaxNGs file.
6729  *
6730  * Returns the parser context or NULL in case of error
6731  */
6732 xmlRelaxNGParserCtxtPtr
6733 xmlRelaxNGNewParserCtxt(const char *URL)
6734 {
6735     xmlRelaxNGParserCtxtPtr ret;
6736 
6737     if (URL == NULL)
6738         return (NULL);
6739 
6740     ret =
6741         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6742     if (ret == NULL) {
6743         xmlRngPErrMemory(NULL, "building parser\n");
6744         return (NULL);
6745     }
6746     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6747     ret->URL = xmlStrdup((const xmlChar *) URL);
6748     ret->error = xmlGenericError;
6749     ret->userData = xmlGenericErrorContext;
6750     return (ret);
6751 }
6752 
6753 /**
6754  * xmlRelaxNGNewMemParserCtxt:
6755  * @buffer:  a pointer to a char array containing the schemas
6756  * @size:  the size of the array
6757  *
6758  * Create an XML RelaxNGs parse context for that memory buffer expected
6759  * to contain an XML RelaxNGs file.
6760  *
6761  * Returns the parser context or NULL in case of error
6762  */
6763 xmlRelaxNGParserCtxtPtr
6764 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6765 {
6766     xmlRelaxNGParserCtxtPtr ret;
6767 
6768     if ((buffer == NULL) || (size <= 0))
6769         return (NULL);
6770 
6771     ret =
6772         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6773     if (ret == NULL) {
6774         xmlRngPErrMemory(NULL, "building parser\n");
6775         return (NULL);
6776     }
6777     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6778     ret->buffer = buffer;
6779     ret->size = size;
6780     ret->error = xmlGenericError;
6781     ret->userData = xmlGenericErrorContext;
6782     return (ret);
6783 }
6784 
6785 /**
6786  * xmlRelaxNGNewDocParserCtxt:
6787  * @doc:  a preparsed document tree
6788  *
6789  * Create an XML RelaxNGs parser context for that document.
6790  * Note: since the process of compiling a RelaxNG schemas modifies the
6791  *       document, the @doc parameter is duplicated internally.
6792  *
6793  * Returns the parser context or NULL in case of error
6794  */
6795 xmlRelaxNGParserCtxtPtr
6796 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6797 {
6798     xmlRelaxNGParserCtxtPtr ret;
6799     xmlDocPtr copy;
6800 
6801     if (doc == NULL)
6802         return (NULL);
6803     copy = xmlCopyDoc(doc, 1);
6804     if (copy == NULL)
6805         return (NULL);
6806 
6807     ret =
6808         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6809     if (ret == NULL) {
6810         xmlRngPErrMemory(NULL, "building parser\n");
6811         return (NULL);
6812     }
6813     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6814     ret->document = copy;
6815     ret->freedoc = 1;
6816     ret->userData = xmlGenericErrorContext;
6817     return (ret);
6818 }
6819 
6820 /**
6821  * xmlRelaxNGFreeParserCtxt:
6822  * @ctxt:  the schema parser context
6823  *
6824  * Free the resources associated to the schema parser context
6825  */
6826 void
6827 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6828 {
6829     if (ctxt == NULL)
6830         return;
6831     if (ctxt->URL != NULL)
6832         xmlFree(ctxt->URL);
6833     if (ctxt->doc != NULL)
6834         xmlRelaxNGFreeDocument(ctxt->doc);
6835     if (ctxt->interleaves != NULL)
6836         xmlHashFree(ctxt->interleaves, NULL);
6837     if (ctxt->documents != NULL)
6838         xmlRelaxNGFreeDocumentList(ctxt->documents);
6839     if (ctxt->includes != NULL)
6840         xmlRelaxNGFreeIncludeList(ctxt->includes);
6841     if (ctxt->docTab != NULL)
6842         xmlFree(ctxt->docTab);
6843     if (ctxt->incTab != NULL)
6844         xmlFree(ctxt->incTab);
6845     if (ctxt->defTab != NULL) {
6846         int i;
6847 
6848         for (i = 0; i < ctxt->defNr; i++)
6849             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6850         xmlFree(ctxt->defTab);
6851     }
6852     if ((ctxt->document != NULL) && (ctxt->freedoc))
6853         xmlFreeDoc(ctxt->document);
6854     xmlFree(ctxt);
6855 }
6856 
6857 /**
6858  * xmlRelaxNGNormExtSpace:
6859  * @value:  a value
6860  *
6861  * Removes the leading and ending spaces of the value
6862  * The string is modified "in situ"
6863  */
6864 static void
6865 xmlRelaxNGNormExtSpace(xmlChar * value)
6866 {
6867     xmlChar *start = value;
6868     xmlChar *cur = value;
6869 
6870     if (value == NULL)
6871         return;
6872 
6873     while (IS_BLANK_CH(*cur))
6874         cur++;
6875     if (cur == start) {
6876         do {
6877             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6878                 cur++;
6879             if (*cur == 0)
6880                 return;
6881             start = cur;
6882             while (IS_BLANK_CH(*cur))
6883                 cur++;
6884             if (*cur == 0) {
6885                 *start = 0;
6886                 return;
6887             }
6888         } while (1);
6889     } else {
6890         do {
6891             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6892                 *start++ = *cur++;
6893             if (*cur == 0) {
6894                 *start = 0;
6895                 return;
6896             }
6897             /* don't try to normalize the inner spaces */
6898             while (IS_BLANK_CH(*cur))
6899                 cur++;
6900             if (*cur == 0) {
6901                 *start = 0;
6902                 return;
6903             }
6904             *start++ = *cur++;
6905         } while (1);
6906     }
6907 }
6908 
6909 /**
6910  * xmlRelaxNGCleanupAttributes:
6911  * @ctxt:  a Relax-NG parser context
6912  * @node:  a Relax-NG node
6913  *
6914  * Check all the attributes on the given node
6915  */
6916 static void
6917 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6918 {
6919     xmlAttrPtr cur, next;
6920 
6921     cur = node->properties;
6922     while (cur != NULL) {
6923         next = cur->next;
6924         if ((cur->ns == NULL) ||
6925             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6926             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6927                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6928                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6929                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6930                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6931                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6932                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6933                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6934                                "Attribute %s is not allowed on %s\n",
6935                                cur->name, node->name);
6936                 }
6937             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6938                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6939                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6940                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6941                                "Attribute %s is not allowed on %s\n",
6942                                cur->name, node->name);
6943                 }
6944             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6945                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6946                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6947                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6948                                "Attribute %s is not allowed on %s\n",
6949                                cur->name, node->name);
6950                 }
6951             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6952                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6953                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6954                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6955                                "Attribute %s is not allowed on %s\n",
6956                                cur->name, node->name);
6957                 }
6958             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6959                 xmlChar *val;
6960                 xmlURIPtr uri;
6961 
6962                 val = xmlNodeListGetString(node->doc, cur->children, 1);
6963                 if (val != NULL) {
6964                     if (val[0] != 0) {
6965                         uri = xmlParseURI((const char *) val);
6966                         if (uri == NULL) {
6967                             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6968                                        "Attribute %s contains invalid URI %s\n",
6969                                        cur->name, val);
6970                         } else {
6971                             if (uri->scheme == NULL) {
6972                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6973                                            "Attribute %s URI %s is not absolute\n",
6974                                            cur->name, val);
6975                             }
6976                             if (uri->fragment != NULL) {
6977                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6978                                            "Attribute %s URI %s has a fragment ID\n",
6979                                            cur->name, val);
6980                             }
6981                             xmlFreeURI(uri);
6982                         }
6983                     }
6984                     xmlFree(val);
6985                 }
6986             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6987                 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6988                            "Unknown attribute %s on %s\n", cur->name,
6989                            node->name);
6990             }
6991         }
6992         cur = next;
6993     }
6994 }
6995 
6996 /**
6997  * xmlRelaxNGCleanupTree:
6998  * @ctxt:  a Relax-NG parser context
6999  * @root:  an xmlNodePtr subtree
7000  *
7001  * Cleanup the subtree from unwanted nodes for parsing, resolve
7002  * Include and externalRef lookups.
7003  */
7004 static void
7005 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
7006 {
7007     xmlNodePtr cur, delete;
7008 
7009     delete = NULL;
7010     cur = root;
7011     while (cur != NULL) {
7012         if (delete != NULL) {
7013             xmlUnlinkNode(delete);
7014             xmlFreeNode(delete);
7015             delete = NULL;
7016         }
7017         if (cur->type == XML_ELEMENT_NODE) {
7018             /*
7019              * Simplification 4.1. Annotations
7020              */
7021             if ((cur->ns == NULL) ||
7022                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
7023                 if ((cur->parent != NULL) &&
7024                     (cur->parent->type == XML_ELEMENT_NODE) &&
7025                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
7026                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
7027                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
7028                     xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
7029                                "element %s doesn't allow foreign elements\n",
7030                                cur->parent->name, NULL);
7031                 }
7032                 delete = cur;
7033                 goto skip_children;
7034             } else {
7035                 xmlRelaxNGCleanupAttributes(ctxt, cur);
7036                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
7037                     xmlChar *href, *ns, *base, *URL;
7038                     xmlRelaxNGDocumentPtr docu;
7039                     xmlNodePtr tmp;
7040 		    xmlURIPtr uri;
7041 
7042                     ns = xmlGetProp(cur, BAD_CAST "ns");
7043                     if (ns == NULL) {
7044                         tmp = cur->parent;
7045                         while ((tmp != NULL) &&
7046                                (tmp->type == XML_ELEMENT_NODE)) {
7047                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7048                             if (ns != NULL)
7049                                 break;
7050                             tmp = tmp->parent;
7051                         }
7052                     }
7053                     href = xmlGetProp(cur, BAD_CAST "href");
7054                     if (href == NULL) {
7055                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7056                                    "xmlRelaxNGParse: externalRef has no href attribute\n",
7057                                    NULL, NULL);
7058                         if (ns != NULL)
7059                             xmlFree(ns);
7060                         delete = cur;
7061                         goto skip_children;
7062                     }
7063 		    uri = xmlParseURI((const char *) href);
7064 		    if (uri == NULL) {
7065                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7066                                    "Incorrect URI for externalRef %s\n",
7067                                    href, NULL);
7068                         if (ns != NULL)
7069                             xmlFree(ns);
7070                         if (href != NULL)
7071                             xmlFree(href);
7072                         delete = cur;
7073                         goto skip_children;
7074 		    }
7075 		    if (uri->fragment != NULL) {
7076                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7077 			       "Fragment forbidden in URI for externalRef %s\n",
7078                                    href, NULL);
7079                         if (ns != NULL)
7080                             xmlFree(ns);
7081 		        xmlFreeURI(uri);
7082                         if (href != NULL)
7083                             xmlFree(href);
7084                         delete = cur;
7085                         goto skip_children;
7086 		    }
7087 		    xmlFreeURI(uri);
7088                     base = xmlNodeGetBase(cur->doc, cur);
7089                     URL = xmlBuildURI(href, base);
7090                     if (URL == NULL) {
7091                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7092                                    "Failed to compute URL for externalRef %s\n",
7093                                    href, NULL);
7094                         if (ns != NULL)
7095                             xmlFree(ns);
7096                         if (href != NULL)
7097                             xmlFree(href);
7098                         if (base != NULL)
7099                             xmlFree(base);
7100                         delete = cur;
7101                         goto skip_children;
7102                     }
7103                     if (href != NULL)
7104                         xmlFree(href);
7105                     if (base != NULL)
7106                         xmlFree(base);
7107                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
7108                     if (docu == NULL) {
7109                         xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
7110                                    "Failed to load externalRef %s\n", URL,
7111                                    NULL);
7112                         if (ns != NULL)
7113                             xmlFree(ns);
7114                         xmlFree(URL);
7115                         delete = cur;
7116                         goto skip_children;
7117                     }
7118                     if (ns != NULL)
7119                         xmlFree(ns);
7120                     xmlFree(URL);
7121                     cur->psvi = docu;
7122                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7123                     xmlChar *href, *ns, *base, *URL;
7124                     xmlRelaxNGIncludePtr incl;
7125                     xmlNodePtr tmp;
7126 
7127                     href = xmlGetProp(cur, BAD_CAST "href");
7128                     if (href == NULL) {
7129                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7130                                    "xmlRelaxNGParse: include has no href attribute\n",
7131                                    NULL, NULL);
7132                         delete = cur;
7133                         goto skip_children;
7134                     }
7135                     base = xmlNodeGetBase(cur->doc, cur);
7136                     URL = xmlBuildURI(href, base);
7137                     if (URL == NULL) {
7138                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7139                                    "Failed to compute URL for include %s\n",
7140                                    href, NULL);
7141                         if (href != NULL)
7142                             xmlFree(href);
7143                         if (base != NULL)
7144                             xmlFree(base);
7145                         delete = cur;
7146                         goto skip_children;
7147                     }
7148                     if (href != NULL)
7149                         xmlFree(href);
7150                     if (base != NULL)
7151                         xmlFree(base);
7152                     ns = xmlGetProp(cur, BAD_CAST "ns");
7153                     if (ns == NULL) {
7154                         tmp = cur->parent;
7155                         while ((tmp != NULL) &&
7156                                (tmp->type == XML_ELEMENT_NODE)) {
7157                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7158                             if (ns != NULL)
7159                                 break;
7160                             tmp = tmp->parent;
7161                         }
7162                     }
7163                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7164                     if (ns != NULL)
7165                         xmlFree(ns);
7166                     if (incl == NULL) {
7167                         xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7168                                    "Failed to load include %s\n", URL,
7169                                    NULL);
7170                         xmlFree(URL);
7171                         delete = cur;
7172                         goto skip_children;
7173                     }
7174                     xmlFree(URL);
7175                     cur->psvi = incl;
7176                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7177                            (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7178                 {
7179                     xmlChar *name, *ns;
7180                     xmlNodePtr text = NULL;
7181 
7182                     /*
7183                      * Simplification 4.8. name attribute of element
7184                      * and attribute elements
7185                      */
7186                     name = xmlGetProp(cur, BAD_CAST "name");
7187                     if (name != NULL) {
7188                         if (cur->children == NULL) {
7189                             text =
7190                                 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7191                                             name);
7192                         } else {
7193                             xmlNodePtr node;
7194 
7195                             node = xmlNewDocNode(cur->doc, cur->ns,
7196 			                         BAD_CAST "name", NULL);
7197                             if (node != NULL) {
7198                                 xmlAddPrevSibling(cur->children, node);
7199                                 text = xmlNewText(name);
7200                                 xmlAddChild(node, text);
7201                                 text = node;
7202                             }
7203                         }
7204                         if (text == NULL) {
7205                             xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7206                                        "Failed to create a name %s element\n",
7207                                        name, NULL);
7208                         }
7209                         xmlUnsetProp(cur, BAD_CAST "name");
7210                         xmlFree(name);
7211                         ns = xmlGetProp(cur, BAD_CAST "ns");
7212                         if (ns != NULL) {
7213                             if (text != NULL) {
7214                                 xmlSetProp(text, BAD_CAST "ns", ns);
7215                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7216                             }
7217                             xmlFree(ns);
7218                         } else if (xmlStrEqual(cur->name,
7219                                                BAD_CAST "attribute")) {
7220                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7221                         }
7222                     }
7223                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7224                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7225                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7226                     /*
7227                      * Simplification 4.8. name attribute of element
7228                      * and attribute elements
7229                      */
7230                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7231                         xmlNodePtr node;
7232                         xmlChar *ns = NULL;
7233 
7234                         node = cur->parent;
7235                         while ((node != NULL) &&
7236                                (node->type == XML_ELEMENT_NODE)) {
7237                             ns = xmlGetProp(node, BAD_CAST "ns");
7238                             if (ns != NULL) {
7239                                 break;
7240                             }
7241                             node = node->parent;
7242                         }
7243                         if (ns == NULL) {
7244                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7245                         } else {
7246                             xmlSetProp(cur, BAD_CAST "ns", ns);
7247                             xmlFree(ns);
7248                         }
7249                     }
7250                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7251                         xmlChar *name, *local, *prefix;
7252 
7253                         /*
7254                          * Simplification: 4.10. QNames
7255                          */
7256                         name = xmlNodeGetContent(cur);
7257                         if (name != NULL) {
7258                             local = xmlSplitQName2(name, &prefix);
7259                             if (local != NULL) {
7260                                 xmlNsPtr ns;
7261 
7262                                 ns = xmlSearchNs(cur->doc, cur, prefix);
7263                                 if (ns == NULL) {
7264                                     xmlRngPErr(ctxt, cur,
7265                                                XML_RNGP_PREFIX_UNDEFINED,
7266                                                "xmlRelaxNGParse: no namespace for prefix %s\n",
7267                                                prefix, NULL);
7268                                 } else {
7269                                     xmlSetProp(cur, BAD_CAST "ns",
7270                                                ns->href);
7271                                     xmlNodeSetContent(cur, local);
7272                                 }
7273                                 xmlFree(local);
7274                                 xmlFree(prefix);
7275                             }
7276                             xmlFree(name);
7277                         }
7278                     }
7279                     /*
7280                      * 4.16
7281                      */
7282                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7283                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7284                             xmlRngPErr(ctxt, cur,
7285                                        XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7286                                        "Found nsName/except//nsName forbidden construct\n",
7287                                        NULL, NULL);
7288                         }
7289                     }
7290                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7291                            (cur != root)) {
7292                     int oldflags = ctxt->flags;
7293 
7294                     /*
7295                      * 4.16
7296                      */
7297                     if ((cur->parent != NULL) &&
7298                         (xmlStrEqual
7299                          (cur->parent->name, BAD_CAST "anyName"))) {
7300                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7301                         xmlRelaxNGCleanupTree(ctxt, cur);
7302                         ctxt->flags = oldflags;
7303                         goto skip_children;
7304                     } else if ((cur->parent != NULL) &&
7305                                (xmlStrEqual
7306                                 (cur->parent->name, BAD_CAST "nsName"))) {
7307                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7308                         xmlRelaxNGCleanupTree(ctxt, cur);
7309                         ctxt->flags = oldflags;
7310                         goto skip_children;
7311                     }
7312                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7313                     /*
7314                      * 4.16
7315                      */
7316                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7317                         xmlRngPErr(ctxt, cur,
7318                                    XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7319                                    "Found anyName/except//anyName forbidden construct\n",
7320                                    NULL, NULL);
7321                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7322                         xmlRngPErr(ctxt, cur,
7323                                    XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7324                                    "Found nsName/except//anyName forbidden construct\n",
7325                                    NULL, NULL);
7326                     }
7327                 }
7328                 /*
7329                  * This is not an else since "include" is transformed
7330                  * into a div
7331                  */
7332                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7333                     xmlChar *ns;
7334                     xmlNodePtr child, ins, tmp;
7335 
7336                     /*
7337                      * implements rule 4.11
7338                      */
7339 
7340                     ns = xmlGetProp(cur, BAD_CAST "ns");
7341 
7342                     child = cur->children;
7343                     ins = cur;
7344                     while (child != NULL) {
7345                         if (ns != NULL) {
7346                             if (!xmlHasProp(child, BAD_CAST "ns")) {
7347                                 xmlSetProp(child, BAD_CAST "ns", ns);
7348                             }
7349                         }
7350                         tmp = child->next;
7351                         xmlUnlinkNode(child);
7352                         ins = xmlAddNextSibling(ins, child);
7353                         child = tmp;
7354                     }
7355                     if (ns != NULL)
7356                         xmlFree(ns);
7357 		    /*
7358 		     * Since we are about to delete cur, if its nsDef is non-NULL we
7359 		     * need to preserve it (it contains the ns definitions for the
7360 		     * children we just moved).  We'll just stick it on to the end
7361 		     * of cur->parent's list, since it's never going to be re-serialized
7362 		     * (bug 143738).
7363 		     */
7364 		    if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
7365 			xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7366 			while (parDef->next != NULL)
7367 			    parDef = parDef->next;
7368 			parDef->next = cur->nsDef;
7369 			cur->nsDef = NULL;
7370 		    }
7371                     delete = cur;
7372                     goto skip_children;
7373                 }
7374             }
7375         }
7376         /*
7377          * Simplification 4.2 whitespaces
7378          */
7379         else if ((cur->type == XML_TEXT_NODE) ||
7380                  (cur->type == XML_CDATA_SECTION_NODE)) {
7381             if (IS_BLANK_NODE(cur)) {
7382                 if ((cur->parent != NULL) &&
7383 		    (cur->parent->type == XML_ELEMENT_NODE)) {
7384                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7385                         &&
7386                         (!xmlStrEqual
7387                          (cur->parent->name, BAD_CAST "param")))
7388                         delete = cur;
7389                 } else {
7390                     delete = cur;
7391                     goto skip_children;
7392                 }
7393             }
7394         } else {
7395             delete = cur;
7396             goto skip_children;
7397         }
7398 
7399         /*
7400          * Skip to next node
7401          */
7402         if (cur->children != NULL) {
7403             if ((cur->children->type != XML_ENTITY_DECL) &&
7404                 (cur->children->type != XML_ENTITY_REF_NODE) &&
7405                 (cur->children->type != XML_ENTITY_NODE)) {
7406                 cur = cur->children;
7407                 continue;
7408             }
7409         }
7410       skip_children:
7411         if (cur->next != NULL) {
7412             cur = cur->next;
7413             continue;
7414         }
7415 
7416         do {
7417             cur = cur->parent;
7418             if (cur == NULL)
7419                 break;
7420             if (cur == root) {
7421                 cur = NULL;
7422                 break;
7423             }
7424             if (cur->next != NULL) {
7425                 cur = cur->next;
7426                 break;
7427             }
7428         } while (cur != NULL);
7429     }
7430     if (delete != NULL) {
7431         xmlUnlinkNode(delete);
7432         xmlFreeNode(delete);
7433         delete = NULL;
7434     }
7435 }
7436 
7437 /**
7438  * xmlRelaxNGCleanupDoc:
7439  * @ctxt:  a Relax-NG parser context
7440  * @doc:  an xmldocPtr document pointer
7441  *
7442  * Cleanup the document from unwanted nodes for parsing, resolve
7443  * Include and externalRef lookups.
7444  *
7445  * Returns the cleaned up document or NULL in case of error
7446  */
7447 static xmlDocPtr
7448 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7449 {
7450     xmlNodePtr root;
7451 
7452     /*
7453      * Extract the root
7454      */
7455     root = xmlDocGetRootElement(doc);
7456     if (root == NULL) {
7457         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7458                    ctxt->URL, NULL);
7459         return (NULL);
7460     }
7461     xmlRelaxNGCleanupTree(ctxt, root);
7462     return (doc);
7463 }
7464 
7465 /**
7466  * xmlRelaxNGParse:
7467  * @ctxt:  a Relax-NG parser context
7468  *
7469  * parse a schema definition resource and build an internal
7470  * XML Shema struture which can be used to validate instances.
7471  *
7472  * Returns the internal XML RelaxNG structure built from the resource or
7473  *         NULL in case of error
7474  */
7475 xmlRelaxNGPtr
7476 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7477 {
7478     xmlRelaxNGPtr ret = NULL;
7479     xmlDocPtr doc;
7480     xmlNodePtr root;
7481 
7482     xmlRelaxNGInitTypes();
7483 
7484     if (ctxt == NULL)
7485         return (NULL);
7486 
7487     /*
7488      * First step is to parse the input document into an DOM/Infoset
7489      */
7490     if (ctxt->URL != NULL) {
7491         doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
7492         if (doc == NULL) {
7493             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7494                        "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7495                        NULL);
7496             return (NULL);
7497         }
7498     } else if (ctxt->buffer != NULL) {
7499         doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
7500         if (doc == NULL) {
7501             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7502                        "xmlRelaxNGParse: could not parse schemas\n", NULL,
7503                        NULL);
7504             return (NULL);
7505         }
7506         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7507         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7508     } else if (ctxt->document != NULL) {
7509         doc = ctxt->document;
7510     } else {
7511         xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7512                    "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7513         return (NULL);
7514     }
7515     ctxt->document = doc;
7516 
7517     /*
7518      * Some preprocessing of the document content
7519      */
7520     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7521     if (doc == NULL) {
7522         xmlFreeDoc(ctxt->document);
7523         ctxt->document = NULL;
7524         return (NULL);
7525     }
7526 
7527     /*
7528      * Then do the parsing for good
7529      */
7530     root = xmlDocGetRootElement(doc);
7531     if (root == NULL) {
7532         xmlRngPErr(ctxt, (xmlNodePtr) doc,
7533 	           XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7534                    (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
7535 
7536         xmlFreeDoc(ctxt->document);
7537         ctxt->document = NULL;
7538         return (NULL);
7539     }
7540     ret = xmlRelaxNGParseDocument(ctxt, root);
7541     if (ret == NULL) {
7542         xmlFreeDoc(ctxt->document);
7543         ctxt->document = NULL;
7544         return (NULL);
7545     }
7546 
7547     /*
7548      * Check the ref/defines links
7549      */
7550     /*
7551      * try to preprocess interleaves
7552      */
7553     if (ctxt->interleaves != NULL) {
7554         xmlHashScan(ctxt->interleaves, xmlRelaxNGComputeInterleaves, ctxt);
7555     }
7556 
7557     /*
7558      * if there was a parsing error return NULL
7559      */
7560     if (ctxt->nbErrors > 0) {
7561         xmlRelaxNGFree(ret);
7562         ctxt->document = NULL;
7563         xmlFreeDoc(doc);
7564         return (NULL);
7565     }
7566 
7567     /*
7568      * try to compile (parts of) the schemas
7569      */
7570     if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7571         if (ret->topgrammar->start->type != XML_RELAXNG_START) {
7572             xmlRelaxNGDefinePtr def;
7573 
7574             def = xmlRelaxNGNewDefine(ctxt, NULL);
7575             if (def != NULL) {
7576                 def->type = XML_RELAXNG_START;
7577                 def->content = ret->topgrammar->start;
7578                 ret->topgrammar->start = def;
7579             }
7580         }
7581         xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
7582     }
7583 
7584     /*
7585      * Transfer the pointer for cleanup at the schema level.
7586      */
7587     ret->doc = doc;
7588     ctxt->document = NULL;
7589     ret->documents = ctxt->documents;
7590     ctxt->documents = NULL;
7591 
7592     ret->includes = ctxt->includes;
7593     ctxt->includes = NULL;
7594     ret->defNr = ctxt->defNr;
7595     ret->defTab = ctxt->defTab;
7596     ctxt->defTab = NULL;
7597     if (ctxt->idref == 1)
7598         ret->idref = 1;
7599 
7600     return (ret);
7601 }
7602 
7603 /**
7604  * xmlRelaxNGSetParserErrors:
7605  * @ctxt:  a Relax-NG validation context
7606  * @err:  the error callback
7607  * @warn:  the warning callback
7608  * @ctx:  contextual data for the callbacks
7609  *
7610  * Set the callback functions used to handle errors for a validation context
7611  */
7612 void
7613 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7614                           xmlRelaxNGValidityErrorFunc err,
7615                           xmlRelaxNGValidityWarningFunc warn, void *ctx)
7616 {
7617     if (ctxt == NULL)
7618         return;
7619     ctxt->error = err;
7620     ctxt->warning = warn;
7621     ctxt->serror = NULL;
7622     ctxt->userData = ctx;
7623 }
7624 
7625 /**
7626  * xmlRelaxNGGetParserErrors:
7627  * @ctxt:  a Relax-NG validation context
7628  * @err:  the error callback result
7629  * @warn:  the warning callback result
7630  * @ctx:  contextual data for the callbacks result
7631  *
7632  * Get the callback information used to handle errors for a validation context
7633  *
7634  * Returns -1 in case of failure, 0 otherwise.
7635  */
7636 int
7637 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7638                           xmlRelaxNGValidityErrorFunc * err,
7639                           xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7640 {
7641     if (ctxt == NULL)
7642         return (-1);
7643     if (err != NULL)
7644         *err = ctxt->error;
7645     if (warn != NULL)
7646         *warn = ctxt->warning;
7647     if (ctx != NULL)
7648         *ctx = ctxt->userData;
7649     return (0);
7650 }
7651 
7652 /**
7653  * xmlRelaxNGSetParserStructuredErrors:
7654  * @ctxt:  a Relax-NG parser context
7655  * @serror:  the error callback
7656  * @ctx:  contextual data for the callbacks
7657  *
7658  * Set the callback functions used to handle errors for a parsing context
7659  */
7660 void
7661 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
7662 				    xmlStructuredErrorFunc serror,
7663 				    void *ctx)
7664 {
7665     if (ctxt == NULL)
7666         return;
7667     ctxt->serror = serror;
7668     ctxt->error = NULL;
7669     ctxt->warning = NULL;
7670     ctxt->userData = ctx;
7671 }
7672 
7673 #ifdef LIBXML_OUTPUT_ENABLED
7674 
7675 /************************************************************************
7676  *									*
7677  *			Dump back a compiled form			*
7678  *									*
7679  ************************************************************************/
7680 static void xmlRelaxNGDumpDefine(FILE * output,
7681                                  xmlRelaxNGDefinePtr define);
7682 
7683 /**
7684  * xmlRelaxNGDumpDefines:
7685  * @output:  the file output
7686  * @defines:  a list of define structures
7687  *
7688  * Dump a RelaxNG structure back
7689  */
7690 static void
7691 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7692 {
7693     while (defines != NULL) {
7694         xmlRelaxNGDumpDefine(output, defines);
7695         defines = defines->next;
7696     }
7697 }
7698 
7699 /**
7700  * xmlRelaxNGDumpDefine:
7701  * @output:  the file output
7702  * @define:  a define structure
7703  *
7704  * Dump a RelaxNG structure back
7705  */
7706 static void
7707 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7708 {
7709     if (define == NULL)
7710         return;
7711     switch (define->type) {
7712         case XML_RELAXNG_EMPTY:
7713             fprintf(output, "<empty/>\n");
7714             break;
7715         case XML_RELAXNG_NOT_ALLOWED:
7716             fprintf(output, "<notAllowed/>\n");
7717             break;
7718         case XML_RELAXNG_TEXT:
7719             fprintf(output, "<text/>\n");
7720             break;
7721         case XML_RELAXNG_ELEMENT:
7722             fprintf(output, "<element>\n");
7723             if (define->name != NULL) {
7724                 fprintf(output, "<name");
7725                 if (define->ns != NULL)
7726                     fprintf(output, " ns=\"%s\"", define->ns);
7727                 fprintf(output, ">%s</name>\n", define->name);
7728             }
7729             xmlRelaxNGDumpDefines(output, define->attrs);
7730             xmlRelaxNGDumpDefines(output, define->content);
7731             fprintf(output, "</element>\n");
7732             break;
7733         case XML_RELAXNG_LIST:
7734             fprintf(output, "<list>\n");
7735             xmlRelaxNGDumpDefines(output, define->content);
7736             fprintf(output, "</list>\n");
7737             break;
7738         case XML_RELAXNG_ONEORMORE:
7739             fprintf(output, "<oneOrMore>\n");
7740             xmlRelaxNGDumpDefines(output, define->content);
7741             fprintf(output, "</oneOrMore>\n");
7742             break;
7743         case XML_RELAXNG_ZEROORMORE:
7744             fprintf(output, "<zeroOrMore>\n");
7745             xmlRelaxNGDumpDefines(output, define->content);
7746             fprintf(output, "</zeroOrMore>\n");
7747             break;
7748         case XML_RELAXNG_CHOICE:
7749             fprintf(output, "<choice>\n");
7750             xmlRelaxNGDumpDefines(output, define->content);
7751             fprintf(output, "</choice>\n");
7752             break;
7753         case XML_RELAXNG_GROUP:
7754             fprintf(output, "<group>\n");
7755             xmlRelaxNGDumpDefines(output, define->content);
7756             fprintf(output, "</group>\n");
7757             break;
7758         case XML_RELAXNG_INTERLEAVE:
7759             fprintf(output, "<interleave>\n");
7760             xmlRelaxNGDumpDefines(output, define->content);
7761             fprintf(output, "</interleave>\n");
7762             break;
7763         case XML_RELAXNG_OPTIONAL:
7764             fprintf(output, "<optional>\n");
7765             xmlRelaxNGDumpDefines(output, define->content);
7766             fprintf(output, "</optional>\n");
7767             break;
7768         case XML_RELAXNG_ATTRIBUTE:
7769             fprintf(output, "<attribute>\n");
7770             xmlRelaxNGDumpDefines(output, define->content);
7771             fprintf(output, "</attribute>\n");
7772             break;
7773         case XML_RELAXNG_DEF:
7774             fprintf(output, "<define");
7775             if (define->name != NULL)
7776                 fprintf(output, " name=\"%s\"", define->name);
7777             fprintf(output, ">\n");
7778             xmlRelaxNGDumpDefines(output, define->content);
7779             fprintf(output, "</define>\n");
7780             break;
7781         case XML_RELAXNG_REF:
7782             fprintf(output, "<ref");
7783             if (define->name != NULL)
7784                 fprintf(output, " name=\"%s\"", define->name);
7785             fprintf(output, ">\n");
7786             xmlRelaxNGDumpDefines(output, define->content);
7787             fprintf(output, "</ref>\n");
7788             break;
7789         case XML_RELAXNG_PARENTREF:
7790             fprintf(output, "<parentRef");
7791             if (define->name != NULL)
7792                 fprintf(output, " name=\"%s\"", define->name);
7793             fprintf(output, ">\n");
7794             xmlRelaxNGDumpDefines(output, define->content);
7795             fprintf(output, "</parentRef>\n");
7796             break;
7797         case XML_RELAXNG_EXTERNALREF:
7798             fprintf(output, "<externalRef>");
7799             xmlRelaxNGDumpDefines(output, define->content);
7800             fprintf(output, "</externalRef>\n");
7801             break;
7802         case XML_RELAXNG_DATATYPE:
7803         case XML_RELAXNG_VALUE:
7804             TODO break;
7805         case XML_RELAXNG_START:
7806         case XML_RELAXNG_EXCEPT:
7807         case XML_RELAXNG_PARAM:
7808             TODO break;
7809         case XML_RELAXNG_NOOP:
7810             xmlRelaxNGDumpDefines(output, define->content);
7811             break;
7812     }
7813 }
7814 
7815 /**
7816  * xmlRelaxNGDumpGrammar:
7817  * @output:  the file output
7818  * @grammar:  a grammar structure
7819  * @top:  is this a top grammar
7820  *
7821  * Dump a RelaxNG structure back
7822  */
7823 static void
7824 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7825 {
7826     if (grammar == NULL)
7827         return;
7828 
7829     fprintf(output, "<grammar");
7830     if (top)
7831         fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7832     switch (grammar->combine) {
7833         case XML_RELAXNG_COMBINE_UNDEFINED:
7834             break;
7835         case XML_RELAXNG_COMBINE_CHOICE:
7836             fprintf(output, " combine=\"choice\"");
7837             break;
7838         case XML_RELAXNG_COMBINE_INTERLEAVE:
7839             fprintf(output, " combine=\"interleave\"");
7840             break;
7841         default:
7842             fprintf(output, " <!-- invalid combine value -->");
7843     }
7844     fprintf(output, ">\n");
7845     if (grammar->start == NULL) {
7846         fprintf(output, " <!-- grammar had no start -->");
7847     } else {
7848         fprintf(output, "<start>\n");
7849         xmlRelaxNGDumpDefine(output, grammar->start);
7850         fprintf(output, "</start>\n");
7851     }
7852     /* TODO ? Dump the defines ? */
7853     fprintf(output, "</grammar>\n");
7854 }
7855 
7856 /**
7857  * xmlRelaxNGDump:
7858  * @output:  the file output
7859  * @schema:  a schema structure
7860  *
7861  * Dump a RelaxNG structure back
7862  */
7863 void
7864 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7865 {
7866     if (output == NULL)
7867         return;
7868     if (schema == NULL) {
7869         fprintf(output, "RelaxNG empty or failed to compile\n");
7870         return;
7871     }
7872     fprintf(output, "RelaxNG: ");
7873     if (schema->doc == NULL) {
7874         fprintf(output, "no document\n");
7875     } else if (schema->doc->URL != NULL) {
7876         fprintf(output, "%s\n", schema->doc->URL);
7877     } else {
7878         fprintf(output, "\n");
7879     }
7880     if (schema->topgrammar == NULL) {
7881         fprintf(output, "RelaxNG has no top grammar\n");
7882         return;
7883     }
7884     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7885 }
7886 
7887 /**
7888  * xmlRelaxNGDumpTree:
7889  * @output:  the file output
7890  * @schema:  a schema structure
7891  *
7892  * Dump the transformed RelaxNG tree.
7893  */
7894 void
7895 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7896 {
7897     if (output == NULL)
7898         return;
7899     if (schema == NULL) {
7900         fprintf(output, "RelaxNG empty or failed to compile\n");
7901         return;
7902     }
7903     if (schema->doc == NULL) {
7904         fprintf(output, "no document\n");
7905     } else {
7906         xmlDocDump(output, schema->doc);
7907     }
7908 }
7909 #endif /* LIBXML_OUTPUT_ENABLED */
7910 
7911 /************************************************************************
7912  *									*
7913  *		Validation of compiled content				*
7914  *									*
7915  ************************************************************************/
7916 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7917                                         xmlRelaxNGDefinePtr define);
7918 
7919 /**
7920  * xmlRelaxNGValidateCompiledCallback:
7921  * @exec:  the regular expression instance
7922  * @token:  the token which matched
7923  * @transdata:  callback data, the define for the subelement if available
7924  @ @inputdata:  callback data, the Relax NG validation context
7925  *
7926  * Handle the callback and if needed validate the element children.
7927  */
7928 static void
7929 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7930                                    const xmlChar * token,
7931                                    void *transdata, void *inputdata)
7932 {
7933     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7934     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7935     int ret;
7936 
7937 #ifdef DEBUG_COMPILE
7938     xmlGenericError(xmlGenericErrorContext,
7939                     "Compiled callback for: '%s'\n", token);
7940 #endif
7941     if (ctxt == NULL) {
7942         fprintf(stderr, "callback on %s missing context\n", token);
7943         return;
7944     }
7945     if (define == NULL) {
7946         if (token[0] == '#')
7947             return;
7948         fprintf(stderr, "callback on %s missing define\n", token);
7949         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7950             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7951         return;
7952     }
7953     if ((ctxt == NULL) || (define == NULL)) {
7954         fprintf(stderr, "callback on %s missing info\n", token);
7955         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7956             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7957         return;
7958     } else if (define->type != XML_RELAXNG_ELEMENT) {
7959         fprintf(stderr, "callback on %s define is not element\n", token);
7960         if (ctxt->errNo == XML_RELAXNG_OK)
7961             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7962         return;
7963     }
7964     ret = xmlRelaxNGValidateDefinition(ctxt, define);
7965     if (ret != 0)
7966         ctxt->perr = ret;
7967 }
7968 
7969 /**
7970  * xmlRelaxNGValidateCompiledContent:
7971  * @ctxt:  the RelaxNG validation context
7972  * @regexp:  the regular expression as compiled
7973  * @content:  list of children to test against the regexp
7974  *
7975  * Validate the content model of an element or start using the regexp
7976  *
7977  * Returns 0 in case of success, -1 in case of error.
7978  */
7979 static int
7980 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7981                                   xmlRegexpPtr regexp, xmlNodePtr content)
7982 {
7983     xmlRegExecCtxtPtr exec;
7984     xmlNodePtr cur;
7985     int ret = 0;
7986     int oldperr;
7987 
7988     if ((ctxt == NULL) || (regexp == NULL))
7989         return (-1);
7990     oldperr = ctxt->perr;
7991     exec = xmlRegNewExecCtxt(regexp,
7992                              xmlRelaxNGValidateCompiledCallback, ctxt);
7993     ctxt->perr = 0;
7994     cur = content;
7995     while (cur != NULL) {
7996         ctxt->state->seq = cur;
7997         switch (cur->type) {
7998             case XML_TEXT_NODE:
7999             case XML_CDATA_SECTION_NODE:
8000                 if (xmlIsBlankNode(cur))
8001                     break;
8002                 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
8003                 if (ret < 0) {
8004                     VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
8005                                cur->parent->name);
8006                 }
8007                 break;
8008             case XML_ELEMENT_NODE:
8009                 if (cur->ns != NULL) {
8010                     ret = xmlRegExecPushString2(exec, cur->name,
8011                                                 cur->ns->href, ctxt);
8012                 } else {
8013                     ret = xmlRegExecPushString(exec, cur->name, ctxt);
8014                 }
8015                 if (ret < 0) {
8016                     VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
8017                 }
8018                 break;
8019             default:
8020                 break;
8021         }
8022         if (ret < 0)
8023             break;
8024         /*
8025          * Switch to next element
8026          */
8027         cur = cur->next;
8028     }
8029     ret = xmlRegExecPushString(exec, NULL, NULL);
8030     if (ret == 1) {
8031         ret = 0;
8032         ctxt->state->seq = NULL;
8033     } else if (ret == 0) {
8034         /*
8035          * TODO: get some of the names needed to exit the current state of exec
8036          */
8037         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8038         ret = -1;
8039         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8040             xmlRelaxNGDumpValidError(ctxt);
8041     } else {
8042         ret = -1;
8043     }
8044     xmlRegFreeExecCtxt(exec);
8045     /*
8046      * There might be content model errors outside of the pure
8047      * regexp validation, e.g. for attribute values.
8048      */
8049     if ((ret == 0) && (ctxt->perr != 0)) {
8050         ret = ctxt->perr;
8051     }
8052     ctxt->perr = oldperr;
8053     return (ret);
8054 }
8055 
8056 /************************************************************************
8057  *									*
8058  *		Progressive validation of when possible			*
8059  *									*
8060  ************************************************************************/
8061 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8062                                            xmlRelaxNGDefinePtr defines);
8063 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
8064                                         int dolog);
8065 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
8066 
8067 /**
8068  * xmlRelaxNGElemPush:
8069  * @ctxt:  the validation context
8070  * @exec:  the regexp runtime for the new content model
8071  *
8072  * Push a new regexp for the current node content model on the stack
8073  *
8074  * Returns 0 in case of success and -1 in case of error.
8075  */
8076 static int
8077 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
8078 {
8079     if (ctxt->elemTab == NULL) {
8080         ctxt->elemMax = 10;
8081         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
8082                                                         sizeof
8083                                                         (xmlRegExecCtxtPtr));
8084         if (ctxt->elemTab == NULL) {
8085             xmlRngVErrMemory(ctxt, "validating\n");
8086             return (-1);
8087         }
8088     }
8089     if (ctxt->elemNr >= ctxt->elemMax) {
8090         ctxt->elemMax *= 2;
8091         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
8092                                                          ctxt->elemMax *
8093                                                          sizeof
8094                                                          (xmlRegExecCtxtPtr));
8095         if (ctxt->elemTab == NULL) {
8096             xmlRngVErrMemory(ctxt, "validating\n");
8097             return (-1);
8098         }
8099     }
8100     ctxt->elemTab[ctxt->elemNr++] = exec;
8101     ctxt->elem = exec;
8102     return (0);
8103 }
8104 
8105 /**
8106  * xmlRelaxNGElemPop:
8107  * @ctxt:  the validation context
8108  *
8109  * Pop the regexp of the current node content model from the stack
8110  *
8111  * Returns the exec or NULL if empty
8112  */
8113 static xmlRegExecCtxtPtr
8114 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
8115 {
8116     xmlRegExecCtxtPtr ret;
8117 
8118     if (ctxt->elemNr <= 0)
8119         return (NULL);
8120     ctxt->elemNr--;
8121     ret = ctxt->elemTab[ctxt->elemNr];
8122     ctxt->elemTab[ctxt->elemNr] = NULL;
8123     if (ctxt->elemNr > 0)
8124         ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
8125     else
8126         ctxt->elem = NULL;
8127     return (ret);
8128 }
8129 
8130 /**
8131  * xmlRelaxNGValidateProgressiveCallback:
8132  * @exec:  the regular expression instance
8133  * @token:  the token which matched
8134  * @transdata:  callback data, the define for the subelement if available
8135  @ @inputdata:  callback data, the Relax NG validation context
8136  *
8137  * Handle the callback and if needed validate the element children.
8138  * some of the in/out informations are passed via the context in @inputdata.
8139  */
8140 static void
8141 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8142                                       ATTRIBUTE_UNUSED,
8143                                       const xmlChar * token,
8144                                       void *transdata, void *inputdata)
8145 {
8146     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8147     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
8148     xmlRelaxNGValidStatePtr state, oldstate;
8149     xmlNodePtr node;
8150     int ret = 0, oldflags;
8151 
8152 #ifdef DEBUG_PROGRESSIVE
8153     xmlGenericError(xmlGenericErrorContext,
8154                     "Progressive callback for: '%s'\n", token);
8155 #endif
8156     if (ctxt == NULL) {
8157         fprintf(stderr, "callback on %s missing context\n", token);
8158         return;
8159     }
8160     node = ctxt->pnode;
8161     ctxt->pstate = 1;
8162     if (define == NULL) {
8163         if (token[0] == '#')
8164             return;
8165         fprintf(stderr, "callback on %s missing define\n", token);
8166         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8167             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8168         ctxt->pstate = -1;
8169         return;
8170     }
8171     if ((ctxt == NULL) || (define == NULL)) {
8172         fprintf(stderr, "callback on %s missing info\n", token);
8173         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8174             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8175         ctxt->pstate = -1;
8176         return;
8177     } else if (define->type != XML_RELAXNG_ELEMENT) {
8178         fprintf(stderr, "callback on %s define is not element\n", token);
8179         if (ctxt->errNo == XML_RELAXNG_OK)
8180             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8181         ctxt->pstate = -1;
8182         return;
8183     }
8184     if (node->type != XML_ELEMENT_NODE) {
8185         VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8186         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8187             xmlRelaxNGDumpValidError(ctxt);
8188         ctxt->pstate = -1;
8189         return;
8190     }
8191     if (define->contModel == NULL) {
8192         /*
8193          * this node cannot be validated in a streamable fashion
8194          */
8195 #ifdef DEBUG_PROGRESSIVE
8196         xmlGenericError(xmlGenericErrorContext,
8197                         "Element '%s' validation is not streamable\n",
8198                         token);
8199 #endif
8200         ctxt->pstate = 0;
8201         ctxt->pdef = define;
8202         return;
8203     }
8204     exec = xmlRegNewExecCtxt(define->contModel,
8205                              xmlRelaxNGValidateProgressiveCallback, ctxt);
8206     if (exec == NULL) {
8207         ctxt->pstate = -1;
8208         return;
8209     }
8210     xmlRelaxNGElemPush(ctxt, exec);
8211 
8212     /*
8213      * Validate the attributes part of the content.
8214      */
8215     state = xmlRelaxNGNewValidState(ctxt, node);
8216     if (state == NULL) {
8217         ctxt->pstate = -1;
8218         return;
8219     }
8220     oldstate = ctxt->state;
8221     ctxt->state = state;
8222     if (define->attrs != NULL) {
8223         ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8224         if (ret != 0) {
8225             ctxt->pstate = -1;
8226             VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8227         }
8228     }
8229     if (ctxt->state != NULL) {
8230         ctxt->state->seq = NULL;
8231         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8232         if (ret != 0) {
8233             ctxt->pstate = -1;
8234         }
8235         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8236     } else if (ctxt->states != NULL) {
8237         int tmp = -1, i;
8238 
8239         oldflags = ctxt->flags;
8240 
8241         for (i = 0; i < ctxt->states->nbState; i++) {
8242             state = ctxt->states->tabState[i];
8243             ctxt->state = state;
8244             ctxt->state->seq = NULL;
8245 
8246             if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8247                 tmp = 0;
8248                 break;
8249             }
8250         }
8251         if (tmp != 0) {
8252             /*
8253              * validation error, log the message for the "best" one
8254              */
8255             ctxt->flags |= FLAGS_IGNORABLE;
8256             xmlRelaxNGLogBestError(ctxt);
8257         }
8258         for (i = 0; i < ctxt->states->nbState; i++) {
8259             xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8260         }
8261         xmlRelaxNGFreeStates(ctxt, ctxt->states);
8262         ctxt->states = NULL;
8263         if ((ret == 0) && (tmp == -1))
8264             ctxt->pstate = -1;
8265         ctxt->flags = oldflags;
8266     }
8267     if (ctxt->pstate == -1) {
8268         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8269             xmlRelaxNGDumpValidError(ctxt);
8270         }
8271     }
8272     ctxt->state = oldstate;
8273 }
8274 
8275 /**
8276  * xmlRelaxNGValidatePushElement:
8277  * @ctxt:  the validation context
8278  * @doc:  a document instance
8279  * @elem:  an element instance
8280  *
8281  * Push a new element start on the RelaxNG validation stack.
8282  *
8283  * returns 1 if no validation problem was found or 0 if validating the
8284  *         element requires a full node, and -1 in case of error.
8285  */
8286 int
8287 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8288                               xmlDocPtr doc ATTRIBUTE_UNUSED,
8289                               xmlNodePtr elem)
8290 {
8291     int ret = 1;
8292 
8293     if ((ctxt == NULL) || (elem == NULL))
8294         return (-1);
8295 
8296 #ifdef DEBUG_PROGRESSIVE
8297     xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8298 #endif
8299     if (ctxt->elem == 0) {
8300         xmlRelaxNGPtr schema;
8301         xmlRelaxNGGrammarPtr grammar;
8302         xmlRegExecCtxtPtr exec;
8303         xmlRelaxNGDefinePtr define;
8304 
8305         schema = ctxt->schema;
8306         if (schema == NULL) {
8307             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8308             return (-1);
8309         }
8310         grammar = schema->topgrammar;
8311         if ((grammar == NULL) || (grammar->start == NULL)) {
8312             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8313             return (-1);
8314         }
8315         define = grammar->start;
8316         if (define->contModel == NULL) {
8317             ctxt->pdef = define;
8318             return (0);
8319         }
8320         exec = xmlRegNewExecCtxt(define->contModel,
8321                                  xmlRelaxNGValidateProgressiveCallback,
8322                                  ctxt);
8323         if (exec == NULL) {
8324             return (-1);
8325         }
8326         xmlRelaxNGElemPush(ctxt, exec);
8327     }
8328     ctxt->pnode = elem;
8329     ctxt->pstate = 0;
8330     if (elem->ns != NULL) {
8331         ret =
8332             xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8333                                   ctxt);
8334     } else {
8335         ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8336     }
8337     if (ret < 0) {
8338         VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8339     } else {
8340         if (ctxt->pstate == 0)
8341             ret = 0;
8342         else if (ctxt->pstate < 0)
8343             ret = -1;
8344         else
8345             ret = 1;
8346     }
8347 #ifdef DEBUG_PROGRESSIVE
8348     if (ret < 0)
8349         xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8350                         elem->name);
8351 #endif
8352     return (ret);
8353 }
8354 
8355 /**
8356  * xmlRelaxNGValidatePushCData:
8357  * @ctxt:  the RelaxNG validation context
8358  * @data:  some character data read
8359  * @len:  the length of the data
8360  *
8361  * check the CData parsed for validation in the current stack
8362  *
8363  * returns 1 if no validation problem was found or -1 otherwise
8364  */
8365 int
8366 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
8367                             const xmlChar * data, int len ATTRIBUTE_UNUSED)
8368 {
8369     int ret = 1;
8370 
8371     if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8372         return (-1);
8373 
8374 #ifdef DEBUG_PROGRESSIVE
8375     xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8376 #endif
8377 
8378     while (*data != 0) {
8379         if (!IS_BLANK_CH(*data))
8380             break;
8381         data++;
8382     }
8383     if (*data == 0)
8384         return (1);
8385 
8386     ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8387     if (ret < 0) {
8388         VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
8389 #ifdef DEBUG_PROGRESSIVE
8390         xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8391 #endif
8392 
8393         return (-1);
8394     }
8395     return (1);
8396 }
8397 
8398 /**
8399  * xmlRelaxNGValidatePopElement:
8400  * @ctxt:  the RelaxNG validation context
8401  * @doc:  a document instance
8402  * @elem:  an element instance
8403  *
8404  * Pop the element end from the RelaxNG validation stack.
8405  *
8406  * returns 1 if no validation problem was found or 0 otherwise
8407  */
8408 int
8409 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8410                              xmlDocPtr doc ATTRIBUTE_UNUSED,
8411                              xmlNodePtr elem)
8412 {
8413     int ret;
8414     xmlRegExecCtxtPtr exec;
8415 
8416     if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8417         return (-1);
8418 #ifdef DEBUG_PROGRESSIVE
8419     xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8420 #endif
8421     /*
8422      * verify that we reached a terminal state of the content model.
8423      */
8424     exec = xmlRelaxNGElemPop(ctxt);
8425     ret = xmlRegExecPushString(exec, NULL, NULL);
8426     if (ret == 0) {
8427         /*
8428          * TODO: get some of the names needed to exit the current state of exec
8429          */
8430         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8431         ret = -1;
8432     } else if (ret < 0) {
8433         ret = -1;
8434     } else {
8435         ret = 1;
8436     }
8437     xmlRegFreeExecCtxt(exec);
8438 #ifdef DEBUG_PROGRESSIVE
8439     if (ret < 0)
8440         xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8441                         elem->name);
8442 #endif
8443     return (ret);
8444 }
8445 
8446 /**
8447  * xmlRelaxNGValidateFullElement:
8448  * @ctxt:  the validation context
8449  * @doc:  a document instance
8450  * @elem:  an element instance
8451  *
8452  * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8453  * 0 and the content of the node has been expanded.
8454  *
8455  * returns 1 if no validation problem was found or -1 in case of error.
8456  */
8457 int
8458 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8459                               xmlDocPtr doc ATTRIBUTE_UNUSED,
8460                               xmlNodePtr elem)
8461 {
8462     int ret;
8463     xmlRelaxNGValidStatePtr state;
8464 
8465     if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8466         return (-1);
8467 #ifdef DEBUG_PROGRESSIVE
8468     xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8469 #endif
8470     state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8471     if (state == NULL) {
8472         return (-1);
8473     }
8474     state->seq = elem;
8475     ctxt->state = state;
8476     ctxt->errNo = XML_RELAXNG_OK;
8477     ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8478     if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8479         ret = -1;
8480     else
8481         ret = 1;
8482     xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8483     ctxt->state = NULL;
8484 #ifdef DEBUG_PROGRESSIVE
8485     if (ret < 0)
8486         xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8487                         elem->name);
8488 #endif
8489     return (ret);
8490 }
8491 
8492 /************************************************************************
8493  *									*
8494  *		Generic interpreted validation implementation		*
8495  *									*
8496  ************************************************************************/
8497 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8498                                    xmlRelaxNGDefinePtr define);
8499 
8500 /**
8501  * xmlRelaxNGSkipIgnored:
8502  * @ctxt:  a schema validation context
8503  * @node:  the top node.
8504  *
8505  * Skip ignorable nodes in that context
8506  *
8507  * Returns the new sibling or NULL in case of error.
8508  */
8509 static xmlNodePtr
8510 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8511                       xmlNodePtr node)
8512 {
8513     /*
8514      * TODO complete and handle entities
8515      */
8516     while ((node != NULL) &&
8517            ((node->type == XML_COMMENT_NODE) ||
8518             (node->type == XML_PI_NODE) ||
8519 	    (node->type == XML_XINCLUDE_START) ||
8520 	    (node->type == XML_XINCLUDE_END) ||
8521             (((node->type == XML_TEXT_NODE) ||
8522               (node->type == XML_CDATA_SECTION_NODE)) &&
8523              ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8524               (IS_BLANK_NODE(node)))))) {
8525         node = node->next;
8526     }
8527     return (node);
8528 }
8529 
8530 /**
8531  * xmlRelaxNGNormalize:
8532  * @ctxt:  a schema validation context
8533  * @str:  the string to normalize
8534  *
8535  * Implements the  normalizeWhiteSpace( s ) function from
8536  * section 6.2.9 of the spec
8537  *
8538  * Returns the new string or NULL in case of error.
8539  */
8540 static xmlChar *
8541 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8542 {
8543     xmlChar *ret, *p;
8544     const xmlChar *tmp;
8545     int len;
8546 
8547     if (str == NULL)
8548         return (NULL);
8549     tmp = str;
8550     while (*tmp != 0)
8551         tmp++;
8552     len = tmp - str;
8553 
8554     ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
8555     if (ret == NULL) {
8556         xmlRngVErrMemory(ctxt, "validating\n");
8557         return (NULL);
8558     }
8559     p = ret;
8560     while (IS_BLANK_CH(*str))
8561         str++;
8562     while (*str != 0) {
8563         if (IS_BLANK_CH(*str)) {
8564             while (IS_BLANK_CH(*str))
8565                 str++;
8566             if (*str == 0)
8567                 break;
8568             *p++ = ' ';
8569         } else
8570             *p++ = *str++;
8571     }
8572     *p = 0;
8573     return (ret);
8574 }
8575 
8576 /**
8577  * xmlRelaxNGValidateDatatype:
8578  * @ctxt:  a Relax-NG validation context
8579  * @value:  the string value
8580  * @type:  the datatype definition
8581  * @node:  the node
8582  *
8583  * Validate the given value against the dataype
8584  *
8585  * Returns 0 if the validation succeeded or an error code.
8586  */
8587 static int
8588 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8589                            const xmlChar * value,
8590                            xmlRelaxNGDefinePtr define, xmlNodePtr node)
8591 {
8592     int ret, tmp;
8593     xmlRelaxNGTypeLibraryPtr lib;
8594     void *result = NULL;
8595     xmlRelaxNGDefinePtr cur;
8596 
8597     if ((define == NULL) || (define->data == NULL)) {
8598         return (-1);
8599     }
8600     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8601     if (lib->check != NULL) {
8602         if ((define->attrs != NULL) &&
8603             (define->attrs->type == XML_RELAXNG_PARAM)) {
8604             ret =
8605                 lib->check(lib->data, define->name, value, &result, node);
8606         } else {
8607             ret = lib->check(lib->data, define->name, value, NULL, node);
8608         }
8609     } else
8610         ret = -1;
8611     if (ret < 0) {
8612         VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8613         if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8614             lib->freef(lib->data, result);
8615         return (-1);
8616     } else if (ret == 1) {
8617         ret = 0;
8618     } else if (ret == 2) {
8619         VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
8620     } else {
8621         VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8622         ret = -1;
8623     }
8624     cur = define->attrs;
8625     while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8626         if (lib->facet != NULL) {
8627             tmp = lib->facet(lib->data, define->name, cur->name,
8628                              cur->value, value, result);
8629             if (tmp != 0)
8630                 ret = -1;
8631         }
8632         cur = cur->next;
8633     }
8634     if ((ret == 0) && (define->content != NULL)) {
8635         const xmlChar *oldvalue, *oldendvalue;
8636 
8637         oldvalue = ctxt->state->value;
8638         oldendvalue = ctxt->state->endvalue;
8639         ctxt->state->value = (xmlChar *) value;
8640         ctxt->state->endvalue = NULL;
8641         ret = xmlRelaxNGValidateValue(ctxt, define->content);
8642         ctxt->state->value = (xmlChar *) oldvalue;
8643         ctxt->state->endvalue = (xmlChar *) oldendvalue;
8644     }
8645     if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8646         lib->freef(lib->data, result);
8647     return (ret);
8648 }
8649 
8650 /**
8651  * xmlRelaxNGNextValue:
8652  * @ctxt:  a Relax-NG validation context
8653  *
8654  * Skip to the next value when validating within a list
8655  *
8656  * Returns 0 if the operation succeeded or an error code.
8657  */
8658 static int
8659 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8660 {
8661     xmlChar *cur;
8662 
8663     cur = ctxt->state->value;
8664     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8665         ctxt->state->value = NULL;
8666         ctxt->state->endvalue = NULL;
8667         return (0);
8668     }
8669     while (*cur != 0)
8670         cur++;
8671     while ((cur != ctxt->state->endvalue) && (*cur == 0))
8672         cur++;
8673     if (cur == ctxt->state->endvalue)
8674         ctxt->state->value = NULL;
8675     else
8676         ctxt->state->value = cur;
8677     return (0);
8678 }
8679 
8680 /**
8681  * xmlRelaxNGValidateValueList:
8682  * @ctxt:  a Relax-NG validation context
8683  * @defines:  the list of definitions to verify
8684  *
8685  * Validate the given set of definitions for the current value
8686  *
8687  * Returns 0 if the validation succeeded or an error code.
8688  */
8689 static int
8690 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8691                             xmlRelaxNGDefinePtr defines)
8692 {
8693     int ret = 0;
8694 
8695     while (defines != NULL) {
8696         ret = xmlRelaxNGValidateValue(ctxt, defines);
8697         if (ret != 0)
8698             break;
8699         defines = defines->next;
8700     }
8701     return (ret);
8702 }
8703 
8704 /**
8705  * xmlRelaxNGValidateValue:
8706  * @ctxt:  a Relax-NG validation context
8707  * @define:  the definition to verify
8708  *
8709  * Validate the given definition for the current value
8710  *
8711  * Returns 0 if the validation succeeded or an error code.
8712  */
8713 static int
8714 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8715                         xmlRelaxNGDefinePtr define)
8716 {
8717     int ret = 0, oldflags;
8718     xmlChar *value;
8719 
8720     value = ctxt->state->value;
8721     switch (define->type) {
8722         case XML_RELAXNG_EMPTY:{
8723                 if ((value != NULL) && (value[0] != 0)) {
8724                     int idx = 0;
8725 
8726                     while (IS_BLANK_CH(value[idx]))
8727                         idx++;
8728                     if (value[idx] != 0)
8729                         ret = -1;
8730                 }
8731                 break;
8732             }
8733         case XML_RELAXNG_TEXT:
8734             break;
8735         case XML_RELAXNG_VALUE:{
8736                 if (!xmlStrEqual(value, define->value)) {
8737                     if (define->name != NULL) {
8738                         xmlRelaxNGTypeLibraryPtr lib;
8739 
8740                         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8741                         if ((lib != NULL) && (lib->comp != NULL)) {
8742                             ret = lib->comp(lib->data, define->name,
8743                                             define->value, define->node,
8744                                             (void *) define->attrs,
8745                                             value, ctxt->state->node);
8746                         } else
8747                             ret = -1;
8748                         if (ret < 0) {
8749                             VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8750                                        define->name);
8751                             return (-1);
8752                         } else if (ret == 1) {
8753                             ret = 0;
8754                         } else {
8755                             ret = -1;
8756                         }
8757                     } else {
8758                         xmlChar *nval, *nvalue;
8759 
8760                         /*
8761                          * TODO: trivial optimizations are possible by
8762                          * computing at compile-time
8763                          */
8764                         nval = xmlRelaxNGNormalize(ctxt, define->value);
8765                         nvalue = xmlRelaxNGNormalize(ctxt, value);
8766 
8767                         if ((nval == NULL) || (nvalue == NULL) ||
8768                             (!xmlStrEqual(nval, nvalue)))
8769                             ret = -1;
8770                         if (nval != NULL)
8771                             xmlFree(nval);
8772                         if (nvalue != NULL)
8773                             xmlFree(nvalue);
8774                     }
8775                 }
8776                 if (ret == 0)
8777                     xmlRelaxNGNextValue(ctxt);
8778                 break;
8779             }
8780         case XML_RELAXNG_DATATYPE:{
8781                 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8782                                                  ctxt->state->seq);
8783                 if (ret == 0)
8784                     xmlRelaxNGNextValue(ctxt);
8785 
8786                 break;
8787             }
8788         case XML_RELAXNG_CHOICE:{
8789                 xmlRelaxNGDefinePtr list = define->content;
8790                 xmlChar *oldvalue;
8791 
8792                 oldflags = ctxt->flags;
8793                 ctxt->flags |= FLAGS_IGNORABLE;
8794 
8795                 oldvalue = ctxt->state->value;
8796                 while (list != NULL) {
8797                     ret = xmlRelaxNGValidateValue(ctxt, list);
8798                     if (ret == 0) {
8799                         break;
8800                     }
8801                     ctxt->state->value = oldvalue;
8802                     list = list->next;
8803                 }
8804                 ctxt->flags = oldflags;
8805                 if (ret != 0) {
8806                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8807                         xmlRelaxNGDumpValidError(ctxt);
8808                 } else {
8809                     if (ctxt->errNr > 0)
8810                         xmlRelaxNGPopErrors(ctxt, 0);
8811                 }
8812                 break;
8813             }
8814         case XML_RELAXNG_LIST:{
8815                 xmlRelaxNGDefinePtr list = define->content;
8816                 xmlChar *oldvalue, *oldend, *val, *cur;
8817 
8818 #ifdef DEBUG_LIST
8819                 int nb_values = 0;
8820 #endif
8821 
8822                 oldvalue = ctxt->state->value;
8823                 oldend = ctxt->state->endvalue;
8824 
8825                 val = xmlStrdup(oldvalue);
8826                 if (val == NULL) {
8827                     val = xmlStrdup(BAD_CAST "");
8828                 }
8829                 if (val == NULL) {
8830                     VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8831                     return (-1);
8832                 }
8833                 cur = val;
8834                 while (*cur != 0) {
8835                     if (IS_BLANK_CH(*cur)) {
8836                         *cur = 0;
8837                         cur++;
8838 #ifdef DEBUG_LIST
8839                         nb_values++;
8840 #endif
8841                         while (IS_BLANK_CH(*cur))
8842                             *cur++ = 0;
8843                     } else
8844                         cur++;
8845                 }
8846 #ifdef DEBUG_LIST
8847                 xmlGenericError(xmlGenericErrorContext,
8848                                 "list value: '%s' found %d items\n",
8849                                 oldvalue, nb_values);
8850                 nb_values = 0;
8851 #endif
8852                 ctxt->state->endvalue = cur;
8853                 cur = val;
8854                 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8855                     cur++;
8856 
8857                 ctxt->state->value = cur;
8858 
8859                 while (list != NULL) {
8860                     if (ctxt->state->value == ctxt->state->endvalue)
8861                         ctxt->state->value = NULL;
8862                     ret = xmlRelaxNGValidateValue(ctxt, list);
8863                     if (ret != 0) {
8864 #ifdef DEBUG_LIST
8865                         xmlGenericError(xmlGenericErrorContext,
8866                                         "Failed to validate value: '%s' with %d rule\n",
8867                                         ctxt->state->value, nb_values);
8868 #endif
8869                         break;
8870                     }
8871 #ifdef DEBUG_LIST
8872                     nb_values++;
8873 #endif
8874                     list = list->next;
8875                 }
8876 
8877                 if ((ret == 0) && (ctxt->state->value != NULL) &&
8878                     (ctxt->state->value != ctxt->state->endvalue)) {
8879                     VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8880                                ctxt->state->value);
8881                     ret = -1;
8882                 }
8883                 xmlFree(val);
8884                 ctxt->state->value = oldvalue;
8885                 ctxt->state->endvalue = oldend;
8886                 break;
8887             }
8888         case XML_RELAXNG_ONEORMORE:
8889             ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8890             if (ret != 0) {
8891                 break;
8892             }
8893             /* Falls through. */
8894         case XML_RELAXNG_ZEROORMORE:{
8895                 xmlChar *cur, *temp;
8896 
8897                 if ((ctxt->state->value == NULL) ||
8898                     (*ctxt->state->value == 0)) {
8899                     ret = 0;
8900                     break;
8901                 }
8902                 oldflags = ctxt->flags;
8903                 ctxt->flags |= FLAGS_IGNORABLE;
8904                 cur = ctxt->state->value;
8905                 temp = NULL;
8906                 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8907                        (temp != cur)) {
8908                     temp = cur;
8909                     ret =
8910                         xmlRelaxNGValidateValueList(ctxt, define->content);
8911                     if (ret != 0) {
8912                         ctxt->state->value = temp;
8913                         ret = 0;
8914                         break;
8915                     }
8916                     cur = ctxt->state->value;
8917                 }
8918                 ctxt->flags = oldflags;
8919 		if (ctxt->errNr > 0)
8920 		    xmlRelaxNGPopErrors(ctxt, 0);
8921                 break;
8922             }
8923         case XML_RELAXNG_OPTIONAL:{
8924                 xmlChar *temp;
8925 
8926                 if ((ctxt->state->value == NULL) ||
8927                     (*ctxt->state->value == 0)) {
8928                     ret = 0;
8929                     break;
8930                 }
8931                 oldflags = ctxt->flags;
8932                 ctxt->flags |= FLAGS_IGNORABLE;
8933                 temp = ctxt->state->value;
8934                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8935                 ctxt->flags = oldflags;
8936                 if (ret != 0) {
8937                     ctxt->state->value = temp;
8938                     if (ctxt->errNr > 0)
8939                         xmlRelaxNGPopErrors(ctxt, 0);
8940                     ret = 0;
8941                     break;
8942                 }
8943 		if (ctxt->errNr > 0)
8944 		    xmlRelaxNGPopErrors(ctxt, 0);
8945                 break;
8946             }
8947         case XML_RELAXNG_EXCEPT:{
8948                 xmlRelaxNGDefinePtr list;
8949 
8950                 list = define->content;
8951                 while (list != NULL) {
8952                     ret = xmlRelaxNGValidateValue(ctxt, list);
8953                     if (ret == 0) {
8954                         ret = -1;
8955                         break;
8956                     } else
8957                         ret = 0;
8958                     list = list->next;
8959                 }
8960                 break;
8961             }
8962         case XML_RELAXNG_DEF:
8963         case XML_RELAXNG_GROUP:{
8964                 xmlRelaxNGDefinePtr list;
8965 
8966                 list = define->content;
8967                 while (list != NULL) {
8968                     ret = xmlRelaxNGValidateValue(ctxt, list);
8969                     if (ret != 0) {
8970                         ret = -1;
8971                         break;
8972                     } else
8973                         ret = 0;
8974                     list = list->next;
8975                 }
8976                 break;
8977             }
8978         case XML_RELAXNG_REF:
8979         case XML_RELAXNG_PARENTREF:
8980 	    if (define->content == NULL) {
8981                 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8982                 ret = -1;
8983 	    } else {
8984                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8985             }
8986             break;
8987         default:
8988             TODO ret = -1;
8989     }
8990     return (ret);
8991 }
8992 
8993 /**
8994  * xmlRelaxNGValidateValueContent:
8995  * @ctxt:  a Relax-NG validation context
8996  * @defines:  the list of definitions to verify
8997  *
8998  * Validate the given definitions for the current value
8999  *
9000  * Returns 0 if the validation succeeded or an error code.
9001  */
9002 static int
9003 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
9004                                xmlRelaxNGDefinePtr defines)
9005 {
9006     int ret = 0;
9007 
9008     while (defines != NULL) {
9009         ret = xmlRelaxNGValidateValue(ctxt, defines);
9010         if (ret != 0)
9011             break;
9012         defines = defines->next;
9013     }
9014     return (ret);
9015 }
9016 
9017 /**
9018  * xmlRelaxNGAttributeMatch:
9019  * @ctxt:  a Relax-NG validation context
9020  * @define:  the definition to check
9021  * @prop:  the attribute
9022  *
9023  * Check if the attribute matches the definition nameClass
9024  *
9025  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
9026  */
9027 static int
9028 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
9029                          xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
9030 {
9031     int ret;
9032 
9033     if (define->name != NULL) {
9034         if (!xmlStrEqual(define->name, prop->name))
9035             return (0);
9036     }
9037     if (define->ns != NULL) {
9038         if (define->ns[0] == 0) {
9039             if (prop->ns != NULL)
9040                 return (0);
9041         } else {
9042             if ((prop->ns == NULL) ||
9043                 (!xmlStrEqual(define->ns, prop->ns->href)))
9044                 return (0);
9045         }
9046     }
9047     if (define->nameClass == NULL)
9048         return (1);
9049     define = define->nameClass;
9050     if (define->type == XML_RELAXNG_EXCEPT) {
9051         xmlRelaxNGDefinePtr list;
9052 
9053         list = define->content;
9054         while (list != NULL) {
9055             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
9056             if (ret == 1)
9057                 return (0);
9058             if (ret < 0)
9059                 return (ret);
9060             list = list->next;
9061         }
9062     } else if (define->type == XML_RELAXNG_CHOICE) {
9063         xmlRelaxNGDefinePtr list;
9064 
9065         list = define->nameClass;
9066         while (list != NULL) {
9067             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
9068             if (ret == 1)
9069                 return (1);
9070             if (ret < 0)
9071                 return (ret);
9072             list = list->next;
9073         }
9074         return (0);
9075     } else {
9076     TODO}
9077     return (1);
9078 }
9079 
9080 /**
9081  * xmlRelaxNGValidateAttribute:
9082  * @ctxt:  a Relax-NG validation context
9083  * @define:  the definition to verify
9084  *
9085  * Validate the given attribute definition for that node
9086  *
9087  * Returns 0 if the validation succeeded or an error code.
9088  */
9089 static int
9090 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
9091                             xmlRelaxNGDefinePtr define)
9092 {
9093     int ret = 0, i;
9094     xmlChar *value, *oldvalue;
9095     xmlAttrPtr prop = NULL, tmp;
9096     xmlNodePtr oldseq;
9097 
9098     if (ctxt->state->nbAttrLeft <= 0)
9099         return (-1);
9100     if (define->name != NULL) {
9101         for (i = 0; i < ctxt->state->nbAttrs; i++) {
9102             tmp = ctxt->state->attrs[i];
9103             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
9104                 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
9105                      (tmp->ns == NULL)) ||
9106                     ((tmp->ns != NULL) &&
9107                      (xmlStrEqual(define->ns, tmp->ns->href)))) {
9108                     prop = tmp;
9109                     break;
9110                 }
9111             }
9112         }
9113         if (prop != NULL) {
9114             value = xmlNodeListGetString(prop->doc, prop->children, 1);
9115             oldvalue = ctxt->state->value;
9116             oldseq = ctxt->state->seq;
9117             ctxt->state->seq = (xmlNodePtr) prop;
9118             ctxt->state->value = value;
9119             ctxt->state->endvalue = NULL;
9120             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9121             if (ctxt->state->value != NULL)
9122                 value = ctxt->state->value;
9123             if (value != NULL)
9124                 xmlFree(value);
9125             ctxt->state->value = oldvalue;
9126             ctxt->state->seq = oldseq;
9127             if (ret == 0) {
9128                 /*
9129                  * flag the attribute as processed
9130                  */
9131                 ctxt->state->attrs[i] = NULL;
9132                 ctxt->state->nbAttrLeft--;
9133             }
9134         } else {
9135             ret = -1;
9136         }
9137 #ifdef DEBUG
9138         xmlGenericError(xmlGenericErrorContext,
9139                         "xmlRelaxNGValidateAttribute(%s): %d\n",
9140                         define->name, ret);
9141 #endif
9142     } else {
9143         for (i = 0; i < ctxt->state->nbAttrs; i++) {
9144             tmp = ctxt->state->attrs[i];
9145             if ((tmp != NULL) &&
9146                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
9147                 prop = tmp;
9148                 break;
9149             }
9150         }
9151         if (prop != NULL) {
9152             value = xmlNodeListGetString(prop->doc, prop->children, 1);
9153             oldvalue = ctxt->state->value;
9154             oldseq = ctxt->state->seq;
9155             ctxt->state->seq = (xmlNodePtr) prop;
9156             ctxt->state->value = value;
9157             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9158             if (ctxt->state->value != NULL)
9159                 value = ctxt->state->value;
9160             if (value != NULL)
9161                 xmlFree(value);
9162             ctxt->state->value = oldvalue;
9163             ctxt->state->seq = oldseq;
9164             if (ret == 0) {
9165                 /*
9166                  * flag the attribute as processed
9167                  */
9168                 ctxt->state->attrs[i] = NULL;
9169                 ctxt->state->nbAttrLeft--;
9170             }
9171         } else {
9172             ret = -1;
9173         }
9174 #ifdef DEBUG
9175         if (define->ns != NULL) {
9176             xmlGenericError(xmlGenericErrorContext,
9177                             "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9178                             define->ns, ret);
9179         } else {
9180             xmlGenericError(xmlGenericErrorContext,
9181                             "xmlRelaxNGValidateAttribute(anyName): %d\n",
9182                             ret);
9183         }
9184 #endif
9185     }
9186 
9187     return (ret);
9188 }
9189 
9190 /**
9191  * xmlRelaxNGValidateAttributeList:
9192  * @ctxt:  a Relax-NG validation context
9193  * @define:  the list of definition to verify
9194  *
9195  * Validate the given node against the list of attribute definitions
9196  *
9197  * Returns 0 if the validation succeeded or an error code.
9198  */
9199 static int
9200 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
9201                                 xmlRelaxNGDefinePtr defines)
9202 {
9203     int ret = 0, res;
9204     int needmore = 0;
9205     xmlRelaxNGDefinePtr cur;
9206 
9207     cur = defines;
9208     while (cur != NULL) {
9209         if (cur->type == XML_RELAXNG_ATTRIBUTE) {
9210             if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9211                 ret = -1;
9212         } else
9213             needmore = 1;
9214         cur = cur->next;
9215     }
9216     if (!needmore)
9217         return (ret);
9218     cur = defines;
9219     while (cur != NULL) {
9220         if (cur->type != XML_RELAXNG_ATTRIBUTE) {
9221             if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9222                 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9223                 if (res < 0)
9224                     ret = -1;
9225             } else {
9226                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9227                 return (-1);
9228             }
9229             if (res == -1)      /* continues on -2 */
9230                 break;
9231         }
9232         cur = cur->next;
9233     }
9234 
9235     return (ret);
9236 }
9237 
9238 /**
9239  * xmlRelaxNGNodeMatchesList:
9240  * @node:  the node
9241  * @list:  a NULL terminated array of definitions
9242  *
9243  * Check if a node can be matched by one of the definitions
9244  *
9245  * Returns 1 if matches 0 otherwise
9246  */
9247 static int
9248 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9249 {
9250     xmlRelaxNGDefinePtr cur;
9251     int i = 0, tmp;
9252 
9253     if ((node == NULL) || (list == NULL))
9254         return (0);
9255 
9256     cur = list[i++];
9257     while (cur != NULL) {
9258         if ((node->type == XML_ELEMENT_NODE) &&
9259             (cur->type == XML_RELAXNG_ELEMENT)) {
9260             tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9261             if (tmp == 1)
9262                 return (1);
9263         } else if (((node->type == XML_TEXT_NODE) ||
9264                     (node->type == XML_CDATA_SECTION_NODE)) &&
9265                    (cur->type == XML_RELAXNG_TEXT)) {
9266             return (1);
9267         }
9268         cur = list[i++];
9269     }
9270     return (0);
9271 }
9272 
9273 /**
9274  * xmlRelaxNGValidateInterleave:
9275  * @ctxt:  a Relax-NG validation context
9276  * @define:  the definition to verify
9277  *
9278  * Validate an interleave definition for a node.
9279  *
9280  * Returns 0 if the validation succeeded or an error code.
9281  */
9282 static int
9283 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9284                              xmlRelaxNGDefinePtr define)
9285 {
9286     int ret = 0, i, nbgroups;
9287     int errNr = ctxt->errNr;
9288     int oldflags;
9289 
9290     xmlRelaxNGValidStatePtr oldstate;
9291     xmlRelaxNGPartitionPtr partitions;
9292     xmlRelaxNGInterleaveGroupPtr group = NULL;
9293     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9294     xmlNodePtr *list = NULL, *lasts = NULL;
9295 
9296     if (define->data != NULL) {
9297         partitions = (xmlRelaxNGPartitionPtr) define->data;
9298         nbgroups = partitions->nbgroups;
9299     } else {
9300         VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9301         return (-1);
9302     }
9303     /*
9304      * Optimizations for MIXED
9305      */
9306     oldflags = ctxt->flags;
9307     if (define->dflags & IS_MIXED) {
9308         ctxt->flags |= FLAGS_MIXED_CONTENT;
9309         if (nbgroups == 2) {
9310             /*
9311              * this is a pure <mixed> case
9312              */
9313             if (ctxt->state != NULL)
9314                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9315                                                          ctxt->state->seq);
9316             if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9317                 ret = xmlRelaxNGValidateDefinition(ctxt,
9318                                                    partitions->groups[1]->
9319                                                    rule);
9320             else
9321                 ret = xmlRelaxNGValidateDefinition(ctxt,
9322                                                    partitions->groups[0]->
9323                                                    rule);
9324             if (ret == 0) {
9325                 if (ctxt->state != NULL)
9326                     ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9327                                                              ctxt->state->
9328                                                              seq);
9329             }
9330             ctxt->flags = oldflags;
9331             return (ret);
9332         }
9333     }
9334 
9335     /*
9336      * Build arrays to store the first and last node of the chain
9337      * pertaining to each group
9338      */
9339     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9340     if (list == NULL) {
9341         xmlRngVErrMemory(ctxt, "validating\n");
9342         return (-1);
9343     }
9344     memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9345     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9346     if (lasts == NULL) {
9347         xmlRngVErrMemory(ctxt, "validating\n");
9348         return (-1);
9349     }
9350     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9351 
9352     /*
9353      * Walk the sequence of children finding the right group and
9354      * sorting them in sequences.
9355      */
9356     cur = ctxt->state->seq;
9357     cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9358     start = cur;
9359     while (cur != NULL) {
9360         ctxt->state->seq = cur;
9361         if ((partitions->triage != NULL) &&
9362             (partitions->flags & IS_DETERMINIST)) {
9363             void *tmp = NULL;
9364 
9365             if ((cur->type == XML_TEXT_NODE) ||
9366                 (cur->type == XML_CDATA_SECTION_NODE)) {
9367                 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9368                                      NULL);
9369             } else if (cur->type == XML_ELEMENT_NODE) {
9370                 if (cur->ns != NULL) {
9371                     tmp = xmlHashLookup2(partitions->triage, cur->name,
9372                                          cur->ns->href);
9373                     if (tmp == NULL)
9374                         tmp = xmlHashLookup2(partitions->triage,
9375                                              BAD_CAST "#any",
9376                                              cur->ns->href);
9377                 } else
9378                     tmp =
9379                         xmlHashLookup2(partitions->triage, cur->name,
9380                                        NULL);
9381                 if (tmp == NULL)
9382                     tmp =
9383                         xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9384                                        NULL);
9385             }
9386 
9387             if (tmp == NULL) {
9388                 i = nbgroups;
9389             } else {
9390                 i = ((ptrdiff_t) tmp) - 1;
9391                 if (partitions->flags & IS_NEEDCHECK) {
9392                     group = partitions->groups[i];
9393                     if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9394                         i = nbgroups;
9395                 }
9396             }
9397         } else {
9398             for (i = 0; i < nbgroups; i++) {
9399                 group = partitions->groups[i];
9400                 if (group == NULL)
9401                     continue;
9402                 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9403                     break;
9404             }
9405         }
9406         /*
9407          * We break as soon as an element not matched is found
9408          */
9409         if (i >= nbgroups) {
9410             break;
9411         }
9412         if (lasts[i] != NULL) {
9413             lasts[i]->next = cur;
9414             lasts[i] = cur;
9415         } else {
9416             list[i] = cur;
9417             lasts[i] = cur;
9418         }
9419         if (cur->next != NULL)
9420             lastchg = cur->next;
9421         else
9422             lastchg = cur;
9423         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9424     }
9425     if (ret != 0) {
9426         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9427         ret = -1;
9428         goto done;
9429     }
9430     lastelem = cur;
9431     oldstate = ctxt->state;
9432     for (i = 0; i < nbgroups; i++) {
9433         ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9434 	if (ctxt->state == NULL) {
9435 	    ret = -1;
9436 	    break;
9437 	}
9438         group = partitions->groups[i];
9439         if (lasts[i] != NULL) {
9440             last = lasts[i]->next;
9441             lasts[i]->next = NULL;
9442         }
9443         ctxt->state->seq = list[i];
9444         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9445         if (ret != 0)
9446             break;
9447         if (ctxt->state != NULL) {
9448             cur = ctxt->state->seq;
9449             cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9450             xmlRelaxNGFreeValidState(ctxt, oldstate);
9451             oldstate = ctxt->state;
9452             ctxt->state = NULL;
9453             if (cur != NULL) {
9454                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9455                 ret = -1;
9456                 ctxt->state = oldstate;
9457                 goto done;
9458             }
9459         } else if (ctxt->states != NULL) {
9460             int j;
9461             int found = 0;
9462 	    int best = -1;
9463 	    int lowattr = -1;
9464 
9465 	    /*
9466 	     * PBM: what happen if there is attributes checks in the interleaves
9467 	     */
9468 
9469             for (j = 0; j < ctxt->states->nbState; j++) {
9470                 cur = ctxt->states->tabState[j]->seq;
9471                 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9472                 if (cur == NULL) {
9473 		    if (found == 0) {
9474 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9475 			best = j;
9476 		    }
9477                     found = 1;
9478 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9479 		        /* try  to keep the latest one to mach old heuristic */
9480 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9481 			best = j;
9482 		    }
9483                     if (lowattr == 0)
9484 		        break;
9485                 } else if (found == 0) {
9486                     if (lowattr == -1) {
9487 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9488 			best = j;
9489 		    } else
9490 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr)  {
9491 		        /* try  to keep the latest one to mach old heuristic */
9492 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9493 			best = j;
9494 		    }
9495 		}
9496             }
9497 	    /*
9498 	     * BIG PBM: here we pick only one restarting point :-(
9499 	     */
9500             if (ctxt->states->nbState > 0) {
9501                 xmlRelaxNGFreeValidState(ctxt, oldstate);
9502 		if (best != -1) {
9503 		    oldstate = ctxt->states->tabState[best];
9504 		    ctxt->states->tabState[best] = NULL;
9505 		} else {
9506 		    oldstate =
9507 			ctxt->states->tabState[ctxt->states->nbState - 1];
9508                     ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
9509                     ctxt->states->nbState--;
9510 		}
9511             }
9512             for (j = 0; j < ctxt->states->nbState ; j++) {
9513                 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9514             }
9515             xmlRelaxNGFreeStates(ctxt, ctxt->states);
9516             ctxt->states = NULL;
9517             if (found == 0) {
9518                 if (cur == NULL) {
9519 		    VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
9520 			       (const xmlChar *) "noname");
9521                 } else {
9522                     VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9523                 }
9524                 ret = -1;
9525                 ctxt->state = oldstate;
9526                 goto done;
9527             }
9528         } else {
9529             ret = -1;
9530             break;
9531         }
9532         if (lasts[i] != NULL) {
9533             lasts[i]->next = last;
9534         }
9535     }
9536     if (ctxt->state != NULL)
9537         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9538     ctxt->state = oldstate;
9539     ctxt->state->seq = lastelem;
9540     if (ret != 0) {
9541         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9542         ret = -1;
9543         goto done;
9544     }
9545 
9546   done:
9547     ctxt->flags = oldflags;
9548     /*
9549      * builds the next links chain from the prev one
9550      */
9551     cur = lastchg;
9552     while (cur != NULL) {
9553         if ((cur == start) || (cur->prev == NULL))
9554             break;
9555         cur->prev->next = cur;
9556         cur = cur->prev;
9557     }
9558     if (ret == 0) {
9559         if (ctxt->errNr > errNr)
9560             xmlRelaxNGPopErrors(ctxt, errNr);
9561     }
9562 
9563     xmlFree(list);
9564     xmlFree(lasts);
9565     return (ret);
9566 }
9567 
9568 /**
9569  * xmlRelaxNGValidateDefinitionList:
9570  * @ctxt:  a Relax-NG validation context
9571  * @define:  the list of definition to verify
9572  *
9573  * Validate the given node content against the (list) of definitions
9574  *
9575  * Returns 0 if the validation succeeded or an error code.
9576  */
9577 static int
9578 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9579                                  xmlRelaxNGDefinePtr defines)
9580 {
9581     int ret = 0, res;
9582 
9583 
9584     if (defines == NULL) {
9585         VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9586                    BAD_CAST "NULL definition list");
9587         return (-1);
9588     }
9589     while (defines != NULL) {
9590         if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9591             res = xmlRelaxNGValidateDefinition(ctxt, defines);
9592             if (res < 0)
9593                 ret = -1;
9594         } else {
9595             VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9596             return (-1);
9597         }
9598         if (res == -1)          /* continues on -2 */
9599             break;
9600         defines = defines->next;
9601     }
9602 
9603     return (ret);
9604 }
9605 
9606 /**
9607  * xmlRelaxNGElementMatch:
9608  * @ctxt:  a Relax-NG validation context
9609  * @define:  the definition to check
9610  * @elem:  the element
9611  *
9612  * Check if the element matches the definition nameClass
9613  *
9614  * Returns 1 if the element matches, 0 if no, or -1 in case of error
9615  */
9616 static int
9617 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9618                        xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9619 {
9620     int ret = 0, oldflags = 0;
9621 
9622     if (define->name != NULL) {
9623         if (!xmlStrEqual(elem->name, define->name)) {
9624             VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9625             return (0);
9626         }
9627     }
9628     if ((define->ns != NULL) && (define->ns[0] != 0)) {
9629         if (elem->ns == NULL) {
9630             VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9631             return (0);
9632         } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9633             VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9634                        elem->name, define->ns);
9635             return (0);
9636         }
9637     } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9638                (define->name == NULL)) {
9639         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9640         return (0);
9641     } else if ((elem->ns != NULL) && (define->name != NULL)) {
9642         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9643         return (0);
9644     }
9645 
9646     if (define->nameClass == NULL)
9647         return (1);
9648 
9649     define = define->nameClass;
9650     if (define->type == XML_RELAXNG_EXCEPT) {
9651         xmlRelaxNGDefinePtr list;
9652 
9653         if (ctxt != NULL) {
9654             oldflags = ctxt->flags;
9655             ctxt->flags |= FLAGS_IGNORABLE;
9656         }
9657 
9658         list = define->content;
9659         while (list != NULL) {
9660             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9661             if (ret == 1) {
9662                 if (ctxt != NULL)
9663                     ctxt->flags = oldflags;
9664                 return (0);
9665             }
9666             if (ret < 0) {
9667                 if (ctxt != NULL)
9668                     ctxt->flags = oldflags;
9669                 return (ret);
9670             }
9671             list = list->next;
9672         }
9673         ret = 1;
9674         if (ctxt != NULL) {
9675             ctxt->flags = oldflags;
9676         }
9677     } else if (define->type == XML_RELAXNG_CHOICE) {
9678         xmlRelaxNGDefinePtr list;
9679 
9680         if (ctxt != NULL) {
9681             oldflags = ctxt->flags;
9682             ctxt->flags |= FLAGS_IGNORABLE;
9683         }
9684 
9685         list = define->nameClass;
9686         while (list != NULL) {
9687             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9688             if (ret == 1) {
9689                 if (ctxt != NULL)
9690                     ctxt->flags = oldflags;
9691                 return (1);
9692             }
9693             if (ret < 0) {
9694                 if (ctxt != NULL)
9695                     ctxt->flags = oldflags;
9696                 return (ret);
9697             }
9698             list = list->next;
9699         }
9700         if (ctxt != NULL) {
9701             if (ret != 0) {
9702                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9703                     xmlRelaxNGDumpValidError(ctxt);
9704             } else {
9705                 if (ctxt->errNr > 0)
9706                     xmlRelaxNGPopErrors(ctxt, 0);
9707             }
9708         }
9709         ret = 0;
9710         if (ctxt != NULL) {
9711             ctxt->flags = oldflags;
9712         }
9713     } else {
9714         TODO ret = -1;
9715     }
9716     return (ret);
9717 }
9718 
9719 /**
9720  * xmlRelaxNGBestState:
9721  * @ctxt:  a Relax-NG validation context
9722  *
9723  * Find the "best" state in the ctxt->states list of states to report
9724  * errors about. I.e. a state with no element left in the child list
9725  * or the one with the less attributes left.
9726  * This is called only if a falidation error was detected
9727  *
9728  * Returns the index of the "best" state or -1 in case of error
9729  */
9730 static int
9731 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9732 {
9733     xmlRelaxNGValidStatePtr state;
9734     int i, tmp;
9735     int best = -1;
9736     int value = 1000000;
9737 
9738     if ((ctxt == NULL) || (ctxt->states == NULL) ||
9739         (ctxt->states->nbState <= 0))
9740         return (-1);
9741 
9742     for (i = 0; i < ctxt->states->nbState; i++) {
9743         state = ctxt->states->tabState[i];
9744         if (state == NULL)
9745             continue;
9746         if (state->seq != NULL) {
9747             if ((best == -1) || (value > 100000)) {
9748                 value = 100000;
9749                 best = i;
9750             }
9751         } else {
9752             tmp = state->nbAttrLeft;
9753             if ((best == -1) || (value > tmp)) {
9754                 value = tmp;
9755                 best = i;
9756             }
9757         }
9758     }
9759     return (best);
9760 }
9761 
9762 /**
9763  * xmlRelaxNGLogBestError:
9764  * @ctxt:  a Relax-NG validation context
9765  *
9766  * Find the "best" state in the ctxt->states list of states to report
9767  * errors about and log it.
9768  */
9769 static void
9770 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9771 {
9772     int best;
9773 
9774     if ((ctxt == NULL) || (ctxt->states == NULL) ||
9775         (ctxt->states->nbState <= 0))
9776         return;
9777 
9778     best = xmlRelaxNGBestState(ctxt);
9779     if ((best >= 0) && (best < ctxt->states->nbState)) {
9780         ctxt->state = ctxt->states->tabState[best];
9781 
9782         xmlRelaxNGValidateElementEnd(ctxt, 1);
9783     }
9784 }
9785 
9786 /**
9787  * xmlRelaxNGValidateElementEnd:
9788  * @ctxt:  a Relax-NG validation context
9789  * @dolog:  indicate that error logging should be done
9790  *
9791  * Validate the end of the element, implements check that
9792  * there is nothing left not consumed in the element content
9793  * or in the attribute list.
9794  *
9795  * Returns 0 if the validation succeeded or an error code.
9796  */
9797 static int
9798 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
9799 {
9800     int i;
9801     xmlRelaxNGValidStatePtr state;
9802 
9803     state = ctxt->state;
9804     if (state->seq != NULL) {
9805         state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9806         if (state->seq != NULL) {
9807             if (dolog) {
9808                 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9809                            state->node->name, state->seq->name);
9810             }
9811             return (-1);
9812         }
9813     }
9814     for (i = 0; i < state->nbAttrs; i++) {
9815         if (state->attrs[i] != NULL) {
9816             if (dolog) {
9817                 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9818                            state->attrs[i]->name, state->node->name);
9819             }
9820             return (-1 - i);
9821         }
9822     }
9823     return (0);
9824 }
9825 
9826 /**
9827  * xmlRelaxNGValidateState:
9828  * @ctxt:  a Relax-NG validation context
9829  * @define:  the definition to verify
9830  *
9831  * Validate the current state against the definition
9832  *
9833  * Returns 0 if the validation succeeded or an error code.
9834  */
9835 static int
9836 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9837                         xmlRelaxNGDefinePtr define)
9838 {
9839     xmlNodePtr node;
9840     int ret = 0, i, tmp, oldflags, errNr;
9841     xmlRelaxNGValidStatePtr oldstate = NULL, state;
9842 
9843     if (define == NULL) {
9844         VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9845         return (-1);
9846     }
9847 
9848     if (ctxt->state != NULL) {
9849         node = ctxt->state->seq;
9850     } else {
9851         node = NULL;
9852     }
9853 #ifdef DEBUG
9854     for (i = 0; i < ctxt->depth; i++)
9855         xmlGenericError(xmlGenericErrorContext, " ");
9856     xmlGenericError(xmlGenericErrorContext,
9857                     "Start validating %s ", xmlRelaxNGDefName(define));
9858     if (define->name != NULL)
9859         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
9860     if ((node != NULL) && (node->name != NULL))
9861         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
9862     else
9863         xmlGenericError(xmlGenericErrorContext, "\n");
9864 #endif
9865     ctxt->depth++;
9866     switch (define->type) {
9867         case XML_RELAXNG_EMPTY:
9868             xmlRelaxNGSkipIgnored(ctxt, node);
9869             ret = 0;
9870             break;
9871         case XML_RELAXNG_NOT_ALLOWED:
9872             ret = -1;
9873             break;
9874         case XML_RELAXNG_TEXT:
9875             while ((node != NULL) &&
9876                    ((node->type == XML_TEXT_NODE) ||
9877                     (node->type == XML_COMMENT_NODE) ||
9878                     (node->type == XML_PI_NODE) ||
9879                     (node->type == XML_CDATA_SECTION_NODE)))
9880                 node = node->next;
9881             ctxt->state->seq = node;
9882             break;
9883         case XML_RELAXNG_ELEMENT:
9884             errNr = ctxt->errNr;
9885             node = xmlRelaxNGSkipIgnored(ctxt, node);
9886             if (node == NULL) {
9887                 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9888                 ret = -1;
9889                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9890                     xmlRelaxNGDumpValidError(ctxt);
9891                 break;
9892             }
9893             if (node->type != XML_ELEMENT_NODE) {
9894                 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9895                 ret = -1;
9896                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9897                     xmlRelaxNGDumpValidError(ctxt);
9898                 break;
9899             }
9900             /*
9901              * This node was already validated successfully against
9902              * this definition.
9903              */
9904             if (node->psvi == define) {
9905                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9906                 if (ctxt->errNr > errNr)
9907                     xmlRelaxNGPopErrors(ctxt, errNr);
9908                 if (ctxt->errNr != 0) {
9909                     while ((ctxt->err != NULL) &&
9910                            (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9911                              && (xmlStrEqual(ctxt->err->arg2, node->name)))
9912                             ||
9913                             ((ctxt->err->err ==
9914                               XML_RELAXNG_ERR_ELEMEXTRANS)
9915                              && (xmlStrEqual(ctxt->err->arg1, node->name)))
9916                             || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9917                             || (ctxt->err->err ==
9918                                 XML_RELAXNG_ERR_NOTELEM)))
9919                         xmlRelaxNGValidErrorPop(ctxt);
9920                 }
9921                 break;
9922             }
9923 
9924             ret = xmlRelaxNGElementMatch(ctxt, define, node);
9925             if (ret <= 0) {
9926                 ret = -1;
9927                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9928                     xmlRelaxNGDumpValidError(ctxt);
9929                 break;
9930             }
9931             ret = 0;
9932             if (ctxt->errNr != 0) {
9933                 if (ctxt->errNr > errNr)
9934                     xmlRelaxNGPopErrors(ctxt, errNr);
9935                 while ((ctxt->err != NULL) &&
9936                        (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9937                          (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9938                         ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9939                          (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9940                         (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9941                         (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9942                     xmlRelaxNGValidErrorPop(ctxt);
9943             }
9944             errNr = ctxt->errNr;
9945 
9946             oldflags = ctxt->flags;
9947             if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9948                 ctxt->flags -= FLAGS_MIXED_CONTENT;
9949             }
9950             state = xmlRelaxNGNewValidState(ctxt, node);
9951             if (state == NULL) {
9952                 ret = -1;
9953                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9954                     xmlRelaxNGDumpValidError(ctxt);
9955                 break;
9956             }
9957 
9958             oldstate = ctxt->state;
9959             ctxt->state = state;
9960             if (define->attrs != NULL) {
9961                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9962                 if (tmp != 0) {
9963                     ret = -1;
9964                     VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9965                 }
9966             }
9967             if (define->contModel != NULL) {
9968                 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9969                 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9970                 xmlNodePtr nseq;
9971 
9972                 nstate = xmlRelaxNGNewValidState(ctxt, node);
9973                 ctxt->state = nstate;
9974                 ctxt->states = NULL;
9975 
9976                 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9977                                                         define->contModel,
9978                                                         ctxt->state->seq);
9979                 nseq = ctxt->state->seq;
9980                 ctxt->state = tmpstate;
9981                 ctxt->states = tmpstates;
9982                 xmlRelaxNGFreeValidState(ctxt, nstate);
9983 
9984 #ifdef DEBUG_COMPILE
9985                 xmlGenericError(xmlGenericErrorContext,
9986                                 "Validating content of '%s' : %d\n",
9987                                 define->name, tmp);
9988 #endif
9989                 if (tmp != 0)
9990                     ret = -1;
9991 
9992                 if (ctxt->states != NULL) {
9993                     tmp = -1;
9994 
9995                     for (i = 0; i < ctxt->states->nbState; i++) {
9996                         state = ctxt->states->tabState[i];
9997                         ctxt->state = state;
9998                         ctxt->state->seq = nseq;
9999 
10000                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
10001                             tmp = 0;
10002                             break;
10003                         }
10004                     }
10005                     if (tmp != 0) {
10006                         /*
10007                          * validation error, log the message for the "best" one
10008                          */
10009                         ctxt->flags |= FLAGS_IGNORABLE;
10010                         xmlRelaxNGLogBestError(ctxt);
10011                     }
10012                     for (i = 0; i < ctxt->states->nbState; i++) {
10013                         xmlRelaxNGFreeValidState(ctxt,
10014                                                  ctxt->states->
10015                                                  tabState[i]);
10016                     }
10017                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10018                     ctxt->flags = oldflags;
10019                     ctxt->states = NULL;
10020                     if ((ret == 0) && (tmp == -1))
10021                         ret = -1;
10022                 } else {
10023                     state = ctxt->state;
10024 		    if (ctxt->state != NULL)
10025 			ctxt->state->seq = nseq;
10026                     if (ret == 0)
10027                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10028                     xmlRelaxNGFreeValidState(ctxt, state);
10029                 }
10030             } else {
10031                 if (define->content != NULL) {
10032                     tmp = xmlRelaxNGValidateDefinitionList(ctxt,
10033                                                            define->
10034                                                            content);
10035                     if (tmp != 0) {
10036                         ret = -1;
10037                         if (ctxt->state == NULL) {
10038                             ctxt->state = oldstate;
10039                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10040                                        node->name);
10041                             ctxt->state = NULL;
10042                         } else {
10043                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10044                                        node->name);
10045                         }
10046 
10047                     }
10048                 }
10049                 if (ctxt->states != NULL) {
10050                     tmp = -1;
10051 
10052                     for (i = 0; i < ctxt->states->nbState; i++) {
10053                         state = ctxt->states->tabState[i];
10054                         ctxt->state = state;
10055 
10056                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
10057                             tmp = 0;
10058                             break;
10059                         }
10060                     }
10061                     if (tmp != 0) {
10062                         /*
10063                          * validation error, log the message for the "best" one
10064                          */
10065                         ctxt->flags |= FLAGS_IGNORABLE;
10066                         xmlRelaxNGLogBestError(ctxt);
10067                     }
10068                     for (i = 0; i < ctxt->states->nbState; i++) {
10069                         xmlRelaxNGFreeValidState(ctxt,
10070                                                  ctxt->states->tabState[i]);
10071                         ctxt->states->tabState[i] = NULL;
10072                     }
10073                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10074                     ctxt->flags = oldflags;
10075                     ctxt->states = NULL;
10076                     if ((ret == 0) && (tmp == -1))
10077                         ret = -1;
10078                 } else {
10079                     state = ctxt->state;
10080                     if (ret == 0)
10081                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10082                     xmlRelaxNGFreeValidState(ctxt, state);
10083                 }
10084             }
10085             if (ret == 0) {
10086                 node->psvi = define;
10087             }
10088             ctxt->flags = oldflags;
10089             ctxt->state = oldstate;
10090             if (oldstate != NULL)
10091                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
10092             if (ret != 0) {
10093                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10094                     xmlRelaxNGDumpValidError(ctxt);
10095                     ret = 0;
10096 #if 0
10097                 } else {
10098                     ret = -2;
10099 #endif
10100                 }
10101             } else {
10102                 if (ctxt->errNr > errNr)
10103                     xmlRelaxNGPopErrors(ctxt, errNr);
10104             }
10105 
10106 #ifdef DEBUG
10107             xmlGenericError(xmlGenericErrorContext,
10108                             "xmlRelaxNGValidateDefinition(): validated %s : %d",
10109                             node->name, ret);
10110             if (oldstate == NULL)
10111                 xmlGenericError(xmlGenericErrorContext, ": no state\n");
10112             else if (oldstate->seq == NULL)
10113                 xmlGenericError(xmlGenericErrorContext, ": done\n");
10114             else if (oldstate->seq->type == XML_ELEMENT_NODE)
10115                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
10116                                 oldstate->seq->name);
10117             else
10118                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
10119                                 oldstate->seq->name, oldstate->seq->type);
10120 #endif
10121             break;
10122         case XML_RELAXNG_OPTIONAL:{
10123                 errNr = ctxt->errNr;
10124                 oldflags = ctxt->flags;
10125                 ctxt->flags |= FLAGS_IGNORABLE;
10126                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10127                 ret =
10128                     xmlRelaxNGValidateDefinitionList(ctxt,
10129                                                      define->content);
10130                 if (ret != 0) {
10131                     if (ctxt->state != NULL)
10132                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10133                     ctxt->state = oldstate;
10134                     ctxt->flags = oldflags;
10135                     ret = 0;
10136                     if (ctxt->errNr > errNr)
10137                         xmlRelaxNGPopErrors(ctxt, errNr);
10138                     break;
10139                 }
10140                 if (ctxt->states != NULL) {
10141                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10142                 } else {
10143                     ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
10144                     if (ctxt->states == NULL) {
10145                         xmlRelaxNGFreeValidState(ctxt, oldstate);
10146                         ctxt->flags = oldflags;
10147                         ret = -1;
10148                         if (ctxt->errNr > errNr)
10149                             xmlRelaxNGPopErrors(ctxt, errNr);
10150                         break;
10151                     }
10152                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10153                     xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
10154                     ctxt->state = NULL;
10155                 }
10156                 ctxt->flags = oldflags;
10157                 ret = 0;
10158                 if (ctxt->errNr > errNr)
10159                     xmlRelaxNGPopErrors(ctxt, errNr);
10160                 break;
10161             }
10162         case XML_RELAXNG_ONEORMORE:
10163             errNr = ctxt->errNr;
10164             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10165             if (ret != 0) {
10166                 break;
10167             }
10168             if (ctxt->errNr > errNr)
10169                 xmlRelaxNGPopErrors(ctxt, errNr);
10170             /* Falls through. */
10171         case XML_RELAXNG_ZEROORMORE:{
10172                 int progress;
10173                 xmlRelaxNGStatesPtr states = NULL, res = NULL;
10174                 int base, j;
10175 
10176                 errNr = ctxt->errNr;
10177                 res = xmlRelaxNGNewStates(ctxt, 1);
10178                 if (res == NULL) {
10179                     ret = -1;
10180                     break;
10181                 }
10182                 /*
10183                  * All the input states are also exit states
10184                  */
10185                 if (ctxt->state != NULL) {
10186                     xmlRelaxNGAddStates(ctxt, res,
10187                                         xmlRelaxNGCopyValidState(ctxt,
10188                                                                  ctxt->
10189                                                                  state));
10190                 } else {
10191                     for (j = 0; j < ctxt->states->nbState; j++) {
10192                         xmlRelaxNGAddStates(ctxt, res,
10193                             xmlRelaxNGCopyValidState(ctxt,
10194                                             ctxt->states->tabState[j]));
10195                     }
10196                 }
10197                 oldflags = ctxt->flags;
10198                 ctxt->flags |= FLAGS_IGNORABLE;
10199                 do {
10200                     progress = 0;
10201                     base = res->nbState;
10202 
10203                     if (ctxt->states != NULL) {
10204                         states = ctxt->states;
10205                         for (i = 0; i < states->nbState; i++) {
10206                             ctxt->state = states->tabState[i];
10207                             ctxt->states = NULL;
10208                             ret = xmlRelaxNGValidateDefinitionList(ctxt,
10209                                                                    define->
10210                                                                    content);
10211                             if (ret == 0) {
10212                                 if (ctxt->state != NULL) {
10213                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10214                                                               ctxt->state);
10215                                     ctxt->state = NULL;
10216                                     if (tmp == 1)
10217                                         progress = 1;
10218                                 } else if (ctxt->states != NULL) {
10219                                     for (j = 0; j < ctxt->states->nbState;
10220                                          j++) {
10221                                         tmp =
10222                                             xmlRelaxNGAddStates(ctxt, res,
10223                                                    ctxt->states->tabState[j]);
10224                                         if (tmp == 1)
10225                                             progress = 1;
10226                                     }
10227                                     xmlRelaxNGFreeStates(ctxt,
10228                                                          ctxt->states);
10229                                     ctxt->states = NULL;
10230                                 }
10231                             } else {
10232                                 if (ctxt->state != NULL) {
10233                                     xmlRelaxNGFreeValidState(ctxt,
10234                                                              ctxt->state);
10235                                     ctxt->state = NULL;
10236                                 }
10237                             }
10238                         }
10239                     } else {
10240                         ret = xmlRelaxNGValidateDefinitionList(ctxt,
10241                                                                define->
10242                                                                content);
10243                         if (ret != 0) {
10244                             xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10245                             ctxt->state = NULL;
10246                         } else {
10247                             base = res->nbState;
10248                             if (ctxt->state != NULL) {
10249                                 tmp = xmlRelaxNGAddStates(ctxt, res,
10250                                                           ctxt->state);
10251                                 ctxt->state = NULL;
10252                                 if (tmp == 1)
10253                                     progress = 1;
10254                             } else if (ctxt->states != NULL) {
10255                                 for (j = 0; j < ctxt->states->nbState; j++) {
10256                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10257                                                ctxt->states->tabState[j]);
10258                                     if (tmp == 1)
10259                                         progress = 1;
10260                                 }
10261                                 if (states == NULL) {
10262                                     states = ctxt->states;
10263                                 } else {
10264                                     xmlRelaxNGFreeStates(ctxt,
10265                                                          ctxt->states);
10266                                 }
10267                                 ctxt->states = NULL;
10268                             }
10269                         }
10270                     }
10271                     if (progress) {
10272                         /*
10273                          * Collect all the new nodes added at that step
10274                          * and make them the new node set
10275                          */
10276                         if (res->nbState - base == 1) {
10277                             ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10278                                                                    res->
10279                                                                    tabState
10280                                                                    [base]);
10281                         } else {
10282                             if (states == NULL) {
10283                                 xmlRelaxNGNewStates(ctxt,
10284                                                     res->nbState - base);
10285 			        states = ctxt->states;
10286 				if (states == NULL) {
10287 				    progress = 0;
10288 				    break;
10289 				}
10290                             }
10291                             states->nbState = 0;
10292                             for (i = base; i < res->nbState; i++)
10293                                 xmlRelaxNGAddStates(ctxt, states,
10294                                                     xmlRelaxNGCopyValidState
10295                                                     (ctxt, res->tabState[i]));
10296                             ctxt->states = states;
10297                         }
10298                     }
10299                 } while (progress == 1);
10300                 if (states != NULL) {
10301                     xmlRelaxNGFreeStates(ctxt, states);
10302                 }
10303                 ctxt->states = res;
10304                 ctxt->flags = oldflags;
10305 #if 0
10306                 /*
10307                  * errors may have to be propagated back...
10308                  */
10309                 if (ctxt->errNr > errNr)
10310                     xmlRelaxNGPopErrors(ctxt, errNr);
10311 #endif
10312                 ret = 0;
10313                 break;
10314             }
10315         case XML_RELAXNG_CHOICE:{
10316                 xmlRelaxNGDefinePtr list = NULL;
10317                 xmlRelaxNGStatesPtr states = NULL;
10318 
10319                 node = xmlRelaxNGSkipIgnored(ctxt, node);
10320 
10321                 errNr = ctxt->errNr;
10322                 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10323 		    (node != NULL)) {
10324 		    /*
10325 		     * node == NULL can't be optimized since IS_TRIABLE
10326 		     * doesn't account for choice which may lead to
10327 		     * only attributes.
10328 		     */
10329                     xmlHashTablePtr triage =
10330                         (xmlHashTablePtr) define->data;
10331 
10332                     /*
10333                      * Something we can optimize cleanly there is only one
10334                      * possble branch out !
10335                      */
10336                     if ((node->type == XML_TEXT_NODE) ||
10337                         (node->type == XML_CDATA_SECTION_NODE)) {
10338                         list =
10339                             xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10340                     } else if (node->type == XML_ELEMENT_NODE) {
10341                         if (node->ns != NULL) {
10342                             list = xmlHashLookup2(triage, node->name,
10343                                                   node->ns->href);
10344                             if (list == NULL)
10345                                 list =
10346                                     xmlHashLookup2(triage, BAD_CAST "#any",
10347                                                    node->ns->href);
10348                         } else
10349                             list =
10350                                 xmlHashLookup2(triage, node->name, NULL);
10351                         if (list == NULL)
10352                             list =
10353                                 xmlHashLookup2(triage, BAD_CAST "#any",
10354                                                NULL);
10355                     }
10356                     if (list == NULL) {
10357                         ret = -1;
10358 			VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
10359                         break;
10360                     }
10361                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10362                     if (ret == 0) {
10363                     }
10364                     break;
10365                 }
10366 
10367                 list = define->content;
10368                 oldflags = ctxt->flags;
10369                 ctxt->flags |= FLAGS_IGNORABLE;
10370 
10371                 while (list != NULL) {
10372                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10373                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10374                     if (ret == 0) {
10375                         if (states == NULL) {
10376                             states = xmlRelaxNGNewStates(ctxt, 1);
10377                         }
10378                         if (ctxt->state != NULL) {
10379                             xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10380                         } else if (ctxt->states != NULL) {
10381                             for (i = 0; i < ctxt->states->nbState; i++) {
10382                                 xmlRelaxNGAddStates(ctxt, states,
10383                                                     ctxt->states->
10384                                                     tabState[i]);
10385                             }
10386                             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10387                             ctxt->states = NULL;
10388                         }
10389                     } else {
10390                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10391                     }
10392                     ctxt->state = oldstate;
10393                     list = list->next;
10394                 }
10395                 if (states != NULL) {
10396                     xmlRelaxNGFreeValidState(ctxt, oldstate);
10397                     ctxt->states = states;
10398                     ctxt->state = NULL;
10399                     ret = 0;
10400                 } else {
10401                     ctxt->states = NULL;
10402                 }
10403                 ctxt->flags = oldflags;
10404                 if (ret != 0) {
10405                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10406                         xmlRelaxNGDumpValidError(ctxt);
10407                     }
10408                 } else {
10409                     if (ctxt->errNr > errNr)
10410                         xmlRelaxNGPopErrors(ctxt, errNr);
10411                 }
10412                 break;
10413             }
10414         case XML_RELAXNG_DEF:
10415         case XML_RELAXNG_GROUP:
10416             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10417             break;
10418         case XML_RELAXNG_INTERLEAVE:
10419             ret = xmlRelaxNGValidateInterleave(ctxt, define);
10420             break;
10421         case XML_RELAXNG_ATTRIBUTE:
10422             ret = xmlRelaxNGValidateAttribute(ctxt, define);
10423             break;
10424         case XML_RELAXNG_START:
10425         case XML_RELAXNG_NOOP:
10426         case XML_RELAXNG_REF:
10427         case XML_RELAXNG_EXTERNALREF:
10428         case XML_RELAXNG_PARENTREF:
10429             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10430             break;
10431         case XML_RELAXNG_DATATYPE:{
10432                 xmlNodePtr child;
10433                 xmlChar *content = NULL;
10434 
10435                 child = node;
10436                 while (child != NULL) {
10437                     if (child->type == XML_ELEMENT_NODE) {
10438                         VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10439                                    node->parent->name);
10440                         ret = -1;
10441                         break;
10442                     } else if ((child->type == XML_TEXT_NODE) ||
10443                                (child->type == XML_CDATA_SECTION_NODE)) {
10444                         content = xmlStrcat(content, child->content);
10445                     }
10446                     /* TODO: handle entities ... */
10447                     child = child->next;
10448                 }
10449                 if (ret == -1) {
10450                     if (content != NULL)
10451                         xmlFree(content);
10452                     break;
10453                 }
10454                 if (content == NULL) {
10455                     content = xmlStrdup(BAD_CAST "");
10456                     if (content == NULL) {
10457                         xmlRngVErrMemory(ctxt, "validating\n");
10458                         ret = -1;
10459                         break;
10460                     }
10461                 }
10462                 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10463                                                  ctxt->state->seq);
10464                 if (ret == -1) {
10465                     VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10466                 } else if (ret == 0) {
10467                     ctxt->state->seq = NULL;
10468                 }
10469                 if (content != NULL)
10470                     xmlFree(content);
10471                 break;
10472             }
10473         case XML_RELAXNG_VALUE:{
10474                 xmlChar *content = NULL;
10475                 xmlChar *oldvalue;
10476                 xmlNodePtr child;
10477 
10478                 child = node;
10479                 while (child != NULL) {
10480                     if (child->type == XML_ELEMENT_NODE) {
10481                         VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10482                                    node->parent->name);
10483                         ret = -1;
10484                         break;
10485                     } else if ((child->type == XML_TEXT_NODE) ||
10486                                (child->type == XML_CDATA_SECTION_NODE)) {
10487                         content = xmlStrcat(content, child->content);
10488                     }
10489                     /* TODO: handle entities ... */
10490                     child = child->next;
10491                 }
10492                 if (ret == -1) {
10493                     if (content != NULL)
10494                         xmlFree(content);
10495                     break;
10496                 }
10497                 if (content == NULL) {
10498                     content = xmlStrdup(BAD_CAST "");
10499                     if (content == NULL) {
10500                         xmlRngVErrMemory(ctxt, "validating\n");
10501                         ret = -1;
10502                         break;
10503                     }
10504                 }
10505                 oldvalue = ctxt->state->value;
10506                 ctxt->state->value = content;
10507                 ret = xmlRelaxNGValidateValue(ctxt, define);
10508                 ctxt->state->value = oldvalue;
10509                 if (ret == -1) {
10510                     VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10511                 } else if (ret == 0) {
10512                     ctxt->state->seq = NULL;
10513                 }
10514                 if (content != NULL)
10515                     xmlFree(content);
10516                 break;
10517             }
10518         case XML_RELAXNG_LIST:{
10519                 xmlChar *content;
10520                 xmlNodePtr child;
10521                 xmlChar *oldvalue, *oldendvalue;
10522                 int len;
10523 
10524                 /*
10525                  * Make sure it's only text nodes
10526                  */
10527 
10528                 content = NULL;
10529                 child = node;
10530                 while (child != NULL) {
10531                     if (child->type == XML_ELEMENT_NODE) {
10532                         VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10533                                    node->parent->name);
10534                         ret = -1;
10535                         break;
10536                     } else if ((child->type == XML_TEXT_NODE) ||
10537                                (child->type == XML_CDATA_SECTION_NODE)) {
10538                         content = xmlStrcat(content, child->content);
10539                     }
10540                     /* TODO: handle entities ... */
10541                     child = child->next;
10542                 }
10543                 if (ret == -1) {
10544                     if (content != NULL)
10545                         xmlFree(content);
10546                     break;
10547                 }
10548                 if (content == NULL) {
10549                     content = xmlStrdup(BAD_CAST "");
10550                     if (content == NULL) {
10551                         xmlRngVErrMemory(ctxt, "validating\n");
10552                         ret = -1;
10553                         break;
10554                     }
10555                 }
10556                 len = xmlStrlen(content);
10557                 oldvalue = ctxt->state->value;
10558                 oldendvalue = ctxt->state->endvalue;
10559                 ctxt->state->value = content;
10560                 ctxt->state->endvalue = content + len;
10561                 ret = xmlRelaxNGValidateValue(ctxt, define);
10562                 ctxt->state->value = oldvalue;
10563                 ctxt->state->endvalue = oldendvalue;
10564                 if (ret == -1) {
10565                     VALID_ERR(XML_RELAXNG_ERR_LIST);
10566                 } else if ((ret == 0) && (node != NULL)) {
10567                     ctxt->state->seq = node->next;
10568                 }
10569                 if (content != NULL)
10570                     xmlFree(content);
10571                 break;
10572             }
10573         case XML_RELAXNG_EXCEPT:
10574         case XML_RELAXNG_PARAM:
10575             TODO ret = -1;
10576             break;
10577     }
10578     ctxt->depth--;
10579 #ifdef DEBUG
10580     for (i = 0; i < ctxt->depth; i++)
10581         xmlGenericError(xmlGenericErrorContext, " ");
10582     xmlGenericError(xmlGenericErrorContext,
10583                     "Validating %s ", xmlRelaxNGDefName(define));
10584     if (define->name != NULL)
10585         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
10586     if (ret == 0)
10587         xmlGenericError(xmlGenericErrorContext, "suceeded\n");
10588     else
10589         xmlGenericError(xmlGenericErrorContext, "failed\n");
10590 #endif
10591     return (ret);
10592 }
10593 
10594 /**
10595  * xmlRelaxNGValidateDefinition:
10596  * @ctxt:  a Relax-NG validation context
10597  * @define:  the definition to verify
10598  *
10599  * Validate the current node lists against the definition
10600  *
10601  * Returns 0 if the validation succeeded or an error code.
10602  */
10603 static int
10604 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10605                              xmlRelaxNGDefinePtr define)
10606 {
10607     xmlRelaxNGStatesPtr states, res;
10608     int i, j, k, ret, oldflags;
10609 
10610     /*
10611      * We should NOT have both ctxt->state and ctxt->states
10612      */
10613     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10614         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10615         ctxt->state = NULL;
10616     }
10617 
10618     if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10619         if (ctxt->states != NULL) {
10620             ctxt->state = ctxt->states->tabState[0];
10621             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10622             ctxt->states = NULL;
10623         }
10624         ret = xmlRelaxNGValidateState(ctxt, define);
10625         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10626             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10627             ctxt->state = NULL;
10628         }
10629         if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10630             ctxt->state = ctxt->states->tabState[0];
10631             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10632             ctxt->states = NULL;
10633         }
10634         return (ret);
10635     }
10636 
10637     states = ctxt->states;
10638     ctxt->states = NULL;
10639     res = NULL;
10640     j = 0;
10641     oldflags = ctxt->flags;
10642     ctxt->flags |= FLAGS_IGNORABLE;
10643     for (i = 0; i < states->nbState; i++) {
10644         ctxt->state = states->tabState[i];
10645         ctxt->states = NULL;
10646         ret = xmlRelaxNGValidateState(ctxt, define);
10647         /*
10648          * We should NOT have both ctxt->state and ctxt->states
10649          */
10650         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10651             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10652             ctxt->state = NULL;
10653         }
10654         if (ret == 0) {
10655             if (ctxt->states == NULL) {
10656                 if (res != NULL) {
10657                     /* add the state to the container */
10658                     xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10659                     ctxt->state = NULL;
10660                 } else {
10661                     /* add the state directly in states */
10662                     states->tabState[j++] = ctxt->state;
10663                     ctxt->state = NULL;
10664                 }
10665             } else {
10666                 if (res == NULL) {
10667                     /* make it the new container and copy other results */
10668                     res = ctxt->states;
10669                     ctxt->states = NULL;
10670                     for (k = 0; k < j; k++)
10671                         xmlRelaxNGAddStates(ctxt, res,
10672                                             states->tabState[k]);
10673                 } else {
10674                     /* add all the new results to res and reff the container */
10675                     for (k = 0; k < ctxt->states->nbState; k++)
10676                         xmlRelaxNGAddStates(ctxt, res,
10677                                             ctxt->states->tabState[k]);
10678                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10679                     ctxt->states = NULL;
10680                 }
10681             }
10682         } else {
10683             if (ctxt->state != NULL) {
10684                 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10685                 ctxt->state = NULL;
10686             } else if (ctxt->states != NULL) {
10687                 for (k = 0; k < ctxt->states->nbState; k++)
10688                     xmlRelaxNGFreeValidState(ctxt,
10689                                              ctxt->states->tabState[k]);
10690                 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10691                 ctxt->states = NULL;
10692             }
10693         }
10694     }
10695     ctxt->flags = oldflags;
10696     if (res != NULL) {
10697         xmlRelaxNGFreeStates(ctxt, states);
10698         ctxt->states = res;
10699         ret = 0;
10700     } else if (j > 1) {
10701         states->nbState = j;
10702         ctxt->states = states;
10703         ret = 0;
10704     } else if (j == 1) {
10705         ctxt->state = states->tabState[0];
10706         xmlRelaxNGFreeStates(ctxt, states);
10707         ret = 0;
10708     } else {
10709         ret = -1;
10710         xmlRelaxNGFreeStates(ctxt, states);
10711         if (ctxt->states != NULL) {
10712             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10713             ctxt->states = NULL;
10714         }
10715     }
10716     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10717         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10718         ctxt->state = NULL;
10719     }
10720     return (ret);
10721 }
10722 
10723 /**
10724  * xmlRelaxNGValidateDocument:
10725  * @ctxt:  a Relax-NG validation context
10726  * @doc:  the document
10727  *
10728  * Validate the given document
10729  *
10730  * Returns 0 if the validation succeeded or an error code.
10731  */
10732 static int
10733 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10734 {
10735     int ret;
10736     xmlRelaxNGPtr schema;
10737     xmlRelaxNGGrammarPtr grammar;
10738     xmlRelaxNGValidStatePtr state;
10739     xmlNodePtr node;
10740 
10741     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10742         return (-1);
10743 
10744     ctxt->errNo = XML_RELAXNG_OK;
10745     schema = ctxt->schema;
10746     grammar = schema->topgrammar;
10747     if (grammar == NULL) {
10748         VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10749         return (-1);
10750     }
10751     state = xmlRelaxNGNewValidState(ctxt, NULL);
10752     ctxt->state = state;
10753     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10754     if ((ctxt->state != NULL) && (state->seq != NULL)) {
10755         state = ctxt->state;
10756         node = state->seq;
10757         node = xmlRelaxNGSkipIgnored(ctxt, node);
10758         if (node != NULL) {
10759             if (ret != -1) {
10760                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10761                 ret = -1;
10762             }
10763         }
10764     } else if (ctxt->states != NULL) {
10765         int i;
10766         int tmp = -1;
10767 
10768         for (i = 0; i < ctxt->states->nbState; i++) {
10769             state = ctxt->states->tabState[i];
10770             node = state->seq;
10771             node = xmlRelaxNGSkipIgnored(ctxt, node);
10772             if (node == NULL)
10773                 tmp = 0;
10774             xmlRelaxNGFreeValidState(ctxt, state);
10775         }
10776         if (tmp == -1) {
10777             if (ret != -1) {
10778                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10779                 ret = -1;
10780             }
10781         }
10782     }
10783     if (ctxt->state != NULL) {
10784         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10785         ctxt->state = NULL;
10786     }
10787     if (ret != 0)
10788         xmlRelaxNGDumpValidError(ctxt);
10789 #ifdef DEBUG
10790     else if (ctxt->errNr != 0) {
10791         ctxt->error(ctxt->userData,
10792                     "%d Extra error messages left on stack !\n",
10793                     ctxt->errNr);
10794         xmlRelaxNGDumpValidError(ctxt);
10795     }
10796 #endif
10797 #ifdef LIBXML_VALID_ENABLED
10798     if (ctxt->idref == 1) {
10799         xmlValidCtxt vctxt;
10800 
10801         memset(&vctxt, 0, sizeof(xmlValidCtxt));
10802         vctxt.valid = 1;
10803         vctxt.error = ctxt->error;
10804         vctxt.warning = ctxt->warning;
10805         vctxt.userData = ctxt->userData;
10806 
10807         if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10808             ret = -1;
10809     }
10810 #endif /* LIBXML_VALID_ENABLED */
10811     if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10812         ret = -1;
10813 
10814     return (ret);
10815 }
10816 
10817 /**
10818  * xmlRelaxNGCleanPSVI:
10819  * @node:  an input element or document
10820  *
10821  * Call this routine to speed up XPath computation on static documents.
10822  * This stamps all the element nodes with the document order
10823  * Like for line information, the order is kept in the element->content
10824  * field, the value stored is actually - the node number (starting at -1)
10825  * to be able to differentiate from line numbers.
10826  *
10827  * Returns the number of elements found in the document or -1 in case
10828  *    of error.
10829  */
10830 static void
10831 xmlRelaxNGCleanPSVI(xmlNodePtr node) {
10832     xmlNodePtr cur;
10833 
10834     if ((node == NULL) ||
10835         ((node->type != XML_ELEMENT_NODE) &&
10836          (node->type != XML_DOCUMENT_NODE) &&
10837          (node->type != XML_HTML_DOCUMENT_NODE)))
10838 	return;
10839     if (node->type == XML_ELEMENT_NODE)
10840         node->psvi = NULL;
10841 
10842     cur = node->children;
10843     while (cur != NULL) {
10844 	if (cur->type == XML_ELEMENT_NODE) {
10845 	    cur->psvi = NULL;
10846 	    if (cur->children != NULL) {
10847 		cur = cur->children;
10848 		continue;
10849 	    }
10850 	}
10851 	if (cur->next != NULL) {
10852 	    cur = cur->next;
10853 	    continue;
10854 	}
10855 	do {
10856 	    cur = cur->parent;
10857 	    if (cur == NULL)
10858 		break;
10859 	    if (cur == node) {
10860 		cur = NULL;
10861 		break;
10862 	    }
10863 	    if (cur->next != NULL) {
10864 		cur = cur->next;
10865 		break;
10866 	    }
10867 	} while (cur != NULL);
10868     }
10869     return;
10870 }
10871 /************************************************************************
10872  *									*
10873  *			Validation interfaces				*
10874  *									*
10875  ************************************************************************/
10876 
10877 /**
10878  * xmlRelaxNGNewValidCtxt:
10879  * @schema:  a precompiled XML RelaxNGs
10880  *
10881  * Create an XML RelaxNGs validation context based on the given schema
10882  *
10883  * Returns the validation context or NULL in case of error
10884  */
10885 xmlRelaxNGValidCtxtPtr
10886 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10887 {
10888     xmlRelaxNGValidCtxtPtr ret;
10889 
10890     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10891     if (ret == NULL) {
10892         xmlRngVErrMemory(NULL, "building context\n");
10893         return (NULL);
10894     }
10895     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10896     ret->schema = schema;
10897     ret->error = xmlGenericError;
10898     ret->userData = xmlGenericErrorContext;
10899     ret->errNr = 0;
10900     ret->errMax = 0;
10901     ret->err = NULL;
10902     ret->errTab = NULL;
10903     if (schema != NULL)
10904 	ret->idref = schema->idref;
10905     ret->states = NULL;
10906     ret->freeState = NULL;
10907     ret->freeStates = NULL;
10908     ret->errNo = XML_RELAXNG_OK;
10909     return (ret);
10910 }
10911 
10912 /**
10913  * xmlRelaxNGFreeValidCtxt:
10914  * @ctxt:  the schema validation context
10915  *
10916  * Free the resources associated to the schema validation context
10917  */
10918 void
10919 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10920 {
10921     int k;
10922 
10923     if (ctxt == NULL)
10924         return;
10925     if (ctxt->states != NULL)
10926         xmlRelaxNGFreeStates(NULL, ctxt->states);
10927     if (ctxt->freeState != NULL) {
10928         for (k = 0; k < ctxt->freeState->nbState; k++) {
10929             xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10930         }
10931         xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10932     }
10933     if (ctxt->freeStates != NULL) {
10934         for (k = 0; k < ctxt->freeStatesNr; k++) {
10935             xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10936         }
10937         xmlFree(ctxt->freeStates);
10938     }
10939     if (ctxt->errTab != NULL)
10940         xmlFree(ctxt->errTab);
10941     if (ctxt->elemTab != NULL) {
10942         xmlRegExecCtxtPtr exec;
10943 
10944         exec = xmlRelaxNGElemPop(ctxt);
10945         while (exec != NULL) {
10946             xmlRegFreeExecCtxt(exec);
10947             exec = xmlRelaxNGElemPop(ctxt);
10948         }
10949         xmlFree(ctxt->elemTab);
10950     }
10951     xmlFree(ctxt);
10952 }
10953 
10954 /**
10955  * xmlRelaxNGSetValidErrors:
10956  * @ctxt:  a Relax-NG validation context
10957  * @err:  the error function
10958  * @warn: the warning function
10959  * @ctx: the functions context
10960  *
10961  * Set the error and warning callback informations
10962  */
10963 void
10964 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10965                          xmlRelaxNGValidityErrorFunc err,
10966                          xmlRelaxNGValidityWarningFunc warn, void *ctx)
10967 {
10968     if (ctxt == NULL)
10969         return;
10970     ctxt->error = err;
10971     ctxt->warning = warn;
10972     ctxt->userData = ctx;
10973     ctxt->serror = NULL;
10974 }
10975 
10976 /**
10977  * xmlRelaxNGSetValidStructuredErrors:
10978  * @ctxt:  a Relax-NG validation context
10979  * @serror:  the structured error function
10980  * @ctx: the functions context
10981  *
10982  * Set the structured error callback
10983  */
10984 void
10985 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
10986                                    xmlStructuredErrorFunc serror, void *ctx)
10987 {
10988     if (ctxt == NULL)
10989         return;
10990     ctxt->serror = serror;
10991     ctxt->error = NULL;
10992     ctxt->warning = NULL;
10993     ctxt->userData = ctx;
10994 }
10995 
10996 /**
10997  * xmlRelaxNGGetValidErrors:
10998  * @ctxt:  a Relax-NG validation context
10999  * @err:  the error function result
11000  * @warn: the warning function result
11001  * @ctx: the functions context result
11002  *
11003  * Get the error and warning callback informations
11004  *
11005  * Returns -1 in case of error and 0 otherwise
11006  */
11007 int
11008 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
11009                          xmlRelaxNGValidityErrorFunc * err,
11010                          xmlRelaxNGValidityWarningFunc * warn, void **ctx)
11011 {
11012     if (ctxt == NULL)
11013         return (-1);
11014     if (err != NULL)
11015         *err = ctxt->error;
11016     if (warn != NULL)
11017         *warn = ctxt->warning;
11018     if (ctx != NULL)
11019         *ctx = ctxt->userData;
11020     return (0);
11021 }
11022 
11023 /**
11024  * xmlRelaxNGValidateDoc:
11025  * @ctxt:  a Relax-NG validation context
11026  * @doc:  a parsed document tree
11027  *
11028  * Validate a document tree in memory.
11029  *
11030  * Returns 0 if the document is valid, a positive error code
11031  *     number otherwise and -1 in case of internal or API error.
11032  */
11033 int
11034 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
11035 {
11036     int ret;
11037 
11038     if ((ctxt == NULL) || (doc == NULL))
11039         return (-1);
11040 
11041     ctxt->doc = doc;
11042 
11043     ret = xmlRelaxNGValidateDocument(ctxt, doc);
11044     /*
11045      * Remove all left PSVI
11046      */
11047     xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
11048 
11049     /*
11050      * TODO: build error codes
11051      */
11052     if (ret == -1)
11053         return (1);
11054     return (ret);
11055 }
11056 
11057 #define bottom_relaxng
11058 #include "elfgcchack.h"
11059 #endif /* LIBXML_SCHEMAS_ENABLED */
11060