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