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