xref: /reactos/sdk/lib/3rdparty/libxml2/relaxng.c (revision 911153da)
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  * DEPRECATED: This function will be made private. Call xmlCleanupParser
2853  * to free global state but see the warnings there. xmlCleanupParser
2854  * should be only called once at program exit. In most cases, you don't
2855  * have call cleanup functions at all.
2856  *
2857  * Cleanup the default Schemas type library associated to RelaxNG
2858  */
2859 void
xmlRelaxNGCleanupTypes(void)2860 xmlRelaxNGCleanupTypes(void)
2861 {
2862     xmlSchemaCleanupTypes();
2863     if (xmlRelaxNGTypeInitialized == 0)
2864         return;
2865     xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary);
2866     xmlRelaxNGTypeInitialized = 0;
2867 }
2868 
2869 /************************************************************************
2870  *									*
2871  *		Compiling element content into regexp			*
2872  *									*
2873  * Sometime the element content can be compiled into a pure regexp,	*
2874  * This allows a faster execution and streamability at that level	*
2875  *									*
2876  ************************************************************************/
2877 
2878 /* from automata.c but not exported */
2879 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
2880 
2881 
2882 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2883                                 xmlRelaxNGDefinePtr def);
2884 
2885 /**
2886  * xmlRelaxNGIsCompilable:
2887  * @define:  the definition to check
2888  *
2889  * Check if a definition is nullable.
2890  *
2891  * Returns 1 if yes, 0 if no and -1 in case of error
2892  */
2893 static int
xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def)2894 xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def)
2895 {
2896     int ret = -1;
2897 
2898     if (def == NULL) {
2899         return (-1);
2900     }
2901     if ((def->type != XML_RELAXNG_ELEMENT) &&
2902         (def->dflags & IS_COMPILABLE))
2903         return (1);
2904     if ((def->type != XML_RELAXNG_ELEMENT) &&
2905         (def->dflags & IS_NOT_COMPILABLE))
2906         return (0);
2907     switch (def->type) {
2908         case XML_RELAXNG_NOOP:
2909             ret = xmlRelaxNGIsCompilable(def->content);
2910             break;
2911         case XML_RELAXNG_TEXT:
2912         case XML_RELAXNG_EMPTY:
2913             ret = 1;
2914             break;
2915         case XML_RELAXNG_ELEMENT:
2916             /*
2917              * Check if the element content is compilable
2918              */
2919             if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2920                 ((def->dflags & IS_COMPILABLE) == 0)) {
2921                 xmlRelaxNGDefinePtr list;
2922 
2923                 list = def->content;
2924                 while (list != NULL) {
2925                     ret = xmlRelaxNGIsCompilable(list);
2926                     if (ret != 1)
2927                         break;
2928                     list = list->next;
2929                 }
2930 		/*
2931 		 * Because the routine is recursive, we must guard against
2932 		 * discovering both COMPILABLE and NOT_COMPILABLE
2933 		 */
2934                 if (ret == 0) {
2935 		    def->dflags &= ~IS_COMPILABLE;
2936                     def->dflags |= IS_NOT_COMPILABLE;
2937 		}
2938                 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2939                     def->dflags |= IS_COMPILABLE;
2940 #ifdef DEBUG_COMPILE
2941                 if (ret == 1) {
2942                     xmlGenericError(xmlGenericErrorContext,
2943                                     "element content for %s is compilable\n",
2944                                     def->name);
2945                 } else if (ret == 0) {
2946                     xmlGenericError(xmlGenericErrorContext,
2947                                     "element content for %s is not compilable\n",
2948                                     def->name);
2949                 } else {
2950                     xmlGenericError(xmlGenericErrorContext,
2951                                     "Problem in RelaxNGIsCompilable for element %s\n",
2952                                     def->name);
2953                 }
2954 #endif
2955             }
2956             /*
2957              * All elements return a compilable status unless they
2958              * are generic like anyName
2959              */
2960             if ((def->nameClass != NULL) || (def->name == NULL))
2961                 ret = 0;
2962             else
2963                 ret = 1;
2964             return (ret);
2965         case XML_RELAXNG_REF:
2966         case XML_RELAXNG_EXTERNALREF:
2967         case XML_RELAXNG_PARENTREF:
2968             if (def->depth == -20) {
2969                 return (1);
2970             } else {
2971                 xmlRelaxNGDefinePtr list;
2972 
2973                 def->depth = -20;
2974                 list = def->content;
2975                 while (list != NULL) {
2976                     ret = xmlRelaxNGIsCompilable(list);
2977                     if (ret != 1)
2978                         break;
2979                     list = list->next;
2980                 }
2981             }
2982             break;
2983         case XML_RELAXNG_START:
2984         case XML_RELAXNG_OPTIONAL:
2985         case XML_RELAXNG_ZEROORMORE:
2986         case XML_RELAXNG_ONEORMORE:
2987         case XML_RELAXNG_CHOICE:
2988         case XML_RELAXNG_GROUP:
2989         case XML_RELAXNG_DEF:{
2990                 xmlRelaxNGDefinePtr list;
2991 
2992                 list = def->content;
2993                 while (list != NULL) {
2994                     ret = xmlRelaxNGIsCompilable(list);
2995                     if (ret != 1)
2996                         break;
2997                     list = list->next;
2998                 }
2999                 break;
3000             }
3001         case XML_RELAXNG_EXCEPT:
3002         case XML_RELAXNG_ATTRIBUTE:
3003         case XML_RELAXNG_INTERLEAVE:
3004         case XML_RELAXNG_DATATYPE:
3005         case XML_RELAXNG_LIST:
3006         case XML_RELAXNG_PARAM:
3007         case XML_RELAXNG_VALUE:
3008         case XML_RELAXNG_NOT_ALLOWED:
3009             ret = 0;
3010             break;
3011     }
3012     if (ret == 0)
3013         def->dflags |= IS_NOT_COMPILABLE;
3014     if (ret == 1)
3015         def->dflags |= IS_COMPILABLE;
3016 #ifdef DEBUG_COMPILE
3017     if (ret == 1) {
3018         xmlGenericError(xmlGenericErrorContext,
3019                         "RelaxNGIsCompilable %s : true\n",
3020                         xmlRelaxNGDefName(def));
3021     } else if (ret == 0) {
3022         xmlGenericError(xmlGenericErrorContext,
3023                         "RelaxNGIsCompilable %s : false\n",
3024                         xmlRelaxNGDefName(def));
3025     } else {
3026         xmlGenericError(xmlGenericErrorContext,
3027                         "Problem in RelaxNGIsCompilable %s\n",
3028                         xmlRelaxNGDefName(def));
3029     }
3030 #endif
3031     return (ret);
3032 }
3033 
3034 /**
3035  * xmlRelaxNGCompile:
3036  * ctxt:  the RelaxNG parser context
3037  * @define:  the definition tree to compile
3038  *
3039  * Compile the set of definitions, it works recursively, till the
3040  * element boundaries, where it tries to compile the content if possible
3041  *
3042  * Returns 0 if success and -1 in case of error
3043  */
3044 static int
xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def)3045 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3046 {
3047     int ret = 0;
3048     xmlRelaxNGDefinePtr list;
3049 
3050     if ((ctxt == NULL) || (def == NULL))
3051         return (-1);
3052 
3053     switch (def->type) {
3054         case XML_RELAXNG_START:
3055             if ((xmlRelaxNGIsCompilable(def) == 1) && (def->depth != -25)) {
3056                 xmlAutomataPtr oldam = ctxt->am;
3057                 xmlAutomataStatePtr oldstate = ctxt->state;
3058 
3059                 def->depth = -25;
3060 
3061                 list = def->content;
3062                 ctxt->am = xmlNewAutomata();
3063                 if (ctxt->am == NULL)
3064                     return (-1);
3065 
3066                 /*
3067                  * assume identical strings but not same pointer are different
3068                  * atoms, needed for non-determinism detection
3069                  * That way if 2 elements with the same name are in a choice
3070                  * branch the automata is found non-deterministic and
3071                  * we fallback to the normal validation which does the right
3072                  * thing of exploring both choices.
3073                  */
3074                 xmlAutomataSetFlags(ctxt->am, 1);
3075 
3076                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3077                 while (list != NULL) {
3078                     xmlRelaxNGCompile(ctxt, list);
3079                     list = list->next;
3080                 }
3081                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3082                 if (xmlAutomataIsDeterminist(ctxt->am))
3083                     def->contModel = xmlAutomataCompile(ctxt->am);
3084 
3085                 xmlFreeAutomata(ctxt->am);
3086                 ctxt->state = oldstate;
3087                 ctxt->am = oldam;
3088             }
3089             break;
3090         case XML_RELAXNG_ELEMENT:
3091             if ((ctxt->am != NULL) && (def->name != NULL)) {
3092                 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3093                                                         ctxt->state, NULL,
3094                                                         def->name, def->ns,
3095                                                         def);
3096             }
3097             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3098                 xmlAutomataPtr oldam = ctxt->am;
3099                 xmlAutomataStatePtr oldstate = ctxt->state;
3100 
3101                 def->depth = -25;
3102 
3103                 list = def->content;
3104                 ctxt->am = xmlNewAutomata();
3105                 if (ctxt->am == NULL)
3106                     return (-1);
3107                 xmlAutomataSetFlags(ctxt->am, 1);
3108                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3109                 while (list != NULL) {
3110                     xmlRelaxNGCompile(ctxt, list);
3111                     list = list->next;
3112                 }
3113                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3114                 def->contModel = xmlAutomataCompile(ctxt->am);
3115                 if (!xmlRegexpIsDeterminist(def->contModel)) {
3116 #ifdef DEBUG_COMPILE
3117                     xmlGenericError(xmlGenericErrorContext,
3118                         "Content model not determinist %s\n",
3119                                     def->name);
3120 #endif
3121                     /*
3122                      * we can only use the automata if it is determinist
3123                      */
3124                     xmlRegFreeRegexp(def->contModel);
3125                     def->contModel = NULL;
3126                 }
3127                 xmlFreeAutomata(ctxt->am);
3128                 ctxt->state = oldstate;
3129                 ctxt->am = oldam;
3130             } else {
3131                 xmlAutomataPtr oldam = ctxt->am;
3132 
3133                 /*
3134                  * we can't build the content model for this element content
3135                  * but it still might be possible to build it for some of its
3136                  * children, recurse.
3137                  */
3138                 ret = xmlRelaxNGTryCompile(ctxt, def);
3139                 ctxt->am = oldam;
3140             }
3141             break;
3142         case XML_RELAXNG_NOOP:
3143             ret = xmlRelaxNGCompile(ctxt, def->content);
3144             break;
3145         case XML_RELAXNG_OPTIONAL:{
3146                 xmlAutomataStatePtr oldstate = ctxt->state;
3147 
3148                 list = def->content;
3149                 while (list != NULL) {
3150                     xmlRelaxNGCompile(ctxt, list);
3151                     list = list->next;
3152                 }
3153                 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3154                 break;
3155             }
3156         case XML_RELAXNG_ZEROORMORE:{
3157                 xmlAutomataStatePtr oldstate;
3158 
3159                 ctxt->state =
3160                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3161                 oldstate = ctxt->state;
3162                 list = def->content;
3163                 while (list != NULL) {
3164                     xmlRelaxNGCompile(ctxt, list);
3165                     list = list->next;
3166                 }
3167                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3168                 ctxt->state =
3169                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3170                 break;
3171             }
3172         case XML_RELAXNG_ONEORMORE:{
3173                 xmlAutomataStatePtr oldstate;
3174 
3175                 list = def->content;
3176                 while (list != NULL) {
3177                     xmlRelaxNGCompile(ctxt, list);
3178                     list = list->next;
3179                 }
3180                 oldstate = ctxt->state;
3181                 list = def->content;
3182                 while (list != NULL) {
3183                     xmlRelaxNGCompile(ctxt, list);
3184                     list = list->next;
3185                 }
3186                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3187                 ctxt->state =
3188                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3189                 break;
3190             }
3191         case XML_RELAXNG_CHOICE:{
3192                 xmlAutomataStatePtr target = NULL;
3193                 xmlAutomataStatePtr oldstate = ctxt->state;
3194 
3195                 list = def->content;
3196                 while (list != NULL) {
3197                     ctxt->state = oldstate;
3198                     ret = xmlRelaxNGCompile(ctxt, list);
3199                     if (ret != 0)
3200                         break;
3201                     if (target == NULL)
3202                         target = ctxt->state;
3203                     else {
3204                         xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3205                                               target);
3206                     }
3207                     list = list->next;
3208                 }
3209                 ctxt->state = target;
3210 
3211                 break;
3212             }
3213         case XML_RELAXNG_REF:
3214         case XML_RELAXNG_EXTERNALREF:
3215         case XML_RELAXNG_PARENTREF:
3216         case XML_RELAXNG_GROUP:
3217         case XML_RELAXNG_DEF:
3218             list = def->content;
3219             while (list != NULL) {
3220                 ret = xmlRelaxNGCompile(ctxt, list);
3221                 if (ret != 0)
3222                     break;
3223                 list = list->next;
3224             }
3225             break;
3226         case XML_RELAXNG_TEXT:{
3227                 xmlAutomataStatePtr oldstate;
3228 
3229                 ctxt->state =
3230                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3231                 oldstate = ctxt->state;
3232                 xmlRelaxNGCompile(ctxt, def->content);
3233                 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3234                                          ctxt->state, BAD_CAST "#text",
3235                                          NULL);
3236                 ctxt->state =
3237                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3238                 break;
3239             }
3240         case XML_RELAXNG_EMPTY:
3241             ctxt->state =
3242                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3243             break;
3244         case XML_RELAXNG_EXCEPT:
3245         case XML_RELAXNG_ATTRIBUTE:
3246         case XML_RELAXNG_INTERLEAVE:
3247         case XML_RELAXNG_NOT_ALLOWED:
3248         case XML_RELAXNG_DATATYPE:
3249         case XML_RELAXNG_LIST:
3250         case XML_RELAXNG_PARAM:
3251         case XML_RELAXNG_VALUE:
3252             /* This should not happen and generate an internal error */
3253             fprintf(stderr, "RNG internal error trying to compile %s\n",
3254                     xmlRelaxNGDefName(def));
3255             break;
3256     }
3257     return (ret);
3258 }
3259 
3260 /**
3261  * xmlRelaxNGTryCompile:
3262  * ctxt:  the RelaxNG parser context
3263  * @define:  the definition tree to compile
3264  *
3265  * Try to compile the set of definitions, it works recursively,
3266  * possibly ignoring parts which cannot be compiled.
3267  *
3268  * Returns 0 if success and -1 in case of error
3269  */
3270 static int
xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def)3271 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3272 {
3273     int ret = 0;
3274     xmlRelaxNGDefinePtr list;
3275 
3276     if ((ctxt == NULL) || (def == NULL))
3277         return (-1);
3278 
3279     if ((def->type == XML_RELAXNG_START) ||
3280         (def->type == XML_RELAXNG_ELEMENT)) {
3281         ret = xmlRelaxNGIsCompilable(def);
3282         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3283             ctxt->am = NULL;
3284             ret = xmlRelaxNGCompile(ctxt, def);
3285 #ifdef DEBUG_PROGRESSIVE
3286             if (ret == 0) {
3287                 if (def->type == XML_RELAXNG_START)
3288                     xmlGenericError(xmlGenericErrorContext,
3289                                     "compiled the start\n");
3290                 else
3291                     xmlGenericError(xmlGenericErrorContext,
3292                                     "compiled element %s\n", def->name);
3293             } else {
3294                 if (def->type == XML_RELAXNG_START)
3295                     xmlGenericError(xmlGenericErrorContext,
3296                                     "failed to compile the start\n");
3297                 else
3298                     xmlGenericError(xmlGenericErrorContext,
3299                                     "failed to compile element %s\n",
3300                                     def->name);
3301             }
3302 #endif
3303             return (ret);
3304         }
3305     }
3306     switch (def->type) {
3307         case XML_RELAXNG_NOOP:
3308             ret = xmlRelaxNGTryCompile(ctxt, def->content);
3309             break;
3310         case XML_RELAXNG_TEXT:
3311         case XML_RELAXNG_DATATYPE:
3312         case XML_RELAXNG_LIST:
3313         case XML_RELAXNG_PARAM:
3314         case XML_RELAXNG_VALUE:
3315         case XML_RELAXNG_EMPTY:
3316         case XML_RELAXNG_ELEMENT:
3317             ret = 0;
3318             break;
3319         case XML_RELAXNG_OPTIONAL:
3320         case XML_RELAXNG_ZEROORMORE:
3321         case XML_RELAXNG_ONEORMORE:
3322         case XML_RELAXNG_CHOICE:
3323         case XML_RELAXNG_GROUP:
3324         case XML_RELAXNG_DEF:
3325         case XML_RELAXNG_START:
3326         case XML_RELAXNG_REF:
3327         case XML_RELAXNG_EXTERNALREF:
3328         case XML_RELAXNG_PARENTREF:
3329             list = def->content;
3330             while (list != NULL) {
3331                 ret = xmlRelaxNGTryCompile(ctxt, list);
3332                 if (ret != 0)
3333                     break;
3334                 list = list->next;
3335             }
3336             break;
3337         case XML_RELAXNG_EXCEPT:
3338         case XML_RELAXNG_ATTRIBUTE:
3339         case XML_RELAXNG_INTERLEAVE:
3340         case XML_RELAXNG_NOT_ALLOWED:
3341             ret = 0;
3342             break;
3343     }
3344     return (ret);
3345 }
3346 
3347 /************************************************************************
3348  *									*
3349  *			Parsing functions				*
3350  *									*
3351  ************************************************************************/
3352 
3353 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3354                                                     ctxt, xmlNodePtr node);
3355 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3356                                                   ctxt, xmlNodePtr node);
3357 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3358                                                    ctxt, xmlNodePtr nodes,
3359                                                    int group);
3360 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3361                                                   ctxt, xmlNodePtr node);
3362 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3363                                              xmlNodePtr node);
3364 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3365                                          xmlNodePtr nodes);
3366 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3367                                                     ctxt, xmlNodePtr node,
3368                                                     xmlRelaxNGDefinePtr
3369                                                     def);
3370 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3371                                                    ctxt, xmlNodePtr nodes);
3372 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3373                                   xmlRelaxNGDefinePtr define,
3374                                   xmlNodePtr elem);
3375 
3376 
3377 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3378 
3379 /**
3380  * xmlRelaxNGIsNullable:
3381  * @define:  the definition to verify
3382  *
3383  * Check if a definition is nullable.
3384  *
3385  * Returns 1 if yes, 0 if no and -1 in case of error
3386  */
3387 static int
xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)3388 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3389 {
3390     int ret;
3391 
3392     if (define == NULL)
3393         return (-1);
3394 
3395     if (define->dflags & IS_NULLABLE)
3396         return (1);
3397     if (define->dflags & IS_NOT_NULLABLE)
3398         return (0);
3399     switch (define->type) {
3400         case XML_RELAXNG_EMPTY:
3401         case XML_RELAXNG_TEXT:
3402             ret = 1;
3403             break;
3404         case XML_RELAXNG_NOOP:
3405         case XML_RELAXNG_DEF:
3406         case XML_RELAXNG_REF:
3407         case XML_RELAXNG_EXTERNALREF:
3408         case XML_RELAXNG_PARENTREF:
3409         case XML_RELAXNG_ONEORMORE:
3410             ret = xmlRelaxNGIsNullable(define->content);
3411             break;
3412         case XML_RELAXNG_EXCEPT:
3413         case XML_RELAXNG_NOT_ALLOWED:
3414         case XML_RELAXNG_ELEMENT:
3415         case XML_RELAXNG_DATATYPE:
3416         case XML_RELAXNG_PARAM:
3417         case XML_RELAXNG_VALUE:
3418         case XML_RELAXNG_LIST:
3419         case XML_RELAXNG_ATTRIBUTE:
3420             ret = 0;
3421             break;
3422         case XML_RELAXNG_CHOICE:{
3423                 xmlRelaxNGDefinePtr list = define->content;
3424 
3425                 while (list != NULL) {
3426                     ret = xmlRelaxNGIsNullable(list);
3427                     if (ret != 0)
3428                         goto done;
3429                     list = list->next;
3430                 }
3431                 ret = 0;
3432                 break;
3433             }
3434         case XML_RELAXNG_START:
3435         case XML_RELAXNG_INTERLEAVE:
3436         case XML_RELAXNG_GROUP:{
3437                 xmlRelaxNGDefinePtr list = define->content;
3438 
3439                 while (list != NULL) {
3440                     ret = xmlRelaxNGIsNullable(list);
3441                     if (ret != 1)
3442                         goto done;
3443                     list = list->next;
3444                 }
3445                 return (1);
3446             }
3447         default:
3448             return (-1);
3449     }
3450   done:
3451     if (ret == 0)
3452         define->dflags |= IS_NOT_NULLABLE;
3453     if (ret == 1)
3454         define->dflags |= IS_NULLABLE;
3455     return (ret);
3456 }
3457 
3458 /**
3459  * xmlRelaxNGIsBlank:
3460  * @str:  a string
3461  *
3462  * Check if a string is ignorable c.f. 4.2. Whitespace
3463  *
3464  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3465  */
3466 static int
xmlRelaxNGIsBlank(xmlChar * str)3467 xmlRelaxNGIsBlank(xmlChar * str)
3468 {
3469     if (str == NULL)
3470         return (1);
3471     while (*str != 0) {
3472         if (!(IS_BLANK_CH(*str)))
3473             return (0);
3474         str++;
3475     }
3476     return (1);
3477 }
3478 
3479 /**
3480  * xmlRelaxNGGetDataTypeLibrary:
3481  * @ctxt:  a Relax-NG parser context
3482  * @node:  the current data or value element
3483  *
3484  * Applies algorithm from 4.3. datatypeLibrary attribute
3485  *
3486  * Returns the datatypeLibrary value or NULL if not found
3487  */
3488 static xmlChar *
xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlNodePtr node)3489 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3490                              xmlNodePtr node)
3491 {
3492     xmlChar *ret, *escape;
3493 
3494     if (node == NULL)
3495         return(NULL);
3496 
3497     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3498         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3499         if (ret != NULL) {
3500             if (ret[0] == 0) {
3501                 xmlFree(ret);
3502                 return (NULL);
3503             }
3504             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3505             if (escape == NULL) {
3506                 return (ret);
3507             }
3508             xmlFree(ret);
3509             return (escape);
3510         }
3511     }
3512     node = node->parent;
3513     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3514         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3515         if (ret != NULL) {
3516             if (ret[0] == 0) {
3517                 xmlFree(ret);
3518                 return (NULL);
3519             }
3520             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3521             if (escape == NULL) {
3522                 return (ret);
3523             }
3524             xmlFree(ret);
3525             return (escape);
3526         }
3527         node = node->parent;
3528     }
3529     return (NULL);
3530 }
3531 
3532 /**
3533  * xmlRelaxNGParseValue:
3534  * @ctxt:  a Relax-NG parser context
3535  * @node:  the data node.
3536  *
3537  * parse the content of a RelaxNG value node.
3538  *
3539  * Returns the definition pointer or NULL in case of error
3540  */
3541 static xmlRelaxNGDefinePtr
xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)3542 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3543 {
3544     xmlRelaxNGDefinePtr def = NULL;
3545     xmlRelaxNGTypeLibraryPtr lib = NULL;
3546     xmlChar *type;
3547     xmlChar *library;
3548     int success = 0;
3549 
3550     def = xmlRelaxNGNewDefine(ctxt, node);
3551     if (def == NULL)
3552         return (NULL);
3553     def->type = XML_RELAXNG_VALUE;
3554 
3555     type = xmlGetProp(node, BAD_CAST "type");
3556     if (type != NULL) {
3557         xmlRelaxNGNormExtSpace(type);
3558         if (xmlValidateNCName(type, 0)) {
3559             xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3560                        "value type '%s' is not an NCName\n", type, NULL);
3561         }
3562         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3563         if (library == NULL)
3564             library =
3565                 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3566 
3567         def->name = type;
3568         def->ns = library;
3569 
3570         lib = (xmlRelaxNGTypeLibraryPtr)
3571             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3572         if (lib == NULL) {
3573             xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3574                        "Use of unregistered type library '%s'\n", library,
3575                        NULL);
3576             def->data = NULL;
3577         } else {
3578             def->data = lib;
3579             if (lib->have == NULL) {
3580                 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3581                            "Internal error with type library '%s': no 'have'\n",
3582                            library, NULL);
3583             } else {
3584                 success = lib->have(lib->data, def->name);
3585                 if (success != 1) {
3586                     xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3587                                "Error type '%s' is not exported by type library '%s'\n",
3588                                def->name, library);
3589                 }
3590             }
3591         }
3592     }
3593     if (node->children == NULL) {
3594         def->value = xmlStrdup(BAD_CAST "");
3595     } else if (((node->children->type != XML_TEXT_NODE) &&
3596                 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3597                (node->children->next != NULL)) {
3598         xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3599                    "Expecting a single text value for <value>content\n",
3600                    NULL, NULL);
3601     } else if (def != NULL) {
3602         def->value = xmlNodeGetContent(node);
3603         if (def->value == NULL) {
3604             xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3605                        "Element <value> has no content\n", NULL, NULL);
3606         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3607             void *val = NULL;
3608 
3609             success =
3610                 lib->check(lib->data, def->name, def->value, &val, node);
3611             if (success != 1) {
3612                 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3613                            "Value '%s' is not acceptable for type '%s'\n",
3614                            def->value, def->name);
3615             } else {
3616                 if (val != NULL)
3617                     def->attrs = val;
3618             }
3619         }
3620     }
3621     return (def);
3622 }
3623 
3624 /**
3625  * xmlRelaxNGParseData:
3626  * @ctxt:  a Relax-NG parser context
3627  * @node:  the data node.
3628  *
3629  * parse the content of a RelaxNG data node.
3630  *
3631  * Returns the definition pointer or NULL in case of error
3632  */
3633 static xmlRelaxNGDefinePtr
xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)3634 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3635 {
3636     xmlRelaxNGDefinePtr def = NULL, except;
3637     xmlRelaxNGDefinePtr param, lastparam = NULL;
3638     xmlRelaxNGTypeLibraryPtr lib;
3639     xmlChar *type;
3640     xmlChar *library;
3641     xmlNodePtr content;
3642     int tmp;
3643 
3644     type = xmlGetProp(node, BAD_CAST "type");
3645     if (type == NULL) {
3646         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3647                    NULL);
3648         return (NULL);
3649     }
3650     xmlRelaxNGNormExtSpace(type);
3651     if (xmlValidateNCName(type, 0)) {
3652         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3653                    "data type '%s' is not an NCName\n", type, NULL);
3654     }
3655     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3656     if (library == NULL)
3657         library =
3658             xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3659 
3660     def = xmlRelaxNGNewDefine(ctxt, node);
3661     if (def == NULL) {
3662         xmlFree(library);
3663         xmlFree(type);
3664         return (NULL);
3665     }
3666     def->type = XML_RELAXNG_DATATYPE;
3667     def->name = type;
3668     def->ns = library;
3669 
3670     lib = (xmlRelaxNGTypeLibraryPtr)
3671         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3672     if (lib == NULL) {
3673         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3674                    "Use of unregistered type library '%s'\n", library,
3675                    NULL);
3676         def->data = NULL;
3677     } else {
3678         def->data = lib;
3679         if (lib->have == NULL) {
3680             xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3681                        "Internal error with type library '%s': no 'have'\n",
3682                        library, NULL);
3683         } else {
3684             tmp = lib->have(lib->data, def->name);
3685             if (tmp != 1) {
3686                 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3687                            "Error type '%s' is not exported by type library '%s'\n",
3688                            def->name, library);
3689             } else
3690                 if ((xmlStrEqual
3691                      (library,
3692                       BAD_CAST
3693                       "http://www.w3.org/2001/XMLSchema-datatypes"))
3694                     && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3695                         || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3696                 ctxt->idref = 1;
3697             }
3698         }
3699     }
3700     content = node->children;
3701 
3702     /*
3703      * Handle optional params
3704      */
3705     while (content != NULL) {
3706         if (!xmlStrEqual(content->name, BAD_CAST "param"))
3707             break;
3708         if (xmlStrEqual(library,
3709                         BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3710             xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3711                        "Type library '%s' does not allow type parameters\n",
3712                        library, NULL);
3713             content = content->next;
3714             while ((content != NULL) &&
3715                    (xmlStrEqual(content->name, BAD_CAST "param")))
3716                 content = content->next;
3717         } else {
3718             param = xmlRelaxNGNewDefine(ctxt, node);
3719             if (param != NULL) {
3720                 param->type = XML_RELAXNG_PARAM;
3721                 param->name = xmlGetProp(content, BAD_CAST "name");
3722                 if (param->name == NULL) {
3723                     xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3724                                "param has no name\n", NULL, NULL);
3725                 }
3726                 param->value = xmlNodeGetContent(content);
3727                 if (lastparam == NULL) {
3728                     def->attrs = lastparam = param;
3729                 } else {
3730                     lastparam->next = param;
3731                     lastparam = param;
3732                 }
3733                 if (lib != NULL) {
3734                 }
3735             }
3736             content = content->next;
3737         }
3738     }
3739     /*
3740      * Handle optional except
3741      */
3742     if ((content != NULL)
3743         && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3744         xmlNodePtr child;
3745         xmlRelaxNGDefinePtr tmp2, last = NULL;
3746 
3747         except = xmlRelaxNGNewDefine(ctxt, node);
3748         if (except == NULL) {
3749             return (def);
3750         }
3751         except->type = XML_RELAXNG_EXCEPT;
3752         child = content->children;
3753 	def->content = except;
3754         if (child == NULL) {
3755             xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3756                        "except has no content\n", NULL, NULL);
3757         }
3758         while (child != NULL) {
3759             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3760             if (tmp2 != NULL) {
3761                 if (last == NULL) {
3762                     except->content = last = tmp2;
3763                 } else {
3764                     last->next = tmp2;
3765                     last = tmp2;
3766                 }
3767             }
3768             child = child->next;
3769         }
3770         content = content->next;
3771     }
3772     /*
3773      * Check there is no unhandled data
3774      */
3775     if (content != NULL) {
3776         xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3777                    "Element data has unexpected content %s\n",
3778                    content->name, NULL);
3779     }
3780 
3781     return (def);
3782 }
3783 
3784 static const xmlChar *invalidName = BAD_CAST "\1";
3785 
3786 /**
3787  * xmlRelaxNGCompareNameClasses:
3788  * @defs1:  the first element/attribute defs
3789  * @defs2:  the second element/attribute defs
3790  * @name:  the restriction on the name
3791  * @ns:  the restriction on the namespace
3792  *
3793  * Compare the 2 lists of element definitions. The comparison is
3794  * that if both lists do not accept the same QNames, it returns 1
3795  * If the 2 lists can accept the same QName the comparison returns 0
3796  *
3797  * Returns 1 distinct, 0 if equal
3798  */
3799 static int
xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,xmlRelaxNGDefinePtr def2)3800 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3801                              xmlRelaxNGDefinePtr def2)
3802 {
3803     int ret = 1;
3804     xmlNode node;
3805     xmlNs ns;
3806     xmlRelaxNGValidCtxt ctxt;
3807 
3808     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3809 
3810     ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3811 
3812     if ((def1->type == XML_RELAXNG_ELEMENT) ||
3813         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3814         if (def2->type == XML_RELAXNG_TEXT)
3815             return (1);
3816         if (def1->name != NULL) {
3817             node.name = def1->name;
3818         } else {
3819             node.name = invalidName;
3820         }
3821         if (def1->ns != NULL) {
3822             if (def1->ns[0] == 0) {
3823                 node.ns = NULL;
3824             } else {
3825 	        node.ns = &ns;
3826                 ns.href = def1->ns;
3827             }
3828         } else {
3829             node.ns = NULL;
3830         }
3831         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3832             if (def1->nameClass != NULL) {
3833                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3834             } else {
3835                 ret = 0;
3836             }
3837         } else {
3838             ret = 1;
3839         }
3840     } else if (def1->type == XML_RELAXNG_TEXT) {
3841         if (def2->type == XML_RELAXNG_TEXT)
3842             return (0);
3843         return (1);
3844     } else if (def1->type == XML_RELAXNG_EXCEPT) {
3845         ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
3846 	if (ret == 0)
3847 	    ret = 1;
3848 	else if (ret == 1)
3849 	    ret = 0;
3850     } else {
3851         TODO ret = 0;
3852     }
3853     if (ret == 0)
3854         return (ret);
3855     if ((def2->type == XML_RELAXNG_ELEMENT) ||
3856         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3857         if (def2->name != NULL) {
3858             node.name = def2->name;
3859         } else {
3860             node.name = invalidName;
3861         }
3862         node.ns = &ns;
3863         if (def2->ns != NULL) {
3864             if (def2->ns[0] == 0) {
3865                 node.ns = NULL;
3866             } else {
3867                 ns.href = def2->ns;
3868             }
3869         } else {
3870             ns.href = invalidName;
3871         }
3872         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3873             if (def2->nameClass != NULL) {
3874                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3875             } else {
3876                 ret = 0;
3877             }
3878         } else {
3879             ret = 1;
3880         }
3881     } else {
3882         TODO ret = 0;
3883     }
3884 
3885     return (ret);
3886 }
3887 
3888 /**
3889  * xmlRelaxNGCompareElemDefLists:
3890  * @ctxt:  a Relax-NG parser context
3891  * @defs1:  the first list of element/attribute defs
3892  * @defs2:  the second list of element/attribute defs
3893  *
3894  * Compare the 2 lists of element or attribute definitions. The comparison
3895  * is that if both lists do not accept the same QNames, it returns 1
3896  * If the 2 lists can accept the same QName the comparison returns 0
3897  *
3898  * Returns 1 distinct, 0 if equal
3899  */
3900 static int
xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlRelaxNGDefinePtr * def1,xmlRelaxNGDefinePtr * def2)3901 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3902                               ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3903                               xmlRelaxNGDefinePtr * def2)
3904 {
3905     xmlRelaxNGDefinePtr *basedef2 = def2;
3906 
3907     if ((def1 == NULL) || (def2 == NULL))
3908         return (1);
3909     if ((*def1 == NULL) || (*def2 == NULL))
3910         return (1);
3911     while (*def1 != NULL) {
3912         while ((*def2) != NULL) {
3913             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3914                 return (0);
3915             def2++;
3916         }
3917         def2 = basedef2;
3918         def1++;
3919     }
3920     return (1);
3921 }
3922 
3923 /**
3924  * xmlRelaxNGGenerateAttributes:
3925  * @ctxt:  a Relax-NG parser context
3926  * @def:  the definition definition
3927  *
3928  * Check if the definition can only generate attributes
3929  *
3930  * Returns 1 if yes, 0 if no and -1 in case of error.
3931  */
3932 static int
xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def)3933 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3934                              xmlRelaxNGDefinePtr def)
3935 {
3936     xmlRelaxNGDefinePtr parent, cur, tmp;
3937 
3938     /*
3939      * Don't run that check in case of error. Infinite recursion
3940      * becomes possible.
3941      */
3942     if (ctxt->nbErrors != 0)
3943         return (-1);
3944 
3945     parent = NULL;
3946     cur = def;
3947     while (cur != NULL) {
3948         if ((cur->type == XML_RELAXNG_ELEMENT) ||
3949             (cur->type == XML_RELAXNG_TEXT) ||
3950             (cur->type == XML_RELAXNG_DATATYPE) ||
3951             (cur->type == XML_RELAXNG_PARAM) ||
3952             (cur->type == XML_RELAXNG_LIST) ||
3953             (cur->type == XML_RELAXNG_VALUE) ||
3954             (cur->type == XML_RELAXNG_EMPTY))
3955             return (0);
3956         if ((cur->type == XML_RELAXNG_CHOICE) ||
3957             (cur->type == XML_RELAXNG_INTERLEAVE) ||
3958             (cur->type == XML_RELAXNG_GROUP) ||
3959             (cur->type == XML_RELAXNG_ONEORMORE) ||
3960             (cur->type == XML_RELAXNG_ZEROORMORE) ||
3961             (cur->type == XML_RELAXNG_OPTIONAL) ||
3962             (cur->type == XML_RELAXNG_PARENTREF) ||
3963             (cur->type == XML_RELAXNG_EXTERNALREF) ||
3964             (cur->type == XML_RELAXNG_REF) ||
3965             (cur->type == XML_RELAXNG_DEF)) {
3966             if (cur->content != NULL) {
3967                 parent = cur;
3968                 cur = cur->content;
3969                 tmp = cur;
3970                 while (tmp != NULL) {
3971                     tmp->parent = parent;
3972                     tmp = tmp->next;
3973                 }
3974                 continue;
3975             }
3976         }
3977         if (cur == def)
3978             break;
3979         if (cur->next != NULL) {
3980             cur = cur->next;
3981             continue;
3982         }
3983         do {
3984             cur = cur->parent;
3985             if (cur == NULL)
3986                 break;
3987             if (cur == def)
3988                 return (1);
3989             if (cur->next != NULL) {
3990                 cur = cur->next;
3991                 break;
3992             }
3993         } while (cur != NULL);
3994     }
3995     return (1);
3996 }
3997 
3998 /**
3999  * xmlRelaxNGGetElements:
4000  * @ctxt:  a Relax-NG parser context
4001  * @def:  the definition definition
4002  * @eora:  gather elements (0), attributes (1) or elements and text (2)
4003  *
4004  * Compute the list of top elements a definition can generate
4005  *
4006  * Returns a list of elements or NULL if none was found.
4007  */
4008 static xmlRelaxNGDefinePtr *
xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def,int eora)4009 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
4010                       xmlRelaxNGDefinePtr def, int eora)
4011 {
4012     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
4013     int len = 0;
4014     int max = 0;
4015 
4016     /*
4017      * Don't run that check in case of error. Infinite recursion
4018      * becomes possible.
4019      */
4020     if (ctxt->nbErrors != 0)
4021         return (NULL);
4022 
4023     parent = NULL;
4024     cur = def;
4025     while (cur != NULL) {
4026         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
4027                              (cur->type == XML_RELAXNG_TEXT))) ||
4028             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE)) ||
4029             ((eora == 2) && ((cur->type == XML_RELAXNG_DATATYPE) ||
4030 	                     (cur->type == XML_RELAXNG_ELEMENT) ||
4031 			     (cur->type == XML_RELAXNG_LIST) ||
4032                              (cur->type == XML_RELAXNG_TEXT) ||
4033 			     (cur->type == XML_RELAXNG_VALUE)))) {
4034             if (ret == NULL) {
4035                 max = 10;
4036                 ret = (xmlRelaxNGDefinePtr *)
4037                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
4038                 if (ret == NULL) {
4039                     xmlRngPErrMemory(ctxt, "getting element list\n");
4040                     return (NULL);
4041                 }
4042             } else if (max <= len) {
4043 	        xmlRelaxNGDefinePtr *temp;
4044 
4045                 max *= 2;
4046                 temp = xmlRealloc(ret,
4047                                (max + 1) * sizeof(xmlRelaxNGDefinePtr));
4048                 if (temp == NULL) {
4049                     xmlRngPErrMemory(ctxt, "getting element list\n");
4050 		    xmlFree(ret);
4051                     return (NULL);
4052                 }
4053 		ret = temp;
4054             }
4055             ret[len++] = cur;
4056             ret[len] = NULL;
4057         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
4058                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
4059                    (cur->type == XML_RELAXNG_GROUP) ||
4060                    (cur->type == XML_RELAXNG_ONEORMORE) ||
4061                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
4062                    (cur->type == XML_RELAXNG_OPTIONAL) ||
4063                    (cur->type == XML_RELAXNG_PARENTREF) ||
4064                    (cur->type == XML_RELAXNG_REF) ||
4065                    (cur->type == XML_RELAXNG_DEF) ||
4066 		   (cur->type == XML_RELAXNG_EXTERNALREF)) {
4067             /*
4068              * Don't go within elements or attributes or string values.
4069              * Just gather the element top list
4070              */
4071             if (cur->content != NULL) {
4072                 parent = cur;
4073                 cur = cur->content;
4074                 tmp = cur;
4075                 while (tmp != NULL) {
4076                     tmp->parent = parent;
4077                     tmp = tmp->next;
4078                 }
4079                 continue;
4080             }
4081         }
4082         if (cur == def)
4083             break;
4084         if (cur->next != NULL) {
4085             cur = cur->next;
4086             continue;
4087         }
4088         do {
4089             cur = cur->parent;
4090             if (cur == NULL)
4091                 break;
4092             if (cur == def)
4093                 return (ret);
4094             if (cur->next != NULL) {
4095                 cur = cur->next;
4096                 break;
4097             }
4098         } while (cur != NULL);
4099     }
4100     return (ret);
4101 }
4102 
4103 /**
4104  * xmlRelaxNGCheckChoiceDeterminism:
4105  * @ctxt:  a Relax-NG parser context
4106  * @def:  the choice definition
4107  *
4108  * Also used to find indeterministic pattern in choice
4109  */
4110 static void
xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def)4111 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
4112                                  xmlRelaxNGDefinePtr def)
4113 {
4114     xmlRelaxNGDefinePtr **list;
4115     xmlRelaxNGDefinePtr cur;
4116     int nbchild = 0, i, j, ret;
4117     int is_nullable = 0;
4118     int is_indeterminist = 0;
4119     xmlHashTablePtr triage = NULL;
4120     int is_triable = 1;
4121 
4122     if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4123         return;
4124 
4125     if (def->dflags & IS_PROCESSED)
4126         return;
4127 
4128     /*
4129      * Don't run that check in case of error. Infinite recursion
4130      * becomes possible.
4131      */
4132     if (ctxt->nbErrors != 0)
4133         return;
4134 
4135     is_nullable = xmlRelaxNGIsNullable(def);
4136 
4137     cur = def->content;
4138     while (cur != NULL) {
4139         nbchild++;
4140         cur = cur->next;
4141     }
4142 
4143     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4144                                               sizeof(xmlRelaxNGDefinePtr
4145                                                      *));
4146     if (list == NULL) {
4147         xmlRngPErrMemory(ctxt, "building choice\n");
4148         return;
4149     }
4150     i = 0;
4151     /*
4152      * a bit strong but safe
4153      */
4154     if (is_nullable == 0) {
4155         triage = xmlHashCreate(10);
4156     } else {
4157         is_triable = 0;
4158     }
4159     cur = def->content;
4160     while (cur != NULL) {
4161         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4162         if ((list[i] == NULL) || (list[i][0] == NULL)) {
4163             is_triable = 0;
4164         } else if (is_triable == 1) {
4165             xmlRelaxNGDefinePtr *tmp;
4166             int res;
4167 
4168             tmp = list[i];
4169             while ((*tmp != NULL) && (is_triable == 1)) {
4170                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4171                     res = xmlHashAddEntry2(triage,
4172                                            BAD_CAST "#text", NULL,
4173                                            (void *) cur);
4174                     if (res != 0)
4175                         is_triable = -1;
4176                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4177                            ((*tmp)->name != NULL)) {
4178                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4179                         res = xmlHashAddEntry2(triage,
4180                                                (*tmp)->name, NULL,
4181                                                (void *) cur);
4182                     else
4183                         res = xmlHashAddEntry2(triage,
4184                                                (*tmp)->name, (*tmp)->ns,
4185                                                (void *) cur);
4186                     if (res != 0)
4187                         is_triable = -1;
4188                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4189                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4190                         res = xmlHashAddEntry2(triage,
4191                                                BAD_CAST "#any", NULL,
4192                                                (void *) cur);
4193                     else
4194                         res = xmlHashAddEntry2(triage,
4195                                                BAD_CAST "#any", (*tmp)->ns,
4196                                                (void *) cur);
4197                     if (res != 0)
4198                         is_triable = -1;
4199                 } else {
4200                     is_triable = -1;
4201                 }
4202                 tmp++;
4203             }
4204         }
4205         i++;
4206         cur = cur->next;
4207     }
4208 
4209     for (i = 0; i < nbchild; i++) {
4210         if (list[i] == NULL)
4211             continue;
4212         for (j = 0; j < i; j++) {
4213             if (list[j] == NULL)
4214                 continue;
4215             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4216             if (ret == 0) {
4217                 is_indeterminist = 1;
4218             }
4219         }
4220     }
4221     for (i = 0; i < nbchild; i++) {
4222         if (list[i] != NULL)
4223             xmlFree(list[i]);
4224     }
4225 
4226     xmlFree(list);
4227     if (is_indeterminist) {
4228         def->dflags |= IS_INDETERMINIST;
4229     }
4230     if (is_triable == 1) {
4231         def->dflags |= IS_TRIABLE;
4232         def->data = triage;
4233     } else if (triage != NULL) {
4234         xmlHashFree(triage, NULL);
4235     }
4236     def->dflags |= IS_PROCESSED;
4237 }
4238 
4239 /**
4240  * xmlRelaxNGCheckGroupAttrs:
4241  * @ctxt:  a Relax-NG parser context
4242  * @def:  the group definition
4243  *
4244  * Detects violations of rule 7.3
4245  */
4246 static void
xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr def)4247 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4248                           xmlRelaxNGDefinePtr def)
4249 {
4250     xmlRelaxNGDefinePtr **list;
4251     xmlRelaxNGDefinePtr cur;
4252     int nbchild = 0, i, j, ret;
4253 
4254     if ((def == NULL) ||
4255         ((def->type != XML_RELAXNG_GROUP) &&
4256          (def->type != XML_RELAXNG_ELEMENT)))
4257         return;
4258 
4259     if (def->dflags & IS_PROCESSED)
4260         return;
4261 
4262     /*
4263      * Don't run that check in case of error. Infinite recursion
4264      * becomes possible.
4265      */
4266     if (ctxt->nbErrors != 0)
4267         return;
4268 
4269     cur = def->attrs;
4270     while (cur != NULL) {
4271         nbchild++;
4272         cur = cur->next;
4273     }
4274     cur = def->content;
4275     while (cur != NULL) {
4276         nbchild++;
4277         cur = cur->next;
4278     }
4279 
4280     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4281                                               sizeof(xmlRelaxNGDefinePtr
4282                                                      *));
4283     if (list == NULL) {
4284         xmlRngPErrMemory(ctxt, "building group\n");
4285         return;
4286     }
4287     i = 0;
4288     cur = def->attrs;
4289     while (cur != NULL) {
4290         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4291         i++;
4292         cur = cur->next;
4293     }
4294     cur = def->content;
4295     while (cur != NULL) {
4296         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4297         i++;
4298         cur = cur->next;
4299     }
4300 
4301     for (i = 0; i < nbchild; i++) {
4302         if (list[i] == NULL)
4303             continue;
4304         for (j = 0; j < i; j++) {
4305             if (list[j] == NULL)
4306                 continue;
4307             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4308             if (ret == 0) {
4309                 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4310                            "Attributes conflicts in group\n", NULL, NULL);
4311             }
4312         }
4313     }
4314     for (i = 0; i < nbchild; i++) {
4315         if (list[i] != NULL)
4316             xmlFree(list[i]);
4317     }
4318 
4319     xmlFree(list);
4320     def->dflags |= IS_PROCESSED;
4321 }
4322 
4323 /**
4324  * xmlRelaxNGComputeInterleaves:
4325  * @def:  the interleave definition
4326  * @ctxt:  a Relax-NG parser context
4327  * @name:  the definition name
4328  *
4329  * A lot of work for preprocessing interleave definitions
4330  * is potentially needed to get a decent execution speed at runtime
4331  *   - trying to get a total order on the element nodes generated
4332  *     by the interleaves, order the list of interleave definitions
4333  *     following that order.
4334  *   - if <text/> is used to handle mixed content, it is better to
4335  *     flag this in the define and simplify the runtime checking
4336  *     algorithm
4337  */
4338 static void
xmlRelaxNGComputeInterleaves(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)4339 xmlRelaxNGComputeInterleaves(void *payload, void *data,
4340                              const xmlChar * name ATTRIBUTE_UNUSED)
4341 {
4342     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4343     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4344     xmlRelaxNGDefinePtr cur, *tmp;
4345 
4346     xmlRelaxNGPartitionPtr partitions = NULL;
4347     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4348     xmlRelaxNGInterleaveGroupPtr group;
4349     int i, j, ret, res;
4350     int nbgroups = 0;
4351     int nbchild = 0;
4352     int is_mixed = 0;
4353     int is_determinist = 1;
4354 
4355     /*
4356      * Don't run that check in case of error. Infinite recursion
4357      * becomes possible.
4358      */
4359     if (ctxt->nbErrors != 0)
4360         return;
4361 
4362 #ifdef DEBUG_INTERLEAVE
4363     xmlGenericError(xmlGenericErrorContext,
4364                     "xmlRelaxNGComputeInterleaves(%s)\n", name);
4365 #endif
4366     cur = def->content;
4367     while (cur != NULL) {
4368         nbchild++;
4369         cur = cur->next;
4370     }
4371 
4372 #ifdef DEBUG_INTERLEAVE
4373     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4374 #endif
4375     groups = (xmlRelaxNGInterleaveGroupPtr *)
4376         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4377     if (groups == NULL)
4378         goto error;
4379     cur = def->content;
4380     while (cur != NULL) {
4381         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4382             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4383         if (groups[nbgroups] == NULL)
4384             goto error;
4385         if (cur->type == XML_RELAXNG_TEXT)
4386             is_mixed++;
4387         groups[nbgroups]->rule = cur;
4388         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 2);
4389         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4390         nbgroups++;
4391         cur = cur->next;
4392     }
4393 #ifdef DEBUG_INTERLEAVE
4394     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4395 #endif
4396 
4397     /*
4398      * Let's check that all rules makes a partitions according to 7.4
4399      */
4400     partitions = (xmlRelaxNGPartitionPtr)
4401         xmlMalloc(sizeof(xmlRelaxNGPartition));
4402     if (partitions == NULL)
4403         goto error;
4404     memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4405     partitions->nbgroups = nbgroups;
4406     partitions->triage = xmlHashCreate(nbgroups);
4407     for (i = 0; i < nbgroups; i++) {
4408         group = groups[i];
4409         for (j = i + 1; j < nbgroups; j++) {
4410             if (groups[j] == NULL)
4411                 continue;
4412 
4413             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4414                                                 groups[j]->defs);
4415             if (ret == 0) {
4416                 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4417                            "Element or text conflicts in interleave\n",
4418                            NULL, NULL);
4419             }
4420             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4421                                                 groups[j]->attrs);
4422             if (ret == 0) {
4423                 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4424                            "Attributes conflicts in interleave\n", NULL,
4425                            NULL);
4426             }
4427         }
4428         tmp = group->defs;
4429         if ((tmp != NULL) && (*tmp != NULL)) {
4430             while (*tmp != NULL) {
4431                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4432                     res = xmlHashAddEntry2(partitions->triage,
4433                                            BAD_CAST "#text", NULL,
4434                                            (void *) (ptrdiff_t) (i + 1));
4435                     if (res != 0)
4436                         is_determinist = -1;
4437                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4438                            ((*tmp)->name != NULL)) {
4439                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4440                         res = xmlHashAddEntry2(partitions->triage,
4441                                                (*tmp)->name, NULL,
4442                                                (void *) (ptrdiff_t) (i + 1));
4443                     else
4444                         res = xmlHashAddEntry2(partitions->triage,
4445                                                (*tmp)->name, (*tmp)->ns,
4446                                                (void *) (ptrdiff_t) (i + 1));
4447                     if (res != 0)
4448                         is_determinist = -1;
4449                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4450                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4451                         res = xmlHashAddEntry2(partitions->triage,
4452                                                BAD_CAST "#any", NULL,
4453                                                (void *) (ptrdiff_t) (i + 1));
4454                     else
4455                         res = xmlHashAddEntry2(partitions->triage,
4456                                                BAD_CAST "#any", (*tmp)->ns,
4457                                                (void *) (ptrdiff_t) (i + 1));
4458                     if ((*tmp)->nameClass != NULL)
4459                         is_determinist = 2;
4460                     if (res != 0)
4461                         is_determinist = -1;
4462                 } else {
4463                     is_determinist = -1;
4464                 }
4465                 tmp++;
4466             }
4467         } else {
4468             is_determinist = 0;
4469         }
4470     }
4471     partitions->groups = groups;
4472 
4473     /*
4474      * and save the partition list back in the def
4475      */
4476     def->data = partitions;
4477     if (is_mixed != 0)
4478         def->dflags |= IS_MIXED;
4479     if (is_determinist == 1)
4480         partitions->flags = IS_DETERMINIST;
4481     if (is_determinist == 2)
4482         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4483     return;
4484 
4485   error:
4486     xmlRngPErrMemory(ctxt, "in interleave computation\n");
4487     if (groups != NULL) {
4488         for (i = 0; i < nbgroups; i++)
4489             if (groups[i] != NULL) {
4490                 if (groups[i]->defs != NULL)
4491                     xmlFree(groups[i]->defs);
4492                 xmlFree(groups[i]);
4493             }
4494         xmlFree(groups);
4495     }
4496     xmlRelaxNGFreePartition(partitions);
4497 }
4498 
4499 /**
4500  * xmlRelaxNGParseInterleave:
4501  * @ctxt:  a Relax-NG parser context
4502  * @node:  the data node.
4503  *
4504  * parse the content of a RelaxNG interleave node.
4505  *
4506  * Returns the definition pointer or NULL in case of error
4507  */
4508 static xmlRelaxNGDefinePtr
xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)4509 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4510 {
4511     xmlRelaxNGDefinePtr def = NULL;
4512     xmlRelaxNGDefinePtr last = NULL, cur;
4513     xmlNodePtr child;
4514 
4515     def = xmlRelaxNGNewDefine(ctxt, node);
4516     if (def == NULL) {
4517         return (NULL);
4518     }
4519     def->type = XML_RELAXNG_INTERLEAVE;
4520 
4521     if (ctxt->interleaves == NULL)
4522         ctxt->interleaves = xmlHashCreate(10);
4523     if (ctxt->interleaves == NULL) {
4524         xmlRngPErrMemory(ctxt, "create interleaves\n");
4525     } else {
4526         char name[32];
4527 
4528         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4529         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4530             xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4531                        "Failed to add %s to hash table\n",
4532 		       (const xmlChar *) name, NULL);
4533         }
4534     }
4535     child = node->children;
4536     if (child == NULL) {
4537         xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4538                    "Element interleave is empty\n", NULL, NULL);
4539     }
4540     while (child != NULL) {
4541         if (IS_RELAXNG(child, "element")) {
4542             cur = xmlRelaxNGParseElement(ctxt, child);
4543         } else {
4544             cur = xmlRelaxNGParsePattern(ctxt, child);
4545         }
4546         if (cur != NULL) {
4547             cur->parent = def;
4548             if (last == NULL) {
4549                 def->content = last = cur;
4550             } else {
4551                 last->next = cur;
4552                 last = cur;
4553             }
4554         }
4555         child = child->next;
4556     }
4557 
4558     return (def);
4559 }
4560 
4561 /**
4562  * xmlRelaxNGParseInclude:
4563  * @ctxt:  a Relax-NG parser context
4564  * @node:  the include node
4565  *
4566  * Integrate the content of an include node in the current grammar
4567  *
4568  * Returns 0 in case of success or -1 in case of error
4569  */
4570 static int
xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)4571 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4572 {
4573     xmlRelaxNGIncludePtr incl;
4574     xmlNodePtr root;
4575     int ret = 0, tmp;
4576 
4577     incl = node->psvi;
4578     if (incl == NULL) {
4579         xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4580                    "Include node has no data\n", NULL, NULL);
4581         return (-1);
4582     }
4583     root = xmlDocGetRootElement(incl->doc);
4584     if (root == NULL) {
4585         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4586                    NULL, NULL);
4587         return (-1);
4588     }
4589     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4590         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4591                    "Include document root is not a grammar\n", NULL, NULL);
4592         return (-1);
4593     }
4594 
4595     /*
4596      * Merge the definition from both the include and the internal list
4597      */
4598     if (root->children != NULL) {
4599         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4600         if (tmp != 0)
4601             ret = -1;
4602     }
4603     if (node->children != NULL) {
4604         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4605         if (tmp != 0)
4606             ret = -1;
4607     }
4608     return (ret);
4609 }
4610 
4611 /**
4612  * xmlRelaxNGParseDefine:
4613  * @ctxt:  a Relax-NG parser context
4614  * @node:  the define node
4615  *
4616  * parse the content of a RelaxNG define element node.
4617  *
4618  * Returns 0 in case of success or -1 in case of error
4619  */
4620 static int
xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)4621 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4622 {
4623     xmlChar *name;
4624     int ret = 0, tmp;
4625     xmlRelaxNGDefinePtr def;
4626     const xmlChar *olddefine;
4627 
4628     name = xmlGetProp(node, BAD_CAST "name");
4629     if (name == NULL) {
4630         xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4631                    "define has no name\n", NULL, NULL);
4632     } else {
4633         xmlRelaxNGNormExtSpace(name);
4634         if (xmlValidateNCName(name, 0)) {
4635             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4636                        "define name '%s' is not an NCName\n", name, NULL);
4637         }
4638         def = xmlRelaxNGNewDefine(ctxt, node);
4639         if (def == NULL) {
4640             xmlFree(name);
4641             return (-1);
4642         }
4643         def->type = XML_RELAXNG_DEF;
4644         def->name = name;
4645         if (node->children == NULL) {
4646             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4647                        "define has no children\n", NULL, NULL);
4648         } else {
4649             olddefine = ctxt->define;
4650             ctxt->define = name;
4651             def->content =
4652                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4653             ctxt->define = olddefine;
4654         }
4655         if (ctxt->grammar->defs == NULL)
4656             ctxt->grammar->defs = xmlHashCreate(10);
4657         if (ctxt->grammar->defs == NULL) {
4658             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4659                        "Could not create definition hash\n", NULL, NULL);
4660             ret = -1;
4661         } else {
4662             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4663             if (tmp < 0) {
4664                 xmlRelaxNGDefinePtr prev;
4665 
4666                 prev = xmlHashLookup(ctxt->grammar->defs, name);
4667                 if (prev == NULL) {
4668                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4669                                "Internal error on define aggregation of %s\n",
4670                                name, NULL);
4671                     ret = -1;
4672                 } else {
4673                     while (prev->nextHash != NULL)
4674                         prev = prev->nextHash;
4675                     prev->nextHash = def;
4676                 }
4677             }
4678         }
4679     }
4680     return (ret);
4681 }
4682 
4683 /**
4684  * xmlRelaxNGParseImportRef:
4685  * @payload: the parser context
4686  * @data: the current grammar
4687  * @name: the reference name
4688  *
4689  * Import import one references into the current grammar
4690  */
4691 static void
xmlRelaxNGParseImportRef(void * payload,void * data,const xmlChar * name)4692 xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) {
4693     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4694     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4695     int tmp;
4696 
4697     def->dflags |= IS_EXTERNAL_REF;
4698 
4699     tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4700     if (tmp < 0) {
4701         xmlRelaxNGDefinePtr prev;
4702 
4703         prev = (xmlRelaxNGDefinePtr)
4704             xmlHashLookup(ctxt->grammar->refs, def->name);
4705         if (prev == NULL) {
4706             if (def->name != NULL) {
4707                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4708                            "Error refs definitions '%s'\n",
4709                            def->name, NULL);
4710             } else {
4711                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4712                            "Error refs definitions\n",
4713                            NULL, NULL);
4714             }
4715         } else {
4716             def->nextHash = prev->nextHash;
4717             prev->nextHash = def;
4718         }
4719     }
4720 }
4721 
4722 /**
4723  * xmlRelaxNGParseImportRefs:
4724  * @ctxt: the parser context
4725  * @grammar: the sub grammar
4726  *
4727  * Import references from the subgrammar into the current grammar
4728  *
4729  * Returns 0 in case of success, -1 in case of failure
4730  */
4731 static int
xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGGrammarPtr grammar)4732 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4733                           xmlRelaxNGGrammarPtr grammar) {
4734     if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4735         return(-1);
4736     if (grammar->refs == NULL)
4737         return(0);
4738     if (ctxt->grammar->refs == NULL)
4739         ctxt->grammar->refs = xmlHashCreate(10);
4740     if (ctxt->grammar->refs == NULL) {
4741         xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4742                    "Could not create references hash\n", NULL, NULL);
4743         return(-1);
4744     }
4745     xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
4746     return(0);
4747 }
4748 
4749 /**
4750  * xmlRelaxNGProcessExternalRef:
4751  * @ctxt: the parser context
4752  * @node:  the externalRef node
4753  *
4754  * Process and compile an externalRef node
4755  *
4756  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4757  */
4758 static xmlRelaxNGDefinePtr
xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)4759 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4760 {
4761     xmlRelaxNGDocumentPtr docu;
4762     xmlNodePtr root, tmp;
4763     xmlChar *ns;
4764     int newNs = 0, oldflags;
4765     xmlRelaxNGDefinePtr def;
4766 
4767     docu = node->psvi;
4768     if (docu != NULL) {
4769         def = xmlRelaxNGNewDefine(ctxt, node);
4770         if (def == NULL)
4771             return (NULL);
4772         def->type = XML_RELAXNG_EXTERNALREF;
4773 
4774         if (docu->content == NULL) {
4775             /*
4776              * Then do the parsing for good
4777              */
4778             root = xmlDocGetRootElement(docu->doc);
4779             if (root == NULL) {
4780                 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4781                            "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4782                            NULL);
4783                 return (NULL);
4784             }
4785             /*
4786              * ns transmission rules
4787              */
4788             ns = xmlGetProp(root, BAD_CAST "ns");
4789             if (ns == NULL) {
4790                 tmp = node;
4791                 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4792                     ns = xmlGetProp(tmp, BAD_CAST "ns");
4793                     if (ns != NULL) {
4794                         break;
4795                     }
4796                     tmp = tmp->parent;
4797                 }
4798                 if (ns != NULL) {
4799                     xmlSetProp(root, BAD_CAST "ns", ns);
4800                     newNs = 1;
4801                     xmlFree(ns);
4802                 }
4803             } else {
4804                 xmlFree(ns);
4805             }
4806 
4807             /*
4808              * Parsing to get a precompiled schemas.
4809              */
4810             oldflags = ctxt->flags;
4811             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4812             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4813             ctxt->flags = oldflags;
4814             if ((docu->schema != NULL) &&
4815                 (docu->schema->topgrammar != NULL)) {
4816                 docu->content = docu->schema->topgrammar->start;
4817                 if (docu->schema->topgrammar->refs)
4818                     xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
4819             }
4820 
4821             /*
4822              * the externalRef may be reused in a different ns context
4823              */
4824             if (newNs == 1) {
4825                 xmlUnsetProp(root, BAD_CAST "ns");
4826             }
4827         }
4828         def->content = docu->content;
4829     } else {
4830         def = NULL;
4831     }
4832     return (def);
4833 }
4834 
4835 /**
4836  * xmlRelaxNGParsePattern:
4837  * @ctxt:  a Relax-NG parser context
4838  * @node:  the pattern node.
4839  *
4840  * parse the content of a RelaxNG pattern node.
4841  *
4842  * Returns the definition pointer or NULL in case of error or if no
4843  *     pattern is generated.
4844  */
4845 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)4846 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4847 {
4848     xmlRelaxNGDefinePtr def = NULL;
4849 
4850     if (node == NULL) {
4851         return (NULL);
4852     }
4853     if (IS_RELAXNG(node, "element")) {
4854         def = xmlRelaxNGParseElement(ctxt, node);
4855     } else if (IS_RELAXNG(node, "attribute")) {
4856         def = xmlRelaxNGParseAttribute(ctxt, node);
4857     } else if (IS_RELAXNG(node, "empty")) {
4858         def = xmlRelaxNGNewDefine(ctxt, node);
4859         if (def == NULL)
4860             return (NULL);
4861         def->type = XML_RELAXNG_EMPTY;
4862         if (node->children != NULL) {
4863             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4864                        "empty: had a child node\n", NULL, NULL);
4865         }
4866     } else if (IS_RELAXNG(node, "text")) {
4867         def = xmlRelaxNGNewDefine(ctxt, node);
4868         if (def == NULL)
4869             return (NULL);
4870         def->type = XML_RELAXNG_TEXT;
4871         if (node->children != NULL) {
4872             xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4873                        "text: had a child node\n", NULL, NULL);
4874         }
4875     } else if (IS_RELAXNG(node, "zeroOrMore")) {
4876         def = xmlRelaxNGNewDefine(ctxt, node);
4877         if (def == NULL)
4878             return (NULL);
4879         def->type = XML_RELAXNG_ZEROORMORE;
4880         if (node->children == NULL) {
4881             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4882                        "Element %s is empty\n", node->name, NULL);
4883         } else {
4884             def->content =
4885                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4886         }
4887     } else if (IS_RELAXNG(node, "oneOrMore")) {
4888         def = xmlRelaxNGNewDefine(ctxt, node);
4889         if (def == NULL)
4890             return (NULL);
4891         def->type = XML_RELAXNG_ONEORMORE;
4892         if (node->children == NULL) {
4893             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4894                        "Element %s is empty\n", node->name, NULL);
4895         } else {
4896             def->content =
4897                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4898         }
4899     } else if (IS_RELAXNG(node, "optional")) {
4900         def = xmlRelaxNGNewDefine(ctxt, node);
4901         if (def == NULL)
4902             return (NULL);
4903         def->type = XML_RELAXNG_OPTIONAL;
4904         if (node->children == NULL) {
4905             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4906                        "Element %s is empty\n", node->name, NULL);
4907         } else {
4908             def->content =
4909                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4910         }
4911     } else if (IS_RELAXNG(node, "choice")) {
4912         def = xmlRelaxNGNewDefine(ctxt, node);
4913         if (def == NULL)
4914             return (NULL);
4915         def->type = XML_RELAXNG_CHOICE;
4916         if (node->children == NULL) {
4917             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4918                        "Element %s is empty\n", node->name, NULL);
4919         } else {
4920             def->content =
4921                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4922         }
4923     } else if (IS_RELAXNG(node, "group")) {
4924         def = xmlRelaxNGNewDefine(ctxt, node);
4925         if (def == NULL)
4926             return (NULL);
4927         def->type = XML_RELAXNG_GROUP;
4928         if (node->children == NULL) {
4929             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4930                        "Element %s is empty\n", node->name, NULL);
4931         } else {
4932             def->content =
4933                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4934         }
4935     } else if (IS_RELAXNG(node, "ref")) {
4936         def = xmlRelaxNGNewDefine(ctxt, node);
4937         if (def == NULL)
4938             return (NULL);
4939         def->type = XML_RELAXNG_REF;
4940         def->name = xmlGetProp(node, BAD_CAST "name");
4941         if (def->name == NULL) {
4942             xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4943                        NULL, NULL);
4944         } else {
4945             xmlRelaxNGNormExtSpace(def->name);
4946             if (xmlValidateNCName(def->name, 0)) {
4947                 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4948                            "ref name '%s' is not an NCName\n", def->name,
4949                            NULL);
4950             }
4951         }
4952         if (node->children != NULL) {
4953             xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4954                        NULL, NULL);
4955         }
4956         if (ctxt->grammar->refs == NULL)
4957             ctxt->grammar->refs = xmlHashCreate(10);
4958         if (ctxt->grammar->refs == NULL) {
4959             xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4960                        "Could not create references hash\n", NULL, NULL);
4961             def = NULL;
4962         } else {
4963             int tmp;
4964 
4965             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4966             if (tmp < 0) {
4967                 xmlRelaxNGDefinePtr prev;
4968 
4969                 prev = (xmlRelaxNGDefinePtr)
4970                     xmlHashLookup(ctxt->grammar->refs, def->name);
4971                 if (prev == NULL) {
4972                     if (def->name != NULL) {
4973 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4974 				   "Error refs definitions '%s'\n",
4975 				   def->name, NULL);
4976                     } else {
4977 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4978 				   "Error refs definitions\n",
4979 				   NULL, NULL);
4980                     }
4981                     def = NULL;
4982                 } else {
4983                     def->nextHash = prev->nextHash;
4984                     prev->nextHash = def;
4985                 }
4986             }
4987         }
4988     } else if (IS_RELAXNG(node, "data")) {
4989         def = xmlRelaxNGParseData(ctxt, node);
4990     } else if (IS_RELAXNG(node, "value")) {
4991         def = xmlRelaxNGParseValue(ctxt, node);
4992     } else if (IS_RELAXNG(node, "list")) {
4993         def = xmlRelaxNGNewDefine(ctxt, node);
4994         if (def == NULL)
4995             return (NULL);
4996         def->type = XML_RELAXNG_LIST;
4997         if (node->children == NULL) {
4998             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4999                        "Element %s is empty\n", node->name, NULL);
5000         } else {
5001             def->content =
5002                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
5003         }
5004     } else if (IS_RELAXNG(node, "interleave")) {
5005         def = xmlRelaxNGParseInterleave(ctxt, node);
5006     } else if (IS_RELAXNG(node, "externalRef")) {
5007         def = xmlRelaxNGProcessExternalRef(ctxt, node);
5008     } else if (IS_RELAXNG(node, "notAllowed")) {
5009         def = xmlRelaxNGNewDefine(ctxt, node);
5010         if (def == NULL)
5011             return (NULL);
5012         def->type = XML_RELAXNG_NOT_ALLOWED;
5013         if (node->children != NULL) {
5014             xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5015                        "xmlRelaxNGParse: notAllowed element is not empty\n",
5016                        NULL, NULL);
5017         }
5018     } else if (IS_RELAXNG(node, "grammar")) {
5019         xmlRelaxNGGrammarPtr grammar, old;
5020         xmlRelaxNGGrammarPtr oldparent;
5021 
5022 #ifdef DEBUG_GRAMMAR
5023         xmlGenericError(xmlGenericErrorContext,
5024                         "Found <grammar> pattern\n");
5025 #endif
5026 
5027         oldparent = ctxt->parentgrammar;
5028         old = ctxt->grammar;
5029         ctxt->parentgrammar = old;
5030         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5031         if (old != NULL) {
5032             ctxt->grammar = old;
5033             ctxt->parentgrammar = oldparent;
5034 #if 0
5035             if (grammar != NULL) {
5036                 grammar->next = old->next;
5037                 old->next = grammar;
5038             }
5039 #endif
5040         }
5041         if (grammar != NULL)
5042             def = grammar->start;
5043         else
5044             def = NULL;
5045     } else if (IS_RELAXNG(node, "parentRef")) {
5046         if (ctxt->parentgrammar == NULL) {
5047             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
5048                        "Use of parentRef without a parent grammar\n", NULL,
5049                        NULL);
5050             return (NULL);
5051         }
5052         def = xmlRelaxNGNewDefine(ctxt, node);
5053         if (def == NULL)
5054             return (NULL);
5055         def->type = XML_RELAXNG_PARENTREF;
5056         def->name = xmlGetProp(node, BAD_CAST "name");
5057         if (def->name == NULL) {
5058             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
5059                        "parentRef has no name\n", NULL, NULL);
5060         } else {
5061             xmlRelaxNGNormExtSpace(def->name);
5062             if (xmlValidateNCName(def->name, 0)) {
5063                 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
5064                            "parentRef name '%s' is not an NCName\n",
5065                            def->name, NULL);
5066             }
5067         }
5068         if (node->children != NULL) {
5069             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
5070                        "parentRef is not empty\n", NULL, NULL);
5071         }
5072         if (ctxt->parentgrammar->refs == NULL)
5073             ctxt->parentgrammar->refs = xmlHashCreate(10);
5074         if (ctxt->parentgrammar->refs == NULL) {
5075             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5076                        "Could not create references hash\n", NULL, NULL);
5077             def = NULL;
5078         } else if (def->name != NULL) {
5079             int tmp;
5080 
5081             tmp =
5082                 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
5083             if (tmp < 0) {
5084                 xmlRelaxNGDefinePtr prev;
5085 
5086                 prev = (xmlRelaxNGDefinePtr)
5087                     xmlHashLookup(ctxt->parentgrammar->refs, def->name);
5088                 if (prev == NULL) {
5089                     xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5090                                "Internal error parentRef definitions '%s'\n",
5091                                def->name, NULL);
5092                     def = NULL;
5093                 } else {
5094                     def->nextHash = prev->nextHash;
5095                     prev->nextHash = def;
5096                 }
5097             }
5098         }
5099     } else if (IS_RELAXNG(node, "mixed")) {
5100         if (node->children == NULL) {
5101             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
5102                        NULL, NULL);
5103             def = NULL;
5104         } else {
5105             def = xmlRelaxNGParseInterleave(ctxt, node);
5106             if (def != NULL) {
5107                 xmlRelaxNGDefinePtr tmp;
5108 
5109                 if ((def->content != NULL) && (def->content->next != NULL)) {
5110                     tmp = xmlRelaxNGNewDefine(ctxt, node);
5111                     if (tmp != NULL) {
5112                         tmp->type = XML_RELAXNG_GROUP;
5113                         tmp->content = def->content;
5114                         def->content = tmp;
5115                     }
5116                 }
5117 
5118                 tmp = xmlRelaxNGNewDefine(ctxt, node);
5119                 if (tmp == NULL)
5120                     return (def);
5121                 tmp->type = XML_RELAXNG_TEXT;
5122                 tmp->next = def->content;
5123                 def->content = tmp;
5124             }
5125         }
5126     } else {
5127         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5128                    "Unexpected node %s is not a pattern\n", node->name,
5129                    NULL);
5130         def = NULL;
5131     }
5132     return (def);
5133 }
5134 
5135 /**
5136  * xmlRelaxNGParseAttribute:
5137  * @ctxt:  a Relax-NG parser context
5138  * @node:  the element node
5139  *
5140  * parse the content of a RelaxNG attribute node.
5141  *
5142  * Returns the definition pointer or NULL in case of error.
5143  */
5144 static xmlRelaxNGDefinePtr
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)5145 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5146 {
5147     xmlRelaxNGDefinePtr ret, cur;
5148     xmlNodePtr child;
5149     int old_flags;
5150 
5151     ret = xmlRelaxNGNewDefine(ctxt, node);
5152     if (ret == NULL)
5153         return (NULL);
5154     ret->type = XML_RELAXNG_ATTRIBUTE;
5155     ret->parent = ctxt->def;
5156     child = node->children;
5157     if (child == NULL) {
5158         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5159                    "xmlRelaxNGParseattribute: attribute has no children\n",
5160                    NULL, NULL);
5161         return (ret);
5162     }
5163     old_flags = ctxt->flags;
5164     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
5165     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5166     if (cur != NULL)
5167         child = child->next;
5168 
5169     if (child != NULL) {
5170         cur = xmlRelaxNGParsePattern(ctxt, child);
5171         if (cur != NULL) {
5172             switch (cur->type) {
5173                 case XML_RELAXNG_EMPTY:
5174                 case XML_RELAXNG_NOT_ALLOWED:
5175                 case XML_RELAXNG_TEXT:
5176                 case XML_RELAXNG_ELEMENT:
5177                 case XML_RELAXNG_DATATYPE:
5178                 case XML_RELAXNG_VALUE:
5179                 case XML_RELAXNG_LIST:
5180                 case XML_RELAXNG_REF:
5181                 case XML_RELAXNG_PARENTREF:
5182                 case XML_RELAXNG_EXTERNALREF:
5183                 case XML_RELAXNG_DEF:
5184                 case XML_RELAXNG_ONEORMORE:
5185                 case XML_RELAXNG_ZEROORMORE:
5186                 case XML_RELAXNG_OPTIONAL:
5187                 case XML_RELAXNG_CHOICE:
5188                 case XML_RELAXNG_GROUP:
5189                 case XML_RELAXNG_INTERLEAVE:
5190                 case XML_RELAXNG_ATTRIBUTE:
5191                     ret->content = cur;
5192                     cur->parent = ret;
5193                     break;
5194                 case XML_RELAXNG_START:
5195                 case XML_RELAXNG_PARAM:
5196                 case XML_RELAXNG_EXCEPT:
5197                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5198                                "attribute has invalid content\n", NULL,
5199                                NULL);
5200                     break;
5201                 case XML_RELAXNG_NOOP:
5202                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5203                                "RNG Internal error, noop found in attribute\n",
5204                                NULL, NULL);
5205                     break;
5206             }
5207         }
5208         child = child->next;
5209     }
5210     if (child != NULL) {
5211         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5212                    "attribute has multiple children\n", NULL, NULL);
5213     }
5214     ctxt->flags = old_flags;
5215     return (ret);
5216 }
5217 
5218 /**
5219  * xmlRelaxNGParseExceptNameClass:
5220  * @ctxt:  a Relax-NG parser context
5221  * @node:  the except node
5222  * @attr:  1 if within an attribute, 0 if within an element
5223  *
5224  * parse the content of a RelaxNG nameClass node.
5225  *
5226  * Returns the definition pointer or NULL in case of error.
5227  */
5228 static xmlRelaxNGDefinePtr
xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node,int attr)5229 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
5230                                xmlNodePtr node, int attr)
5231 {
5232     xmlRelaxNGDefinePtr ret, cur, last = NULL;
5233     xmlNodePtr child;
5234 
5235     if (!IS_RELAXNG(node, "except")) {
5236         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5237                    "Expecting an except node\n", NULL, NULL);
5238         return (NULL);
5239     }
5240     if (node->next != NULL) {
5241         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5242                    "exceptNameClass allows only a single except node\n",
5243                    NULL, NULL);
5244     }
5245     if (node->children == NULL) {
5246         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5247                    NULL, NULL);
5248         return (NULL);
5249     }
5250 
5251     ret = xmlRelaxNGNewDefine(ctxt, node);
5252     if (ret == NULL)
5253         return (NULL);
5254     ret->type = XML_RELAXNG_EXCEPT;
5255     child = node->children;
5256     while (child != NULL) {
5257         cur = xmlRelaxNGNewDefine(ctxt, child);
5258         if (cur == NULL)
5259             break;
5260         if (attr)
5261             cur->type = XML_RELAXNG_ATTRIBUTE;
5262         else
5263             cur->type = XML_RELAXNG_ELEMENT;
5264 
5265         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5266             if (last == NULL) {
5267                 ret->content = cur;
5268             } else {
5269                 last->next = cur;
5270             }
5271             last = cur;
5272         }
5273         child = child->next;
5274     }
5275 
5276     return (ret);
5277 }
5278 
5279 /**
5280  * xmlRelaxNGParseNameClass:
5281  * @ctxt:  a Relax-NG parser context
5282  * @node:  the nameClass node
5283  * @def:  the current definition
5284  *
5285  * parse the content of a RelaxNG nameClass node.
5286  *
5287  * Returns the definition pointer or NULL in case of error.
5288  */
5289 static xmlRelaxNGDefinePtr
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node,xmlRelaxNGDefinePtr def)5290 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5291                          xmlRelaxNGDefinePtr def)
5292 {
5293     xmlRelaxNGDefinePtr ret, tmp;
5294     xmlChar *val;
5295 
5296     ret = def;
5297     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5298         (IS_RELAXNG(node, "nsName"))) {
5299         if ((def->type != XML_RELAXNG_ELEMENT) &&
5300             (def->type != XML_RELAXNG_ATTRIBUTE)) {
5301             ret = xmlRelaxNGNewDefine(ctxt, node);
5302             if (ret == NULL)
5303                 return (NULL);
5304             ret->parent = def;
5305             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5306                 ret->type = XML_RELAXNG_ATTRIBUTE;
5307             else
5308                 ret->type = XML_RELAXNG_ELEMENT;
5309         }
5310     }
5311     if (IS_RELAXNG(node, "name")) {
5312         val = xmlNodeGetContent(node);
5313         xmlRelaxNGNormExtSpace(val);
5314         if (xmlValidateNCName(val, 0)) {
5315 	    if (node->parent != NULL)
5316 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5317 			   "Element %s name '%s' is not an NCName\n",
5318 			   node->parent->name, val);
5319 	    else
5320 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5321 			   "name '%s' is not an NCName\n",
5322 			   val, NULL);
5323         }
5324         ret->name = val;
5325         val = xmlGetProp(node, BAD_CAST "ns");
5326         ret->ns = val;
5327         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5328             (val != NULL) &&
5329             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5330 	    xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5331                         "Attribute with namespace '%s' is not allowed\n",
5332                         val, NULL);
5333         }
5334         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5335             (val != NULL) &&
5336             (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5337 	    xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5338                        "Attribute with QName 'xmlns' is not allowed\n",
5339                        val, NULL);
5340         }
5341     } else if (IS_RELAXNG(node, "anyName")) {
5342         ret->name = NULL;
5343         ret->ns = NULL;
5344         if (node->children != NULL) {
5345             ret->nameClass =
5346                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5347                                                (def->type ==
5348                                                 XML_RELAXNG_ATTRIBUTE));
5349         }
5350     } else if (IS_RELAXNG(node, "nsName")) {
5351         ret->name = NULL;
5352         ret->ns = xmlGetProp(node, BAD_CAST "ns");
5353         if (ret->ns == NULL) {
5354             xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5355                        "nsName has no ns attribute\n", NULL, NULL);
5356         }
5357         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5358             (ret->ns != NULL) &&
5359             (xmlStrEqual
5360              (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5361             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5362                        "Attribute with namespace '%s' is not allowed\n",
5363                        ret->ns, NULL);
5364         }
5365         if (node->children != NULL) {
5366             ret->nameClass =
5367                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5368                                                (def->type ==
5369                                                 XML_RELAXNG_ATTRIBUTE));
5370         }
5371     } else if (IS_RELAXNG(node, "choice")) {
5372         xmlNodePtr child;
5373         xmlRelaxNGDefinePtr last = NULL;
5374 
5375         if (def->type == XML_RELAXNG_CHOICE) {
5376             ret = def;
5377         } else {
5378             ret = xmlRelaxNGNewDefine(ctxt, node);
5379             if (ret == NULL)
5380                 return (NULL);
5381             ret->parent = def;
5382             ret->type = XML_RELAXNG_CHOICE;
5383         }
5384 
5385         if (node->children == NULL) {
5386             xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5387                        "Element choice is empty\n", NULL, NULL);
5388         } else {
5389 
5390             child = node->children;
5391             while (child != NULL) {
5392                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5393                 if (tmp != NULL) {
5394                     if (last == NULL) {
5395                         last = tmp;
5396                     } else {
5397                         last->next = tmp;
5398                         last = tmp;
5399                     }
5400                 }
5401                 child = child->next;
5402             }
5403         }
5404     } else {
5405         xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5406                    "expecting name, anyName, nsName or choice : got %s\n",
5407                    (node == NULL ? (const xmlChar *) "nothing" : node->name),
5408 		   NULL);
5409         return (NULL);
5410     }
5411     if (ret != def) {
5412         if (def->nameClass == NULL) {
5413             def->nameClass = ret;
5414         } else {
5415             tmp = def->nameClass;
5416             while (tmp->next != NULL) {
5417                 tmp = tmp->next;
5418             }
5419             tmp->next = ret;
5420         }
5421     }
5422     return (ret);
5423 }
5424 
5425 /**
5426  * xmlRelaxNGParseElement:
5427  * @ctxt:  a Relax-NG parser context
5428  * @node:  the element node
5429  *
5430  * parse the content of a RelaxNG element node.
5431  *
5432  * Returns the definition pointer or NULL in case of error.
5433  */
5434 static xmlRelaxNGDefinePtr
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)5435 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5436 {
5437     xmlRelaxNGDefinePtr ret, cur, last;
5438     xmlNodePtr child;
5439     const xmlChar *olddefine;
5440 
5441     ret = xmlRelaxNGNewDefine(ctxt, node);
5442     if (ret == NULL)
5443         return (NULL);
5444     ret->type = XML_RELAXNG_ELEMENT;
5445     ret->parent = ctxt->def;
5446     child = node->children;
5447     if (child == NULL) {
5448         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5449                    "xmlRelaxNGParseElement: element has no children\n",
5450                    NULL, NULL);
5451         return (ret);
5452     }
5453     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5454     if (cur != NULL)
5455         child = child->next;
5456 
5457     if (child == NULL) {
5458         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5459                    "xmlRelaxNGParseElement: element has no content\n",
5460                    NULL, NULL);
5461         return (ret);
5462     }
5463     olddefine = ctxt->define;
5464     ctxt->define = NULL;
5465     last = NULL;
5466     while (child != NULL) {
5467         cur = xmlRelaxNGParsePattern(ctxt, child);
5468         if (cur != NULL) {
5469             cur->parent = ret;
5470             switch (cur->type) {
5471                 case XML_RELAXNG_EMPTY:
5472                 case XML_RELAXNG_NOT_ALLOWED:
5473                 case XML_RELAXNG_TEXT:
5474                 case XML_RELAXNG_ELEMENT:
5475                 case XML_RELAXNG_DATATYPE:
5476                 case XML_RELAXNG_VALUE:
5477                 case XML_RELAXNG_LIST:
5478                 case XML_RELAXNG_REF:
5479                 case XML_RELAXNG_PARENTREF:
5480                 case XML_RELAXNG_EXTERNALREF:
5481                 case XML_RELAXNG_DEF:
5482                 case XML_RELAXNG_ZEROORMORE:
5483                 case XML_RELAXNG_ONEORMORE:
5484                 case XML_RELAXNG_OPTIONAL:
5485                 case XML_RELAXNG_CHOICE:
5486                 case XML_RELAXNG_GROUP:
5487                 case XML_RELAXNG_INTERLEAVE:
5488                     if (last == NULL) {
5489                         ret->content = last = cur;
5490                     } else {
5491                         if ((last->type == XML_RELAXNG_ELEMENT) &&
5492                             (ret->content == last)) {
5493                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
5494                             if (ret->content != NULL) {
5495                                 ret->content->type = XML_RELAXNG_GROUP;
5496                                 ret->content->content = last;
5497                             } else {
5498                                 ret->content = last;
5499                             }
5500                         }
5501                         last->next = cur;
5502                         last = cur;
5503                     }
5504                     break;
5505                 case XML_RELAXNG_ATTRIBUTE:
5506                     cur->next = ret->attrs;
5507                     ret->attrs = cur;
5508                     break;
5509                 case XML_RELAXNG_START:
5510                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5511                                "RNG Internal error, start found in element\n",
5512                                NULL, NULL);
5513                     break;
5514                 case XML_RELAXNG_PARAM:
5515                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5516                                "RNG Internal error, param found in element\n",
5517                                NULL, NULL);
5518                     break;
5519                 case XML_RELAXNG_EXCEPT:
5520                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5521                                "RNG Internal error, except found in element\n",
5522                                NULL, NULL);
5523                     break;
5524                 case XML_RELAXNG_NOOP:
5525                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5526                                "RNG Internal error, noop found in element\n",
5527                                NULL, NULL);
5528                     break;
5529             }
5530         }
5531         child = child->next;
5532     }
5533     ctxt->define = olddefine;
5534     return (ret);
5535 }
5536 
5537 /**
5538  * xmlRelaxNGParsePatterns:
5539  * @ctxt:  a Relax-NG parser context
5540  * @nodes:  list of nodes
5541  * @group:  use an implicit <group> for elements
5542  *
5543  * parse the content of a RelaxNG start node.
5544  *
5545  * Returns the definition pointer or NULL in case of error.
5546  */
5547 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr nodes,int group)5548 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5549                         int group)
5550 {
5551     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5552 
5553     parent = ctxt->def;
5554     while (nodes != NULL) {
5555         if (IS_RELAXNG(nodes, "element")) {
5556             cur = xmlRelaxNGParseElement(ctxt, nodes);
5557             if (cur == NULL)
5558                 return (NULL);
5559             if (def == NULL) {
5560                 def = last = cur;
5561             } else {
5562                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5563                     (def == last)) {
5564                     def = xmlRelaxNGNewDefine(ctxt, nodes);
5565                     if (def == NULL)
5566                         return (NULL);
5567                     def->type = XML_RELAXNG_GROUP;
5568                     def->content = last;
5569                 }
5570                 last->next = cur;
5571                 last = cur;
5572             }
5573             cur->parent = parent;
5574         } else {
5575             cur = xmlRelaxNGParsePattern(ctxt, nodes);
5576             if (cur != NULL) {
5577                 if (def == NULL) {
5578                     def = last = cur;
5579                 } else {
5580                     last->next = cur;
5581                     last = cur;
5582                 }
5583             }
5584         }
5585         nodes = nodes->next;
5586     }
5587     return (def);
5588 }
5589 
5590 /**
5591  * xmlRelaxNGParseStart:
5592  * @ctxt:  a Relax-NG parser context
5593  * @nodes:  start children nodes
5594  *
5595  * parse the content of a RelaxNG start node.
5596  *
5597  * Returns 0 in case of success, -1 in case of error
5598  */
5599 static int
xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr nodes)5600 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5601 {
5602     int ret = 0;
5603     xmlRelaxNGDefinePtr def = NULL, last;
5604 
5605     if (nodes == NULL) {
5606         xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5607                    NULL, NULL);
5608         return (-1);
5609     }
5610     if (IS_RELAXNG(nodes, "empty")) {
5611         def = xmlRelaxNGNewDefine(ctxt, nodes);
5612         if (def == NULL)
5613             return (-1);
5614         def->type = XML_RELAXNG_EMPTY;
5615         if (nodes->children != NULL) {
5616             xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5617                        "element empty is not empty\n", NULL, NULL);
5618         }
5619     } else if (IS_RELAXNG(nodes, "notAllowed")) {
5620         def = xmlRelaxNGNewDefine(ctxt, nodes);
5621         if (def == NULL)
5622             return (-1);
5623         def->type = XML_RELAXNG_NOT_ALLOWED;
5624         if (nodes->children != NULL) {
5625             xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5626                        "element notAllowed is not empty\n", NULL, NULL);
5627         }
5628     } else {
5629         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5630     }
5631     if (ctxt->grammar->start != NULL) {
5632         last = ctxt->grammar->start;
5633         while (last->next != NULL)
5634             last = last->next;
5635         last->next = def;
5636     } else {
5637         ctxt->grammar->start = def;
5638     }
5639     nodes = nodes->next;
5640     if (nodes != NULL) {
5641         xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5642                    "start more than one children\n", NULL, NULL);
5643         return (-1);
5644     }
5645     return (ret);
5646 }
5647 
5648 /**
5649  * xmlRelaxNGParseGrammarContent:
5650  * @ctxt:  a Relax-NG parser context
5651  * @nodes:  grammar children nodes
5652  *
5653  * parse the content of a RelaxNG grammar node.
5654  *
5655  * Returns 0 in case of success, -1 in case of error
5656  */
5657 static int
xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr nodes)5658 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5659                               xmlNodePtr nodes)
5660 {
5661     int ret = 0, tmp;
5662 
5663     if (nodes == NULL) {
5664         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5665                    "grammar has no children\n", NULL, NULL);
5666         return (-1);
5667     }
5668     while (nodes != NULL) {
5669         if (IS_RELAXNG(nodes, "start")) {
5670             if (nodes->children == NULL) {
5671                 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5672                            "start has no children\n", NULL, NULL);
5673             } else {
5674                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5675                 if (tmp != 0)
5676                     ret = -1;
5677             }
5678         } else if (IS_RELAXNG(nodes, "define")) {
5679             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5680             if (tmp != 0)
5681                 ret = -1;
5682         } else if (IS_RELAXNG(nodes, "include")) {
5683             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5684             if (tmp != 0)
5685                 ret = -1;
5686         } else {
5687             xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5688                        "grammar has unexpected child %s\n", nodes->name,
5689                        NULL);
5690             ret = -1;
5691         }
5692         nodes = nodes->next;
5693     }
5694     return (ret);
5695 }
5696 
5697 /**
5698  * xmlRelaxNGCheckReference:
5699  * @ref:  the ref
5700  * @ctxt:  a Relax-NG parser context
5701  * @name:  the name associated to the defines
5702  *
5703  * Applies the 4.17. combine attribute rule for all the define
5704  * element of a given grammar using the same name.
5705  */
5706 static void
xmlRelaxNGCheckReference(void * payload,void * data,const xmlChar * name)5707 xmlRelaxNGCheckReference(void *payload, void *data, const xmlChar * name)
5708 {
5709     xmlRelaxNGDefinePtr ref = (xmlRelaxNGDefinePtr) payload;
5710     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5711     xmlRelaxNGGrammarPtr grammar;
5712     xmlRelaxNGDefinePtr def, cur;
5713 
5714     /*
5715      * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5716      */
5717     if (ref->dflags & IS_EXTERNAL_REF)
5718         return;
5719 
5720     grammar = ctxt->grammar;
5721     if (grammar == NULL) {
5722         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5723                    "Internal error: no grammar in CheckReference %s\n",
5724                    name, NULL);
5725         return;
5726     }
5727     if (ref->content != NULL) {
5728         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5729                    "Internal error: reference has content in CheckReference %s\n",
5730                    name, NULL);
5731         return;
5732     }
5733     if (grammar->defs != NULL) {
5734         def = xmlHashLookup(grammar->defs, name);
5735         if (def != NULL) {
5736             cur = ref;
5737             while (cur != NULL) {
5738                 cur->content = def;
5739                 cur = cur->nextHash;
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     } else {
5747         xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5748                    "Reference %s has no matching definition\n", name,
5749                    NULL);
5750     }
5751 }
5752 
5753 /**
5754  * xmlRelaxNGCheckCombine:
5755  * @define:  the define(s) list
5756  * @ctxt:  a Relax-NG parser context
5757  * @name:  the name associated to the defines
5758  *
5759  * Applies the 4.17. combine attribute rule for all the define
5760  * element of a given grammar using the same name.
5761  */
5762 static void
xmlRelaxNGCheckCombine(void * payload,void * data,const xmlChar * name)5763 xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name)
5764 {
5765     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) payload;
5766     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5767     xmlChar *combine;
5768     int choiceOrInterleave = -1;
5769     int missing = 0;
5770     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5771 
5772     if (define->nextHash == NULL)
5773         return;
5774     cur = define;
5775     while (cur != NULL) {
5776         combine = xmlGetProp(cur->node, BAD_CAST "combine");
5777         if (combine != NULL) {
5778             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5779                 if (choiceOrInterleave == -1)
5780                     choiceOrInterleave = 1;
5781                 else if (choiceOrInterleave == 0) {
5782                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5783                                "Defines for %s use both 'choice' and 'interleave'\n",
5784                                name, NULL);
5785                 }
5786             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5787                 if (choiceOrInterleave == -1)
5788                     choiceOrInterleave = 0;
5789                 else if (choiceOrInterleave == 1) {
5790                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5791                                "Defines for %s use both 'choice' and 'interleave'\n",
5792                                name, NULL);
5793                 }
5794             } else {
5795                 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5796                            "Defines for %s use unknown combine value '%s''\n",
5797                            name, combine);
5798             }
5799             xmlFree(combine);
5800         } else {
5801             if (missing == 0)
5802                 missing = 1;
5803             else {
5804                 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5805                            "Some defines for %s needs the combine attribute\n",
5806                            name, NULL);
5807             }
5808         }
5809 
5810         cur = cur->nextHash;
5811     }
5812 #ifdef DEBUG
5813     xmlGenericError(xmlGenericErrorContext,
5814                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5815                     name, choiceOrInterleave);
5816 #endif
5817     if (choiceOrInterleave == -1)
5818         choiceOrInterleave = 0;
5819     cur = xmlRelaxNGNewDefine(ctxt, define->node);
5820     if (cur == NULL)
5821         return;
5822     if (choiceOrInterleave == 0)
5823         cur->type = XML_RELAXNG_INTERLEAVE;
5824     else
5825         cur->type = XML_RELAXNG_CHOICE;
5826     tmp = define;
5827     last = NULL;
5828     while (tmp != NULL) {
5829         if (tmp->content != NULL) {
5830             if (tmp->content->next != NULL) {
5831                 /*
5832                  * we need first to create a wrapper.
5833                  */
5834                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5835                 if (tmp2 == NULL)
5836                     break;
5837                 tmp2->type = XML_RELAXNG_GROUP;
5838                 tmp2->content = tmp->content;
5839             } else {
5840                 tmp2 = tmp->content;
5841             }
5842             if (last == NULL) {
5843                 cur->content = tmp2;
5844             } else {
5845                 last->next = tmp2;
5846             }
5847             last = tmp2;
5848         }
5849         tmp->content = cur;
5850         tmp = tmp->nextHash;
5851     }
5852     define->content = cur;
5853     if (choiceOrInterleave == 0) {
5854         if (ctxt->interleaves == NULL)
5855             ctxt->interleaves = xmlHashCreate(10);
5856         if (ctxt->interleaves == NULL) {
5857             xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5858                        "Failed to create interleaves hash table\n", NULL,
5859                        NULL);
5860         } else {
5861             char tmpname[32];
5862 
5863             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5864             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5865                 0) {
5866                 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5867                            "Failed to add %s to hash table\n",
5868 			   (const xmlChar *) tmpname, NULL);
5869             }
5870         }
5871     }
5872 }
5873 
5874 /**
5875  * xmlRelaxNGCombineStart:
5876  * @ctxt:  a Relax-NG parser context
5877  * @grammar:  the grammar
5878  *
5879  * Applies the 4.17. combine rule for all the start
5880  * element of a given grammar.
5881  */
5882 static void
xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGGrammarPtr grammar)5883 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5884                        xmlRelaxNGGrammarPtr grammar)
5885 {
5886     xmlRelaxNGDefinePtr starts;
5887     xmlChar *combine;
5888     int choiceOrInterleave = -1;
5889     int missing = 0;
5890     xmlRelaxNGDefinePtr cur;
5891 
5892     starts = grammar->start;
5893     if ((starts == NULL) || (starts->next == NULL))
5894         return;
5895     cur = starts;
5896     while (cur != NULL) {
5897         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5898             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5899             combine = NULL;
5900             xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5901                        "Internal error: start element not found\n", NULL,
5902                        NULL);
5903         } else {
5904             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5905         }
5906 
5907         if (combine != NULL) {
5908             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5909                 if (choiceOrInterleave == -1)
5910                     choiceOrInterleave = 1;
5911                 else if (choiceOrInterleave == 0) {
5912                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5913                                "<start> use both 'choice' and 'interleave'\n",
5914                                NULL, NULL);
5915                 }
5916             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5917                 if (choiceOrInterleave == -1)
5918                     choiceOrInterleave = 0;
5919                 else if (choiceOrInterleave == 1) {
5920                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5921                                "<start> use both 'choice' and 'interleave'\n",
5922                                NULL, NULL);
5923                 }
5924             } else {
5925                 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5926                            "<start> uses unknown combine value '%s''\n",
5927                            combine, NULL);
5928             }
5929             xmlFree(combine);
5930         } else {
5931             if (missing == 0)
5932                 missing = 1;
5933             else {
5934                 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5935                            "Some <start> element miss the combine attribute\n",
5936                            NULL, NULL);
5937             }
5938         }
5939 
5940         cur = cur->next;
5941     }
5942 #ifdef DEBUG
5943     xmlGenericError(xmlGenericErrorContext,
5944                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5945                     choiceOrInterleave);
5946 #endif
5947     if (choiceOrInterleave == -1)
5948         choiceOrInterleave = 0;
5949     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5950     if (cur == NULL)
5951         return;
5952     if (choiceOrInterleave == 0)
5953         cur->type = XML_RELAXNG_INTERLEAVE;
5954     else
5955         cur->type = XML_RELAXNG_CHOICE;
5956     cur->content = grammar->start;
5957     grammar->start = cur;
5958     if (choiceOrInterleave == 0) {
5959         if (ctxt->interleaves == NULL)
5960             ctxt->interleaves = xmlHashCreate(10);
5961         if (ctxt->interleaves == NULL) {
5962             xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5963                        "Failed to create interleaves hash table\n", NULL,
5964                        NULL);
5965         } else {
5966             char tmpname[32];
5967 
5968             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5969             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5970                 0) {
5971                 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5972                            "Failed to add %s to hash table\n",
5973 			   (const xmlChar *) tmpname, NULL);
5974             }
5975         }
5976     }
5977 }
5978 
5979 /**
5980  * xmlRelaxNGCheckCycles:
5981  * @ctxt:  a Relax-NG parser context
5982  * @nodes:  grammar children nodes
5983  * @depth:  the counter
5984  *
5985  * Check for cycles.
5986  *
5987  * Returns 0 if check passed, and -1 in case of error
5988  */
5989 static int
xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr cur,int depth)5990 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5991                       xmlRelaxNGDefinePtr cur, int depth)
5992 {
5993     int ret = 0;
5994 
5995     while ((ret == 0) && (cur != NULL)) {
5996         if ((cur->type == XML_RELAXNG_REF) ||
5997             (cur->type == XML_RELAXNG_PARENTREF)) {
5998             if (cur->depth == -1) {
5999                 cur->depth = depth;
6000                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
6001                 cur->depth = -2;
6002             } else if (depth == cur->depth) {
6003                 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
6004                            "Detected a cycle in %s references\n",
6005                            cur->name, NULL);
6006                 return (-1);
6007             }
6008         } else if (cur->type == XML_RELAXNG_ELEMENT) {
6009             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
6010         } else {
6011             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
6012         }
6013         cur = cur->next;
6014     }
6015     return (ret);
6016 }
6017 
6018 /**
6019  * xmlRelaxNGTryUnlink:
6020  * @ctxt:  a Relax-NG parser context
6021  * @cur:  the definition to unlink
6022  * @parent:  the parent definition
6023  * @prev:  the previous sibling definition
6024  *
6025  * Try to unlink a definition. If not possible make it a NOOP
6026  *
6027  * Returns the new prev definition
6028  */
6029 static xmlRelaxNGDefinePtr
xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlRelaxNGDefinePtr cur,xmlRelaxNGDefinePtr parent,xmlRelaxNGDefinePtr prev)6030 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
6031                     xmlRelaxNGDefinePtr cur,
6032                     xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
6033 {
6034     if (prev != NULL) {
6035         prev->next = cur->next;
6036     } else {
6037         if (parent != NULL) {
6038             if (parent->content == cur)
6039                 parent->content = cur->next;
6040             else if (parent->attrs == cur)
6041                 parent->attrs = cur->next;
6042             else if (parent->nameClass == cur)
6043                 parent->nameClass = cur->next;
6044         } else {
6045             cur->type = XML_RELAXNG_NOOP;
6046             prev = cur;
6047         }
6048     }
6049     return (prev);
6050 }
6051 
6052 /**
6053  * xmlRelaxNGSimplify:
6054  * @ctxt:  a Relax-NG parser context
6055  * @nodes:  grammar children nodes
6056  *
6057  * Check for simplification of empty and notAllowed
6058  */
6059 static void
xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr cur,xmlRelaxNGDefinePtr parent)6060 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
6061                    xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
6062 {
6063     xmlRelaxNGDefinePtr prev = NULL;
6064 
6065     while (cur != NULL) {
6066         if ((cur->type == XML_RELAXNG_REF) ||
6067             (cur->type == XML_RELAXNG_PARENTREF)) {
6068             if (cur->depth != -3) {
6069                 cur->depth = -3;
6070                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6071             }
6072         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6073             cur->parent = parent;
6074             if ((parent != NULL) &&
6075                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6076                  (parent->type == XML_RELAXNG_LIST) ||
6077                  (parent->type == XML_RELAXNG_GROUP) ||
6078                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
6079                  (parent->type == XML_RELAXNG_ONEORMORE) ||
6080                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6081                 parent->type = XML_RELAXNG_NOT_ALLOWED;
6082                 break;
6083             }
6084             if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
6085                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6086             } else
6087                 prev = cur;
6088         } else if (cur->type == XML_RELAXNG_EMPTY) {
6089             cur->parent = parent;
6090             if ((parent != NULL) &&
6091                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6092                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
6093                 parent->type = XML_RELAXNG_EMPTY;
6094                 break;
6095             }
6096             if ((parent != NULL) &&
6097                 ((parent->type == XML_RELAXNG_GROUP) ||
6098                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
6099                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6100             } else
6101                 prev = cur;
6102         } else {
6103             cur->parent = parent;
6104             if (cur->content != NULL)
6105                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6106             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
6107                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
6108             if (cur->nameClass != NULL)
6109                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
6110             /*
6111              * On Elements, try to move attribute only generating rules on
6112              * the attrs rules.
6113              */
6114             if (cur->type == XML_RELAXNG_ELEMENT) {
6115                 int attronly;
6116                 xmlRelaxNGDefinePtr tmp, pre;
6117 
6118                 while (cur->content != NULL) {
6119                     attronly =
6120                         xmlRelaxNGGenerateAttributes(ctxt, cur->content);
6121                     if (attronly == 1) {
6122                         /*
6123                          * migrate cur->content to attrs
6124                          */
6125                         tmp = cur->content;
6126                         cur->content = tmp->next;
6127                         tmp->next = cur->attrs;
6128                         cur->attrs = tmp;
6129                     } else {
6130                         /*
6131                          * cur->content can generate elements or text
6132                          */
6133                         break;
6134                     }
6135                 }
6136                 pre = cur->content;
6137                 while ((pre != NULL) && (pre->next != NULL)) {
6138                     tmp = pre->next;
6139                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6140                     if (attronly == 1) {
6141                         /*
6142                          * migrate tmp to attrs
6143                          */
6144                         pre->next = tmp->next;
6145                         tmp->next = cur->attrs;
6146                         cur->attrs = tmp;
6147                     } else {
6148                         pre = tmp;
6149                     }
6150                 }
6151             }
6152             /*
6153              * This may result in a simplification
6154              */
6155             if ((cur->type == XML_RELAXNG_GROUP) ||
6156                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6157                 if (cur->content == NULL)
6158                     cur->type = XML_RELAXNG_EMPTY;
6159                 else if (cur->content->next == NULL) {
6160                     if ((parent == NULL) && (prev == NULL)) {
6161                         cur->type = XML_RELAXNG_NOOP;
6162                     } else if (prev == NULL) {
6163                         parent->content = cur->content;
6164                         cur->content->next = cur->next;
6165                         cur = cur->content;
6166                     } else {
6167                         cur->content->next = cur->next;
6168                         prev->next = cur->content;
6169                         cur = cur->content;
6170                     }
6171                 }
6172             }
6173             /*
6174              * the current node may have been transformed back
6175              */
6176             if ((cur->type == XML_RELAXNG_EXCEPT) &&
6177                 (cur->content != NULL) &&
6178                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6179                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6180             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6181                 if ((parent != NULL) &&
6182                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6183                      (parent->type == XML_RELAXNG_LIST) ||
6184                      (parent->type == XML_RELAXNG_GROUP) ||
6185                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6186                      (parent->type == XML_RELAXNG_ONEORMORE) ||
6187                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6188                     parent->type = XML_RELAXNG_NOT_ALLOWED;
6189                     break;
6190                 }
6191                 if ((parent != NULL) &&
6192                     (parent->type == XML_RELAXNG_CHOICE)) {
6193                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6194                 } else
6195                     prev = cur;
6196             } else if (cur->type == XML_RELAXNG_EMPTY) {
6197                 if ((parent != NULL) &&
6198                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
6199                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
6200                     parent->type = XML_RELAXNG_EMPTY;
6201                     break;
6202                 }
6203                 if ((parent != NULL) &&
6204                     ((parent->type == XML_RELAXNG_GROUP) ||
6205                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
6206                      (parent->type == XML_RELAXNG_CHOICE))) {
6207                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6208                 } else
6209                     prev = cur;
6210             } else {
6211                 prev = cur;
6212             }
6213         }
6214         cur = cur->next;
6215     }
6216 }
6217 
6218 /**
6219  * xmlRelaxNGGroupContentType:
6220  * @ct1:  the first content type
6221  * @ct2:  the second content type
6222  *
6223  * Try to group 2 content types
6224  *
6225  * Returns the content type
6226  */
6227 static xmlRelaxNGContentType
xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,xmlRelaxNGContentType ct2)6228 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6229                            xmlRelaxNGContentType ct2)
6230 {
6231     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6232         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6233         return (XML_RELAXNG_CONTENT_ERROR);
6234     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6235         return (ct2);
6236     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6237         return (ct1);
6238     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6239         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6240         return (XML_RELAXNG_CONTENT_COMPLEX);
6241     return (XML_RELAXNG_CONTENT_ERROR);
6242 }
6243 
6244 /**
6245  * xmlRelaxNGMaxContentType:
6246  * @ct1:  the first content type
6247  * @ct2:  the second content type
6248  *
6249  * Compute the max content-type
6250  *
6251  * Returns the content type
6252  */
6253 static xmlRelaxNGContentType
xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,xmlRelaxNGContentType ct2)6254 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6255                          xmlRelaxNGContentType ct2)
6256 {
6257     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6258         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6259         return (XML_RELAXNG_CONTENT_ERROR);
6260     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6261         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6262         return (XML_RELAXNG_CONTENT_SIMPLE);
6263     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6264         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6265         return (XML_RELAXNG_CONTENT_COMPLEX);
6266     return (XML_RELAXNG_CONTENT_EMPTY);
6267 }
6268 
6269 /**
6270  * xmlRelaxNGCheckRules:
6271  * @ctxt:  a Relax-NG parser context
6272  * @cur:  the current definition
6273  * @flags:  some accumulated flags
6274  * @ptype:  the parent type
6275  *
6276  * Check for rules in section 7.1 and 7.2
6277  *
6278  * Returns the content type of @cur
6279  */
6280 static xmlRelaxNGContentType
xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGDefinePtr cur,int flags,xmlRelaxNGType ptype)6281 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6282                      xmlRelaxNGDefinePtr cur, int flags,
6283                      xmlRelaxNGType ptype)
6284 {
6285     int nflags;
6286     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6287 
6288     while (cur != NULL) {
6289         ret = XML_RELAXNG_CONTENT_EMPTY;
6290         if ((cur->type == XML_RELAXNG_REF) ||
6291             (cur->type == XML_RELAXNG_PARENTREF)) {
6292            /*
6293             * This should actually be caught by list//element(ref) at the
6294             * element boundaries, c.f. Bug #159968 local refs are dropped
6295             * in step 4.19.
6296             */
6297 #if 0
6298             if (flags & XML_RELAXNG_IN_LIST) {
6299                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6300                            "Found forbidden pattern list//ref\n", NULL,
6301                            NULL);
6302             }
6303 #endif
6304             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6305                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6306                            "Found forbidden pattern data/except//ref\n",
6307                            NULL, NULL);
6308             }
6309             if (cur->content == NULL) {
6310                 if (cur->type == XML_RELAXNG_PARENTREF)
6311                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6312                                "Internal found no define for parent refs\n",
6313                                NULL, NULL);
6314                 else
6315                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6316                                "Internal found no define for ref %s\n",
6317                                (cur->name ? cur->name: BAD_CAST "null"), NULL);
6318             }
6319             if (cur->depth > -4) {
6320                 cur->depth = -4;
6321                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6322                                            flags, cur->type);
6323                 cur->depth = ret - 15;
6324             } else if (cur->depth == -4) {
6325                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6326             } else {
6327                 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6328             }
6329         } else if (cur->type == XML_RELAXNG_ELEMENT) {
6330             /*
6331              * The 7.3 Attribute derivation rule for groups is plugged there
6332              */
6333             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6334             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6335                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6336                            "Found forbidden pattern data/except//element(ref)\n",
6337                            NULL, NULL);
6338             }
6339             if (flags & XML_RELAXNG_IN_LIST) {
6340                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6341                            "Found forbidden pattern list//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             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6350                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6351                            "Found forbidden pattern attribute//element(ref)\n",
6352                            NULL, NULL);
6353             }
6354             /*
6355              * reset since in the simple form elements are only child
6356              * of grammar/define
6357              */
6358             nflags = 0;
6359             ret =
6360                 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6361             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6362                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6363                            "Element %s attributes have a content type error\n",
6364                            cur->name, NULL);
6365             }
6366             ret =
6367                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6368                                      cur->type);
6369             if (ret == XML_RELAXNG_CONTENT_ERROR) {
6370                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6371                            "Element %s has a content type error\n",
6372                            cur->name, NULL);
6373             } else {
6374                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6375             }
6376         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6377             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6378                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6379                            "Found forbidden pattern attribute//attribute\n",
6380                            NULL, NULL);
6381             }
6382             if (flags & XML_RELAXNG_IN_LIST) {
6383                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6384                            "Found forbidden pattern list//attribute\n",
6385                            NULL, NULL);
6386             }
6387             if (flags & XML_RELAXNG_IN_OOMGROUP) {
6388                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6389                            "Found forbidden pattern oneOrMore//group//attribute\n",
6390                            NULL, NULL);
6391             }
6392             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6393                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6394                            "Found forbidden pattern oneOrMore//interleave//attribute\n",
6395                            NULL, NULL);
6396             }
6397             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6398                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6399                            "Found forbidden pattern data/except//attribute\n",
6400                            NULL, NULL);
6401             }
6402             if (flags & XML_RELAXNG_IN_START) {
6403                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6404                            "Found forbidden pattern start//attribute\n",
6405                            NULL, NULL);
6406             }
6407             if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6408                 && cur->name == NULL
6409                 /* following is checking alternative name class readiness
6410                    in case it went the "choice" route */
6411                 && cur->nameClass == NULL) {
6412                 if (cur->ns == NULL) {
6413                     xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6414                                "Found anyName attribute without oneOrMore ancestor\n",
6415                                NULL, NULL);
6416                 } else {
6417                     xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6418                                "Found nsName attribute without oneOrMore ancestor\n",
6419                                NULL, NULL);
6420                 }
6421             }
6422             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6423             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6424             ret = XML_RELAXNG_CONTENT_EMPTY;
6425         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6426                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
6427             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6428                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6429                            "Found forbidden pattern data/except//oneOrMore\n",
6430                            NULL, NULL);
6431             }
6432             if (flags & XML_RELAXNG_IN_START) {
6433                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6434                            "Found forbidden pattern start//oneOrMore\n",
6435                            NULL, NULL);
6436             }
6437             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6438             ret =
6439                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6440                                      cur->type);
6441             ret = xmlRelaxNGGroupContentType(ret, ret);
6442         } else if (cur->type == XML_RELAXNG_LIST) {
6443             if (flags & XML_RELAXNG_IN_LIST) {
6444                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6445                            "Found forbidden pattern list//list\n", NULL,
6446                            NULL);
6447             }
6448             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6449                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6450                            "Found forbidden pattern data/except//list\n",
6451                            NULL, NULL);
6452             }
6453             if (flags & XML_RELAXNG_IN_START) {
6454                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6455                            "Found forbidden pattern start//list\n", NULL,
6456                            NULL);
6457             }
6458             nflags = flags | XML_RELAXNG_IN_LIST;
6459             ret =
6460                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6461                                      cur->type);
6462         } else if (cur->type == XML_RELAXNG_GROUP) {
6463             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6464                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6465                            "Found forbidden pattern data/except//group\n",
6466                            NULL, NULL);
6467             }
6468             if (flags & XML_RELAXNG_IN_START) {
6469                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6470                            "Found forbidden pattern start//group\n", NULL,
6471                            NULL);
6472             }
6473             if (flags & XML_RELAXNG_IN_ONEORMORE)
6474                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6475             else
6476                 nflags = flags;
6477             ret =
6478                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6479                                      cur->type);
6480             /*
6481              * The 7.3 Attribute derivation rule for groups is plugged there
6482              */
6483             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6484         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6485             if (flags & XML_RELAXNG_IN_LIST) {
6486                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6487                            "Found forbidden pattern list//interleave\n",
6488                            NULL, NULL);
6489             }
6490             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6491                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6492                            "Found forbidden pattern data/except//interleave\n",
6493                            NULL, NULL);
6494             }
6495             if (flags & XML_RELAXNG_IN_START) {
6496                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6497                            "Found forbidden pattern start//interleave\n",
6498                            NULL, NULL);
6499             }
6500             if (flags & XML_RELAXNG_IN_ONEORMORE)
6501                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6502             else
6503                 nflags = flags;
6504             ret =
6505                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6506                                      cur->type);
6507         } else if (cur->type == XML_RELAXNG_EXCEPT) {
6508             if ((cur->parent != NULL) &&
6509                 (cur->parent->type == XML_RELAXNG_DATATYPE))
6510                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6511             else
6512                 nflags = flags;
6513             ret =
6514                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6515                                      cur->type);
6516         } else if (cur->type == XML_RELAXNG_DATATYPE) {
6517             if (flags & XML_RELAXNG_IN_START) {
6518                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6519                            "Found forbidden pattern start//data\n", NULL,
6520                            NULL);
6521             }
6522             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6523             ret = XML_RELAXNG_CONTENT_SIMPLE;
6524         } else if (cur->type == XML_RELAXNG_VALUE) {
6525             if (flags & XML_RELAXNG_IN_START) {
6526                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6527                            "Found forbidden pattern start//value\n", NULL,
6528                            NULL);
6529             }
6530             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6531             ret = XML_RELAXNG_CONTENT_SIMPLE;
6532         } else if (cur->type == XML_RELAXNG_TEXT) {
6533             if (flags & XML_RELAXNG_IN_LIST) {
6534                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6535                            "Found forbidden pattern list//text\n", NULL,
6536                            NULL);
6537             }
6538             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6539                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6540                            "Found forbidden pattern data/except//text\n",
6541                            NULL, NULL);
6542             }
6543             if (flags & XML_RELAXNG_IN_START) {
6544                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6545                            "Found forbidden pattern start//text\n", NULL,
6546                            NULL);
6547             }
6548             ret = XML_RELAXNG_CONTENT_COMPLEX;
6549         } else if (cur->type == XML_RELAXNG_EMPTY) {
6550             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6551                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6552                            "Found forbidden pattern data/except//empty\n",
6553                            NULL, NULL);
6554             }
6555             if (flags & XML_RELAXNG_IN_START) {
6556                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6557                            "Found forbidden pattern start//empty\n", NULL,
6558                            NULL);
6559             }
6560             ret = XML_RELAXNG_CONTENT_EMPTY;
6561         } else if (cur->type == XML_RELAXNG_CHOICE) {
6562             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6563             ret =
6564                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6565         } else {
6566             ret =
6567                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6568         }
6569         cur = cur->next;
6570         if (ptype == XML_RELAXNG_GROUP) {
6571             val = xmlRelaxNGGroupContentType(val, ret);
6572         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6573             /*
6574              * TODO: scan complain that tmp is never used, seems on purpose
6575              *       need double-checking
6576              */
6577             tmp = xmlRelaxNGGroupContentType(val, ret);
6578             if (tmp != XML_RELAXNG_CONTENT_ERROR)
6579                 tmp = xmlRelaxNGMaxContentType(val, ret);
6580         } else if (ptype == XML_RELAXNG_CHOICE) {
6581             val = xmlRelaxNGMaxContentType(val, ret);
6582         } else if (ptype == XML_RELAXNG_LIST) {
6583             val = XML_RELAXNG_CONTENT_SIMPLE;
6584         } else if (ptype == XML_RELAXNG_EXCEPT) {
6585             if (ret == XML_RELAXNG_CONTENT_ERROR)
6586                 val = XML_RELAXNG_CONTENT_ERROR;
6587             else
6588                 val = XML_RELAXNG_CONTENT_SIMPLE;
6589         } else {
6590             val = xmlRelaxNGGroupContentType(val, ret);
6591         }
6592 
6593     }
6594     return (val);
6595 }
6596 
6597 /**
6598  * xmlRelaxNGParseGrammar:
6599  * @ctxt:  a Relax-NG parser context
6600  * @nodes:  grammar children nodes
6601  *
6602  * parse a Relax-NG <grammar> node
6603  *
6604  * Returns the internal xmlRelaxNGGrammarPtr built or
6605  *         NULL in case of error
6606  */
6607 static xmlRelaxNGGrammarPtr
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr nodes)6608 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6609 {
6610     xmlRelaxNGGrammarPtr ret, tmp, old;
6611 
6612 #ifdef DEBUG_GRAMMAR
6613     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6614 #endif
6615 
6616     ret = xmlRelaxNGNewGrammar(ctxt);
6617     if (ret == NULL)
6618         return (NULL);
6619 
6620     /*
6621      * Link the new grammar in the tree
6622      */
6623     ret->parent = ctxt->grammar;
6624     if (ctxt->grammar != NULL) {
6625         tmp = ctxt->grammar->children;
6626         if (tmp == NULL) {
6627             ctxt->grammar->children = ret;
6628         } else {
6629             while (tmp->next != NULL)
6630                 tmp = tmp->next;
6631             tmp->next = ret;
6632         }
6633     }
6634 
6635     old = ctxt->grammar;
6636     ctxt->grammar = ret;
6637     xmlRelaxNGParseGrammarContent(ctxt, nodes);
6638     ctxt->grammar = ret;
6639     if (ctxt->grammar == NULL) {
6640         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6641                    "Failed to parse <grammar> content\n", NULL, NULL);
6642     } else if (ctxt->grammar->start == NULL) {
6643         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6644                    "Element <grammar> has no <start>\n", NULL, NULL);
6645     }
6646 
6647     /*
6648      * Apply 4.17 merging rules to defines and starts
6649      */
6650     xmlRelaxNGCombineStart(ctxt, ret);
6651     if (ret->defs != NULL) {
6652         xmlHashScan(ret->defs, xmlRelaxNGCheckCombine, ctxt);
6653     }
6654 
6655     /*
6656      * link together defines and refs in this grammar
6657      */
6658     if (ret->refs != NULL) {
6659         xmlHashScan(ret->refs, xmlRelaxNGCheckReference, ctxt);
6660     }
6661 
6662 
6663     /* @@@@ */
6664 
6665     ctxt->grammar = old;
6666     return (ret);
6667 }
6668 
6669 /**
6670  * xmlRelaxNGParseDocument:
6671  * @ctxt:  a Relax-NG parser context
6672  * @node:  the root node of the RelaxNG schema
6673  *
6674  * parse a Relax-NG definition resource and build an internal
6675  * xmlRelaxNG structure which can be used to validate instances.
6676  *
6677  * Returns the internal XML RelaxNG structure built or
6678  *         NULL in case of error
6679  */
6680 static xmlRelaxNGPtr
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)6681 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6682 {
6683     xmlRelaxNGPtr schema = NULL;
6684     const xmlChar *olddefine;
6685     xmlRelaxNGGrammarPtr old;
6686 
6687     if ((ctxt == NULL) || (node == NULL))
6688         return (NULL);
6689 
6690     schema = xmlRelaxNGNewRelaxNG(ctxt);
6691     if (schema == NULL)
6692         return (NULL);
6693 
6694     olddefine = ctxt->define;
6695     ctxt->define = NULL;
6696     if (IS_RELAXNG(node, "grammar")) {
6697         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6698         if (schema->topgrammar == NULL) {
6699             xmlRelaxNGFree(schema);
6700             return (NULL);
6701         }
6702     } else {
6703         xmlRelaxNGGrammarPtr tmp, ret;
6704 
6705         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6706         if (schema->topgrammar == NULL) {
6707             xmlRelaxNGFree(schema);
6708             return (NULL);
6709         }
6710         /*
6711          * Link the new grammar in the tree
6712          */
6713         ret->parent = ctxt->grammar;
6714         if (ctxt->grammar != NULL) {
6715             tmp = ctxt->grammar->children;
6716             if (tmp == NULL) {
6717                 ctxt->grammar->children = ret;
6718             } else {
6719                 while (tmp->next != NULL)
6720                     tmp = tmp->next;
6721                 tmp->next = ret;
6722             }
6723         }
6724         old = ctxt->grammar;
6725         ctxt->grammar = ret;
6726         xmlRelaxNGParseStart(ctxt, node);
6727         if (old != NULL)
6728             ctxt->grammar = old;
6729     }
6730     ctxt->define = olddefine;
6731     if (schema->topgrammar->start != NULL) {
6732         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6733         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6734             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6735             while ((schema->topgrammar->start != NULL) &&
6736                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6737                    (schema->topgrammar->start->next != NULL))
6738                 schema->topgrammar->start =
6739                     schema->topgrammar->start->content;
6740             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6741                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6742         }
6743     }
6744 #ifdef DEBUG
6745     if (schema == NULL)
6746         xmlGenericError(xmlGenericErrorContext,
6747                         "xmlRelaxNGParseDocument() failed\n");
6748 #endif
6749 
6750     return (schema);
6751 }
6752 
6753 /************************************************************************
6754  *									*
6755  *			Reading RelaxNGs				*
6756  *									*
6757  ************************************************************************/
6758 
6759 /**
6760  * xmlRelaxNGNewParserCtxt:
6761  * @URL:  the location of the schema
6762  *
6763  * Create an XML RelaxNGs parse context for that file/resource expected
6764  * to contain an XML RelaxNGs file.
6765  *
6766  * Returns the parser context or NULL in case of error
6767  */
6768 xmlRelaxNGParserCtxtPtr
xmlRelaxNGNewParserCtxt(const char * URL)6769 xmlRelaxNGNewParserCtxt(const char *URL)
6770 {
6771     xmlRelaxNGParserCtxtPtr ret;
6772 
6773     if (URL == NULL)
6774         return (NULL);
6775 
6776     ret =
6777         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6778     if (ret == NULL) {
6779         xmlRngPErrMemory(NULL, "building parser\n");
6780         return (NULL);
6781     }
6782     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6783     ret->URL = xmlStrdup((const xmlChar *) URL);
6784     ret->error = xmlGenericError;
6785     ret->userData = xmlGenericErrorContext;
6786     return (ret);
6787 }
6788 
6789 /**
6790  * xmlRelaxNGNewMemParserCtxt:
6791  * @buffer:  a pointer to a char array containing the schemas
6792  * @size:  the size of the array
6793  *
6794  * Create an XML RelaxNGs parse context for that memory buffer expected
6795  * to contain an XML RelaxNGs file.
6796  *
6797  * Returns the parser context or NULL in case of error
6798  */
6799 xmlRelaxNGParserCtxtPtr
xmlRelaxNGNewMemParserCtxt(const char * buffer,int size)6800 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6801 {
6802     xmlRelaxNGParserCtxtPtr ret;
6803 
6804     if ((buffer == NULL) || (size <= 0))
6805         return (NULL);
6806 
6807     ret =
6808         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6809     if (ret == NULL) {
6810         xmlRngPErrMemory(NULL, "building parser\n");
6811         return (NULL);
6812     }
6813     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6814     ret->buffer = buffer;
6815     ret->size = size;
6816     ret->error = xmlGenericError;
6817     ret->userData = xmlGenericErrorContext;
6818     return (ret);
6819 }
6820 
6821 /**
6822  * xmlRelaxNGNewDocParserCtxt:
6823  * @doc:  a preparsed document tree
6824  *
6825  * Create an XML RelaxNGs parser context for that document.
6826  * Note: since the process of compiling a RelaxNG schemas modifies the
6827  *       document, the @doc parameter is duplicated internally.
6828  *
6829  * Returns the parser context or NULL in case of error
6830  */
6831 xmlRelaxNGParserCtxtPtr
xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)6832 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6833 {
6834     xmlRelaxNGParserCtxtPtr ret;
6835     xmlDocPtr copy;
6836 
6837     if (doc == NULL)
6838         return (NULL);
6839     copy = xmlCopyDoc(doc, 1);
6840     if (copy == NULL)
6841         return (NULL);
6842 
6843     ret =
6844         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6845     if (ret == NULL) {
6846         xmlRngPErrMemory(NULL, "building parser\n");
6847         xmlFreeDoc(copy);
6848         return (NULL);
6849     }
6850     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6851     ret->document = copy;
6852     ret->freedoc = 1;
6853     ret->userData = xmlGenericErrorContext;
6854     return (ret);
6855 }
6856 
6857 /**
6858  * xmlRelaxNGFreeParserCtxt:
6859  * @ctxt:  the schema parser context
6860  *
6861  * Free the resources associated to the schema parser context
6862  */
6863 void
xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)6864 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6865 {
6866     if (ctxt == NULL)
6867         return;
6868     if (ctxt->URL != NULL)
6869         xmlFree(ctxt->URL);
6870     if (ctxt->doc != NULL)
6871         xmlRelaxNGFreeDocument(ctxt->doc);
6872     if (ctxt->interleaves != NULL)
6873         xmlHashFree(ctxt->interleaves, NULL);
6874     if (ctxt->documents != NULL)
6875         xmlRelaxNGFreeDocumentList(ctxt->documents);
6876     if (ctxt->includes != NULL)
6877         xmlRelaxNGFreeIncludeList(ctxt->includes);
6878     if (ctxt->docTab != NULL)
6879         xmlFree(ctxt->docTab);
6880     if (ctxt->incTab != NULL)
6881         xmlFree(ctxt->incTab);
6882     if (ctxt->defTab != NULL) {
6883         int i;
6884 
6885         for (i = 0; i < ctxt->defNr; i++)
6886             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6887         xmlFree(ctxt->defTab);
6888     }
6889     if ((ctxt->document != NULL) && (ctxt->freedoc))
6890         xmlFreeDoc(ctxt->document);
6891     xmlFree(ctxt);
6892 }
6893 
6894 /**
6895  * xmlRelaxNGNormExtSpace:
6896  * @value:  a value
6897  *
6898  * Removes the leading and ending spaces of the value
6899  * The string is modified "in situ"
6900  */
6901 static void
xmlRelaxNGNormExtSpace(xmlChar * value)6902 xmlRelaxNGNormExtSpace(xmlChar * value)
6903 {
6904     xmlChar *start = value;
6905     xmlChar *cur = value;
6906 
6907     if (value == NULL)
6908         return;
6909 
6910     while (IS_BLANK_CH(*cur))
6911         cur++;
6912     if (cur == start) {
6913         do {
6914             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6915                 cur++;
6916             if (*cur == 0)
6917                 return;
6918             start = cur;
6919             while (IS_BLANK_CH(*cur))
6920                 cur++;
6921             if (*cur == 0) {
6922                 *start = 0;
6923                 return;
6924             }
6925         } while (1);
6926     } else {
6927         do {
6928             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6929                 *start++ = *cur++;
6930             if (*cur == 0) {
6931                 *start = 0;
6932                 return;
6933             }
6934             /* don't try to normalize the inner spaces */
6935             while (IS_BLANK_CH(*cur))
6936                 cur++;
6937             if (*cur == 0) {
6938                 *start = 0;
6939                 return;
6940             }
6941             *start++ = *cur++;
6942         } while (1);
6943     }
6944 }
6945 
6946 /**
6947  * xmlRelaxNGCleanupAttributes:
6948  * @ctxt:  a Relax-NG parser context
6949  * @node:  a Relax-NG node
6950  *
6951  * Check all the attributes on the given node
6952  */
6953 static void
xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr node)6954 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6955 {
6956     xmlAttrPtr cur, next;
6957 
6958     cur = node->properties;
6959     while (cur != NULL) {
6960         next = cur->next;
6961         if ((cur->ns == NULL) ||
6962             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6963             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6964                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6965                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6966                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6967                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6968                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6969                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6970                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6971                                "Attribute %s is not allowed on %s\n",
6972                                cur->name, node->name);
6973                 }
6974             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6975                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6976                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6977                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6978                                "Attribute %s is not allowed on %s\n",
6979                                cur->name, node->name);
6980                 }
6981             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6982                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6983                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6984                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6985                                "Attribute %s is not allowed on %s\n",
6986                                cur->name, node->name);
6987                 }
6988             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6989                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6990                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6991                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6992                                "Attribute %s is not allowed on %s\n",
6993                                cur->name, node->name);
6994                 }
6995             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6996                 xmlChar *val;
6997                 xmlURIPtr uri;
6998 
6999                 val = xmlNodeListGetString(node->doc, cur->children, 1);
7000                 if (val != NULL) {
7001                     if (val[0] != 0) {
7002                         uri = xmlParseURI((const char *) val);
7003                         if (uri == NULL) {
7004                             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
7005                                        "Attribute %s contains invalid URI %s\n",
7006                                        cur->name, val);
7007                         } else {
7008                             if (uri->scheme == NULL) {
7009                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
7010                                            "Attribute %s URI %s is not absolute\n",
7011                                            cur->name, val);
7012                             }
7013                             if (uri->fragment != NULL) {
7014                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
7015                                            "Attribute %s URI %s has a fragment ID\n",
7016                                            cur->name, val);
7017                             }
7018                             xmlFreeURI(uri);
7019                         }
7020                     }
7021                     xmlFree(val);
7022                 }
7023             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
7024                 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
7025                            "Unknown attribute %s on %s\n", cur->name,
7026                            node->name);
7027             }
7028         }
7029         cur = next;
7030     }
7031 }
7032 
7033 /**
7034  * xmlRelaxNGCleanupTree:
7035  * @ctxt:  a Relax-NG parser context
7036  * @root:  an xmlNodePtr subtree
7037  *
7038  * Cleanup the subtree from unwanted nodes for parsing, resolve
7039  * Include and externalRef lookups.
7040  */
7041 static void
xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt,xmlNodePtr root)7042 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
7043 {
7044     xmlNodePtr cur, delete;
7045 
7046     delete = NULL;
7047     cur = root;
7048     while (cur != NULL) {
7049         if (delete != NULL) {
7050             xmlUnlinkNode(delete);
7051             xmlFreeNode(delete);
7052             delete = NULL;
7053         }
7054         if (cur->type == XML_ELEMENT_NODE) {
7055             /*
7056              * Simplification 4.1. Annotations
7057              */
7058             if ((cur->ns == NULL) ||
7059                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
7060                 if ((cur->parent != NULL) &&
7061                     (cur->parent->type == XML_ELEMENT_NODE) &&
7062                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
7063                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
7064                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
7065                     xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
7066                                "element %s doesn't allow foreign elements\n",
7067                                cur->parent->name, NULL);
7068                 }
7069                 delete = cur;
7070                 goto skip_children;
7071             } else {
7072                 xmlRelaxNGCleanupAttributes(ctxt, cur);
7073                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
7074                     xmlChar *href, *ns, *base, *URL;
7075                     xmlRelaxNGDocumentPtr docu;
7076                     xmlNodePtr tmp;
7077 		    xmlURIPtr uri;
7078 
7079                     ns = xmlGetProp(cur, BAD_CAST "ns");
7080                     if (ns == NULL) {
7081                         tmp = cur->parent;
7082                         while ((tmp != NULL) &&
7083                                (tmp->type == XML_ELEMENT_NODE)) {
7084                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7085                             if (ns != NULL)
7086                                 break;
7087                             tmp = tmp->parent;
7088                         }
7089                     }
7090                     href = xmlGetProp(cur, BAD_CAST "href");
7091                     if (href == NULL) {
7092                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7093                                    "xmlRelaxNGParse: externalRef has no href attribute\n",
7094                                    NULL, NULL);
7095                         if (ns != NULL)
7096                             xmlFree(ns);
7097                         delete = cur;
7098                         goto skip_children;
7099                     }
7100 		    uri = xmlParseURI((const char *) href);
7101 		    if (uri == NULL) {
7102                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7103                                    "Incorrect URI for externalRef %s\n",
7104                                    href, NULL);
7105                         if (ns != NULL)
7106                             xmlFree(ns);
7107                         if (href != NULL)
7108                             xmlFree(href);
7109                         delete = cur;
7110                         goto skip_children;
7111 		    }
7112 		    if (uri->fragment != NULL) {
7113                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7114 			       "Fragment forbidden in URI for externalRef %s\n",
7115                                    href, NULL);
7116                         if (ns != NULL)
7117                             xmlFree(ns);
7118 		        xmlFreeURI(uri);
7119                         if (href != NULL)
7120                             xmlFree(href);
7121                         delete = cur;
7122                         goto skip_children;
7123 		    }
7124 		    xmlFreeURI(uri);
7125                     base = xmlNodeGetBase(cur->doc, cur);
7126                     URL = xmlBuildURI(href, base);
7127                     if (URL == NULL) {
7128                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7129                                    "Failed to compute URL for externalRef %s\n",
7130                                    href, NULL);
7131                         if (ns != NULL)
7132                             xmlFree(ns);
7133                         if (href != NULL)
7134                             xmlFree(href);
7135                         if (base != NULL)
7136                             xmlFree(base);
7137                         delete = cur;
7138                         goto skip_children;
7139                     }
7140                     if (href != NULL)
7141                         xmlFree(href);
7142                     if (base != NULL)
7143                         xmlFree(base);
7144                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
7145                     if (docu == NULL) {
7146                         xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
7147                                    "Failed to load externalRef %s\n", URL,
7148                                    NULL);
7149                         if (ns != NULL)
7150                             xmlFree(ns);
7151                         xmlFree(URL);
7152                         delete = cur;
7153                         goto skip_children;
7154                     }
7155                     if (ns != NULL)
7156                         xmlFree(ns);
7157                     xmlFree(URL);
7158                     cur->psvi = docu;
7159                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7160                     xmlChar *href, *ns, *base, *URL;
7161                     xmlRelaxNGIncludePtr incl;
7162                     xmlNodePtr tmp;
7163 
7164                     href = xmlGetProp(cur, BAD_CAST "href");
7165                     if (href == NULL) {
7166                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7167                                    "xmlRelaxNGParse: include has no href attribute\n",
7168                                    NULL, NULL);
7169                         delete = cur;
7170                         goto skip_children;
7171                     }
7172                     base = xmlNodeGetBase(cur->doc, cur);
7173                     URL = xmlBuildURI(href, base);
7174                     if (URL == NULL) {
7175                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7176                                    "Failed to compute URL for include %s\n",
7177                                    href, NULL);
7178                         if (href != NULL)
7179                             xmlFree(href);
7180                         if (base != NULL)
7181                             xmlFree(base);
7182                         delete = cur;
7183                         goto skip_children;
7184                     }
7185                     if (href != NULL)
7186                         xmlFree(href);
7187                     if (base != NULL)
7188                         xmlFree(base);
7189                     ns = xmlGetProp(cur, BAD_CAST "ns");
7190                     if (ns == NULL) {
7191                         tmp = cur->parent;
7192                         while ((tmp != NULL) &&
7193                                (tmp->type == XML_ELEMENT_NODE)) {
7194                             ns = xmlGetProp(tmp, BAD_CAST "ns");
7195                             if (ns != NULL)
7196                                 break;
7197                             tmp = tmp->parent;
7198                         }
7199                     }
7200                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7201                     if (ns != NULL)
7202                         xmlFree(ns);
7203                     if (incl == NULL) {
7204                         xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7205                                    "Failed to load include %s\n", URL,
7206                                    NULL);
7207                         xmlFree(URL);
7208                         delete = cur;
7209                         goto skip_children;
7210                     }
7211                     xmlFree(URL);
7212                     cur->psvi = incl;
7213                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7214                            (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7215                 {
7216                     xmlChar *name, *ns;
7217                     xmlNodePtr text = NULL;
7218 
7219                     /*
7220                      * Simplification 4.8. name attribute of element
7221                      * and attribute elements
7222                      */
7223                     name = xmlGetProp(cur, BAD_CAST "name");
7224                     if (name != NULL) {
7225                         if (cur->children == NULL) {
7226                             text =
7227                                 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7228                                             name);
7229                         } else {
7230                             xmlNodePtr node;
7231 
7232                             node = xmlNewDocNode(cur->doc, cur->ns,
7233 			                         BAD_CAST "name", NULL);
7234                             if (node != NULL) {
7235                                 xmlAddPrevSibling(cur->children, node);
7236                                 text = xmlNewDocText(node->doc, name);
7237                                 xmlAddChild(node, text);
7238                                 text = node;
7239                             }
7240                         }
7241                         if (text == NULL) {
7242                             xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7243                                        "Failed to create a name %s element\n",
7244                                        name, NULL);
7245                         }
7246                         xmlUnsetProp(cur, BAD_CAST "name");
7247                         xmlFree(name);
7248                         ns = xmlGetProp(cur, BAD_CAST "ns");
7249                         if (ns != NULL) {
7250                             if (text != NULL) {
7251                                 xmlSetProp(text, BAD_CAST "ns", ns);
7252                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7253                             }
7254                             xmlFree(ns);
7255                         } else if (xmlStrEqual(cur->name,
7256                                                BAD_CAST "attribute")) {
7257                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7258                         }
7259                     }
7260                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7261                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7262                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7263                     /*
7264                      * Simplification 4.8. name attribute of element
7265                      * and attribute elements
7266                      */
7267                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7268                         xmlNodePtr node;
7269                         xmlChar *ns = NULL;
7270 
7271                         node = cur->parent;
7272                         while ((node != NULL) &&
7273                                (node->type == XML_ELEMENT_NODE)) {
7274                             ns = xmlGetProp(node, BAD_CAST "ns");
7275                             if (ns != NULL) {
7276                                 break;
7277                             }
7278                             node = node->parent;
7279                         }
7280                         if (ns == NULL) {
7281                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7282                         } else {
7283                             xmlSetProp(cur, BAD_CAST "ns", ns);
7284                             xmlFree(ns);
7285                         }
7286                     }
7287                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7288                         xmlChar *name, *local, *prefix;
7289 
7290                         /*
7291                          * Simplification: 4.10. QNames
7292                          */
7293                         name = xmlNodeGetContent(cur);
7294                         if (name != NULL) {
7295                             local = xmlSplitQName2(name, &prefix);
7296                             if (local != NULL) {
7297                                 xmlNsPtr ns;
7298 
7299                                 ns = xmlSearchNs(cur->doc, cur, prefix);
7300                                 if (ns == NULL) {
7301                                     xmlRngPErr(ctxt, cur,
7302                                                XML_RNGP_PREFIX_UNDEFINED,
7303                                                "xmlRelaxNGParse: no namespace for prefix %s\n",
7304                                                prefix, NULL);
7305                                 } else {
7306                                     xmlSetProp(cur, BAD_CAST "ns",
7307                                                ns->href);
7308                                     xmlNodeSetContent(cur, local);
7309                                 }
7310                                 xmlFree(local);
7311                                 xmlFree(prefix);
7312                             }
7313                             xmlFree(name);
7314                         }
7315                     }
7316                     /*
7317                      * 4.16
7318                      */
7319                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7320                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7321                             xmlRngPErr(ctxt, cur,
7322                                        XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7323                                        "Found nsName/except//nsName forbidden construct\n",
7324                                        NULL, NULL);
7325                         }
7326                     }
7327                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7328                            (cur != root)) {
7329                     int oldflags = ctxt->flags;
7330 
7331                     /*
7332                      * 4.16
7333                      */
7334                     if ((cur->parent != NULL) &&
7335                         (xmlStrEqual
7336                          (cur->parent->name, BAD_CAST "anyName"))) {
7337                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7338                         xmlRelaxNGCleanupTree(ctxt, cur);
7339                         ctxt->flags = oldflags;
7340                         goto skip_children;
7341                     } else if ((cur->parent != NULL) &&
7342                                (xmlStrEqual
7343                                 (cur->parent->name, BAD_CAST "nsName"))) {
7344                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7345                         xmlRelaxNGCleanupTree(ctxt, cur);
7346                         ctxt->flags = oldflags;
7347                         goto skip_children;
7348                     }
7349                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7350                     /*
7351                      * 4.16
7352                      */
7353                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7354                         xmlRngPErr(ctxt, cur,
7355                                    XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7356                                    "Found anyName/except//anyName forbidden construct\n",
7357                                    NULL, NULL);
7358                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7359                         xmlRngPErr(ctxt, cur,
7360                                    XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7361                                    "Found nsName/except//anyName forbidden construct\n",
7362                                    NULL, NULL);
7363                     }
7364                 }
7365                 /*
7366                  * This is not an else since "include" is transformed
7367                  * into a div
7368                  */
7369                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7370                     xmlChar *ns;
7371                     xmlNodePtr child, ins, tmp;
7372 
7373                     /*
7374                      * implements rule 4.11
7375                      */
7376 
7377                     ns = xmlGetProp(cur, BAD_CAST "ns");
7378 
7379                     child = cur->children;
7380                     ins = cur;
7381                     while (child != NULL) {
7382                         if (ns != NULL) {
7383                             if (!xmlHasProp(child, BAD_CAST "ns")) {
7384                                 xmlSetProp(child, BAD_CAST "ns", ns);
7385                             }
7386                         }
7387                         tmp = child->next;
7388                         xmlUnlinkNode(child);
7389                         ins = xmlAddNextSibling(ins, child);
7390                         child = tmp;
7391                     }
7392                     if (ns != NULL)
7393                         xmlFree(ns);
7394 		    /*
7395 		     * Since we are about to delete cur, if its nsDef is non-NULL we
7396 		     * need to preserve it (it contains the ns definitions for the
7397 		     * children we just moved).  We'll just stick it on to the end
7398 		     * of cur->parent's list, since it's never going to be re-serialized
7399 		     * (bug 143738).
7400 		     */
7401 		    if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
7402 			xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7403 			while (parDef->next != NULL)
7404 			    parDef = parDef->next;
7405 			parDef->next = cur->nsDef;
7406 			cur->nsDef = NULL;
7407 		    }
7408                     delete = cur;
7409                     goto skip_children;
7410                 }
7411             }
7412         }
7413         /*
7414          * Simplification 4.2 whitespaces
7415          */
7416         else if ((cur->type == XML_TEXT_NODE) ||
7417                  (cur->type == XML_CDATA_SECTION_NODE)) {
7418             if (IS_BLANK_NODE(cur)) {
7419                 if ((cur->parent != NULL) &&
7420 		    (cur->parent->type == XML_ELEMENT_NODE)) {
7421                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7422                         &&
7423                         (!xmlStrEqual
7424                          (cur->parent->name, BAD_CAST "param")))
7425                         delete = cur;
7426                 } else {
7427                     delete = cur;
7428                     goto skip_children;
7429                 }
7430             }
7431         } else {
7432             delete = cur;
7433             goto skip_children;
7434         }
7435 
7436         /*
7437          * Skip to next node
7438          */
7439         if (cur->children != NULL) {
7440             if ((cur->children->type != XML_ENTITY_DECL) &&
7441                 (cur->children->type != XML_ENTITY_REF_NODE) &&
7442                 (cur->children->type != XML_ENTITY_NODE)) {
7443                 cur = cur->children;
7444                 continue;
7445             }
7446         }
7447       skip_children:
7448         if (cur->next != NULL) {
7449             cur = cur->next;
7450             continue;
7451         }
7452 
7453         do {
7454             cur = cur->parent;
7455             if (cur == NULL)
7456                 break;
7457             if (cur == root) {
7458                 cur = NULL;
7459                 break;
7460             }
7461             if (cur->next != NULL) {
7462                 cur = cur->next;
7463                 break;
7464             }
7465         } while (cur != NULL);
7466     }
7467     if (delete != NULL) {
7468         xmlUnlinkNode(delete);
7469         xmlFreeNode(delete);
7470         delete = NULL;
7471     }
7472 }
7473 
7474 /**
7475  * xmlRelaxNGCleanupDoc:
7476  * @ctxt:  a Relax-NG parser context
7477  * @doc:  an xmldocPtr document pointer
7478  *
7479  * Cleanup the document from unwanted nodes for parsing, resolve
7480  * Include and externalRef lookups.
7481  *
7482  * Returns the cleaned up document or NULL in case of error
7483  */
7484 static xmlDocPtr
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,xmlDocPtr doc)7485 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7486 {
7487     xmlNodePtr root;
7488 
7489     /*
7490      * Extract the root
7491      */
7492     root = xmlDocGetRootElement(doc);
7493     if (root == NULL) {
7494         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7495                    ctxt->URL, NULL);
7496         return (NULL);
7497     }
7498     xmlRelaxNGCleanupTree(ctxt, root);
7499     return (doc);
7500 }
7501 
7502 /**
7503  * xmlRelaxNGParse:
7504  * @ctxt:  a Relax-NG parser context
7505  *
7506  * parse a schema definition resource and build an internal
7507  * XML Schema structure which can be used to validate instances.
7508  *
7509  * Returns the internal XML RelaxNG structure built from the resource or
7510  *         NULL in case of error
7511  */
7512 xmlRelaxNGPtr
xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)7513 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7514 {
7515     xmlRelaxNGPtr ret = NULL;
7516     xmlDocPtr doc;
7517     xmlNodePtr root;
7518 
7519     xmlRelaxNGInitTypes();
7520 
7521     if (ctxt == NULL)
7522         return (NULL);
7523 
7524     /*
7525      * First step is to parse the input document into an DOM/Infoset
7526      */
7527     if (ctxt->URL != NULL) {
7528         doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
7529         if (doc == NULL) {
7530             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7531                        "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7532                        NULL);
7533             return (NULL);
7534         }
7535     } else if (ctxt->buffer != NULL) {
7536         doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
7537         if (doc == NULL) {
7538             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7539                        "xmlRelaxNGParse: could not parse schemas\n", NULL,
7540                        NULL);
7541             return (NULL);
7542         }
7543         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7544         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7545     } else if (ctxt->document != NULL) {
7546         doc = ctxt->document;
7547     } else {
7548         xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7549                    "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7550         return (NULL);
7551     }
7552     ctxt->document = doc;
7553 
7554     /*
7555      * Some preprocessing of the document content
7556      */
7557     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7558     if (doc == NULL) {
7559         xmlFreeDoc(ctxt->document);
7560         ctxt->document = NULL;
7561         return (NULL);
7562     }
7563 
7564     /*
7565      * Then do the parsing for good
7566      */
7567     root = xmlDocGetRootElement(doc);
7568     if (root == NULL) {
7569         xmlRngPErr(ctxt, (xmlNodePtr) doc,
7570 	           XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7571                    (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
7572 
7573         xmlFreeDoc(ctxt->document);
7574         ctxt->document = NULL;
7575         return (NULL);
7576     }
7577     ret = xmlRelaxNGParseDocument(ctxt, root);
7578     if (ret == NULL) {
7579         xmlFreeDoc(ctxt->document);
7580         ctxt->document = NULL;
7581         return (NULL);
7582     }
7583 
7584     /*
7585      * Check the ref/defines links
7586      */
7587     /*
7588      * try to preprocess interleaves
7589      */
7590     if (ctxt->interleaves != NULL) {
7591         xmlHashScan(ctxt->interleaves, xmlRelaxNGComputeInterleaves, ctxt);
7592     }
7593 
7594     /*
7595      * if there was a parsing error return NULL
7596      */
7597     if (ctxt->nbErrors > 0) {
7598         xmlRelaxNGFree(ret);
7599         ctxt->document = NULL;
7600         xmlFreeDoc(doc);
7601         return (NULL);
7602     }
7603 
7604     /*
7605      * try to compile (parts of) the schemas
7606      */
7607     if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7608         if (ret->topgrammar->start->type != XML_RELAXNG_START) {
7609             xmlRelaxNGDefinePtr def;
7610 
7611             def = xmlRelaxNGNewDefine(ctxt, NULL);
7612             if (def != NULL) {
7613                 def->type = XML_RELAXNG_START;
7614                 def->content = ret->topgrammar->start;
7615                 ret->topgrammar->start = def;
7616             }
7617         }
7618         xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
7619     }
7620 
7621     /*
7622      * Transfer the pointer for cleanup at the schema level.
7623      */
7624     ret->doc = doc;
7625     ctxt->document = NULL;
7626     ret->documents = ctxt->documents;
7627     ctxt->documents = NULL;
7628 
7629     ret->includes = ctxt->includes;
7630     ctxt->includes = NULL;
7631     ret->defNr = ctxt->defNr;
7632     ret->defTab = ctxt->defTab;
7633     ctxt->defTab = NULL;
7634     if (ctxt->idref == 1)
7635         ret->idref = 1;
7636 
7637     return (ret);
7638 }
7639 
7640 /**
7641  * xmlRelaxNGSetParserErrors:
7642  * @ctxt:  a Relax-NG validation context
7643  * @err:  the error callback
7644  * @warn:  the warning callback
7645  * @ctx:  contextual data for the callbacks
7646  *
7647  * Set the callback functions used to handle errors for a validation context
7648  */
7649 void
xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGValidityErrorFunc err,xmlRelaxNGValidityWarningFunc warn,void * ctx)7650 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7651                           xmlRelaxNGValidityErrorFunc err,
7652                           xmlRelaxNGValidityWarningFunc warn, void *ctx)
7653 {
7654     if (ctxt == NULL)
7655         return;
7656     ctxt->error = err;
7657     ctxt->warning = warn;
7658     ctxt->serror = NULL;
7659     ctxt->userData = ctx;
7660 }
7661 
7662 /**
7663  * xmlRelaxNGGetParserErrors:
7664  * @ctxt:  a Relax-NG validation context
7665  * @err:  the error callback result
7666  * @warn:  the warning callback result
7667  * @ctx:  contextual data for the callbacks result
7668  *
7669  * Get the callback information used to handle errors for a validation context
7670  *
7671  * Returns -1 in case of failure, 0 otherwise.
7672  */
7673 int
xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,xmlRelaxNGValidityErrorFunc * err,xmlRelaxNGValidityWarningFunc * warn,void ** ctx)7674 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7675                           xmlRelaxNGValidityErrorFunc * err,
7676                           xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7677 {
7678     if (ctxt == NULL)
7679         return (-1);
7680     if (err != NULL)
7681         *err = ctxt->error;
7682     if (warn != NULL)
7683         *warn = ctxt->warning;
7684     if (ctx != NULL)
7685         *ctx = ctxt->userData;
7686     return (0);
7687 }
7688 
7689 /**
7690  * xmlRelaxNGSetParserStructuredErrors:
7691  * @ctxt:  a Relax-NG parser context
7692  * @serror:  the error callback
7693  * @ctx:  contextual data for the callbacks
7694  *
7695  * Set the callback functions used to handle errors for a parsing context
7696  */
7697 void
xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,xmlStructuredErrorFunc serror,void * ctx)7698 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
7699 				    xmlStructuredErrorFunc serror,
7700 				    void *ctx)
7701 {
7702     if (ctxt == NULL)
7703         return;
7704     ctxt->serror = serror;
7705     ctxt->error = NULL;
7706     ctxt->warning = NULL;
7707     ctxt->userData = ctx;
7708 }
7709 
7710 #ifdef LIBXML_OUTPUT_ENABLED
7711 
7712 /************************************************************************
7713  *									*
7714  *			Dump back a compiled form			*
7715  *									*
7716  ************************************************************************/
7717 static void xmlRelaxNGDumpDefine(FILE * output,
7718                                  xmlRelaxNGDefinePtr define);
7719 
7720 /**
7721  * xmlRelaxNGDumpDefines:
7722  * @output:  the file output
7723  * @defines:  a list of define structures
7724  *
7725  * Dump a RelaxNG structure back
7726  */
7727 static void
xmlRelaxNGDumpDefines(FILE * output,xmlRelaxNGDefinePtr defines)7728 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7729 {
7730     while (defines != NULL) {
7731         xmlRelaxNGDumpDefine(output, defines);
7732         defines = defines->next;
7733     }
7734 }
7735 
7736 /**
7737  * xmlRelaxNGDumpDefine:
7738  * @output:  the file output
7739  * @define:  a define structure
7740  *
7741  * Dump a RelaxNG structure back
7742  */
7743 static void
xmlRelaxNGDumpDefine(FILE * output,xmlRelaxNGDefinePtr define)7744 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7745 {
7746     if (define == NULL)
7747         return;
7748     switch (define->type) {
7749         case XML_RELAXNG_EMPTY:
7750             fprintf(output, "<empty/>\n");
7751             break;
7752         case XML_RELAXNG_NOT_ALLOWED:
7753             fprintf(output, "<notAllowed/>\n");
7754             break;
7755         case XML_RELAXNG_TEXT:
7756             fprintf(output, "<text/>\n");
7757             break;
7758         case XML_RELAXNG_ELEMENT:
7759             fprintf(output, "<element>\n");
7760             if (define->name != NULL) {
7761                 fprintf(output, "<name");
7762                 if (define->ns != NULL)
7763                     fprintf(output, " ns=\"%s\"", define->ns);
7764                 fprintf(output, ">%s</name>\n", define->name);
7765             }
7766             xmlRelaxNGDumpDefines(output, define->attrs);
7767             xmlRelaxNGDumpDefines(output, define->content);
7768             fprintf(output, "</element>\n");
7769             break;
7770         case XML_RELAXNG_LIST:
7771             fprintf(output, "<list>\n");
7772             xmlRelaxNGDumpDefines(output, define->content);
7773             fprintf(output, "</list>\n");
7774             break;
7775         case XML_RELAXNG_ONEORMORE:
7776             fprintf(output, "<oneOrMore>\n");
7777             xmlRelaxNGDumpDefines(output, define->content);
7778             fprintf(output, "</oneOrMore>\n");
7779             break;
7780         case XML_RELAXNG_ZEROORMORE:
7781             fprintf(output, "<zeroOrMore>\n");
7782             xmlRelaxNGDumpDefines(output, define->content);
7783             fprintf(output, "</zeroOrMore>\n");
7784             break;
7785         case XML_RELAXNG_CHOICE:
7786             fprintf(output, "<choice>\n");
7787             xmlRelaxNGDumpDefines(output, define->content);
7788             fprintf(output, "</choice>\n");
7789             break;
7790         case XML_RELAXNG_GROUP:
7791             fprintf(output, "<group>\n");
7792             xmlRelaxNGDumpDefines(output, define->content);
7793             fprintf(output, "</group>\n");
7794             break;
7795         case XML_RELAXNG_INTERLEAVE:
7796             fprintf(output, "<interleave>\n");
7797             xmlRelaxNGDumpDefines(output, define->content);
7798             fprintf(output, "</interleave>\n");
7799             break;
7800         case XML_RELAXNG_OPTIONAL:
7801             fprintf(output, "<optional>\n");
7802             xmlRelaxNGDumpDefines(output, define->content);
7803             fprintf(output, "</optional>\n");
7804             break;
7805         case XML_RELAXNG_ATTRIBUTE:
7806             fprintf(output, "<attribute>\n");
7807             xmlRelaxNGDumpDefines(output, define->content);
7808             fprintf(output, "</attribute>\n");
7809             break;
7810         case XML_RELAXNG_DEF:
7811             fprintf(output, "<define");
7812             if (define->name != NULL)
7813                 fprintf(output, " name=\"%s\"", define->name);
7814             fprintf(output, ">\n");
7815             xmlRelaxNGDumpDefines(output, define->content);
7816             fprintf(output, "</define>\n");
7817             break;
7818         case XML_RELAXNG_REF:
7819             fprintf(output, "<ref");
7820             if (define->name != NULL)
7821                 fprintf(output, " name=\"%s\"", define->name);
7822             fprintf(output, ">\n");
7823             xmlRelaxNGDumpDefines(output, define->content);
7824             fprintf(output, "</ref>\n");
7825             break;
7826         case XML_RELAXNG_PARENTREF:
7827             fprintf(output, "<parentRef");
7828             if (define->name != NULL)
7829                 fprintf(output, " name=\"%s\"", define->name);
7830             fprintf(output, ">\n");
7831             xmlRelaxNGDumpDefines(output, define->content);
7832             fprintf(output, "</parentRef>\n");
7833             break;
7834         case XML_RELAXNG_EXTERNALREF:
7835             fprintf(output, "<externalRef>");
7836             xmlRelaxNGDumpDefines(output, define->content);
7837             fprintf(output, "</externalRef>\n");
7838             break;
7839         case XML_RELAXNG_DATATYPE:
7840         case XML_RELAXNG_VALUE:
7841             TODO break;
7842         case XML_RELAXNG_START:
7843         case XML_RELAXNG_EXCEPT:
7844         case XML_RELAXNG_PARAM:
7845             TODO break;
7846         case XML_RELAXNG_NOOP:
7847             xmlRelaxNGDumpDefines(output, define->content);
7848             break;
7849     }
7850 }
7851 
7852 /**
7853  * xmlRelaxNGDumpGrammar:
7854  * @output:  the file output
7855  * @grammar:  a grammar structure
7856  * @top:  is this a top grammar
7857  *
7858  * Dump a RelaxNG structure back
7859  */
7860 static void
xmlRelaxNGDumpGrammar(FILE * output,xmlRelaxNGGrammarPtr grammar,int top)7861 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7862 {
7863     if (grammar == NULL)
7864         return;
7865 
7866     fprintf(output, "<grammar");
7867     if (top)
7868         fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7869     switch (grammar->combine) {
7870         case XML_RELAXNG_COMBINE_UNDEFINED:
7871             break;
7872         case XML_RELAXNG_COMBINE_CHOICE:
7873             fprintf(output, " combine=\"choice\"");
7874             break;
7875         case XML_RELAXNG_COMBINE_INTERLEAVE:
7876             fprintf(output, " combine=\"interleave\"");
7877             break;
7878         default:
7879             fprintf(output, " <!-- invalid combine value -->");
7880     }
7881     fprintf(output, ">\n");
7882     if (grammar->start == NULL) {
7883         fprintf(output, " <!-- grammar had no start -->");
7884     } else {
7885         fprintf(output, "<start>\n");
7886         xmlRelaxNGDumpDefine(output, grammar->start);
7887         fprintf(output, "</start>\n");
7888     }
7889     /* TODO ? Dump the defines ? */
7890     fprintf(output, "</grammar>\n");
7891 }
7892 
7893 /**
7894  * xmlRelaxNGDump:
7895  * @output:  the file output
7896  * @schema:  a schema structure
7897  *
7898  * Dump a RelaxNG structure back
7899  */
7900 void
xmlRelaxNGDump(FILE * output,xmlRelaxNGPtr schema)7901 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7902 {
7903     if (output == NULL)
7904         return;
7905     if (schema == NULL) {
7906         fprintf(output, "RelaxNG empty or failed to compile\n");
7907         return;
7908     }
7909     fprintf(output, "RelaxNG: ");
7910     if (schema->doc == NULL) {
7911         fprintf(output, "no document\n");
7912     } else if (schema->doc->URL != NULL) {
7913         fprintf(output, "%s\n", schema->doc->URL);
7914     } else {
7915         fprintf(output, "\n");
7916     }
7917     if (schema->topgrammar == NULL) {
7918         fprintf(output, "RelaxNG has no top grammar\n");
7919         return;
7920     }
7921     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7922 }
7923 
7924 /**
7925  * xmlRelaxNGDumpTree:
7926  * @output:  the file output
7927  * @schema:  a schema structure
7928  *
7929  * Dump the transformed RelaxNG tree.
7930  */
7931 void
xmlRelaxNGDumpTree(FILE * output,xmlRelaxNGPtr schema)7932 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7933 {
7934     if (output == NULL)
7935         return;
7936     if (schema == NULL) {
7937         fprintf(output, "RelaxNG empty or failed to compile\n");
7938         return;
7939     }
7940     if (schema->doc == NULL) {
7941         fprintf(output, "no document\n");
7942     } else {
7943         xmlDocDump(output, schema->doc);
7944     }
7945 }
7946 #endif /* LIBXML_OUTPUT_ENABLED */
7947 
7948 /************************************************************************
7949  *									*
7950  *		Validation of compiled content				*
7951  *									*
7952  ************************************************************************/
7953 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7954                                         xmlRelaxNGDefinePtr define);
7955 
7956 /**
7957  * xmlRelaxNGValidateCompiledCallback:
7958  * @exec:  the regular expression instance
7959  * @token:  the token which matched
7960  * @transdata:  callback data, the define for the subelement if available
7961  @ @inputdata:  callback data, the Relax NG validation context
7962  *
7963  * Handle the callback and if needed validate the element children.
7964  */
7965 static void
xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,const xmlChar * token,void * transdata,void * inputdata)7966 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7967                                    const xmlChar * token,
7968                                    void *transdata, void *inputdata)
7969 {
7970     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7971     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7972     int ret;
7973 
7974 #ifdef DEBUG_COMPILE
7975     xmlGenericError(xmlGenericErrorContext,
7976                     "Compiled callback for: '%s'\n", token);
7977 #endif
7978     if (ctxt == NULL) {
7979         fprintf(stderr, "callback on %s missing context\n", token);
7980         return;
7981     }
7982     if (define == NULL) {
7983         if (token[0] == '#')
7984             return;
7985         fprintf(stderr, "callback on %s missing define\n", token);
7986         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7987             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7988         return;
7989     }
7990     if ((ctxt == NULL) || (define == NULL)) {
7991         fprintf(stderr, "callback on %s missing info\n", token);
7992         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7993             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7994         return;
7995     } else if (define->type != XML_RELAXNG_ELEMENT) {
7996         fprintf(stderr, "callback on %s define is not element\n", token);
7997         if (ctxt->errNo == XML_RELAXNG_OK)
7998             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7999         return;
8000     }
8001     ret = xmlRelaxNGValidateDefinition(ctxt, define);
8002     if (ret != 0)
8003         ctxt->perr = ret;
8004 }
8005 
8006 /**
8007  * xmlRelaxNGValidateCompiledContent:
8008  * @ctxt:  the RelaxNG validation context
8009  * @regexp:  the regular expression as compiled
8010  * @content:  list of children to test against the regexp
8011  *
8012  * Validate the content model of an element or start using the regexp
8013  *
8014  * Returns 0 in case of success, -1 in case of error.
8015  */
8016 static int
xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,xmlRegexpPtr regexp,xmlNodePtr content)8017 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
8018                                   xmlRegexpPtr regexp, xmlNodePtr content)
8019 {
8020     xmlRegExecCtxtPtr exec;
8021     xmlNodePtr cur;
8022     int ret = 0;
8023     int oldperr;
8024 
8025     if ((ctxt == NULL) || (regexp == NULL))
8026         return (-1);
8027     oldperr = ctxt->perr;
8028     exec = xmlRegNewExecCtxt(regexp,
8029                              xmlRelaxNGValidateCompiledCallback, ctxt);
8030     ctxt->perr = 0;
8031     cur = content;
8032     while (cur != NULL) {
8033         ctxt->state->seq = cur;
8034         switch (cur->type) {
8035             case XML_TEXT_NODE:
8036             case XML_CDATA_SECTION_NODE:
8037                 if (xmlIsBlankNode(cur))
8038                     break;
8039                 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
8040                 if (ret < 0) {
8041                     VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
8042                                cur->parent->name);
8043                 }
8044                 break;
8045             case XML_ELEMENT_NODE:
8046                 if (cur->ns != NULL) {
8047                     ret = xmlRegExecPushString2(exec, cur->name,
8048                                                 cur->ns->href, ctxt);
8049                 } else {
8050                     ret = xmlRegExecPushString(exec, cur->name, ctxt);
8051                 }
8052                 if (ret < 0) {
8053                     VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
8054                 }
8055                 break;
8056             default:
8057                 break;
8058         }
8059         if (ret < 0)
8060             break;
8061         /*
8062          * Switch to next element
8063          */
8064         cur = cur->next;
8065     }
8066     ret = xmlRegExecPushString(exec, NULL, NULL);
8067     if (ret == 1) {
8068         ret = 0;
8069         ctxt->state->seq = NULL;
8070     } else if (ret == 0) {
8071         /*
8072          * TODO: get some of the names needed to exit the current state of exec
8073          */
8074         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8075         ret = -1;
8076         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8077             xmlRelaxNGDumpValidError(ctxt);
8078     } else {
8079         ret = -1;
8080     }
8081     xmlRegFreeExecCtxt(exec);
8082     /*
8083      * There might be content model errors outside of the pure
8084      * regexp validation, e.g. for attribute values.
8085      */
8086     if ((ret == 0) && (ctxt->perr != 0)) {
8087         ret = ctxt->perr;
8088     }
8089     ctxt->perr = oldperr;
8090     return (ret);
8091 }
8092 
8093 /************************************************************************
8094  *									*
8095  *		Progressive validation of when possible			*
8096  *									*
8097  ************************************************************************/
8098 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8099                                            xmlRelaxNGDefinePtr defines);
8100 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
8101                                         int dolog);
8102 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
8103 
8104 /**
8105  * xmlRelaxNGElemPush:
8106  * @ctxt:  the validation context
8107  * @exec:  the regexp runtime for the new content model
8108  *
8109  * Push a new regexp for the current node content model on the stack
8110  *
8111  * Returns 0 in case of success and -1 in case of error.
8112  */
8113 static int
xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt,xmlRegExecCtxtPtr exec)8114 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
8115 {
8116     if (ctxt->elemTab == NULL) {
8117         ctxt->elemMax = 10;
8118         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
8119                                                         sizeof
8120                                                         (xmlRegExecCtxtPtr));
8121         if (ctxt->elemTab == NULL) {
8122             xmlRngVErrMemory(ctxt, "validating\n");
8123             return (-1);
8124         }
8125     }
8126     if (ctxt->elemNr >= ctxt->elemMax) {
8127         ctxt->elemMax *= 2;
8128         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
8129                                                          ctxt->elemMax *
8130                                                          sizeof
8131                                                          (xmlRegExecCtxtPtr));
8132         if (ctxt->elemTab == NULL) {
8133             xmlRngVErrMemory(ctxt, "validating\n");
8134             return (-1);
8135         }
8136     }
8137     ctxt->elemTab[ctxt->elemNr++] = exec;
8138     ctxt->elem = exec;
8139     return (0);
8140 }
8141 
8142 /**
8143  * xmlRelaxNGElemPop:
8144  * @ctxt:  the validation context
8145  *
8146  * Pop the regexp of the current node content model from the stack
8147  *
8148  * Returns the exec or NULL if empty
8149  */
8150 static xmlRegExecCtxtPtr
xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)8151 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
8152 {
8153     xmlRegExecCtxtPtr ret;
8154 
8155     if (ctxt->elemNr <= 0)
8156         return (NULL);
8157     ctxt->elemNr--;
8158     ret = ctxt->elemTab[ctxt->elemNr];
8159     ctxt->elemTab[ctxt->elemNr] = NULL;
8160     if (ctxt->elemNr > 0)
8161         ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
8162     else
8163         ctxt->elem = NULL;
8164     return (ret);
8165 }
8166 
8167 /**
8168  * xmlRelaxNGValidateProgressiveCallback:
8169  * @exec:  the regular expression instance
8170  * @token:  the token which matched
8171  * @transdata:  callback data, the define for the subelement if available
8172  @ @inputdata:  callback data, the Relax NG validation context
8173  *
8174  * Handle the callback and if needed validate the element children.
8175  * some of the in/out information are passed via the context in @inputdata.
8176  */
8177 static void
xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,const xmlChar * token,void * transdata,void * inputdata)8178 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8179                                       ATTRIBUTE_UNUSED,
8180                                       const xmlChar * token,
8181                                       void *transdata, void *inputdata)
8182 {
8183     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8184     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
8185     xmlRelaxNGValidStatePtr state, oldstate;
8186     xmlNodePtr node;
8187     int ret = 0, oldflags;
8188 
8189 #ifdef DEBUG_PROGRESSIVE
8190     xmlGenericError(xmlGenericErrorContext,
8191                     "Progressive callback for: '%s'\n", token);
8192 #endif
8193     if (ctxt == NULL) {
8194         fprintf(stderr, "callback on %s missing context\n", token);
8195         return;
8196     }
8197     node = ctxt->pnode;
8198     ctxt->pstate = 1;
8199     if (define == NULL) {
8200         if (token[0] == '#')
8201             return;
8202         fprintf(stderr, "callback on %s missing define\n", token);
8203         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8204             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8205         ctxt->pstate = -1;
8206         return;
8207     }
8208     if ((ctxt == NULL) || (define == NULL)) {
8209         fprintf(stderr, "callback on %s missing info\n", token);
8210         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8211             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8212         ctxt->pstate = -1;
8213         return;
8214     } else if (define->type != XML_RELAXNG_ELEMENT) {
8215         fprintf(stderr, "callback on %s define is not element\n", token);
8216         if (ctxt->errNo == XML_RELAXNG_OK)
8217             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8218         ctxt->pstate = -1;
8219         return;
8220     }
8221     if (node->type != XML_ELEMENT_NODE) {
8222         VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8223         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8224             xmlRelaxNGDumpValidError(ctxt);
8225         ctxt->pstate = -1;
8226         return;
8227     }
8228     if (define->contModel == NULL) {
8229         /*
8230          * this node cannot be validated in a streamable fashion
8231          */
8232 #ifdef DEBUG_PROGRESSIVE
8233         xmlGenericError(xmlGenericErrorContext,
8234                         "Element '%s' validation is not streamable\n",
8235                         token);
8236 #endif
8237         ctxt->pstate = 0;
8238         ctxt->pdef = define;
8239         return;
8240     }
8241     exec = xmlRegNewExecCtxt(define->contModel,
8242                              xmlRelaxNGValidateProgressiveCallback, ctxt);
8243     if (exec == NULL) {
8244         ctxt->pstate = -1;
8245         return;
8246     }
8247     xmlRelaxNGElemPush(ctxt, exec);
8248 
8249     /*
8250      * Validate the attributes part of the content.
8251      */
8252     state = xmlRelaxNGNewValidState(ctxt, node);
8253     if (state == NULL) {
8254         ctxt->pstate = -1;
8255         return;
8256     }
8257     oldstate = ctxt->state;
8258     ctxt->state = state;
8259     if (define->attrs != NULL) {
8260         ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8261         if (ret != 0) {
8262             ctxt->pstate = -1;
8263             VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8264         }
8265     }
8266     if (ctxt->state != NULL) {
8267         ctxt->state->seq = NULL;
8268         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8269         if (ret != 0) {
8270             ctxt->pstate = -1;
8271         }
8272         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8273     } else if (ctxt->states != NULL) {
8274         int tmp = -1, i;
8275 
8276         oldflags = ctxt->flags;
8277 
8278         for (i = 0; i < ctxt->states->nbState; i++) {
8279             state = ctxt->states->tabState[i];
8280             ctxt->state = state;
8281             ctxt->state->seq = NULL;
8282 
8283             if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8284                 tmp = 0;
8285                 break;
8286             }
8287         }
8288         if (tmp != 0) {
8289             /*
8290              * validation error, log the message for the "best" one
8291              */
8292             ctxt->flags |= FLAGS_IGNORABLE;
8293             xmlRelaxNGLogBestError(ctxt);
8294         }
8295         for (i = 0; i < ctxt->states->nbState; i++) {
8296             xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8297         }
8298         xmlRelaxNGFreeStates(ctxt, ctxt->states);
8299         ctxt->states = NULL;
8300         if ((ret == 0) && (tmp == -1))
8301             ctxt->pstate = -1;
8302         ctxt->flags = oldflags;
8303     }
8304     if (ctxt->pstate == -1) {
8305         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8306             xmlRelaxNGDumpValidError(ctxt);
8307         }
8308     }
8309     ctxt->state = oldstate;
8310 }
8311 
8312 /**
8313  * xmlRelaxNGValidatePushElement:
8314  * @ctxt:  the validation context
8315  * @doc:  a document instance
8316  * @elem:  an element instance
8317  *
8318  * Push a new element start on the RelaxNG validation stack.
8319  *
8320  * returns 1 if no validation problem was found or 0 if validating the
8321  *         element requires a full node, and -1 in case of error.
8322  */
8323 int
xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr elem)8324 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8325                               xmlDocPtr doc ATTRIBUTE_UNUSED,
8326                               xmlNodePtr elem)
8327 {
8328     int ret = 1;
8329 
8330     if ((ctxt == NULL) || (elem == NULL))
8331         return (-1);
8332 
8333 #ifdef DEBUG_PROGRESSIVE
8334     xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8335 #endif
8336     if (ctxt->elem == 0) {
8337         xmlRelaxNGPtr schema;
8338         xmlRelaxNGGrammarPtr grammar;
8339         xmlRegExecCtxtPtr exec;
8340         xmlRelaxNGDefinePtr define;
8341 
8342         schema = ctxt->schema;
8343         if (schema == NULL) {
8344             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8345             return (-1);
8346         }
8347         grammar = schema->topgrammar;
8348         if ((grammar == NULL) || (grammar->start == NULL)) {
8349             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8350             return (-1);
8351         }
8352         define = grammar->start;
8353         if (define->contModel == NULL) {
8354             ctxt->pdef = define;
8355             return (0);
8356         }
8357         exec = xmlRegNewExecCtxt(define->contModel,
8358                                  xmlRelaxNGValidateProgressiveCallback,
8359                                  ctxt);
8360         if (exec == NULL) {
8361             return (-1);
8362         }
8363         xmlRelaxNGElemPush(ctxt, exec);
8364     }
8365     ctxt->pnode = elem;
8366     ctxt->pstate = 0;
8367     if (elem->ns != NULL) {
8368         ret =
8369             xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8370                                   ctxt);
8371     } else {
8372         ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8373     }
8374     if (ret < 0) {
8375         VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8376     } else {
8377         if (ctxt->pstate == 0)
8378             ret = 0;
8379         else if (ctxt->pstate < 0)
8380             ret = -1;
8381         else
8382             ret = 1;
8383     }
8384 #ifdef DEBUG_PROGRESSIVE
8385     if (ret < 0)
8386         xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8387                         elem->name);
8388 #endif
8389     return (ret);
8390 }
8391 
8392 /**
8393  * xmlRelaxNGValidatePushCData:
8394  * @ctxt:  the RelaxNG validation context
8395  * @data:  some character data read
8396  * @len:  the length of the data
8397  *
8398  * check the CData parsed for validation in the current stack
8399  *
8400  * returns 1 if no validation problem was found or -1 otherwise
8401  */
8402 int
xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,const xmlChar * data,int len ATTRIBUTE_UNUSED)8403 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
8404                             const xmlChar * data, int len ATTRIBUTE_UNUSED)
8405 {
8406     int ret = 1;
8407 
8408     if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8409         return (-1);
8410 
8411 #ifdef DEBUG_PROGRESSIVE
8412     xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8413 #endif
8414 
8415     while (*data != 0) {
8416         if (!IS_BLANK_CH(*data))
8417             break;
8418         data++;
8419     }
8420     if (*data == 0)
8421         return (1);
8422 
8423     ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8424     if (ret < 0) {
8425         VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
8426 #ifdef DEBUG_PROGRESSIVE
8427         xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8428 #endif
8429 
8430         return (-1);
8431     }
8432     return (1);
8433 }
8434 
8435 /**
8436  * xmlRelaxNGValidatePopElement:
8437  * @ctxt:  the RelaxNG validation context
8438  * @doc:  a document instance
8439  * @elem:  an element instance
8440  *
8441  * Pop the element end from the RelaxNG validation stack.
8442  *
8443  * returns 1 if no validation problem was found or 0 otherwise
8444  */
8445 int
xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr elem)8446 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8447                              xmlDocPtr doc ATTRIBUTE_UNUSED,
8448                              xmlNodePtr elem)
8449 {
8450     int ret;
8451     xmlRegExecCtxtPtr exec;
8452 
8453     if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8454         return (-1);
8455 #ifdef DEBUG_PROGRESSIVE
8456     xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8457 #endif
8458     /*
8459      * verify that we reached a terminal state of the content model.
8460      */
8461     exec = xmlRelaxNGElemPop(ctxt);
8462     ret = xmlRegExecPushString(exec, NULL, NULL);
8463     if (ret == 0) {
8464         /*
8465          * TODO: get some of the names needed to exit the current state of exec
8466          */
8467         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8468         ret = -1;
8469     } else if (ret < 0) {
8470         ret = -1;
8471     } else {
8472         ret = 1;
8473     }
8474     xmlRegFreeExecCtxt(exec);
8475 #ifdef DEBUG_PROGRESSIVE
8476     if (ret < 0)
8477         xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8478                         elem->name);
8479 #endif
8480     return (ret);
8481 }
8482 
8483 /**
8484  * xmlRelaxNGValidateFullElement:
8485  * @ctxt:  the validation context
8486  * @doc:  a document instance
8487  * @elem:  an element instance
8488  *
8489  * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8490  * 0 and the content of the node has been expanded.
8491  *
8492  * returns 1 if no validation problem was found or -1 in case of error.
8493  */
8494 int
xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr elem)8495 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8496                               xmlDocPtr doc ATTRIBUTE_UNUSED,
8497                               xmlNodePtr elem)
8498 {
8499     int ret;
8500     xmlRelaxNGValidStatePtr state;
8501 
8502     if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8503         return (-1);
8504 #ifdef DEBUG_PROGRESSIVE
8505     xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8506 #endif
8507     state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8508     if (state == NULL) {
8509         return (-1);
8510     }
8511     state->seq = elem;
8512     ctxt->state = state;
8513     ctxt->errNo = XML_RELAXNG_OK;
8514     ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8515     if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8516         ret = -1;
8517     else
8518         ret = 1;
8519     xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8520     ctxt->state = NULL;
8521 #ifdef DEBUG_PROGRESSIVE
8522     if (ret < 0)
8523         xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8524                         elem->name);
8525 #endif
8526     return (ret);
8527 }
8528 
8529 /************************************************************************
8530  *									*
8531  *		Generic interpreted validation implementation		*
8532  *									*
8533  ************************************************************************/
8534 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8535                                    xmlRelaxNGDefinePtr define);
8536 
8537 /**
8538  * xmlRelaxNGSkipIgnored:
8539  * @ctxt:  a schema validation context
8540  * @node:  the top node.
8541  *
8542  * Skip ignorable nodes in that context
8543  *
8544  * Returns the new sibling or NULL in case of error.
8545  */
8546 static xmlNodePtr
xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlNodePtr node)8547 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8548                       xmlNodePtr node)
8549 {
8550     /*
8551      * TODO complete and handle entities
8552      */
8553     while ((node != NULL) &&
8554            ((node->type == XML_COMMENT_NODE) ||
8555             (node->type == XML_PI_NODE) ||
8556 	    (node->type == XML_XINCLUDE_START) ||
8557 	    (node->type == XML_XINCLUDE_END) ||
8558             (((node->type == XML_TEXT_NODE) ||
8559               (node->type == XML_CDATA_SECTION_NODE)) &&
8560              ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8561               (IS_BLANK_NODE(node)))))) {
8562         node = node->next;
8563     }
8564     return (node);
8565 }
8566 
8567 /**
8568  * xmlRelaxNGNormalize:
8569  * @ctxt:  a schema validation context
8570  * @str:  the string to normalize
8571  *
8572  * Implements the  normalizeWhiteSpace( s ) function from
8573  * section 6.2.9 of the spec
8574  *
8575  * Returns the new string or NULL in case of error.
8576  */
8577 static xmlChar *
xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,const xmlChar * str)8578 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8579 {
8580     xmlChar *ret, *p;
8581     const xmlChar *tmp;
8582     int len;
8583 
8584     if (str == NULL)
8585         return (NULL);
8586     tmp = str;
8587     while (*tmp != 0)
8588         tmp++;
8589     len = tmp - str;
8590 
8591     ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
8592     if (ret == NULL) {
8593         xmlRngVErrMemory(ctxt, "validating\n");
8594         return (NULL);
8595     }
8596     p = ret;
8597     while (IS_BLANK_CH(*str))
8598         str++;
8599     while (*str != 0) {
8600         if (IS_BLANK_CH(*str)) {
8601             while (IS_BLANK_CH(*str))
8602                 str++;
8603             if (*str == 0)
8604                 break;
8605             *p++ = ' ';
8606         } else
8607             *p++ = *str++;
8608     }
8609     *p = 0;
8610     return (ret);
8611 }
8612 
8613 /**
8614  * xmlRelaxNGValidateDatatype:
8615  * @ctxt:  a Relax-NG validation context
8616  * @value:  the string value
8617  * @type:  the datatype definition
8618  * @node:  the node
8619  *
8620  * Validate the given value against the datatype
8621  *
8622  * Returns 0 if the validation succeeded or an error code.
8623  */
8624 static int
xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,const xmlChar * value,xmlRelaxNGDefinePtr define,xmlNodePtr node)8625 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8626                            const xmlChar * value,
8627                            xmlRelaxNGDefinePtr define, xmlNodePtr node)
8628 {
8629     int ret, tmp;
8630     xmlRelaxNGTypeLibraryPtr lib;
8631     void *result = NULL;
8632     xmlRelaxNGDefinePtr cur;
8633 
8634     if ((define == NULL) || (define->data == NULL)) {
8635         return (-1);
8636     }
8637     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8638     if (lib->check != NULL) {
8639         if ((define->attrs != NULL) &&
8640             (define->attrs->type == XML_RELAXNG_PARAM)) {
8641             ret =
8642                 lib->check(lib->data, define->name, value, &result, node);
8643         } else {
8644             ret = lib->check(lib->data, define->name, value, NULL, node);
8645         }
8646     } else
8647         ret = -1;
8648     if (ret < 0) {
8649         VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8650         if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8651             lib->freef(lib->data, result);
8652         return (-1);
8653     } else if (ret == 1) {
8654         ret = 0;
8655     } else if (ret == 2) {
8656         VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
8657     } else {
8658         VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8659         ret = -1;
8660     }
8661     cur = define->attrs;
8662     while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8663         if (lib->facet != NULL) {
8664             tmp = lib->facet(lib->data, define->name, cur->name,
8665                              cur->value, value, result);
8666             if (tmp != 0)
8667                 ret = -1;
8668         }
8669         cur = cur->next;
8670     }
8671     if ((ret == 0) && (define->content != NULL)) {
8672         const xmlChar *oldvalue, *oldendvalue;
8673 
8674         oldvalue = ctxt->state->value;
8675         oldendvalue = ctxt->state->endvalue;
8676         ctxt->state->value = (xmlChar *) value;
8677         ctxt->state->endvalue = NULL;
8678         ret = xmlRelaxNGValidateValue(ctxt, define->content);
8679         ctxt->state->value = (xmlChar *) oldvalue;
8680         ctxt->state->endvalue = (xmlChar *) oldendvalue;
8681     }
8682     if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8683         lib->freef(lib->data, result);
8684     return (ret);
8685 }
8686 
8687 /**
8688  * xmlRelaxNGNextValue:
8689  * @ctxt:  a Relax-NG validation context
8690  *
8691  * Skip to the next value when validating within a list
8692  *
8693  * Returns 0 if the operation succeeded or an error code.
8694  */
8695 static int
xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)8696 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8697 {
8698     xmlChar *cur;
8699 
8700     cur = ctxt->state->value;
8701     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8702         ctxt->state->value = NULL;
8703         ctxt->state->endvalue = NULL;
8704         return (0);
8705     }
8706     while (*cur != 0)
8707         cur++;
8708     while ((cur != ctxt->state->endvalue) && (*cur == 0))
8709         cur++;
8710     if (cur == ctxt->state->endvalue)
8711         ctxt->state->value = NULL;
8712     else
8713         ctxt->state->value = cur;
8714     return (0);
8715 }
8716 
8717 /**
8718  * xmlRelaxNGValidateValueList:
8719  * @ctxt:  a Relax-NG validation context
8720  * @defines:  the list of definitions to verify
8721  *
8722  * Validate the given set of definitions for the current value
8723  *
8724  * Returns 0 if the validation succeeded or an error code.
8725  */
8726 static int
xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr defines)8727 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8728                             xmlRelaxNGDefinePtr defines)
8729 {
8730     int ret = 0;
8731 
8732     while (defines != NULL) {
8733         ret = xmlRelaxNGValidateValue(ctxt, defines);
8734         if (ret != 0)
8735             break;
8736         defines = defines->next;
8737     }
8738     return (ret);
8739 }
8740 
8741 /**
8742  * xmlRelaxNGValidateValue:
8743  * @ctxt:  a Relax-NG validation context
8744  * @define:  the definition to verify
8745  *
8746  * Validate the given definition for the current value
8747  *
8748  * Returns 0 if the validation succeeded or an error code.
8749  */
8750 static int
xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define)8751 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8752                         xmlRelaxNGDefinePtr define)
8753 {
8754     int ret = 0, oldflags;
8755     xmlChar *value;
8756 
8757     value = ctxt->state->value;
8758     switch (define->type) {
8759         case XML_RELAXNG_EMPTY:{
8760                 if ((value != NULL) && (value[0] != 0)) {
8761                     int idx = 0;
8762 
8763                     while (IS_BLANK_CH(value[idx]))
8764                         idx++;
8765                     if (value[idx] != 0)
8766                         ret = -1;
8767                 }
8768                 break;
8769             }
8770         case XML_RELAXNG_TEXT:
8771             break;
8772         case XML_RELAXNG_VALUE:{
8773                 if (!xmlStrEqual(value, define->value)) {
8774                     if (define->name != NULL) {
8775                         xmlRelaxNGTypeLibraryPtr lib;
8776 
8777                         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8778                         if ((lib != NULL) && (lib->comp != NULL)) {
8779                             ret = lib->comp(lib->data, define->name,
8780                                             define->value, define->node,
8781                                             (void *) define->attrs,
8782                                             value, ctxt->state->node);
8783                         } else
8784                             ret = -1;
8785                         if (ret < 0) {
8786                             VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8787                                        define->name);
8788                             return (-1);
8789                         } else if (ret == 1) {
8790                             ret = 0;
8791                         } else {
8792                             ret = -1;
8793                         }
8794                     } else {
8795                         xmlChar *nval, *nvalue;
8796 
8797                         /*
8798                          * TODO: trivial optimizations are possible by
8799                          * computing at compile-time
8800                          */
8801                         nval = xmlRelaxNGNormalize(ctxt, define->value);
8802                         nvalue = xmlRelaxNGNormalize(ctxt, value);
8803 
8804                         if ((nval == NULL) || (nvalue == NULL) ||
8805                             (!xmlStrEqual(nval, nvalue)))
8806                             ret = -1;
8807                         if (nval != NULL)
8808                             xmlFree(nval);
8809                         if (nvalue != NULL)
8810                             xmlFree(nvalue);
8811                     }
8812                 }
8813                 if (ret == 0)
8814                     xmlRelaxNGNextValue(ctxt);
8815                 break;
8816             }
8817         case XML_RELAXNG_DATATYPE:{
8818                 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8819                                                  ctxt->state->seq);
8820                 if (ret == 0)
8821                     xmlRelaxNGNextValue(ctxt);
8822 
8823                 break;
8824             }
8825         case XML_RELAXNG_CHOICE:{
8826                 xmlRelaxNGDefinePtr list = define->content;
8827                 xmlChar *oldvalue;
8828 
8829                 oldflags = ctxt->flags;
8830                 ctxt->flags |= FLAGS_IGNORABLE;
8831 
8832                 oldvalue = ctxt->state->value;
8833                 while (list != NULL) {
8834                     ret = xmlRelaxNGValidateValue(ctxt, list);
8835                     if (ret == 0) {
8836                         break;
8837                     }
8838                     ctxt->state->value = oldvalue;
8839                     list = list->next;
8840                 }
8841                 ctxt->flags = oldflags;
8842                 if (ret != 0) {
8843                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8844                         xmlRelaxNGDumpValidError(ctxt);
8845                 } else {
8846                     if (ctxt->errNr > 0)
8847                         xmlRelaxNGPopErrors(ctxt, 0);
8848                 }
8849                 break;
8850             }
8851         case XML_RELAXNG_LIST:{
8852                 xmlRelaxNGDefinePtr list = define->content;
8853                 xmlChar *oldvalue, *oldend, *val, *cur;
8854 
8855 #ifdef DEBUG_LIST
8856                 int nb_values = 0;
8857 #endif
8858 
8859                 oldvalue = ctxt->state->value;
8860                 oldend = ctxt->state->endvalue;
8861 
8862                 val = xmlStrdup(oldvalue);
8863                 if (val == NULL) {
8864                     val = xmlStrdup(BAD_CAST "");
8865                 }
8866                 if (val == NULL) {
8867                     VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8868                     return (-1);
8869                 }
8870                 cur = val;
8871                 while (*cur != 0) {
8872                     if (IS_BLANK_CH(*cur)) {
8873                         *cur = 0;
8874                         cur++;
8875 #ifdef DEBUG_LIST
8876                         nb_values++;
8877 #endif
8878                         while (IS_BLANK_CH(*cur))
8879                             *cur++ = 0;
8880                     } else
8881                         cur++;
8882                 }
8883 #ifdef DEBUG_LIST
8884                 xmlGenericError(xmlGenericErrorContext,
8885                                 "list value: '%s' found %d items\n",
8886                                 oldvalue, nb_values);
8887                 nb_values = 0;
8888 #endif
8889                 ctxt->state->endvalue = cur;
8890                 cur = val;
8891                 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8892                     cur++;
8893 
8894                 ctxt->state->value = cur;
8895 
8896                 while (list != NULL) {
8897                     if (ctxt->state->value == ctxt->state->endvalue)
8898                         ctxt->state->value = NULL;
8899                     ret = xmlRelaxNGValidateValue(ctxt, list);
8900                     if (ret != 0) {
8901 #ifdef DEBUG_LIST
8902                         xmlGenericError(xmlGenericErrorContext,
8903                                         "Failed to validate value: '%s' with %d rule\n",
8904                                         ctxt->state->value, nb_values);
8905 #endif
8906                         break;
8907                     }
8908 #ifdef DEBUG_LIST
8909                     nb_values++;
8910 #endif
8911                     list = list->next;
8912                 }
8913 
8914                 if ((ret == 0) && (ctxt->state->value != NULL) &&
8915                     (ctxt->state->value != ctxt->state->endvalue)) {
8916                     VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8917                                ctxt->state->value);
8918                     ret = -1;
8919                 }
8920                 xmlFree(val);
8921                 ctxt->state->value = oldvalue;
8922                 ctxt->state->endvalue = oldend;
8923                 break;
8924             }
8925         case XML_RELAXNG_ONEORMORE:
8926             ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8927             if (ret != 0) {
8928                 break;
8929             }
8930             /* Falls through. */
8931         case XML_RELAXNG_ZEROORMORE:{
8932                 xmlChar *cur, *temp;
8933 
8934                 if ((ctxt->state->value == NULL) ||
8935                     (*ctxt->state->value == 0)) {
8936                     ret = 0;
8937                     break;
8938                 }
8939                 oldflags = ctxt->flags;
8940                 ctxt->flags |= FLAGS_IGNORABLE;
8941                 cur = ctxt->state->value;
8942                 temp = NULL;
8943                 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8944                        (temp != cur)) {
8945                     temp = cur;
8946                     ret =
8947                         xmlRelaxNGValidateValueList(ctxt, define->content);
8948                     if (ret != 0) {
8949                         ctxt->state->value = temp;
8950                         ret = 0;
8951                         break;
8952                     }
8953                     cur = ctxt->state->value;
8954                 }
8955                 ctxt->flags = oldflags;
8956 		if (ctxt->errNr > 0)
8957 		    xmlRelaxNGPopErrors(ctxt, 0);
8958                 break;
8959             }
8960         case XML_RELAXNG_OPTIONAL:{
8961                 xmlChar *temp;
8962 
8963                 if ((ctxt->state->value == NULL) ||
8964                     (*ctxt->state->value == 0)) {
8965                     ret = 0;
8966                     break;
8967                 }
8968                 oldflags = ctxt->flags;
8969                 ctxt->flags |= FLAGS_IGNORABLE;
8970                 temp = ctxt->state->value;
8971                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8972                 ctxt->flags = oldflags;
8973                 if (ret != 0) {
8974                     ctxt->state->value = temp;
8975                     if (ctxt->errNr > 0)
8976                         xmlRelaxNGPopErrors(ctxt, 0);
8977                     ret = 0;
8978                     break;
8979                 }
8980 		if (ctxt->errNr > 0)
8981 		    xmlRelaxNGPopErrors(ctxt, 0);
8982                 break;
8983             }
8984         case XML_RELAXNG_EXCEPT:{
8985                 xmlRelaxNGDefinePtr list;
8986 
8987                 list = define->content;
8988                 while (list != NULL) {
8989                     ret = xmlRelaxNGValidateValue(ctxt, list);
8990                     if (ret == 0) {
8991                         ret = -1;
8992                         break;
8993                     } else
8994                         ret = 0;
8995                     list = list->next;
8996                 }
8997                 break;
8998             }
8999         case XML_RELAXNG_DEF:
9000         case XML_RELAXNG_GROUP:{
9001                 xmlRelaxNGDefinePtr list;
9002 
9003                 list = define->content;
9004                 while (list != NULL) {
9005                     ret = xmlRelaxNGValidateValue(ctxt, list);
9006                     if (ret != 0) {
9007                         ret = -1;
9008                         break;
9009                     } else
9010                         ret = 0;
9011                     list = list->next;
9012                 }
9013                 break;
9014             }
9015         case XML_RELAXNG_REF:
9016         case XML_RELAXNG_PARENTREF:
9017 	    if (define->content == NULL) {
9018                 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9019                 ret = -1;
9020 	    } else {
9021                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
9022             }
9023             break;
9024         default:
9025             TODO ret = -1;
9026     }
9027     return (ret);
9028 }
9029 
9030 /**
9031  * xmlRelaxNGValidateValueContent:
9032  * @ctxt:  a Relax-NG validation context
9033  * @defines:  the list of definitions to verify
9034  *
9035  * Validate the given definitions for the current value
9036  *
9037  * Returns 0 if the validation succeeded or an error code.
9038  */
9039 static int
xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr defines)9040 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
9041                                xmlRelaxNGDefinePtr defines)
9042 {
9043     int ret = 0;
9044 
9045     while (defines != NULL) {
9046         ret = xmlRelaxNGValidateValue(ctxt, defines);
9047         if (ret != 0)
9048             break;
9049         defines = defines->next;
9050     }
9051     return (ret);
9052 }
9053 
9054 /**
9055  * xmlRelaxNGAttributeMatch:
9056  * @ctxt:  a Relax-NG validation context
9057  * @define:  the definition to check
9058  * @prop:  the attribute
9059  *
9060  * Check if the attribute matches the definition nameClass
9061  *
9062  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
9063  */
9064 static int
xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define,xmlAttrPtr prop)9065 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
9066                          xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
9067 {
9068     int ret;
9069 
9070     if (define->name != NULL) {
9071         if (!xmlStrEqual(define->name, prop->name))
9072             return (0);
9073     }
9074     if (define->ns != NULL) {
9075         if (define->ns[0] == 0) {
9076             if (prop->ns != NULL)
9077                 return (0);
9078         } else {
9079             if ((prop->ns == NULL) ||
9080                 (!xmlStrEqual(define->ns, prop->ns->href)))
9081                 return (0);
9082         }
9083     }
9084     if (define->nameClass == NULL)
9085         return (1);
9086     define = define->nameClass;
9087     if (define->type == XML_RELAXNG_EXCEPT) {
9088         xmlRelaxNGDefinePtr list;
9089 
9090         list = define->content;
9091         while (list != NULL) {
9092             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
9093             if (ret == 1)
9094                 return (0);
9095             if (ret < 0)
9096                 return (ret);
9097             list = list->next;
9098         }
9099     } else if (define->type == XML_RELAXNG_CHOICE) {
9100         xmlRelaxNGDefinePtr list;
9101 
9102         list = define->nameClass;
9103         while (list != NULL) {
9104             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
9105             if (ret == 1)
9106                 return (1);
9107             if (ret < 0)
9108                 return (ret);
9109             list = list->next;
9110         }
9111         return (0);
9112     } else {
9113     TODO}
9114     return (1);
9115 }
9116 
9117 /**
9118  * xmlRelaxNGValidateAttribute:
9119  * @ctxt:  a Relax-NG validation context
9120  * @define:  the definition to verify
9121  *
9122  * Validate the given attribute definition for that node
9123  *
9124  * Returns 0 if the validation succeeded or an error code.
9125  */
9126 static int
xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define)9127 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
9128                             xmlRelaxNGDefinePtr define)
9129 {
9130     int ret = 0, i;
9131     xmlChar *value, *oldvalue;
9132     xmlAttrPtr prop = NULL, tmp;
9133     xmlNodePtr oldseq;
9134 
9135     if (ctxt->state->nbAttrLeft <= 0)
9136         return (-1);
9137     if (define->name != NULL) {
9138         for (i = 0; i < ctxt->state->nbAttrs; i++) {
9139             tmp = ctxt->state->attrs[i];
9140             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
9141                 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
9142                      (tmp->ns == NULL)) ||
9143                     ((tmp->ns != NULL) &&
9144                      (xmlStrEqual(define->ns, tmp->ns->href)))) {
9145                     prop = tmp;
9146                     break;
9147                 }
9148             }
9149         }
9150         if (prop != NULL) {
9151             value = xmlNodeListGetString(prop->doc, prop->children, 1);
9152             oldvalue = ctxt->state->value;
9153             oldseq = ctxt->state->seq;
9154             ctxt->state->seq = (xmlNodePtr) prop;
9155             ctxt->state->value = value;
9156             ctxt->state->endvalue = NULL;
9157             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9158             if (ctxt->state->value != NULL)
9159                 value = ctxt->state->value;
9160             if (value != NULL)
9161                 xmlFree(value);
9162             ctxt->state->value = oldvalue;
9163             ctxt->state->seq = oldseq;
9164             if (ret == 0) {
9165                 /*
9166                  * flag the attribute as processed
9167                  */
9168                 ctxt->state->attrs[i] = NULL;
9169                 ctxt->state->nbAttrLeft--;
9170             }
9171         } else {
9172             ret = -1;
9173         }
9174 #ifdef DEBUG
9175         xmlGenericError(xmlGenericErrorContext,
9176                         "xmlRelaxNGValidateAttribute(%s): %d\n",
9177                         define->name, ret);
9178 #endif
9179     } else {
9180         for (i = 0; i < ctxt->state->nbAttrs; i++) {
9181             tmp = ctxt->state->attrs[i];
9182             if ((tmp != NULL) &&
9183                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
9184                 prop = tmp;
9185                 break;
9186             }
9187         }
9188         if (prop != NULL) {
9189             value = xmlNodeListGetString(prop->doc, prop->children, 1);
9190             oldvalue = ctxt->state->value;
9191             oldseq = ctxt->state->seq;
9192             ctxt->state->seq = (xmlNodePtr) prop;
9193             ctxt->state->value = value;
9194             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9195             if (ctxt->state->value != NULL)
9196                 value = ctxt->state->value;
9197             if (value != NULL)
9198                 xmlFree(value);
9199             ctxt->state->value = oldvalue;
9200             ctxt->state->seq = oldseq;
9201             if (ret == 0) {
9202                 /*
9203                  * flag the attribute as processed
9204                  */
9205                 ctxt->state->attrs[i] = NULL;
9206                 ctxt->state->nbAttrLeft--;
9207             }
9208         } else {
9209             ret = -1;
9210         }
9211 #ifdef DEBUG
9212         if (define->ns != NULL) {
9213             xmlGenericError(xmlGenericErrorContext,
9214                             "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9215                             define->ns, ret);
9216         } else {
9217             xmlGenericError(xmlGenericErrorContext,
9218                             "xmlRelaxNGValidateAttribute(anyName): %d\n",
9219                             ret);
9220         }
9221 #endif
9222     }
9223 
9224     return (ret);
9225 }
9226 
9227 /**
9228  * xmlRelaxNGValidateAttributeList:
9229  * @ctxt:  a Relax-NG validation context
9230  * @define:  the list of definition to verify
9231  *
9232  * Validate the given node against the list of attribute definitions
9233  *
9234  * Returns 0 if the validation succeeded or an error code.
9235  */
9236 static int
xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr defines)9237 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
9238                                 xmlRelaxNGDefinePtr defines)
9239 {
9240     int ret = 0, res;
9241     int needmore = 0;
9242     xmlRelaxNGDefinePtr cur;
9243 
9244     cur = defines;
9245     while (cur != NULL) {
9246         if (cur->type == XML_RELAXNG_ATTRIBUTE) {
9247             if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9248                 ret = -1;
9249         } else
9250             needmore = 1;
9251         cur = cur->next;
9252     }
9253     if (!needmore)
9254         return (ret);
9255     cur = defines;
9256     while (cur != NULL) {
9257         if (cur->type != XML_RELAXNG_ATTRIBUTE) {
9258             if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9259                 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9260                 if (res < 0)
9261                     ret = -1;
9262             } else {
9263                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9264                 return (-1);
9265             }
9266             if (res == -1)      /* continues on -2 */
9267                 break;
9268         }
9269         cur = cur->next;
9270     }
9271 
9272     return (ret);
9273 }
9274 
9275 /**
9276  * xmlRelaxNGNodeMatchesList:
9277  * @node:  the node
9278  * @list:  a NULL terminated array of definitions
9279  *
9280  * Check if a node can be matched by one of the definitions
9281  *
9282  * Returns 1 if matches 0 otherwise
9283  */
9284 static int
xmlRelaxNGNodeMatchesList(xmlNodePtr node,xmlRelaxNGDefinePtr * list)9285 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9286 {
9287     xmlRelaxNGDefinePtr cur;
9288     int i = 0, tmp;
9289 
9290     if ((node == NULL) || (list == NULL))
9291         return (0);
9292 
9293     cur = list[i++];
9294     while (cur != NULL) {
9295         if ((node->type == XML_ELEMENT_NODE) &&
9296             (cur->type == XML_RELAXNG_ELEMENT)) {
9297             tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9298             if (tmp == 1)
9299                 return (1);
9300         } else if (((node->type == XML_TEXT_NODE) ||
9301                     (node->type == XML_CDATA_SECTION_NODE)) &&
9302                    ((cur->type == XML_RELAXNG_DATATYPE) ||
9303 		    (cur->type == XML_RELAXNG_LIST) ||
9304                     (cur->type == XML_RELAXNG_TEXT) ||
9305                     (cur->type == XML_RELAXNG_VALUE))) {
9306             return (1);
9307         }
9308         cur = list[i++];
9309     }
9310     return (0);
9311 }
9312 
9313 /**
9314  * xmlRelaxNGValidateInterleave:
9315  * @ctxt:  a Relax-NG validation context
9316  * @define:  the definition to verify
9317  *
9318  * Validate an interleave definition for a node.
9319  *
9320  * Returns 0 if the validation succeeded or an error code.
9321  */
9322 static int
xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define)9323 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9324                              xmlRelaxNGDefinePtr define)
9325 {
9326     int ret = 0, i, nbgroups;
9327     int errNr = ctxt->errNr;
9328     int oldflags;
9329 
9330     xmlRelaxNGValidStatePtr oldstate;
9331     xmlRelaxNGPartitionPtr partitions;
9332     xmlRelaxNGInterleaveGroupPtr group = NULL;
9333     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9334     xmlNodePtr *list = NULL, *lasts = NULL;
9335 
9336     if (define->data != NULL) {
9337         partitions = (xmlRelaxNGPartitionPtr) define->data;
9338         nbgroups = partitions->nbgroups;
9339     } else {
9340         VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9341         return (-1);
9342     }
9343     /*
9344      * Optimizations for MIXED
9345      */
9346     oldflags = ctxt->flags;
9347     if (define->dflags & IS_MIXED) {
9348         ctxt->flags |= FLAGS_MIXED_CONTENT;
9349         if (nbgroups == 2) {
9350             /*
9351              * this is a pure <mixed> case
9352              */
9353             if (ctxt->state != NULL)
9354                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9355                                                          ctxt->state->seq);
9356             if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9357                 ret = xmlRelaxNGValidateDefinition(ctxt,
9358                                                    partitions->groups[1]->
9359                                                    rule);
9360             else
9361                 ret = xmlRelaxNGValidateDefinition(ctxt,
9362                                                    partitions->groups[0]->
9363                                                    rule);
9364             if (ret == 0) {
9365                 if (ctxt->state != NULL)
9366                     ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9367                                                              ctxt->state->
9368                                                              seq);
9369             }
9370             ctxt->flags = oldflags;
9371             return (ret);
9372         }
9373     }
9374 
9375     /*
9376      * Build arrays to store the first and last node of the chain
9377      * pertaining to each group
9378      */
9379     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9380     if (list == NULL) {
9381         xmlRngVErrMemory(ctxt, "validating\n");
9382         return (-1);
9383     }
9384     memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9385     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9386     if (lasts == NULL) {
9387         xmlRngVErrMemory(ctxt, "validating\n");
9388         return (-1);
9389     }
9390     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9391 
9392     /*
9393      * Walk the sequence of children finding the right group and
9394      * sorting them in sequences.
9395      */
9396     cur = ctxt->state->seq;
9397     cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9398     start = cur;
9399     while (cur != NULL) {
9400         ctxt->state->seq = cur;
9401         if ((partitions->triage != NULL) &&
9402             (partitions->flags & IS_DETERMINIST)) {
9403             void *tmp = NULL;
9404 
9405             if ((cur->type == XML_TEXT_NODE) ||
9406                 (cur->type == XML_CDATA_SECTION_NODE)) {
9407                 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9408                                      NULL);
9409             } else if (cur->type == XML_ELEMENT_NODE) {
9410                 if (cur->ns != NULL) {
9411                     tmp = xmlHashLookup2(partitions->triage, cur->name,
9412                                          cur->ns->href);
9413                     if (tmp == NULL)
9414                         tmp = xmlHashLookup2(partitions->triage,
9415                                              BAD_CAST "#any",
9416                                              cur->ns->href);
9417                 } else
9418                     tmp =
9419                         xmlHashLookup2(partitions->triage, cur->name,
9420                                        NULL);
9421                 if (tmp == NULL)
9422                     tmp =
9423                         xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9424                                        NULL);
9425             }
9426 
9427             if (tmp == NULL) {
9428                 i = nbgroups;
9429             } else {
9430                 i = ((ptrdiff_t) tmp) - 1;
9431                 if (partitions->flags & IS_NEEDCHECK) {
9432                     group = partitions->groups[i];
9433                     if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9434                         i = nbgroups;
9435                 }
9436             }
9437         } else {
9438             for (i = 0; i < nbgroups; i++) {
9439                 group = partitions->groups[i];
9440                 if (group == NULL)
9441                     continue;
9442                 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9443                     break;
9444             }
9445         }
9446         /*
9447          * We break as soon as an element not matched is found
9448          */
9449         if (i >= nbgroups) {
9450             break;
9451         }
9452         if (lasts[i] != NULL) {
9453             lasts[i]->next = cur;
9454             lasts[i] = cur;
9455         } else {
9456             list[i] = cur;
9457             lasts[i] = cur;
9458         }
9459         if (cur->next != NULL)
9460             lastchg = cur->next;
9461         else
9462             lastchg = cur;
9463         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9464     }
9465     if (ret != 0) {
9466         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9467         ret = -1;
9468         goto done;
9469     }
9470     lastelem = cur;
9471     oldstate = ctxt->state;
9472     for (i = 0; i < nbgroups; i++) {
9473         ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9474 	if (ctxt->state == NULL) {
9475 	    ret = -1;
9476 	    break;
9477 	}
9478         group = partitions->groups[i];
9479         if (lasts[i] != NULL) {
9480             last = lasts[i]->next;
9481             lasts[i]->next = NULL;
9482         }
9483         ctxt->state->seq = list[i];
9484         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9485         if (ret != 0)
9486             break;
9487         if (ctxt->state != NULL) {
9488             cur = ctxt->state->seq;
9489             cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9490             xmlRelaxNGFreeValidState(ctxt, oldstate);
9491             oldstate = ctxt->state;
9492             ctxt->state = NULL;
9493             if (cur != NULL
9494                     /* there's a nasty violation of context-free unambiguities,
9495                        since in open-name-class context, interleave in the
9496                        production shall finish without caring about anything
9497                        else that is OK to follow in that case -- it would
9498                        otherwise get marked as "extra content" and would
9499                        hence fail the validation, hence this perhaps
9500                        dirty attempt to rectify such a situation */
9501                     && (define->parent->type != XML_RELAXNG_DEF
9502                         || !xmlStrEqual(define->parent->name,
9503                                         (const xmlChar *) "open-name-class"))) {
9504                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9505                 ret = -1;
9506                 ctxt->state = oldstate;
9507                 goto done;
9508             }
9509         } else if (ctxt->states != NULL) {
9510             int j;
9511             int found = 0;
9512 	    int best = -1;
9513 	    int lowattr = -1;
9514 
9515 	    /*
9516 	     * PBM: what happen if there is attributes checks in the interleaves
9517 	     */
9518 
9519             for (j = 0; j < ctxt->states->nbState; j++) {
9520                 cur = ctxt->states->tabState[j]->seq;
9521                 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9522                 if (cur == NULL) {
9523 		    if (found == 0) {
9524 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9525 			best = j;
9526 		    }
9527                     found = 1;
9528 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9529 		        /* try  to keep the latest one to mach old heuristic */
9530 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9531 			best = j;
9532 		    }
9533                     if (lowattr == 0)
9534 		        break;
9535                 } else if (found == 0) {
9536                     if (lowattr == -1) {
9537 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9538 			best = j;
9539 		    } else
9540 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr)  {
9541 		        /* try  to keep the latest one to mach old heuristic */
9542 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9543 			best = j;
9544 		    }
9545 		}
9546             }
9547 	    /*
9548 	     * BIG PBM: here we pick only one restarting point :-(
9549 	     */
9550             if (ctxt->states->nbState > 0) {
9551                 xmlRelaxNGFreeValidState(ctxt, oldstate);
9552 		if (best != -1) {
9553 		    oldstate = ctxt->states->tabState[best];
9554 		    ctxt->states->tabState[best] = NULL;
9555 		} else {
9556 		    oldstate =
9557 			ctxt->states->tabState[ctxt->states->nbState - 1];
9558                     ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
9559                     ctxt->states->nbState--;
9560 		}
9561             }
9562             for (j = 0; j < ctxt->states->nbState ; j++) {
9563                 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9564             }
9565             xmlRelaxNGFreeStates(ctxt, ctxt->states);
9566             ctxt->states = NULL;
9567             if (found == 0) {
9568                 if (cur == NULL) {
9569 		    VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
9570 			       (const xmlChar *) "noname");
9571                 } else {
9572                     VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9573                 }
9574                 ret = -1;
9575                 ctxt->state = oldstate;
9576                 goto done;
9577             }
9578         } else {
9579             ret = -1;
9580             break;
9581         }
9582         if (lasts[i] != NULL) {
9583             lasts[i]->next = last;
9584         }
9585     }
9586     if (ctxt->state != NULL)
9587         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9588     ctxt->state = oldstate;
9589     ctxt->state->seq = lastelem;
9590     if (ret != 0) {
9591         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9592         ret = -1;
9593         goto done;
9594     }
9595 
9596   done:
9597     ctxt->flags = oldflags;
9598     /*
9599      * builds the next links chain from the prev one
9600      */
9601     cur = lastchg;
9602     while (cur != NULL) {
9603         if ((cur == start) || (cur->prev == NULL))
9604             break;
9605         cur->prev->next = cur;
9606         cur = cur->prev;
9607     }
9608     if (ret == 0) {
9609         if (ctxt->errNr > errNr)
9610             xmlRelaxNGPopErrors(ctxt, errNr);
9611     }
9612 
9613     xmlFree(list);
9614     xmlFree(lasts);
9615     return (ret);
9616 }
9617 
9618 /**
9619  * xmlRelaxNGValidateDefinitionList:
9620  * @ctxt:  a Relax-NG validation context
9621  * @define:  the list of definition to verify
9622  *
9623  * Validate the given node content against the (list) of definitions
9624  *
9625  * Returns 0 if the validation succeeded or an error code.
9626  */
9627 static int
xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr defines)9628 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9629                                  xmlRelaxNGDefinePtr defines)
9630 {
9631     int ret = 0, res;
9632 
9633 
9634     if (defines == NULL) {
9635         VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9636                    BAD_CAST "NULL definition list");
9637         return (-1);
9638     }
9639     while (defines != NULL) {
9640         if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9641             res = xmlRelaxNGValidateDefinition(ctxt, defines);
9642             if (res < 0)
9643                 ret = -1;
9644         } else {
9645             VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9646             return (-1);
9647         }
9648         if (res == -1)          /* continues on -2 */
9649             break;
9650         defines = defines->next;
9651     }
9652 
9653     return (ret);
9654 }
9655 
9656 /**
9657  * xmlRelaxNGElementMatch:
9658  * @ctxt:  a Relax-NG validation context
9659  * @define:  the definition to check
9660  * @elem:  the element
9661  *
9662  * Check if the element matches the definition nameClass
9663  *
9664  * Returns 1 if the element matches, 0 if no, or -1 in case of error
9665  */
9666 static int
xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define,xmlNodePtr elem)9667 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9668                        xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9669 {
9670     int ret = 0, oldflags = 0;
9671 
9672     if (define->name != NULL) {
9673         if (!xmlStrEqual(elem->name, define->name)) {
9674             VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9675             return (0);
9676         }
9677     }
9678     if ((define->ns != NULL) && (define->ns[0] != 0)) {
9679         if (elem->ns == NULL) {
9680             VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9681             return (0);
9682         } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9683             VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9684                        elem->name, define->ns);
9685             return (0);
9686         }
9687     } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9688                (define->name == NULL)) {
9689         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9690         return (0);
9691     } else if ((elem->ns != NULL) && (define->name != NULL)) {
9692         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9693         return (0);
9694     }
9695 
9696     if (define->nameClass == NULL)
9697         return (1);
9698 
9699     define = define->nameClass;
9700     if (define->type == XML_RELAXNG_EXCEPT) {
9701         xmlRelaxNGDefinePtr list;
9702 
9703         if (ctxt != NULL) {
9704             oldflags = ctxt->flags;
9705             ctxt->flags |= FLAGS_IGNORABLE;
9706         }
9707 
9708         list = define->content;
9709         while (list != NULL) {
9710             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9711             if (ret == 1) {
9712                 if (ctxt != NULL)
9713                     ctxt->flags = oldflags;
9714                 return (0);
9715             }
9716             if (ret < 0) {
9717                 if (ctxt != NULL)
9718                     ctxt->flags = oldflags;
9719                 return (ret);
9720             }
9721             list = list->next;
9722         }
9723         ret = 1;
9724         if (ctxt != NULL) {
9725             ctxt->flags = oldflags;
9726         }
9727     } else if (define->type == XML_RELAXNG_CHOICE) {
9728         xmlRelaxNGDefinePtr list;
9729 
9730         if (ctxt != NULL) {
9731             oldflags = ctxt->flags;
9732             ctxt->flags |= FLAGS_IGNORABLE;
9733         }
9734 
9735         list = define->nameClass;
9736         while (list != NULL) {
9737             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9738             if (ret == 1) {
9739                 if (ctxt != NULL)
9740                     ctxt->flags = oldflags;
9741                 return (1);
9742             }
9743             if (ret < 0) {
9744                 if (ctxt != NULL)
9745                     ctxt->flags = oldflags;
9746                 return (ret);
9747             }
9748             list = list->next;
9749         }
9750         if (ctxt != NULL) {
9751             if (ret != 0) {
9752                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9753                     xmlRelaxNGDumpValidError(ctxt);
9754             } else {
9755                 if (ctxt->errNr > 0)
9756                     xmlRelaxNGPopErrors(ctxt, 0);
9757             }
9758         }
9759         ret = 0;
9760         if (ctxt != NULL) {
9761             ctxt->flags = oldflags;
9762         }
9763     } else {
9764         TODO ret = -1;
9765     }
9766     return (ret);
9767 }
9768 
9769 /**
9770  * xmlRelaxNGBestState:
9771  * @ctxt:  a Relax-NG validation context
9772  *
9773  * Find the "best" state in the ctxt->states list of states to report
9774  * errors about. I.e. a state with no element left in the child list
9775  * or the one with the less attributes left.
9776  * This is called only if a validation error was detected
9777  *
9778  * Returns the index of the "best" state or -1 in case of error
9779  */
9780 static int
xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)9781 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9782 {
9783     xmlRelaxNGValidStatePtr state;
9784     int i, tmp;
9785     int best = -1;
9786     int value = 1000000;
9787 
9788     if ((ctxt == NULL) || (ctxt->states == NULL) ||
9789         (ctxt->states->nbState <= 0))
9790         return (-1);
9791 
9792     for (i = 0; i < ctxt->states->nbState; i++) {
9793         state = ctxt->states->tabState[i];
9794         if (state == NULL)
9795             continue;
9796         if (state->seq != NULL) {
9797             if ((best == -1) || (value > 100000)) {
9798                 value = 100000;
9799                 best = i;
9800             }
9801         } else {
9802             tmp = state->nbAttrLeft;
9803             if ((best == -1) || (value > tmp)) {
9804                 value = tmp;
9805                 best = i;
9806             }
9807         }
9808     }
9809     return (best);
9810 }
9811 
9812 /**
9813  * xmlRelaxNGLogBestError:
9814  * @ctxt:  a Relax-NG validation context
9815  *
9816  * Find the "best" state in the ctxt->states list of states to report
9817  * errors about and log it.
9818  */
9819 static void
xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)9820 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9821 {
9822     int best;
9823 
9824     if ((ctxt == NULL) || (ctxt->states == NULL) ||
9825         (ctxt->states->nbState <= 0))
9826         return;
9827 
9828     best = xmlRelaxNGBestState(ctxt);
9829     if ((best >= 0) && (best < ctxt->states->nbState)) {
9830         ctxt->state = ctxt->states->tabState[best];
9831 
9832         xmlRelaxNGValidateElementEnd(ctxt, 1);
9833     }
9834 }
9835 
9836 /**
9837  * xmlRelaxNGValidateElementEnd:
9838  * @ctxt:  a Relax-NG validation context
9839  * @dolog:  indicate that error logging should be done
9840  *
9841  * Validate the end of the element, implements check that
9842  * there is nothing left not consumed in the element content
9843  * or in the attribute list.
9844  *
9845  * Returns 0 if the validation succeeded or an error code.
9846  */
9847 static int
xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,int dolog)9848 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
9849 {
9850     int i;
9851     xmlRelaxNGValidStatePtr state;
9852 
9853     state = ctxt->state;
9854     if (state->seq != NULL) {
9855         state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9856         if (state->seq != NULL) {
9857             if (dolog) {
9858                 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9859                            state->node->name, state->seq->name);
9860             }
9861             return (-1);
9862         }
9863     }
9864     for (i = 0; i < state->nbAttrs; i++) {
9865         if (state->attrs[i] != NULL) {
9866             if (dolog) {
9867                 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9868                            state->attrs[i]->name, state->node->name);
9869             }
9870             return (-1 - i);
9871         }
9872     }
9873     return (0);
9874 }
9875 
9876 /**
9877  * xmlRelaxNGValidateState:
9878  * @ctxt:  a Relax-NG validation context
9879  * @define:  the definition to verify
9880  *
9881  * Validate the current state against the definition
9882  *
9883  * Returns 0 if the validation succeeded or an error code.
9884  */
9885 static int
xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define)9886 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9887                         xmlRelaxNGDefinePtr define)
9888 {
9889     xmlNodePtr node;
9890     int ret = 0, i, tmp, oldflags, errNr;
9891     xmlRelaxNGValidStatePtr oldstate = NULL, state;
9892 
9893     if (define == NULL) {
9894         VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9895         return (-1);
9896     }
9897 
9898     if (ctxt->state != NULL) {
9899         node = ctxt->state->seq;
9900     } else {
9901         node = NULL;
9902     }
9903 #ifdef DEBUG
9904     for (i = 0; i < ctxt->depth; i++)
9905         xmlGenericError(xmlGenericErrorContext, " ");
9906     xmlGenericError(xmlGenericErrorContext,
9907                     "Start validating %s ", xmlRelaxNGDefName(define));
9908     if (define->name != NULL)
9909         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
9910     if ((node != NULL) && (node->name != NULL))
9911         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
9912     else
9913         xmlGenericError(xmlGenericErrorContext, "\n");
9914 #endif
9915     ctxt->depth++;
9916     switch (define->type) {
9917         case XML_RELAXNG_EMPTY:
9918             ret = 0;
9919             break;
9920         case XML_RELAXNG_NOT_ALLOWED:
9921             ret = -1;
9922             break;
9923         case XML_RELAXNG_TEXT:
9924             while ((node != NULL) &&
9925                    ((node->type == XML_TEXT_NODE) ||
9926                     (node->type == XML_COMMENT_NODE) ||
9927                     (node->type == XML_PI_NODE) ||
9928                     (node->type == XML_CDATA_SECTION_NODE)))
9929                 node = node->next;
9930             ctxt->state->seq = node;
9931             break;
9932         case XML_RELAXNG_ELEMENT:
9933             errNr = ctxt->errNr;
9934             node = xmlRelaxNGSkipIgnored(ctxt, node);
9935             if (node == NULL) {
9936                 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9937                 ret = -1;
9938                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9939                     xmlRelaxNGDumpValidError(ctxt);
9940                 break;
9941             }
9942             if (node->type != XML_ELEMENT_NODE) {
9943                 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9944                 ret = -1;
9945                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9946                     xmlRelaxNGDumpValidError(ctxt);
9947                 break;
9948             }
9949             /*
9950              * This node was already validated successfully against
9951              * this definition.
9952              */
9953             if (node->psvi == define) {
9954                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9955                 if (ctxt->errNr > errNr)
9956                     xmlRelaxNGPopErrors(ctxt, errNr);
9957                 if (ctxt->errNr != 0) {
9958                     while ((ctxt->err != NULL) &&
9959                            (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9960                              && (xmlStrEqual(ctxt->err->arg2, node->name)))
9961                             ||
9962                             ((ctxt->err->err ==
9963                               XML_RELAXNG_ERR_ELEMEXTRANS)
9964                              && (xmlStrEqual(ctxt->err->arg1, node->name)))
9965                             || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9966                             || (ctxt->err->err ==
9967                                 XML_RELAXNG_ERR_NOTELEM)))
9968                         xmlRelaxNGValidErrorPop(ctxt);
9969                 }
9970                 break;
9971             }
9972 
9973             ret = xmlRelaxNGElementMatch(ctxt, define, node);
9974             if (ret <= 0) {
9975                 ret = -1;
9976                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9977                     xmlRelaxNGDumpValidError(ctxt);
9978                 break;
9979             }
9980             ret = 0;
9981             if (ctxt->errNr != 0) {
9982                 if (ctxt->errNr > errNr)
9983                     xmlRelaxNGPopErrors(ctxt, errNr);
9984                 while ((ctxt->err != NULL) &&
9985                        (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9986                          (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9987                         ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9988                          (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9989                         (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9990                         (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9991                     xmlRelaxNGValidErrorPop(ctxt);
9992             }
9993             errNr = ctxt->errNr;
9994 
9995             oldflags = ctxt->flags;
9996             if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9997                 ctxt->flags -= FLAGS_MIXED_CONTENT;
9998             }
9999             state = xmlRelaxNGNewValidState(ctxt, node);
10000             if (state == NULL) {
10001                 ret = -1;
10002                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
10003                     xmlRelaxNGDumpValidError(ctxt);
10004                 break;
10005             }
10006 
10007             oldstate = ctxt->state;
10008             ctxt->state = state;
10009             if (define->attrs != NULL) {
10010                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
10011                 if (tmp != 0) {
10012                     ret = -1;
10013                     VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
10014                 }
10015             }
10016             if (define->contModel != NULL) {
10017                 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
10018                 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
10019                 xmlNodePtr nseq;
10020 
10021                 nstate = xmlRelaxNGNewValidState(ctxt, node);
10022                 ctxt->state = nstate;
10023                 ctxt->states = NULL;
10024 
10025                 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
10026                                                         define->contModel,
10027                                                         ctxt->state->seq);
10028                 nseq = ctxt->state->seq;
10029                 ctxt->state = tmpstate;
10030                 ctxt->states = tmpstates;
10031                 xmlRelaxNGFreeValidState(ctxt, nstate);
10032 
10033 #ifdef DEBUG_COMPILE
10034                 xmlGenericError(xmlGenericErrorContext,
10035                                 "Validating content of '%s' : %d\n",
10036                                 define->name, tmp);
10037 #endif
10038                 if (tmp != 0)
10039                     ret = -1;
10040 
10041                 if (ctxt->states != NULL) {
10042                     tmp = -1;
10043 
10044                     for (i = 0; i < ctxt->states->nbState; i++) {
10045                         state = ctxt->states->tabState[i];
10046                         ctxt->state = state;
10047                         ctxt->state->seq = nseq;
10048 
10049                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
10050                             tmp = 0;
10051                             break;
10052                         }
10053                     }
10054                     if (tmp != 0) {
10055                         /*
10056                          * validation error, log the message for the "best" one
10057                          */
10058                         ctxt->flags |= FLAGS_IGNORABLE;
10059                         xmlRelaxNGLogBestError(ctxt);
10060                     }
10061                     for (i = 0; i < ctxt->states->nbState; i++) {
10062                         xmlRelaxNGFreeValidState(ctxt,
10063                                                  ctxt->states->
10064                                                  tabState[i]);
10065                     }
10066                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10067                     ctxt->flags = oldflags;
10068                     ctxt->states = NULL;
10069                     if ((ret == 0) && (tmp == -1))
10070                         ret = -1;
10071                 } else {
10072                     state = ctxt->state;
10073 		    if (ctxt->state != NULL)
10074 			ctxt->state->seq = nseq;
10075                     if (ret == 0)
10076                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10077                     xmlRelaxNGFreeValidState(ctxt, state);
10078                 }
10079             } else {
10080                 if (define->content != NULL) {
10081                     tmp = xmlRelaxNGValidateDefinitionList(ctxt,
10082                                                            define->
10083                                                            content);
10084                     if (tmp != 0) {
10085                         ret = -1;
10086                         if (ctxt->state == NULL) {
10087                             ctxt->state = oldstate;
10088                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10089                                        node->name);
10090                             ctxt->state = NULL;
10091                         } else {
10092                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10093                                        node->name);
10094                         }
10095 
10096                     }
10097                 }
10098                 if (ctxt->states != NULL) {
10099                     tmp = -1;
10100 
10101                     for (i = 0; i < ctxt->states->nbState; i++) {
10102                         state = ctxt->states->tabState[i];
10103                         ctxt->state = state;
10104 
10105                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
10106                             tmp = 0;
10107                             break;
10108                         }
10109                     }
10110                     if (tmp != 0) {
10111                         /*
10112                          * validation error, log the message for the "best" one
10113                          */
10114                         ctxt->flags |= FLAGS_IGNORABLE;
10115                         xmlRelaxNGLogBestError(ctxt);
10116                     }
10117                     for (i = 0; i < ctxt->states->nbState; i++) {
10118                         xmlRelaxNGFreeValidState(ctxt,
10119                                                  ctxt->states->tabState[i]);
10120                         ctxt->states->tabState[i] = NULL;
10121                     }
10122                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10123                     ctxt->flags = oldflags;
10124                     ctxt->states = NULL;
10125                     if ((ret == 0) && (tmp == -1))
10126                         ret = -1;
10127                 } else {
10128                     state = ctxt->state;
10129                     if (ret == 0)
10130                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10131                     xmlRelaxNGFreeValidState(ctxt, state);
10132                 }
10133             }
10134             if (ret == 0) {
10135                 node->psvi = define;
10136             }
10137             ctxt->flags = oldflags;
10138             ctxt->state = oldstate;
10139             if (oldstate != NULL)
10140                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
10141             if (ret != 0) {
10142                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10143                     xmlRelaxNGDumpValidError(ctxt);
10144                     ret = 0;
10145 #if 0
10146                 } else {
10147                     ret = -2;
10148 #endif
10149                 }
10150             } else {
10151                 if (ctxt->errNr > errNr)
10152                     xmlRelaxNGPopErrors(ctxt, errNr);
10153             }
10154 
10155 #ifdef DEBUG
10156             xmlGenericError(xmlGenericErrorContext,
10157                             "xmlRelaxNGValidateDefinition(): validated %s : %d",
10158                             node->name, ret);
10159             if (oldstate == NULL)
10160                 xmlGenericError(xmlGenericErrorContext, ": no state\n");
10161             else if (oldstate->seq == NULL)
10162                 xmlGenericError(xmlGenericErrorContext, ": done\n");
10163             else if (oldstate->seq->type == XML_ELEMENT_NODE)
10164                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
10165                                 oldstate->seq->name);
10166             else
10167                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
10168                                 oldstate->seq->name, oldstate->seq->type);
10169 #endif
10170             break;
10171         case XML_RELAXNG_OPTIONAL:{
10172                 errNr = ctxt->errNr;
10173                 oldflags = ctxt->flags;
10174                 ctxt->flags |= FLAGS_IGNORABLE;
10175                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10176                 ret =
10177                     xmlRelaxNGValidateDefinitionList(ctxt,
10178                                                      define->content);
10179                 if (ret != 0) {
10180                     if (ctxt->state != NULL)
10181                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10182                     ctxt->state = oldstate;
10183                     ctxt->flags = oldflags;
10184                     ret = 0;
10185                     if (ctxt->errNr > errNr)
10186                         xmlRelaxNGPopErrors(ctxt, errNr);
10187                     break;
10188                 }
10189                 if (ctxt->states != NULL) {
10190                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10191                 } else {
10192                     ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
10193                     if (ctxt->states == NULL) {
10194                         xmlRelaxNGFreeValidState(ctxt, oldstate);
10195                         ctxt->flags = oldflags;
10196                         ret = -1;
10197                         if (ctxt->errNr > errNr)
10198                             xmlRelaxNGPopErrors(ctxt, errNr);
10199                         break;
10200                     }
10201                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10202                     xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
10203                     ctxt->state = NULL;
10204                 }
10205                 ctxt->flags = oldflags;
10206                 ret = 0;
10207                 if (ctxt->errNr > errNr)
10208                     xmlRelaxNGPopErrors(ctxt, errNr);
10209                 break;
10210             }
10211         case XML_RELAXNG_ONEORMORE:
10212             errNr = ctxt->errNr;
10213             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10214             if (ret != 0) {
10215                 break;
10216             }
10217             if (ctxt->errNr > errNr)
10218                 xmlRelaxNGPopErrors(ctxt, errNr);
10219             /* Falls through. */
10220         case XML_RELAXNG_ZEROORMORE:{
10221                 int progress;
10222                 xmlRelaxNGStatesPtr states = NULL, res = NULL;
10223                 int base, j;
10224 
10225                 errNr = ctxt->errNr;
10226                 res = xmlRelaxNGNewStates(ctxt, 1);
10227                 if (res == NULL) {
10228                     ret = -1;
10229                     break;
10230                 }
10231                 /*
10232                  * All the input states are also exit states
10233                  */
10234                 if (ctxt->state != NULL) {
10235                     xmlRelaxNGAddStates(ctxt, res,
10236                                         xmlRelaxNGCopyValidState(ctxt,
10237                                                                  ctxt->
10238                                                                  state));
10239                 } else {
10240                     for (j = 0; j < ctxt->states->nbState; j++) {
10241                         xmlRelaxNGAddStates(ctxt, res,
10242                             xmlRelaxNGCopyValidState(ctxt,
10243                                             ctxt->states->tabState[j]));
10244                     }
10245                 }
10246                 oldflags = ctxt->flags;
10247                 ctxt->flags |= FLAGS_IGNORABLE;
10248                 do {
10249                     progress = 0;
10250                     base = res->nbState;
10251 
10252                     if (ctxt->states != NULL) {
10253                         states = ctxt->states;
10254                         for (i = 0; i < states->nbState; i++) {
10255                             ctxt->state = states->tabState[i];
10256                             ctxt->states = NULL;
10257                             ret = xmlRelaxNGValidateDefinitionList(ctxt,
10258                                                                    define->
10259                                                                    content);
10260                             if (ret == 0) {
10261                                 if (ctxt->state != NULL) {
10262                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10263                                                               ctxt->state);
10264                                     ctxt->state = NULL;
10265                                     if (tmp == 1)
10266                                         progress = 1;
10267                                 } else if (ctxt->states != NULL) {
10268                                     for (j = 0; j < ctxt->states->nbState;
10269                                          j++) {
10270                                         tmp =
10271                                             xmlRelaxNGAddStates(ctxt, res,
10272                                                    ctxt->states->tabState[j]);
10273                                         if (tmp == 1)
10274                                             progress = 1;
10275                                     }
10276                                     xmlRelaxNGFreeStates(ctxt,
10277                                                          ctxt->states);
10278                                     ctxt->states = NULL;
10279                                 }
10280                             } else {
10281                                 if (ctxt->state != NULL) {
10282                                     xmlRelaxNGFreeValidState(ctxt,
10283                                                              ctxt->state);
10284                                     ctxt->state = NULL;
10285                                 }
10286                             }
10287                         }
10288                     } else {
10289                         ret = xmlRelaxNGValidateDefinitionList(ctxt,
10290                                                                define->
10291                                                                content);
10292                         if (ret != 0) {
10293                             xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10294                             ctxt->state = NULL;
10295                         } else {
10296                             base = res->nbState;
10297                             if (ctxt->state != NULL) {
10298                                 tmp = xmlRelaxNGAddStates(ctxt, res,
10299                                                           ctxt->state);
10300                                 ctxt->state = NULL;
10301                                 if (tmp == 1)
10302                                     progress = 1;
10303                             } else if (ctxt->states != NULL) {
10304                                 for (j = 0; j < ctxt->states->nbState; j++) {
10305                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10306                                                ctxt->states->tabState[j]);
10307                                     if (tmp == 1)
10308                                         progress = 1;
10309                                 }
10310                                 if (states == NULL) {
10311                                     states = ctxt->states;
10312                                 } else {
10313                                     xmlRelaxNGFreeStates(ctxt,
10314                                                          ctxt->states);
10315                                 }
10316                                 ctxt->states = NULL;
10317                             }
10318                         }
10319                     }
10320                     if (progress) {
10321                         /*
10322                          * Collect all the new nodes added at that step
10323                          * and make them the new node set
10324                          */
10325                         if (res->nbState - base == 1) {
10326                             ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10327                                                                    res->
10328                                                                    tabState
10329                                                                    [base]);
10330                         } else {
10331                             if (states == NULL) {
10332                                 xmlRelaxNGNewStates(ctxt,
10333                                                     res->nbState - base);
10334 			        states = ctxt->states;
10335 				if (states == NULL) {
10336 				    progress = 0;
10337 				    break;
10338 				}
10339                             }
10340                             states->nbState = 0;
10341                             for (i = base; i < res->nbState; i++)
10342                                 xmlRelaxNGAddStates(ctxt, states,
10343                                                     xmlRelaxNGCopyValidState
10344                                                     (ctxt, res->tabState[i]));
10345                             ctxt->states = states;
10346                         }
10347                     }
10348                 } while (progress == 1);
10349                 if (states != NULL) {
10350                     xmlRelaxNGFreeStates(ctxt, states);
10351                 }
10352                 ctxt->states = res;
10353                 ctxt->flags = oldflags;
10354 #if 0
10355                 /*
10356                  * errors may have to be propagated back...
10357                  */
10358                 if (ctxt->errNr > errNr)
10359                     xmlRelaxNGPopErrors(ctxt, errNr);
10360 #endif
10361                 ret = 0;
10362                 break;
10363             }
10364         case XML_RELAXNG_CHOICE:{
10365                 xmlRelaxNGDefinePtr list = NULL;
10366                 xmlRelaxNGStatesPtr states = NULL;
10367 
10368                 node = xmlRelaxNGSkipIgnored(ctxt, node);
10369 
10370                 errNr = ctxt->errNr;
10371                 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10372 		    (node != NULL)) {
10373 		    /*
10374 		     * node == NULL can't be optimized since IS_TRIABLE
10375 		     * doesn't account for choice which may lead to
10376 		     * only attributes.
10377 		     */
10378                     xmlHashTablePtr triage =
10379                         (xmlHashTablePtr) define->data;
10380 
10381                     /*
10382                      * Something we can optimize cleanly there is only one
10383                      * possible branch out !
10384                      */
10385                     if ((node->type == XML_TEXT_NODE) ||
10386                         (node->type == XML_CDATA_SECTION_NODE)) {
10387                         list =
10388                             xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10389                     } else if (node->type == XML_ELEMENT_NODE) {
10390                         if (node->ns != NULL) {
10391                             list = xmlHashLookup2(triage, node->name,
10392                                                   node->ns->href);
10393                             if (list == NULL)
10394                                 list =
10395                                     xmlHashLookup2(triage, BAD_CAST "#any",
10396                                                    node->ns->href);
10397                         } else
10398                             list =
10399                                 xmlHashLookup2(triage, node->name, NULL);
10400                         if (list == NULL)
10401                             list =
10402                                 xmlHashLookup2(triage, BAD_CAST "#any",
10403                                                NULL);
10404                     }
10405                     if (list == NULL) {
10406                         ret = -1;
10407 			VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
10408                         break;
10409                     }
10410                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10411                     if (ret == 0) {
10412                     }
10413                     break;
10414                 }
10415 
10416                 list = define->content;
10417                 oldflags = ctxt->flags;
10418                 ctxt->flags |= FLAGS_IGNORABLE;
10419 
10420                 while (list != NULL) {
10421                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10422                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10423                     if (ret == 0) {
10424                         if (states == NULL) {
10425                             states = xmlRelaxNGNewStates(ctxt, 1);
10426                         }
10427                         if (ctxt->state != NULL) {
10428                             xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10429                         } else if (ctxt->states != NULL) {
10430                             for (i = 0; i < ctxt->states->nbState; i++) {
10431                                 xmlRelaxNGAddStates(ctxt, states,
10432                                                     ctxt->states->
10433                                                     tabState[i]);
10434                             }
10435                             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10436                             ctxt->states = NULL;
10437                         }
10438                     } else {
10439                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10440                     }
10441                     ctxt->state = oldstate;
10442                     list = list->next;
10443                 }
10444                 if (states != NULL) {
10445                     xmlRelaxNGFreeValidState(ctxt, oldstate);
10446                     ctxt->states = states;
10447                     ctxt->state = NULL;
10448                     ret = 0;
10449                 } else {
10450                     ctxt->states = NULL;
10451                 }
10452                 ctxt->flags = oldflags;
10453                 if (ret != 0) {
10454                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10455                         xmlRelaxNGDumpValidError(ctxt);
10456                     }
10457                 } else {
10458                     if (ctxt->errNr > errNr)
10459                         xmlRelaxNGPopErrors(ctxt, errNr);
10460                 }
10461                 break;
10462             }
10463         case XML_RELAXNG_DEF:
10464         case XML_RELAXNG_GROUP:
10465             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10466             break;
10467         case XML_RELAXNG_INTERLEAVE:
10468             ret = xmlRelaxNGValidateInterleave(ctxt, define);
10469             break;
10470         case XML_RELAXNG_ATTRIBUTE:
10471             ret = xmlRelaxNGValidateAttribute(ctxt, define);
10472             break;
10473         case XML_RELAXNG_START:
10474         case XML_RELAXNG_NOOP:
10475         case XML_RELAXNG_REF:
10476         case XML_RELAXNG_EXTERNALREF:
10477         case XML_RELAXNG_PARENTREF:
10478             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10479             break;
10480         case XML_RELAXNG_DATATYPE:{
10481                 xmlNodePtr child;
10482                 xmlChar *content = NULL;
10483 
10484                 child = node;
10485                 while (child != NULL) {
10486                     if (child->type == XML_ELEMENT_NODE) {
10487                         VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10488                                    node->parent->name);
10489                         ret = -1;
10490                         break;
10491                     } else if ((child->type == XML_TEXT_NODE) ||
10492                                (child->type == XML_CDATA_SECTION_NODE)) {
10493                         content = xmlStrcat(content, child->content);
10494                     }
10495                     /* TODO: handle entities ... */
10496                     child = child->next;
10497                 }
10498                 if (ret == -1) {
10499                     if (content != NULL)
10500                         xmlFree(content);
10501                     break;
10502                 }
10503                 if (content == NULL) {
10504                     content = xmlStrdup(BAD_CAST "");
10505                     if (content == NULL) {
10506                         xmlRngVErrMemory(ctxt, "validating\n");
10507                         ret = -1;
10508                         break;
10509                     }
10510                 }
10511                 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10512                                                  ctxt->state->seq);
10513                 if (ret == -1) {
10514                     VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10515                 } else if (ret == 0) {
10516                     ctxt->state->seq = NULL;
10517                 }
10518                 if (content != NULL)
10519                     xmlFree(content);
10520                 break;
10521             }
10522         case XML_RELAXNG_VALUE:{
10523                 xmlChar *content = NULL;
10524                 xmlChar *oldvalue;
10525                 xmlNodePtr child;
10526 
10527                 child = node;
10528                 while (child != NULL) {
10529                     if (child->type == XML_ELEMENT_NODE) {
10530                         VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10531                                    node->parent->name);
10532                         ret = -1;
10533                         break;
10534                     } else if ((child->type == XML_TEXT_NODE) ||
10535                                (child->type == XML_CDATA_SECTION_NODE)) {
10536                         content = xmlStrcat(content, child->content);
10537                     }
10538                     /* TODO: handle entities ... */
10539                     child = child->next;
10540                 }
10541                 if (ret == -1) {
10542                     if (content != NULL)
10543                         xmlFree(content);
10544                     break;
10545                 }
10546                 if (content == NULL) {
10547                     content = xmlStrdup(BAD_CAST "");
10548                     if (content == NULL) {
10549                         xmlRngVErrMemory(ctxt, "validating\n");
10550                         ret = -1;
10551                         break;
10552                     }
10553                 }
10554                 oldvalue = ctxt->state->value;
10555                 ctxt->state->value = content;
10556                 ret = xmlRelaxNGValidateValue(ctxt, define);
10557                 ctxt->state->value = oldvalue;
10558                 if (ret == -1) {
10559                     VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10560                 } else if (ret == 0) {
10561                     ctxt->state->seq = NULL;
10562                 }
10563                 if (content != NULL)
10564                     xmlFree(content);
10565                 break;
10566             }
10567         case XML_RELAXNG_LIST:{
10568                 xmlChar *content;
10569                 xmlNodePtr child;
10570                 xmlChar *oldvalue, *oldendvalue;
10571                 int len;
10572 
10573                 /*
10574                  * Make sure it's only text nodes
10575                  */
10576 
10577                 content = NULL;
10578                 child = node;
10579                 while (child != NULL) {
10580                     if (child->type == XML_ELEMENT_NODE) {
10581                         VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10582                                    node->parent->name);
10583                         ret = -1;
10584                         break;
10585                     } else if ((child->type == XML_TEXT_NODE) ||
10586                                (child->type == XML_CDATA_SECTION_NODE)) {
10587                         content = xmlStrcat(content, child->content);
10588                     }
10589                     /* TODO: handle entities ... */
10590                     child = child->next;
10591                 }
10592                 if (ret == -1) {
10593                     if (content != NULL)
10594                         xmlFree(content);
10595                     break;
10596                 }
10597                 if (content == NULL) {
10598                     content = xmlStrdup(BAD_CAST "");
10599                     if (content == NULL) {
10600                         xmlRngVErrMemory(ctxt, "validating\n");
10601                         ret = -1;
10602                         break;
10603                     }
10604                 }
10605                 len = xmlStrlen(content);
10606                 oldvalue = ctxt->state->value;
10607                 oldendvalue = ctxt->state->endvalue;
10608                 ctxt->state->value = content;
10609                 ctxt->state->endvalue = content + len;
10610                 ret = xmlRelaxNGValidateValue(ctxt, define);
10611                 ctxt->state->value = oldvalue;
10612                 ctxt->state->endvalue = oldendvalue;
10613                 if (ret == -1) {
10614                     VALID_ERR(XML_RELAXNG_ERR_LIST);
10615                 } else if ((ret == 0) && (node != NULL)) {
10616                     ctxt->state->seq = node->next;
10617                 }
10618                 if (content != NULL)
10619                     xmlFree(content);
10620                 break;
10621             }
10622         case XML_RELAXNG_EXCEPT:
10623         case XML_RELAXNG_PARAM:
10624             TODO ret = -1;
10625             break;
10626     }
10627     ctxt->depth--;
10628 #ifdef DEBUG
10629     for (i = 0; i < ctxt->depth; i++)
10630         xmlGenericError(xmlGenericErrorContext, " ");
10631     xmlGenericError(xmlGenericErrorContext,
10632                     "Validating %s ", xmlRelaxNGDefName(define));
10633     if (define->name != NULL)
10634         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
10635     if (ret == 0)
10636         xmlGenericError(xmlGenericErrorContext, "succeeded\n");
10637     else
10638         xmlGenericError(xmlGenericErrorContext, "failed\n");
10639 #endif
10640     return (ret);
10641 }
10642 
10643 /**
10644  * xmlRelaxNGValidateDefinition:
10645  * @ctxt:  a Relax-NG validation context
10646  * @define:  the definition to verify
10647  *
10648  * Validate the current node lists against the definition
10649  *
10650  * Returns 0 if the validation succeeded or an error code.
10651  */
10652 static int
xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGDefinePtr define)10653 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10654                              xmlRelaxNGDefinePtr define)
10655 {
10656     xmlRelaxNGStatesPtr states, res;
10657     int i, j, k, ret, oldflags;
10658 
10659     /*
10660      * We should NOT have both ctxt->state and ctxt->states
10661      */
10662     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10663         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10664         ctxt->state = NULL;
10665     }
10666 
10667     if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10668         if (ctxt->states != NULL) {
10669             ctxt->state = ctxt->states->tabState[0];
10670             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10671             ctxt->states = NULL;
10672         }
10673         ret = xmlRelaxNGValidateState(ctxt, define);
10674         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10675             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10676             ctxt->state = NULL;
10677         }
10678         if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10679             ctxt->state = ctxt->states->tabState[0];
10680             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10681             ctxt->states = NULL;
10682         }
10683         return (ret);
10684     }
10685 
10686     states = ctxt->states;
10687     ctxt->states = NULL;
10688     res = NULL;
10689     j = 0;
10690     oldflags = ctxt->flags;
10691     ctxt->flags |= FLAGS_IGNORABLE;
10692     for (i = 0; i < states->nbState; i++) {
10693         ctxt->state = states->tabState[i];
10694         ctxt->states = NULL;
10695         ret = xmlRelaxNGValidateState(ctxt, define);
10696         /*
10697          * We should NOT have both ctxt->state and ctxt->states
10698          */
10699         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10700             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10701             ctxt->state = NULL;
10702         }
10703         if (ret == 0) {
10704             if (ctxt->states == NULL) {
10705                 if (res != NULL) {
10706                     /* add the state to the container */
10707                     xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10708                     ctxt->state = NULL;
10709                 } else {
10710                     /* add the state directly in states */
10711                     states->tabState[j++] = ctxt->state;
10712                     ctxt->state = NULL;
10713                 }
10714             } else {
10715                 if (res == NULL) {
10716                     /* make it the new container and copy other results */
10717                     res = ctxt->states;
10718                     ctxt->states = NULL;
10719                     for (k = 0; k < j; k++)
10720                         xmlRelaxNGAddStates(ctxt, res,
10721                                             states->tabState[k]);
10722                 } else {
10723                     /* add all the new results to res and reff the container */
10724                     for (k = 0; k < ctxt->states->nbState; k++)
10725                         xmlRelaxNGAddStates(ctxt, res,
10726                                             ctxt->states->tabState[k]);
10727                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10728                     ctxt->states = NULL;
10729                 }
10730             }
10731         } else {
10732             if (ctxt->state != NULL) {
10733                 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10734                 ctxt->state = NULL;
10735             } else if (ctxt->states != NULL) {
10736                 for (k = 0; k < ctxt->states->nbState; k++)
10737                     xmlRelaxNGFreeValidState(ctxt,
10738                                              ctxt->states->tabState[k]);
10739                 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10740                 ctxt->states = NULL;
10741             }
10742         }
10743     }
10744     ctxt->flags = oldflags;
10745     if (res != NULL) {
10746         xmlRelaxNGFreeStates(ctxt, states);
10747         ctxt->states = res;
10748         ret = 0;
10749     } else if (j > 1) {
10750         states->nbState = j;
10751         ctxt->states = states;
10752         ret = 0;
10753     } else if (j == 1) {
10754         ctxt->state = states->tabState[0];
10755         xmlRelaxNGFreeStates(ctxt, states);
10756         ret = 0;
10757     } else {
10758         ret = -1;
10759         xmlRelaxNGFreeStates(ctxt, states);
10760         if (ctxt->states != NULL) {
10761             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10762             ctxt->states = NULL;
10763         }
10764     }
10765     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10766         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10767         ctxt->state = NULL;
10768     }
10769     return (ret);
10770 }
10771 
10772 /**
10773  * xmlRelaxNGValidateDocument:
10774  * @ctxt:  a Relax-NG validation context
10775  * @doc:  the document
10776  *
10777  * Validate the given document
10778  *
10779  * Returns 0 if the validation succeeded or an error code.
10780  */
10781 static int
xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt,xmlDocPtr doc)10782 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10783 {
10784     int ret;
10785     xmlRelaxNGPtr schema;
10786     xmlRelaxNGGrammarPtr grammar;
10787     xmlRelaxNGValidStatePtr state;
10788     xmlNodePtr node;
10789 
10790     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10791         return (-1);
10792 
10793     ctxt->errNo = XML_RELAXNG_OK;
10794     schema = ctxt->schema;
10795     grammar = schema->topgrammar;
10796     if (grammar == NULL) {
10797         VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10798         return (-1);
10799     }
10800     state = xmlRelaxNGNewValidState(ctxt, NULL);
10801     ctxt->state = state;
10802     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10803     if ((ctxt->state != NULL) && (state->seq != NULL)) {
10804         state = ctxt->state;
10805         node = state->seq;
10806         node = xmlRelaxNGSkipIgnored(ctxt, node);
10807         if (node != NULL) {
10808             if (ret != -1) {
10809                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10810                 ret = -1;
10811             }
10812         }
10813     } else if (ctxt->states != NULL) {
10814         int i;
10815         int tmp = -1;
10816 
10817         for (i = 0; i < ctxt->states->nbState; i++) {
10818             state = ctxt->states->tabState[i];
10819             node = state->seq;
10820             node = xmlRelaxNGSkipIgnored(ctxt, node);
10821             if (node == NULL)
10822                 tmp = 0;
10823             xmlRelaxNGFreeValidState(ctxt, state);
10824         }
10825         if (tmp == -1) {
10826             if (ret != -1) {
10827                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10828                 ret = -1;
10829             }
10830         }
10831     }
10832     if (ctxt->state != NULL) {
10833         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10834         ctxt->state = NULL;
10835     }
10836     if (ret != 0)
10837         xmlRelaxNGDumpValidError(ctxt);
10838 #ifdef DEBUG
10839     else if (ctxt->errNr != 0) {
10840         ctxt->error(ctxt->userData,
10841                     "%d Extra error messages left on stack !\n",
10842                     ctxt->errNr);
10843         xmlRelaxNGDumpValidError(ctxt);
10844     }
10845 #endif
10846 #ifdef LIBXML_VALID_ENABLED
10847     if (ctxt->idref == 1) {
10848         xmlValidCtxt vctxt;
10849 
10850         memset(&vctxt, 0, sizeof(xmlValidCtxt));
10851         vctxt.valid = 1;
10852         vctxt.error = ctxt->error;
10853         vctxt.warning = ctxt->warning;
10854         vctxt.userData = ctxt->userData;
10855 
10856         if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10857             ret = -1;
10858     }
10859 #endif /* LIBXML_VALID_ENABLED */
10860     if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10861         ret = -1;
10862 
10863     return (ret);
10864 }
10865 
10866 /**
10867  * xmlRelaxNGCleanPSVI:
10868  * @node:  an input element or document
10869  *
10870  * Call this routine to speed up XPath computation on static documents.
10871  * This stamps all the element nodes with the document order
10872  * Like for line information, the order is kept in the element->content
10873  * field, the value stored is actually - the node number (starting at -1)
10874  * to be able to differentiate from line numbers.
10875  *
10876  * Returns the number of elements found in the document or -1 in case
10877  *    of error.
10878  */
10879 static void
xmlRelaxNGCleanPSVI(xmlNodePtr node)10880 xmlRelaxNGCleanPSVI(xmlNodePtr node) {
10881     xmlNodePtr cur;
10882 
10883     if ((node == NULL) ||
10884         ((node->type != XML_ELEMENT_NODE) &&
10885          (node->type != XML_DOCUMENT_NODE) &&
10886          (node->type != XML_HTML_DOCUMENT_NODE)))
10887 	return;
10888     if (node->type == XML_ELEMENT_NODE)
10889         node->psvi = NULL;
10890 
10891     cur = node->children;
10892     while (cur != NULL) {
10893 	if (cur->type == XML_ELEMENT_NODE) {
10894 	    cur->psvi = NULL;
10895 	    if (cur->children != NULL) {
10896 		cur = cur->children;
10897 		continue;
10898 	    }
10899 	}
10900 	if (cur->next != NULL) {
10901 	    cur = cur->next;
10902 	    continue;
10903 	}
10904 	do {
10905 	    cur = cur->parent;
10906 	    if (cur == NULL)
10907 		break;
10908 	    if (cur == node) {
10909 		cur = NULL;
10910 		break;
10911 	    }
10912 	    if (cur->next != NULL) {
10913 		cur = cur->next;
10914 		break;
10915 	    }
10916 	} while (cur != NULL);
10917     }
10918     return;
10919 }
10920 /************************************************************************
10921  *									*
10922  *			Validation interfaces				*
10923  *									*
10924  ************************************************************************/
10925 
10926 /**
10927  * xmlRelaxNGNewValidCtxt:
10928  * @schema:  a precompiled XML RelaxNGs
10929  *
10930  * Create an XML RelaxNGs validation context based on the given schema
10931  *
10932  * Returns the validation context or NULL in case of error
10933  */
10934 xmlRelaxNGValidCtxtPtr
xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)10935 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10936 {
10937     xmlRelaxNGValidCtxtPtr ret;
10938 
10939     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10940     if (ret == NULL) {
10941         xmlRngVErrMemory(NULL, "building context\n");
10942         return (NULL);
10943     }
10944     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10945     ret->schema = schema;
10946     ret->error = xmlGenericError;
10947     ret->userData = xmlGenericErrorContext;
10948     ret->errNr = 0;
10949     ret->errMax = 0;
10950     ret->err = NULL;
10951     ret->errTab = NULL;
10952     if (schema != NULL)
10953 	ret->idref = schema->idref;
10954     ret->states = NULL;
10955     ret->freeState = NULL;
10956     ret->freeStates = NULL;
10957     ret->errNo = XML_RELAXNG_OK;
10958     return (ret);
10959 }
10960 
10961 /**
10962  * xmlRelaxNGFreeValidCtxt:
10963  * @ctxt:  the schema validation context
10964  *
10965  * Free the resources associated to the schema validation context
10966  */
10967 void
xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)10968 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10969 {
10970     int k;
10971 
10972     if (ctxt == NULL)
10973         return;
10974     if (ctxt->states != NULL)
10975         xmlRelaxNGFreeStates(NULL, ctxt->states);
10976     if (ctxt->freeState != NULL) {
10977         for (k = 0; k < ctxt->freeState->nbState; k++) {
10978             xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10979         }
10980         xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10981     }
10982     if (ctxt->freeStates != NULL) {
10983         for (k = 0; k < ctxt->freeStatesNr; k++) {
10984             xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10985         }
10986         xmlFree(ctxt->freeStates);
10987     }
10988     if (ctxt->errTab != NULL)
10989         xmlFree(ctxt->errTab);
10990     if (ctxt->elemTab != NULL) {
10991         xmlRegExecCtxtPtr exec;
10992 
10993         exec = xmlRelaxNGElemPop(ctxt);
10994         while (exec != NULL) {
10995             xmlRegFreeExecCtxt(exec);
10996             exec = xmlRelaxNGElemPop(ctxt);
10997         }
10998         xmlFree(ctxt->elemTab);
10999     }
11000     xmlFree(ctxt);
11001 }
11002 
11003 /**
11004  * xmlRelaxNGSetValidErrors:
11005  * @ctxt:  a Relax-NG validation context
11006  * @err:  the error function
11007  * @warn: the warning function
11008  * @ctx: the functions context
11009  *
11010  * Set the error and warning callback information
11011  */
11012 void
xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGValidityErrorFunc err,xmlRelaxNGValidityWarningFunc warn,void * ctx)11013 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
11014                          xmlRelaxNGValidityErrorFunc err,
11015                          xmlRelaxNGValidityWarningFunc warn, void *ctx)
11016 {
11017     if (ctxt == NULL)
11018         return;
11019     ctxt->error = err;
11020     ctxt->warning = warn;
11021     ctxt->userData = ctx;
11022     ctxt->serror = NULL;
11023 }
11024 
11025 /**
11026  * xmlRelaxNGSetValidStructuredErrors:
11027  * @ctxt:  a Relax-NG validation context
11028  * @serror:  the structured error function
11029  * @ctx: the functions context
11030  *
11031  * Set the structured error callback
11032  */
11033 void
xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,xmlStructuredErrorFunc serror,void * ctx)11034 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
11035                                    xmlStructuredErrorFunc serror, void *ctx)
11036 {
11037     if (ctxt == NULL)
11038         return;
11039     ctxt->serror = serror;
11040     ctxt->error = NULL;
11041     ctxt->warning = NULL;
11042     ctxt->userData = ctx;
11043 }
11044 
11045 /**
11046  * xmlRelaxNGGetValidErrors:
11047  * @ctxt:  a Relax-NG validation context
11048  * @err:  the error function result
11049  * @warn: the warning function result
11050  * @ctx: the functions context result
11051  *
11052  * Get the error and warning callback information
11053  *
11054  * Returns -1 in case of error and 0 otherwise
11055  */
11056 int
xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,xmlRelaxNGValidityErrorFunc * err,xmlRelaxNGValidityWarningFunc * warn,void ** ctx)11057 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
11058                          xmlRelaxNGValidityErrorFunc * err,
11059                          xmlRelaxNGValidityWarningFunc * warn, void **ctx)
11060 {
11061     if (ctxt == NULL)
11062         return (-1);
11063     if (err != NULL)
11064         *err = ctxt->error;
11065     if (warn != NULL)
11066         *warn = ctxt->warning;
11067     if (ctx != NULL)
11068         *ctx = ctxt->userData;
11069     return (0);
11070 }
11071 
11072 /**
11073  * xmlRelaxNGValidateDoc:
11074  * @ctxt:  a Relax-NG validation context
11075  * @doc:  a parsed document tree
11076  *
11077  * Validate a document tree in memory.
11078  *
11079  * Returns 0 if the document is valid, a positive error code
11080  *     number otherwise and -1 in case of internal or API error.
11081  */
11082 int
xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt,xmlDocPtr doc)11083 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
11084 {
11085     int ret;
11086 
11087     if ((ctxt == NULL) || (doc == NULL))
11088         return (-1);
11089 
11090     ctxt->doc = doc;
11091 
11092     ret = xmlRelaxNGValidateDocument(ctxt, doc);
11093     /*
11094      * Remove all left PSVI
11095      */
11096     xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
11097 
11098     /*
11099      * TODO: build error codes
11100      */
11101     if (ret == -1)
11102         return (1);
11103     return (ret);
11104 }
11105 
11106 #endif /* LIBXML_SCHEMAS_ENABLED */
11107