VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/relaxng.c@ 105770

Last change on this file since 105770 was 105420, checked in by vboxsync, 4 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette