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