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