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