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