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