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