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