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