Imported Upstream version 2.9.5_rc2
[platform/upstream/libxml2.git] / relaxng.c
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 <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 #include <libxml/parserInternals.h>
26 #include <libxml/hash.h>
27 #include <libxml/uri.h>
28
29 #include <libxml/relaxng.h>
30
31 #include <libxml/xmlschemastypes.h>
32 #include <libxml/xmlautomata.h>
33 #include <libxml/xmlregexp.h>
34 #include <libxml/xmlschemastypes.h>
35
36 /*
37  * The Relax-NG namespace
38  */
39 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40     "http://relaxng.org/ns/structure/1.0";
41
42 #define IS_RELAXNG(node, typ)                                           \
43    ((node != NULL) && (node->ns != NULL) &&                             \
44     (node->type == XML_ELEMENT_NODE) &&                                 \
45     (xmlStrEqual(node->name, (const xmlChar *) typ)) &&         \
46     (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
47
48
49 #if 0
50 #define DEBUG 1
51
52 #define DEBUG_GRAMMAR 1
53
54 #define DEBUG_CONTENT 1
55
56 #define DEBUG_TYPE 1
57
58 #define DEBUG_VALID 1
59
60 #define DEBUG_INTERLEAVE 1
61
62 #define DEBUG_LIST 1
63
64 #define DEBUG_INCLUDE 1
65
66 #define DEBUG_ERROR 1
67
68 #define DEBUG_COMPILE 1
69
70 #define DEBUG_PROGRESSIVE 1
71 #endif
72
73 #define MAX_ERROR 5
74
75 #define TODO                                                            \
76     xmlGenericError(xmlGenericErrorContext,                             \
77             "Unimplemented block at %s:%d\n",                           \
78             __FILE__, __LINE__);
79
80 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
81 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
82
83 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
84 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
85
86 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
87 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
88
89 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
90 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
91
92 typedef enum {
93     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
94     XML_RELAXNG_COMBINE_CHOICE, /* choice */
95     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
96 } xmlRelaxNGCombine;
97
98 typedef enum {
99     XML_RELAXNG_CONTENT_ERROR = -1,
100     XML_RELAXNG_CONTENT_EMPTY = 0,
101     XML_RELAXNG_CONTENT_SIMPLE,
102     XML_RELAXNG_CONTENT_COMPLEX
103 } xmlRelaxNGContentType;
104
105 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
106 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
107
108 struct _xmlRelaxNGGrammar {
109     xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */
110     xmlRelaxNGGrammarPtr children;      /* the children grammar if any */
111     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
112     xmlRelaxNGDefinePtr start;  /* <start> content */
113     xmlRelaxNGCombine combine;  /* the default combine value */
114     xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */
115     xmlHashTablePtr defs;       /* define* */
116     xmlHashTablePtr refs;       /* references */
117 };
118
119
120 typedef enum {
121     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
122     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
123     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
124     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
125     XML_RELAXNG_TEXT,           /* textual content */
126     XML_RELAXNG_ELEMENT,        /* an element */
127     XML_RELAXNG_DATATYPE,       /* extenal data type definition */
128     XML_RELAXNG_PARAM,          /* extenal data type parameter */
129     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
130     XML_RELAXNG_LIST,           /* a list of patterns */
131     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
132     XML_RELAXNG_DEF,            /* a definition */
133     XML_RELAXNG_REF,            /* reference to a definition */
134     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
135     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
136     XML_RELAXNG_OPTIONAL,       /* optional patterns */
137     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
138     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
139     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
140     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
141     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
142     XML_RELAXNG_START           /* Used to keep track of starts on grammars */
143 } xmlRelaxNGType;
144
145 #define IS_NULLABLE             (1 << 0)
146 #define IS_NOT_NULLABLE         (1 << 1)
147 #define IS_INDETERMINIST        (1 << 2)
148 #define IS_MIXED                (1 << 3)
149 #define IS_TRIABLE              (1 << 4)
150 #define IS_PROCESSED            (1 << 5)
151 #define IS_COMPILABLE           (1 << 6)
152 #define IS_NOT_COMPILABLE       (1 << 7)
153 #define IS_EXTERNAL_REF         (1 << 8)
154
155 struct _xmlRelaxNGDefine {
156     xmlRelaxNGType type;        /* the type of definition */
157     xmlNodePtr node;            /* the node in the source */
158     xmlChar *name;              /* the element local name if present */
159     xmlChar *ns;                /* the namespace local name if present */
160     xmlChar *value;             /* value when available */
161     void *data;                 /* data lib or specific pointer */
162     xmlRelaxNGDefinePtr content;        /* the expected content */
163     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
164     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
165     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
166     xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */
167     xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */
168     short depth;                /* used for the cycle detection */
169     short dflags;               /* define related flags */
170     xmlRegexpPtr contModel;     /* a compiled content model if available */
171 };
172
173 /**
174  * _xmlRelaxNG:
175  *
176  * A RelaxNGs definition
177  */
178 struct _xmlRelaxNG {
179     void *_private;             /* unused by the library for users or bindings */
180     xmlRelaxNGGrammarPtr topgrammar;
181     xmlDocPtr doc;
182
183     int idref;                  /* requires idref checking */
184
185     xmlHashTablePtr defs;       /* define */
186     xmlHashTablePtr refs;       /* references */
187     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
188     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
189     int defNr;                  /* number of defines used */
190     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
191
192 };
193
194 #define XML_RELAXNG_IN_ATTRIBUTE        (1 << 0)
195 #define XML_RELAXNG_IN_ONEORMORE        (1 << 1)
196 #define XML_RELAXNG_IN_LIST             (1 << 2)
197 #define XML_RELAXNG_IN_DATAEXCEPT       (1 << 3)
198 #define XML_RELAXNG_IN_START            (1 << 4)
199 #define XML_RELAXNG_IN_OOMGROUP         (1 << 5)
200 #define XML_RELAXNG_IN_OOMINTERLEAVE    (1 << 6)
201 #define XML_RELAXNG_IN_EXTERNALREF      (1 << 7)
202 #define XML_RELAXNG_IN_ANYEXCEPT        (1 << 8)
203 #define XML_RELAXNG_IN_NSEXCEPT         (1 << 9)
204
205 struct _xmlRelaxNGParserCtxt {
206     void *userData;             /* user specific data block */
207     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
208     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
209     xmlStructuredErrorFunc serror;
210     xmlRelaxNGValidErr err;
211
212     xmlRelaxNGPtr schema;       /* The schema in use */
213     xmlRelaxNGGrammarPtr grammar;       /* the current grammar */
214     xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
215     int flags;                  /* parser flags */
216     int nbErrors;               /* number of errors at parse time */
217     int nbWarnings;             /* number of warnings at parse time */
218     const xmlChar *define;      /* the current define scope */
219     xmlRelaxNGDefinePtr def;    /* the current define */
220
221     int nbInterleaves;
222     xmlHashTablePtr interleaves;        /* keep track of all the interleaves */
223
224     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
225     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
226     xmlChar *URL;
227     xmlDocPtr document;
228
229     int defNr;                  /* number of defines used */
230     int defMax;                 /* number of defines aloocated */
231     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
232
233     const char *buffer;
234     int size;
235
236     /* the document stack */
237     xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */
238     int docNr;                  /* Depth of the parsing stack */
239     int docMax;                 /* Max depth of the parsing stack */
240     xmlRelaxNGDocumentPtr *docTab;      /* array of docs */
241
242     /* the include stack */
243     xmlRelaxNGIncludePtr inc;   /* Current parsed include */
244     int incNr;                  /* Depth of the include parsing stack */
245     int incMax;                 /* Max depth of the parsing stack */
246     xmlRelaxNGIncludePtr *incTab;       /* array of incs */
247
248     int idref;                  /* requires idref checking */
249
250     /* used to compile content models */
251     xmlAutomataPtr am;          /* the automata */
252     xmlAutomataStatePtr state;  /* used to build the automata */
253
254     int crng;                   /* compact syntax and other flags */
255     int freedoc;                /* need to free the document */
256 };
257
258 #define FLAGS_IGNORABLE         1
259 #define FLAGS_NEGATIVE          2
260 #define FLAGS_MIXED_CONTENT     4
261 #define FLAGS_NOERROR           8
262
263 /**
264  * xmlRelaxNGInterleaveGroup:
265  *
266  * A RelaxNGs partition set associated to lists of definitions
267  */
268 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
269 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
270 struct _xmlRelaxNGInterleaveGroup {
271     xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */
272     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
273     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
274 };
275
276 #define IS_DETERMINIST          1
277 #define IS_NEEDCHECK            2
278
279 /**
280  * xmlRelaxNGPartitions:
281  *
282  * A RelaxNGs partition associated to an interleave group
283  */
284 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
285 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
286 struct _xmlRelaxNGPartition {
287     int nbgroups;               /* number of groups in the partitions */
288     xmlHashTablePtr triage;     /* hash table used to direct nodes to the
289                                  * right group when possible */
290     int flags;                  /* determinist ? */
291     xmlRelaxNGInterleaveGroupPtr *groups;
292 };
293
294 /**
295  * xmlRelaxNGValidState:
296  *
297  * A RelaxNGs validation state
298  */
299 #define MAX_ATTR 20
300 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
301 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
302 struct _xmlRelaxNGValidState {
303     xmlNodePtr node;            /* the current node */
304     xmlNodePtr seq;             /* the sequence of children left to validate */
305     int nbAttrs;                /* the number of attributes */
306     int maxAttrs;               /* the size of attrs */
307     int nbAttrLeft;             /* the number of attributes left to validate */
308     xmlChar *value;             /* the value when operating on string */
309     xmlChar *endvalue;          /* the end value when operating on string */
310     xmlAttrPtr *attrs;          /* the array of attributes */
311 };
312
313 /**
314  * xmlRelaxNGStates:
315  *
316  * A RelaxNGs container for validation state
317  */
318 typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
319 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
320 struct _xmlRelaxNGStates {
321     int nbState;                /* the number of states */
322     int maxState;               /* the size of the array */
323     xmlRelaxNGValidStatePtr *tabState;
324 };
325
326 #define ERROR_IS_DUP    1
327
328 /**
329  * xmlRelaxNGValidError:
330  *
331  * A RelaxNGs validation error
332  */
333 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
334 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
335 struct _xmlRelaxNGValidError {
336     xmlRelaxNGValidErr err;     /* the error number */
337     int flags;                  /* flags */
338     xmlNodePtr node;            /* the current node */
339     xmlNodePtr seq;             /* the current child */
340     const xmlChar *arg1;        /* first arg */
341     const xmlChar *arg2;        /* second arg */
342 };
343
344 /**
345  * xmlRelaxNGValidCtxt:
346  *
347  * A RelaxNGs validation context
348  */
349
350 struct _xmlRelaxNGValidCtxt {
351     void *userData;             /* user specific data block */
352     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
353     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
354     xmlStructuredErrorFunc serror;
355     int nbErrors;               /* number of errors in validation */
356
357     xmlRelaxNGPtr schema;       /* The schema in use */
358     xmlDocPtr doc;              /* the document being validated */
359     int flags;                  /* validation flags */
360     int depth;                  /* validation depth */
361     int idref;                  /* requires idref checking */
362     int errNo;                  /* the first error found */
363
364     /*
365      * Errors accumulated in branches may have to be stacked to be
366      * provided back when it's sure they affect validation.
367      */
368     xmlRelaxNGValidErrorPtr err;        /* Last error */
369     int errNr;                  /* Depth of the error stack */
370     int errMax;                 /* Max depth of the error stack */
371     xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
372
373     xmlRelaxNGValidStatePtr state;      /* the current validation state */
374     xmlRelaxNGStatesPtr states; /* the accumulated state list */
375
376     xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */
377     int freeStatesNr;
378     int freeStatesMax;
379     xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */
380
381     /*
382      * This is used for "progressive" validation
383      */
384     xmlRegExecCtxtPtr elem;     /* the current element regexp */
385     int elemNr;                 /* the number of element validated */
386     int elemMax;                /* the max depth of elements */
387     xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
388     int pstate;                 /* progressive state */
389     xmlNodePtr pnode;           /* the current node */
390     xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */
391     int perr;                   /* signal error in content model
392                                  * outside the regexp */
393 };
394
395 /**
396  * xmlRelaxNGInclude:
397  *
398  * Structure associated to a RelaxNGs document element
399  */
400 struct _xmlRelaxNGInclude {
401     xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
402     xmlChar *href;              /* the normalized href value */
403     xmlDocPtr doc;              /* the associated XML document */
404     xmlRelaxNGDefinePtr content;        /* the definitions */
405     xmlRelaxNGPtr schema;       /* the schema */
406 };
407
408 /**
409  * xmlRelaxNGDocument:
410  *
411  * Structure associated to a RelaxNGs document element
412  */
413 struct _xmlRelaxNGDocument {
414     xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
415     xmlChar *href;              /* the normalized href value */
416     xmlDocPtr doc;              /* the associated XML document */
417     xmlRelaxNGDefinePtr content;        /* the definitions */
418     xmlRelaxNGPtr schema;       /* the schema */
419     int externalRef;            /* 1 if an external ref */
420 };
421
422
423 /************************************************************************
424  *                                                                      *
425  *              Some factorized error routines                          *
426  *                                                                      *
427  ************************************************************************/
428
429 /**
430  * xmlRngPErrMemory:
431  * @ctxt:  an Relax-NG parser context
432  * @extra:  extra informations
433  *
434  * Handle a redefinition of attribute error
435  */
436 static void
437 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
438 {
439     xmlStructuredErrorFunc schannel = NULL;
440     xmlGenericErrorFunc channel = NULL;
441     void *data = NULL;
442
443     if (ctxt != NULL) {
444         if (ctxt->serror != NULL)
445             schannel = ctxt->serror;
446         else
447             channel = ctxt->error;
448         data = ctxt->userData;
449         ctxt->nbErrors++;
450     }
451     if (extra)
452         __xmlRaiseError(schannel, channel, data,
453                         NULL, NULL, XML_FROM_RELAXNGP,
454                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
455                         NULL, NULL, 0, 0,
456                         "Memory allocation failed : %s\n", extra);
457     else
458         __xmlRaiseError(schannel, channel, data,
459                         NULL, NULL, XML_FROM_RELAXNGP,
460                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
461                         NULL, NULL, 0, 0, "Memory allocation failed\n");
462 }
463
464 /**
465  * xmlRngVErrMemory:
466  * @ctxt:  a Relax-NG validation context
467  * @extra:  extra informations
468  *
469  * Handle a redefinition of attribute error
470  */
471 static void
472 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
473 {
474     xmlStructuredErrorFunc schannel = NULL;
475     xmlGenericErrorFunc channel = NULL;
476     void *data = NULL;
477
478     if (ctxt != NULL) {
479         if (ctxt->serror != NULL)
480             schannel = ctxt->serror;
481         else
482             channel = ctxt->error;
483         data = ctxt->userData;
484         ctxt->nbErrors++;
485     }
486     if (extra)
487         __xmlRaiseError(schannel, channel, data,
488                         NULL, NULL, XML_FROM_RELAXNGV,
489                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
490                         NULL, NULL, 0, 0,
491                         "Memory allocation failed : %s\n", extra);
492     else
493         __xmlRaiseError(schannel, channel, data,
494                         NULL, NULL, XML_FROM_RELAXNGV,
495                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
496                         NULL, NULL, 0, 0, "Memory allocation failed\n");
497 }
498
499 /**
500  * xmlRngPErr:
501  * @ctxt:  a Relax-NG parser context
502  * @node:  the node raising the error
503  * @error:  the error code
504  * @msg:  message
505  * @str1:  extra info
506  * @str2:  extra info
507  *
508  * Handle a Relax NG Parsing error
509  */
510 static void LIBXML_ATTR_FORMAT(4,0)
511 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
512            const char *msg, const xmlChar * str1, const xmlChar * str2)
513 {
514     xmlStructuredErrorFunc schannel = NULL;
515     xmlGenericErrorFunc channel = NULL;
516     void *data = NULL;
517
518     if (ctxt != NULL) {
519         if (ctxt->serror != NULL)
520             schannel = ctxt->serror;
521         else
522             channel = ctxt->error;
523         data = ctxt->userData;
524         ctxt->nbErrors++;
525     }
526     __xmlRaiseError(schannel, channel, data,
527                     NULL, node, XML_FROM_RELAXNGP,
528                     error, XML_ERR_ERROR, NULL, 0,
529                     (const char *) str1, (const char *) str2, NULL, 0, 0,
530                     msg, str1, str2);
531 }
532
533 /**
534  * xmlRngVErr:
535  * @ctxt:  a Relax-NG validation context
536  * @node:  the node raising the error
537  * @error:  the error code
538  * @msg:  message
539  * @str1:  extra info
540  * @str2:  extra info
541  *
542  * Handle a Relax NG Validation error
543  */
544 static void LIBXML_ATTR_FORMAT(4,0)
545 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
546            const char *msg, const xmlChar * str1, const xmlChar * str2)
547 {
548     xmlStructuredErrorFunc schannel = NULL;
549     xmlGenericErrorFunc channel = NULL;
550     void *data = NULL;
551
552     if (ctxt != NULL) {
553         if (ctxt->serror != NULL)
554             schannel = ctxt->serror;
555         else
556             channel = ctxt->error;
557         data = ctxt->userData;
558         ctxt->nbErrors++;
559     }
560     __xmlRaiseError(schannel, channel, data,
561                     NULL, node, XML_FROM_RELAXNGV,
562                     error, XML_ERR_ERROR, NULL, 0,
563                     (const char *) str1, (const char *) str2, NULL, 0, 0,
564                     msg, str1, str2);
565 }
566
567 /************************************************************************
568  *                                                                      *
569  *              Preliminary type checking interfaces                    *
570  *                                                                      *
571  ************************************************************************/
572
573 /**
574  * xmlRelaxNGTypeHave:
575  * @data:  data needed for the library
576  * @type:  the type name
577  * @value:  the value to check
578  *
579  * Function provided by a type library to check if a type is exported
580  *
581  * Returns 1 if yes, 0 if no and -1 in case of error.
582  */
583 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
584
585 /**
586  * xmlRelaxNGTypeCheck:
587  * @data:  data needed for the library
588  * @type:  the type name
589  * @value:  the value to check
590  * @result:  place to store the result if needed
591  *
592  * Function provided by a type library to check if a value match a type
593  *
594  * Returns 1 if yes, 0 if no and -1 in case of error.
595  */
596 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
597                                     const xmlChar * value, void **result,
598                                     xmlNodePtr node);
599
600 /**
601  * xmlRelaxNGFacetCheck:
602  * @data:  data needed for the library
603  * @type:  the type name
604  * @facet:  the facet name
605  * @val:  the facet value
606  * @strval:  the string value
607  * @value:  the value to check
608  *
609  * Function provided by a type library to check a value facet
610  *
611  * Returns 1 if yes, 0 if no and -1 in case of error.
612  */
613 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
614                                      const xmlChar * facet,
615                                      const xmlChar * val,
616                                      const xmlChar * strval, void *value);
617
618 /**
619  * xmlRelaxNGTypeFree:
620  * @data:  data needed for the library
621  * @result:  the value to free
622  *
623  * Function provided by a type library to free a returned result
624  */
625 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
626
627 /**
628  * xmlRelaxNGTypeCompare:
629  * @data:  data needed for the library
630  * @type:  the type name
631  * @value1:  the first value
632  * @value2:  the second value
633  *
634  * Function provided by a type library to compare two values accordingly
635  * to a type.
636  *
637  * Returns 1 if yes, 0 if no and -1 in case of error.
638  */
639 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
640                                       const xmlChar * value1,
641                                       xmlNodePtr ctxt1,
642                                       void *comp1,
643                                       const xmlChar * value2,
644                                       xmlNodePtr ctxt2);
645 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
646 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
647 struct _xmlRelaxNGTypeLibrary {
648     const xmlChar *namespace;   /* the datatypeLibrary value */
649     void *data;                 /* data needed for the library */
650     xmlRelaxNGTypeHave have;    /* the export function */
651     xmlRelaxNGTypeCheck check;  /* the checking function */
652     xmlRelaxNGTypeCompare comp; /* the compare function */
653     xmlRelaxNGFacetCheck facet; /* the facet check function */
654     xmlRelaxNGTypeFree freef;   /* the freeing function */
655 };
656
657 /************************************************************************
658  *                                                                      *
659  *                      Allocation functions                            *
660  *                                                                      *
661  ************************************************************************/
662 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
663 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
664 static void xmlRelaxNGNormExtSpace(xmlChar * value);
665 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
666 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
667                                      ATTRIBUTE_UNUSED,
668                                      xmlRelaxNGValidStatePtr state1,
669                                      xmlRelaxNGValidStatePtr state2);
670 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
671                                      xmlRelaxNGValidStatePtr state);
672
673 /**
674  * xmlRelaxNGFreeDocument:
675  * @docu:  a document structure
676  *
677  * Deallocate a RelaxNG document structure.
678  */
679 static void
680 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
681 {
682     if (docu == NULL)
683         return;
684
685     if (docu->href != NULL)
686         xmlFree(docu->href);
687     if (docu->doc != NULL)
688         xmlFreeDoc(docu->doc);
689     if (docu->schema != NULL)
690         xmlRelaxNGFreeInnerSchema(docu->schema);
691     xmlFree(docu);
692 }
693
694 /**
695  * xmlRelaxNGFreeDocumentList:
696  * @docu:  a list of  document structure
697  *
698  * Deallocate a RelaxNG document structures.
699  */
700 static void
701 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
702 {
703     xmlRelaxNGDocumentPtr next;
704
705     while (docu != NULL) {
706         next = docu->next;
707         xmlRelaxNGFreeDocument(docu);
708         docu = next;
709     }
710 }
711
712 /**
713  * xmlRelaxNGFreeInclude:
714  * @incl:  a include structure
715  *
716  * Deallocate a RelaxNG include structure.
717  */
718 static void
719 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
720 {
721     if (incl == NULL)
722         return;
723
724     if (incl->href != NULL)
725         xmlFree(incl->href);
726     if (incl->doc != NULL)
727         xmlFreeDoc(incl->doc);
728     if (incl->schema != NULL)
729         xmlRelaxNGFree(incl->schema);
730     xmlFree(incl);
731 }
732
733 /**
734  * xmlRelaxNGFreeIncludeList:
735  * @incl:  a include structure list
736  *
737  * Deallocate a RelaxNG include structure.
738  */
739 static void
740 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
741 {
742     xmlRelaxNGIncludePtr next;
743
744     while (incl != NULL) {
745         next = incl->next;
746         xmlRelaxNGFreeInclude(incl);
747         incl = next;
748     }
749 }
750
751 /**
752  * xmlRelaxNGNewRelaxNG:
753  * @ctxt:  a Relax-NG validation context (optional)
754  *
755  * Allocate a new RelaxNG structure.
756  *
757  * Returns the newly allocated structure or NULL in case or error
758  */
759 static xmlRelaxNGPtr
760 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
761 {
762     xmlRelaxNGPtr ret;
763
764     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
765     if (ret == NULL) {
766         xmlRngPErrMemory(ctxt, NULL);
767         return (NULL);
768     }
769     memset(ret, 0, sizeof(xmlRelaxNG));
770
771     return (ret);
772 }
773
774 /**
775  * xmlRelaxNGFreeInnerSchema:
776  * @schema:  a schema structure
777  *
778  * Deallocate a RelaxNG schema structure.
779  */
780 static void
781 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
782 {
783     if (schema == NULL)
784         return;
785
786     if (schema->doc != NULL)
787         xmlFreeDoc(schema->doc);
788     if (schema->defTab != NULL) {
789         int i;
790
791         for (i = 0; i < schema->defNr; i++)
792             xmlRelaxNGFreeDefine(schema->defTab[i]);
793         xmlFree(schema->defTab);
794     }
795
796     xmlFree(schema);
797 }
798
799 /**
800  * xmlRelaxNGFree:
801  * @schema:  a schema structure
802  *
803  * Deallocate a RelaxNG structure.
804  */
805 void
806 xmlRelaxNGFree(xmlRelaxNGPtr schema)
807 {
808     if (schema == NULL)
809         return;
810
811     if (schema->topgrammar != NULL)
812         xmlRelaxNGFreeGrammar(schema->topgrammar);
813     if (schema->doc != NULL)
814         xmlFreeDoc(schema->doc);
815     if (schema->documents != NULL)
816         xmlRelaxNGFreeDocumentList(schema->documents);
817     if (schema->includes != NULL)
818         xmlRelaxNGFreeIncludeList(schema->includes);
819     if (schema->defTab != NULL) {
820         int i;
821
822         for (i = 0; i < schema->defNr; i++)
823             xmlRelaxNGFreeDefine(schema->defTab[i]);
824         xmlFree(schema->defTab);
825     }
826
827     xmlFree(schema);
828 }
829
830 /**
831  * xmlRelaxNGNewGrammar:
832  * @ctxt:  a Relax-NG validation context (optional)
833  *
834  * Allocate a new RelaxNG grammar.
835  *
836  * Returns the newly allocated structure or NULL in case or error
837  */
838 static xmlRelaxNGGrammarPtr
839 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
840 {
841     xmlRelaxNGGrammarPtr ret;
842
843     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
844     if (ret == NULL) {
845         xmlRngPErrMemory(ctxt, NULL);
846         return (NULL);
847     }
848     memset(ret, 0, sizeof(xmlRelaxNGGrammar));
849
850     return (ret);
851 }
852
853 /**
854  * xmlRelaxNGFreeGrammar:
855  * @grammar:  a grammar structure
856  *
857  * Deallocate a RelaxNG grammar structure.
858  */
859 static void
860 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
861 {
862     if (grammar == NULL)
863         return;
864
865     if (grammar->children != NULL) {
866         xmlRelaxNGFreeGrammar(grammar->children);
867     }
868     if (grammar->next != NULL) {
869         xmlRelaxNGFreeGrammar(grammar->next);
870     }
871     if (grammar->refs != NULL) {
872         xmlHashFree(grammar->refs, NULL);
873     }
874     if (grammar->defs != NULL) {
875         xmlHashFree(grammar->defs, NULL);
876     }
877
878     xmlFree(grammar);
879 }
880
881 /**
882  * xmlRelaxNGNewDefine:
883  * @ctxt:  a Relax-NG validation context
884  * @node:  the node in the input document.
885  *
886  * Allocate a new RelaxNG define.
887  *
888  * Returns the newly allocated structure or NULL in case or error
889  */
890 static xmlRelaxNGDefinePtr
891 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
892 {
893     xmlRelaxNGDefinePtr ret;
894
895     if (ctxt->defMax == 0) {
896         ctxt->defMax = 16;
897         ctxt->defNr = 0;
898         ctxt->defTab = (xmlRelaxNGDefinePtr *)
899             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
900         if (ctxt->defTab == NULL) {
901             xmlRngPErrMemory(ctxt, "allocating define\n");
902             return (NULL);
903         }
904     } else if (ctxt->defMax <= ctxt->defNr) {
905         xmlRelaxNGDefinePtr *tmp;
906
907         ctxt->defMax *= 2;
908         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
909                                                  ctxt->defMax *
910                                                  sizeof
911                                                  (xmlRelaxNGDefinePtr));
912         if (tmp == NULL) {
913             xmlRngPErrMemory(ctxt, "allocating define\n");
914             return (NULL);
915         }
916         ctxt->defTab = tmp;
917     }
918     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
919     if (ret == NULL) {
920         xmlRngPErrMemory(ctxt, "allocating define\n");
921         return (NULL);
922     }
923     memset(ret, 0, sizeof(xmlRelaxNGDefine));
924     ctxt->defTab[ctxt->defNr++] = ret;
925     ret->node = node;
926     ret->depth = -1;
927     return (ret);
928 }
929
930 /**
931  * xmlRelaxNGFreePartition:
932  * @partitions:  a partition set structure
933  *
934  * Deallocate RelaxNG partition set structures.
935  */
936 static void
937 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
938 {
939     xmlRelaxNGInterleaveGroupPtr group;
940     int j;
941
942     if (partitions != NULL) {
943         if (partitions->groups != NULL) {
944             for (j = 0; j < partitions->nbgroups; j++) {
945                 group = partitions->groups[j];
946                 if (group != NULL) {
947                     if (group->defs != NULL)
948                         xmlFree(group->defs);
949                     if (group->attrs != NULL)
950                         xmlFree(group->attrs);
951                     xmlFree(group);
952                 }
953             }
954             xmlFree(partitions->groups);
955         }
956         if (partitions->triage != NULL) {
957             xmlHashFree(partitions->triage, NULL);
958         }
959         xmlFree(partitions);
960     }
961 }
962
963 /**
964  * xmlRelaxNGFreeDefine:
965  * @define:  a define structure
966  *
967  * Deallocate a RelaxNG define structure.
968  */
969 static void
970 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
971 {
972     if (define == NULL)
973         return;
974
975     if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
976         xmlRelaxNGTypeLibraryPtr lib;
977
978         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
979         if ((lib != NULL) && (lib->freef != NULL))
980             lib->freef(lib->data, (void *) define->attrs);
981     }
982     if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
983         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
984     if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
985         xmlHashFree((xmlHashTablePtr) define->data, NULL);
986     if (define->name != NULL)
987         xmlFree(define->name);
988     if (define->ns != NULL)
989         xmlFree(define->ns);
990     if (define->value != NULL)
991         xmlFree(define->value);
992     if (define->contModel != NULL)
993         xmlRegFreeRegexp(define->contModel);
994     xmlFree(define);
995 }
996
997 /**
998  * xmlRelaxNGNewStates:
999  * @ctxt:  a Relax-NG validation context
1000  * @size:  the default size for the container
1001  *
1002  * Allocate a new RelaxNG validation state container
1003  *
1004  * Returns the newly allocated structure or NULL in case or error
1005  */
1006 static xmlRelaxNGStatesPtr
1007 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1008 {
1009     xmlRelaxNGStatesPtr ret;
1010
1011     if ((ctxt != NULL) &&
1012         (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
1013         ctxt->freeStatesNr--;
1014         ret = ctxt->freeStates[ctxt->freeStatesNr];
1015         ret->nbState = 0;
1016         return (ret);
1017     }
1018     if (size < 16)
1019         size = 16;
1020
1021     ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
1022                                           (size -
1023                                            1) *
1024                                           sizeof(xmlRelaxNGValidStatePtr));
1025     if (ret == NULL) {
1026         xmlRngVErrMemory(ctxt, "allocating states\n");
1027         return (NULL);
1028     }
1029     ret->nbState = 0;
1030     ret->maxState = size;
1031     ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1032                                                           sizeof
1033                                                           (xmlRelaxNGValidStatePtr));
1034     if (ret->tabState == NULL) {
1035         xmlRngVErrMemory(ctxt, "allocating states\n");
1036         xmlFree(ret);
1037         return (NULL);
1038     }
1039     return (ret);
1040 }
1041
1042 /**
1043  * xmlRelaxNGAddStateUniq:
1044  * @ctxt:  a Relax-NG validation context
1045  * @states:  the states container
1046  * @state:  the validation state
1047  *
1048  * Add a RelaxNG validation state to the container without checking
1049  * for unicity.
1050  *
1051  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1052  */
1053 static int
1054 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
1055                         xmlRelaxNGStatesPtr states,
1056                         xmlRelaxNGValidStatePtr state)
1057 {
1058     if (state == NULL) {
1059         return (-1);
1060     }
1061     if (states->nbState >= states->maxState) {
1062         xmlRelaxNGValidStatePtr *tmp;
1063         int size;
1064
1065         size = states->maxState * 2;
1066         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1067                                                      (size) *
1068                                                      sizeof
1069                                                      (xmlRelaxNGValidStatePtr));
1070         if (tmp == NULL) {
1071             xmlRngVErrMemory(ctxt, "adding states\n");
1072             return (-1);
1073         }
1074         states->tabState = tmp;
1075         states->maxState = size;
1076     }
1077     states->tabState[states->nbState++] = state;
1078     return (1);
1079 }
1080
1081 /**
1082  * xmlRelaxNGAddState:
1083  * @ctxt:  a Relax-NG validation context
1084  * @states:  the states container
1085  * @state:  the validation state
1086  *
1087  * Add a RelaxNG validation state to the container
1088  *
1089  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1090  */
1091 static int
1092 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1093                     xmlRelaxNGStatesPtr states,
1094                     xmlRelaxNGValidStatePtr state)
1095 {
1096     int i;
1097
1098     if (state == NULL || states == NULL) {
1099         return (-1);
1100     }
1101     if (states->nbState >= states->maxState) {
1102         xmlRelaxNGValidStatePtr *tmp;
1103         int size;
1104
1105         size = states->maxState * 2;
1106         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1107                                                      (size) *
1108                                                      sizeof
1109                                                      (xmlRelaxNGValidStatePtr));
1110         if (tmp == NULL) {
1111             xmlRngVErrMemory(ctxt, "adding states\n");
1112             return (-1);
1113         }
1114         states->tabState = tmp;
1115         states->maxState = size;
1116     }
1117     for (i = 0; i < states->nbState; i++) {
1118         if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1119             xmlRelaxNGFreeValidState(ctxt, state);
1120             return (0);
1121         }
1122     }
1123     states->tabState[states->nbState++] = state;
1124     return (1);
1125 }
1126
1127 /**
1128  * xmlRelaxNGFreeStates:
1129  * @ctxt:  a Relax-NG validation context
1130  * @states:  teh container
1131  *
1132  * Free a RelaxNG validation state container
1133  */
1134 static void
1135 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
1136                      xmlRelaxNGStatesPtr states)
1137 {
1138     if (states == NULL)
1139         return;
1140     if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
1141         ctxt->freeStatesMax = 40;
1142         ctxt->freeStatesNr = 0;
1143         ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1144             xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1145         if (ctxt->freeStates == NULL) {
1146             xmlRngVErrMemory(ctxt, "storing states\n");
1147         }
1148     } else if ((ctxt != NULL)
1149                && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1150         xmlRelaxNGStatesPtr *tmp;
1151
1152         tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1153                                                  2 * ctxt->freeStatesMax *
1154                                                  sizeof
1155                                                  (xmlRelaxNGStatesPtr));
1156         if (tmp == NULL) {
1157             xmlRngVErrMemory(ctxt, "storing states\n");
1158             xmlFree(states->tabState);
1159             xmlFree(states);
1160             return;
1161         }
1162         ctxt->freeStates = tmp;
1163         ctxt->freeStatesMax *= 2;
1164     }
1165     if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
1166         xmlFree(states->tabState);
1167         xmlFree(states);
1168     } else {
1169         ctxt->freeStates[ctxt->freeStatesNr++] = states;
1170     }
1171 }
1172
1173 /**
1174  * xmlRelaxNGNewValidState:
1175  * @ctxt:  a Relax-NG validation context
1176  * @node:  the current node or NULL for the document
1177  *
1178  * Allocate a new RelaxNG validation state
1179  *
1180  * Returns the newly allocated structure or NULL in case or error
1181  */
1182 static xmlRelaxNGValidStatePtr
1183 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1184 {
1185     xmlRelaxNGValidStatePtr ret;
1186     xmlAttrPtr attr;
1187     xmlAttrPtr attrs[MAX_ATTR];
1188     int nbAttrs = 0;
1189     xmlNodePtr root = NULL;
1190
1191     if (node == NULL) {
1192         root = xmlDocGetRootElement(ctxt->doc);
1193         if (root == NULL)
1194             return (NULL);
1195     } else {
1196         attr = node->properties;
1197         while (attr != NULL) {
1198             if (nbAttrs < MAX_ATTR)
1199                 attrs[nbAttrs++] = attr;
1200             else
1201                 nbAttrs++;
1202             attr = attr->next;
1203         }
1204     }
1205     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1206         ctxt->freeState->nbState--;
1207         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1208     } else {
1209         ret =
1210             (xmlRelaxNGValidStatePtr)
1211             xmlMalloc(sizeof(xmlRelaxNGValidState));
1212         if (ret == NULL) {
1213             xmlRngVErrMemory(ctxt, "allocating states\n");
1214             return (NULL);
1215         }
1216         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1217     }
1218     ret->value = NULL;
1219     ret->endvalue = NULL;
1220     if (node == NULL) {
1221         ret->node = (xmlNodePtr) ctxt->doc;
1222         ret->seq = root;
1223     } else {
1224         ret->node = node;
1225         ret->seq = node->children;
1226     }
1227     ret->nbAttrs = 0;
1228     if (nbAttrs > 0) {
1229         if (ret->attrs == NULL) {
1230             if (nbAttrs < 4)
1231                 ret->maxAttrs = 4;
1232             else
1233                 ret->maxAttrs = nbAttrs;
1234             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1235                                                   sizeof(xmlAttrPtr));
1236             if (ret->attrs == NULL) {
1237                 xmlRngVErrMemory(ctxt, "allocating states\n");
1238                 return (ret);
1239             }
1240         } else if (ret->maxAttrs < nbAttrs) {
1241             xmlAttrPtr *tmp;
1242
1243             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1244                                             sizeof(xmlAttrPtr));
1245             if (tmp == NULL) {
1246                 xmlRngVErrMemory(ctxt, "allocating states\n");
1247                 return (ret);
1248             }
1249             ret->attrs = tmp;
1250             ret->maxAttrs = nbAttrs;
1251         }
1252         ret->nbAttrs = nbAttrs;
1253         if (nbAttrs < MAX_ATTR) {
1254             memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1255         } else {
1256             attr = node->properties;
1257             nbAttrs = 0;
1258             while (attr != NULL) {
1259                 ret->attrs[nbAttrs++] = attr;
1260                 attr = attr->next;
1261             }
1262         }
1263     }
1264     ret->nbAttrLeft = ret->nbAttrs;
1265     return (ret);
1266 }
1267
1268 /**
1269  * xmlRelaxNGCopyValidState:
1270  * @ctxt:  a Relax-NG validation context
1271  * @state:  a validation state
1272  *
1273  * Copy the validation state
1274  *
1275  * Returns the newly allocated structure or NULL in case or error
1276  */
1277 static xmlRelaxNGValidStatePtr
1278 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1279                          xmlRelaxNGValidStatePtr state)
1280 {
1281     xmlRelaxNGValidStatePtr ret;
1282     unsigned int maxAttrs;
1283     xmlAttrPtr *attrs;
1284
1285     if (state == NULL)
1286         return (NULL);
1287     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1288         ctxt->freeState->nbState--;
1289         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1290     } else {
1291         ret =
1292             (xmlRelaxNGValidStatePtr)
1293             xmlMalloc(sizeof(xmlRelaxNGValidState));
1294         if (ret == NULL) {
1295             xmlRngVErrMemory(ctxt, "allocating states\n");
1296             return (NULL);
1297         }
1298         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1299     }
1300     attrs = ret->attrs;
1301     maxAttrs = ret->maxAttrs;
1302     memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1303     ret->attrs = attrs;
1304     ret->maxAttrs = maxAttrs;
1305     if (state->nbAttrs > 0) {
1306         if (ret->attrs == NULL) {
1307             ret->maxAttrs = state->maxAttrs;
1308             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1309                                                   sizeof(xmlAttrPtr));
1310             if (ret->attrs == NULL) {
1311                 xmlRngVErrMemory(ctxt, "allocating states\n");
1312                 ret->nbAttrs = 0;
1313                 return (ret);
1314             }
1315         } else if (ret->maxAttrs < state->nbAttrs) {
1316             xmlAttrPtr *tmp;
1317
1318             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1319                                             sizeof(xmlAttrPtr));
1320             if (tmp == NULL) {
1321                 xmlRngVErrMemory(ctxt, "allocating states\n");
1322                 ret->nbAttrs = 0;
1323                 return (ret);
1324             }
1325             ret->maxAttrs = state->maxAttrs;
1326             ret->attrs = tmp;
1327         }
1328         memcpy(ret->attrs, state->attrs,
1329                state->nbAttrs * sizeof(xmlAttrPtr));
1330     }
1331     return (ret);
1332 }
1333
1334 /**
1335  * xmlRelaxNGEqualValidState:
1336  * @ctxt:  a Relax-NG validation context
1337  * @state1:  a validation state
1338  * @state2:  a validation state
1339  *
1340  * Compare the validation states for equality
1341  *
1342  * Returns 1 if equald, 0 otherwise
1343  */
1344 static int
1345 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1346                           xmlRelaxNGValidStatePtr state1,
1347                           xmlRelaxNGValidStatePtr state2)
1348 {
1349     int i;
1350
1351     if ((state1 == NULL) || (state2 == NULL))
1352         return (0);
1353     if (state1 == state2)
1354         return (1);
1355     if (state1->node != state2->node)
1356         return (0);
1357     if (state1->seq != state2->seq)
1358         return (0);
1359     if (state1->nbAttrLeft != state2->nbAttrLeft)
1360         return (0);
1361     if (state1->nbAttrs != state2->nbAttrs)
1362         return (0);
1363     if (state1->endvalue != state2->endvalue)
1364         return (0);
1365     if ((state1->value != state2->value) &&
1366         (!xmlStrEqual(state1->value, state2->value)))
1367         return (0);
1368     for (i = 0; i < state1->nbAttrs; i++) {
1369         if (state1->attrs[i] != state2->attrs[i])
1370             return (0);
1371     }
1372     return (1);
1373 }
1374
1375 /**
1376  * xmlRelaxNGFreeValidState:
1377  * @state:  a validation state structure
1378  *
1379  * Deallocate a RelaxNG validation state structure.
1380  */
1381 static void
1382 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1383                          xmlRelaxNGValidStatePtr state)
1384 {
1385     if (state == NULL)
1386         return;
1387
1388     if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1389         ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1390     }
1391     if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1392         if (state->attrs != NULL)
1393             xmlFree(state->attrs);
1394         xmlFree(state);
1395     } else {
1396         xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1397     }
1398 }
1399
1400 /************************************************************************
1401  *                                                                      *
1402  *                      Semi internal functions                         *
1403  *                                                                      *
1404  ************************************************************************/
1405
1406 /**
1407  * xmlRelaxParserSetFlag:
1408  * @ctxt: a RelaxNG parser context
1409  * @flags: a set of flags values
1410  *
1411  * Semi private function used to pass informations to a parser context
1412  * which are a combination of xmlRelaxNGParserFlag .
1413  *
1414  * Returns 0 if success and -1 in case of error
1415  */
1416 int
1417 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1418 {
1419     if (ctxt == NULL) return(-1);
1420     if (flags & XML_RELAXNGP_FREE_DOC) {
1421         ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1422         flags -= XML_RELAXNGP_FREE_DOC;
1423     }
1424     if (flags & XML_RELAXNGP_CRNG) {
1425         ctxt->crng |= XML_RELAXNGP_CRNG;
1426         flags -= XML_RELAXNGP_CRNG;
1427     }
1428     if (flags != 0) return(-1);
1429     return(0);
1430 }
1431
1432 /************************************************************************
1433  *                                                                      *
1434  *                      Document functions                              *
1435  *                                                                      *
1436  ************************************************************************/
1437 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1438                                       xmlDocPtr doc);
1439
1440 /**
1441  * xmlRelaxNGIncludePush:
1442  * @ctxt:  the parser context
1443  * @value:  the element doc
1444  *
1445  * Pushes a new include on top of the include stack
1446  *
1447  * Returns 0 in case of error, the index in the stack otherwise
1448  */
1449 static int
1450 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1451                       xmlRelaxNGIncludePtr value)
1452 {
1453     if (ctxt->incTab == NULL) {
1454         ctxt->incMax = 4;
1455         ctxt->incNr = 0;
1456         ctxt->incTab =
1457             (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1458                                                sizeof(ctxt->incTab[0]));
1459         if (ctxt->incTab == NULL) {
1460             xmlRngPErrMemory(ctxt, "allocating include\n");
1461             return (0);
1462         }
1463     }
1464     if (ctxt->incNr >= ctxt->incMax) {
1465         ctxt->incMax *= 2;
1466         ctxt->incTab =
1467             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1468                                                 ctxt->incMax *
1469                                                 sizeof(ctxt->incTab[0]));
1470         if (ctxt->incTab == NULL) {
1471             xmlRngPErrMemory(ctxt, "allocating include\n");
1472             return (0);
1473         }
1474     }
1475     ctxt->incTab[ctxt->incNr] = value;
1476     ctxt->inc = value;
1477     return (ctxt->incNr++);
1478 }
1479
1480 /**
1481  * xmlRelaxNGIncludePop:
1482  * @ctxt: the parser context
1483  *
1484  * Pops the top include from the include stack
1485  *
1486  * Returns the include just removed
1487  */
1488 static xmlRelaxNGIncludePtr
1489 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1490 {
1491     xmlRelaxNGIncludePtr ret;
1492
1493     if (ctxt->incNr <= 0)
1494         return (NULL);
1495     ctxt->incNr--;
1496     if (ctxt->incNr > 0)
1497         ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1498     else
1499         ctxt->inc = NULL;
1500     ret = ctxt->incTab[ctxt->incNr];
1501     ctxt->incTab[ctxt->incNr] = NULL;
1502     return (ret);
1503 }
1504
1505 /**
1506  * xmlRelaxNGRemoveRedefine:
1507  * @ctxt: the parser context
1508  * @URL:  the normalized URL
1509  * @target:  the included target
1510  * @name:  the define name to eliminate
1511  *
1512  * Applies the elimination algorithm of 4.7
1513  *
1514  * Returns 0 in case of error, 1 in case of success.
1515  */
1516 static int
1517 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1518                          const xmlChar * URL ATTRIBUTE_UNUSED,
1519                          xmlNodePtr target, const xmlChar * name)
1520 {
1521     int found = 0;
1522     xmlNodePtr tmp, tmp2;
1523     xmlChar *name2;
1524
1525 #ifdef DEBUG_INCLUDE
1526     if (name == NULL)
1527         xmlGenericError(xmlGenericErrorContext,
1528                         "Elimination of <include> start from %s\n", URL);
1529     else
1530         xmlGenericError(xmlGenericErrorContext,
1531                         "Elimination of <include> define %s from %s\n",
1532                         name, URL);
1533 #endif
1534     tmp = target;
1535     while (tmp != NULL) {
1536         tmp2 = tmp->next;
1537         if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1538             found = 1;
1539             xmlUnlinkNode(tmp);
1540             xmlFreeNode(tmp);
1541         } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1542             name2 = xmlGetProp(tmp, BAD_CAST "name");
1543             xmlRelaxNGNormExtSpace(name2);
1544             if (name2 != NULL) {
1545                 if (xmlStrEqual(name, name2)) {
1546                     found = 1;
1547                     xmlUnlinkNode(tmp);
1548                     xmlFreeNode(tmp);
1549                 }
1550                 xmlFree(name2);
1551             }
1552         } else if (IS_RELAXNG(tmp, "include")) {
1553             xmlChar *href = NULL;
1554             xmlRelaxNGDocumentPtr inc = tmp->psvi;
1555
1556             if ((inc != NULL) && (inc->doc != NULL) &&
1557                 (inc->doc->children != NULL)) {
1558
1559                 if (xmlStrEqual
1560                     (inc->doc->children->name, BAD_CAST "grammar")) {
1561 #ifdef DEBUG_INCLUDE
1562                     href = xmlGetProp(tmp, BAD_CAST "href");
1563 #endif
1564                     if (xmlRelaxNGRemoveRedefine(ctxt, href,
1565                                                  xmlDocGetRootElement(inc->doc)->children,
1566                                                  name) == 1) {
1567                         found = 1;
1568                     }
1569 #ifdef DEBUG_INCLUDE
1570                     if (href != NULL)
1571                         xmlFree(href);
1572 #endif
1573                 }
1574             }
1575         }
1576         tmp = tmp2;
1577     }
1578     return (found);
1579 }
1580
1581 /**
1582  * xmlRelaxNGLoadInclude:
1583  * @ctxt: the parser context
1584  * @URL:  the normalized URL
1585  * @node: the include node.
1586  * @ns:  the namespace passed from the context.
1587  *
1588  * First lookup if the document is already loaded into the parser context,
1589  * check against recursion. If not found the resource is loaded and
1590  * the content is preprocessed before being returned back to the caller.
1591  *
1592  * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1593  */
1594 static xmlRelaxNGIncludePtr
1595 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1596                       xmlNodePtr node, const xmlChar * ns)
1597 {
1598     xmlRelaxNGIncludePtr ret = NULL;
1599     xmlDocPtr doc;
1600     int i;
1601     xmlNodePtr root, cur;
1602
1603 #ifdef DEBUG_INCLUDE
1604     xmlGenericError(xmlGenericErrorContext,
1605                     "xmlRelaxNGLoadInclude(%s)\n", URL);
1606 #endif
1607
1608     /*
1609      * check against recursion in the stack
1610      */
1611     for (i = 0; i < ctxt->incNr; i++) {
1612         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1613             xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1614                        "Detected an Include recursion for %s\n", URL,
1615                        NULL);
1616             return (NULL);
1617         }
1618     }
1619
1620     /*
1621      * load the document
1622      */
1623     doc = xmlReadFile((const char *) URL,NULL,0);
1624     if (doc == NULL) {
1625         xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1626                    "xmlRelaxNG: could not load %s\n", URL, NULL);
1627         return (NULL);
1628     }
1629 #ifdef DEBUG_INCLUDE
1630     xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
1631 #endif
1632
1633     /*
1634      * Allocate the document structures and register it first.
1635      */
1636     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1637     if (ret == NULL) {
1638         xmlRngPErrMemory(ctxt, "allocating include\n");
1639         xmlFreeDoc(doc);
1640         return (NULL);
1641     }
1642     memset(ret, 0, sizeof(xmlRelaxNGInclude));
1643     ret->doc = doc;
1644     ret->href = xmlStrdup(URL);
1645     ret->next = ctxt->includes;
1646     ctxt->includes = ret;
1647
1648     /*
1649      * transmit the ns if needed
1650      */
1651     if (ns != NULL) {
1652         root = xmlDocGetRootElement(doc);
1653         if (root != NULL) {
1654             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1655                 xmlSetProp(root, BAD_CAST "ns", ns);
1656             }
1657         }
1658     }
1659
1660     /*
1661      * push it on the stack
1662      */
1663     xmlRelaxNGIncludePush(ctxt, ret);
1664
1665     /*
1666      * Some preprocessing of the document content, this include recursing
1667      * in the include stack.
1668      */
1669 #ifdef DEBUG_INCLUDE
1670     xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
1671 #endif
1672
1673     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1674     if (doc == NULL) {
1675         ctxt->inc = NULL;
1676         return (NULL);
1677     }
1678
1679     /*
1680      * Pop up the include from the stack
1681      */
1682     xmlRelaxNGIncludePop(ctxt);
1683
1684 #ifdef DEBUG_INCLUDE
1685     xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
1686 #endif
1687     /*
1688      * Check that the top element is a grammar
1689      */
1690     root = xmlDocGetRootElement(doc);
1691     if (root == NULL) {
1692         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1693                    "xmlRelaxNG: included document is empty %s\n", URL,
1694                    NULL);
1695         return (NULL);
1696     }
1697     if (!IS_RELAXNG(root, "grammar")) {
1698         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1699                    "xmlRelaxNG: included document %s root is not a grammar\n",
1700                    URL, NULL);
1701         return (NULL);
1702     }
1703
1704     /*
1705      * Elimination of redefined rules in the include.
1706      */
1707     cur = node->children;
1708     while (cur != NULL) {
1709         if (IS_RELAXNG(cur, "start")) {
1710             int found = 0;
1711
1712             found =
1713                 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1714             if (!found) {
1715                 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1716                            "xmlRelaxNG: include %s has a start but not the included grammar\n",
1717                            URL, NULL);
1718             }
1719         } else if (IS_RELAXNG(cur, "define")) {
1720             xmlChar *name;
1721
1722             name = xmlGetProp(cur, BAD_CAST "name");
1723             if (name == NULL) {
1724                 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1725                            "xmlRelaxNG: include %s has define without name\n",
1726                            URL, NULL);
1727             } else {
1728                 int found;
1729
1730                 xmlRelaxNGNormExtSpace(name);
1731                 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1732                                                  root->children, name);
1733                 if (!found) {
1734                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1735                                "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1736                                URL, name);
1737                 }
1738                 xmlFree(name);
1739             }
1740         }
1741         cur = cur->next;
1742     }
1743
1744
1745     return (ret);
1746 }
1747
1748 /**
1749  * xmlRelaxNGValidErrorPush:
1750  * @ctxt:  the validation context
1751  * @err:  the error code
1752  * @arg1:  the first string argument
1753  * @arg2:  the second string argument
1754  * @dup:  arg need to be duplicated
1755  *
1756  * Pushes a new error on top of the error stack
1757  *
1758  * Returns 0 in case of error, the index in the stack otherwise
1759  */
1760 static int
1761 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1762                          xmlRelaxNGValidErr err, const xmlChar * arg1,
1763                          const xmlChar * arg2, int dup)
1764 {
1765     xmlRelaxNGValidErrorPtr cur;
1766
1767 #ifdef DEBUG_ERROR
1768     xmlGenericError(xmlGenericErrorContext,
1769                     "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1770 #endif
1771     if (ctxt->errTab == NULL) {
1772         ctxt->errMax = 8;
1773         ctxt->errNr = 0;
1774         ctxt->errTab =
1775             (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1776                                                 sizeof
1777                                                 (xmlRelaxNGValidError));
1778         if (ctxt->errTab == NULL) {
1779             xmlRngVErrMemory(ctxt, "pushing error\n");
1780             return (0);
1781         }
1782         ctxt->err = NULL;
1783     }
1784     if (ctxt->errNr >= ctxt->errMax) {
1785         ctxt->errMax *= 2;
1786         ctxt->errTab =
1787             (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1788                                                  ctxt->errMax *
1789                                                  sizeof
1790                                                  (xmlRelaxNGValidError));
1791         if (ctxt->errTab == NULL) {
1792             xmlRngVErrMemory(ctxt, "pushing error\n");
1793             return (0);
1794         }
1795         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1796     }
1797     if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1798         (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1799         return (ctxt->errNr);
1800     cur = &ctxt->errTab[ctxt->errNr];
1801     cur->err = err;
1802     if (dup) {
1803         cur->arg1 = xmlStrdup(arg1);
1804         cur->arg2 = xmlStrdup(arg2);
1805         cur->flags = ERROR_IS_DUP;
1806     } else {
1807         cur->arg1 = arg1;
1808         cur->arg2 = arg2;
1809         cur->flags = 0;
1810     }
1811     if (ctxt->state != NULL) {
1812         cur->node = ctxt->state->node;
1813         cur->seq = ctxt->state->seq;
1814     } else {
1815         cur->node = NULL;
1816         cur->seq = NULL;
1817     }
1818     ctxt->err = cur;
1819     return (ctxt->errNr++);
1820 }
1821
1822 /**
1823  * xmlRelaxNGValidErrorPop:
1824  * @ctxt: the validation context
1825  *
1826  * Pops the top error from the error stack
1827  */
1828 static void
1829 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1830 {
1831     xmlRelaxNGValidErrorPtr cur;
1832
1833     if (ctxt->errNr <= 0) {
1834         ctxt->err = NULL;
1835         return;
1836     }
1837     ctxt->errNr--;
1838     if (ctxt->errNr > 0)
1839         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1840     else
1841         ctxt->err = NULL;
1842     cur = &ctxt->errTab[ctxt->errNr];
1843     if (cur->flags & ERROR_IS_DUP) {
1844         if (cur->arg1 != NULL)
1845             xmlFree((xmlChar *) cur->arg1);
1846         cur->arg1 = NULL;
1847         if (cur->arg2 != NULL)
1848             xmlFree((xmlChar *) cur->arg2);
1849         cur->arg2 = NULL;
1850         cur->flags = 0;
1851     }
1852 }
1853
1854 /**
1855  * xmlRelaxNGDocumentPush:
1856  * @ctxt:  the parser context
1857  * @value:  the element doc
1858  *
1859  * Pushes a new doc on top of the doc stack
1860  *
1861  * Returns 0 in case of error, the index in the stack otherwise
1862  */
1863 static int
1864 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1865                        xmlRelaxNGDocumentPtr value)
1866 {
1867     if (ctxt->docTab == NULL) {
1868         ctxt->docMax = 4;
1869         ctxt->docNr = 0;
1870         ctxt->docTab =
1871             (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1872                                                 sizeof(ctxt->docTab[0]));
1873         if (ctxt->docTab == NULL) {
1874             xmlRngPErrMemory(ctxt, "adding document\n");
1875             return (0);
1876         }
1877     }
1878     if (ctxt->docNr >= ctxt->docMax) {
1879         ctxt->docMax *= 2;
1880         ctxt->docTab =
1881             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1882                                                  ctxt->docMax *
1883                                                  sizeof(ctxt->docTab[0]));
1884         if (ctxt->docTab == NULL) {
1885             xmlRngPErrMemory(ctxt, "adding document\n");
1886             return (0);
1887         }
1888     }
1889     ctxt->docTab[ctxt->docNr] = value;
1890     ctxt->doc = value;
1891     return (ctxt->docNr++);
1892 }
1893
1894 /**
1895  * xmlRelaxNGDocumentPop:
1896  * @ctxt: the parser context
1897  *
1898  * Pops the top doc from the doc stack
1899  *
1900  * Returns the doc just removed
1901  */
1902 static xmlRelaxNGDocumentPtr
1903 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1904 {
1905     xmlRelaxNGDocumentPtr ret;
1906
1907     if (ctxt->docNr <= 0)
1908         return (NULL);
1909     ctxt->docNr--;
1910     if (ctxt->docNr > 0)
1911         ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1912     else
1913         ctxt->doc = NULL;
1914     ret = ctxt->docTab[ctxt->docNr];
1915     ctxt->docTab[ctxt->docNr] = NULL;
1916     return (ret);
1917 }
1918
1919 /**
1920  * xmlRelaxNGLoadExternalRef:
1921  * @ctxt: the parser context
1922  * @URL:  the normalized URL
1923  * @ns:  the inherited ns if any
1924  *
1925  * First lookup if the document is already loaded into the parser context,
1926  * check against recursion. If not found the resource is loaded and
1927  * the content is preprocessed before being returned back to the caller.
1928  *
1929  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1930  */
1931 static xmlRelaxNGDocumentPtr
1932 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1933                           const xmlChar * URL, const xmlChar * ns)
1934 {
1935     xmlRelaxNGDocumentPtr ret = NULL;
1936     xmlDocPtr doc;
1937     xmlNodePtr root;
1938     int i;
1939
1940     /*
1941      * check against recursion in the stack
1942      */
1943     for (i = 0; i < ctxt->docNr; i++) {
1944         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1945             xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1946                        "Detected an externalRef recursion for %s\n", URL,
1947                        NULL);
1948             return (NULL);
1949         }
1950     }
1951
1952     /*
1953      * load the document
1954      */
1955     doc = xmlReadFile((const char *) URL,NULL,0);
1956     if (doc == NULL) {
1957         xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1958                    "xmlRelaxNG: could not load %s\n", URL, NULL);
1959         return (NULL);
1960     }
1961
1962     /*
1963      * Allocate the document structures and register it first.
1964      */
1965     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1966     if (ret == NULL) {
1967         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1968                    "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1969         xmlFreeDoc(doc);
1970         return (NULL);
1971     }
1972     memset(ret, 0, sizeof(xmlRelaxNGDocument));
1973     ret->doc = doc;
1974     ret->href = xmlStrdup(URL);
1975     ret->next = ctxt->documents;
1976     ret->externalRef = 1;
1977     ctxt->documents = ret;
1978
1979     /*
1980      * transmit the ns if needed
1981      */
1982     if (ns != NULL) {
1983         root = xmlDocGetRootElement(doc);
1984         if (root != NULL) {
1985             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1986                 xmlSetProp(root, BAD_CAST "ns", ns);
1987             }
1988         }
1989     }
1990
1991     /*
1992      * push it on the stack and register it in the hash table
1993      */
1994     xmlRelaxNGDocumentPush(ctxt, ret);
1995
1996     /*
1997      * Some preprocessing of the document content
1998      */
1999     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
2000     if (doc == NULL) {
2001         ctxt->doc = NULL;
2002         return (NULL);
2003     }
2004
2005     xmlRelaxNGDocumentPop(ctxt);
2006
2007     return (ret);
2008 }
2009
2010 /************************************************************************
2011  *                                                                      *
2012  *                      Error functions                                 *
2013  *                                                                      *
2014  ************************************************************************/
2015
2016 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2017 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2018 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2019 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2020 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2021
2022 static const char *
2023 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2024 {
2025     if (def == NULL)
2026         return ("none");
2027     switch (def->type) {
2028         case XML_RELAXNG_EMPTY:
2029             return ("empty");
2030         case XML_RELAXNG_NOT_ALLOWED:
2031             return ("notAllowed");
2032         case XML_RELAXNG_EXCEPT:
2033             return ("except");
2034         case XML_RELAXNG_TEXT:
2035             return ("text");
2036         case XML_RELAXNG_ELEMENT:
2037             return ("element");
2038         case XML_RELAXNG_DATATYPE:
2039             return ("datatype");
2040         case XML_RELAXNG_VALUE:
2041             return ("value");
2042         case XML_RELAXNG_LIST:
2043             return ("list");
2044         case XML_RELAXNG_ATTRIBUTE:
2045             return ("attribute");
2046         case XML_RELAXNG_DEF:
2047             return ("def");
2048         case XML_RELAXNG_REF:
2049             return ("ref");
2050         case XML_RELAXNG_EXTERNALREF:
2051             return ("externalRef");
2052         case XML_RELAXNG_PARENTREF:
2053             return ("parentRef");
2054         case XML_RELAXNG_OPTIONAL:
2055             return ("optional");
2056         case XML_RELAXNG_ZEROORMORE:
2057             return ("zeroOrMore");
2058         case XML_RELAXNG_ONEORMORE:
2059             return ("oneOrMore");
2060         case XML_RELAXNG_CHOICE:
2061             return ("choice");
2062         case XML_RELAXNG_GROUP:
2063             return ("group");
2064         case XML_RELAXNG_INTERLEAVE:
2065             return ("interleave");
2066         case XML_RELAXNG_START:
2067             return ("start");
2068         case XML_RELAXNG_NOOP:
2069             return ("noop");
2070         case XML_RELAXNG_PARAM:
2071             return ("param");
2072     }
2073     return ("unknown");
2074 }
2075
2076 /**
2077  * xmlRelaxNGGetErrorString:
2078  * @err:  the error code
2079  * @arg1:  the first string argument
2080  * @arg2:  the second string argument
2081  *
2082  * computes a formatted error string for the given error code and args
2083  *
2084  * Returns the error string, it must be deallocated by the caller
2085  */
2086 static xmlChar *
2087 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2088                          const xmlChar * arg2)
2089 {
2090     char msg[1000];
2091     xmlChar *result;
2092
2093     if (arg1 == NULL)
2094         arg1 = BAD_CAST "";
2095     if (arg2 == NULL)
2096         arg2 = BAD_CAST "";
2097
2098     msg[0] = 0;
2099     switch (err) {
2100         case XML_RELAXNG_OK:
2101             return (NULL);
2102         case XML_RELAXNG_ERR_MEMORY:
2103             return (xmlCharStrdup("out of memory\n"));
2104         case XML_RELAXNG_ERR_TYPE:
2105             snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2106             break;
2107         case XML_RELAXNG_ERR_TYPEVAL:
2108             snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2109                      arg2);
2110             break;
2111         case XML_RELAXNG_ERR_DUPID:
2112             snprintf(msg, 1000, "ID %s redefined\n", arg1);
2113             break;
2114         case XML_RELAXNG_ERR_TYPECMP:
2115             snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2116             break;
2117         case XML_RELAXNG_ERR_NOSTATE:
2118             return (xmlCharStrdup("Internal error: no state\n"));
2119         case XML_RELAXNG_ERR_NODEFINE:
2120             return (xmlCharStrdup("Internal error: no define\n"));
2121         case XML_RELAXNG_ERR_INTERNAL:
2122             snprintf(msg, 1000, "Internal error: %s\n", arg1);
2123             break;
2124         case XML_RELAXNG_ERR_LISTEXTRA:
2125             snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2126             break;
2127         case XML_RELAXNG_ERR_INTERNODATA:
2128             return (xmlCharStrdup
2129                     ("Internal: interleave block has no data\n"));
2130         case XML_RELAXNG_ERR_INTERSEQ:
2131             return (xmlCharStrdup("Invalid sequence in interleave\n"));
2132         case XML_RELAXNG_ERR_INTEREXTRA:
2133             snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2134             break;
2135         case XML_RELAXNG_ERR_ELEMNAME:
2136             snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2137                      arg2);
2138             break;
2139         case XML_RELAXNG_ERR_ELEMNONS:
2140             snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2141                      arg1);
2142             break;
2143         case XML_RELAXNG_ERR_ELEMWRONGNS:
2144             snprintf(msg, 1000,
2145                      "Element %s has wrong namespace: expecting %s\n", arg1,
2146                      arg2);
2147             break;
2148         case XML_RELAXNG_ERR_ELEMWRONG:
2149             snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2150             break;
2151         case XML_RELAXNG_ERR_TEXTWRONG:
2152             snprintf(msg, 1000,
2153                      "Did not expect text in element %s content\n", arg1);
2154             break;
2155         case XML_RELAXNG_ERR_ELEMEXTRANS:
2156             snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2157                      arg1);
2158             break;
2159         case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2160             snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2161             break;
2162         case XML_RELAXNG_ERR_NOELEM:
2163             snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2164                      arg1);
2165             break;
2166         case XML_RELAXNG_ERR_NOTELEM:
2167             return (xmlCharStrdup("Expecting an element got text\n"));
2168         case XML_RELAXNG_ERR_ATTRVALID:
2169             snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2170                      arg1);
2171             break;
2172         case XML_RELAXNG_ERR_CONTENTVALID:
2173             snprintf(msg, 1000, "Element %s failed to validate content\n",
2174                      arg1);
2175             break;
2176         case XML_RELAXNG_ERR_EXTRACONTENT:
2177             snprintf(msg, 1000, "Element %s has extra content: %s\n",
2178                      arg1, arg2);
2179             break;
2180         case XML_RELAXNG_ERR_INVALIDATTR:
2181             snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2182                      arg1, arg2);
2183             break;
2184         case XML_RELAXNG_ERR_LACKDATA:
2185             snprintf(msg, 1000, "Datatype element %s contains no data\n",
2186                      arg1);
2187             break;
2188         case XML_RELAXNG_ERR_DATAELEM:
2189             snprintf(msg, 1000, "Datatype element %s has child elements\n",
2190                      arg1);
2191             break;
2192         case XML_RELAXNG_ERR_VALELEM:
2193             snprintf(msg, 1000, "Value element %s has child elements\n",
2194                      arg1);
2195             break;
2196         case XML_RELAXNG_ERR_LISTELEM:
2197             snprintf(msg, 1000, "List element %s has child elements\n",
2198                      arg1);
2199             break;
2200         case XML_RELAXNG_ERR_DATATYPE:
2201             snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2202             break;
2203         case XML_RELAXNG_ERR_VALUE:
2204             snprintf(msg, 1000, "Error validating value %s\n", arg1);
2205             break;
2206         case XML_RELAXNG_ERR_LIST:
2207             return (xmlCharStrdup("Error validating list\n"));
2208         case XML_RELAXNG_ERR_NOGRAMMAR:
2209             return (xmlCharStrdup("No top grammar defined\n"));
2210         case XML_RELAXNG_ERR_EXTRADATA:
2211             return (xmlCharStrdup("Extra data in the document\n"));
2212         default:
2213             return (xmlCharStrdup("Unknown error !\n"));
2214     }
2215     if (msg[0] == 0) {
2216         snprintf(msg, 1000, "Unknown error code %d\n", err);
2217     }
2218     msg[1000 - 1] = 0;
2219     result = xmlCharStrdup(msg);
2220     return (xmlEscapeFormatString(&result));
2221 }
2222
2223 /**
2224  * xmlRelaxNGShowValidError:
2225  * @ctxt:  the validation context
2226  * @err:  the error number
2227  * @node:  the node
2228  * @child:  the node child generating the problem.
2229  * @arg1:  the first argument
2230  * @arg2:  the second argument
2231  *
2232  * Show a validation error.
2233  */
2234 static void
2235 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2236                          xmlRelaxNGValidErr err, xmlNodePtr node,
2237                          xmlNodePtr child, const xmlChar * arg1,
2238                          const xmlChar * arg2)
2239 {
2240     xmlChar *msg;
2241
2242     if (ctxt->flags & FLAGS_NOERROR)
2243         return;
2244
2245 #ifdef DEBUG_ERROR
2246     xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
2247 #endif
2248     msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2249     if (msg == NULL)
2250         return;
2251
2252     if (ctxt->errNo == XML_RELAXNG_OK)
2253         ctxt->errNo = err;
2254     xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2255                (const char *) msg, arg1, arg2);
2256     xmlFree(msg);
2257 }
2258
2259 /**
2260  * xmlRelaxNGPopErrors:
2261  * @ctxt:  the validation context
2262  * @level:  the error level in the stack
2263  *
2264  * pop and discard all errors until the given level is reached
2265  */
2266 static void
2267 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2268 {
2269     int i;
2270     xmlRelaxNGValidErrorPtr err;
2271
2272 #ifdef DEBUG_ERROR
2273     xmlGenericError(xmlGenericErrorContext,
2274                     "Pop errors till level %d\n", level);
2275 #endif
2276     for (i = level; i < ctxt->errNr; i++) {
2277         err = &ctxt->errTab[i];
2278         if (err->flags & ERROR_IS_DUP) {
2279             if (err->arg1 != NULL)
2280                 xmlFree((xmlChar *) err->arg1);
2281             err->arg1 = NULL;
2282             if (err->arg2 != NULL)
2283                 xmlFree((xmlChar *) err->arg2);
2284             err->arg2 = NULL;
2285             err->flags = 0;
2286         }
2287     }
2288     ctxt->errNr = level;
2289     if (ctxt->errNr <= 0)
2290         ctxt->err = NULL;
2291 }
2292
2293 /**
2294  * xmlRelaxNGDumpValidError:
2295  * @ctxt:  the validation context
2296  *
2297  * Show all validation error over a given index.
2298  */
2299 static void
2300 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2301 {
2302     int i, j, k;
2303     xmlRelaxNGValidErrorPtr err, dup;
2304
2305 #ifdef DEBUG_ERROR
2306     xmlGenericError(xmlGenericErrorContext,
2307                     "Dumping error stack %d errors\n", ctxt->errNr);
2308 #endif
2309     for (i = 0, k = 0; i < ctxt->errNr; i++) {
2310         err = &ctxt->errTab[i];
2311         if (k < MAX_ERROR) {
2312             for (j = 0; j < i; j++) {
2313                 dup = &ctxt->errTab[j];
2314                 if ((err->err == dup->err) && (err->node == dup->node) &&
2315                     (xmlStrEqual(err->arg1, dup->arg1)) &&
2316                     (xmlStrEqual(err->arg2, dup->arg2))) {
2317                     goto skip;
2318                 }
2319             }
2320             xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2321                                      err->arg1, err->arg2);
2322             k++;
2323         }
2324       skip:
2325         if (err->flags & ERROR_IS_DUP) {
2326             if (err->arg1 != NULL)
2327                 xmlFree((xmlChar *) err->arg1);
2328             err->arg1 = NULL;
2329             if (err->arg2 != NULL)
2330                 xmlFree((xmlChar *) err->arg2);
2331             err->arg2 = NULL;
2332             err->flags = 0;
2333         }
2334     }
2335     ctxt->errNr = 0;
2336 }
2337
2338 /**
2339  * xmlRelaxNGAddValidError:
2340  * @ctxt:  the validation context
2341  * @err:  the error number
2342  * @arg1:  the first argument
2343  * @arg2:  the second argument
2344  * @dup:  need to dup the args
2345  *
2346  * Register a validation error, either generating it if it's sure
2347  * or stacking it for later handling if unsure.
2348  */
2349 static void
2350 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2351                         xmlRelaxNGValidErr err, const xmlChar * arg1,
2352                         const xmlChar * arg2, int dup)
2353 {
2354     if (ctxt == NULL)
2355         return;
2356     if (ctxt->flags & FLAGS_NOERROR)
2357         return;
2358
2359 #ifdef DEBUG_ERROR
2360     xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
2361 #endif
2362     /*
2363      * generate the error directly
2364      */
2365     if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2366          (ctxt->flags & FLAGS_NEGATIVE)) {
2367         xmlNodePtr node, seq;
2368
2369         /*
2370          * Flush first any stacked error which might be the
2371          * real cause of the problem.
2372          */
2373         if (ctxt->errNr != 0)
2374             xmlRelaxNGDumpValidError(ctxt);
2375         if (ctxt->state != NULL) {
2376             node = ctxt->state->node;
2377             seq = ctxt->state->seq;
2378         } else {
2379             node = seq = NULL;
2380         }
2381         if ((node == NULL) && (seq == NULL)) {
2382             node = ctxt->pnode;
2383         }
2384         xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2385     }
2386     /*
2387      * Stack the error for later processing if needed
2388      */
2389     else {
2390         xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2391     }
2392 }
2393
2394
2395 /************************************************************************
2396  *                                                                      *
2397  *                      Type library hooks                              *
2398  *                                                                      *
2399  ************************************************************************/
2400 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2401                                     const xmlChar * str);
2402
2403 /**
2404  * xmlRelaxNGSchemaTypeHave:
2405  * @data:  data needed for the library
2406  * @type:  the type name
2407  *
2408  * Check if the given type is provided by
2409  * the W3C XMLSchema Datatype library.
2410  *
2411  * Returns 1 if yes, 0 if no and -1 in case of error.
2412  */
2413 static int
2414 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2415 {
2416     xmlSchemaTypePtr typ;
2417
2418     if (type == NULL)
2419         return (-1);
2420     typ = xmlSchemaGetPredefinedType(type,
2421                                      BAD_CAST
2422                                      "http://www.w3.org/2001/XMLSchema");
2423     if (typ == NULL)
2424         return (0);
2425     return (1);
2426 }
2427
2428 /**
2429  * xmlRelaxNGSchemaTypeCheck:
2430  * @data:  data needed for the library
2431  * @type:  the type name
2432  * @value:  the value to check
2433  * @node:  the node
2434  *
2435  * Check if the given type and value are validated by
2436  * the W3C XMLSchema Datatype library.
2437  *
2438  * Returns 1 if yes, 0 if no and -1 in case of error.
2439  */
2440 static int
2441 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2442                           const xmlChar * type,
2443                           const xmlChar * value,
2444                           void **result, xmlNodePtr node)
2445 {
2446     xmlSchemaTypePtr typ;
2447     int ret;
2448
2449     if ((type == NULL) || (value == NULL))
2450         return (-1);
2451     typ = xmlSchemaGetPredefinedType(type,
2452                                      BAD_CAST
2453                                      "http://www.w3.org/2001/XMLSchema");
2454     if (typ == NULL)
2455         return (-1);
2456     ret = xmlSchemaValPredefTypeNode(typ, value,
2457                                      (xmlSchemaValPtr *) result, node);
2458     if (ret == 2)               /* special ID error code */
2459         return (2);
2460     if (ret == 0)
2461         return (1);
2462     if (ret > 0)
2463         return (0);
2464     return (-1);
2465 }
2466
2467 /**
2468  * xmlRelaxNGSchemaFacetCheck:
2469  * @data:  data needed for the library
2470  * @type:  the type name
2471  * @facet:  the facet name
2472  * @val:  the facet value
2473  * @strval:  the string value
2474  * @value:  the value to check
2475  *
2476  * Function provided by a type library to check a value facet
2477  *
2478  * Returns 1 if yes, 0 if no and -1 in case of error.
2479  */
2480 static int
2481 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2482                            const xmlChar * type, const xmlChar * facetname,
2483                            const xmlChar * val, const xmlChar * strval,
2484                            void *value)
2485 {
2486     xmlSchemaFacetPtr facet;
2487     xmlSchemaTypePtr typ;
2488     int ret;
2489
2490     if ((type == NULL) || (strval == NULL))
2491         return (-1);
2492     typ = xmlSchemaGetPredefinedType(type,
2493                                      BAD_CAST
2494                                      "http://www.w3.org/2001/XMLSchema");
2495     if (typ == NULL)
2496         return (-1);
2497
2498     facet = xmlSchemaNewFacet();
2499     if (facet == NULL)
2500         return (-1);
2501
2502     if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2503         facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2504     } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2505         facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2506     } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2507         facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2508     } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2509         facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2510     } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2511         facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2512     } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2513         facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2514     } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2515         facet->type = XML_SCHEMA_FACET_PATTERN;
2516     } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2517         facet->type = XML_SCHEMA_FACET_ENUMERATION;
2518     } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2519         facet->type = XML_SCHEMA_FACET_WHITESPACE;
2520     } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2521         facet->type = XML_SCHEMA_FACET_LENGTH;
2522     } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2523         facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2524     } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2525         facet->type = XML_SCHEMA_FACET_MINLENGTH;
2526     } else {
2527         xmlSchemaFreeFacet(facet);
2528         return (-1);
2529     }
2530     facet->value = val;
2531     ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2532     if (ret != 0) {
2533         xmlSchemaFreeFacet(facet);
2534         return (-1);
2535     }
2536     ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2537     xmlSchemaFreeFacet(facet);
2538     if (ret != 0)
2539         return (-1);
2540     return (0);
2541 }
2542
2543 /**
2544  * xmlRelaxNGSchemaFreeValue:
2545  * @data:  data needed for the library
2546  * @value:  the value to free
2547  *
2548  * Function provided by a type library to free a Schemas value
2549  *
2550  * Returns 1 if yes, 0 if no and -1 in case of error.
2551  */
2552 static void
2553 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2554 {
2555     xmlSchemaFreeValue(value);
2556 }
2557
2558 /**
2559  * xmlRelaxNGSchemaTypeCompare:
2560  * @data:  data needed for the library
2561  * @type:  the type name
2562  * @value1:  the first value
2563  * @value2:  the second value
2564  *
2565  * Compare two values for equality accordingly a type from the W3C XMLSchema
2566  * Datatype library.
2567  *
2568  * Returns 1 if equal, 0 if no and -1 in case of error.
2569  */
2570 static int
2571 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2572                             const xmlChar * type,
2573                             const xmlChar * value1,
2574                             xmlNodePtr ctxt1,
2575                             void *comp1,
2576                             const xmlChar * value2, xmlNodePtr ctxt2)
2577 {
2578     int ret;
2579     xmlSchemaTypePtr typ;
2580     xmlSchemaValPtr res1 = NULL, res2 = NULL;
2581
2582     if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2583         return (-1);
2584     typ = xmlSchemaGetPredefinedType(type,
2585                                      BAD_CAST
2586                                      "http://www.w3.org/2001/XMLSchema");
2587     if (typ == NULL)
2588         return (-1);
2589     if (comp1 == NULL) {
2590         ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2591         if (ret != 0)
2592             return (-1);
2593         if (res1 == NULL)
2594             return (-1);
2595     } else {
2596         res1 = (xmlSchemaValPtr) comp1;
2597     }
2598     ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2599     if (ret != 0) {
2600         if (res1 != (xmlSchemaValPtr) comp1)
2601             xmlSchemaFreeValue(res1);
2602         return (-1);
2603     }
2604     ret = xmlSchemaCompareValues(res1, res2);
2605     if (res1 != (xmlSchemaValPtr) comp1)
2606         xmlSchemaFreeValue(res1);
2607     xmlSchemaFreeValue(res2);
2608     if (ret == -2)
2609         return (-1);
2610     if (ret == 0)
2611         return (1);
2612     return (0);
2613 }
2614
2615 /**
2616  * xmlRelaxNGDefaultTypeHave:
2617  * @data:  data needed for the library
2618  * @type:  the type name
2619  *
2620  * Check if the given type is provided by
2621  * the default datatype library.
2622  *
2623  * Returns 1 if yes, 0 if no and -1 in case of error.
2624  */
2625 static int
2626 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2627                           const xmlChar * type)
2628 {
2629     if (type == NULL)
2630         return (-1);
2631     if (xmlStrEqual(type, BAD_CAST "string"))
2632         return (1);
2633     if (xmlStrEqual(type, BAD_CAST "token"))
2634         return (1);
2635     return (0);
2636 }
2637
2638 /**
2639  * xmlRelaxNGDefaultTypeCheck:
2640  * @data:  data needed for the library
2641  * @type:  the type name
2642  * @value:  the value to check
2643  * @node:  the node
2644  *
2645  * Check if the given type and value are validated by
2646  * the default datatype library.
2647  *
2648  * Returns 1 if yes, 0 if no and -1 in case of error.
2649  */
2650 static int
2651 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2652                            const xmlChar * type ATTRIBUTE_UNUSED,
2653                            const xmlChar * value ATTRIBUTE_UNUSED,
2654                            void **result ATTRIBUTE_UNUSED,
2655                            xmlNodePtr node ATTRIBUTE_UNUSED)
2656 {
2657     if (value == NULL)
2658         return (-1);
2659     if (xmlStrEqual(type, BAD_CAST "string"))
2660         return (1);
2661     if (xmlStrEqual(type, BAD_CAST "token")) {
2662         return (1);
2663     }
2664
2665     return (0);
2666 }
2667
2668 /**
2669  * xmlRelaxNGDefaultTypeCompare:
2670  * @data:  data needed for the library
2671  * @type:  the type name
2672  * @value1:  the first value
2673  * @value2:  the second value
2674  *
2675  * Compare two values accordingly a type from the default
2676  * datatype library.
2677  *
2678  * Returns 1 if yes, 0 if no and -1 in case of error.
2679  */
2680 static int
2681 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2682                              const xmlChar * type,
2683                              const xmlChar * value1,
2684                              xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2685                              void *comp1 ATTRIBUTE_UNUSED,
2686                              const xmlChar * value2,
2687                              xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2688 {
2689     int ret = -1;
2690
2691     if (xmlStrEqual(type, BAD_CAST "string")) {
2692         ret = xmlStrEqual(value1, value2);
2693     } else if (xmlStrEqual(type, BAD_CAST "token")) {
2694         if (!xmlStrEqual(value1, value2)) {
2695             xmlChar *nval, *nvalue;
2696
2697             /*
2698              * TODO: trivial optimizations are possible by
2699              * computing at compile-time
2700              */
2701             nval = xmlRelaxNGNormalize(NULL, value1);
2702             nvalue = xmlRelaxNGNormalize(NULL, value2);
2703
2704             if ((nval == NULL) || (nvalue == NULL))
2705                 ret = -1;
2706             else if (xmlStrEqual(nval, nvalue))
2707                 ret = 1;
2708             else
2709                 ret = 0;
2710             if (nval != NULL)
2711                 xmlFree(nval);
2712             if (nvalue != NULL)
2713                 xmlFree(nvalue);
2714         } else
2715             ret = 1;
2716     }
2717     return (ret);
2718 }
2719
2720 static int xmlRelaxNGTypeInitialized = 0;
2721 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2722
2723 /**
2724  * xmlRelaxNGFreeTypeLibrary:
2725  * @lib:  the type library structure
2726  * @namespace:  the URI bound to the library
2727  *
2728  * Free the structure associated to the type library
2729  */
2730 static void
2731 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2732                           const xmlChar * namespace ATTRIBUTE_UNUSED)
2733 {
2734     if (lib == NULL)
2735         return;
2736     if (lib->namespace != NULL)
2737         xmlFree((xmlChar *) lib->namespace);
2738     xmlFree(lib);
2739 }
2740
2741 /**
2742  * xmlRelaxNGRegisterTypeLibrary:
2743  * @namespace:  the URI bound to the library
2744  * @data:  data associated to the library
2745  * @have:  the provide function
2746  * @check:  the checking function
2747  * @comp:  the comparison function
2748  *
2749  * Register a new type library
2750  *
2751  * Returns 0 in case of success and -1 in case of error.
2752  */
2753 static int
2754 xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2755                               xmlRelaxNGTypeHave have,
2756                               xmlRelaxNGTypeCheck check,
2757                               xmlRelaxNGTypeCompare comp,
2758                               xmlRelaxNGFacetCheck facet,
2759                               xmlRelaxNGTypeFree freef)
2760 {
2761     xmlRelaxNGTypeLibraryPtr lib;
2762     int ret;
2763
2764     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2765         (check == NULL) || (comp == NULL))
2766         return (-1);
2767     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2768         xmlGenericError(xmlGenericErrorContext,
2769                         "Relax-NG types library '%s' already registered\n",
2770                         namespace);
2771         return (-1);
2772     }
2773     lib =
2774         (xmlRelaxNGTypeLibraryPtr)
2775         xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2776     if (lib == NULL) {
2777         xmlRngVErrMemory(NULL, "adding types library\n");
2778         return (-1);
2779     }
2780     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2781     lib->namespace = xmlStrdup(namespace);
2782     lib->data = data;
2783     lib->have = have;
2784     lib->comp = comp;
2785     lib->check = check;
2786     lib->facet = facet;
2787     lib->freef = freef;
2788     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2789     if (ret < 0) {
2790         xmlGenericError(xmlGenericErrorContext,
2791                         "Relax-NG types library failed to register '%s'\n",
2792                         namespace);
2793         xmlRelaxNGFreeTypeLibrary(lib, namespace);
2794         return (-1);
2795     }
2796     return (0);
2797 }
2798
2799 /**
2800  * xmlRelaxNGInitTypes:
2801  *
2802  * Initilize the default type libraries.
2803  *
2804  * Returns 0 in case of success and -1 in case of error.
2805  */
2806 int
2807 xmlRelaxNGInitTypes(void)
2808 {
2809     if (xmlRelaxNGTypeInitialized != 0)
2810         return (0);
2811     xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2812     if (xmlRelaxNGRegisteredTypes == NULL) {
2813         xmlGenericError(xmlGenericErrorContext,
2814                         "Failed to allocate sh table for Relax-NG types\n");
2815         return (-1);
2816     }
2817     xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2818                                   "http://www.w3.org/2001/XMLSchema-datatypes",
2819                                   NULL, xmlRelaxNGSchemaTypeHave,
2820                                   xmlRelaxNGSchemaTypeCheck,
2821                                   xmlRelaxNGSchemaTypeCompare,
2822                                   xmlRelaxNGSchemaFacetCheck,
2823                                   xmlRelaxNGSchemaFreeValue);
2824     xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2825                                   xmlRelaxNGDefaultTypeHave,
2826                                   xmlRelaxNGDefaultTypeCheck,
2827                                   xmlRelaxNGDefaultTypeCompare, NULL,
2828                                   NULL);
2829     xmlRelaxNGTypeInitialized = 1;
2830     return (0);
2831 }
2832
2833 /**
2834  * xmlRelaxNGCleanupTypes:
2835  *
2836  * Cleanup the default Schemas type library associated to RelaxNG
2837  */
2838 void
2839 xmlRelaxNGCleanupTypes(void)
2840 {
2841     xmlSchemaCleanupTypes();
2842     if (xmlRelaxNGTypeInitialized == 0)
2843         return;
2844     xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2845                 xmlRelaxNGFreeTypeLibrary);
2846     xmlRelaxNGTypeInitialized = 0;
2847 }
2848
2849 /************************************************************************
2850  *                                                                      *
2851  *              Compiling element content into regexp                   *
2852  *                                                                      *
2853  * Sometime the element content can be compiled into a pure regexp,     *
2854  * This allows a faster execution and streamability at that level       *
2855  *                                                                      *
2856  ************************************************************************/
2857
2858 /* from automata.c but not exported */
2859 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
2860
2861
2862 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2863                                 xmlRelaxNGDefinePtr def);
2864
2865 /**
2866  * xmlRelaxNGIsCompileable:
2867  * @define:  the definition to check
2868  *
2869  * Check if a definition is nullable.
2870  *
2871  * Returns 1 if yes, 0 if no and -1 in case of error
2872  */
2873 static int
2874 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2875 {
2876     int ret = -1;
2877
2878     if (def == NULL) {
2879         return (-1);
2880     }
2881     if ((def->type != XML_RELAXNG_ELEMENT) &&
2882         (def->dflags & IS_COMPILABLE))
2883         return (1);
2884     if ((def->type != XML_RELAXNG_ELEMENT) &&
2885         (def->dflags & IS_NOT_COMPILABLE))
2886         return (0);
2887     switch (def->type) {
2888         case XML_RELAXNG_NOOP:
2889             ret = xmlRelaxNGIsCompileable(def->content);
2890             break;
2891         case XML_RELAXNG_TEXT:
2892         case XML_RELAXNG_EMPTY:
2893             ret = 1;
2894             break;
2895         case XML_RELAXNG_ELEMENT:
2896             /*
2897              * Check if the element content is compileable
2898              */
2899             if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2900                 ((def->dflags & IS_COMPILABLE) == 0)) {
2901                 xmlRelaxNGDefinePtr list;
2902
2903                 list = def->content;
2904                 while (list != NULL) {
2905                     ret = xmlRelaxNGIsCompileable(list);
2906                     if (ret != 1)
2907                         break;
2908                     list = list->next;
2909                 }
2910                 /*
2911                  * Because the routine is recursive, we must guard against
2912                  * discovering both COMPILABLE and NOT_COMPILABLE
2913                  */
2914                 if (ret == 0) {
2915                     def->dflags &= ~IS_COMPILABLE;
2916                     def->dflags |= IS_NOT_COMPILABLE;
2917                 }
2918                 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2919                     def->dflags |= IS_COMPILABLE;
2920 #ifdef DEBUG_COMPILE
2921                 if (ret == 1) {
2922                     xmlGenericError(xmlGenericErrorContext,
2923                                     "element content for %s is compilable\n",
2924                                     def->name);
2925                 } else if (ret == 0) {
2926                     xmlGenericError(xmlGenericErrorContext,
2927                                     "element content for %s is not compilable\n",
2928                                     def->name);
2929                 } else {
2930                     xmlGenericError(xmlGenericErrorContext,
2931                                     "Problem in RelaxNGIsCompileable for element %s\n",
2932                                     def->name);
2933                 }
2934 #endif
2935             }
2936             /*
2937              * All elements return a compileable status unless they
2938              * are generic like anyName
2939              */
2940             if ((def->nameClass != NULL) || (def->name == NULL))
2941                 ret = 0;
2942             else
2943                 ret = 1;
2944             return (ret);
2945         case XML_RELAXNG_REF:
2946         case XML_RELAXNG_EXTERNALREF:
2947         case XML_RELAXNG_PARENTREF:
2948             if (def->depth == -20) {
2949                 return (1);
2950             } else {
2951                 xmlRelaxNGDefinePtr list;
2952
2953                 def->depth = -20;
2954                 list = def->content;
2955                 while (list != NULL) {
2956                     ret = xmlRelaxNGIsCompileable(list);
2957                     if (ret != 1)
2958                         break;
2959                     list = list->next;
2960                 }
2961             }
2962             break;
2963         case XML_RELAXNG_START:
2964         case XML_RELAXNG_OPTIONAL:
2965         case XML_RELAXNG_ZEROORMORE:
2966         case XML_RELAXNG_ONEORMORE:
2967         case XML_RELAXNG_CHOICE:
2968         case XML_RELAXNG_GROUP:
2969         case XML_RELAXNG_DEF:{
2970                 xmlRelaxNGDefinePtr list;
2971
2972                 list = def->content;
2973                 while (list != NULL) {
2974                     ret = xmlRelaxNGIsCompileable(list);
2975                     if (ret != 1)
2976                         break;
2977                     list = list->next;
2978                 }
2979                 break;
2980             }
2981         case XML_RELAXNG_EXCEPT:
2982         case XML_RELAXNG_ATTRIBUTE:
2983         case XML_RELAXNG_INTERLEAVE:
2984         case XML_RELAXNG_DATATYPE:
2985         case XML_RELAXNG_LIST:
2986         case XML_RELAXNG_PARAM:
2987         case XML_RELAXNG_VALUE:
2988         case XML_RELAXNG_NOT_ALLOWED:
2989             ret = 0;
2990             break;
2991     }
2992     if (ret == 0)
2993         def->dflags |= IS_NOT_COMPILABLE;
2994     if (ret == 1)
2995         def->dflags |= IS_COMPILABLE;
2996 #ifdef DEBUG_COMPILE
2997     if (ret == 1) {
2998         xmlGenericError(xmlGenericErrorContext,
2999                         "RelaxNGIsCompileable %s : true\n",
3000                         xmlRelaxNGDefName(def));
3001     } else if (ret == 0) {
3002         xmlGenericError(xmlGenericErrorContext,
3003                         "RelaxNGIsCompileable %s : false\n",
3004                         xmlRelaxNGDefName(def));
3005     } else {
3006         xmlGenericError(xmlGenericErrorContext,
3007                         "Problem in RelaxNGIsCompileable %s\n",
3008                         xmlRelaxNGDefName(def));
3009     }
3010 #endif
3011     return (ret);
3012 }
3013
3014 /**
3015  * xmlRelaxNGCompile:
3016  * ctxt:  the RelaxNG parser context
3017  * @define:  the definition tree to compile
3018  *
3019  * Compile the set of definitions, it works recursively, till the
3020  * element boundaries, where it tries to compile the content if possible
3021  *
3022  * Returns 0 if success and -1 in case of error
3023  */
3024 static int
3025 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3026 {
3027     int ret = 0;
3028     xmlRelaxNGDefinePtr list;
3029
3030     if ((ctxt == NULL) || (def == NULL))
3031         return (-1);
3032
3033     switch (def->type) {
3034         case XML_RELAXNG_START:
3035             if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
3036                 xmlAutomataPtr oldam = ctxt->am;
3037                 xmlAutomataStatePtr oldstate = ctxt->state;
3038
3039                 def->depth = -25;
3040
3041                 list = def->content;
3042                 ctxt->am = xmlNewAutomata();
3043                 if (ctxt->am == NULL)
3044                     return (-1);
3045
3046                 /*
3047                  * assume identical strings but not same pointer are different
3048                  * atoms, needed for non-determinism detection
3049                  * That way if 2 elements with the same name are in a choice
3050                  * branch the automata is found non-deterministic and
3051                  * we fallback to the normal validation which does the right
3052                  * thing of exploring both choices.
3053                  */
3054                 xmlAutomataSetFlags(ctxt->am, 1);
3055
3056                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3057                 while (list != NULL) {
3058                     xmlRelaxNGCompile(ctxt, list);
3059                     list = list->next;
3060                 }
3061                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3062                 if (xmlAutomataIsDeterminist(ctxt->am))
3063                     def->contModel = xmlAutomataCompile(ctxt->am);
3064
3065                 xmlFreeAutomata(ctxt->am);
3066                 ctxt->state = oldstate;
3067                 ctxt->am = oldam;
3068             }
3069             break;
3070         case XML_RELAXNG_ELEMENT:
3071             if ((ctxt->am != NULL) && (def->name != NULL)) {
3072                 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3073                                                         ctxt->state, NULL,
3074                                                         def->name, def->ns,
3075                                                         def);
3076             }
3077             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3078                 xmlAutomataPtr oldam = ctxt->am;
3079                 xmlAutomataStatePtr oldstate = ctxt->state;
3080
3081                 def->depth = -25;
3082
3083                 list = def->content;
3084                 ctxt->am = xmlNewAutomata();
3085                 if (ctxt->am == NULL)
3086                     return (-1);
3087                 xmlAutomataSetFlags(ctxt->am, 1);
3088                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3089                 while (list != NULL) {
3090                     xmlRelaxNGCompile(ctxt, list);
3091                     list = list->next;
3092                 }
3093                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3094                 def->contModel = xmlAutomataCompile(ctxt->am);
3095                 if (!xmlRegexpIsDeterminist(def->contModel)) {
3096 #ifdef DEBUG_COMPILE
3097                     xmlGenericError(xmlGenericErrorContext,
3098                         "Content model not determinist %s\n",
3099                                     def->name);
3100 #endif
3101                     /*
3102                      * we can only use the automata if it is determinist
3103                      */
3104                     xmlRegFreeRegexp(def->contModel);
3105                     def->contModel = NULL;
3106                 }
3107                 xmlFreeAutomata(ctxt->am);
3108                 ctxt->state = oldstate;
3109                 ctxt->am = oldam;
3110             } else {
3111                 xmlAutomataPtr oldam = ctxt->am;
3112
3113                 /*
3114                  * we can't build the content model for this element content
3115                  * but it still might be possible to build it for some of its
3116                  * children, recurse.
3117                  */
3118                 ret = xmlRelaxNGTryCompile(ctxt, def);
3119                 ctxt->am = oldam;
3120             }
3121             break;
3122         case XML_RELAXNG_NOOP:
3123             ret = xmlRelaxNGCompile(ctxt, def->content);
3124             break;
3125         case XML_RELAXNG_OPTIONAL:{
3126                 xmlAutomataStatePtr oldstate = ctxt->state;
3127
3128                 list = def->content;
3129                 while (list != NULL) {
3130                     xmlRelaxNGCompile(ctxt, list);
3131                     list = list->next;
3132                 }
3133                 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3134                 break;
3135             }
3136         case XML_RELAXNG_ZEROORMORE:{
3137                 xmlAutomataStatePtr oldstate;
3138
3139                 ctxt->state =
3140                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3141                 oldstate = ctxt->state;
3142                 list = def->content;
3143                 while (list != NULL) {
3144                     xmlRelaxNGCompile(ctxt, list);
3145                     list = list->next;
3146                 }
3147                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3148                 ctxt->state =
3149                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3150                 break;
3151             }
3152         case XML_RELAXNG_ONEORMORE:{
3153                 xmlAutomataStatePtr oldstate;
3154
3155                 list = def->content;
3156                 while (list != NULL) {
3157                     xmlRelaxNGCompile(ctxt, list);
3158                     list = list->next;
3159                 }
3160                 oldstate = ctxt->state;
3161                 list = def->content;
3162                 while (list != NULL) {
3163                     xmlRelaxNGCompile(ctxt, list);
3164                     list = list->next;
3165                 }
3166                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3167                 ctxt->state =
3168                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3169                 break;
3170             }
3171         case XML_RELAXNG_CHOICE:{
3172                 xmlAutomataStatePtr target = NULL;
3173                 xmlAutomataStatePtr oldstate = ctxt->state;
3174
3175                 list = def->content;
3176                 while (list != NULL) {
3177                     ctxt->state = oldstate;
3178                     ret = xmlRelaxNGCompile(ctxt, list);
3179                     if (ret != 0)
3180                         break;
3181                     if (target == NULL)
3182                         target = ctxt->state;
3183                     else {
3184                         xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3185                                               target);
3186                     }
3187                     list = list->next;
3188                 }
3189                 ctxt->state = target;
3190
3191                 break;
3192             }
3193         case XML_RELAXNG_REF:
3194         case XML_RELAXNG_EXTERNALREF:
3195         case XML_RELAXNG_PARENTREF:
3196         case XML_RELAXNG_GROUP:
3197         case XML_RELAXNG_DEF:
3198             list = def->content;
3199             while (list != NULL) {
3200                 ret = xmlRelaxNGCompile(ctxt, list);
3201                 if (ret != 0)
3202                     break;
3203                 list = list->next;
3204             }
3205             break;
3206         case XML_RELAXNG_TEXT:{
3207                 xmlAutomataStatePtr oldstate;
3208
3209                 ctxt->state =
3210                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3211                 oldstate = ctxt->state;
3212                 xmlRelaxNGCompile(ctxt, def->content);
3213                 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3214                                          ctxt->state, BAD_CAST "#text",
3215                                          NULL);
3216                 ctxt->state =
3217                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3218                 break;
3219             }
3220         case XML_RELAXNG_EMPTY:
3221             ctxt->state =
3222                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3223             break;
3224         case XML_RELAXNG_EXCEPT:
3225         case XML_RELAXNG_ATTRIBUTE:
3226         case XML_RELAXNG_INTERLEAVE:
3227         case XML_RELAXNG_NOT_ALLOWED:
3228         case XML_RELAXNG_DATATYPE:
3229         case XML_RELAXNG_LIST:
3230         case XML_RELAXNG_PARAM:
3231         case XML_RELAXNG_VALUE:
3232             /* This should not happen and generate an internal error */
3233             fprintf(stderr, "RNG internal error trying to compile %s\n",
3234                     xmlRelaxNGDefName(def));
3235             break;
3236     }
3237     return (ret);
3238 }
3239
3240 /**
3241  * xmlRelaxNGTryCompile:
3242  * ctxt:  the RelaxNG parser context
3243  * @define:  the definition tree to compile
3244  *
3245  * Try to compile the set of definitions, it works recursively,
3246  * possibly ignoring parts which cannot be compiled.
3247  *
3248  * Returns 0 if success and -1 in case of error
3249  */
3250 static int
3251 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3252 {
3253     int ret = 0;
3254     xmlRelaxNGDefinePtr list;
3255
3256     if ((ctxt == NULL) || (def == NULL))
3257         return (-1);
3258
3259     if ((def->type == XML_RELAXNG_START) ||
3260         (def->type == XML_RELAXNG_ELEMENT)) {
3261         ret = xmlRelaxNGIsCompileable(def);
3262         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3263             ctxt->am = NULL;
3264             ret = xmlRelaxNGCompile(ctxt, def);
3265 #ifdef DEBUG_PROGRESSIVE
3266             if (ret == 0) {
3267                 if (def->type == XML_RELAXNG_START)
3268                     xmlGenericError(xmlGenericErrorContext,
3269                                     "compiled the start\n");
3270                 else
3271                     xmlGenericError(xmlGenericErrorContext,
3272                                     "compiled element %s\n", def->name);
3273             } else {
3274                 if (def->type == XML_RELAXNG_START)
3275                     xmlGenericError(xmlGenericErrorContext,
3276                                     "failed to compile the start\n");
3277                 else
3278                     xmlGenericError(xmlGenericErrorContext,
3279                                     "failed to compile element %s\n",
3280                                     def->name);
3281             }
3282 #endif
3283             return (ret);
3284         }
3285     }
3286     switch (def->type) {
3287         case XML_RELAXNG_NOOP:
3288             ret = xmlRelaxNGTryCompile(ctxt, def->content);
3289             break;
3290         case XML_RELAXNG_TEXT:
3291         case XML_RELAXNG_DATATYPE:
3292         case XML_RELAXNG_LIST:
3293         case XML_RELAXNG_PARAM:
3294         case XML_RELAXNG_VALUE:
3295         case XML_RELAXNG_EMPTY:
3296         case XML_RELAXNG_ELEMENT:
3297             ret = 0;
3298             break;
3299         case XML_RELAXNG_OPTIONAL:
3300         case XML_RELAXNG_ZEROORMORE:
3301         case XML_RELAXNG_ONEORMORE:
3302         case XML_RELAXNG_CHOICE:
3303         case XML_RELAXNG_GROUP:
3304         case XML_RELAXNG_DEF:
3305         case XML_RELAXNG_START:
3306         case XML_RELAXNG_REF:
3307         case XML_RELAXNG_EXTERNALREF:
3308         case XML_RELAXNG_PARENTREF:
3309             list = def->content;
3310             while (list != NULL) {
3311                 ret = xmlRelaxNGTryCompile(ctxt, list);
3312                 if (ret != 0)
3313                     break;
3314                 list = list->next;
3315             }
3316             break;
3317         case XML_RELAXNG_EXCEPT:
3318         case XML_RELAXNG_ATTRIBUTE:
3319         case XML_RELAXNG_INTERLEAVE:
3320         case XML_RELAXNG_NOT_ALLOWED:
3321             ret = 0;
3322             break;
3323     }
3324     return (ret);
3325 }
3326
3327 /************************************************************************
3328  *                                                                      *
3329  *                      Parsing functions                               *
3330  *                                                                      *
3331  ************************************************************************/
3332
3333 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3334                                                     ctxt, xmlNodePtr node);
3335 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3336                                                   ctxt, xmlNodePtr node);
3337 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3338                                                    ctxt, xmlNodePtr nodes,
3339                                                    int group);
3340 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3341                                                   ctxt, xmlNodePtr node);
3342 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3343                                              xmlNodePtr node);
3344 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3345                                          xmlNodePtr nodes);
3346 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3347                                                     ctxt, xmlNodePtr node,
3348                                                     xmlRelaxNGDefinePtr
3349                                                     def);
3350 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3351                                                    ctxt, xmlNodePtr nodes);
3352 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3353                                   xmlRelaxNGDefinePtr define,
3354                                   xmlNodePtr elem);
3355
3356
3357 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3358
3359 /**
3360  * xmlRelaxNGIsNullable:
3361  * @define:  the definition to verify
3362  *
3363  * Check if a definition is nullable.
3364  *
3365  * Returns 1 if yes, 0 if no and -1 in case of error
3366  */
3367 static int
3368 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3369 {
3370     int ret;
3371
3372     if (define == NULL)
3373         return (-1);
3374
3375     if (define->dflags & IS_NULLABLE)
3376         return (1);
3377     if (define->dflags & IS_NOT_NULLABLE)
3378         return (0);
3379     switch (define->type) {
3380         case XML_RELAXNG_EMPTY:
3381         case XML_RELAXNG_TEXT:
3382             ret = 1;
3383             break;
3384         case XML_RELAXNG_NOOP:
3385         case XML_RELAXNG_DEF:
3386         case XML_RELAXNG_REF:
3387         case XML_RELAXNG_EXTERNALREF:
3388         case XML_RELAXNG_PARENTREF:
3389         case XML_RELAXNG_ONEORMORE:
3390             ret = xmlRelaxNGIsNullable(define->content);
3391             break;
3392         case XML_RELAXNG_EXCEPT:
3393         case XML_RELAXNG_NOT_ALLOWED:
3394         case XML_RELAXNG_ELEMENT:
3395         case XML_RELAXNG_DATATYPE:
3396         case XML_RELAXNG_PARAM:
3397         case XML_RELAXNG_VALUE:
3398         case XML_RELAXNG_LIST:
3399         case XML_RELAXNG_ATTRIBUTE:
3400             ret = 0;
3401             break;
3402         case XML_RELAXNG_CHOICE:{
3403                 xmlRelaxNGDefinePtr list = define->content;
3404
3405                 while (list != NULL) {
3406                     ret = xmlRelaxNGIsNullable(list);
3407                     if (ret != 0)
3408                         goto done;
3409                     list = list->next;
3410                 }
3411                 ret = 0;
3412                 break;
3413             }
3414         case XML_RELAXNG_START:
3415         case XML_RELAXNG_INTERLEAVE:
3416         case XML_RELAXNG_GROUP:{
3417                 xmlRelaxNGDefinePtr list = define->content;
3418
3419                 while (list != NULL) {
3420                     ret = xmlRelaxNGIsNullable(list);
3421                     if (ret != 1)
3422                         goto done;
3423                     list = list->next;
3424                 }
3425                 return (1);
3426             }
3427         default:
3428             return (-1);
3429     }
3430   done:
3431     if (ret == 0)
3432         define->dflags |= IS_NOT_NULLABLE;
3433     if (ret == 1)
3434         define->dflags |= IS_NULLABLE;
3435     return (ret);
3436 }
3437
3438 /**
3439  * xmlRelaxNGIsBlank:
3440  * @str:  a string
3441  *
3442  * Check if a string is ignorable c.f. 4.2. Whitespace
3443  *
3444  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3445  */
3446 static int
3447 xmlRelaxNGIsBlank(xmlChar * str)
3448 {
3449     if (str == NULL)
3450         return (1);
3451     while (*str != 0) {
3452         if (!(IS_BLANK_CH(*str)))
3453             return (0);
3454         str++;
3455     }
3456     return (1);
3457 }
3458
3459 /**
3460  * xmlRelaxNGGetDataTypeLibrary:
3461  * @ctxt:  a Relax-NG parser context
3462  * @node:  the current data or value element
3463  *
3464  * Applies algorithm from 4.3. datatypeLibrary attribute
3465  *
3466  * Returns the datatypeLibary value or NULL if not found
3467  */
3468 static xmlChar *
3469 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3470                              xmlNodePtr node)
3471 {
3472     xmlChar *ret, *escape;
3473
3474     if (node == NULL)
3475         return(NULL);
3476
3477     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3478         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3479         if (ret != NULL) {
3480             if (ret[0] == 0) {
3481                 xmlFree(ret);
3482                 return (NULL);
3483             }
3484             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3485             if (escape == NULL) {
3486                 return (ret);
3487             }
3488             xmlFree(ret);
3489             return (escape);
3490         }
3491     }
3492     node = node->parent;
3493     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3494         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3495         if (ret != NULL) {
3496             if (ret[0] == 0) {
3497                 xmlFree(ret);
3498                 return (NULL);
3499             }
3500             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3501             if (escape == NULL) {
3502                 return (ret);
3503             }
3504             xmlFree(ret);
3505             return (escape);
3506         }
3507         node = node->parent;
3508     }
3509     return (NULL);
3510 }
3511
3512 /**
3513  * xmlRelaxNGParseValue:
3514  * @ctxt:  a Relax-NG parser context
3515  * @node:  the data node.
3516  *
3517  * parse the content of a RelaxNG value node.
3518  *
3519  * Returns the definition pointer or NULL in case of error
3520  */
3521 static xmlRelaxNGDefinePtr
3522 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3523 {
3524     xmlRelaxNGDefinePtr def = NULL;
3525     xmlRelaxNGTypeLibraryPtr lib = NULL;
3526     xmlChar *type;
3527     xmlChar *library;
3528     int success = 0;
3529
3530     def = xmlRelaxNGNewDefine(ctxt, node);
3531     if (def == NULL)
3532         return (NULL);
3533     def->type = XML_RELAXNG_VALUE;
3534
3535     type = xmlGetProp(node, BAD_CAST "type");
3536     if (type != NULL) {
3537         xmlRelaxNGNormExtSpace(type);
3538         if (xmlValidateNCName(type, 0)) {
3539             xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3540                        "value type '%s' is not an NCName\n", type, NULL);
3541         }
3542         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3543         if (library == NULL)
3544             library =
3545                 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3546
3547         def->name = type;
3548         def->ns = library;
3549
3550         lib = (xmlRelaxNGTypeLibraryPtr)
3551             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3552         if (lib == NULL) {
3553             xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3554                        "Use of unregistered type library '%s'\n", library,
3555                        NULL);
3556             def->data = NULL;
3557         } else {
3558             def->data = lib;
3559             if (lib->have == NULL) {
3560                 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3561                            "Internal error with type library '%s': no 'have'\n",
3562                            library, NULL);
3563             } else {
3564                 success = lib->have(lib->data, def->name);
3565                 if (success != 1) {
3566                     xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3567                                "Error type '%s' is not exported by type library '%s'\n",
3568                                def->name, library);
3569                 }
3570             }
3571         }
3572     }
3573     if (node->children == NULL) {
3574         def->value = xmlStrdup(BAD_CAST "");
3575     } else if (((node->children->type != XML_TEXT_NODE) &&
3576                 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3577                (node->children->next != NULL)) {
3578         xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3579                    "Expecting a single text value for <value>content\n",
3580                    NULL, NULL);
3581     } else if (def != NULL) {
3582         def->value = xmlNodeGetContent(node);
3583         if (def->value == NULL) {
3584             xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3585                        "Element <value> has no content\n", NULL, NULL);
3586         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3587             void *val = NULL;
3588
3589             success =
3590                 lib->check(lib->data, def->name, def->value, &val, node);
3591             if (success != 1) {
3592                 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3593                            "Value '%s' is not acceptable for type '%s'\n",
3594                            def->value, def->name);
3595             } else {
3596                 if (val != NULL)
3597                     def->attrs = val;
3598             }
3599         }
3600     }
3601     return (def);
3602 }
3603
3604 /**
3605  * xmlRelaxNGParseData:
3606  * @ctxt:  a Relax-NG parser context
3607  * @node:  the data node.
3608  *
3609  * parse the content of a RelaxNG data node.
3610  *
3611  * Returns the definition pointer or NULL in case of error
3612  */
3613 static xmlRelaxNGDefinePtr
3614 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3615 {
3616     xmlRelaxNGDefinePtr def = NULL, except;
3617     xmlRelaxNGDefinePtr param, lastparam = NULL;
3618     xmlRelaxNGTypeLibraryPtr lib;
3619     xmlChar *type;
3620     xmlChar *library;
3621     xmlNodePtr content;
3622     int tmp;
3623
3624     type = xmlGetProp(node, BAD_CAST "type");
3625     if (type == NULL) {
3626         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3627                    NULL);
3628         return (NULL);
3629     }
3630     xmlRelaxNGNormExtSpace(type);
3631     if (xmlValidateNCName(type, 0)) {
3632         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3633                    "data type '%s' is not an NCName\n", type, NULL);
3634     }
3635     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3636     if (library == NULL)
3637         library =
3638             xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3639
3640     def = xmlRelaxNGNewDefine(ctxt, node);
3641     if (def == NULL) {
3642         xmlFree(type);
3643         return (NULL);
3644     }
3645     def->type = XML_RELAXNG_DATATYPE;
3646     def->name = type;
3647     def->ns = library;
3648
3649     lib = (xmlRelaxNGTypeLibraryPtr)
3650         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3651     if (lib == NULL) {
3652         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3653                    "Use of unregistered type library '%s'\n", library,
3654                    NULL);
3655         def->data = NULL;
3656     } else {
3657         def->data = lib;
3658         if (lib->have == NULL) {
3659             xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3660                        "Internal error with type library '%s': no 'have'\n",
3661                        library, NULL);
3662         } else {
3663             tmp = lib->have(lib->data, def->name);
3664             if (tmp != 1) {
3665                 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3666                            "Error type '%s' is not exported by type library '%s'\n",
3667                            def->name, library);
3668             } else
3669                 if ((xmlStrEqual
3670                      (library,
3671                       BAD_CAST
3672                       "http://www.w3.org/2001/XMLSchema-datatypes"))
3673                     && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3674                         || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3675                 ctxt->idref = 1;
3676             }
3677         }
3678     }
3679     content = node->children;
3680
3681     /*
3682      * Handle optional params
3683      */
3684     while (content != NULL) {
3685         if (!xmlStrEqual(content->name, BAD_CAST "param"))
3686             break;
3687         if (xmlStrEqual(library,
3688                         BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3689             xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3690                        "Type library '%s' does not allow type parameters\n",
3691                        library, NULL);
3692             content = content->next;
3693             while ((content != NULL) &&
3694                    (xmlStrEqual(content->name, BAD_CAST "param")))
3695                 content = content->next;
3696         } else {
3697             param = xmlRelaxNGNewDefine(ctxt, node);
3698             if (param != NULL) {
3699                 param->type = XML_RELAXNG_PARAM;
3700                 param->name = xmlGetProp(content, BAD_CAST "name");
3701                 if (param->name == NULL) {
3702                     xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3703                                "param has no name\n", NULL, NULL);
3704                 }
3705                 param->value = xmlNodeGetContent(content);
3706                 if (lastparam == NULL) {
3707                     def->attrs = lastparam = param;
3708                 } else {
3709                     lastparam->next = param;
3710                     lastparam = param;
3711                 }
3712                 if (lib != NULL) {
3713                 }
3714             }
3715             content = content->next;
3716         }
3717     }
3718     /*
3719      * Handle optional except
3720      */
3721     if ((content != NULL)
3722         && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3723         xmlNodePtr child;
3724         xmlRelaxNGDefinePtr tmp2, last = NULL;
3725
3726         except = xmlRelaxNGNewDefine(ctxt, node);
3727         if (except == NULL) {
3728             return (def);
3729         }
3730         except->type = XML_RELAXNG_EXCEPT;
3731         child = content->children;
3732         def->content = except;
3733         if (child == NULL) {
3734             xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3735                        "except has no content\n", NULL, NULL);
3736         }
3737         while (child != NULL) {
3738             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3739             if (tmp2 != NULL) {
3740                 if (last == NULL) {
3741                     except->content = last = tmp2;
3742                 } else {
3743                     last->next = tmp2;
3744                     last = tmp2;
3745                 }
3746             }
3747             child = child->next;
3748         }
3749         content = content->next;
3750     }
3751     /*
3752      * Check there is no unhandled data
3753      */
3754     if (content != NULL) {
3755         xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3756                    "Element data has unexpected content %s\n",
3757                    content->name, NULL);
3758     }
3759
3760     return (def);
3761 }
3762
3763 static const xmlChar *invalidName = BAD_CAST "\1";
3764
3765 /**
3766  * xmlRelaxNGCompareNameClasses:
3767  * @defs1:  the first element/attribute defs
3768  * @defs2:  the second element/attribute defs
3769  * @name:  the restriction on the name
3770  * @ns:  the restriction on the namespace
3771  *
3772  * Compare the 2 lists of element definitions. The comparison is
3773  * that if both lists do not accept the same QNames, it returns 1
3774  * If the 2 lists can accept the same QName the comparison returns 0
3775  *
3776  * Returns 1 disttinct, 0 if equal
3777  */
3778 static int
3779 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3780                              xmlRelaxNGDefinePtr def2)
3781 {
3782     int ret = 1;
3783     xmlNode node;
3784     xmlNs ns;
3785     xmlRelaxNGValidCtxt ctxt;
3786
3787     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3788
3789     ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3790
3791     if ((def1->type == XML_RELAXNG_ELEMENT) ||
3792         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3793         if (def2->type == XML_RELAXNG_TEXT)
3794             return (1);
3795         if (def1->name != NULL) {
3796             node.name = def1->name;
3797         } else {
3798             node.name = invalidName;
3799         }
3800         if (def1->ns != NULL) {
3801             if (def1->ns[0] == 0) {
3802                 node.ns = NULL;
3803             } else {
3804                 node.ns = &ns;
3805                 ns.href = def1->ns;
3806             }
3807         } else {
3808             node.ns = NULL;
3809         }
3810         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3811             if (def1->nameClass != NULL) {
3812                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3813             } else {
3814                 ret = 0;
3815             }
3816         } else {
3817             ret = 1;
3818         }
3819     } else if (def1->type == XML_RELAXNG_TEXT) {
3820         if (def2->type == XML_RELAXNG_TEXT)
3821             return (0);
3822         return (1);
3823     } else if (def1->type == XML_RELAXNG_EXCEPT) {
3824         ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
3825         if (ret == 0)
3826             ret = 1;
3827         else if (ret == 1)
3828             ret = 0;
3829     } else {
3830         TODO ret = 0;
3831     }
3832     if (ret == 0)
3833         return (ret);
3834     if ((def2->type == XML_RELAXNG_ELEMENT) ||
3835         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3836         if (def2->name != NULL) {
3837             node.name = def2->name;
3838         } else {
3839             node.name = invalidName;
3840         }
3841         node.ns = &ns;
3842         if (def2->ns != NULL) {
3843             if (def2->ns[0] == 0) {
3844                 node.ns = NULL;
3845             } else {
3846                 ns.href = def2->ns;
3847             }
3848         } else {
3849             ns.href = invalidName;
3850         }
3851         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3852             if (def2->nameClass != NULL) {
3853                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3854             } else {
3855                 ret = 0;
3856             }
3857         } else {
3858             ret = 1;
3859         }
3860     } else {
3861         TODO ret = 0;
3862     }
3863
3864     return (ret);
3865 }
3866
3867 /**
3868  * xmlRelaxNGCompareElemDefLists:
3869  * @ctxt:  a Relax-NG parser context
3870  * @defs1:  the first list of element/attribute defs
3871  * @defs2:  the second list of element/attribute defs
3872  *
3873  * Compare the 2 lists of element or attribute definitions. The comparison
3874  * is that if both lists do not accept the same QNames, it returns 1
3875  * If the 2 lists can accept the same QName the comparison returns 0
3876  *
3877  * Returns 1 disttinct, 0 if equal
3878  */
3879 static int
3880 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3881                               ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3882                               xmlRelaxNGDefinePtr * def2)
3883 {
3884     xmlRelaxNGDefinePtr *basedef2 = def2;
3885
3886     if ((def1 == NULL) || (def2 == NULL))
3887         return (1);
3888     if ((*def1 == NULL) || (*def2 == NULL))
3889         return (1);
3890     while (*def1 != NULL) {
3891         while ((*def2) != NULL) {
3892             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3893                 return (0);
3894             def2++;
3895         }
3896         def2 = basedef2;
3897         def1++;
3898     }
3899     return (1);
3900 }
3901
3902 /**
3903  * xmlRelaxNGGenerateAttributes:
3904  * @ctxt:  a Relax-NG parser context
3905  * @def:  the definition definition
3906  *
3907  * Check if the definition can only generate attributes
3908  *
3909  * Returns 1 if yes, 0 if no and -1 in case of error.
3910  */
3911 static int
3912 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3913                              xmlRelaxNGDefinePtr def)
3914 {
3915     xmlRelaxNGDefinePtr parent, cur, tmp;
3916
3917     /*
3918      * Don't run that check in case of error. Infinite recursion
3919      * becomes possible.
3920      */
3921     if (ctxt->nbErrors != 0)
3922         return (-1);
3923
3924     parent = NULL;
3925     cur = def;
3926     while (cur != NULL) {
3927         if ((cur->type == XML_RELAXNG_ELEMENT) ||
3928             (cur->type == XML_RELAXNG_TEXT) ||
3929             (cur->type == XML_RELAXNG_DATATYPE) ||
3930             (cur->type == XML_RELAXNG_PARAM) ||
3931             (cur->type == XML_RELAXNG_LIST) ||
3932             (cur->type == XML_RELAXNG_VALUE) ||
3933             (cur->type == XML_RELAXNG_EMPTY))
3934             return (0);
3935         if ((cur->type == XML_RELAXNG_CHOICE) ||
3936             (cur->type == XML_RELAXNG_INTERLEAVE) ||
3937             (cur->type == XML_RELAXNG_GROUP) ||
3938             (cur->type == XML_RELAXNG_ONEORMORE) ||
3939             (cur->type == XML_RELAXNG_ZEROORMORE) ||
3940             (cur->type == XML_RELAXNG_OPTIONAL) ||
3941             (cur->type == XML_RELAXNG_PARENTREF) ||
3942             (cur->type == XML_RELAXNG_EXTERNALREF) ||
3943             (cur->type == XML_RELAXNG_REF) ||
3944             (cur->type == XML_RELAXNG_DEF)) {
3945             if (cur->content != NULL) {
3946                 parent = cur;
3947                 cur = cur->content;
3948                 tmp = cur;
3949                 while (tmp != NULL) {
3950                     tmp->parent = parent;
3951                     tmp = tmp->next;
3952                 }
3953                 continue;
3954             }
3955         }
3956         if (cur == def)
3957             break;
3958         if (cur->next != NULL) {
3959             cur = cur->next;
3960             continue;
3961         }
3962         do {
3963             cur = cur->parent;
3964             if (cur == NULL)
3965                 break;
3966             if (cur == def)
3967                 return (1);
3968             if (cur->next != NULL) {
3969                 cur = cur->next;
3970                 break;
3971             }
3972         } while (cur != NULL);
3973     }
3974     return (1);
3975 }
3976
3977 /**
3978  * xmlRelaxNGGetElements:
3979  * @ctxt:  a Relax-NG parser context
3980  * @def:  the definition definition
3981  * @eora:  gather elements (0) or attributes (1)
3982  *
3983  * Compute the list of top elements a definition can generate
3984  *
3985  * Returns a list of elements or NULL if none was found.
3986  */
3987 static xmlRelaxNGDefinePtr *
3988 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
3989                       xmlRelaxNGDefinePtr def, int eora)
3990 {
3991     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
3992     int len = 0;
3993     int max = 0;
3994
3995     /*
3996      * Don't run that check in case of error. Infinite recursion
3997      * becomes possible.
3998      */
3999     if (ctxt->nbErrors != 0)
4000         return (NULL);
4001
4002     parent = NULL;
4003     cur = def;
4004     while (cur != NULL) {
4005         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
4006                              (cur->type == XML_RELAXNG_TEXT))) ||
4007             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
4008             if (ret == NULL) {
4009                 max = 10;
4010                 ret = (xmlRelaxNGDefinePtr *)
4011                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
4012                 if (ret == NULL) {
4013                     xmlRngPErrMemory(ctxt, "getting element list\n");
4014                     return (NULL);
4015                 }
4016             } else if (max <= len) {
4017                 xmlRelaxNGDefinePtr *temp;
4018
4019                 max *= 2;
4020                 temp = xmlRealloc(ret,
4021                                (max + 1) * sizeof(xmlRelaxNGDefinePtr));
4022                 if (temp == NULL) {
4023                     xmlRngPErrMemory(ctxt, "getting element list\n");
4024                     xmlFree(ret);
4025                     return (NULL);
4026                 }
4027                 ret = temp;
4028             }
4029             ret[len++] = cur;
4030             ret[len] = NULL;
4031         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
4032                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
4033                    (cur->type == XML_RELAXNG_GROUP) ||
4034                    (cur->type == XML_RELAXNG_ONEORMORE) ||
4035                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
4036                    (cur->type == XML_RELAXNG_OPTIONAL) ||
4037                    (cur->type == XML_RELAXNG_PARENTREF) ||
4038                    (cur->type == XML_RELAXNG_REF) ||
4039                    (cur->type == XML_RELAXNG_DEF) ||
4040                    (cur->type == XML_RELAXNG_EXTERNALREF)) {
4041             /*
4042              * Don't go within elements or attributes or string values.
4043              * Just gather the element top list
4044              */
4045             if (cur->content != NULL) {
4046                 parent = cur;
4047                 cur = cur->content;
4048                 tmp = cur;
4049                 while (tmp != NULL) {
4050                     tmp->parent = parent;
4051                     tmp = tmp->next;
4052                 }
4053                 continue;
4054             }
4055         }
4056         if (cur == def)
4057             break;
4058         if (cur->next != NULL) {
4059             cur = cur->next;
4060             continue;
4061         }
4062         do {
4063             cur = cur->parent;
4064             if (cur == NULL)
4065                 break;
4066             if (cur == def)
4067                 return (ret);
4068             if (cur->next != NULL) {
4069                 cur = cur->next;
4070                 break;
4071             }
4072         } while (cur != NULL);
4073     }
4074     return (ret);
4075 }
4076
4077 /**
4078  * xmlRelaxNGCheckChoiceDeterminism:
4079  * @ctxt:  a Relax-NG parser context
4080  * @def:  the choice definition
4081  *
4082  * Also used to find indeterministic pattern in choice
4083  */
4084 static void
4085 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
4086                                  xmlRelaxNGDefinePtr def)
4087 {
4088     xmlRelaxNGDefinePtr **list;
4089     xmlRelaxNGDefinePtr cur;
4090     int nbchild = 0, i, j, ret;
4091     int is_nullable = 0;
4092     int is_indeterminist = 0;
4093     xmlHashTablePtr triage = NULL;
4094     int is_triable = 1;
4095
4096     if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4097         return;
4098
4099     if (def->dflags & IS_PROCESSED)
4100         return;
4101
4102     /*
4103      * Don't run that check in case of error. Infinite recursion
4104      * becomes possible.
4105      */
4106     if (ctxt->nbErrors != 0)
4107         return;
4108
4109     is_nullable = xmlRelaxNGIsNullable(def);
4110
4111     cur = def->content;
4112     while (cur != NULL) {
4113         nbchild++;
4114         cur = cur->next;
4115     }
4116
4117     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4118                                               sizeof(xmlRelaxNGDefinePtr
4119                                                      *));
4120     if (list == NULL) {
4121         xmlRngPErrMemory(ctxt, "building choice\n");
4122         return;
4123     }
4124     i = 0;
4125     /*
4126      * a bit strong but safe
4127      */
4128     if (is_nullable == 0) {
4129         triage = xmlHashCreate(10);
4130     } else {
4131         is_triable = 0;
4132     }
4133     cur = def->content;
4134     while (cur != NULL) {
4135         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4136         if ((list[i] == NULL) || (list[i][0] == NULL)) {
4137             is_triable = 0;
4138         } else if (is_triable == 1) {
4139             xmlRelaxNGDefinePtr *tmp;
4140             int res;
4141
4142             tmp = list[i];
4143             while ((*tmp != NULL) && (is_triable == 1)) {
4144                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4145                     res = xmlHashAddEntry2(triage,
4146                                            BAD_CAST "#text", NULL,
4147                                            (void *) cur);
4148                     if (res != 0)
4149                         is_triable = -1;
4150                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4151                            ((*tmp)->name != NULL)) {
4152                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4153                         res = xmlHashAddEntry2(triage,
4154                                                (*tmp)->name, NULL,
4155                                                (void *) cur);
4156                     else
4157                         res = xmlHashAddEntry2(triage,
4158                                                (*tmp)->name, (*tmp)->ns,
4159                                                (void *) cur);
4160                     if (res != 0)
4161                         is_triable = -1;
4162                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4163                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4164                         res = xmlHashAddEntry2(triage,
4165                                                BAD_CAST "#any", NULL,
4166                                                (void *) cur);
4167                     else
4168                         res = xmlHashAddEntry2(triage,
4169                                                BAD_CAST "#any", (*tmp)->ns,
4170                                                (void *) cur);
4171                     if (res != 0)
4172                         is_triable = -1;
4173                 } else {
4174                     is_triable = -1;
4175                 }
4176                 tmp++;
4177             }
4178         }
4179         i++;
4180         cur = cur->next;
4181     }
4182
4183     for (i = 0; i < nbchild; i++) {
4184         if (list[i] == NULL)
4185             continue;
4186         for (j = 0; j < i; j++) {
4187             if (list[j] == NULL)
4188                 continue;
4189             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4190             if (ret == 0) {
4191                 is_indeterminist = 1;
4192             }
4193         }
4194     }
4195     for (i = 0; i < nbchild; i++) {
4196         if (list[i] != NULL)
4197             xmlFree(list[i]);
4198     }
4199
4200     xmlFree(list);
4201     if (is_indeterminist) {
4202         def->dflags |= IS_INDETERMINIST;
4203     }
4204     if (is_triable == 1) {
4205         def->dflags |= IS_TRIABLE;
4206         def->data = triage;
4207     } else if (triage != NULL) {
4208         xmlHashFree(triage, NULL);
4209     }
4210     def->dflags |= IS_PROCESSED;
4211 }
4212
4213 /**
4214  * xmlRelaxNGCheckGroupAttrs:
4215  * @ctxt:  a Relax-NG parser context
4216  * @def:  the group definition
4217  *
4218  * Detects violations of rule 7.3
4219  */
4220 static void
4221 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4222                           xmlRelaxNGDefinePtr def)
4223 {
4224     xmlRelaxNGDefinePtr **list;
4225     xmlRelaxNGDefinePtr cur;
4226     int nbchild = 0, i, j, ret;
4227
4228     if ((def == NULL) ||
4229         ((def->type != XML_RELAXNG_GROUP) &&
4230          (def->type != XML_RELAXNG_ELEMENT)))
4231         return;
4232
4233     if (def->dflags & IS_PROCESSED)
4234         return;
4235
4236     /*
4237      * Don't run that check in case of error. Infinite recursion
4238      * becomes possible.
4239      */
4240     if (ctxt->nbErrors != 0)
4241         return;
4242
4243     cur = def->attrs;
4244     while (cur != NULL) {
4245         nbchild++;
4246         cur = cur->next;
4247     }
4248     cur = def->content;
4249     while (cur != NULL) {
4250         nbchild++;
4251         cur = cur->next;
4252     }
4253
4254     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4255                                               sizeof(xmlRelaxNGDefinePtr
4256                                                      *));
4257     if (list == NULL) {
4258         xmlRngPErrMemory(ctxt, "building group\n");
4259         return;
4260     }
4261     i = 0;
4262     cur = def->attrs;
4263     while (cur != NULL) {
4264         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4265         i++;
4266         cur = cur->next;
4267     }
4268     cur = def->content;
4269     while (cur != NULL) {
4270         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4271         i++;
4272         cur = cur->next;
4273     }
4274
4275     for (i = 0; i < nbchild; i++) {
4276         if (list[i] == NULL)
4277             continue;
4278         for (j = 0; j < i; j++) {
4279             if (list[j] == NULL)
4280                 continue;
4281             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4282             if (ret == 0) {
4283                 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4284                            "Attributes conflicts in group\n", NULL, NULL);
4285             }
4286         }
4287     }
4288     for (i = 0; i < nbchild; i++) {
4289         if (list[i] != NULL)
4290             xmlFree(list[i]);
4291     }
4292
4293     xmlFree(list);
4294     def->dflags |= IS_PROCESSED;
4295 }
4296
4297 /**
4298  * xmlRelaxNGComputeInterleaves:
4299  * @def:  the interleave definition
4300  * @ctxt:  a Relax-NG parser context
4301  * @name:  the definition name
4302  *
4303  * A lot of work for preprocessing interleave definitions
4304  * is potentially needed to get a decent execution speed at runtime
4305  *   - trying to get a total order on the element nodes generated
4306  *     by the interleaves, order the list of interleave definitions
4307  *     following that order.
4308  *   - if <text/> is used to handle mixed content, it is better to
4309  *     flag this in the define and simplify the runtime checking
4310  *     algorithm
4311  */
4312 static void
4313 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4314                              xmlRelaxNGParserCtxtPtr ctxt,
4315                              xmlChar * name ATTRIBUTE_UNUSED)
4316 {
4317     xmlRelaxNGDefinePtr cur, *tmp;
4318
4319     xmlRelaxNGPartitionPtr partitions = NULL;
4320     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4321     xmlRelaxNGInterleaveGroupPtr group;
4322     int i, j, ret, res;
4323     int nbgroups = 0;
4324     int nbchild = 0;
4325     int is_mixed = 0;
4326     int is_determinist = 1;
4327
4328     /*
4329      * Don't run that check in case of error. Infinite recursion
4330      * becomes possible.
4331      */
4332     if (ctxt->nbErrors != 0)
4333         return;
4334
4335 #ifdef DEBUG_INTERLEAVE
4336     xmlGenericError(xmlGenericErrorContext,
4337                     "xmlRelaxNGComputeInterleaves(%s)\n", name);
4338 #endif
4339     cur = def->content;
4340     while (cur != NULL) {
4341         nbchild++;
4342         cur = cur->next;
4343     }
4344
4345 #ifdef DEBUG_INTERLEAVE
4346     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4347 #endif
4348     groups = (xmlRelaxNGInterleaveGroupPtr *)
4349         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4350     if (groups == NULL)
4351         goto error;
4352     cur = def->content;
4353     while (cur != NULL) {
4354         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4355             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4356         if (groups[nbgroups] == NULL)
4357             goto error;
4358         if (cur->type == XML_RELAXNG_TEXT)
4359             is_mixed++;
4360         groups[nbgroups]->rule = cur;
4361         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4362         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4363         nbgroups++;
4364         cur = cur->next;
4365     }
4366 #ifdef DEBUG_INTERLEAVE
4367     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4368 #endif
4369
4370     /*
4371      * Let's check that all rules makes a partitions according to 7.4
4372      */
4373     partitions = (xmlRelaxNGPartitionPtr)
4374         xmlMalloc(sizeof(xmlRelaxNGPartition));
4375     if (partitions == NULL)
4376         goto error;
4377     memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4378     partitions->nbgroups = nbgroups;
4379     partitions->triage = xmlHashCreate(nbgroups);
4380     for (i = 0; i < nbgroups; i++) {
4381         group = groups[i];
4382         for (j = i + 1; j < nbgroups; j++) {
4383             if (groups[j] == NULL)
4384                 continue;
4385
4386             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4387                                                 groups[j]->defs);
4388             if (ret == 0) {
4389                 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4390                            "Element or text conflicts in interleave\n",
4391                            NULL, NULL);
4392             }
4393             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4394                                                 groups[j]->attrs);
4395             if (ret == 0) {
4396                 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4397                            "Attributes conflicts in interleave\n", NULL,
4398                            NULL);
4399             }
4400         }
4401         tmp = group->defs;
4402         if ((tmp != NULL) && (*tmp != NULL)) {
4403             while (*tmp != NULL) {
4404                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4405                     res = xmlHashAddEntry2(partitions->triage,
4406                                            BAD_CAST "#text", NULL,
4407                                            (void *) (long) (i + 1));
4408                     if (res != 0)
4409                         is_determinist = -1;
4410                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4411                            ((*tmp)->name != NULL)) {
4412                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4413                         res = xmlHashAddEntry2(partitions->triage,
4414                                                (*tmp)->name, NULL,
4415                                                (void *) (long) (i + 1));
4416                     else
4417                         res = xmlHashAddEntry2(partitions->triage,
4418                                                (*tmp)->name, (*tmp)->ns,
4419                                                (void *) (long) (i + 1));
4420                     if (res != 0)
4421                         is_determinist = -1;
4422                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4423                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4424                         res = xmlHashAddEntry2(partitions->triage,
4425                                                BAD_CAST "#any", NULL,
4426                                                (void *) (long) (i + 1));
4427                     else
4428                         res = xmlHashAddEntry2(partitions->triage,
4429                                                BAD_CAST "#any", (*tmp)->ns,
4430                                                (void *) (long) (i + 1));
4431                     if ((*tmp)->nameClass != NULL)
4432                         is_determinist = 2;
4433                     if (res != 0)
4434                         is_determinist = -1;
4435                 } else {
4436                     is_determinist = -1;
4437                 }
4438                 tmp++;
4439             }
4440         } else {
4441             is_determinist = 0;
4442         }
4443     }
4444     partitions->groups = groups;
4445
4446     /*
4447      * and save the partition list back in the def
4448      */
4449     def->data = partitions;
4450     if (is_mixed != 0)
4451         def->dflags |= IS_MIXED;
4452     if (is_determinist == 1)
4453         partitions->flags = IS_DETERMINIST;
4454     if (is_determinist == 2)
4455         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4456     return;
4457
4458   error:
4459     xmlRngPErrMemory(ctxt, "in interleave computation\n");
4460     if (groups != NULL) {
4461         for (i = 0; i < nbgroups; i++)
4462             if (groups[i] != NULL) {
4463                 if (groups[i]->defs != NULL)
4464                     xmlFree(groups[i]->defs);
4465                 xmlFree(groups[i]);
4466             }
4467         xmlFree(groups);
4468     }
4469     xmlRelaxNGFreePartition(partitions);
4470 }
4471
4472 /**
4473  * xmlRelaxNGParseInterleave:
4474  * @ctxt:  a Relax-NG parser context
4475  * @node:  the data node.
4476  *
4477  * parse the content of a RelaxNG interleave node.
4478  *
4479  * Returns the definition pointer or NULL in case of error
4480  */
4481 static xmlRelaxNGDefinePtr
4482 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4483 {
4484     xmlRelaxNGDefinePtr def = NULL;
4485     xmlRelaxNGDefinePtr last = NULL, cur;
4486     xmlNodePtr child;
4487
4488     def = xmlRelaxNGNewDefine(ctxt, node);
4489     if (def == NULL) {
4490         return (NULL);
4491     }
4492     def->type = XML_RELAXNG_INTERLEAVE;
4493
4494     if (ctxt->interleaves == NULL)
4495         ctxt->interleaves = xmlHashCreate(10);
4496     if (ctxt->interleaves == NULL) {
4497         xmlRngPErrMemory(ctxt, "create interleaves\n");
4498     } else {
4499         char name[32];
4500
4501         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4502         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4503             xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4504                        "Failed to add %s to hash table\n",
4505                        (const xmlChar *) name, NULL);
4506         }
4507     }
4508     child = node->children;
4509     if (child == NULL) {
4510         xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4511                    "Element interleave is empty\n", NULL, NULL);
4512     }
4513     while (child != NULL) {
4514         if (IS_RELAXNG(child, "element")) {
4515             cur = xmlRelaxNGParseElement(ctxt, child);
4516         } else {
4517             cur = xmlRelaxNGParsePattern(ctxt, child);
4518         }
4519         if (cur != NULL) {
4520             cur->parent = def;
4521             if (last == NULL) {
4522                 def->content = last = cur;
4523             } else {
4524                 last->next = cur;
4525                 last = cur;
4526             }
4527         }
4528         child = child->next;
4529     }
4530
4531     return (def);
4532 }
4533
4534 /**
4535  * xmlRelaxNGParseInclude:
4536  * @ctxt:  a Relax-NG parser context
4537  * @node:  the include node
4538  *
4539  * Integrate the content of an include node in the current grammar
4540  *
4541  * Returns 0 in case of success or -1 in case of error
4542  */
4543 static int
4544 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4545 {
4546     xmlRelaxNGIncludePtr incl;
4547     xmlNodePtr root;
4548     int ret = 0, tmp;
4549
4550     incl = node->psvi;
4551     if (incl == NULL) {
4552         xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4553                    "Include node has no data\n", NULL, NULL);
4554         return (-1);
4555     }
4556     root = xmlDocGetRootElement(incl->doc);
4557     if (root == NULL) {
4558         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4559                    NULL, NULL);
4560         return (-1);
4561     }
4562     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4563         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4564                    "Include document root is not a grammar\n", NULL, NULL);
4565         return (-1);
4566     }
4567
4568     /*
4569      * Merge the definition from both the include and the internal list
4570      */
4571     if (root->children != NULL) {
4572         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4573         if (tmp != 0)
4574             ret = -1;
4575     }
4576     if (node->children != NULL) {
4577         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4578         if (tmp != 0)
4579             ret = -1;
4580     }
4581     return (ret);
4582 }
4583
4584 /**
4585  * xmlRelaxNGParseDefine:
4586  * @ctxt:  a Relax-NG parser context
4587  * @node:  the define node
4588  *
4589  * parse the content of a RelaxNG define element node.
4590  *
4591  * Returns 0 in case of success or -1 in case of error
4592  */
4593 static int
4594 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4595 {
4596     xmlChar *name;
4597     int ret = 0, tmp;
4598     xmlRelaxNGDefinePtr def;
4599     const xmlChar *olddefine;
4600
4601     name = xmlGetProp(node, BAD_CAST "name");
4602     if (name == NULL) {
4603         xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4604                    "define has no name\n", NULL, NULL);
4605     } else {
4606         xmlRelaxNGNormExtSpace(name);
4607         if (xmlValidateNCName(name, 0)) {
4608             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4609                        "define name '%s' is not an NCName\n", name, NULL);
4610         }
4611         def = xmlRelaxNGNewDefine(ctxt, node);
4612         if (def == NULL) {
4613             xmlFree(name);
4614             return (-1);
4615         }
4616         def->type = XML_RELAXNG_DEF;
4617         def->name = name;
4618         if (node->children == NULL) {
4619             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4620                        "define has no children\n", NULL, NULL);
4621         } else {
4622             olddefine = ctxt->define;
4623             ctxt->define = name;
4624             def->content =
4625                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4626             ctxt->define = olddefine;
4627         }
4628         if (ctxt->grammar->defs == NULL)
4629             ctxt->grammar->defs = xmlHashCreate(10);
4630         if (ctxt->grammar->defs == NULL) {
4631             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4632                        "Could not create definition hash\n", NULL, NULL);
4633             ret = -1;
4634         } else {
4635             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4636             if (tmp < 0) {
4637                 xmlRelaxNGDefinePtr prev;
4638
4639                 prev = xmlHashLookup(ctxt->grammar->defs, name);
4640                 if (prev == NULL) {
4641                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4642                                "Internal error on define aggregation of %s\n",
4643                                name, NULL);
4644                     ret = -1;
4645                 } else {
4646                     while (prev->nextHash != NULL)
4647                         prev = prev->nextHash;
4648                     prev->nextHash = def;
4649                 }
4650             }
4651         }
4652     }
4653     return (ret);
4654 }
4655
4656 /**
4657  * xmlRelaxNGParseImportRef:
4658  * @payload: the parser context
4659  * @data: the current grammar
4660  * @name: the reference name
4661  *
4662  * Import import one references into the current grammar
4663  */
4664 static void
4665 xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
4666     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4667     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4668     int tmp;
4669
4670     def->dflags |= IS_EXTERNAL_REF;
4671
4672     tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4673     if (tmp < 0) {
4674         xmlRelaxNGDefinePtr prev;
4675
4676         prev = (xmlRelaxNGDefinePtr)
4677             xmlHashLookup(ctxt->grammar->refs, def->name);
4678         if (prev == NULL) {
4679             if (def->name != NULL) {
4680                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4681                            "Error refs definitions '%s'\n",
4682                            def->name, NULL);
4683             } else {
4684                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4685                            "Error refs definitions\n",
4686                            NULL, NULL);
4687             }
4688         } else {
4689             def->nextHash = prev->nextHash;
4690             prev->nextHash = def;
4691         }
4692     }
4693 }
4694
4695 /**
4696  * xmlRelaxNGParseImportRefs:
4697  * @ctxt: the parser context
4698  * @grammar: the sub grammar
4699  *
4700  * Import references from the subgrammar into the current grammar
4701  *
4702  * Returns 0 in case of success, -1 in case of failure
4703  */
4704 static int
4705 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4706                           xmlRelaxNGGrammarPtr grammar) {
4707     if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4708         return(-1);
4709     if (grammar->refs == NULL)
4710         return(0);
4711     if (ctxt->grammar->refs == NULL)
4712         ctxt->grammar->refs = xmlHashCreate(10);
4713     if (ctxt->grammar->refs == NULL) {
4714         xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4715                    "Could not create references hash\n", NULL, NULL);
4716         return(-1);
4717     }
4718     xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
4719     return(0);
4720 }
4721
4722 /**
4723  * xmlRelaxNGProcessExternalRef:
4724  * @ctxt: the parser context
4725  * @node:  the externlRef node
4726  *
4727  * Process and compile an externlRef node
4728  *
4729  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4730  */
4731 static xmlRelaxNGDefinePtr
4732 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4733 {
4734     xmlRelaxNGDocumentPtr docu;
4735     xmlNodePtr root, tmp;
4736     xmlChar *ns;
4737     int newNs = 0, oldflags;
4738     xmlRelaxNGDefinePtr def;
4739
4740     docu = node->psvi;
4741     if (docu != NULL) {
4742         def = xmlRelaxNGNewDefine(ctxt, node);
4743         if (def == NULL)
4744             return (NULL);
4745         def->type = XML_RELAXNG_EXTERNALREF;
4746
4747         if (docu->content == NULL) {
4748             /*
4749              * Then do the parsing for good
4750              */
4751             root = xmlDocGetRootElement(docu->doc);
4752             if (root == NULL) {
4753                 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4754                            "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4755                            NULL);
4756                 return (NULL);
4757             }
4758             /*
4759              * ns transmission rules
4760              */
4761             ns = xmlGetProp(root, BAD_CAST "ns");
4762             if (ns == NULL) {
4763                 tmp = node;
4764                 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4765                     ns = xmlGetProp(tmp, BAD_CAST "ns");
4766                     if (ns != NULL) {
4767                         break;
4768                     }
4769                     tmp = tmp->parent;
4770                 }
4771                 if (ns != NULL) {
4772                     xmlSetProp(root, BAD_CAST "ns", ns);
4773                     newNs = 1;
4774                     xmlFree(ns);
4775                 }
4776             } else {
4777                 xmlFree(ns);
4778             }
4779
4780             /*
4781              * Parsing to get a precompiled schemas.
4782              */
4783             oldflags = ctxt->flags;
4784             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4785             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4786             ctxt->flags = oldflags;
4787             if ((docu->schema != NULL) &&
4788                 (docu->schema->topgrammar != NULL)) {
4789                 docu->content = docu->schema->topgrammar->start;
4790                 if (docu->schema->topgrammar->refs)
4791                     xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
4792             }
4793
4794             /*
4795              * the externalRef may be reused in a different ns context
4796              */
4797             if (newNs == 1) {
4798                 xmlUnsetProp(root, BAD_CAST "ns");
4799             }
4800         }
4801         def->content = docu->content;
4802     } else {
4803         def = NULL;
4804     }
4805     return (def);
4806 }
4807
4808 /**
4809  * xmlRelaxNGParsePattern:
4810  * @ctxt:  a Relax-NG parser context
4811  * @node:  the pattern node.
4812  *
4813  * parse the content of a RelaxNG pattern node.
4814  *
4815  * Returns the definition pointer or NULL in case of error or if no
4816  *     pattern is generated.
4817  */
4818 static xmlRelaxNGDefinePtr
4819 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4820 {
4821     xmlRelaxNGDefinePtr def = NULL;
4822
4823     if (node == NULL) {
4824         return (NULL);
4825     }
4826     if (IS_RELAXNG(node, "element")) {
4827         def = xmlRelaxNGParseElement(ctxt, node);
4828     } else if (IS_RELAXNG(node, "attribute")) {
4829         def = xmlRelaxNGParseAttribute(ctxt, node);
4830     } else if (IS_RELAXNG(node, "empty")) {
4831         def = xmlRelaxNGNewDefine(ctxt, node);
4832         if (def == NULL)
4833             return (NULL);
4834         def->type = XML_RELAXNG_EMPTY;
4835         if (node->children != NULL) {
4836             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4837                        "empty: had a child node\n", NULL, NULL);
4838         }
4839     } else if (IS_RELAXNG(node, "text")) {
4840         def = xmlRelaxNGNewDefine(ctxt, node);
4841         if (def == NULL)
4842             return (NULL);
4843         def->type = XML_RELAXNG_TEXT;
4844         if (node->children != NULL) {
4845             xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4846                        "text: had a child node\n", NULL, NULL);
4847         }
4848     } else if (IS_RELAXNG(node, "zeroOrMore")) {
4849         def = xmlRelaxNGNewDefine(ctxt, node);
4850         if (def == NULL)
4851             return (NULL);
4852         def->type = XML_RELAXNG_ZEROORMORE;
4853         if (node->children == NULL) {
4854             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4855                        "Element %s is empty\n", node->name, NULL);
4856         } else {
4857             def->content =
4858                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4859         }
4860     } else if (IS_RELAXNG(node, "oneOrMore")) {
4861         def = xmlRelaxNGNewDefine(ctxt, node);
4862         if (def == NULL)
4863             return (NULL);
4864         def->type = XML_RELAXNG_ONEORMORE;
4865         if (node->children == NULL) {
4866             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4867                        "Element %s is empty\n", node->name, NULL);
4868         } else {
4869             def->content =
4870                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4871         }
4872     } else if (IS_RELAXNG(node, "optional")) {
4873         def = xmlRelaxNGNewDefine(ctxt, node);
4874         if (def == NULL)
4875             return (NULL);
4876         def->type = XML_RELAXNG_OPTIONAL;
4877         if (node->children == NULL) {
4878             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4879                        "Element %s is empty\n", node->name, NULL);
4880         } else {
4881             def->content =
4882                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4883         }
4884     } else if (IS_RELAXNG(node, "choice")) {
4885         def = xmlRelaxNGNewDefine(ctxt, node);
4886         if (def == NULL)
4887             return (NULL);
4888         def->type = XML_RELAXNG_CHOICE;
4889         if (node->children == NULL) {
4890             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4891                        "Element %s is empty\n", node->name, NULL);
4892         } else {
4893             def->content =
4894                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4895         }
4896     } else if (IS_RELAXNG(node, "group")) {
4897         def = xmlRelaxNGNewDefine(ctxt, node);
4898         if (def == NULL)
4899             return (NULL);
4900         def->type = XML_RELAXNG_GROUP;
4901         if (node->children == NULL) {
4902             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4903                        "Element %s is empty\n", node->name, NULL);
4904         } else {
4905             def->content =
4906                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4907         }
4908     } else if (IS_RELAXNG(node, "ref")) {
4909         def = xmlRelaxNGNewDefine(ctxt, node);
4910         if (def == NULL)
4911             return (NULL);
4912         def->type = XML_RELAXNG_REF;
4913         def->name = xmlGetProp(node, BAD_CAST "name");
4914         if (def->name == NULL) {
4915             xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4916                        NULL, NULL);
4917         } else {
4918             xmlRelaxNGNormExtSpace(def->name);
4919             if (xmlValidateNCName(def->name, 0)) {
4920                 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4921                            "ref name '%s' is not an NCName\n", def->name,
4922                            NULL);
4923             }
4924         }
4925         if (node->children != NULL) {
4926             xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4927                        NULL, NULL);
4928         }
4929         if (ctxt->grammar->refs == NULL)
4930             ctxt->grammar->refs = xmlHashCreate(10);
4931         if (ctxt->grammar->refs == NULL) {
4932             xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4933                        "Could not create references hash\n", NULL, NULL);
4934             def = NULL;
4935         } else {
4936             int tmp;
4937
4938             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4939             if (tmp < 0) {
4940                 xmlRelaxNGDefinePtr prev;
4941
4942                 prev = (xmlRelaxNGDefinePtr)
4943                     xmlHashLookup(ctxt->grammar->refs, def->name);
4944                 if (prev == NULL) {
4945                     if (def->name != NULL) {
4946                         xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4947                                    "Error refs definitions '%s'\n",
4948                                    def->name, NULL);
4949                     } else {
4950                         xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4951                                    "Error refs definitions\n",
4952                                    NULL, NULL);
4953                     }
4954                     def = NULL;
4955                 } else {
4956                     def->nextHash = prev->nextHash;
4957                     prev->nextHash = def;
4958                 }
4959             }
4960         }
4961     } else if (IS_RELAXNG(node, "data")) {
4962         def = xmlRelaxNGParseData(ctxt, node);
4963     } else if (IS_RELAXNG(node, "value")) {
4964         def = xmlRelaxNGParseValue(ctxt, node);
4965     } else if (IS_RELAXNG(node, "list")) {
4966         def = xmlRelaxNGNewDefine(ctxt, node);
4967         if (def == NULL)
4968             return (NULL);
4969         def->type = XML_RELAXNG_LIST;
4970         if (node->children == NULL) {
4971             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4972                        "Element %s is empty\n", node->name, NULL);
4973         } else {
4974             def->content =
4975                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4976         }
4977     } else if (IS_RELAXNG(node, "interleave")) {
4978         def = xmlRelaxNGParseInterleave(ctxt, node);
4979     } else if (IS_RELAXNG(node, "externalRef")) {
4980         def = xmlRelaxNGProcessExternalRef(ctxt, node);
4981     } else if (IS_RELAXNG(node, "notAllowed")) {
4982         def = xmlRelaxNGNewDefine(ctxt, node);
4983         if (def == NULL)
4984             return (NULL);
4985         def->type = XML_RELAXNG_NOT_ALLOWED;
4986         if (node->children != NULL) {
4987             xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4988                        "xmlRelaxNGParse: notAllowed element is not empty\n",
4989                        NULL, NULL);
4990         }
4991     } else if (IS_RELAXNG(node, "grammar")) {
4992         xmlRelaxNGGrammarPtr grammar, old;
4993         xmlRelaxNGGrammarPtr oldparent;
4994
4995 #ifdef DEBUG_GRAMMAR
4996         xmlGenericError(xmlGenericErrorContext,
4997                         "Found <grammar> pattern\n");
4998 #endif
4999
5000         oldparent = ctxt->parentgrammar;
5001         old = ctxt->grammar;
5002         ctxt->parentgrammar = old;
5003         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5004         if (old != NULL) {
5005             ctxt->grammar = old;
5006             ctxt->parentgrammar = oldparent;
5007 #if 0
5008             if (grammar != NULL) {
5009                 grammar->next = old->next;
5010                 old->next = grammar;
5011             }
5012 #endif
5013         }
5014         if (grammar != NULL)
5015             def = grammar->start;
5016         else
5017             def = NULL;
5018     } else if (IS_RELAXNG(node, "parentRef")) {
5019         if (ctxt->parentgrammar == NULL) {
5020             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
5021                        "Use of parentRef without a parent grammar\n", NULL,
5022                        NULL);
5023             return (NULL);
5024         }
5025         def = xmlRelaxNGNewDefine(ctxt, node);
5026         if (def == NULL)
5027             return (NULL);
5028         def->type = XML_RELAXNG_PARENTREF;
5029         def->name = xmlGetProp(node, BAD_CAST "name");
5030         if (def->name == NULL) {
5031             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
5032                        "parentRef has no name\n", NULL, NULL);
5033         } else {
5034             xmlRelaxNGNormExtSpace(def->name);
5035             if (xmlValidateNCName(def->name, 0)) {
5036                 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
5037                            "parentRef name '%s' is not an NCName\n",
5038                            def->name, NULL);
5039             }
5040         }
5041         if (node->children != NULL) {
5042             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
5043                        "parentRef is not empty\n", NULL, NULL);
5044         }
5045         if (ctxt->parentgrammar->refs == NULL)
5046             ctxt->parentgrammar->refs = xmlHashCreate(10);
5047         if (ctxt->parentgrammar->refs == NULL) {
5048             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5049                        "Could not create references hash\n", NULL, NULL);
5050             def = NULL;
5051         } else if (def->name != NULL) {
5052             int tmp;
5053
5054             tmp =
5055                 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
5056             if (tmp < 0) {
5057                 xmlRelaxNGDefinePtr prev;
5058
5059                 prev = (xmlRelaxNGDefinePtr)
5060                     xmlHashLookup(ctxt->parentgrammar->refs, def->name);
5061                 if (prev == NULL) {
5062                     xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5063                                "Internal error parentRef definitions '%s'\n",
5064                                def->name, NULL);
5065                     def = NULL;
5066                 } else {
5067                     def->nextHash = prev->nextHash;
5068                     prev->nextHash = def;
5069                 }
5070             }
5071         }
5072     } else if (IS_RELAXNG(node, "mixed")) {
5073         if (node->children == NULL) {
5074             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
5075                        NULL, NULL);
5076             def = NULL;
5077         } else {
5078             def = xmlRelaxNGParseInterleave(ctxt, node);
5079             if (def != NULL) {
5080                 xmlRelaxNGDefinePtr tmp;
5081
5082                 if ((def->content != NULL) && (def->content->next != NULL)) {
5083                     tmp = xmlRelaxNGNewDefine(ctxt, node);
5084                     if (tmp != NULL) {
5085                         tmp->type = XML_RELAXNG_GROUP;
5086                         tmp->content = def->content;
5087                         def->content = tmp;
5088                     }
5089                 }
5090
5091                 tmp = xmlRelaxNGNewDefine(ctxt, node);
5092                 if (tmp == NULL)
5093                     return (def);
5094                 tmp->type = XML_RELAXNG_TEXT;
5095                 tmp->next = def->content;
5096                 def->content = tmp;
5097             }
5098         }
5099     } else {
5100         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5101                    "Unexpected node %s is not a pattern\n", node->name,
5102                    NULL);
5103         def = NULL;
5104     }
5105     return (def);
5106 }
5107
5108 /**
5109  * xmlRelaxNGParseAttribute:
5110  * @ctxt:  a Relax-NG parser context
5111  * @node:  the element node
5112  *
5113  * parse the content of a RelaxNG attribute node.
5114  *
5115  * Returns the definition pointer or NULL in case of error.
5116  */
5117 static xmlRelaxNGDefinePtr
5118 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5119 {
5120     xmlRelaxNGDefinePtr ret, cur;
5121     xmlNodePtr child;
5122     int old_flags;
5123
5124     ret = xmlRelaxNGNewDefine(ctxt, node);
5125     if (ret == NULL)
5126         return (NULL);
5127     ret->type = XML_RELAXNG_ATTRIBUTE;
5128     ret->parent = ctxt->def;
5129     child = node->children;
5130     if (child == NULL) {
5131         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5132                    "xmlRelaxNGParseattribute: attribute has no children\n",
5133                    NULL, NULL);
5134         return (ret);
5135     }
5136     old_flags = ctxt->flags;
5137     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
5138     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5139     if (cur != NULL)
5140         child = child->next;
5141
5142     if (child != NULL) {
5143         cur = xmlRelaxNGParsePattern(ctxt, child);
5144         if (cur != NULL) {
5145             switch (cur->type) {
5146                 case XML_RELAXNG_EMPTY:
5147                 case XML_RELAXNG_NOT_ALLOWED:
5148                 case XML_RELAXNG_TEXT:
5149                 case XML_RELAXNG_ELEMENT:
5150                 case XML_RELAXNG_DATATYPE:
5151                 case XML_RELAXNG_VALUE:
5152                 case XML_RELAXNG_LIST:
5153                 case XML_RELAXNG_REF:
5154                 case XML_RELAXNG_PARENTREF:
5155                 case XML_RELAXNG_EXTERNALREF:
5156                 case XML_RELAXNG_DEF:
5157                 case XML_RELAXNG_ONEORMORE:
5158                 case XML_RELAXNG_ZEROORMORE:
5159                 case XML_RELAXNG_OPTIONAL:
5160                 case XML_RELAXNG_CHOICE:
5161                 case XML_RELAXNG_GROUP:
5162                 case XML_RELAXNG_INTERLEAVE:
5163                 case XML_RELAXNG_ATTRIBUTE:
5164                     ret->content = cur;
5165                     cur->parent = ret;
5166                     break;
5167                 case XML_RELAXNG_START:
5168                 case XML_RELAXNG_PARAM:
5169                 case XML_RELAXNG_EXCEPT:
5170                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5171                                "attribute has invalid content\n", NULL,
5172                                NULL);
5173                     break;
5174                 case XML_RELAXNG_NOOP:
5175                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5176                                "RNG Internal error, noop found in attribute\n",
5177                                NULL, NULL);
5178                     break;
5179             }
5180         }
5181         child = child->next;
5182     }
5183     if (child != NULL) {
5184         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5185                    "attribute has multiple children\n", NULL, NULL);
5186     }
5187     ctxt->flags = old_flags;
5188     return (ret);
5189 }
5190
5191 /**
5192  * xmlRelaxNGParseExceptNameClass:
5193  * @ctxt:  a Relax-NG parser context
5194  * @node:  the except node
5195  * @attr:  1 if within an attribute, 0 if within an element
5196  *
5197  * parse the content of a RelaxNG nameClass node.
5198  *
5199  * Returns the definition pointer or NULL in case of error.
5200  */
5201 static xmlRelaxNGDefinePtr
5202 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
5203                                xmlNodePtr node, int attr)
5204 {
5205     xmlRelaxNGDefinePtr ret, cur, last = NULL;
5206     xmlNodePtr child;
5207
5208     if (!IS_RELAXNG(node, "except")) {
5209         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5210                    "Expecting an except node\n", NULL, NULL);
5211         return (NULL);
5212     }
5213     if (node->next != NULL) {
5214         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5215                    "exceptNameClass allows only a single except node\n",
5216                    NULL, NULL);
5217     }
5218     if (node->children == NULL) {
5219         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5220                    NULL, NULL);
5221         return (NULL);
5222     }
5223
5224     ret = xmlRelaxNGNewDefine(ctxt, node);
5225     if (ret == NULL)
5226         return (NULL);
5227     ret->type = XML_RELAXNG_EXCEPT;
5228     child = node->children;
5229     while (child != NULL) {
5230         cur = xmlRelaxNGNewDefine(ctxt, child);
5231         if (cur == NULL)
5232             break;
5233         if (attr)
5234             cur->type = XML_RELAXNG_ATTRIBUTE;
5235         else
5236             cur->type = XML_RELAXNG_ELEMENT;
5237
5238         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5239             if (last == NULL) {
5240                 ret->content = cur;
5241             } else {
5242                 last->next = cur;
5243             }
5244             last = cur;
5245         }
5246         child = child->next;
5247     }
5248
5249     return (ret);
5250 }
5251
5252 /**
5253  * xmlRelaxNGParseNameClass:
5254  * @ctxt:  a Relax-NG parser context
5255  * @node:  the nameClass node
5256  * @def:  the current definition
5257  *
5258  * parse the content of a RelaxNG nameClass node.
5259  *
5260  * Returns the definition pointer or NULL in case of error.
5261  */
5262 static xmlRelaxNGDefinePtr
5263 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5264                          xmlRelaxNGDefinePtr def)
5265 {
5266     xmlRelaxNGDefinePtr ret, tmp;
5267     xmlChar *val;
5268
5269     ret = def;
5270     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5271         (IS_RELAXNG(node, "nsName"))) {
5272         if ((def->type != XML_RELAXNG_ELEMENT) &&
5273             (def->type != XML_RELAXNG_ATTRIBUTE)) {
5274             ret = xmlRelaxNGNewDefine(ctxt, node);
5275             if (ret == NULL)
5276                 return (NULL);
5277             ret->parent = def;
5278             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5279                 ret->type = XML_RELAXNG_ATTRIBUTE;
5280             else
5281                 ret->type = XML_RELAXNG_ELEMENT;
5282         }
5283     }
5284     if (IS_RELAXNG(node, "name")) {
5285         val = xmlNodeGetContent(node);
5286         xmlRelaxNGNormExtSpace(val);
5287         if (xmlValidateNCName(val, 0)) {
5288             if (node->parent != NULL)
5289                 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5290                            "Element %s name '%s' is not an NCName\n",
5291                            node->parent->name, val);
5292             else
5293                 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5294                            "name '%s' is not an NCName\n",
5295                            val, NULL);
5296         }
5297         ret->name = val;
5298         val = xmlGetProp(node, BAD_CAST "ns");
5299         ret->ns = val;
5300         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5301             (val != NULL) &&
5302             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5303             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5304                         "Attribute with namespace '%s' is not allowed\n",
5305                         val, NULL);
5306         }
5307         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5308             (val != NULL) &&
5309             (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5310             xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5311                        "Attribute with QName 'xmlns' is not allowed\n",
5312                        val, NULL);
5313         }
5314     } else if (IS_RELAXNG(node, "anyName")) {
5315         ret->name = NULL;
5316         ret->ns = NULL;
5317         if (node->children != NULL) {
5318             ret->nameClass =
5319                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5320                                                (def->type ==
5321                                                 XML_RELAXNG_ATTRIBUTE));
5322         }
5323     } else if (IS_RELAXNG(node, "nsName")) {
5324         ret->name = NULL;
5325         ret->ns = xmlGetProp(node, BAD_CAST "ns");
5326         if (ret->ns == NULL) {
5327             xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5328                        "nsName has no ns attribute\n", NULL, NULL);
5329         }
5330         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5331             (ret->ns != NULL) &&
5332             (xmlStrEqual
5333              (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5334             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5335                        "Attribute with namespace '%s' is not allowed\n",
5336                        ret->ns, NULL);
5337         }
5338         if (node->children != NULL) {
5339             ret->nameClass =
5340                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5341                                                (def->type ==
5342                                                 XML_RELAXNG_ATTRIBUTE));
5343         }
5344     } else if (IS_RELAXNG(node, "choice")) {
5345         xmlNodePtr child;
5346         xmlRelaxNGDefinePtr last = NULL;
5347
5348         ret = xmlRelaxNGNewDefine(ctxt, node);
5349         if (ret == NULL)
5350             return (NULL);
5351         ret->parent = def;
5352         ret->type = XML_RELAXNG_CHOICE;
5353
5354         if (node->children == NULL) {
5355             xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5356                        "Element choice is empty\n", NULL, NULL);
5357         } else {
5358
5359             child = node->children;
5360             while (child != NULL) {
5361                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5362                 if (tmp != NULL) {
5363                     if (last == NULL) {
5364                         last = ret->nameClass = tmp;
5365                     } else {
5366                         last->next = tmp;
5367                         last = tmp;
5368                     }
5369                 }
5370                 child = child->next;
5371             }
5372         }
5373     } else {
5374         xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5375                    "expecting name, anyName, nsName or choice : got %s\n",
5376                    (node == NULL ? (const xmlChar *) "nothing" : node->name),
5377                    NULL);
5378         return (NULL);
5379     }
5380     if (ret != def) {
5381         if (def->nameClass == NULL) {
5382             def->nameClass = ret;
5383         } else {
5384             tmp = def->nameClass;
5385             while (tmp->next != NULL) {
5386                 tmp = tmp->next;
5387             }
5388             tmp->next = ret;
5389         }
5390     }
5391     return (ret);
5392 }
5393
5394 /**
5395  * xmlRelaxNGParseElement:
5396  * @ctxt:  a Relax-NG parser context
5397  * @node:  the element node
5398  *
5399  * parse the content of a RelaxNG element node.
5400  *
5401  * Returns the definition pointer or NULL in case of error.
5402  */
5403 static xmlRelaxNGDefinePtr
5404 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5405 {
5406     xmlRelaxNGDefinePtr ret, cur, last;
5407     xmlNodePtr child;
5408     const xmlChar *olddefine;
5409
5410     ret = xmlRelaxNGNewDefine(ctxt, node);
5411     if (ret == NULL)
5412         return (NULL);
5413     ret->type = XML_RELAXNG_ELEMENT;
5414     ret->parent = ctxt->def;
5415     child = node->children;
5416     if (child == NULL) {
5417         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5418                    "xmlRelaxNGParseElement: element has no children\n",
5419                    NULL, NULL);
5420         return (ret);
5421     }
5422     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5423     if (cur != NULL)
5424         child = child->next;
5425
5426     if (child == NULL) {
5427         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5428                    "xmlRelaxNGParseElement: element has no content\n",
5429                    NULL, NULL);
5430         return (ret);
5431     }
5432     olddefine = ctxt->define;
5433     ctxt->define = NULL;
5434     last = NULL;
5435     while (child != NULL) {
5436         cur = xmlRelaxNGParsePattern(ctxt, child);
5437         if (cur != NULL) {
5438             cur->parent = ret;
5439             switch (cur->type) {
5440                 case XML_RELAXNG_EMPTY:
5441                 case XML_RELAXNG_NOT_ALLOWED:
5442                 case XML_RELAXNG_TEXT:
5443                 case XML_RELAXNG_ELEMENT:
5444                 case XML_RELAXNG_DATATYPE:
5445                 case XML_RELAXNG_VALUE:
5446                 case XML_RELAXNG_LIST:
5447                 case XML_RELAXNG_REF:
5448                 case XML_RELAXNG_PARENTREF:
5449                 case XML_RELAXNG_EXTERNALREF:
5450                 case XML_RELAXNG_DEF:
5451                 case XML_RELAXNG_ZEROORMORE:
5452                 case XML_RELAXNG_ONEORMORE:
5453                 case XML_RELAXNG_OPTIONAL:
5454                 case XML_RELAXNG_CHOICE:
5455                 case XML_RELAXNG_GROUP:
5456                 case XML_RELAXNG_INTERLEAVE:
5457                     if (last == NULL) {
5458                         ret->content = last = cur;
5459                     } else {
5460                         if ((last->type == XML_RELAXNG_ELEMENT) &&
5461                             (ret->content == last)) {
5462                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
5463                             if (ret->content != NULL) {
5464                                 ret->content->type = XML_RELAXNG_GROUP;
5465                                 ret->content->content = last;
5466                             } else {
5467                                 ret->content = last;
5468                             }
5469                         }
5470                         last->next = cur;
5471                         last = cur;
5472                     }
5473                     break;
5474                 case XML_RELAXNG_ATTRIBUTE:
5475                     cur->next = ret->attrs;
5476                     ret->attrs = cur;
5477                     break;
5478                 case XML_RELAXNG_START:
5479                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5480                                "RNG Internal error, start found in element\n",
5481                                NULL, NULL);
5482                     break;
5483                 case XML_RELAXNG_PARAM:
5484                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5485                                "RNG Internal error, param found in element\n",
5486                                NULL, NULL);
5487                     break;
5488                 case XML_RELAXNG_EXCEPT:
5489                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5490                                "RNG Internal error, except found in element\n",
5491                                NULL, NULL);
5492                     break;
5493                 case XML_RELAXNG_NOOP:
5494                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5495                                "RNG Internal error, noop found in element\n",
5496                                NULL, NULL);
5497                     break;
5498             }
5499         }
5500         child = child->next;
5501     }
5502     ctxt->define = olddefine;
5503     return (ret);
5504 }
5505
5506 /**
5507  * xmlRelaxNGParsePatterns:
5508  * @ctxt:  a Relax-NG parser context
5509  * @nodes:  list of nodes
5510  * @group:  use an implicit <group> for elements
5511  *
5512  * parse the content of a RelaxNG start node.
5513  *
5514  * Returns the definition pointer or NULL in case of error.
5515  */
5516 static xmlRelaxNGDefinePtr
5517 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5518                         int group)
5519 {
5520     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5521
5522     parent = ctxt->def;
5523     while (nodes != NULL) {
5524         if (IS_RELAXNG(nodes, "element")) {
5525             cur = xmlRelaxNGParseElement(ctxt, nodes);
5526             if (def == NULL) {
5527                 def = last = cur;
5528             } else {
5529                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5530                     (def == last)) {
5531                     def = xmlRelaxNGNewDefine(ctxt, nodes);
5532                     def->type = XML_RELAXNG_GROUP;
5533                     def->content = last;
5534                 }
5535                 last->next = cur;
5536                 last = cur;
5537             }
5538             cur->parent = parent;
5539         } else {
5540             cur = xmlRelaxNGParsePattern(ctxt, nodes);
5541             if (cur != NULL) {
5542                 if (def == NULL) {
5543                     def = last = cur;
5544                 } else {
5545                     last->next = cur;
5546                     last = cur;
5547                 }
5548             }
5549         }
5550         nodes = nodes->next;
5551     }
5552     return (def);
5553 }
5554
5555 /**
5556  * xmlRelaxNGParseStart:
5557  * @ctxt:  a Relax-NG parser context
5558  * @nodes:  start children nodes
5559  *
5560  * parse the content of a RelaxNG start node.
5561  *
5562  * Returns 0 in case of success, -1 in case of error
5563  */
5564 static int
5565 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5566 {
5567     int ret = 0;
5568     xmlRelaxNGDefinePtr def = NULL, last;
5569
5570     if (nodes == NULL) {
5571         xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5572                    NULL, NULL);
5573         return (-1);
5574     }
5575     if (IS_RELAXNG(nodes, "empty")) {
5576         def = xmlRelaxNGNewDefine(ctxt, nodes);
5577         if (def == NULL)
5578             return (-1);
5579         def->type = XML_RELAXNG_EMPTY;
5580         if (nodes->children != NULL) {
5581             xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5582                        "element empty is not empty\n", NULL, NULL);
5583         }
5584     } else if (IS_RELAXNG(nodes, "notAllowed")) {
5585         def = xmlRelaxNGNewDefine(ctxt, nodes);
5586         if (def == NULL)
5587             return (-1);
5588         def->type = XML_RELAXNG_NOT_ALLOWED;
5589         if (nodes->children != NULL) {
5590             xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5591                        "element notAllowed is not empty\n", NULL, NULL);
5592         }
5593     } else {
5594         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5595     }
5596     if (ctxt->grammar->start != NULL) {
5597         last = ctxt->grammar->start;
5598         while (last->next != NULL)
5599             last = last->next;
5600         last->next = def;
5601     } else {
5602         ctxt->grammar->start = def;
5603     }
5604     nodes = nodes->next;
5605     if (nodes != NULL) {
5606         xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5607                    "start more than one children\n", NULL, NULL);
5608         return (-1);
5609     }
5610     return (ret);
5611 }
5612
5613 /**
5614  * xmlRelaxNGParseGrammarContent:
5615  * @ctxt:  a Relax-NG parser context
5616  * @nodes:  grammar children nodes
5617  *
5618  * parse the content of a RelaxNG grammar node.
5619  *
5620  * Returns 0 in case of success, -1 in case of error
5621  */
5622 static int
5623 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5624                               xmlNodePtr nodes)
5625 {
5626     int ret = 0, tmp;
5627
5628     if (nodes == NULL) {
5629         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5630                    "grammar has no children\n", NULL, NULL);
5631         return (-1);
5632     }
5633     while (nodes != NULL) {
5634         if (IS_RELAXNG(nodes, "start")) {
5635             if (nodes->children == NULL) {
5636                 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5637                            "start has no children\n", NULL, NULL);
5638             } else {
5639                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5640                 if (tmp != 0)
5641                     ret = -1;
5642             }
5643         } else if (IS_RELAXNG(nodes, "define")) {
5644             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5645             if (tmp != 0)
5646                 ret = -1;
5647         } else if (IS_RELAXNG(nodes, "include")) {
5648             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5649             if (tmp != 0)
5650                 ret = -1;
5651         } else {
5652             xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5653                        "grammar has unexpected child %s\n", nodes->name,
5654                        NULL);
5655             ret = -1;
5656         }
5657         nodes = nodes->next;
5658     }
5659     return (ret);
5660 }
5661
5662 /**
5663  * xmlRelaxNGCheckReference:
5664  * @ref:  the ref
5665  * @ctxt:  a Relax-NG parser context
5666  * @name:  the name associated to the defines
5667  *
5668  * Applies the 4.17. combine attribute rule for all the define
5669  * element of a given grammar using the same name.
5670  */
5671 static void
5672 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5673                          xmlRelaxNGParserCtxtPtr ctxt,
5674                          const xmlChar * name)
5675 {
5676     xmlRelaxNGGrammarPtr grammar;
5677     xmlRelaxNGDefinePtr def, cur;
5678
5679     /*
5680      * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5681      */
5682     if (ref->dflags & IS_EXTERNAL_REF)
5683         return;
5684
5685     grammar = ctxt->grammar;
5686     if (grammar == NULL) {
5687         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5688                    "Internal error: no grammar in CheckReference %s\n",
5689                    name, NULL);
5690         return;
5691     }
5692     if (ref->content != NULL) {
5693         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5694                    "Internal error: reference has content in CheckReference %s\n",
5695                    name, NULL);
5696         return;
5697     }
5698     if (grammar->defs != NULL) {
5699         def = xmlHashLookup(grammar->defs, name);
5700         if (def != NULL) {
5701             cur = ref;
5702             while (cur != NULL) {
5703                 cur->content = def;
5704                 cur = cur->nextHash;
5705             }
5706         } else {
5707             xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5708                        "Reference %s has no matching definition\n", name,
5709                        NULL);
5710         }
5711     } else {
5712         xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5713                    "Reference %s has no matching definition\n", name,
5714                    NULL);
5715     }
5716 }
5717
5718 /**
5719  * xmlRelaxNGCheckCombine:
5720  * @define:  the define(s) list
5721  * @ctxt:  a Relax-NG parser context
5722  * @name:  the name associated to the defines
5723  *
5724  * Applies the 4.17. combine attribute rule for all the define
5725  * element of a given grammar using the same name.
5726  */
5727 static void
5728 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5729                        xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5730 {
5731     xmlChar *combine;
5732     int choiceOrInterleave = -1;
5733     int missing = 0;
5734     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5735
5736     if (define->nextHash == NULL)
5737         return;
5738     cur = define;
5739     while (cur != NULL) {
5740         combine = xmlGetProp(cur->node, BAD_CAST "combine");
5741         if (combine != NULL) {
5742             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5743                 if (choiceOrInterleave == -1)
5744                     choiceOrInterleave = 1;
5745                 else if (choiceOrInterleave == 0) {
5746                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5747                                "Defines for %s use both 'choice' and 'interleave'\n",
5748                                name, NULL);
5749                 }
5750             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5751                 if (choiceOrInterleave == -1)
5752                     choiceOrInterleave = 0;
5753                 else if (choiceOrInterleave == 1) {
5754                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5755                                "Defines for %s use both 'choice' and 'interleave'\n",
5756                                name, NULL);
5757                 }
5758             } else {
5759                 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5760                            "Defines for %s use unknown combine value '%s''\n",
5761                            name, combine);
5762             }
5763             xmlFree(combine);
5764         } else {
5765             if (missing == 0)
5766                 missing = 1;
5767             else {
5768                 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5769                            "Some defines for %s needs the combine attribute\n",
5770                            name, NULL);
5771             }
5772         }
5773
5774         cur = cur->nextHash;
5775     }
5776 #ifdef DEBUG
5777     xmlGenericError(xmlGenericErrorContext,
5778                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5779                     name, choiceOrInterleave);
5780 #endif
5781     if (choiceOrInterleave == -1)
5782         choiceOrInterleave = 0;
5783     cur = xmlRelaxNGNewDefine(ctxt, define->node);
5784     if (cur == NULL)
5785         return;
5786     if (choiceOrInterleave == 0)
5787         cur->type = XML_RELAXNG_INTERLEAVE;
5788     else
5789         cur->type = XML_RELAXNG_CHOICE;
5790     tmp = define;
5791     last = NULL;
5792     while (tmp != NULL) {
5793         if (tmp->content != NULL) {
5794             if (tmp->content->next != NULL) {
5795                 /*
5796                  * we need first to create a wrapper.
5797                  */
5798                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5799                 if (tmp2 == NULL)
5800                     break;
5801                 tmp2->type = XML_RELAXNG_GROUP;
5802                 tmp2->content = tmp->content;
5803             } else {
5804                 tmp2 = tmp->content;
5805             }
5806             if (last == NULL) {
5807                 cur->content = tmp2;
5808             } else {
5809                 last->next = tmp2;
5810             }
5811             last = tmp2;
5812         }
5813         tmp->content = cur;
5814         tmp = tmp->nextHash;
5815     }
5816     define->content = cur;
5817     if (choiceOrInterleave == 0) {
5818         if (ctxt->interleaves == NULL)
5819             ctxt->interleaves = xmlHashCreate(10);
5820         if (ctxt->interleaves == NULL) {
5821             xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5822                        "Failed to create interleaves hash table\n", NULL,
5823                        NULL);
5824         } else {
5825             char tmpname[32];
5826
5827             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5828             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5829                 0) {
5830                 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5831                            "Failed to add %s to hash table\n",
5832                            (const xmlChar *) tmpname, NULL);
5833             }
5834         }
5835     }
5836 }
5837
5838 /**
5839  * xmlRelaxNGCombineStart:
5840  * @ctxt:  a Relax-NG parser context
5841  * @grammar:  the grammar
5842  *
5843  * Applies the 4.17. combine rule for all the start
5844  * element of a given grammar.
5845  */
5846 static void
5847 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5848                        xmlRelaxNGGrammarPtr grammar)
5849 {
5850     xmlRelaxNGDefinePtr starts;
5851     xmlChar *combine;
5852     int choiceOrInterleave = -1;
5853     int missing = 0;
5854     xmlRelaxNGDefinePtr cur;
5855
5856     starts = grammar->start;
5857     if ((starts == NULL) || (starts->next == NULL))
5858         return;
5859     cur = starts;
5860     while (cur != NULL) {
5861         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5862             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5863             combine = NULL;
5864             xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5865                        "Internal error: start element not found\n", NULL,
5866                        NULL);
5867         } else {
5868             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5869         }
5870
5871         if (combine != NULL) {
5872             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5873                 if (choiceOrInterleave == -1)
5874                     choiceOrInterleave = 1;
5875                 else if (choiceOrInterleave == 0) {
5876                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5877                                "<start> use both 'choice' and 'interleave'\n",
5878                                NULL, NULL);
5879                 }
5880             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5881                 if (choiceOrInterleave == -1)
5882                     choiceOrInterleave = 0;
5883                 else if (choiceOrInterleave == 1) {
5884                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5885                                "<start> use both 'choice' and 'interleave'\n",
5886                                NULL, NULL);
5887                 }
5888             } else {
5889                 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5890                            "<start> uses unknown combine value '%s''\n",
5891                            combine, NULL);
5892             }
5893             xmlFree(combine);
5894         } else {
5895             if (missing == 0)
5896                 missing = 1;
5897             else {
5898                 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5899                            "Some <start> element miss the combine attribute\n",
5900                            NULL, NULL);
5901             }
5902         }
5903
5904         cur = cur->next;
5905     }
5906 #ifdef DEBUG
5907     xmlGenericError(xmlGenericErrorContext,
5908                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5909                     choiceOrInterleave);
5910 #endif
5911     if (choiceOrInterleave == -1)
5912         choiceOrInterleave = 0;
5913     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5914     if (cur == NULL)
5915         return;
5916     if (choiceOrInterleave == 0)
5917         cur->type = XML_RELAXNG_INTERLEAVE;
5918     else
5919         cur->type = XML_RELAXNG_CHOICE;
5920     cur->content = grammar->start;
5921     grammar->start = cur;
5922     if (choiceOrInterleave == 0) {
5923         if (ctxt->interleaves == NULL)
5924             ctxt->interleaves = xmlHashCreate(10);
5925         if (ctxt->interleaves == NULL) {
5926             xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5927                        "Failed to create interleaves hash table\n", NULL,
5928                        NULL);
5929         } else {
5930             char tmpname[32];
5931
5932             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5933             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5934                 0) {
5935                 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5936                            "Failed to add %s to hash table\n",
5937                            (const xmlChar *) tmpname, NULL);
5938             }
5939         }
5940     }
5941 }
5942
5943 /**
5944  * xmlRelaxNGCheckCycles:
5945  * @ctxt:  a Relax-NG parser context
5946  * @nodes:  grammar children nodes
5947  * @depth:  the counter
5948  *
5949  * Check for cycles.
5950  *
5951  * Returns 0 if check passed, and -1 in case of error
5952  */
5953 static int
5954 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5955                       xmlRelaxNGDefinePtr cur, int depth)
5956 {
5957     int ret = 0;
5958
5959     while ((ret == 0) && (cur != NULL)) {
5960         if ((cur->type == XML_RELAXNG_REF) ||
5961             (cur->type == XML_RELAXNG_PARENTREF)) {
5962             if (cur->depth == -1) {
5963                 cur->depth = depth;
5964                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5965                 cur->depth = -2;
5966             } else if (depth == cur->depth) {
5967                 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5968                            "Detected a cycle in %s references\n",
5969                            cur->name, NULL);
5970                 return (-1);
5971             }
5972         } else if (cur->type == XML_RELAXNG_ELEMENT) {
5973             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5974         } else {
5975             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5976         }
5977         cur = cur->next;
5978     }
5979     return (ret);
5980 }
5981
5982 /**
5983  * xmlRelaxNGTryUnlink:
5984  * @ctxt:  a Relax-NG parser context
5985  * @cur:  the definition to unlink
5986  * @parent:  the parent definition
5987  * @prev:  the previous sibling definition
5988  *
5989  * Try to unlink a definition. If not possble make it a NOOP
5990  *
5991  * Returns the new prev definition
5992  */
5993 static xmlRelaxNGDefinePtr
5994 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5995                     xmlRelaxNGDefinePtr cur,
5996                     xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5997 {
5998     if (prev != NULL) {
5999         prev->next = cur->next;
6000     } else {
6001         if (parent != NULL) {
6002             if (parent->content == cur)
6003                 parent->content = cur->next;
6004             else if (parent->attrs == cur)
6005                 parent->attrs = cur->next;
6006             else if (parent->nameClass == cur)
6007                 parent->nameClass = cur->next;
6008         } else {
6009             cur->type = XML_RELAXNG_NOOP;
6010             prev = cur;
6011         }
6012     }
6013     return (prev);
6014 }
6015
6016 /**
6017  * xmlRelaxNGSimplify:
6018  * @ctxt:  a Relax-NG parser context
6019  * @nodes:  grammar children nodes
6020  *
6021  * Check for simplification of empty and notAllowed
6022  */
6023 static void
6024 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
6025                    xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
6026 {
6027     xmlRelaxNGDefinePtr prev = NULL;
6028
6029     while (cur != NULL) {
6030         if ((cur->type == XML_RELAXNG_REF) ||
6031             (cur->type == XML_RELAXNG_PARENTREF)) {
6032             if (cur->depth != -3) {
6033                 cur->depth = -3;
6034                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6035             }
6036         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6037             cur->parent = parent;
6038             if ((parent != NULL) &&
6039                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6040                  (parent->type == XML_RELAXNG_LIST) ||
6041                  (parent->type == XML_RELAXNG_GROUP) ||
6042                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
6043                  (parent->type == XML_RELAXNG_ONEORMORE) ||
6044                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6045                 parent->type = XML_RELAXNG_NOT_ALLOWED;
6046                 break;
6047             }
6048             if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
6049                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6050             } else
6051                 prev = cur;
6052         } else if (cur->type == XML_RELAXNG_EMPTY) {
6053             cur->parent = parent;
6054             if ((parent != NULL) &&
6055                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6056                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6057                 parent->type = XML_RELAXNG_EMPTY;
6058                 break;
6059             }
6060             if ((parent != NULL) &&
6061                 ((parent->type == XML_RELAXNG_GROUP) ||
6062                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
6063                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6064             } else
6065                 prev = cur;
6066         } else {
6067             cur->parent = parent;
6068             if (cur->content != NULL)
6069                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6070             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
6071                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
6072             if (cur->nameClass != NULL)
6073                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
6074             /*
6075              * On Elements, try to move attribute only generating rules on
6076              * the attrs rules.
6077              */
6078             if (cur->type == XML_RELAXNG_ELEMENT) {
6079                 int attronly;
6080                 xmlRelaxNGDefinePtr tmp, pre;
6081
6082                 while (cur->content != NULL) {
6083                     attronly =
6084                         xmlRelaxNGGenerateAttributes(ctxt, cur->content);
6085                     if (attronly == 1) {
6086                         /*
6087                          * migrate cur->content to attrs
6088                          */
6089                         tmp = cur->content;
6090                         cur->content = tmp->next;
6091                         tmp->next = cur->attrs;
6092                         cur->attrs = tmp;
6093                     } else {
6094                         /*
6095                          * cur->content can generate elements or text
6096                          */
6097                         break;
6098                     }
6099                 }
6100                 pre = cur->content;
6101                 while ((pre != NULL) && (pre->next != NULL)) {
6102                     tmp = pre->next;
6103                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6104                     if (attronly == 1) {
6105                         /*
6106                          * migrate tmp to attrs
6107                          */
6108                         pre->next = tmp->next;
6109                         tmp->next = cur->attrs;
6110                         cur->attrs = tmp;
6111                     } else {
6112                         pre = tmp;
6113                     }
6114                 }
6115             }
6116             /*
6117              * This may result in a simplification
6118              */
6119             if ((cur->type == XML_RELAXNG_GROUP) ||
6120                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6121                 if (cur->content == NULL)
6122                     cur->type = XML_RELAXNG_EMPTY;
6123                 else if (cur->content->next == NULL) {
6124                     if ((parent == NULL) && (prev == NULL)) {
6125                         cur->type = XML_RELAXNG_NOOP;
6126                     } else if (prev == NULL) {
6127                         parent->content = cur->content;
6128                         cur->content->next = cur->next;
6129                         cur = cur->content;
6130                     } else {
6131                         cur->content->next = cur->next;
6132                         prev->next = cur->content;
6133                         cur = cur->content;
6134                     }
6135                 }
6136             }
6137             /*
6138              * the current node may have been transformed back
6139              */
6140             if ((cur->type == XML_RELAXNG_EXCEPT) &&
6141                 (cur->content != NULL) &&
6142                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6143                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6144             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6145                 if ((parent != NULL) &&
6146                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6147                      (parent->type == XML_RELAXNG_LIST) ||
6148                      (parent->type == XML_RELAXNG_GROUP) ||
6149                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6150                      (parent->type == XML_RELAXNG_ONEORMORE) ||
6151                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6152                     parent->type = XML_RELAXNG_NOT_ALLOWED;
6153                     break;
6154                 }
6155                 if ((parent != NULL) &&
6156                     (parent->type == XML_RELAXNG_CHOICE)) {
6157                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6158                 } else
6159                     prev = cur;
6160             } else if (cur->type == XML_RELAXNG_EMPTY) {
6161                 if ((parent != NULL) &&
6162                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
6163                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6164                     parent->type = XML_RELAXNG_EMPTY;
6165                     break;
6166                 }
6167                 if ((parent != NULL) &&
6168                     ((parent->type == XML_RELAXNG_GROUP) ||
6169                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6170                      (parent->type == XML_RELAXNG_CHOICE))) {
6171                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6172                 } else
6173                     prev = cur;
6174             } else {
6175                 prev = cur;
6176             }
6177         }
6178         cur = cur->next;
6179     }
6180 }
6181
6182 /**
6183  * xmlRelaxNGGroupContentType:
6184  * @ct1:  the first content type
6185  * @ct2:  the second content type
6186  *
6187  * Try to group 2 content types
6188  *
6189  * Returns the content type
6190  */
6191 static xmlRelaxNGContentType
6192 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6193                            xmlRelaxNGContentType ct2)
6194 {
6195     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6196         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6197         return (XML_RELAXNG_CONTENT_ERROR);
6198     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6199         return (ct2);
6200     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6201         return (ct1);
6202     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6203         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6204         return (XML_RELAXNG_CONTENT_COMPLEX);
6205     return (XML_RELAXNG_CONTENT_ERROR);
6206 }
6207
6208 /**
6209  * xmlRelaxNGMaxContentType:
6210  * @ct1:  the first content type
6211  * @ct2:  the second content type
6212  *
6213  * Compute the max content-type
6214  *
6215  * Returns the content type
6216  */
6217 static xmlRelaxNGContentType
6218 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6219                          xmlRelaxNGContentType ct2)
6220 {
6221     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6222         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6223         return (XML_RELAXNG_CONTENT_ERROR);
6224     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6225         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6226         return (XML_RELAXNG_CONTENT_SIMPLE);
6227     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6228         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6229         return (XML_RELAXNG_CONTENT_COMPLEX);
6230     return (XML_RELAXNG_CONTENT_EMPTY);
6231 }
6232
6233 /**
6234  * xmlRelaxNGCheckRules:
6235  * @ctxt:  a Relax-NG parser context
6236  * @cur:  the current definition
6237  * @flags:  some accumulated flags
6238  * @ptype:  the parent type
6239  *
6240  * Check for rules in section 7.1 and 7.2
6241  *
6242  * Returns the content type of @cur
6243  */
6244 static xmlRelaxNGContentType
6245 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6246                      xmlRelaxNGDefinePtr cur, int flags,
6247                      xmlRelaxNGType ptype)
6248 {
6249     int nflags;
6250     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6251
6252     while (cur != NULL) {
6253         ret = XML_RELAXNG_CONTENT_EMPTY;
6254         if ((cur->type == XML_RELAXNG_REF) ||
6255             (cur->type == XML_RELAXNG_PARENTREF)) {
6256            /*
6257             * This should actually be caught by list//element(ref) at the
6258             * element boundaries, c.f. Bug #159968 local refs are dropped
6259             * in step 4.19.
6260             */
6261 #if 0
6262             if (flags & XML_RELAXNG_IN_LIST) {
6263                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6264                            "Found forbidden pattern list//ref\n", NULL,
6265                            NULL);
6266             }
6267 #endif
6268             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6269                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6270                            "Found forbidden pattern data/except//ref\n",
6271                            NULL, NULL);
6272             }
6273             if (cur->content == NULL) {
6274                 if (cur->type == XML_RELAXNG_PARENTREF)
6275                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6276                                "Internal found no define for parent refs\n",
6277                                NULL, NULL);
6278                 else
6279                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6280                                "Internal found no define for ref %s\n",
6281                                (cur->name ? cur->name: BAD_CAST "null"), NULL);
6282             }
6283             if (cur->depth > -4) {
6284                 cur->depth = -4;
6285                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6286                                            flags, cur->type);
6287                 cur->depth = ret - 15;
6288             } else if (cur->depth == -4) {
6289                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6290             } else {
6291                 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6292             }
6293         } else if (cur->type == XML_RELAXNG_ELEMENT) {
6294             /*
6295              * The 7.3 Attribute derivation rule for groups is plugged there
6296              */
6297             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6298             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6299                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6300                            "Found forbidden pattern data/except//element(ref)\n",
6301                            NULL, NULL);
6302             }
6303             if (flags & XML_RELAXNG_IN_LIST) {
6304                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6305                            "Found forbidden pattern list//element(ref)\n",
6306                            NULL, NULL);
6307             }
6308             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6309                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6310                            "Found forbidden pattern attribute//element(ref)\n",
6311                            NULL, NULL);
6312             }
6313             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6314                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6315                            "Found forbidden pattern attribute//element(ref)\n",
6316                            NULL, NULL);
6317             }
6318             /*
6319              * reset since in the simple form elements are only child
6320              * of grammar/define
6321              */
6322             nflags = 0;
6323             ret =
6324                 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6325             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6326                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6327                            "Element %s attributes have a content type error\n",
6328                            cur->name, NULL);
6329             }
6330             ret =
6331                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6332                                      cur->type);
6333             if (ret == XML_RELAXNG_CONTENT_ERROR) {
6334                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6335                            "Element %s has a content type error\n",
6336                            cur->name, NULL);
6337             } else {
6338                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6339             }
6340         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6341             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6342                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6343                            "Found forbidden pattern attribute//attribute\n",
6344                            NULL, NULL);
6345             }
6346             if (flags & XML_RELAXNG_IN_LIST) {
6347                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6348                            "Found forbidden pattern list//attribute\n",
6349                            NULL, NULL);
6350             }
6351             if (flags & XML_RELAXNG_IN_OOMGROUP) {
6352                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6353                            "Found forbidden pattern oneOrMore//group//attribute\n",
6354                            NULL, NULL);
6355             }
6356             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6357                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6358                            "Found forbidden pattern oneOrMore//interleave//attribute\n",
6359                            NULL, NULL);
6360             }
6361             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6362                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6363                            "Found forbidden pattern data/except//attribute\n",
6364                            NULL, NULL);
6365             }
6366             if (flags & XML_RELAXNG_IN_START) {
6367                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6368                            "Found forbidden pattern start//attribute\n",
6369                            NULL, NULL);
6370             }
6371             if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6372                 && (cur->name == NULL)) {
6373                 if (cur->ns == NULL) {
6374                     xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6375                                "Found anyName attribute without oneOrMore ancestor\n",
6376                                NULL, NULL);
6377                 } else {
6378                     xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6379                                "Found nsName attribute without oneOrMore ancestor\n",
6380                                NULL, NULL);
6381                 }
6382             }
6383             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6384             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6385             ret = XML_RELAXNG_CONTENT_EMPTY;
6386         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6387                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
6388             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6389                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6390                            "Found forbidden pattern data/except//oneOrMore\n",
6391                            NULL, NULL);
6392             }
6393             if (flags & XML_RELAXNG_IN_START) {
6394                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6395                            "Found forbidden pattern start//oneOrMore\n",
6396                            NULL, NULL);
6397             }
6398             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6399             ret =
6400                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6401                                      cur->type);
6402             ret = xmlRelaxNGGroupContentType(ret, ret);
6403         } else if (cur->type == XML_RELAXNG_LIST) {
6404             if (flags & XML_RELAXNG_IN_LIST) {
6405                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6406                            "Found forbidden pattern list//list\n", NULL,
6407                            NULL);
6408             }
6409             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6410                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6411                            "Found forbidden pattern data/except//list\n",
6412                            NULL, NULL);
6413             }
6414             if (flags & XML_RELAXNG_IN_START) {
6415                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6416                            "Found forbidden pattern start//list\n", NULL,
6417                            NULL);
6418             }
6419             nflags = flags | XML_RELAXNG_IN_LIST;
6420             ret =
6421                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6422                                      cur->type);
6423         } else if (cur->type == XML_RELAXNG_GROUP) {
6424             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6425                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6426                            "Found forbidden pattern data/except//group\n",
6427                            NULL, NULL);
6428             }
6429             if (flags & XML_RELAXNG_IN_START) {
6430                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6431                            "Found forbidden pattern start//group\n", NULL,
6432                            NULL);
6433             }
6434             if (flags & XML_RELAXNG_IN_ONEORMORE)
6435                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6436             else
6437                 nflags = flags;
6438             ret =
6439                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6440                                      cur->type);
6441             /*
6442              * The 7.3 Attribute derivation rule for groups is plugged there
6443              */
6444             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6445         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6446             if (flags & XML_RELAXNG_IN_LIST) {
6447                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6448                            "Found forbidden pattern list//interleave\n",
6449                            NULL, NULL);
6450             }
6451             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6452                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6453                            "Found forbidden pattern data/except//interleave\n",
6454                            NULL, NULL);
6455             }
6456             if (flags & XML_RELAXNG_IN_START) {
6457                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6458                            "Found forbidden pattern start//interleave\n",
6459                            NULL, NULL);
6460             }
6461             if (flags & XML_RELAXNG_IN_ONEORMORE)
6462                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6463             else
6464                 nflags = flags;
6465             ret =
6466                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6467                                      cur->type);
6468         } else if (cur->type == XML_RELAXNG_EXCEPT) {
6469             if ((cur->parent != NULL) &&
6470                 (cur->parent->type == XML_RELAXNG_DATATYPE))
6471                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6472             else
6473                 nflags = flags;
6474             ret =
6475                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6476                                      cur->type);
6477         } else if (cur->type == XML_RELAXNG_DATATYPE) {
6478             if (flags & XML_RELAXNG_IN_START) {
6479                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6480                            "Found forbidden pattern start//data\n", NULL,
6481                            NULL);
6482             }
6483             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6484             ret = XML_RELAXNG_CONTENT_SIMPLE;
6485         } else if (cur->type == XML_RELAXNG_VALUE) {
6486             if (flags & XML_RELAXNG_IN_START) {
6487                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6488                            "Found forbidden pattern start//value\n", NULL,
6489                            NULL);
6490             }
6491             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6492             ret = XML_RELAXNG_CONTENT_SIMPLE;
6493         } else if (cur->type == XML_RELAXNG_TEXT) {
6494             if (flags & XML_RELAXNG_IN_LIST) {
6495                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6496                            "Found forbidden pattern list//text\n", NULL,
6497                            NULL);
6498             }
6499             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6500                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6501                            "Found forbidden pattern data/except//text\n",
6502                            NULL, NULL);
6503             }
6504             if (flags & XML_RELAXNG_IN_START) {
6505                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6506                            "Found forbidden pattern start//text\n", NULL,
6507                            NULL);
6508             }
6509             ret = XML_RELAXNG_CONTENT_COMPLEX;
6510         } else if (cur->type == XML_RELAXNG_EMPTY) {
6511             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6512                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6513                            "Found forbidden pattern data/except//empty\n",
6514                            NULL, NULL);
6515             }
6516             if (flags & XML_RELAXNG_IN_START) {
6517                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6518                            "Found forbidden pattern start//empty\n", NULL,
6519                            NULL);
6520             }
6521             ret = XML_RELAXNG_CONTENT_EMPTY;
6522         } else if (cur->type == XML_RELAXNG_CHOICE) {
6523             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6524             ret =
6525                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6526         } else {
6527             ret =
6528                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6529         }
6530         cur = cur->next;
6531         if (ptype == XML_RELAXNG_GROUP) {
6532             val = xmlRelaxNGGroupContentType(val, ret);
6533         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6534             /*
6535              * TODO: scan complain that tmp is never used, seems on purpose
6536              *       need double-checking
6537              */
6538             tmp = xmlRelaxNGGroupContentType(val, ret);
6539             if (tmp != XML_RELAXNG_CONTENT_ERROR)
6540                 tmp = xmlRelaxNGMaxContentType(val, ret);
6541         } else if (ptype == XML_RELAXNG_CHOICE) {
6542             val = xmlRelaxNGMaxContentType(val, ret);
6543         } else if (ptype == XML_RELAXNG_LIST) {
6544             val = XML_RELAXNG_CONTENT_SIMPLE;
6545         } else if (ptype == XML_RELAXNG_EXCEPT) {
6546             if (ret == XML_RELAXNG_CONTENT_ERROR)
6547                 val = XML_RELAXNG_CONTENT_ERROR;
6548             else
6549                 val = XML_RELAXNG_CONTENT_SIMPLE;
6550         } else {
6551             val = xmlRelaxNGGroupContentType(val, ret);
6552         }
6553
6554     }
6555     return (val);
6556 }
6557
6558 /**
6559  * xmlRelaxNGParseGrammar:
6560  * @ctxt:  a Relax-NG parser context
6561  * @nodes:  grammar children nodes
6562  *
6563  * parse a Relax-NG <grammar> node
6564  *
6565  * Returns the internal xmlRelaxNGGrammarPtr built or
6566  *         NULL in case of error
6567  */
6568 static xmlRelaxNGGrammarPtr
6569 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6570 {
6571     xmlRelaxNGGrammarPtr ret, tmp, old;
6572
6573 #ifdef DEBUG_GRAMMAR
6574     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6575 #endif
6576
6577     ret = xmlRelaxNGNewGrammar(ctxt);
6578     if (ret == NULL)
6579         return (NULL);
6580
6581     /*
6582      * Link the new grammar in the tree
6583      */
6584     ret->parent = ctxt->grammar;
6585     if (ctxt->grammar != NULL) {
6586         tmp = ctxt->grammar->children;
6587         if (tmp == NULL) {
6588             ctxt->grammar->children = ret;
6589         } else {
6590             while (tmp->next != NULL)
6591                 tmp = tmp->next;
6592             tmp->next = ret;
6593         }
6594     }
6595
6596     old = ctxt->grammar;
6597     ctxt->grammar = ret;
6598     xmlRelaxNGParseGrammarContent(ctxt, nodes);
6599     ctxt->grammar = ret;
6600     if (ctxt->grammar == NULL) {
6601         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6602                    "Failed to parse <grammar> content\n", NULL, NULL);
6603     } else if (ctxt->grammar->start == NULL) {
6604         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6605                    "Element <grammar> has no <start>\n", NULL, NULL);
6606     }
6607
6608     /*
6609      * Apply 4.17 merging rules to defines and starts
6610      */
6611     xmlRelaxNGCombineStart(ctxt, ret);
6612     if (ret->defs != NULL) {
6613         xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6614                     ctxt);
6615     }
6616
6617     /*
6618      * link together defines and refs in this grammar
6619      */
6620     if (ret->refs != NULL) {
6621         xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6622                     ctxt);
6623     }
6624
6625
6626     /* @@@@ */
6627
6628     ctxt->grammar = old;
6629     return (ret);
6630 }
6631
6632 /**
6633  * xmlRelaxNGParseDocument:
6634  * @ctxt:  a Relax-NG parser context
6635  * @node:  the root node of the RelaxNG schema
6636  *
6637  * parse a Relax-NG definition resource and build an internal
6638  * xmlRelaxNG struture which can be used to validate instances.
6639  *
6640  * Returns the internal XML RelaxNG structure built or
6641  *         NULL in case of error
6642  */
6643 static xmlRelaxNGPtr
6644 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6645 {
6646     xmlRelaxNGPtr schema = NULL;
6647     const xmlChar *olddefine;
6648     xmlRelaxNGGrammarPtr old;
6649
6650     if ((ctxt == NULL) || (node == NULL))
6651         return (NULL);
6652
6653     schema = xmlRelaxNGNewRelaxNG(ctxt);
6654     if (schema == NULL)
6655         return (NULL);
6656
6657     olddefine = ctxt->define;
6658     ctxt->define = NULL;
6659     if (IS_RELAXNG(node, "grammar")) {
6660         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6661         if (schema->topgrammar == NULL) {
6662             xmlRelaxNGFree(schema);
6663             return (NULL);
6664         }
6665     } else {
6666         xmlRelaxNGGrammarPtr tmp, ret;
6667
6668         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6669         if (schema->topgrammar == NULL) {
6670             xmlRelaxNGFree(schema);
6671             return (NULL);
6672         }
6673         /*
6674          * Link the new grammar in the tree
6675          */
6676         ret->parent = ctxt->grammar;
6677         if (ctxt->grammar != NULL) {
6678             tmp = ctxt->grammar->children;
6679             if (tmp == NULL) {
6680                 ctxt->grammar->children = ret;
6681             } else {
6682                 while (tmp->next != NULL)
6683                     tmp = tmp->next;
6684                 tmp->next = ret;
6685             }
6686         }
6687         old = ctxt->grammar;
6688         ctxt->grammar = ret;
6689         xmlRelaxNGParseStart(ctxt, node);
6690         if (old != NULL)
6691             ctxt->grammar = old;
6692     }
6693     ctxt->define = olddefine;
6694     if (schema->topgrammar->start != NULL) {
6695         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6696         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6697             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6698             while ((schema->topgrammar->start != NULL) &&
6699                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6700                    (schema->topgrammar->start->next != NULL))
6701                 schema->topgrammar->start =
6702                     schema->topgrammar->start->content;
6703             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6704                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6705         }
6706     }
6707 #ifdef DEBUG
6708     if (schema == NULL)
6709         xmlGenericError(xmlGenericErrorContext,
6710                         "xmlRelaxNGParseDocument() failed\n");
6711 #endif
6712
6713     return (schema);
6714 }
6715
6716 /************************************************************************
6717  *                                                                      *
6718  *                      Reading RelaxNGs                                *
6719  *                                                                      *
6720  ************************************************************************/
6721
6722 /**
6723  * xmlRelaxNGNewParserCtxt:
6724  * @URL:  the location of the schema
6725  *
6726  * Create an XML RelaxNGs parse context for that file/resource expected
6727  * to contain an XML RelaxNGs file.
6728  *
6729  * Returns the parser context or NULL in case of error
6730  */
6731 xmlRelaxNGParserCtxtPtr
6732 xmlRelaxNGNewParserCtxt(const char *URL)
6733 {
6734     xmlRelaxNGParserCtxtPtr ret;
6735
6736     if (URL == NULL)
6737         return (NULL);
6738
6739     ret =
6740         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6741     if (ret == NULL) {
6742         xmlRngPErrMemory(NULL, "building parser\n");
6743         return (NULL);
6744     }
6745     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6746     ret->URL = xmlStrdup((const xmlChar *) URL);
6747     ret->error = xmlGenericError;
6748     ret->userData = xmlGenericErrorContext;
6749     return (ret);
6750 }
6751
6752 /**
6753  * xmlRelaxNGNewMemParserCtxt:
6754  * @buffer:  a pointer to a char array containing the schemas
6755  * @size:  the size of the array
6756  *
6757  * Create an XML RelaxNGs parse context for that memory buffer expected
6758  * to contain an XML RelaxNGs file.
6759  *
6760  * Returns the parser context or NULL in case of error
6761  */
6762 xmlRelaxNGParserCtxtPtr
6763 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6764 {
6765     xmlRelaxNGParserCtxtPtr ret;
6766
6767     if ((buffer == NULL) || (size <= 0))
6768         return (NULL);
6769
6770     ret =
6771         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6772     if (ret == NULL) {
6773         xmlRngPErrMemory(NULL, "building parser\n");
6774         return (NULL);
6775     }
6776     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6777     ret->buffer = buffer;
6778     ret->size = size;
6779     ret->error = xmlGenericError;
6780     ret->userData = xmlGenericErrorContext;
6781     return (ret);
6782 }
6783
6784 /**
6785  * xmlRelaxNGNewDocParserCtxt:
6786  * @doc:  a preparsed document tree
6787  *
6788  * Create an XML RelaxNGs parser context for that document.
6789  * Note: since the process of compiling a RelaxNG schemas modifies the
6790  *       document, the @doc parameter is duplicated internally.
6791  *
6792  * Returns the parser context or NULL in case of error
6793  */
6794 xmlRelaxNGParserCtxtPtr
6795 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6796 {
6797     xmlRelaxNGParserCtxtPtr ret;
6798     xmlDocPtr copy;
6799
6800     if (doc == NULL)
6801         return (NULL);
6802     copy = xmlCopyDoc(doc, 1);
6803     if (copy == NULL)
6804         return (NULL);
6805
6806     ret =
6807         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6808     if (ret == NULL) {
6809         xmlRngPErrMemory(NULL, "building parser\n");
6810         return (NULL);
6811     }
6812     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6813     ret->document = copy;
6814     ret->freedoc = 1;
6815     ret->userData = xmlGenericErrorContext;
6816     return (ret);
6817 }
6818
6819 /**
6820  * xmlRelaxNGFreeParserCtxt:
6821  * @ctxt:  the schema parser context
6822  *
6823  * Free the resources associated to the schema parser context
6824  */
6825 void
6826 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6827 {
6828     if (ctxt == NULL)
6829         return;
6830     if (ctxt->URL != NULL)
6831         xmlFree(ctxt->URL);
6832     if (ctxt->doc != NULL)
6833         xmlRelaxNGFreeDocument(ctxt->doc);
6834     if (ctxt->interleaves != NULL)
6835         xmlHashFree(ctxt->interleaves, NULL);
6836     if (ctxt->documents != NULL)
6837         xmlRelaxNGFreeDocumentList(ctxt->documents);
6838     if (ctxt->includes != NULL)
6839         xmlRelaxNGFreeIncludeList(ctxt->includes);
6840     if (ctxt->docTab != NULL)
6841         xmlFree(ctxt->docTab);
6842     if (ctxt->incTab != NULL)
6843         xmlFree(ctxt->incTab);
6844     if (ctxt->defTab != NULL) {
6845         int i;
6846
6847         for (i = 0; i < ctxt->defNr; i++)
6848             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6849         xmlFree(ctxt->defTab);
6850     }
6851     if ((ctxt->document != NULL) && (ctxt->freedoc))
6852         xmlFreeDoc(ctxt->document);
6853     xmlFree(ctxt);
6854 }
6855
6856 /**
6857  * xmlRelaxNGNormExtSpace:
6858  * @value:  a value
6859  *
6860  * Removes the leading and ending spaces of the value
6861  * The string is modified "in situ"
6862  */
6863 static void
6864 xmlRelaxNGNormExtSpace(xmlChar * value)
6865 {
6866     xmlChar *start = value;
6867     xmlChar *cur = value;
6868
6869     if (value == NULL)
6870         return;
6871
6872     while (IS_BLANK_CH(*cur))
6873         cur++;
6874     if (cur == start) {
6875         do {
6876             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6877                 cur++;
6878             if (*cur == 0)
6879                 return;
6880             start = cur;
6881             while (IS_BLANK_CH(*cur))
6882                 cur++;
6883             if (*cur == 0) {
6884                 *start = 0;
6885                 return;
6886             }
6887         } while (1);
6888     } else {
6889         do {
6890             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6891                 *start++ = *cur++;
6892             if (*cur == 0) {
6893                 *start = 0;
6894                 return;
6895             }
6896             /* don't try to normalize the inner spaces */
6897             while (IS_BLANK_CH(*cur))
6898                 cur++;
6899             if (*cur == 0) {
6900                 *start = 0;
6901                 return;
6902             }
6903             *start++ = *cur++;
6904         } while (1);
6905     }
6906 }
6907
6908 /**
6909  * xmlRelaxNGCleanupAttributes:
6910  * @ctxt:  a Relax-NG parser context
6911  * @node:  a Relax-NG node
6912  *
6913  * Check all the attributes on the given node
6914  */
6915 static void
6916 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6917 {
6918     xmlAttrPtr cur, next;
6919
6920     cur = node->properties;
6921     while (cur != NULL) {
6922         next = cur->next;
6923         if ((cur->ns == NULL) ||
6924             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6925             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6926                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6927                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6928                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6929                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6930                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6931                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6932                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6933                                "Attribute %s is not allowed on %s\n",
6934                                cur->name, node->name);
6935                 }
6936             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6937                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6938                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6939                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6940                                "Attribute %s is not allowed on %s\n",
6941                                cur->name, node->name);
6942                 }
6943             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6944                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6945                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6946                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6947                                "Attribute %s is not allowed on %s\n",
6948                                cur->name, node->name);
6949                 }
6950             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6951                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6952                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6953                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6954                                "Attribute %s is not allowed on %s\n",
6955                                cur->name, node->name);
6956                 }
6957             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6958                 xmlChar *val;
6959                 xmlURIPtr uri;
6960
6961                 val = xmlNodeListGetString(node->doc, cur->children, 1);
6962                 if (val != NULL) {
6963                     if (val[0] != 0) {
6964                         uri = xmlParseURI((const char *) val);
6965                         if (uri == NULL) {
6966                             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6967                                        "Attribute %s contains invalid URI %s\n",
6968                                        cur->name, val);
6969                         } else {
6970                             if (uri->scheme == NULL) {
6971                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6972                                            "Attribute %s URI %s is not absolute\n",
6973                                            cur->name, val);
6974                             }
6975                             if (uri->fragment != NULL) {
6976                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6977                                            "Attribute %s URI %s has a fragment ID\n",
6978                                            cur->name, val);
6979                             }
6980                             xmlFreeURI(uri);
6981                         }
6982                     }
6983                     xmlFree(val);
6984                 }
6985             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6986                 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6987                            "Unknown attribute %s on %s\n", cur->name,
6988                            node->name);
6989             }
6990         }
6991         cur = next;
6992     }
6993 }
6994
6995 /**
6996  * xmlRelaxNGCleanupTree:
6997  * @ctxt:  a Relax-NG parser context
6998  * @root:  an xmlNodePtr subtree
6999  *
7000  * Cleanup the subtree from unwanted nodes for parsing, resolve
7001  * Include and externalRef lookups.
7002  */
7003 static void
7004 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
7005 {
7006     xmlNodePtr cur, delete;
7007
7008     delete = NULL;
7009     cur = root;
7010     while (cur != NULL) {
7011         if (delete != NULL) {
7012             xmlUnlinkNode(delete);
7013             xmlFreeNode(delete);
7014             delete = NULL;
7015         }
7016         if (cur->type == XML_ELEMENT_NODE) {
7017             /*
7018              * Simplification 4.1. Annotations
7019              */
7020             if ((cur->ns == NULL) ||
7021                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
7022                 if ((cur->parent != NULL) &&
7023                     (cur->parent->type == XML_ELEMENT_NODE) &&
7024                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
7025                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
7026                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
7027                     xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
7028                                "element %s doesn't allow foreign elements\n",
7029                                cur->parent->name, NULL);
7030                 }
7031                 delete = cur;
7032                 goto skip_children;
7033             } else {
7034                 xmlRelaxNGCleanupAttributes(ctxt, cur);
7035                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
7036                     xmlChar *href, *ns, *base, *URL;
7037                     xmlRelaxNGDocumentPtr docu;
7038                     xmlNodePtr tmp;
7039                     xmlURIPtr uri;
7040
7041                     ns = xmlGetProp(cur, BAD_CAST "ns");
7042                     if (ns == NULL) {
7043                         tmp = cur->parent;
7044                         while ((tmp != NULL) &&
7045                                (tmp->type == XML_ELEMENT_NODE)) {
7046                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7047                             if (ns != NULL)
7048                                 break;
7049                             tmp = tmp->parent;
7050                         }
7051                     }
7052                     href = xmlGetProp(cur, BAD_CAST "href");
7053                     if (href == NULL) {
7054                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7055                                    "xmlRelaxNGParse: externalRef has no href attribute\n",
7056                                    NULL, NULL);
7057                         if (ns != NULL)
7058                             xmlFree(ns);
7059                         delete = cur;
7060                         goto skip_children;
7061                     }
7062                     uri = xmlParseURI((const char *) href);
7063                     if (uri == NULL) {
7064                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7065                                    "Incorrect URI for externalRef %s\n",
7066                                    href, NULL);
7067                         if (ns != NULL)
7068                             xmlFree(ns);
7069                         if (href != NULL)
7070                             xmlFree(href);
7071                         delete = cur;
7072                         goto skip_children;
7073                     }
7074                     if (uri->fragment != NULL) {
7075                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7076                                "Fragment forbidden in URI for externalRef %s\n",
7077                                    href, NULL);
7078                         if (ns != NULL)
7079                             xmlFree(ns);
7080                         xmlFreeURI(uri);
7081                         if (href != NULL)
7082                             xmlFree(href);
7083                         delete = cur;
7084                         goto skip_children;
7085                     }
7086                     xmlFreeURI(uri);
7087                     base = xmlNodeGetBase(cur->doc, cur);
7088                     URL = xmlBuildURI(href, base);
7089                     if (URL == NULL) {
7090                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7091                                    "Failed to compute URL for externalRef %s\n",
7092                                    href, NULL);
7093                         if (ns != NULL)
7094                             xmlFree(ns);
7095                         if (href != NULL)
7096                             xmlFree(href);
7097                         if (base != NULL)
7098                             xmlFree(base);
7099                         delete = cur;
7100                         goto skip_children;
7101                     }
7102                     if (href != NULL)
7103                         xmlFree(href);
7104                     if (base != NULL)
7105                         xmlFree(base);
7106                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
7107                     if (docu == NULL) {
7108                         xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
7109                                    "Failed to load externalRef %s\n", URL,
7110                                    NULL);
7111                         if (ns != NULL)
7112                             xmlFree(ns);
7113                         xmlFree(URL);
7114                         delete = cur;
7115                         goto skip_children;
7116                     }
7117                     if (ns != NULL)
7118                         xmlFree(ns);
7119                     xmlFree(URL);
7120                     cur->psvi = docu;
7121                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7122                     xmlChar *href, *ns, *base, *URL;
7123                     xmlRelaxNGIncludePtr incl;
7124                     xmlNodePtr tmp;
7125
7126                     href = xmlGetProp(cur, BAD_CAST "href");
7127                     if (href == NULL) {
7128                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7129                                    "xmlRelaxNGParse: include has no href attribute\n",
7130                                    NULL, NULL);
7131                         delete = cur;
7132                         goto skip_children;
7133                     }
7134                     base = xmlNodeGetBase(cur->doc, cur);
7135                     URL = xmlBuildURI(href, base);
7136                     if (URL == NULL) {
7137                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7138                                    "Failed to compute URL for include %s\n",
7139                                    href, NULL);
7140                         if (href != NULL)
7141                             xmlFree(href);
7142                         if (base != NULL)
7143                             xmlFree(base);
7144                         delete = cur;
7145                         goto skip_children;
7146                     }
7147                     if (href != NULL)
7148                         xmlFree(href);
7149                     if (base != NULL)
7150                         xmlFree(base);
7151                     ns = xmlGetProp(cur, BAD_CAST "ns");
7152                     if (ns == NULL) {
7153                         tmp = cur->parent;
7154                         while ((tmp != NULL) &&
7155                                (tmp->type == XML_ELEMENT_NODE)) {
7156                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7157                             if (ns != NULL)
7158                                 break;
7159                             tmp = tmp->parent;
7160                         }
7161                     }
7162                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7163                     if (ns != NULL)
7164                         xmlFree(ns);
7165                     if (incl == NULL) {
7166                         xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7167                                    "Failed to load include %s\n", URL,
7168                                    NULL);
7169                         xmlFree(URL);
7170                         delete = cur;
7171                         goto skip_children;
7172                     }
7173                     xmlFree(URL);
7174                     cur->psvi = incl;
7175                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7176                            (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7177                 {
7178                     xmlChar *name, *ns;
7179                     xmlNodePtr text = NULL;
7180
7181                     /*
7182                      * Simplification 4.8. name attribute of element
7183                      * and attribute elements
7184                      */
7185                     name = xmlGetProp(cur, BAD_CAST "name");
7186                     if (name != NULL) {
7187                         if (cur->children == NULL) {
7188                             text =
7189                                 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7190                                             name);
7191                         } else {
7192                             xmlNodePtr node;
7193
7194                             node = xmlNewDocNode(cur->doc, cur->ns,
7195                                                  BAD_CAST "name", NULL);
7196                             if (node != NULL) {
7197                                 xmlAddPrevSibling(cur->children, node);
7198                                 text = xmlNewText(name);
7199                                 xmlAddChild(node, text);
7200                                 text = node;
7201                             }
7202                         }
7203                         if (text == NULL) {
7204                             xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7205                                        "Failed to create a name %s element\n",
7206                                        name, NULL);
7207                         }
7208                         xmlUnsetProp(cur, BAD_CAST "name");
7209                         xmlFree(name);
7210                         ns = xmlGetProp(cur, BAD_CAST "ns");
7211                         if (ns != NULL) {
7212                             if (text != NULL) {
7213                                 xmlSetProp(text, BAD_CAST "ns", ns);
7214                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7215                             }
7216                             xmlFree(ns);
7217                         } else if (xmlStrEqual(cur->name,
7218                                                BAD_CAST "attribute")) {
7219                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7220                         }
7221                     }
7222                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7223                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7224                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7225                     /*
7226                      * Simplification 4.8. name attribute of element
7227                      * and attribute elements
7228                      */
7229                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7230                         xmlNodePtr node;
7231                         xmlChar *ns = NULL;
7232
7233                         node = cur->parent;
7234                         while ((node != NULL) &&
7235                                (node->type == XML_ELEMENT_NODE)) {
7236                             ns = xmlGetProp(node, BAD_CAST "ns");
7237                             if (ns != NULL) {
7238                                 break;
7239                             }
7240                             node = node->parent;
7241                         }
7242                         if (ns == NULL) {
7243                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7244                         } else {
7245                             xmlSetProp(cur, BAD_CAST "ns", ns);
7246                             xmlFree(ns);
7247                         }
7248                     }
7249                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7250                         xmlChar *name, *local, *prefix;
7251
7252                         /*
7253                          * Simplification: 4.10. QNames
7254                          */
7255                         name = xmlNodeGetContent(cur);
7256                         if (name != NULL) {
7257                             local = xmlSplitQName2(name, &prefix);
7258                             if (local != NULL) {
7259                                 xmlNsPtr ns;
7260
7261                                 ns = xmlSearchNs(cur->doc, cur, prefix);
7262                                 if (ns == NULL) {
7263                                     xmlRngPErr(ctxt, cur,
7264                                                XML_RNGP_PREFIX_UNDEFINED,
7265                                                "xmlRelaxNGParse: no namespace for prefix %s\n",
7266                                                prefix, NULL);
7267                                 } else {
7268                                     xmlSetProp(cur, BAD_CAST "ns",
7269                                                ns->href);
7270                                     xmlNodeSetContent(cur, local);
7271                                 }
7272                                 xmlFree(local);
7273                                 xmlFree(prefix);
7274                             }
7275                             xmlFree(name);
7276                         }
7277                     }
7278                     /*
7279                      * 4.16
7280                      */
7281                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7282                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7283                             xmlRngPErr(ctxt, cur,
7284                                        XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7285                                        "Found nsName/except//nsName forbidden construct\n",
7286                                        NULL, NULL);
7287                         }
7288                     }
7289                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7290                            (cur != root)) {
7291                     int oldflags = ctxt->flags;
7292
7293                     /*
7294                      * 4.16
7295                      */
7296                     if ((cur->parent != NULL) &&
7297                         (xmlStrEqual
7298                          (cur->parent->name, BAD_CAST "anyName"))) {
7299                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7300                         xmlRelaxNGCleanupTree(ctxt, cur);
7301                         ctxt->flags = oldflags;
7302                         goto skip_children;
7303                     } else if ((cur->parent != NULL) &&
7304                                (xmlStrEqual
7305                                 (cur->parent->name, BAD_CAST "nsName"))) {
7306                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7307                         xmlRelaxNGCleanupTree(ctxt, cur);
7308                         ctxt->flags = oldflags;
7309                         goto skip_children;
7310                     }
7311                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7312                     /*
7313                      * 4.16
7314                      */
7315                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7316                         xmlRngPErr(ctxt, cur,
7317                                    XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7318                                    "Found anyName/except//anyName forbidden construct\n",
7319                                    NULL, NULL);
7320                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7321                         xmlRngPErr(ctxt, cur,
7322                                    XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7323                                    "Found nsName/except//anyName forbidden construct\n",
7324                                    NULL, NULL);
7325                     }
7326                 }
7327                 /*
7328                  * This is not an else since "include" is transformed
7329                  * into a div
7330                  */
7331                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7332                     xmlChar *ns;
7333                     xmlNodePtr child, ins, tmp;
7334
7335                     /*
7336                      * implements rule 4.11
7337                      */
7338
7339                     ns = xmlGetProp(cur, BAD_CAST "ns");
7340
7341                     child = cur->children;
7342                     ins = cur;
7343                     while (child != NULL) {
7344                         if (ns != NULL) {
7345                             if (!xmlHasProp(child, BAD_CAST "ns")) {
7346                                 xmlSetProp(child, BAD_CAST "ns", ns);
7347                             }
7348                         }
7349                         tmp = child->next;
7350                         xmlUnlinkNode(child);
7351                         ins = xmlAddNextSibling(ins, child);
7352                         child = tmp;
7353                     }
7354                     if (ns != NULL)
7355                         xmlFree(ns);
7356                     /*
7357                      * Since we are about to delete cur, if its nsDef is non-NULL we
7358                      * need to preserve it (it contains the ns definitions for the
7359                      * children we just moved).  We'll just stick it on to the end
7360                      * of cur->parent's list, since it's never going to be re-serialized
7361                      * (bug 143738).
7362                      */
7363                     if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
7364                         xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7365                         while (parDef->next != NULL)
7366                             parDef = parDef->next;
7367                         parDef->next = cur->nsDef;
7368                         cur->nsDef = NULL;
7369                     }
7370                     delete = cur;
7371                     goto skip_children;
7372                 }
7373             }
7374         }
7375         /*
7376          * Simplification 4.2 whitespaces
7377          */
7378         else if ((cur->type == XML_TEXT_NODE) ||
7379                  (cur->type == XML_CDATA_SECTION_NODE)) {
7380             if (IS_BLANK_NODE(cur)) {
7381                 if ((cur->parent != NULL) &&
7382                     (cur->parent->type == XML_ELEMENT_NODE)) {
7383                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7384                         &&
7385                         (!xmlStrEqual
7386                          (cur->parent->name, BAD_CAST "param")))
7387                         delete = cur;
7388                 } else {
7389                     delete = cur;
7390                     goto skip_children;
7391                 }
7392             }
7393         } else {
7394             delete = cur;
7395             goto skip_children;
7396         }
7397
7398         /*
7399          * Skip to next node
7400          */
7401         if (cur->children != NULL) {
7402             if ((cur->children->type != XML_ENTITY_DECL) &&
7403                 (cur->children->type != XML_ENTITY_REF_NODE) &&
7404                 (cur->children->type != XML_ENTITY_NODE)) {
7405                 cur = cur->children;
7406                 continue;
7407             }
7408         }
7409       skip_children:
7410         if (cur->next != NULL) {
7411             cur = cur->next;
7412             continue;
7413         }
7414
7415         do {
7416             cur = cur->parent;
7417             if (cur == NULL)
7418                 break;
7419             if (cur == root) {
7420                 cur = NULL;
7421                 break;
7422             }
7423             if (cur->next != NULL) {
7424                 cur = cur->next;
7425                 break;
7426             }
7427         } while (cur != NULL);
7428     }
7429     if (delete != NULL) {
7430         xmlUnlinkNode(delete);
7431         xmlFreeNode(delete);
7432         delete = NULL;
7433     }
7434 }
7435
7436 /**
7437  * xmlRelaxNGCleanupDoc:
7438  * @ctxt:  a Relax-NG parser context
7439  * @doc:  an xmldocPtr document pointer
7440  *
7441  * Cleanup the document from unwanted nodes for parsing, resolve
7442  * Include and externalRef lookups.
7443  *
7444  * Returns the cleaned up document or NULL in case of error
7445  */
7446 static xmlDocPtr
7447 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7448 {
7449     xmlNodePtr root;
7450
7451     /*
7452      * Extract the root
7453      */
7454     root = xmlDocGetRootElement(doc);
7455     if (root == NULL) {
7456         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7457                    ctxt->URL, NULL);
7458         return (NULL);
7459     }
7460     xmlRelaxNGCleanupTree(ctxt, root);
7461     return (doc);
7462 }
7463
7464 /**
7465  * xmlRelaxNGParse:
7466  * @ctxt:  a Relax-NG parser context
7467  *
7468  * parse a schema definition resource and build an internal
7469  * XML Shema struture which can be used to validate instances.
7470  *
7471  * Returns the internal XML RelaxNG structure built from the resource or
7472  *         NULL in case of error
7473  */
7474 xmlRelaxNGPtr
7475 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7476 {
7477     xmlRelaxNGPtr ret = NULL;
7478     xmlDocPtr doc;
7479     xmlNodePtr root;
7480
7481     xmlRelaxNGInitTypes();
7482
7483     if (ctxt == NULL)
7484         return (NULL);
7485
7486     /*
7487      * First step is to parse the input document into an DOM/Infoset
7488      */
7489     if (ctxt->URL != NULL) {
7490         doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
7491         if (doc == NULL) {
7492             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7493                        "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7494                        NULL);
7495             return (NULL);
7496         }
7497     } else if (ctxt->buffer != NULL) {
7498         doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
7499         if (doc == NULL) {
7500             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7501                        "xmlRelaxNGParse: could not parse schemas\n", NULL,
7502                        NULL);
7503             return (NULL);
7504         }
7505         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7506         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7507     } else if (ctxt->document != NULL) {
7508         doc = ctxt->document;
7509     } else {
7510         xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7511                    "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7512         return (NULL);
7513     }
7514     ctxt->document = doc;
7515
7516     /*
7517      * Some preprocessing of the document content
7518      */
7519     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7520     if (doc == NULL) {
7521         xmlFreeDoc(ctxt->document);
7522         ctxt->document = NULL;
7523         return (NULL);
7524     }
7525
7526     /*
7527      * Then do the parsing for good
7528      */
7529     root = xmlDocGetRootElement(doc);
7530     if (root == NULL) {
7531         xmlRngPErr(ctxt, (xmlNodePtr) doc,
7532                    XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7533                    (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
7534
7535         xmlFreeDoc(ctxt->document);
7536         ctxt->document = NULL;
7537         return (NULL);
7538     }
7539     ret = xmlRelaxNGParseDocument(ctxt, root);
7540     if (ret == NULL) {
7541         xmlFreeDoc(ctxt->document);
7542         ctxt->document = NULL;
7543         return (NULL);
7544     }
7545
7546     /*
7547      * Check the ref/defines links
7548      */
7549     /*
7550      * try to preprocess interleaves
7551      */
7552     if (ctxt->interleaves != NULL) {
7553         xmlHashScan(ctxt->interleaves,
7554                     (xmlHashScanner) 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             /* no break on purpose */
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 = ((long) 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             /* no break on purpose */
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 */