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