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