Annotation of embedaddon/libxml2/relaxng.c, revision 1.1
1.1 ! misho 1: /*
! 2: * relaxng.c : implementation of the Relax-NG handling and validity checking
! 3: *
! 4: * See Copyright for the status of this software.
! 5: *
! 6: * Daniel Veillard <veillard@redhat.com>
! 7: */
! 8:
! 9: /**
! 10: * TODO:
! 11: * - add support for DTD compatibility spec
! 12: * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
! 13: * - report better mem allocations pbms at runtime and abort immediately.
! 14: */
! 15:
! 16: #define IN_LIBXML
! 17: #include "libxml.h"
! 18:
! 19: #ifdef LIBXML_SCHEMAS_ENABLED
! 20:
! 21: #include <string.h>
! 22: #include <stdio.h>
! 23: #include <libxml/xmlmemory.h>
! 24: #include <libxml/parser.h>
! 25: #include <libxml/parserInternals.h>
! 26: #include <libxml/hash.h>
! 27: #include <libxml/uri.h>
! 28:
! 29: #include <libxml/relaxng.h>
! 30:
! 31: #include <libxml/xmlschemastypes.h>
! 32: #include <libxml/xmlautomata.h>
! 33: #include <libxml/xmlregexp.h>
! 34: #include <libxml/xmlschemastypes.h>
! 35:
! 36: /*
! 37: * The Relax-NG namespace
! 38: */
! 39: static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
! 40: "http://relaxng.org/ns/structure/1.0";
! 41:
! 42: #define IS_RELAXNG(node, type) \
! 43: ((node != NULL) && (node->ns != NULL) && \
! 44: (xmlStrEqual(node->name, (const xmlChar *) type)) && \
! 45: (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
! 46:
! 47:
! 48: #if 0
! 49: #define DEBUG 1
! 50:
! 51: #define DEBUG_GRAMMAR 1
! 52:
! 53: #define DEBUG_CONTENT 1
! 54:
! 55: #define DEBUG_TYPE 1
! 56:
! 57: #define DEBUG_VALID 1
! 58:
! 59: #define DEBUG_INTERLEAVE 1
! 60:
! 61: #define DEBUG_LIST 1
! 62:
! 63: #define DEBUG_INCLUDE 1
! 64:
! 65: #define DEBUG_ERROR 1
! 66:
! 67: #define DEBUG_COMPILE 1
! 68:
! 69: #define DEBUG_PROGRESSIVE 1
! 70: #endif
! 71:
! 72: #define MAX_ERROR 5
! 73:
! 74: #define TODO \
! 75: xmlGenericError(xmlGenericErrorContext, \
! 76: "Unimplemented block at %s:%d\n", \
! 77: __FILE__, __LINE__);
! 78:
! 79: typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
! 80: typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
! 81:
! 82: typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
! 83: typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
! 84:
! 85: typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
! 86: typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
! 87:
! 88: typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
! 89: typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
! 90:
! 91: typedef enum {
! 92: XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
! 93: XML_RELAXNG_COMBINE_CHOICE, /* choice */
! 94: XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
! 95: } xmlRelaxNGCombine;
! 96:
! 97: typedef enum {
! 98: XML_RELAXNG_CONTENT_ERROR = -1,
! 99: XML_RELAXNG_CONTENT_EMPTY = 0,
! 100: XML_RELAXNG_CONTENT_SIMPLE,
! 101: XML_RELAXNG_CONTENT_COMPLEX
! 102: } xmlRelaxNGContentType;
! 103:
! 104: typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
! 105: typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
! 106:
! 107: struct _xmlRelaxNGGrammar {
! 108: xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
! 109: xmlRelaxNGGrammarPtr children; /* the children grammar if any */
! 110: xmlRelaxNGGrammarPtr next; /* the next grammar if any */
! 111: xmlRelaxNGDefinePtr start; /* <start> content */
! 112: xmlRelaxNGCombine combine; /* the default combine value */
! 113: xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
! 114: xmlHashTablePtr defs; /* define* */
! 115: xmlHashTablePtr refs; /* references */
! 116: };
! 117:
! 118:
! 119: typedef enum {
! 120: XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
! 121: XML_RELAXNG_EMPTY = 0, /* an empty pattern */
! 122: XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
! 123: XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
! 124: XML_RELAXNG_TEXT, /* textual content */
! 125: XML_RELAXNG_ELEMENT, /* an element */
! 126: XML_RELAXNG_DATATYPE, /* extenal data type definition */
! 127: XML_RELAXNG_PARAM, /* extenal data type parameter */
! 128: XML_RELAXNG_VALUE, /* value from an extenal data type definition */
! 129: XML_RELAXNG_LIST, /* a list of patterns */
! 130: XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
! 131: XML_RELAXNG_DEF, /* a definition */
! 132: XML_RELAXNG_REF, /* reference to a definition */
! 133: XML_RELAXNG_EXTERNALREF, /* reference to an external def */
! 134: XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
! 135: XML_RELAXNG_OPTIONAL, /* optional patterns */
! 136: XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
! 137: XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
! 138: XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
! 139: XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
! 140: XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
! 141: XML_RELAXNG_START /* Used to keep track of starts on grammars */
! 142: } xmlRelaxNGType;
! 143:
! 144: #define IS_NULLABLE (1 << 0)
! 145: #define IS_NOT_NULLABLE (1 << 1)
! 146: #define IS_INDETERMINIST (1 << 2)
! 147: #define IS_MIXED (1 << 3)
! 148: #define IS_TRIABLE (1 << 4)
! 149: #define IS_PROCESSED (1 << 5)
! 150: #define IS_COMPILABLE (1 << 6)
! 151: #define IS_NOT_COMPILABLE (1 << 7)
! 152: #define IS_EXTERNAL_REF (1 << 8)
! 153:
! 154: struct _xmlRelaxNGDefine {
! 155: xmlRelaxNGType type; /* the type of definition */
! 156: xmlNodePtr node; /* the node in the source */
! 157: xmlChar *name; /* the element local name if present */
! 158: xmlChar *ns; /* the namespace local name if present */
! 159: xmlChar *value; /* value when available */
! 160: void *data; /* data lib or specific pointer */
! 161: xmlRelaxNGDefinePtr content; /* the expected content */
! 162: xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
! 163: xmlRelaxNGDefinePtr next; /* list within grouping sequences */
! 164: xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
! 165: xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
! 166: xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
! 167: short depth; /* used for the cycle detection */
! 168: short dflags; /* define related flags */
! 169: xmlRegexpPtr contModel; /* a compiled content model if available */
! 170: };
! 171:
! 172: /**
! 173: * _xmlRelaxNG:
! 174: *
! 175: * A RelaxNGs definition
! 176: */
! 177: struct _xmlRelaxNG {
! 178: void *_private; /* unused by the library for users or bindings */
! 179: xmlRelaxNGGrammarPtr topgrammar;
! 180: xmlDocPtr doc;
! 181:
! 182: int idref; /* requires idref checking */
! 183:
! 184: xmlHashTablePtr defs; /* define */
! 185: xmlHashTablePtr refs; /* references */
! 186: xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
! 187: xmlRelaxNGIncludePtr includes; /* all the includes loaded */
! 188: int defNr; /* number of defines used */
! 189: xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
! 190:
! 191: };
! 192:
! 193: #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
! 194: #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
! 195: #define XML_RELAXNG_IN_LIST (1 << 2)
! 196: #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
! 197: #define XML_RELAXNG_IN_START (1 << 4)
! 198: #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
! 199: #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
! 200: #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
! 201: #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
! 202: #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
! 203:
! 204: struct _xmlRelaxNGParserCtxt {
! 205: void *userData; /* user specific data block */
! 206: xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
! 207: xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
! 208: xmlStructuredErrorFunc serror;
! 209: xmlRelaxNGValidErr err;
! 210:
! 211: xmlRelaxNGPtr schema; /* The schema in use */
! 212: xmlRelaxNGGrammarPtr grammar; /* the current grammar */
! 213: xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
! 214: int flags; /* parser flags */
! 215: int nbErrors; /* number of errors at parse time */
! 216: int nbWarnings; /* number of warnings at parse time */
! 217: const xmlChar *define; /* the current define scope */
! 218: xmlRelaxNGDefinePtr def; /* the current define */
! 219:
! 220: int nbInterleaves;
! 221: xmlHashTablePtr interleaves; /* keep track of all the interleaves */
! 222:
! 223: xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
! 224: xmlRelaxNGIncludePtr includes; /* all the includes loaded */
! 225: xmlChar *URL;
! 226: xmlDocPtr document;
! 227:
! 228: int defNr; /* number of defines used */
! 229: int defMax; /* number of defines aloocated */
! 230: xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
! 231:
! 232: const char *buffer;
! 233: int size;
! 234:
! 235: /* the document stack */
! 236: xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
! 237: int docNr; /* Depth of the parsing stack */
! 238: int docMax; /* Max depth of the parsing stack */
! 239: xmlRelaxNGDocumentPtr *docTab; /* array of docs */
! 240:
! 241: /* the include stack */
! 242: xmlRelaxNGIncludePtr inc; /* Current parsed include */
! 243: int incNr; /* Depth of the include parsing stack */
! 244: int incMax; /* Max depth of the parsing stack */
! 245: xmlRelaxNGIncludePtr *incTab; /* array of incs */
! 246:
! 247: int idref; /* requires idref checking */
! 248:
! 249: /* used to compile content models */
! 250: xmlAutomataPtr am; /* the automata */
! 251: xmlAutomataStatePtr state; /* used to build the automata */
! 252:
! 253: int crng; /* compact syntax and other flags */
! 254: int freedoc; /* need to free the document */
! 255: };
! 256:
! 257: #define FLAGS_IGNORABLE 1
! 258: #define FLAGS_NEGATIVE 2
! 259: #define FLAGS_MIXED_CONTENT 4
! 260: #define FLAGS_NOERROR 8
! 261:
! 262: /**
! 263: * xmlRelaxNGInterleaveGroup:
! 264: *
! 265: * A RelaxNGs partition set associated to lists of definitions
! 266: */
! 267: typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
! 268: typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
! 269: struct _xmlRelaxNGInterleaveGroup {
! 270: xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
! 271: xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
! 272: xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
! 273: };
! 274:
! 275: #define IS_DETERMINIST 1
! 276: #define IS_NEEDCHECK 2
! 277:
! 278: /**
! 279: * xmlRelaxNGPartitions:
! 280: *
! 281: * A RelaxNGs partition associated to an interleave group
! 282: */
! 283: typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
! 284: typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
! 285: struct _xmlRelaxNGPartition {
! 286: int nbgroups; /* number of groups in the partitions */
! 287: xmlHashTablePtr triage; /* hash table used to direct nodes to the
! 288: * right group when possible */
! 289: int flags; /* determinist ? */
! 290: xmlRelaxNGInterleaveGroupPtr *groups;
! 291: };
! 292:
! 293: /**
! 294: * xmlRelaxNGValidState:
! 295: *
! 296: * A RelaxNGs validation state
! 297: */
! 298: #define MAX_ATTR 20
! 299: typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
! 300: typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
! 301: struct _xmlRelaxNGValidState {
! 302: xmlNodePtr node; /* the current node */
! 303: xmlNodePtr seq; /* the sequence of children left to validate */
! 304: int nbAttrs; /* the number of attributes */
! 305: int maxAttrs; /* the size of attrs */
! 306: int nbAttrLeft; /* the number of attributes left to validate */
! 307: xmlChar *value; /* the value when operating on string */
! 308: xmlChar *endvalue; /* the end value when operating on string */
! 309: xmlAttrPtr *attrs; /* the array of attributes */
! 310: };
! 311:
! 312: /**
! 313: * xmlRelaxNGStates:
! 314: *
! 315: * A RelaxNGs container for validation state
! 316: */
! 317: typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
! 318: typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
! 319: struct _xmlRelaxNGStates {
! 320: int nbState; /* the number of states */
! 321: int maxState; /* the size of the array */
! 322: xmlRelaxNGValidStatePtr *tabState;
! 323: };
! 324:
! 325: #define ERROR_IS_DUP 1
! 326:
! 327: /**
! 328: * xmlRelaxNGValidError:
! 329: *
! 330: * A RelaxNGs validation error
! 331: */
! 332: typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
! 333: typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
! 334: struct _xmlRelaxNGValidError {
! 335: xmlRelaxNGValidErr err; /* the error number */
! 336: int flags; /* flags */
! 337: xmlNodePtr node; /* the current node */
! 338: xmlNodePtr seq; /* the current child */
! 339: const xmlChar *arg1; /* first arg */
! 340: const xmlChar *arg2; /* second arg */
! 341: };
! 342:
! 343: /**
! 344: * xmlRelaxNGValidCtxt:
! 345: *
! 346: * A RelaxNGs validation context
! 347: */
! 348:
! 349: struct _xmlRelaxNGValidCtxt {
! 350: void *userData; /* user specific data block */
! 351: xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
! 352: xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
! 353: xmlStructuredErrorFunc serror;
! 354: int nbErrors; /* number of errors in validation */
! 355:
! 356: xmlRelaxNGPtr schema; /* The schema in use */
! 357: xmlDocPtr doc; /* the document being validated */
! 358: int flags; /* validation flags */
! 359: int depth; /* validation depth */
! 360: int idref; /* requires idref checking */
! 361: int errNo; /* the first error found */
! 362:
! 363: /*
! 364: * Errors accumulated in branches may have to be stacked to be
! 365: * provided back when it's sure they affect validation.
! 366: */
! 367: xmlRelaxNGValidErrorPtr err; /* Last error */
! 368: int errNr; /* Depth of the error stack */
! 369: int errMax; /* Max depth of the error stack */
! 370: xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
! 371:
! 372: xmlRelaxNGValidStatePtr state; /* the current validation state */
! 373: xmlRelaxNGStatesPtr states; /* the accumulated state list */
! 374:
! 375: xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
! 376: int freeStatesNr;
! 377: int freeStatesMax;
! 378: xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
! 379:
! 380: /*
! 381: * This is used for "progressive" validation
! 382: */
! 383: xmlRegExecCtxtPtr elem; /* the current element regexp */
! 384: int elemNr; /* the number of element validated */
! 385: int elemMax; /* the max depth of elements */
! 386: xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
! 387: int pstate; /* progressive state */
! 388: xmlNodePtr pnode; /* the current node */
! 389: xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
! 390: int perr; /* signal error in content model
! 391: * outside the regexp */
! 392: };
! 393:
! 394: /**
! 395: * xmlRelaxNGInclude:
! 396: *
! 397: * Structure associated to a RelaxNGs document element
! 398: */
! 399: struct _xmlRelaxNGInclude {
! 400: xmlRelaxNGIncludePtr next; /* keep a chain of includes */
! 401: xmlChar *href; /* the normalized href value */
! 402: xmlDocPtr doc; /* the associated XML document */
! 403: xmlRelaxNGDefinePtr content; /* the definitions */
! 404: xmlRelaxNGPtr schema; /* the schema */
! 405: };
! 406:
! 407: /**
! 408: * xmlRelaxNGDocument:
! 409: *
! 410: * Structure associated to a RelaxNGs document element
! 411: */
! 412: struct _xmlRelaxNGDocument {
! 413: xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
! 414: xmlChar *href; /* the normalized href value */
! 415: xmlDocPtr doc; /* the associated XML document */
! 416: xmlRelaxNGDefinePtr content; /* the definitions */
! 417: xmlRelaxNGPtr schema; /* the schema */
! 418: int externalRef; /* 1 if an external ref */
! 419: };
! 420:
! 421:
! 422: /************************************************************************
! 423: * *
! 424: * Some factorized error routines *
! 425: * *
! 426: ************************************************************************/
! 427:
! 428: /**
! 429: * xmlRngPErrMemory:
! 430: * @ctxt: an Relax-NG parser context
! 431: * @extra: extra informations
! 432: *
! 433: * Handle a redefinition of attribute error
! 434: */
! 435: static void
! 436: xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
! 437: {
! 438: xmlStructuredErrorFunc schannel = NULL;
! 439: xmlGenericErrorFunc channel = NULL;
! 440: void *data = NULL;
! 441:
! 442: if (ctxt != NULL) {
! 443: if (ctxt->serror != NULL)
! 444: schannel = ctxt->serror;
! 445: else
! 446: channel = ctxt->error;
! 447: data = ctxt->userData;
! 448: ctxt->nbErrors++;
! 449: }
! 450: if (extra)
! 451: __xmlRaiseError(schannel, channel, data,
! 452: NULL, NULL, XML_FROM_RELAXNGP,
! 453: XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
! 454: NULL, NULL, 0, 0,
! 455: "Memory allocation failed : %s\n", extra);
! 456: else
! 457: __xmlRaiseError(schannel, channel, data,
! 458: NULL, NULL, XML_FROM_RELAXNGP,
! 459: XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
! 460: NULL, NULL, 0, 0, "Memory allocation failed\n");
! 461: }
! 462:
! 463: /**
! 464: * xmlRngVErrMemory:
! 465: * @ctxt: a Relax-NG validation context
! 466: * @extra: extra informations
! 467: *
! 468: * Handle a redefinition of attribute error
! 469: */
! 470: static void
! 471: xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
! 472: {
! 473: xmlStructuredErrorFunc schannel = NULL;
! 474: xmlGenericErrorFunc channel = NULL;
! 475: void *data = NULL;
! 476:
! 477: if (ctxt != NULL) {
! 478: if (ctxt->serror != NULL)
! 479: schannel = ctxt->serror;
! 480: else
! 481: channel = ctxt->error;
! 482: data = ctxt->userData;
! 483: ctxt->nbErrors++;
! 484: }
! 485: if (extra)
! 486: __xmlRaiseError(schannel, channel, data,
! 487: NULL, NULL, XML_FROM_RELAXNGV,
! 488: XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
! 489: NULL, NULL, 0, 0,
! 490: "Memory allocation failed : %s\n", extra);
! 491: else
! 492: __xmlRaiseError(schannel, channel, data,
! 493: NULL, NULL, XML_FROM_RELAXNGV,
! 494: XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
! 495: NULL, NULL, 0, 0, "Memory allocation failed\n");
! 496: }
! 497:
! 498: /**
! 499: * xmlRngPErr:
! 500: * @ctxt: a Relax-NG parser context
! 501: * @node: the node raising the error
! 502: * @error: the error code
! 503: * @msg: message
! 504: * @str1: extra info
! 505: * @str2: extra info
! 506: *
! 507: * Handle a Relax NG Parsing error
! 508: */
! 509: static void
! 510: xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
! 511: const char *msg, const xmlChar * str1, const xmlChar * str2)
! 512: {
! 513: xmlStructuredErrorFunc schannel = NULL;
! 514: xmlGenericErrorFunc channel = NULL;
! 515: void *data = NULL;
! 516:
! 517: if (ctxt != NULL) {
! 518: if (ctxt->serror != NULL)
! 519: schannel = ctxt->serror;
! 520: else
! 521: channel = ctxt->error;
! 522: data = ctxt->userData;
! 523: ctxt->nbErrors++;
! 524: }
! 525: __xmlRaiseError(schannel, channel, data,
! 526: NULL, node, XML_FROM_RELAXNGP,
! 527: error, XML_ERR_ERROR, NULL, 0,
! 528: (const char *) str1, (const char *) str2, NULL, 0, 0,
! 529: msg, str1, str2);
! 530: }
! 531:
! 532: /**
! 533: * xmlRngVErr:
! 534: * @ctxt: a Relax-NG validation context
! 535: * @node: the node raising the error
! 536: * @error: the error code
! 537: * @msg: message
! 538: * @str1: extra info
! 539: * @str2: extra info
! 540: *
! 541: * Handle a Relax NG Validation error
! 542: */
! 543: static void
! 544: xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
! 545: const char *msg, const xmlChar * str1, const xmlChar * str2)
! 546: {
! 547: xmlStructuredErrorFunc schannel = NULL;
! 548: xmlGenericErrorFunc channel = NULL;
! 549: void *data = NULL;
! 550:
! 551: if (ctxt != NULL) {
! 552: if (ctxt->serror != NULL)
! 553: schannel = ctxt->serror;
! 554: else
! 555: channel = ctxt->error;
! 556: data = ctxt->userData;
! 557: ctxt->nbErrors++;
! 558: }
! 559: __xmlRaiseError(schannel, channel, data,
! 560: NULL, node, XML_FROM_RELAXNGV,
! 561: error, XML_ERR_ERROR, NULL, 0,
! 562: (const char *) str1, (const char *) str2, NULL, 0, 0,
! 563: msg, str1, str2);
! 564: }
! 565:
! 566: /************************************************************************
! 567: * *
! 568: * Preliminary type checking interfaces *
! 569: * *
! 570: ************************************************************************/
! 571:
! 572: /**
! 573: * xmlRelaxNGTypeHave:
! 574: * @data: data needed for the library
! 575: * @type: the type name
! 576: * @value: the value to check
! 577: *
! 578: * Function provided by a type library to check if a type is exported
! 579: *
! 580: * Returns 1 if yes, 0 if no and -1 in case of error.
! 581: */
! 582: typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
! 583:
! 584: /**
! 585: * xmlRelaxNGTypeCheck:
! 586: * @data: data needed for the library
! 587: * @type: the type name
! 588: * @value: the value to check
! 589: * @result: place to store the result if needed
! 590: *
! 591: * Function provided by a type library to check if a value match a type
! 592: *
! 593: * Returns 1 if yes, 0 if no and -1 in case of error.
! 594: */
! 595: typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
! 596: const xmlChar * value, void **result,
! 597: xmlNodePtr node);
! 598:
! 599: /**
! 600: * xmlRelaxNGFacetCheck:
! 601: * @data: data needed for the library
! 602: * @type: the type name
! 603: * @facet: the facet name
! 604: * @val: the facet value
! 605: * @strval: the string value
! 606: * @value: the value to check
! 607: *
! 608: * Function provided by a type library to check a value facet
! 609: *
! 610: * Returns 1 if yes, 0 if no and -1 in case of error.
! 611: */
! 612: typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
! 613: const xmlChar * facet,
! 614: const xmlChar * val,
! 615: const xmlChar * strval, void *value);
! 616:
! 617: /**
! 618: * xmlRelaxNGTypeFree:
! 619: * @data: data needed for the library
! 620: * @result: the value to free
! 621: *
! 622: * Function provided by a type library to free a returned result
! 623: */
! 624: typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
! 625:
! 626: /**
! 627: * xmlRelaxNGTypeCompare:
! 628: * @data: data needed for the library
! 629: * @type: the type name
! 630: * @value1: the first value
! 631: * @value2: the second value
! 632: *
! 633: * Function provided by a type library to compare two values accordingly
! 634: * to a type.
! 635: *
! 636: * Returns 1 if yes, 0 if no and -1 in case of error.
! 637: */
! 638: typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
! 639: const xmlChar * value1,
! 640: xmlNodePtr ctxt1,
! 641: void *comp1,
! 642: const xmlChar * value2,
! 643: xmlNodePtr ctxt2);
! 644: typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
! 645: typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
! 646: struct _xmlRelaxNGTypeLibrary {
! 647: const xmlChar *namespace; /* the datatypeLibrary value */
! 648: void *data; /* data needed for the library */
! 649: xmlRelaxNGTypeHave have; /* the export function */
! 650: xmlRelaxNGTypeCheck check; /* the checking function */
! 651: xmlRelaxNGTypeCompare comp; /* the compare function */
! 652: xmlRelaxNGFacetCheck facet; /* the facet check function */
! 653: xmlRelaxNGTypeFree freef; /* the freeing function */
! 654: };
! 655:
! 656: /************************************************************************
! 657: * *
! 658: * Allocation functions *
! 659: * *
! 660: ************************************************************************/
! 661: static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
! 662: static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
! 663: static void xmlRelaxNGNormExtSpace(xmlChar * value);
! 664: static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
! 665: static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
! 666: ATTRIBUTE_UNUSED,
! 667: xmlRelaxNGValidStatePtr state1,
! 668: xmlRelaxNGValidStatePtr state2);
! 669: static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
! 670: xmlRelaxNGValidStatePtr state);
! 671:
! 672: /**
! 673: * xmlRelaxNGFreeDocument:
! 674: * @docu: a document structure
! 675: *
! 676: * Deallocate a RelaxNG document structure.
! 677: */
! 678: static void
! 679: xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
! 680: {
! 681: if (docu == NULL)
! 682: return;
! 683:
! 684: if (docu->href != NULL)
! 685: xmlFree(docu->href);
! 686: if (docu->doc != NULL)
! 687: xmlFreeDoc(docu->doc);
! 688: if (docu->schema != NULL)
! 689: xmlRelaxNGFreeInnerSchema(docu->schema);
! 690: xmlFree(docu);
! 691: }
! 692:
! 693: /**
! 694: * xmlRelaxNGFreeDocumentList:
! 695: * @docu: a list of document structure
! 696: *
! 697: * Deallocate a RelaxNG document structures.
! 698: */
! 699: static void
! 700: xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
! 701: {
! 702: xmlRelaxNGDocumentPtr next;
! 703:
! 704: while (docu != NULL) {
! 705: next = docu->next;
! 706: xmlRelaxNGFreeDocument(docu);
! 707: docu = next;
! 708: }
! 709: }
! 710:
! 711: /**
! 712: * xmlRelaxNGFreeInclude:
! 713: * @incl: a include structure
! 714: *
! 715: * Deallocate a RelaxNG include structure.
! 716: */
! 717: static void
! 718: xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
! 719: {
! 720: if (incl == NULL)
! 721: return;
! 722:
! 723: if (incl->href != NULL)
! 724: xmlFree(incl->href);
! 725: if (incl->doc != NULL)
! 726: xmlFreeDoc(incl->doc);
! 727: if (incl->schema != NULL)
! 728: xmlRelaxNGFree(incl->schema);
! 729: xmlFree(incl);
! 730: }
! 731:
! 732: /**
! 733: * xmlRelaxNGFreeIncludeList:
! 734: * @incl: a include structure list
! 735: *
! 736: * Deallocate a RelaxNG include structure.
! 737: */
! 738: static void
! 739: xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
! 740: {
! 741: xmlRelaxNGIncludePtr next;
! 742:
! 743: while (incl != NULL) {
! 744: next = incl->next;
! 745: xmlRelaxNGFreeInclude(incl);
! 746: incl = next;
! 747: }
! 748: }
! 749:
! 750: /**
! 751: * xmlRelaxNGNewRelaxNG:
! 752: * @ctxt: a Relax-NG validation context (optional)
! 753: *
! 754: * Allocate a new RelaxNG structure.
! 755: *
! 756: * Returns the newly allocated structure or NULL in case or error
! 757: */
! 758: static xmlRelaxNGPtr
! 759: xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
! 760: {
! 761: xmlRelaxNGPtr ret;
! 762:
! 763: ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
! 764: if (ret == NULL) {
! 765: xmlRngPErrMemory(ctxt, NULL);
! 766: return (NULL);
! 767: }
! 768: memset(ret, 0, sizeof(xmlRelaxNG));
! 769:
! 770: return (ret);
! 771: }
! 772:
! 773: /**
! 774: * xmlRelaxNGFreeInnerSchema:
! 775: * @schema: a schema structure
! 776: *
! 777: * Deallocate a RelaxNG schema structure.
! 778: */
! 779: static void
! 780: xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
! 781: {
! 782: if (schema == NULL)
! 783: return;
! 784:
! 785: if (schema->doc != NULL)
! 786: xmlFreeDoc(schema->doc);
! 787: if (schema->defTab != NULL) {
! 788: int i;
! 789:
! 790: for (i = 0; i < schema->defNr; i++)
! 791: xmlRelaxNGFreeDefine(schema->defTab[i]);
! 792: xmlFree(schema->defTab);
! 793: }
! 794:
! 795: xmlFree(schema);
! 796: }
! 797:
! 798: /**
! 799: * xmlRelaxNGFree:
! 800: * @schema: a schema structure
! 801: *
! 802: * Deallocate a RelaxNG structure.
! 803: */
! 804: void
! 805: xmlRelaxNGFree(xmlRelaxNGPtr schema)
! 806: {
! 807: if (schema == NULL)
! 808: return;
! 809:
! 810: if (schema->topgrammar != NULL)
! 811: xmlRelaxNGFreeGrammar(schema->topgrammar);
! 812: if (schema->doc != NULL)
! 813: xmlFreeDoc(schema->doc);
! 814: if (schema->documents != NULL)
! 815: xmlRelaxNGFreeDocumentList(schema->documents);
! 816: if (schema->includes != NULL)
! 817: xmlRelaxNGFreeIncludeList(schema->includes);
! 818: if (schema->defTab != NULL) {
! 819: int i;
! 820:
! 821: for (i = 0; i < schema->defNr; i++)
! 822: xmlRelaxNGFreeDefine(schema->defTab[i]);
! 823: xmlFree(schema->defTab);
! 824: }
! 825:
! 826: xmlFree(schema);
! 827: }
! 828:
! 829: /**
! 830: * xmlRelaxNGNewGrammar:
! 831: * @ctxt: a Relax-NG validation context (optional)
! 832: *
! 833: * Allocate a new RelaxNG grammar.
! 834: *
! 835: * Returns the newly allocated structure or NULL in case or error
! 836: */
! 837: static xmlRelaxNGGrammarPtr
! 838: xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
! 839: {
! 840: xmlRelaxNGGrammarPtr ret;
! 841:
! 842: ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
! 843: if (ret == NULL) {
! 844: xmlRngPErrMemory(ctxt, NULL);
! 845: return (NULL);
! 846: }
! 847: memset(ret, 0, sizeof(xmlRelaxNGGrammar));
! 848:
! 849: return (ret);
! 850: }
! 851:
! 852: /**
! 853: * xmlRelaxNGFreeGrammar:
! 854: * @grammar: a grammar structure
! 855: *
! 856: * Deallocate a RelaxNG grammar structure.
! 857: */
! 858: static void
! 859: xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
! 860: {
! 861: if (grammar == NULL)
! 862: return;
! 863:
! 864: if (grammar->children != NULL) {
! 865: xmlRelaxNGFreeGrammar(grammar->children);
! 866: }
! 867: if (grammar->next != NULL) {
! 868: xmlRelaxNGFreeGrammar(grammar->next);
! 869: }
! 870: if (grammar->refs != NULL) {
! 871: xmlHashFree(grammar->refs, NULL);
! 872: }
! 873: if (grammar->defs != NULL) {
! 874: xmlHashFree(grammar->defs, NULL);
! 875: }
! 876:
! 877: xmlFree(grammar);
! 878: }
! 879:
! 880: /**
! 881: * xmlRelaxNGNewDefine:
! 882: * @ctxt: a Relax-NG validation context
! 883: * @node: the node in the input document.
! 884: *
! 885: * Allocate a new RelaxNG define.
! 886: *
! 887: * Returns the newly allocated structure or NULL in case or error
! 888: */
! 889: static xmlRelaxNGDefinePtr
! 890: xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 891: {
! 892: xmlRelaxNGDefinePtr ret;
! 893:
! 894: if (ctxt->defMax == 0) {
! 895: ctxt->defMax = 16;
! 896: ctxt->defNr = 0;
! 897: ctxt->defTab = (xmlRelaxNGDefinePtr *)
! 898: xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
! 899: if (ctxt->defTab == NULL) {
! 900: xmlRngPErrMemory(ctxt, "allocating define\n");
! 901: return (NULL);
! 902: }
! 903: } else if (ctxt->defMax <= ctxt->defNr) {
! 904: xmlRelaxNGDefinePtr *tmp;
! 905:
! 906: ctxt->defMax *= 2;
! 907: tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
! 908: ctxt->defMax *
! 909: sizeof
! 910: (xmlRelaxNGDefinePtr));
! 911: if (tmp == NULL) {
! 912: xmlRngPErrMemory(ctxt, "allocating define\n");
! 913: return (NULL);
! 914: }
! 915: ctxt->defTab = tmp;
! 916: }
! 917: ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
! 918: if (ret == NULL) {
! 919: xmlRngPErrMemory(ctxt, "allocating define\n");
! 920: return (NULL);
! 921: }
! 922: memset(ret, 0, sizeof(xmlRelaxNGDefine));
! 923: ctxt->defTab[ctxt->defNr++] = ret;
! 924: ret->node = node;
! 925: ret->depth = -1;
! 926: return (ret);
! 927: }
! 928:
! 929: /**
! 930: * xmlRelaxNGFreePartition:
! 931: * @partitions: a partition set structure
! 932: *
! 933: * Deallocate RelaxNG partition set structures.
! 934: */
! 935: static void
! 936: xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
! 937: {
! 938: xmlRelaxNGInterleaveGroupPtr group;
! 939: int j;
! 940:
! 941: if (partitions != NULL) {
! 942: if (partitions->groups != NULL) {
! 943: for (j = 0; j < partitions->nbgroups; j++) {
! 944: group = partitions->groups[j];
! 945: if (group != NULL) {
! 946: if (group->defs != NULL)
! 947: xmlFree(group->defs);
! 948: if (group->attrs != NULL)
! 949: xmlFree(group->attrs);
! 950: xmlFree(group);
! 951: }
! 952: }
! 953: xmlFree(partitions->groups);
! 954: }
! 955: if (partitions->triage != NULL) {
! 956: xmlHashFree(partitions->triage, NULL);
! 957: }
! 958: xmlFree(partitions);
! 959: }
! 960: }
! 961:
! 962: /**
! 963: * xmlRelaxNGFreeDefine:
! 964: * @define: a define structure
! 965: *
! 966: * Deallocate a RelaxNG define structure.
! 967: */
! 968: static void
! 969: xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
! 970: {
! 971: if (define == NULL)
! 972: return;
! 973:
! 974: if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
! 975: xmlRelaxNGTypeLibraryPtr lib;
! 976:
! 977: lib = (xmlRelaxNGTypeLibraryPtr) define->data;
! 978: if ((lib != NULL) && (lib->freef != NULL))
! 979: lib->freef(lib->data, (void *) define->attrs);
! 980: }
! 981: if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
! 982: xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
! 983: if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
! 984: xmlHashFree((xmlHashTablePtr) define->data, NULL);
! 985: if (define->name != NULL)
! 986: xmlFree(define->name);
! 987: if (define->ns != NULL)
! 988: xmlFree(define->ns);
! 989: if (define->value != NULL)
! 990: xmlFree(define->value);
! 991: if (define->contModel != NULL)
! 992: xmlRegFreeRegexp(define->contModel);
! 993: xmlFree(define);
! 994: }
! 995:
! 996: /**
! 997: * xmlRelaxNGNewStates:
! 998: * @ctxt: a Relax-NG validation context
! 999: * @size: the default size for the container
! 1000: *
! 1001: * Allocate a new RelaxNG validation state container
! 1002: *
! 1003: * Returns the newly allocated structure or NULL in case or error
! 1004: */
! 1005: static xmlRelaxNGStatesPtr
! 1006: xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
! 1007: {
! 1008: xmlRelaxNGStatesPtr ret;
! 1009:
! 1010: if ((ctxt != NULL) &&
! 1011: (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
! 1012: ctxt->freeStatesNr--;
! 1013: ret = ctxt->freeStates[ctxt->freeStatesNr];
! 1014: ret->nbState = 0;
! 1015: return (ret);
! 1016: }
! 1017: if (size < 16)
! 1018: size = 16;
! 1019:
! 1020: ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
! 1021: (size -
! 1022: 1) *
! 1023: sizeof(xmlRelaxNGValidStatePtr));
! 1024: if (ret == NULL) {
! 1025: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1026: return (NULL);
! 1027: }
! 1028: ret->nbState = 0;
! 1029: ret->maxState = size;
! 1030: ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
! 1031: sizeof
! 1032: (xmlRelaxNGValidStatePtr));
! 1033: if (ret->tabState == NULL) {
! 1034: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1035: xmlFree(ret);
! 1036: return (NULL);
! 1037: }
! 1038: return (ret);
! 1039: }
! 1040:
! 1041: /**
! 1042: * xmlRelaxNGAddStateUniq:
! 1043: * @ctxt: a Relax-NG validation context
! 1044: * @states: the states container
! 1045: * @state: the validation state
! 1046: *
! 1047: * Add a RelaxNG validation state to the container without checking
! 1048: * for unicity.
! 1049: *
! 1050: * Return 1 in case of success and 0 if this is a duplicate and -1 on error
! 1051: */
! 1052: static int
! 1053: xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
! 1054: xmlRelaxNGStatesPtr states,
! 1055: xmlRelaxNGValidStatePtr state)
! 1056: {
! 1057: if (state == NULL) {
! 1058: return (-1);
! 1059: }
! 1060: if (states->nbState >= states->maxState) {
! 1061: xmlRelaxNGValidStatePtr *tmp;
! 1062: int size;
! 1063:
! 1064: size = states->maxState * 2;
! 1065: tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
! 1066: (size) *
! 1067: sizeof
! 1068: (xmlRelaxNGValidStatePtr));
! 1069: if (tmp == NULL) {
! 1070: xmlRngVErrMemory(ctxt, "adding states\n");
! 1071: return (-1);
! 1072: }
! 1073: states->tabState = tmp;
! 1074: states->maxState = size;
! 1075: }
! 1076: states->tabState[states->nbState++] = state;
! 1077: return (1);
! 1078: }
! 1079:
! 1080: /**
! 1081: * xmlRelaxNGAddState:
! 1082: * @ctxt: a Relax-NG validation context
! 1083: * @states: the states container
! 1084: * @state: the validation state
! 1085: *
! 1086: * Add a RelaxNG validation state to the container
! 1087: *
! 1088: * Return 1 in case of success and 0 if this is a duplicate and -1 on error
! 1089: */
! 1090: static int
! 1091: xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
! 1092: xmlRelaxNGStatesPtr states,
! 1093: xmlRelaxNGValidStatePtr state)
! 1094: {
! 1095: int i;
! 1096:
! 1097: if (state == NULL) {
! 1098: return (-1);
! 1099: }
! 1100: if (states->nbState >= states->maxState) {
! 1101: xmlRelaxNGValidStatePtr *tmp;
! 1102: int size;
! 1103:
! 1104: size = states->maxState * 2;
! 1105: tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
! 1106: (size) *
! 1107: sizeof
! 1108: (xmlRelaxNGValidStatePtr));
! 1109: if (tmp == NULL) {
! 1110: xmlRngVErrMemory(ctxt, "adding states\n");
! 1111: return (-1);
! 1112: }
! 1113: states->tabState = tmp;
! 1114: states->maxState = size;
! 1115: }
! 1116: for (i = 0; i < states->nbState; i++) {
! 1117: if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
! 1118: xmlRelaxNGFreeValidState(ctxt, state);
! 1119: return (0);
! 1120: }
! 1121: }
! 1122: states->tabState[states->nbState++] = state;
! 1123: return (1);
! 1124: }
! 1125:
! 1126: /**
! 1127: * xmlRelaxNGFreeStates:
! 1128: * @ctxt: a Relax-NG validation context
! 1129: * @states: teh container
! 1130: *
! 1131: * Free a RelaxNG validation state container
! 1132: */
! 1133: static void
! 1134: xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
! 1135: xmlRelaxNGStatesPtr states)
! 1136: {
! 1137: if (states == NULL)
! 1138: return;
! 1139: if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
! 1140: ctxt->freeStatesMax = 40;
! 1141: ctxt->freeStatesNr = 0;
! 1142: ctxt->freeStates = (xmlRelaxNGStatesPtr *)
! 1143: xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
! 1144: if (ctxt->freeStates == NULL) {
! 1145: xmlRngVErrMemory(ctxt, "storing states\n");
! 1146: }
! 1147: } else if ((ctxt != NULL)
! 1148: && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
! 1149: xmlRelaxNGStatesPtr *tmp;
! 1150:
! 1151: tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
! 1152: 2 * ctxt->freeStatesMax *
! 1153: sizeof
! 1154: (xmlRelaxNGStatesPtr));
! 1155: if (tmp == NULL) {
! 1156: xmlRngVErrMemory(ctxt, "storing states\n");
! 1157: xmlFree(states->tabState);
! 1158: xmlFree(states);
! 1159: return;
! 1160: }
! 1161: ctxt->freeStates = tmp;
! 1162: ctxt->freeStatesMax *= 2;
! 1163: }
! 1164: if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
! 1165: xmlFree(states->tabState);
! 1166: xmlFree(states);
! 1167: } else {
! 1168: ctxt->freeStates[ctxt->freeStatesNr++] = states;
! 1169: }
! 1170: }
! 1171:
! 1172: /**
! 1173: * xmlRelaxNGNewValidState:
! 1174: * @ctxt: a Relax-NG validation context
! 1175: * @node: the current node or NULL for the document
! 1176: *
! 1177: * Allocate a new RelaxNG validation state
! 1178: *
! 1179: * Returns the newly allocated structure or NULL in case or error
! 1180: */
! 1181: static xmlRelaxNGValidStatePtr
! 1182: xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
! 1183: {
! 1184: xmlRelaxNGValidStatePtr ret;
! 1185: xmlAttrPtr attr;
! 1186: xmlAttrPtr attrs[MAX_ATTR];
! 1187: int nbAttrs = 0;
! 1188: xmlNodePtr root = NULL;
! 1189:
! 1190: if (node == NULL) {
! 1191: root = xmlDocGetRootElement(ctxt->doc);
! 1192: if (root == NULL)
! 1193: return (NULL);
! 1194: } else {
! 1195: attr = node->properties;
! 1196: while (attr != NULL) {
! 1197: if (nbAttrs < MAX_ATTR)
! 1198: attrs[nbAttrs++] = attr;
! 1199: else
! 1200: nbAttrs++;
! 1201: attr = attr->next;
! 1202: }
! 1203: }
! 1204: if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
! 1205: ctxt->freeState->nbState--;
! 1206: ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
! 1207: } else {
! 1208: ret =
! 1209: (xmlRelaxNGValidStatePtr)
! 1210: xmlMalloc(sizeof(xmlRelaxNGValidState));
! 1211: if (ret == NULL) {
! 1212: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1213: return (NULL);
! 1214: }
! 1215: memset(ret, 0, sizeof(xmlRelaxNGValidState));
! 1216: }
! 1217: ret->value = NULL;
! 1218: ret->endvalue = NULL;
! 1219: if (node == NULL) {
! 1220: ret->node = (xmlNodePtr) ctxt->doc;
! 1221: ret->seq = root;
! 1222: } else {
! 1223: ret->node = node;
! 1224: ret->seq = node->children;
! 1225: }
! 1226: ret->nbAttrs = 0;
! 1227: if (nbAttrs > 0) {
! 1228: if (ret->attrs == NULL) {
! 1229: if (nbAttrs < 4)
! 1230: ret->maxAttrs = 4;
! 1231: else
! 1232: ret->maxAttrs = nbAttrs;
! 1233: ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
! 1234: sizeof(xmlAttrPtr));
! 1235: if (ret->attrs == NULL) {
! 1236: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1237: return (ret);
! 1238: }
! 1239: } else if (ret->maxAttrs < nbAttrs) {
! 1240: xmlAttrPtr *tmp;
! 1241:
! 1242: tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
! 1243: sizeof(xmlAttrPtr));
! 1244: if (tmp == NULL) {
! 1245: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1246: return (ret);
! 1247: }
! 1248: ret->attrs = tmp;
! 1249: ret->maxAttrs = nbAttrs;
! 1250: }
! 1251: ret->nbAttrs = nbAttrs;
! 1252: if (nbAttrs < MAX_ATTR) {
! 1253: memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
! 1254: } else {
! 1255: attr = node->properties;
! 1256: nbAttrs = 0;
! 1257: while (attr != NULL) {
! 1258: ret->attrs[nbAttrs++] = attr;
! 1259: attr = attr->next;
! 1260: }
! 1261: }
! 1262: }
! 1263: ret->nbAttrLeft = ret->nbAttrs;
! 1264: return (ret);
! 1265: }
! 1266:
! 1267: /**
! 1268: * xmlRelaxNGCopyValidState:
! 1269: * @ctxt: a Relax-NG validation context
! 1270: * @state: a validation state
! 1271: *
! 1272: * Copy the validation state
! 1273: *
! 1274: * Returns the newly allocated structure or NULL in case or error
! 1275: */
! 1276: static xmlRelaxNGValidStatePtr
! 1277: xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
! 1278: xmlRelaxNGValidStatePtr state)
! 1279: {
! 1280: xmlRelaxNGValidStatePtr ret;
! 1281: unsigned int maxAttrs;
! 1282: xmlAttrPtr *attrs;
! 1283:
! 1284: if (state == NULL)
! 1285: return (NULL);
! 1286: if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
! 1287: ctxt->freeState->nbState--;
! 1288: ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
! 1289: } else {
! 1290: ret =
! 1291: (xmlRelaxNGValidStatePtr)
! 1292: xmlMalloc(sizeof(xmlRelaxNGValidState));
! 1293: if (ret == NULL) {
! 1294: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1295: return (NULL);
! 1296: }
! 1297: memset(ret, 0, sizeof(xmlRelaxNGValidState));
! 1298: }
! 1299: attrs = ret->attrs;
! 1300: maxAttrs = ret->maxAttrs;
! 1301: memcpy(ret, state, sizeof(xmlRelaxNGValidState));
! 1302: ret->attrs = attrs;
! 1303: ret->maxAttrs = maxAttrs;
! 1304: if (state->nbAttrs > 0) {
! 1305: if (ret->attrs == NULL) {
! 1306: ret->maxAttrs = state->maxAttrs;
! 1307: ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
! 1308: sizeof(xmlAttrPtr));
! 1309: if (ret->attrs == NULL) {
! 1310: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1311: ret->nbAttrs = 0;
! 1312: return (ret);
! 1313: }
! 1314: } else if (ret->maxAttrs < state->nbAttrs) {
! 1315: xmlAttrPtr *tmp;
! 1316:
! 1317: tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
! 1318: sizeof(xmlAttrPtr));
! 1319: if (tmp == NULL) {
! 1320: xmlRngVErrMemory(ctxt, "allocating states\n");
! 1321: ret->nbAttrs = 0;
! 1322: return (ret);
! 1323: }
! 1324: ret->maxAttrs = state->maxAttrs;
! 1325: ret->attrs = tmp;
! 1326: }
! 1327: memcpy(ret->attrs, state->attrs,
! 1328: state->nbAttrs * sizeof(xmlAttrPtr));
! 1329: }
! 1330: return (ret);
! 1331: }
! 1332:
! 1333: /**
! 1334: * xmlRelaxNGEqualValidState:
! 1335: * @ctxt: a Relax-NG validation context
! 1336: * @state1: a validation state
! 1337: * @state2: a validation state
! 1338: *
! 1339: * Compare the validation states for equality
! 1340: *
! 1341: * Returns 1 if equald, 0 otherwise
! 1342: */
! 1343: static int
! 1344: xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
! 1345: xmlRelaxNGValidStatePtr state1,
! 1346: xmlRelaxNGValidStatePtr state2)
! 1347: {
! 1348: int i;
! 1349:
! 1350: if ((state1 == NULL) || (state2 == NULL))
! 1351: return (0);
! 1352: if (state1 == state2)
! 1353: return (1);
! 1354: if (state1->node != state2->node)
! 1355: return (0);
! 1356: if (state1->seq != state2->seq)
! 1357: return (0);
! 1358: if (state1->nbAttrLeft != state2->nbAttrLeft)
! 1359: return (0);
! 1360: if (state1->nbAttrs != state2->nbAttrs)
! 1361: return (0);
! 1362: if (state1->endvalue != state2->endvalue)
! 1363: return (0);
! 1364: if ((state1->value != state2->value) &&
! 1365: (!xmlStrEqual(state1->value, state2->value)))
! 1366: return (0);
! 1367: for (i = 0; i < state1->nbAttrs; i++) {
! 1368: if (state1->attrs[i] != state2->attrs[i])
! 1369: return (0);
! 1370: }
! 1371: return (1);
! 1372: }
! 1373:
! 1374: /**
! 1375: * xmlRelaxNGFreeValidState:
! 1376: * @state: a validation state structure
! 1377: *
! 1378: * Deallocate a RelaxNG validation state structure.
! 1379: */
! 1380: static void
! 1381: xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
! 1382: xmlRelaxNGValidStatePtr state)
! 1383: {
! 1384: if (state == NULL)
! 1385: return;
! 1386:
! 1387: if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
! 1388: ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
! 1389: }
! 1390: if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
! 1391: if (state->attrs != NULL)
! 1392: xmlFree(state->attrs);
! 1393: xmlFree(state);
! 1394: } else {
! 1395: xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
! 1396: }
! 1397: }
! 1398:
! 1399: /************************************************************************
! 1400: * *
! 1401: * Semi internal functions *
! 1402: * *
! 1403: ************************************************************************/
! 1404:
! 1405: /**
! 1406: * xmlRelaxParserSetFlag:
! 1407: * @ctxt: a RelaxNG parser context
! 1408: * @flags: a set of flags values
! 1409: *
! 1410: * Semi private function used to pass informations to a parser context
! 1411: * which are a combination of xmlRelaxNGParserFlag .
! 1412: *
! 1413: * Returns 0 if success and -1 in case of error
! 1414: */
! 1415: int
! 1416: xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
! 1417: {
! 1418: if (ctxt == NULL) return(-1);
! 1419: if (flags & XML_RELAXNGP_FREE_DOC) {
! 1420: ctxt->crng |= XML_RELAXNGP_FREE_DOC;
! 1421: flags -= XML_RELAXNGP_FREE_DOC;
! 1422: }
! 1423: if (flags & XML_RELAXNGP_CRNG) {
! 1424: ctxt->crng |= XML_RELAXNGP_CRNG;
! 1425: flags -= XML_RELAXNGP_CRNG;
! 1426: }
! 1427: if (flags != 0) return(-1);
! 1428: return(0);
! 1429: }
! 1430:
! 1431: /************************************************************************
! 1432: * *
! 1433: * Document functions *
! 1434: * *
! 1435: ************************************************************************/
! 1436: static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
! 1437: xmlDocPtr doc);
! 1438:
! 1439: /**
! 1440: * xmlRelaxNGIncludePush:
! 1441: * @ctxt: the parser context
! 1442: * @value: the element doc
! 1443: *
! 1444: * Pushes a new include on top of the include stack
! 1445: *
! 1446: * Returns 0 in case of error, the index in the stack otherwise
! 1447: */
! 1448: static int
! 1449: xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
! 1450: xmlRelaxNGIncludePtr value)
! 1451: {
! 1452: if (ctxt->incTab == NULL) {
! 1453: ctxt->incMax = 4;
! 1454: ctxt->incNr = 0;
! 1455: ctxt->incTab =
! 1456: (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
! 1457: sizeof(ctxt->incTab[0]));
! 1458: if (ctxt->incTab == NULL) {
! 1459: xmlRngPErrMemory(ctxt, "allocating include\n");
! 1460: return (0);
! 1461: }
! 1462: }
! 1463: if (ctxt->incNr >= ctxt->incMax) {
! 1464: ctxt->incMax *= 2;
! 1465: ctxt->incTab =
! 1466: (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
! 1467: ctxt->incMax *
! 1468: sizeof(ctxt->incTab[0]));
! 1469: if (ctxt->incTab == NULL) {
! 1470: xmlRngPErrMemory(ctxt, "allocating include\n");
! 1471: return (0);
! 1472: }
! 1473: }
! 1474: ctxt->incTab[ctxt->incNr] = value;
! 1475: ctxt->inc = value;
! 1476: return (ctxt->incNr++);
! 1477: }
! 1478:
! 1479: /**
! 1480: * xmlRelaxNGIncludePop:
! 1481: * @ctxt: the parser context
! 1482: *
! 1483: * Pops the top include from the include stack
! 1484: *
! 1485: * Returns the include just removed
! 1486: */
! 1487: static xmlRelaxNGIncludePtr
! 1488: xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
! 1489: {
! 1490: xmlRelaxNGIncludePtr ret;
! 1491:
! 1492: if (ctxt->incNr <= 0)
! 1493: return (NULL);
! 1494: ctxt->incNr--;
! 1495: if (ctxt->incNr > 0)
! 1496: ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
! 1497: else
! 1498: ctxt->inc = NULL;
! 1499: ret = ctxt->incTab[ctxt->incNr];
! 1500: ctxt->incTab[ctxt->incNr] = NULL;
! 1501: return (ret);
! 1502: }
! 1503:
! 1504: /**
! 1505: * xmlRelaxNGRemoveRedefine:
! 1506: * @ctxt: the parser context
! 1507: * @URL: the normalized URL
! 1508: * @target: the included target
! 1509: * @name: the define name to eliminate
! 1510: *
! 1511: * Applies the elimination algorithm of 4.7
! 1512: *
! 1513: * Returns 0 in case of error, 1 in case of success.
! 1514: */
! 1515: static int
! 1516: xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
! 1517: const xmlChar * URL ATTRIBUTE_UNUSED,
! 1518: xmlNodePtr target, const xmlChar * name)
! 1519: {
! 1520: int found = 0;
! 1521: xmlNodePtr tmp, tmp2;
! 1522: xmlChar *name2;
! 1523:
! 1524: #ifdef DEBUG_INCLUDE
! 1525: if (name == NULL)
! 1526: xmlGenericError(xmlGenericErrorContext,
! 1527: "Elimination of <include> start from %s\n", URL);
! 1528: else
! 1529: xmlGenericError(xmlGenericErrorContext,
! 1530: "Elimination of <include> define %s from %s\n",
! 1531: name, URL);
! 1532: #endif
! 1533: tmp = target;
! 1534: while (tmp != NULL) {
! 1535: tmp2 = tmp->next;
! 1536: if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
! 1537: found = 1;
! 1538: xmlUnlinkNode(tmp);
! 1539: xmlFreeNode(tmp);
! 1540: } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
! 1541: name2 = xmlGetProp(tmp, BAD_CAST "name");
! 1542: xmlRelaxNGNormExtSpace(name2);
! 1543: if (name2 != NULL) {
! 1544: if (xmlStrEqual(name, name2)) {
! 1545: found = 1;
! 1546: xmlUnlinkNode(tmp);
! 1547: xmlFreeNode(tmp);
! 1548: }
! 1549: xmlFree(name2);
! 1550: }
! 1551: } else if (IS_RELAXNG(tmp, "include")) {
! 1552: xmlChar *href = NULL;
! 1553: xmlRelaxNGDocumentPtr inc = tmp->psvi;
! 1554:
! 1555: if ((inc != NULL) && (inc->doc != NULL) &&
! 1556: (inc->doc->children != NULL)) {
! 1557:
! 1558: if (xmlStrEqual
! 1559: (inc->doc->children->name, BAD_CAST "grammar")) {
! 1560: #ifdef DEBUG_INCLUDE
! 1561: href = xmlGetProp(tmp, BAD_CAST "href");
! 1562: #endif
! 1563: if (xmlRelaxNGRemoveRedefine(ctxt, href,
! 1564: inc->doc->children->
! 1565: children, name) == 1) {
! 1566: found = 1;
! 1567: }
! 1568: #ifdef DEBUG_INCLUDE
! 1569: if (href != NULL)
! 1570: xmlFree(href);
! 1571: #endif
! 1572: }
! 1573: }
! 1574: }
! 1575: tmp = tmp2;
! 1576: }
! 1577: return (found);
! 1578: }
! 1579:
! 1580: /**
! 1581: * xmlRelaxNGLoadInclude:
! 1582: * @ctxt: the parser context
! 1583: * @URL: the normalized URL
! 1584: * @node: the include node.
! 1585: * @ns: the namespace passed from the context.
! 1586: *
! 1587: * First lookup if the document is already loaded into the parser context,
! 1588: * check against recursion. If not found the resource is loaded and
! 1589: * the content is preprocessed before being returned back to the caller.
! 1590: *
! 1591: * Returns the xmlRelaxNGIncludePtr or NULL in case of error
! 1592: */
! 1593: static xmlRelaxNGIncludePtr
! 1594: xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
! 1595: xmlNodePtr node, const xmlChar * ns)
! 1596: {
! 1597: xmlRelaxNGIncludePtr ret = NULL;
! 1598: xmlDocPtr doc;
! 1599: int i;
! 1600: xmlNodePtr root, cur;
! 1601:
! 1602: #ifdef DEBUG_INCLUDE
! 1603: xmlGenericError(xmlGenericErrorContext,
! 1604: "xmlRelaxNGLoadInclude(%s)\n", URL);
! 1605: #endif
! 1606:
! 1607: /*
! 1608: * check against recursion in the stack
! 1609: */
! 1610: for (i = 0; i < ctxt->incNr; i++) {
! 1611: if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
! 1612: xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
! 1613: "Detected an Include recursion for %s\n", URL,
! 1614: NULL);
! 1615: return (NULL);
! 1616: }
! 1617: }
! 1618:
! 1619: /*
! 1620: * load the document
! 1621: */
! 1622: doc = xmlReadFile((const char *) URL,NULL,0);
! 1623: if (doc == NULL) {
! 1624: xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
! 1625: "xmlRelaxNG: could not load %s\n", URL, NULL);
! 1626: return (NULL);
! 1627: }
! 1628: #ifdef DEBUG_INCLUDE
! 1629: xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
! 1630: #endif
! 1631:
! 1632: /*
! 1633: * Allocate the document structures and register it first.
! 1634: */
! 1635: ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
! 1636: if (ret == NULL) {
! 1637: xmlRngPErrMemory(ctxt, "allocating include\n");
! 1638: xmlFreeDoc(doc);
! 1639: return (NULL);
! 1640: }
! 1641: memset(ret, 0, sizeof(xmlRelaxNGInclude));
! 1642: ret->doc = doc;
! 1643: ret->href = xmlStrdup(URL);
! 1644: ret->next = ctxt->includes;
! 1645: ctxt->includes = ret;
! 1646:
! 1647: /*
! 1648: * transmit the ns if needed
! 1649: */
! 1650: if (ns != NULL) {
! 1651: root = xmlDocGetRootElement(doc);
! 1652: if (root != NULL) {
! 1653: if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
! 1654: xmlSetProp(root, BAD_CAST "ns", ns);
! 1655: }
! 1656: }
! 1657: }
! 1658:
! 1659: /*
! 1660: * push it on the stack
! 1661: */
! 1662: xmlRelaxNGIncludePush(ctxt, ret);
! 1663:
! 1664: /*
! 1665: * Some preprocessing of the document content, this include recursing
! 1666: * in the include stack.
! 1667: */
! 1668: #ifdef DEBUG_INCLUDE
! 1669: xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
! 1670: #endif
! 1671:
! 1672: doc = xmlRelaxNGCleanupDoc(ctxt, doc);
! 1673: if (doc == NULL) {
! 1674: ctxt->inc = NULL;
! 1675: return (NULL);
! 1676: }
! 1677:
! 1678: /*
! 1679: * Pop up the include from the stack
! 1680: */
! 1681: xmlRelaxNGIncludePop(ctxt);
! 1682:
! 1683: #ifdef DEBUG_INCLUDE
! 1684: xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
! 1685: #endif
! 1686: /*
! 1687: * Check that the top element is a grammar
! 1688: */
! 1689: root = xmlDocGetRootElement(doc);
! 1690: if (root == NULL) {
! 1691: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
! 1692: "xmlRelaxNG: included document is empty %s\n", URL,
! 1693: NULL);
! 1694: return (NULL);
! 1695: }
! 1696: if (!IS_RELAXNG(root, "grammar")) {
! 1697: xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
! 1698: "xmlRelaxNG: included document %s root is not a grammar\n",
! 1699: URL, NULL);
! 1700: return (NULL);
! 1701: }
! 1702:
! 1703: /*
! 1704: * Elimination of redefined rules in the include.
! 1705: */
! 1706: cur = node->children;
! 1707: while (cur != NULL) {
! 1708: if (IS_RELAXNG(cur, "start")) {
! 1709: int found = 0;
! 1710:
! 1711: found =
! 1712: xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
! 1713: if (!found) {
! 1714: xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
! 1715: "xmlRelaxNG: include %s has a start but not the included grammar\n",
! 1716: URL, NULL);
! 1717: }
! 1718: } else if (IS_RELAXNG(cur, "define")) {
! 1719: xmlChar *name;
! 1720:
! 1721: name = xmlGetProp(cur, BAD_CAST "name");
! 1722: if (name == NULL) {
! 1723: xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
! 1724: "xmlRelaxNG: include %s has define without name\n",
! 1725: URL, NULL);
! 1726: } else {
! 1727: int found;
! 1728:
! 1729: xmlRelaxNGNormExtSpace(name);
! 1730: found = xmlRelaxNGRemoveRedefine(ctxt, URL,
! 1731: root->children, name);
! 1732: if (!found) {
! 1733: xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
! 1734: "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
! 1735: URL, name);
! 1736: }
! 1737: xmlFree(name);
! 1738: }
! 1739: }
! 1740: cur = cur->next;
! 1741: }
! 1742:
! 1743:
! 1744: return (ret);
! 1745: }
! 1746:
! 1747: /**
! 1748: * xmlRelaxNGValidErrorPush:
! 1749: * @ctxt: the validation context
! 1750: * @err: the error code
! 1751: * @arg1: the first string argument
! 1752: * @arg2: the second string argument
! 1753: * @dup: arg need to be duplicated
! 1754: *
! 1755: * Pushes a new error on top of the error stack
! 1756: *
! 1757: * Returns 0 in case of error, the index in the stack otherwise
! 1758: */
! 1759: static int
! 1760: xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
! 1761: xmlRelaxNGValidErr err, const xmlChar * arg1,
! 1762: const xmlChar * arg2, int dup)
! 1763: {
! 1764: xmlRelaxNGValidErrorPtr cur;
! 1765:
! 1766: #ifdef DEBUG_ERROR
! 1767: xmlGenericError(xmlGenericErrorContext,
! 1768: "Pushing error %d at %d on stack\n", err, ctxt->errNr);
! 1769: #endif
! 1770: if (ctxt->errTab == NULL) {
! 1771: ctxt->errMax = 8;
! 1772: ctxt->errNr = 0;
! 1773: ctxt->errTab =
! 1774: (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
! 1775: sizeof
! 1776: (xmlRelaxNGValidError));
! 1777: if (ctxt->errTab == NULL) {
! 1778: xmlRngVErrMemory(ctxt, "pushing error\n");
! 1779: return (0);
! 1780: }
! 1781: ctxt->err = NULL;
! 1782: }
! 1783: if (ctxt->errNr >= ctxt->errMax) {
! 1784: ctxt->errMax *= 2;
! 1785: ctxt->errTab =
! 1786: (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
! 1787: ctxt->errMax *
! 1788: sizeof
! 1789: (xmlRelaxNGValidError));
! 1790: if (ctxt->errTab == NULL) {
! 1791: xmlRngVErrMemory(ctxt, "pushing error\n");
! 1792: return (0);
! 1793: }
! 1794: ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
! 1795: }
! 1796: if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
! 1797: (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
! 1798: return (ctxt->errNr);
! 1799: cur = &ctxt->errTab[ctxt->errNr];
! 1800: cur->err = err;
! 1801: if (dup) {
! 1802: cur->arg1 = xmlStrdup(arg1);
! 1803: cur->arg2 = xmlStrdup(arg2);
! 1804: cur->flags = ERROR_IS_DUP;
! 1805: } else {
! 1806: cur->arg1 = arg1;
! 1807: cur->arg2 = arg2;
! 1808: cur->flags = 0;
! 1809: }
! 1810: if (ctxt->state != NULL) {
! 1811: cur->node = ctxt->state->node;
! 1812: cur->seq = ctxt->state->seq;
! 1813: } else {
! 1814: cur->node = NULL;
! 1815: cur->seq = NULL;
! 1816: }
! 1817: ctxt->err = cur;
! 1818: return (ctxt->errNr++);
! 1819: }
! 1820:
! 1821: /**
! 1822: * xmlRelaxNGValidErrorPop:
! 1823: * @ctxt: the validation context
! 1824: *
! 1825: * Pops the top error from the error stack
! 1826: */
! 1827: static void
! 1828: xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
! 1829: {
! 1830: xmlRelaxNGValidErrorPtr cur;
! 1831:
! 1832: if (ctxt->errNr <= 0) {
! 1833: ctxt->err = NULL;
! 1834: return;
! 1835: }
! 1836: ctxt->errNr--;
! 1837: if (ctxt->errNr > 0)
! 1838: ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
! 1839: else
! 1840: ctxt->err = NULL;
! 1841: cur = &ctxt->errTab[ctxt->errNr];
! 1842: if (cur->flags & ERROR_IS_DUP) {
! 1843: if (cur->arg1 != NULL)
! 1844: xmlFree((xmlChar *) cur->arg1);
! 1845: cur->arg1 = NULL;
! 1846: if (cur->arg2 != NULL)
! 1847: xmlFree((xmlChar *) cur->arg2);
! 1848: cur->arg2 = NULL;
! 1849: cur->flags = 0;
! 1850: }
! 1851: }
! 1852:
! 1853: /**
! 1854: * xmlRelaxNGDocumentPush:
! 1855: * @ctxt: the parser context
! 1856: * @value: the element doc
! 1857: *
! 1858: * Pushes a new doc on top of the doc stack
! 1859: *
! 1860: * Returns 0 in case of error, the index in the stack otherwise
! 1861: */
! 1862: static int
! 1863: xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
! 1864: xmlRelaxNGDocumentPtr value)
! 1865: {
! 1866: if (ctxt->docTab == NULL) {
! 1867: ctxt->docMax = 4;
! 1868: ctxt->docNr = 0;
! 1869: ctxt->docTab =
! 1870: (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
! 1871: sizeof(ctxt->docTab[0]));
! 1872: if (ctxt->docTab == NULL) {
! 1873: xmlRngPErrMemory(ctxt, "adding document\n");
! 1874: return (0);
! 1875: }
! 1876: }
! 1877: if (ctxt->docNr >= ctxt->docMax) {
! 1878: ctxt->docMax *= 2;
! 1879: ctxt->docTab =
! 1880: (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
! 1881: ctxt->docMax *
! 1882: sizeof(ctxt->docTab[0]));
! 1883: if (ctxt->docTab == NULL) {
! 1884: xmlRngPErrMemory(ctxt, "adding document\n");
! 1885: return (0);
! 1886: }
! 1887: }
! 1888: ctxt->docTab[ctxt->docNr] = value;
! 1889: ctxt->doc = value;
! 1890: return (ctxt->docNr++);
! 1891: }
! 1892:
! 1893: /**
! 1894: * xmlRelaxNGDocumentPop:
! 1895: * @ctxt: the parser context
! 1896: *
! 1897: * Pops the top doc from the doc stack
! 1898: *
! 1899: * Returns the doc just removed
! 1900: */
! 1901: static xmlRelaxNGDocumentPtr
! 1902: xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
! 1903: {
! 1904: xmlRelaxNGDocumentPtr ret;
! 1905:
! 1906: if (ctxt->docNr <= 0)
! 1907: return (NULL);
! 1908: ctxt->docNr--;
! 1909: if (ctxt->docNr > 0)
! 1910: ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
! 1911: else
! 1912: ctxt->doc = NULL;
! 1913: ret = ctxt->docTab[ctxt->docNr];
! 1914: ctxt->docTab[ctxt->docNr] = NULL;
! 1915: return (ret);
! 1916: }
! 1917:
! 1918: /**
! 1919: * xmlRelaxNGLoadExternalRef:
! 1920: * @ctxt: the parser context
! 1921: * @URL: the normalized URL
! 1922: * @ns: the inherited ns if any
! 1923: *
! 1924: * First lookup if the document is already loaded into the parser context,
! 1925: * check against recursion. If not found the resource is loaded and
! 1926: * the content is preprocessed before being returned back to the caller.
! 1927: *
! 1928: * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
! 1929: */
! 1930: static xmlRelaxNGDocumentPtr
! 1931: xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
! 1932: const xmlChar * URL, const xmlChar * ns)
! 1933: {
! 1934: xmlRelaxNGDocumentPtr ret = NULL;
! 1935: xmlDocPtr doc;
! 1936: xmlNodePtr root;
! 1937: int i;
! 1938:
! 1939: /*
! 1940: * check against recursion in the stack
! 1941: */
! 1942: for (i = 0; i < ctxt->docNr; i++) {
! 1943: if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
! 1944: xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
! 1945: "Detected an externalRef recursion for %s\n", URL,
! 1946: NULL);
! 1947: return (NULL);
! 1948: }
! 1949: }
! 1950:
! 1951: /*
! 1952: * load the document
! 1953: */
! 1954: doc = xmlReadFile((const char *) URL,NULL,0);
! 1955: if (doc == NULL) {
! 1956: xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
! 1957: "xmlRelaxNG: could not load %s\n", URL, NULL);
! 1958: return (NULL);
! 1959: }
! 1960:
! 1961: /*
! 1962: * Allocate the document structures and register it first.
! 1963: */
! 1964: ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
! 1965: if (ret == NULL) {
! 1966: xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
! 1967: "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
! 1968: xmlFreeDoc(doc);
! 1969: return (NULL);
! 1970: }
! 1971: memset(ret, 0, sizeof(xmlRelaxNGDocument));
! 1972: ret->doc = doc;
! 1973: ret->href = xmlStrdup(URL);
! 1974: ret->next = ctxt->documents;
! 1975: ret->externalRef = 1;
! 1976: ctxt->documents = ret;
! 1977:
! 1978: /*
! 1979: * transmit the ns if needed
! 1980: */
! 1981: if (ns != NULL) {
! 1982: root = xmlDocGetRootElement(doc);
! 1983: if (root != NULL) {
! 1984: if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
! 1985: xmlSetProp(root, BAD_CAST "ns", ns);
! 1986: }
! 1987: }
! 1988: }
! 1989:
! 1990: /*
! 1991: * push it on the stack and register it in the hash table
! 1992: */
! 1993: xmlRelaxNGDocumentPush(ctxt, ret);
! 1994:
! 1995: /*
! 1996: * Some preprocessing of the document content
! 1997: */
! 1998: doc = xmlRelaxNGCleanupDoc(ctxt, doc);
! 1999: if (doc == NULL) {
! 2000: ctxt->doc = NULL;
! 2001: return (NULL);
! 2002: }
! 2003:
! 2004: xmlRelaxNGDocumentPop(ctxt);
! 2005:
! 2006: return (ret);
! 2007: }
! 2008:
! 2009: /************************************************************************
! 2010: * *
! 2011: * Error functions *
! 2012: * *
! 2013: ************************************************************************/
! 2014:
! 2015: #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
! 2016: #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
! 2017: #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
! 2018: #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
! 2019: #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
! 2020:
! 2021: static const char *
! 2022: xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
! 2023: {
! 2024: if (def == NULL)
! 2025: return ("none");
! 2026: switch (def->type) {
! 2027: case XML_RELAXNG_EMPTY:
! 2028: return ("empty");
! 2029: case XML_RELAXNG_NOT_ALLOWED:
! 2030: return ("notAllowed");
! 2031: case XML_RELAXNG_EXCEPT:
! 2032: return ("except");
! 2033: case XML_RELAXNG_TEXT:
! 2034: return ("text");
! 2035: case XML_RELAXNG_ELEMENT:
! 2036: return ("element");
! 2037: case XML_RELAXNG_DATATYPE:
! 2038: return ("datatype");
! 2039: case XML_RELAXNG_VALUE:
! 2040: return ("value");
! 2041: case XML_RELAXNG_LIST:
! 2042: return ("list");
! 2043: case XML_RELAXNG_ATTRIBUTE:
! 2044: return ("attribute");
! 2045: case XML_RELAXNG_DEF:
! 2046: return ("def");
! 2047: case XML_RELAXNG_REF:
! 2048: return ("ref");
! 2049: case XML_RELAXNG_EXTERNALREF:
! 2050: return ("externalRef");
! 2051: case XML_RELAXNG_PARENTREF:
! 2052: return ("parentRef");
! 2053: case XML_RELAXNG_OPTIONAL:
! 2054: return ("optional");
! 2055: case XML_RELAXNG_ZEROORMORE:
! 2056: return ("zeroOrMore");
! 2057: case XML_RELAXNG_ONEORMORE:
! 2058: return ("oneOrMore");
! 2059: case XML_RELAXNG_CHOICE:
! 2060: return ("choice");
! 2061: case XML_RELAXNG_GROUP:
! 2062: return ("group");
! 2063: case XML_RELAXNG_INTERLEAVE:
! 2064: return ("interleave");
! 2065: case XML_RELAXNG_START:
! 2066: return ("start");
! 2067: case XML_RELAXNG_NOOP:
! 2068: return ("noop");
! 2069: case XML_RELAXNG_PARAM:
! 2070: return ("param");
! 2071: }
! 2072: return ("unknown");
! 2073: }
! 2074:
! 2075: /**
! 2076: * xmlRelaxNGGetErrorString:
! 2077: * @err: the error code
! 2078: * @arg1: the first string argument
! 2079: * @arg2: the second string argument
! 2080: *
! 2081: * computes a formatted error string for the given error code and args
! 2082: *
! 2083: * Returns the error string, it must be deallocated by the caller
! 2084: */
! 2085: static xmlChar *
! 2086: xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
! 2087: const xmlChar * arg2)
! 2088: {
! 2089: char msg[1000];
! 2090:
! 2091: if (arg1 == NULL)
! 2092: arg1 = BAD_CAST "";
! 2093: if (arg2 == NULL)
! 2094: arg2 = BAD_CAST "";
! 2095:
! 2096: msg[0] = 0;
! 2097: switch (err) {
! 2098: case XML_RELAXNG_OK:
! 2099: return (NULL);
! 2100: case XML_RELAXNG_ERR_MEMORY:
! 2101: return (xmlCharStrdup("out of memory\n"));
! 2102: case XML_RELAXNG_ERR_TYPE:
! 2103: snprintf(msg, 1000, "failed to validate type %s\n", arg1);
! 2104: break;
! 2105: case XML_RELAXNG_ERR_TYPEVAL:
! 2106: snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
! 2107: arg2);
! 2108: break;
! 2109: case XML_RELAXNG_ERR_DUPID:
! 2110: snprintf(msg, 1000, "ID %s redefined\n", arg1);
! 2111: break;
! 2112: case XML_RELAXNG_ERR_TYPECMP:
! 2113: snprintf(msg, 1000, "failed to compare type %s\n", arg1);
! 2114: break;
! 2115: case XML_RELAXNG_ERR_NOSTATE:
! 2116: return (xmlCharStrdup("Internal error: no state\n"));
! 2117: case XML_RELAXNG_ERR_NODEFINE:
! 2118: return (xmlCharStrdup("Internal error: no define\n"));
! 2119: case XML_RELAXNG_ERR_INTERNAL:
! 2120: snprintf(msg, 1000, "Internal error: %s\n", arg1);
! 2121: break;
! 2122: case XML_RELAXNG_ERR_LISTEXTRA:
! 2123: snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
! 2124: break;
! 2125: case XML_RELAXNG_ERR_INTERNODATA:
! 2126: return (xmlCharStrdup
! 2127: ("Internal: interleave block has no data\n"));
! 2128: case XML_RELAXNG_ERR_INTERSEQ:
! 2129: return (xmlCharStrdup("Invalid sequence in interleave\n"));
! 2130: case XML_RELAXNG_ERR_INTEREXTRA:
! 2131: snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
! 2132: break;
! 2133: case XML_RELAXNG_ERR_ELEMNAME:
! 2134: snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
! 2135: arg2);
! 2136: break;
! 2137: case XML_RELAXNG_ERR_ELEMNONS:
! 2138: snprintf(msg, 1000, "Expecting a namespace for element %s\n",
! 2139: arg1);
! 2140: break;
! 2141: case XML_RELAXNG_ERR_ELEMWRONGNS:
! 2142: snprintf(msg, 1000,
! 2143: "Element %s has wrong namespace: expecting %s\n", arg1,
! 2144: arg2);
! 2145: break;
! 2146: case XML_RELAXNG_ERR_ELEMWRONG:
! 2147: snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
! 2148: break;
! 2149: case XML_RELAXNG_ERR_TEXTWRONG:
! 2150: snprintf(msg, 1000,
! 2151: "Did not expect text in element %s content\n", arg1);
! 2152: break;
! 2153: case XML_RELAXNG_ERR_ELEMEXTRANS:
! 2154: snprintf(msg, 1000, "Expecting no namespace for element %s\n",
! 2155: arg1);
! 2156: break;
! 2157: case XML_RELAXNG_ERR_ELEMNOTEMPTY:
! 2158: snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
! 2159: break;
! 2160: case XML_RELAXNG_ERR_NOELEM:
! 2161: snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
! 2162: arg1);
! 2163: break;
! 2164: case XML_RELAXNG_ERR_NOTELEM:
! 2165: return (xmlCharStrdup("Expecting an element got text\n"));
! 2166: case XML_RELAXNG_ERR_ATTRVALID:
! 2167: snprintf(msg, 1000, "Element %s failed to validate attributes\n",
! 2168: arg1);
! 2169: break;
! 2170: case XML_RELAXNG_ERR_CONTENTVALID:
! 2171: snprintf(msg, 1000, "Element %s failed to validate content\n",
! 2172: arg1);
! 2173: break;
! 2174: case XML_RELAXNG_ERR_EXTRACONTENT:
! 2175: snprintf(msg, 1000, "Element %s has extra content: %s\n",
! 2176: arg1, arg2);
! 2177: break;
! 2178: case XML_RELAXNG_ERR_INVALIDATTR:
! 2179: snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
! 2180: arg1, arg2);
! 2181: break;
! 2182: case XML_RELAXNG_ERR_LACKDATA:
! 2183: snprintf(msg, 1000, "Datatype element %s contains no data\n",
! 2184: arg1);
! 2185: break;
! 2186: case XML_RELAXNG_ERR_DATAELEM:
! 2187: snprintf(msg, 1000, "Datatype element %s has child elements\n",
! 2188: arg1);
! 2189: break;
! 2190: case XML_RELAXNG_ERR_VALELEM:
! 2191: snprintf(msg, 1000, "Value element %s has child elements\n",
! 2192: arg1);
! 2193: break;
! 2194: case XML_RELAXNG_ERR_LISTELEM:
! 2195: snprintf(msg, 1000, "List element %s has child elements\n",
! 2196: arg1);
! 2197: break;
! 2198: case XML_RELAXNG_ERR_DATATYPE:
! 2199: snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
! 2200: break;
! 2201: case XML_RELAXNG_ERR_VALUE:
! 2202: snprintf(msg, 1000, "Error validating value %s\n", arg1);
! 2203: break;
! 2204: case XML_RELAXNG_ERR_LIST:
! 2205: return (xmlCharStrdup("Error validating list\n"));
! 2206: case XML_RELAXNG_ERR_NOGRAMMAR:
! 2207: return (xmlCharStrdup("No top grammar defined\n"));
! 2208: case XML_RELAXNG_ERR_EXTRADATA:
! 2209: return (xmlCharStrdup("Extra data in the document\n"));
! 2210: default:
! 2211: return (xmlCharStrdup("Unknown error !\n"));
! 2212: }
! 2213: if (msg[0] == 0) {
! 2214: snprintf(msg, 1000, "Unknown error code %d\n", err);
! 2215: }
! 2216: msg[1000 - 1] = 0;
! 2217: return (xmlStrdup((xmlChar *) msg));
! 2218: }
! 2219:
! 2220: /**
! 2221: * xmlRelaxNGShowValidError:
! 2222: * @ctxt: the validation context
! 2223: * @err: the error number
! 2224: * @node: the node
! 2225: * @child: the node child generating the problem.
! 2226: * @arg1: the first argument
! 2227: * @arg2: the second argument
! 2228: *
! 2229: * Show a validation error.
! 2230: */
! 2231: static void
! 2232: xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
! 2233: xmlRelaxNGValidErr err, xmlNodePtr node,
! 2234: xmlNodePtr child, const xmlChar * arg1,
! 2235: const xmlChar * arg2)
! 2236: {
! 2237: xmlChar *msg;
! 2238:
! 2239: if (ctxt->flags & FLAGS_NOERROR)
! 2240: return;
! 2241:
! 2242: #ifdef DEBUG_ERROR
! 2243: xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
! 2244: #endif
! 2245: msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
! 2246: if (msg == NULL)
! 2247: return;
! 2248:
! 2249: if (ctxt->errNo == XML_RELAXNG_OK)
! 2250: ctxt->errNo = err;
! 2251: xmlRngVErr(ctxt, (child == NULL ? node : child), err,
! 2252: (const char *) msg, arg1, arg2);
! 2253: xmlFree(msg);
! 2254: }
! 2255:
! 2256: /**
! 2257: * xmlRelaxNGPopErrors:
! 2258: * @ctxt: the validation context
! 2259: * @level: the error level in the stack
! 2260: *
! 2261: * pop and discard all errors until the given level is reached
! 2262: */
! 2263: static void
! 2264: xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
! 2265: {
! 2266: int i;
! 2267: xmlRelaxNGValidErrorPtr err;
! 2268:
! 2269: #ifdef DEBUG_ERROR
! 2270: xmlGenericError(xmlGenericErrorContext,
! 2271: "Pop errors till level %d\n", level);
! 2272: #endif
! 2273: for (i = level; i < ctxt->errNr; i++) {
! 2274: err = &ctxt->errTab[i];
! 2275: if (err->flags & ERROR_IS_DUP) {
! 2276: if (err->arg1 != NULL)
! 2277: xmlFree((xmlChar *) err->arg1);
! 2278: err->arg1 = NULL;
! 2279: if (err->arg2 != NULL)
! 2280: xmlFree((xmlChar *) err->arg2);
! 2281: err->arg2 = NULL;
! 2282: err->flags = 0;
! 2283: }
! 2284: }
! 2285: ctxt->errNr = level;
! 2286: if (ctxt->errNr <= 0)
! 2287: ctxt->err = NULL;
! 2288: }
! 2289:
! 2290: /**
! 2291: * xmlRelaxNGDumpValidError:
! 2292: * @ctxt: the validation context
! 2293: *
! 2294: * Show all validation error over a given index.
! 2295: */
! 2296: static void
! 2297: xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
! 2298: {
! 2299: int i, j, k;
! 2300: xmlRelaxNGValidErrorPtr err, dup;
! 2301:
! 2302: #ifdef DEBUG_ERROR
! 2303: xmlGenericError(xmlGenericErrorContext,
! 2304: "Dumping error stack %d errors\n", ctxt->errNr);
! 2305: #endif
! 2306: for (i = 0, k = 0; i < ctxt->errNr; i++) {
! 2307: err = &ctxt->errTab[i];
! 2308: if (k < MAX_ERROR) {
! 2309: for (j = 0; j < i; j++) {
! 2310: dup = &ctxt->errTab[j];
! 2311: if ((err->err == dup->err) && (err->node == dup->node) &&
! 2312: (xmlStrEqual(err->arg1, dup->arg1)) &&
! 2313: (xmlStrEqual(err->arg2, dup->arg2))) {
! 2314: goto skip;
! 2315: }
! 2316: }
! 2317: xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
! 2318: err->arg1, err->arg2);
! 2319: k++;
! 2320: }
! 2321: skip:
! 2322: if (err->flags & ERROR_IS_DUP) {
! 2323: if (err->arg1 != NULL)
! 2324: xmlFree((xmlChar *) err->arg1);
! 2325: err->arg1 = NULL;
! 2326: if (err->arg2 != NULL)
! 2327: xmlFree((xmlChar *) err->arg2);
! 2328: err->arg2 = NULL;
! 2329: err->flags = 0;
! 2330: }
! 2331: }
! 2332: ctxt->errNr = 0;
! 2333: }
! 2334:
! 2335: /**
! 2336: * xmlRelaxNGAddValidError:
! 2337: * @ctxt: the validation context
! 2338: * @err: the error number
! 2339: * @arg1: the first argument
! 2340: * @arg2: the second argument
! 2341: * @dup: need to dup the args
! 2342: *
! 2343: * Register a validation error, either generating it if it's sure
! 2344: * or stacking it for later handling if unsure.
! 2345: */
! 2346: static void
! 2347: xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
! 2348: xmlRelaxNGValidErr err, const xmlChar * arg1,
! 2349: const xmlChar * arg2, int dup)
! 2350: {
! 2351: if (ctxt == NULL)
! 2352: return;
! 2353: if (ctxt->flags & FLAGS_NOERROR)
! 2354: return;
! 2355:
! 2356: #ifdef DEBUG_ERROR
! 2357: xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
! 2358: #endif
! 2359: /*
! 2360: * generate the error directly
! 2361: */
! 2362: if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
! 2363: (ctxt->flags & FLAGS_NEGATIVE)) {
! 2364: xmlNodePtr node, seq;
! 2365:
! 2366: /*
! 2367: * Flush first any stacked error which might be the
! 2368: * real cause of the problem.
! 2369: */
! 2370: if (ctxt->errNr != 0)
! 2371: xmlRelaxNGDumpValidError(ctxt);
! 2372: if (ctxt->state != NULL) {
! 2373: node = ctxt->state->node;
! 2374: seq = ctxt->state->seq;
! 2375: } else {
! 2376: node = seq = NULL;
! 2377: }
! 2378: if ((node == NULL) && (seq == NULL)) {
! 2379: node = ctxt->pnode;
! 2380: }
! 2381: xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
! 2382: }
! 2383: /*
! 2384: * Stack the error for later processing if needed
! 2385: */
! 2386: else {
! 2387: xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
! 2388: }
! 2389: }
! 2390:
! 2391:
! 2392: /************************************************************************
! 2393: * *
! 2394: * Type library hooks *
! 2395: * *
! 2396: ************************************************************************/
! 2397: static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
! 2398: const xmlChar * str);
! 2399:
! 2400: /**
! 2401: * xmlRelaxNGSchemaTypeHave:
! 2402: * @data: data needed for the library
! 2403: * @type: the type name
! 2404: *
! 2405: * Check if the given type is provided by
! 2406: * the W3C XMLSchema Datatype library.
! 2407: *
! 2408: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2409: */
! 2410: static int
! 2411: xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
! 2412: {
! 2413: xmlSchemaTypePtr typ;
! 2414:
! 2415: if (type == NULL)
! 2416: return (-1);
! 2417: typ = xmlSchemaGetPredefinedType(type,
! 2418: BAD_CAST
! 2419: "http://www.w3.org/2001/XMLSchema");
! 2420: if (typ == NULL)
! 2421: return (0);
! 2422: return (1);
! 2423: }
! 2424:
! 2425: /**
! 2426: * xmlRelaxNGSchemaTypeCheck:
! 2427: * @data: data needed for the library
! 2428: * @type: the type name
! 2429: * @value: the value to check
! 2430: * @node: the node
! 2431: *
! 2432: * Check if the given type and value are validated by
! 2433: * the W3C XMLSchema Datatype library.
! 2434: *
! 2435: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2436: */
! 2437: static int
! 2438: xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
! 2439: const xmlChar * type,
! 2440: const xmlChar * value,
! 2441: void **result, xmlNodePtr node)
! 2442: {
! 2443: xmlSchemaTypePtr typ;
! 2444: int ret;
! 2445:
! 2446: if ((type == NULL) || (value == NULL))
! 2447: return (-1);
! 2448: typ = xmlSchemaGetPredefinedType(type,
! 2449: BAD_CAST
! 2450: "http://www.w3.org/2001/XMLSchema");
! 2451: if (typ == NULL)
! 2452: return (-1);
! 2453: ret = xmlSchemaValPredefTypeNode(typ, value,
! 2454: (xmlSchemaValPtr *) result, node);
! 2455: if (ret == 2) /* special ID error code */
! 2456: return (2);
! 2457: if (ret == 0)
! 2458: return (1);
! 2459: if (ret > 0)
! 2460: return (0);
! 2461: return (-1);
! 2462: }
! 2463:
! 2464: /**
! 2465: * xmlRelaxNGSchemaFacetCheck:
! 2466: * @data: data needed for the library
! 2467: * @type: the type name
! 2468: * @facet: the facet name
! 2469: * @val: the facet value
! 2470: * @strval: the string value
! 2471: * @value: the value to check
! 2472: *
! 2473: * Function provided by a type library to check a value facet
! 2474: *
! 2475: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2476: */
! 2477: static int
! 2478: xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
! 2479: const xmlChar * type, const xmlChar * facetname,
! 2480: const xmlChar * val, const xmlChar * strval,
! 2481: void *value)
! 2482: {
! 2483: xmlSchemaFacetPtr facet;
! 2484: xmlSchemaTypePtr typ;
! 2485: int ret;
! 2486:
! 2487: if ((type == NULL) || (strval == NULL))
! 2488: return (-1);
! 2489: typ = xmlSchemaGetPredefinedType(type,
! 2490: BAD_CAST
! 2491: "http://www.w3.org/2001/XMLSchema");
! 2492: if (typ == NULL)
! 2493: return (-1);
! 2494:
! 2495: facet = xmlSchemaNewFacet();
! 2496: if (facet == NULL)
! 2497: return (-1);
! 2498:
! 2499: if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
! 2500: facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
! 2501: } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
! 2502: facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
! 2503: } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
! 2504: facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
! 2505: } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
! 2506: facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
! 2507: } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
! 2508: facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
! 2509: } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
! 2510: facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
! 2511: } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
! 2512: facet->type = XML_SCHEMA_FACET_PATTERN;
! 2513: } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
! 2514: facet->type = XML_SCHEMA_FACET_ENUMERATION;
! 2515: } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
! 2516: facet->type = XML_SCHEMA_FACET_WHITESPACE;
! 2517: } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
! 2518: facet->type = XML_SCHEMA_FACET_LENGTH;
! 2519: } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
! 2520: facet->type = XML_SCHEMA_FACET_MAXLENGTH;
! 2521: } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
! 2522: facet->type = XML_SCHEMA_FACET_MINLENGTH;
! 2523: } else {
! 2524: xmlSchemaFreeFacet(facet);
! 2525: return (-1);
! 2526: }
! 2527: facet->value = val;
! 2528: ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
! 2529: if (ret != 0) {
! 2530: xmlSchemaFreeFacet(facet);
! 2531: return (-1);
! 2532: }
! 2533: ret = xmlSchemaValidateFacet(typ, facet, strval, value);
! 2534: xmlSchemaFreeFacet(facet);
! 2535: if (ret != 0)
! 2536: return (-1);
! 2537: return (0);
! 2538: }
! 2539:
! 2540: /**
! 2541: * xmlRelaxNGSchemaFreeValue:
! 2542: * @data: data needed for the library
! 2543: * @value: the value to free
! 2544: *
! 2545: * Function provided by a type library to free a Schemas value
! 2546: *
! 2547: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2548: */
! 2549: static void
! 2550: xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
! 2551: {
! 2552: xmlSchemaFreeValue(value);
! 2553: }
! 2554:
! 2555: /**
! 2556: * xmlRelaxNGSchemaTypeCompare:
! 2557: * @data: data needed for the library
! 2558: * @type: the type name
! 2559: * @value1: the first value
! 2560: * @value2: the second value
! 2561: *
! 2562: * Compare two values for equality accordingly a type from the W3C XMLSchema
! 2563: * Datatype library.
! 2564: *
! 2565: * Returns 1 if equal, 0 if no and -1 in case of error.
! 2566: */
! 2567: static int
! 2568: xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
! 2569: const xmlChar * type,
! 2570: const xmlChar * value1,
! 2571: xmlNodePtr ctxt1,
! 2572: void *comp1,
! 2573: const xmlChar * value2, xmlNodePtr ctxt2)
! 2574: {
! 2575: int ret;
! 2576: xmlSchemaTypePtr typ;
! 2577: xmlSchemaValPtr res1 = NULL, res2 = NULL;
! 2578:
! 2579: if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
! 2580: return (-1);
! 2581: typ = xmlSchemaGetPredefinedType(type,
! 2582: BAD_CAST
! 2583: "http://www.w3.org/2001/XMLSchema");
! 2584: if (typ == NULL)
! 2585: return (-1);
! 2586: if (comp1 == NULL) {
! 2587: ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
! 2588: if (ret != 0)
! 2589: return (-1);
! 2590: if (res1 == NULL)
! 2591: return (-1);
! 2592: } else {
! 2593: res1 = (xmlSchemaValPtr) comp1;
! 2594: }
! 2595: ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
! 2596: if (ret != 0) {
! 2597: if ((comp1 == NULL) && (res1 != NULL))
! 2598: xmlSchemaFreeValue(res1);
! 2599: return (-1);
! 2600: }
! 2601: if (res1 == NULL) {
! 2602: return (-1);
! 2603: }
! 2604: ret = xmlSchemaCompareValues(res1, res2);
! 2605: if (res1 != (xmlSchemaValPtr) comp1)
! 2606: xmlSchemaFreeValue(res1);
! 2607: xmlSchemaFreeValue(res2);
! 2608: if (ret == -2)
! 2609: return (-1);
! 2610: if (ret == 0)
! 2611: return (1);
! 2612: return (0);
! 2613: }
! 2614:
! 2615: /**
! 2616: * xmlRelaxNGDefaultTypeHave:
! 2617: * @data: data needed for the library
! 2618: * @type: the type name
! 2619: *
! 2620: * Check if the given type is provided by
! 2621: * the default datatype library.
! 2622: *
! 2623: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2624: */
! 2625: static int
! 2626: xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
! 2627: const xmlChar * type)
! 2628: {
! 2629: if (type == NULL)
! 2630: return (-1);
! 2631: if (xmlStrEqual(type, BAD_CAST "string"))
! 2632: return (1);
! 2633: if (xmlStrEqual(type, BAD_CAST "token"))
! 2634: return (1);
! 2635: return (0);
! 2636: }
! 2637:
! 2638: /**
! 2639: * xmlRelaxNGDefaultTypeCheck:
! 2640: * @data: data needed for the library
! 2641: * @type: the type name
! 2642: * @value: the value to check
! 2643: * @node: the node
! 2644: *
! 2645: * Check if the given type and value are validated by
! 2646: * the default datatype library.
! 2647: *
! 2648: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2649: */
! 2650: static int
! 2651: xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
! 2652: const xmlChar * type ATTRIBUTE_UNUSED,
! 2653: const xmlChar * value ATTRIBUTE_UNUSED,
! 2654: void **result ATTRIBUTE_UNUSED,
! 2655: xmlNodePtr node ATTRIBUTE_UNUSED)
! 2656: {
! 2657: if (value == NULL)
! 2658: return (-1);
! 2659: if (xmlStrEqual(type, BAD_CAST "string"))
! 2660: return (1);
! 2661: if (xmlStrEqual(type, BAD_CAST "token")) {
! 2662: return (1);
! 2663: }
! 2664:
! 2665: return (0);
! 2666: }
! 2667:
! 2668: /**
! 2669: * xmlRelaxNGDefaultTypeCompare:
! 2670: * @data: data needed for the library
! 2671: * @type: the type name
! 2672: * @value1: the first value
! 2673: * @value2: the second value
! 2674: *
! 2675: * Compare two values accordingly a type from the default
! 2676: * datatype library.
! 2677: *
! 2678: * Returns 1 if yes, 0 if no and -1 in case of error.
! 2679: */
! 2680: static int
! 2681: xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
! 2682: const xmlChar * type,
! 2683: const xmlChar * value1,
! 2684: xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
! 2685: void *comp1 ATTRIBUTE_UNUSED,
! 2686: const xmlChar * value2,
! 2687: xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
! 2688: {
! 2689: int ret = -1;
! 2690:
! 2691: if (xmlStrEqual(type, BAD_CAST "string")) {
! 2692: ret = xmlStrEqual(value1, value2);
! 2693: } else if (xmlStrEqual(type, BAD_CAST "token")) {
! 2694: if (!xmlStrEqual(value1, value2)) {
! 2695: xmlChar *nval, *nvalue;
! 2696:
! 2697: /*
! 2698: * TODO: trivial optimizations are possible by
! 2699: * computing at compile-time
! 2700: */
! 2701: nval = xmlRelaxNGNormalize(NULL, value1);
! 2702: nvalue = xmlRelaxNGNormalize(NULL, value2);
! 2703:
! 2704: if ((nval == NULL) || (nvalue == NULL))
! 2705: ret = -1;
! 2706: else if (xmlStrEqual(nval, nvalue))
! 2707: ret = 1;
! 2708: else
! 2709: ret = 0;
! 2710: if (nval != NULL)
! 2711: xmlFree(nval);
! 2712: if (nvalue != NULL)
! 2713: xmlFree(nvalue);
! 2714: } else
! 2715: ret = 1;
! 2716: }
! 2717: return (ret);
! 2718: }
! 2719:
! 2720: static int xmlRelaxNGTypeInitialized = 0;
! 2721: static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
! 2722:
! 2723: /**
! 2724: * xmlRelaxNGFreeTypeLibrary:
! 2725: * @lib: the type library structure
! 2726: * @namespace: the URI bound to the library
! 2727: *
! 2728: * Free the structure associated to the type library
! 2729: */
! 2730: static void
! 2731: xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
! 2732: const xmlChar * namespace ATTRIBUTE_UNUSED)
! 2733: {
! 2734: if (lib == NULL)
! 2735: return;
! 2736: if (lib->namespace != NULL)
! 2737: xmlFree((xmlChar *) lib->namespace);
! 2738: xmlFree(lib);
! 2739: }
! 2740:
! 2741: /**
! 2742: * xmlRelaxNGRegisterTypeLibrary:
! 2743: * @namespace: the URI bound to the library
! 2744: * @data: data associated to the library
! 2745: * @have: the provide function
! 2746: * @check: the checking function
! 2747: * @comp: the comparison function
! 2748: *
! 2749: * Register a new type library
! 2750: *
! 2751: * Returns 0 in case of success and -1 in case of error.
! 2752: */
! 2753: static int
! 2754: xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
! 2755: xmlRelaxNGTypeHave have,
! 2756: xmlRelaxNGTypeCheck check,
! 2757: xmlRelaxNGTypeCompare comp,
! 2758: xmlRelaxNGFacetCheck facet,
! 2759: xmlRelaxNGTypeFree freef)
! 2760: {
! 2761: xmlRelaxNGTypeLibraryPtr lib;
! 2762: int ret;
! 2763:
! 2764: if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
! 2765: (check == NULL) || (comp == NULL))
! 2766: return (-1);
! 2767: if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
! 2768: xmlGenericError(xmlGenericErrorContext,
! 2769: "Relax-NG types library '%s' already registered\n",
! 2770: namespace);
! 2771: return (-1);
! 2772: }
! 2773: lib =
! 2774: (xmlRelaxNGTypeLibraryPtr)
! 2775: xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
! 2776: if (lib == NULL) {
! 2777: xmlRngVErrMemory(NULL, "adding types library\n");
! 2778: return (-1);
! 2779: }
! 2780: memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
! 2781: lib->namespace = xmlStrdup(namespace);
! 2782: lib->data = data;
! 2783: lib->have = have;
! 2784: lib->comp = comp;
! 2785: lib->check = check;
! 2786: lib->facet = facet;
! 2787: lib->freef = freef;
! 2788: ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
! 2789: if (ret < 0) {
! 2790: xmlGenericError(xmlGenericErrorContext,
! 2791: "Relax-NG types library failed to register '%s'\n",
! 2792: namespace);
! 2793: xmlRelaxNGFreeTypeLibrary(lib, namespace);
! 2794: return (-1);
! 2795: }
! 2796: return (0);
! 2797: }
! 2798:
! 2799: /**
! 2800: * xmlRelaxNGInitTypes:
! 2801: *
! 2802: * Initilize the default type libraries.
! 2803: *
! 2804: * Returns 0 in case of success and -1 in case of error.
! 2805: */
! 2806: int
! 2807: xmlRelaxNGInitTypes(void)
! 2808: {
! 2809: if (xmlRelaxNGTypeInitialized != 0)
! 2810: return (0);
! 2811: xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
! 2812: if (xmlRelaxNGRegisteredTypes == NULL) {
! 2813: xmlGenericError(xmlGenericErrorContext,
! 2814: "Failed to allocate sh table for Relax-NG types\n");
! 2815: return (-1);
! 2816: }
! 2817: xmlRelaxNGRegisterTypeLibrary(BAD_CAST
! 2818: "http://www.w3.org/2001/XMLSchema-datatypes",
! 2819: NULL, xmlRelaxNGSchemaTypeHave,
! 2820: xmlRelaxNGSchemaTypeCheck,
! 2821: xmlRelaxNGSchemaTypeCompare,
! 2822: xmlRelaxNGSchemaFacetCheck,
! 2823: xmlRelaxNGSchemaFreeValue);
! 2824: xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
! 2825: xmlRelaxNGDefaultTypeHave,
! 2826: xmlRelaxNGDefaultTypeCheck,
! 2827: xmlRelaxNGDefaultTypeCompare, NULL,
! 2828: NULL);
! 2829: xmlRelaxNGTypeInitialized = 1;
! 2830: return (0);
! 2831: }
! 2832:
! 2833: /**
! 2834: * xmlRelaxNGCleanupTypes:
! 2835: *
! 2836: * Cleanup the default Schemas type library associated to RelaxNG
! 2837: */
! 2838: void
! 2839: xmlRelaxNGCleanupTypes(void)
! 2840: {
! 2841: xmlSchemaCleanupTypes();
! 2842: if (xmlRelaxNGTypeInitialized == 0)
! 2843: return;
! 2844: xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
! 2845: xmlRelaxNGFreeTypeLibrary);
! 2846: xmlRelaxNGTypeInitialized = 0;
! 2847: }
! 2848:
! 2849: /************************************************************************
! 2850: * *
! 2851: * Compiling element content into regexp *
! 2852: * *
! 2853: * Sometime the element content can be compiled into a pure regexp, *
! 2854: * This allows a faster execution and streamability at that level *
! 2855: * *
! 2856: ************************************************************************/
! 2857:
! 2858: /* from automata.c but not exported */
! 2859: void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
! 2860:
! 2861:
! 2862: static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
! 2863: xmlRelaxNGDefinePtr def);
! 2864:
! 2865: /**
! 2866: * xmlRelaxNGIsCompileable:
! 2867: * @define: the definition to check
! 2868: *
! 2869: * Check if a definition is nullable.
! 2870: *
! 2871: * Returns 1 if yes, 0 if no and -1 in case of error
! 2872: */
! 2873: static int
! 2874: xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
! 2875: {
! 2876: int ret = -1;
! 2877:
! 2878: if (def == NULL) {
! 2879: return (-1);
! 2880: }
! 2881: if ((def->type != XML_RELAXNG_ELEMENT) &&
! 2882: (def->dflags & IS_COMPILABLE))
! 2883: return (1);
! 2884: if ((def->type != XML_RELAXNG_ELEMENT) &&
! 2885: (def->dflags & IS_NOT_COMPILABLE))
! 2886: return (0);
! 2887: switch (def->type) {
! 2888: case XML_RELAXNG_NOOP:
! 2889: ret = xmlRelaxNGIsCompileable(def->content);
! 2890: break;
! 2891: case XML_RELAXNG_TEXT:
! 2892: case XML_RELAXNG_EMPTY:
! 2893: ret = 1;
! 2894: break;
! 2895: case XML_RELAXNG_ELEMENT:
! 2896: /*
! 2897: * Check if the element content is compileable
! 2898: */
! 2899: if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
! 2900: ((def->dflags & IS_COMPILABLE) == 0)) {
! 2901: xmlRelaxNGDefinePtr list;
! 2902:
! 2903: list = def->content;
! 2904: while (list != NULL) {
! 2905: ret = xmlRelaxNGIsCompileable(list);
! 2906: if (ret != 1)
! 2907: break;
! 2908: list = list->next;
! 2909: }
! 2910: /*
! 2911: * Because the routine is recursive, we must guard against
! 2912: * discovering both COMPILABLE and NOT_COMPILABLE
! 2913: */
! 2914: if (ret == 0) {
! 2915: def->dflags &= ~IS_COMPILABLE;
! 2916: def->dflags |= IS_NOT_COMPILABLE;
! 2917: }
! 2918: if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
! 2919: def->dflags |= IS_COMPILABLE;
! 2920: #ifdef DEBUG_COMPILE
! 2921: if (ret == 1) {
! 2922: xmlGenericError(xmlGenericErrorContext,
! 2923: "element content for %s is compilable\n",
! 2924: def->name);
! 2925: } else if (ret == 0) {
! 2926: xmlGenericError(xmlGenericErrorContext,
! 2927: "element content for %s is not compilable\n",
! 2928: def->name);
! 2929: } else {
! 2930: xmlGenericError(xmlGenericErrorContext,
! 2931: "Problem in RelaxNGIsCompileable for element %s\n",
! 2932: def->name);
! 2933: }
! 2934: #endif
! 2935: }
! 2936: /*
! 2937: * All elements return a compileable status unless they
! 2938: * are generic like anyName
! 2939: */
! 2940: if ((def->nameClass != NULL) || (def->name == NULL))
! 2941: ret = 0;
! 2942: else
! 2943: ret = 1;
! 2944: return (ret);
! 2945: case XML_RELAXNG_REF:
! 2946: case XML_RELAXNG_EXTERNALREF:
! 2947: case XML_RELAXNG_PARENTREF:
! 2948: if (def->depth == -20) {
! 2949: return (1);
! 2950: } else {
! 2951: xmlRelaxNGDefinePtr list;
! 2952:
! 2953: def->depth = -20;
! 2954: list = def->content;
! 2955: while (list != NULL) {
! 2956: ret = xmlRelaxNGIsCompileable(list);
! 2957: if (ret != 1)
! 2958: break;
! 2959: list = list->next;
! 2960: }
! 2961: }
! 2962: break;
! 2963: case XML_RELAXNG_START:
! 2964: case XML_RELAXNG_OPTIONAL:
! 2965: case XML_RELAXNG_ZEROORMORE:
! 2966: case XML_RELAXNG_ONEORMORE:
! 2967: case XML_RELAXNG_CHOICE:
! 2968: case XML_RELAXNG_GROUP:
! 2969: case XML_RELAXNG_DEF:{
! 2970: xmlRelaxNGDefinePtr list;
! 2971:
! 2972: list = def->content;
! 2973: while (list != NULL) {
! 2974: ret = xmlRelaxNGIsCompileable(list);
! 2975: if (ret != 1)
! 2976: break;
! 2977: list = list->next;
! 2978: }
! 2979: break;
! 2980: }
! 2981: case XML_RELAXNG_EXCEPT:
! 2982: case XML_RELAXNG_ATTRIBUTE:
! 2983: case XML_RELAXNG_INTERLEAVE:
! 2984: case XML_RELAXNG_DATATYPE:
! 2985: case XML_RELAXNG_LIST:
! 2986: case XML_RELAXNG_PARAM:
! 2987: case XML_RELAXNG_VALUE:
! 2988: case XML_RELAXNG_NOT_ALLOWED:
! 2989: ret = 0;
! 2990: break;
! 2991: }
! 2992: if (ret == 0)
! 2993: def->dflags |= IS_NOT_COMPILABLE;
! 2994: if (ret == 1)
! 2995: def->dflags |= IS_COMPILABLE;
! 2996: #ifdef DEBUG_COMPILE
! 2997: if (ret == 1) {
! 2998: xmlGenericError(xmlGenericErrorContext,
! 2999: "RelaxNGIsCompileable %s : true\n",
! 3000: xmlRelaxNGDefName(def));
! 3001: } else if (ret == 0) {
! 3002: xmlGenericError(xmlGenericErrorContext,
! 3003: "RelaxNGIsCompileable %s : false\n",
! 3004: xmlRelaxNGDefName(def));
! 3005: } else {
! 3006: xmlGenericError(xmlGenericErrorContext,
! 3007: "Problem in RelaxNGIsCompileable %s\n",
! 3008: xmlRelaxNGDefName(def));
! 3009: }
! 3010: #endif
! 3011: return (ret);
! 3012: }
! 3013:
! 3014: /**
! 3015: * xmlRelaxNGCompile:
! 3016: * ctxt: the RelaxNG parser context
! 3017: * @define: the definition tree to compile
! 3018: *
! 3019: * Compile the set of definitions, it works recursively, till the
! 3020: * element boundaries, where it tries to compile the content if possible
! 3021: *
! 3022: * Returns 0 if success and -1 in case of error
! 3023: */
! 3024: static int
! 3025: xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
! 3026: {
! 3027: int ret = 0;
! 3028: xmlRelaxNGDefinePtr list;
! 3029:
! 3030: if ((ctxt == NULL) || (def == NULL))
! 3031: return (-1);
! 3032:
! 3033: switch (def->type) {
! 3034: case XML_RELAXNG_START:
! 3035: if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
! 3036: xmlAutomataPtr oldam = ctxt->am;
! 3037: xmlAutomataStatePtr oldstate = ctxt->state;
! 3038:
! 3039: def->depth = -25;
! 3040:
! 3041: list = def->content;
! 3042: ctxt->am = xmlNewAutomata();
! 3043: if (ctxt->am == NULL)
! 3044: return (-1);
! 3045:
! 3046: /*
! 3047: * assume identical strings but not same pointer are different
! 3048: * atoms, needed for non-determinism detection
! 3049: * That way if 2 elements with the same name are in a choice
! 3050: * branch the automata is found non-deterministic and
! 3051: * we fallback to the normal validation which does the right
! 3052: * thing of exploring both choices.
! 3053: */
! 3054: xmlAutomataSetFlags(ctxt->am, 1);
! 3055:
! 3056: ctxt->state = xmlAutomataGetInitState(ctxt->am);
! 3057: while (list != NULL) {
! 3058: xmlRelaxNGCompile(ctxt, list);
! 3059: list = list->next;
! 3060: }
! 3061: xmlAutomataSetFinalState(ctxt->am, ctxt->state);
! 3062: def->contModel = xmlAutomataCompile(ctxt->am);
! 3063: xmlRegexpIsDeterminist(def->contModel);
! 3064:
! 3065: xmlFreeAutomata(ctxt->am);
! 3066: ctxt->state = oldstate;
! 3067: ctxt->am = oldam;
! 3068: }
! 3069: break;
! 3070: case XML_RELAXNG_ELEMENT:
! 3071: if ((ctxt->am != NULL) && (def->name != NULL)) {
! 3072: ctxt->state = xmlAutomataNewTransition2(ctxt->am,
! 3073: ctxt->state, NULL,
! 3074: def->name, def->ns,
! 3075: def);
! 3076: }
! 3077: if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
! 3078: xmlAutomataPtr oldam = ctxt->am;
! 3079: xmlAutomataStatePtr oldstate = ctxt->state;
! 3080:
! 3081: def->depth = -25;
! 3082:
! 3083: list = def->content;
! 3084: ctxt->am = xmlNewAutomata();
! 3085: if (ctxt->am == NULL)
! 3086: return (-1);
! 3087: xmlAutomataSetFlags(ctxt->am, 1);
! 3088: ctxt->state = xmlAutomataGetInitState(ctxt->am);
! 3089: while (list != NULL) {
! 3090: xmlRelaxNGCompile(ctxt, list);
! 3091: list = list->next;
! 3092: }
! 3093: xmlAutomataSetFinalState(ctxt->am, ctxt->state);
! 3094: def->contModel = xmlAutomataCompile(ctxt->am);
! 3095: if (!xmlRegexpIsDeterminist(def->contModel)) {
! 3096: #ifdef DEBUG_COMPILE
! 3097: xmlGenericError(xmlGenericErrorContext,
! 3098: "Content model not determinist %s\n",
! 3099: def->name);
! 3100: #endif
! 3101: /*
! 3102: * we can only use the automata if it is determinist
! 3103: */
! 3104: xmlRegFreeRegexp(def->contModel);
! 3105: def->contModel = NULL;
! 3106: }
! 3107: xmlFreeAutomata(ctxt->am);
! 3108: ctxt->state = oldstate;
! 3109: ctxt->am = oldam;
! 3110: } else {
! 3111: xmlAutomataPtr oldam = ctxt->am;
! 3112:
! 3113: /*
! 3114: * we can't build the content model for this element content
! 3115: * but it still might be possible to build it for some of its
! 3116: * children, recurse.
! 3117: */
! 3118: ret = xmlRelaxNGTryCompile(ctxt, def);
! 3119: ctxt->am = oldam;
! 3120: }
! 3121: break;
! 3122: case XML_RELAXNG_NOOP:
! 3123: ret = xmlRelaxNGCompile(ctxt, def->content);
! 3124: break;
! 3125: case XML_RELAXNG_OPTIONAL:{
! 3126: xmlAutomataStatePtr oldstate = ctxt->state;
! 3127:
! 3128: list = def->content;
! 3129: while (list != NULL) {
! 3130: xmlRelaxNGCompile(ctxt, list);
! 3131: list = list->next;
! 3132: }
! 3133: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 3134: break;
! 3135: }
! 3136: case XML_RELAXNG_ZEROORMORE:{
! 3137: xmlAutomataStatePtr oldstate;
! 3138:
! 3139: ctxt->state =
! 3140: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
! 3141: oldstate = ctxt->state;
! 3142: list = def->content;
! 3143: while (list != NULL) {
! 3144: xmlRelaxNGCompile(ctxt, list);
! 3145: list = list->next;
! 3146: }
! 3147: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
! 3148: ctxt->state =
! 3149: xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
! 3150: break;
! 3151: }
! 3152: case XML_RELAXNG_ONEORMORE:{
! 3153: xmlAutomataStatePtr oldstate;
! 3154:
! 3155: list = def->content;
! 3156: while (list != NULL) {
! 3157: xmlRelaxNGCompile(ctxt, list);
! 3158: list = list->next;
! 3159: }
! 3160: oldstate = ctxt->state;
! 3161: list = def->content;
! 3162: while (list != NULL) {
! 3163: xmlRelaxNGCompile(ctxt, list);
! 3164: list = list->next;
! 3165: }
! 3166: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
! 3167: ctxt->state =
! 3168: xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
! 3169: break;
! 3170: }
! 3171: case XML_RELAXNG_CHOICE:{
! 3172: xmlAutomataStatePtr target = NULL;
! 3173: xmlAutomataStatePtr oldstate = ctxt->state;
! 3174:
! 3175: list = def->content;
! 3176: while (list != NULL) {
! 3177: ctxt->state = oldstate;
! 3178: ret = xmlRelaxNGCompile(ctxt, list);
! 3179: if (ret != 0)
! 3180: break;
! 3181: if (target == NULL)
! 3182: target = ctxt->state;
! 3183: else {
! 3184: xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
! 3185: target);
! 3186: }
! 3187: list = list->next;
! 3188: }
! 3189: ctxt->state = target;
! 3190:
! 3191: break;
! 3192: }
! 3193: case XML_RELAXNG_REF:
! 3194: case XML_RELAXNG_EXTERNALREF:
! 3195: case XML_RELAXNG_PARENTREF:
! 3196: case XML_RELAXNG_GROUP:
! 3197: case XML_RELAXNG_DEF:
! 3198: list = def->content;
! 3199: while (list != NULL) {
! 3200: ret = xmlRelaxNGCompile(ctxt, list);
! 3201: if (ret != 0)
! 3202: break;
! 3203: list = list->next;
! 3204: }
! 3205: break;
! 3206: case XML_RELAXNG_TEXT:{
! 3207: xmlAutomataStatePtr oldstate;
! 3208:
! 3209: ctxt->state =
! 3210: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
! 3211: oldstate = ctxt->state;
! 3212: xmlRelaxNGCompile(ctxt, def->content);
! 3213: xmlAutomataNewTransition(ctxt->am, ctxt->state,
! 3214: ctxt->state, BAD_CAST "#text",
! 3215: NULL);
! 3216: ctxt->state =
! 3217: xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
! 3218: break;
! 3219: }
! 3220: case XML_RELAXNG_EMPTY:
! 3221: ctxt->state =
! 3222: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
! 3223: break;
! 3224: case XML_RELAXNG_EXCEPT:
! 3225: case XML_RELAXNG_ATTRIBUTE:
! 3226: case XML_RELAXNG_INTERLEAVE:
! 3227: case XML_RELAXNG_NOT_ALLOWED:
! 3228: case XML_RELAXNG_DATATYPE:
! 3229: case XML_RELAXNG_LIST:
! 3230: case XML_RELAXNG_PARAM:
! 3231: case XML_RELAXNG_VALUE:
! 3232: /* This should not happen and generate an internal error */
! 3233: fprintf(stderr, "RNG internal error trying to compile %s\n",
! 3234: xmlRelaxNGDefName(def));
! 3235: break;
! 3236: }
! 3237: return (ret);
! 3238: }
! 3239:
! 3240: /**
! 3241: * xmlRelaxNGTryCompile:
! 3242: * ctxt: the RelaxNG parser context
! 3243: * @define: the definition tree to compile
! 3244: *
! 3245: * Try to compile the set of definitions, it works recursively,
! 3246: * possibly ignoring parts which cannot be compiled.
! 3247: *
! 3248: * Returns 0 if success and -1 in case of error
! 3249: */
! 3250: static int
! 3251: xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
! 3252: {
! 3253: int ret = 0;
! 3254: xmlRelaxNGDefinePtr list;
! 3255:
! 3256: if ((ctxt == NULL) || (def == NULL))
! 3257: return (-1);
! 3258:
! 3259: if ((def->type == XML_RELAXNG_START) ||
! 3260: (def->type == XML_RELAXNG_ELEMENT)) {
! 3261: ret = xmlRelaxNGIsCompileable(def);
! 3262: if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
! 3263: ctxt->am = NULL;
! 3264: ret = xmlRelaxNGCompile(ctxt, def);
! 3265: #ifdef DEBUG_PROGRESSIVE
! 3266: if (ret == 0) {
! 3267: if (def->type == XML_RELAXNG_START)
! 3268: xmlGenericError(xmlGenericErrorContext,
! 3269: "compiled the start\n");
! 3270: else
! 3271: xmlGenericError(xmlGenericErrorContext,
! 3272: "compiled element %s\n", def->name);
! 3273: } else {
! 3274: if (def->type == XML_RELAXNG_START)
! 3275: xmlGenericError(xmlGenericErrorContext,
! 3276: "failed to compile the start\n");
! 3277: else
! 3278: xmlGenericError(xmlGenericErrorContext,
! 3279: "failed to compile element %s\n",
! 3280: def->name);
! 3281: }
! 3282: #endif
! 3283: return (ret);
! 3284: }
! 3285: }
! 3286: switch (def->type) {
! 3287: case XML_RELAXNG_NOOP:
! 3288: ret = xmlRelaxNGTryCompile(ctxt, def->content);
! 3289: break;
! 3290: case XML_RELAXNG_TEXT:
! 3291: case XML_RELAXNG_DATATYPE:
! 3292: case XML_RELAXNG_LIST:
! 3293: case XML_RELAXNG_PARAM:
! 3294: case XML_RELAXNG_VALUE:
! 3295: case XML_RELAXNG_EMPTY:
! 3296: case XML_RELAXNG_ELEMENT:
! 3297: ret = 0;
! 3298: break;
! 3299: case XML_RELAXNG_OPTIONAL:
! 3300: case XML_RELAXNG_ZEROORMORE:
! 3301: case XML_RELAXNG_ONEORMORE:
! 3302: case XML_RELAXNG_CHOICE:
! 3303: case XML_RELAXNG_GROUP:
! 3304: case XML_RELAXNG_DEF:
! 3305: case XML_RELAXNG_START:
! 3306: case XML_RELAXNG_REF:
! 3307: case XML_RELAXNG_EXTERNALREF:
! 3308: case XML_RELAXNG_PARENTREF:
! 3309: list = def->content;
! 3310: while (list != NULL) {
! 3311: ret = xmlRelaxNGTryCompile(ctxt, list);
! 3312: if (ret != 0)
! 3313: break;
! 3314: list = list->next;
! 3315: }
! 3316: break;
! 3317: case XML_RELAXNG_EXCEPT:
! 3318: case XML_RELAXNG_ATTRIBUTE:
! 3319: case XML_RELAXNG_INTERLEAVE:
! 3320: case XML_RELAXNG_NOT_ALLOWED:
! 3321: ret = 0;
! 3322: break;
! 3323: }
! 3324: return (ret);
! 3325: }
! 3326:
! 3327: /************************************************************************
! 3328: * *
! 3329: * Parsing functions *
! 3330: * *
! 3331: ************************************************************************/
! 3332:
! 3333: static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
! 3334: ctxt, xmlNodePtr node);
! 3335: static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
! 3336: ctxt, xmlNodePtr node);
! 3337: static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
! 3338: ctxt, xmlNodePtr nodes,
! 3339: int group);
! 3340: static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
! 3341: ctxt, xmlNodePtr node);
! 3342: static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
! 3343: xmlNodePtr node);
! 3344: static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
! 3345: xmlNodePtr nodes);
! 3346: static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
! 3347: ctxt, xmlNodePtr node,
! 3348: xmlRelaxNGDefinePtr
! 3349: def);
! 3350: static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
! 3351: ctxt, xmlNodePtr nodes);
! 3352: static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
! 3353: xmlRelaxNGDefinePtr define,
! 3354: xmlNodePtr elem);
! 3355:
! 3356:
! 3357: #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
! 3358:
! 3359: /**
! 3360: * xmlRelaxNGIsNullable:
! 3361: * @define: the definition to verify
! 3362: *
! 3363: * Check if a definition is nullable.
! 3364: *
! 3365: * Returns 1 if yes, 0 if no and -1 in case of error
! 3366: */
! 3367: static int
! 3368: xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
! 3369: {
! 3370: int ret;
! 3371:
! 3372: if (define == NULL)
! 3373: return (-1);
! 3374:
! 3375: if (define->dflags & IS_NULLABLE)
! 3376: return (1);
! 3377: if (define->dflags & IS_NOT_NULLABLE)
! 3378: return (0);
! 3379: switch (define->type) {
! 3380: case XML_RELAXNG_EMPTY:
! 3381: case XML_RELAXNG_TEXT:
! 3382: ret = 1;
! 3383: break;
! 3384: case XML_RELAXNG_NOOP:
! 3385: case XML_RELAXNG_DEF:
! 3386: case XML_RELAXNG_REF:
! 3387: case XML_RELAXNG_EXTERNALREF:
! 3388: case XML_RELAXNG_PARENTREF:
! 3389: case XML_RELAXNG_ONEORMORE:
! 3390: ret = xmlRelaxNGIsNullable(define->content);
! 3391: break;
! 3392: case XML_RELAXNG_EXCEPT:
! 3393: case XML_RELAXNG_NOT_ALLOWED:
! 3394: case XML_RELAXNG_ELEMENT:
! 3395: case XML_RELAXNG_DATATYPE:
! 3396: case XML_RELAXNG_PARAM:
! 3397: case XML_RELAXNG_VALUE:
! 3398: case XML_RELAXNG_LIST:
! 3399: case XML_RELAXNG_ATTRIBUTE:
! 3400: ret = 0;
! 3401: break;
! 3402: case XML_RELAXNG_CHOICE:{
! 3403: xmlRelaxNGDefinePtr list = define->content;
! 3404:
! 3405: while (list != NULL) {
! 3406: ret = xmlRelaxNGIsNullable(list);
! 3407: if (ret != 0)
! 3408: goto done;
! 3409: list = list->next;
! 3410: }
! 3411: ret = 0;
! 3412: break;
! 3413: }
! 3414: case XML_RELAXNG_START:
! 3415: case XML_RELAXNG_INTERLEAVE:
! 3416: case XML_RELAXNG_GROUP:{
! 3417: xmlRelaxNGDefinePtr list = define->content;
! 3418:
! 3419: while (list != NULL) {
! 3420: ret = xmlRelaxNGIsNullable(list);
! 3421: if (ret != 1)
! 3422: goto done;
! 3423: list = list->next;
! 3424: }
! 3425: return (1);
! 3426: }
! 3427: default:
! 3428: return (-1);
! 3429: }
! 3430: done:
! 3431: if (ret == 0)
! 3432: define->dflags |= IS_NOT_NULLABLE;
! 3433: if (ret == 1)
! 3434: define->dflags |= IS_NULLABLE;
! 3435: return (ret);
! 3436: }
! 3437:
! 3438: /**
! 3439: * xmlRelaxNGIsBlank:
! 3440: * @str: a string
! 3441: *
! 3442: * Check if a string is ignorable c.f. 4.2. Whitespace
! 3443: *
! 3444: * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
! 3445: */
! 3446: static int
! 3447: xmlRelaxNGIsBlank(xmlChar * str)
! 3448: {
! 3449: if (str == NULL)
! 3450: return (1);
! 3451: while (*str != 0) {
! 3452: if (!(IS_BLANK_CH(*str)))
! 3453: return (0);
! 3454: str++;
! 3455: }
! 3456: return (1);
! 3457: }
! 3458:
! 3459: /**
! 3460: * xmlRelaxNGGetDataTypeLibrary:
! 3461: * @ctxt: a Relax-NG parser context
! 3462: * @node: the current data or value element
! 3463: *
! 3464: * Applies algorithm from 4.3. datatypeLibrary attribute
! 3465: *
! 3466: * Returns the datatypeLibary value or NULL if not found
! 3467: */
! 3468: static xmlChar *
! 3469: xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
! 3470: xmlNodePtr node)
! 3471: {
! 3472: xmlChar *ret, *escape;
! 3473:
! 3474: if (node == NULL)
! 3475: return(NULL);
! 3476:
! 3477: if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
! 3478: ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
! 3479: if (ret != NULL) {
! 3480: if (ret[0] == 0) {
! 3481: xmlFree(ret);
! 3482: return (NULL);
! 3483: }
! 3484: escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
! 3485: if (escape == NULL) {
! 3486: return (ret);
! 3487: }
! 3488: xmlFree(ret);
! 3489: return (escape);
! 3490: }
! 3491: }
! 3492: node = node->parent;
! 3493: while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
! 3494: ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
! 3495: if (ret != NULL) {
! 3496: if (ret[0] == 0) {
! 3497: xmlFree(ret);
! 3498: return (NULL);
! 3499: }
! 3500: escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
! 3501: if (escape == NULL) {
! 3502: return (ret);
! 3503: }
! 3504: xmlFree(ret);
! 3505: return (escape);
! 3506: }
! 3507: node = node->parent;
! 3508: }
! 3509: return (NULL);
! 3510: }
! 3511:
! 3512: /**
! 3513: * xmlRelaxNGParseValue:
! 3514: * @ctxt: a Relax-NG parser context
! 3515: * @node: the data node.
! 3516: *
! 3517: * parse the content of a RelaxNG value node.
! 3518: *
! 3519: * Returns the definition pointer or NULL in case of error
! 3520: */
! 3521: static xmlRelaxNGDefinePtr
! 3522: xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 3523: {
! 3524: xmlRelaxNGDefinePtr def = NULL;
! 3525: xmlRelaxNGTypeLibraryPtr lib = NULL;
! 3526: xmlChar *type;
! 3527: xmlChar *library;
! 3528: int success = 0;
! 3529:
! 3530: def = xmlRelaxNGNewDefine(ctxt, node);
! 3531: if (def == NULL)
! 3532: return (NULL);
! 3533: def->type = XML_RELAXNG_VALUE;
! 3534:
! 3535: type = xmlGetProp(node, BAD_CAST "type");
! 3536: if (type != NULL) {
! 3537: xmlRelaxNGNormExtSpace(type);
! 3538: if (xmlValidateNCName(type, 0)) {
! 3539: xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
! 3540: "value type '%s' is not an NCName\n", type, NULL);
! 3541: }
! 3542: library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
! 3543: if (library == NULL)
! 3544: library =
! 3545: xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
! 3546:
! 3547: def->name = type;
! 3548: def->ns = library;
! 3549:
! 3550: lib = (xmlRelaxNGTypeLibraryPtr)
! 3551: xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
! 3552: if (lib == NULL) {
! 3553: xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
! 3554: "Use of unregistered type library '%s'\n", library,
! 3555: NULL);
! 3556: def->data = NULL;
! 3557: } else {
! 3558: def->data = lib;
! 3559: if (lib->have == NULL) {
! 3560: xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
! 3561: "Internal error with type library '%s': no 'have'\n",
! 3562: library, NULL);
! 3563: } else {
! 3564: success = lib->have(lib->data, def->name);
! 3565: if (success != 1) {
! 3566: xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
! 3567: "Error type '%s' is not exported by type library '%s'\n",
! 3568: def->name, library);
! 3569: }
! 3570: }
! 3571: }
! 3572: }
! 3573: if (node->children == NULL) {
! 3574: def->value = xmlStrdup(BAD_CAST "");
! 3575: } else if (((node->children->type != XML_TEXT_NODE) &&
! 3576: (node->children->type != XML_CDATA_SECTION_NODE)) ||
! 3577: (node->children->next != NULL)) {
! 3578: xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
! 3579: "Expecting a single text value for <value>content\n",
! 3580: NULL, NULL);
! 3581: } else if (def != NULL) {
! 3582: def->value = xmlNodeGetContent(node);
! 3583: if (def->value == NULL) {
! 3584: xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
! 3585: "Element <value> has no content\n", NULL, NULL);
! 3586: } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
! 3587: void *val = NULL;
! 3588:
! 3589: success =
! 3590: lib->check(lib->data, def->name, def->value, &val, node);
! 3591: if (success != 1) {
! 3592: xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
! 3593: "Value '%s' is not acceptable for type '%s'\n",
! 3594: def->value, def->name);
! 3595: } else {
! 3596: if (val != NULL)
! 3597: def->attrs = val;
! 3598: }
! 3599: }
! 3600: }
! 3601: return (def);
! 3602: }
! 3603:
! 3604: /**
! 3605: * xmlRelaxNGParseData:
! 3606: * @ctxt: a Relax-NG parser context
! 3607: * @node: the data node.
! 3608: *
! 3609: * parse the content of a RelaxNG data node.
! 3610: *
! 3611: * Returns the definition pointer or NULL in case of error
! 3612: */
! 3613: static xmlRelaxNGDefinePtr
! 3614: xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 3615: {
! 3616: xmlRelaxNGDefinePtr def = NULL, except;
! 3617: xmlRelaxNGDefinePtr param, lastparam = NULL;
! 3618: xmlRelaxNGTypeLibraryPtr lib;
! 3619: xmlChar *type;
! 3620: xmlChar *library;
! 3621: xmlNodePtr content;
! 3622: int tmp;
! 3623:
! 3624: type = xmlGetProp(node, BAD_CAST "type");
! 3625: if (type == NULL) {
! 3626: xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
! 3627: NULL);
! 3628: return (NULL);
! 3629: }
! 3630: xmlRelaxNGNormExtSpace(type);
! 3631: if (xmlValidateNCName(type, 0)) {
! 3632: xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
! 3633: "data type '%s' is not an NCName\n", type, NULL);
! 3634: }
! 3635: library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
! 3636: if (library == NULL)
! 3637: library =
! 3638: xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
! 3639:
! 3640: def = xmlRelaxNGNewDefine(ctxt, node);
! 3641: if (def == NULL) {
! 3642: xmlFree(type);
! 3643: return (NULL);
! 3644: }
! 3645: def->type = XML_RELAXNG_DATATYPE;
! 3646: def->name = type;
! 3647: def->ns = library;
! 3648:
! 3649: lib = (xmlRelaxNGTypeLibraryPtr)
! 3650: xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
! 3651: if (lib == NULL) {
! 3652: xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
! 3653: "Use of unregistered type library '%s'\n", library,
! 3654: NULL);
! 3655: def->data = NULL;
! 3656: } else {
! 3657: def->data = lib;
! 3658: if (lib->have == NULL) {
! 3659: xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
! 3660: "Internal error with type library '%s': no 'have'\n",
! 3661: library, NULL);
! 3662: } else {
! 3663: tmp = lib->have(lib->data, def->name);
! 3664: if (tmp != 1) {
! 3665: xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
! 3666: "Error type '%s' is not exported by type library '%s'\n",
! 3667: def->name, library);
! 3668: } else
! 3669: if ((xmlStrEqual
! 3670: (library,
! 3671: BAD_CAST
! 3672: "http://www.w3.org/2001/XMLSchema-datatypes"))
! 3673: && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
! 3674: || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
! 3675: ctxt->idref = 1;
! 3676: }
! 3677: }
! 3678: }
! 3679: content = node->children;
! 3680:
! 3681: /*
! 3682: * Handle optional params
! 3683: */
! 3684: while (content != NULL) {
! 3685: if (!xmlStrEqual(content->name, BAD_CAST "param"))
! 3686: break;
! 3687: if (xmlStrEqual(library,
! 3688: BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
! 3689: xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
! 3690: "Type library '%s' does not allow type parameters\n",
! 3691: library, NULL);
! 3692: content = content->next;
! 3693: while ((content != NULL) &&
! 3694: (xmlStrEqual(content->name, BAD_CAST "param")))
! 3695: content = content->next;
! 3696: } else {
! 3697: param = xmlRelaxNGNewDefine(ctxt, node);
! 3698: if (param != NULL) {
! 3699: param->type = XML_RELAXNG_PARAM;
! 3700: param->name = xmlGetProp(content, BAD_CAST "name");
! 3701: if (param->name == NULL) {
! 3702: xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
! 3703: "param has no name\n", NULL, NULL);
! 3704: }
! 3705: param->value = xmlNodeGetContent(content);
! 3706: if (lastparam == NULL) {
! 3707: def->attrs = lastparam = param;
! 3708: } else {
! 3709: lastparam->next = param;
! 3710: lastparam = param;
! 3711: }
! 3712: if (lib != NULL) {
! 3713: }
! 3714: }
! 3715: content = content->next;
! 3716: }
! 3717: }
! 3718: /*
! 3719: * Handle optional except
! 3720: */
! 3721: if ((content != NULL)
! 3722: && (xmlStrEqual(content->name, BAD_CAST "except"))) {
! 3723: xmlNodePtr child;
! 3724: xmlRelaxNGDefinePtr tmp2, last = NULL;
! 3725:
! 3726: except = xmlRelaxNGNewDefine(ctxt, node);
! 3727: if (except == NULL) {
! 3728: return (def);
! 3729: }
! 3730: except->type = XML_RELAXNG_EXCEPT;
! 3731: child = content->children;
! 3732: def->content = except;
! 3733: if (child == NULL) {
! 3734: xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
! 3735: "except has no content\n", NULL, NULL);
! 3736: }
! 3737: while (child != NULL) {
! 3738: tmp2 = xmlRelaxNGParsePattern(ctxt, child);
! 3739: if (tmp2 != NULL) {
! 3740: if (last == NULL) {
! 3741: except->content = last = tmp2;
! 3742: } else {
! 3743: last->next = tmp2;
! 3744: last = tmp2;
! 3745: }
! 3746: }
! 3747: child = child->next;
! 3748: }
! 3749: content = content->next;
! 3750: }
! 3751: /*
! 3752: * Check there is no unhandled data
! 3753: */
! 3754: if (content != NULL) {
! 3755: xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
! 3756: "Element data has unexpected content %s\n",
! 3757: content->name, NULL);
! 3758: }
! 3759:
! 3760: return (def);
! 3761: }
! 3762:
! 3763: static const xmlChar *invalidName = BAD_CAST "\1";
! 3764:
! 3765: /**
! 3766: * xmlRelaxNGCompareNameClasses:
! 3767: * @defs1: the first element/attribute defs
! 3768: * @defs2: the second element/attribute defs
! 3769: * @name: the restriction on the name
! 3770: * @ns: the restriction on the namespace
! 3771: *
! 3772: * Compare the 2 lists of element definitions. The comparison is
! 3773: * that if both lists do not accept the same QNames, it returns 1
! 3774: * If the 2 lists can accept the same QName the comparison returns 0
! 3775: *
! 3776: * Returns 1 disttinct, 0 if equal
! 3777: */
! 3778: static int
! 3779: xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
! 3780: xmlRelaxNGDefinePtr def2)
! 3781: {
! 3782: int ret = 1;
! 3783: xmlNode node;
! 3784: xmlNs ns;
! 3785: xmlRelaxNGValidCtxt ctxt;
! 3786:
! 3787: memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
! 3788:
! 3789: ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
! 3790:
! 3791: if ((def1->type == XML_RELAXNG_ELEMENT) ||
! 3792: (def1->type == XML_RELAXNG_ATTRIBUTE)) {
! 3793: if (def2->type == XML_RELAXNG_TEXT)
! 3794: return (1);
! 3795: if (def1->name != NULL) {
! 3796: node.name = def1->name;
! 3797: } else {
! 3798: node.name = invalidName;
! 3799: }
! 3800: if (def1->ns != NULL) {
! 3801: if (def1->ns[0] == 0) {
! 3802: node.ns = NULL;
! 3803: } else {
! 3804: node.ns = &ns;
! 3805: ns.href = def1->ns;
! 3806: }
! 3807: } else {
! 3808: node.ns = NULL;
! 3809: }
! 3810: if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
! 3811: if (def1->nameClass != NULL) {
! 3812: ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
! 3813: } else {
! 3814: ret = 0;
! 3815: }
! 3816: } else {
! 3817: ret = 1;
! 3818: }
! 3819: } else if (def1->type == XML_RELAXNG_TEXT) {
! 3820: if (def2->type == XML_RELAXNG_TEXT)
! 3821: return (0);
! 3822: return (1);
! 3823: } else if (def1->type == XML_RELAXNG_EXCEPT) {
! 3824: TODO ret = 0;
! 3825: } else {
! 3826: TODO ret = 0;
! 3827: }
! 3828: if (ret == 0)
! 3829: return (ret);
! 3830: if ((def2->type == XML_RELAXNG_ELEMENT) ||
! 3831: (def2->type == XML_RELAXNG_ATTRIBUTE)) {
! 3832: if (def2->name != NULL) {
! 3833: node.name = def2->name;
! 3834: } else {
! 3835: node.name = invalidName;
! 3836: }
! 3837: node.ns = &ns;
! 3838: if (def2->ns != NULL) {
! 3839: if (def2->ns[0] == 0) {
! 3840: node.ns = NULL;
! 3841: } else {
! 3842: ns.href = def2->ns;
! 3843: }
! 3844: } else {
! 3845: ns.href = invalidName;
! 3846: }
! 3847: if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
! 3848: if (def2->nameClass != NULL) {
! 3849: ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
! 3850: } else {
! 3851: ret = 0;
! 3852: }
! 3853: } else {
! 3854: ret = 1;
! 3855: }
! 3856: } else {
! 3857: TODO ret = 0;
! 3858: }
! 3859:
! 3860: return (ret);
! 3861: }
! 3862:
! 3863: /**
! 3864: * xmlRelaxNGCompareElemDefLists:
! 3865: * @ctxt: a Relax-NG parser context
! 3866: * @defs1: the first list of element/attribute defs
! 3867: * @defs2: the second list of element/attribute defs
! 3868: *
! 3869: * Compare the 2 lists of element or attribute definitions. The comparison
! 3870: * is that if both lists do not accept the same QNames, it returns 1
! 3871: * If the 2 lists can accept the same QName the comparison returns 0
! 3872: *
! 3873: * Returns 1 disttinct, 0 if equal
! 3874: */
! 3875: static int
! 3876: xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
! 3877: ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
! 3878: xmlRelaxNGDefinePtr * def2)
! 3879: {
! 3880: xmlRelaxNGDefinePtr *basedef2 = def2;
! 3881:
! 3882: if ((def1 == NULL) || (def2 == NULL))
! 3883: return (1);
! 3884: if ((*def1 == NULL) || (*def2 == NULL))
! 3885: return (1);
! 3886: while (*def1 != NULL) {
! 3887: while ((*def2) != NULL) {
! 3888: if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
! 3889: return (0);
! 3890: def2++;
! 3891: }
! 3892: def2 = basedef2;
! 3893: def1++;
! 3894: }
! 3895: return (1);
! 3896: }
! 3897:
! 3898: /**
! 3899: * xmlRelaxNGGenerateAttributes:
! 3900: * @ctxt: a Relax-NG parser context
! 3901: * @def: the definition definition
! 3902: *
! 3903: * Check if the definition can only generate attributes
! 3904: *
! 3905: * Returns 1 if yes, 0 if no and -1 in case of error.
! 3906: */
! 3907: static int
! 3908: xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
! 3909: xmlRelaxNGDefinePtr def)
! 3910: {
! 3911: xmlRelaxNGDefinePtr parent, cur, tmp;
! 3912:
! 3913: /*
! 3914: * Don't run that check in case of error. Infinite recursion
! 3915: * becomes possible.
! 3916: */
! 3917: if (ctxt->nbErrors != 0)
! 3918: return (-1);
! 3919:
! 3920: parent = NULL;
! 3921: cur = def;
! 3922: while (cur != NULL) {
! 3923: if ((cur->type == XML_RELAXNG_ELEMENT) ||
! 3924: (cur->type == XML_RELAXNG_TEXT) ||
! 3925: (cur->type == XML_RELAXNG_DATATYPE) ||
! 3926: (cur->type == XML_RELAXNG_PARAM) ||
! 3927: (cur->type == XML_RELAXNG_LIST) ||
! 3928: (cur->type == XML_RELAXNG_VALUE) ||
! 3929: (cur->type == XML_RELAXNG_EMPTY))
! 3930: return (0);
! 3931: if ((cur->type == XML_RELAXNG_CHOICE) ||
! 3932: (cur->type == XML_RELAXNG_INTERLEAVE) ||
! 3933: (cur->type == XML_RELAXNG_GROUP) ||
! 3934: (cur->type == XML_RELAXNG_ONEORMORE) ||
! 3935: (cur->type == XML_RELAXNG_ZEROORMORE) ||
! 3936: (cur->type == XML_RELAXNG_OPTIONAL) ||
! 3937: (cur->type == XML_RELAXNG_PARENTREF) ||
! 3938: (cur->type == XML_RELAXNG_EXTERNALREF) ||
! 3939: (cur->type == XML_RELAXNG_REF) ||
! 3940: (cur->type == XML_RELAXNG_DEF)) {
! 3941: if (cur->content != NULL) {
! 3942: parent = cur;
! 3943: cur = cur->content;
! 3944: tmp = cur;
! 3945: while (tmp != NULL) {
! 3946: tmp->parent = parent;
! 3947: tmp = tmp->next;
! 3948: }
! 3949: continue;
! 3950: }
! 3951: }
! 3952: if (cur == def)
! 3953: break;
! 3954: if (cur->next != NULL) {
! 3955: cur = cur->next;
! 3956: continue;
! 3957: }
! 3958: do {
! 3959: cur = cur->parent;
! 3960: if (cur == NULL)
! 3961: break;
! 3962: if (cur == def)
! 3963: return (1);
! 3964: if (cur->next != NULL) {
! 3965: cur = cur->next;
! 3966: break;
! 3967: }
! 3968: } while (cur != NULL);
! 3969: }
! 3970: return (1);
! 3971: }
! 3972:
! 3973: /**
! 3974: * xmlRelaxNGGetElements:
! 3975: * @ctxt: a Relax-NG parser context
! 3976: * @def: the definition definition
! 3977: * @eora: gather elements (0) or attributes (1)
! 3978: *
! 3979: * Compute the list of top elements a definition can generate
! 3980: *
! 3981: * Returns a list of elements or NULL if none was found.
! 3982: */
! 3983: static xmlRelaxNGDefinePtr *
! 3984: xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
! 3985: xmlRelaxNGDefinePtr def, int eora)
! 3986: {
! 3987: xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
! 3988: int len = 0;
! 3989: int max = 0;
! 3990:
! 3991: /*
! 3992: * Don't run that check in case of error. Infinite recursion
! 3993: * becomes possible.
! 3994: */
! 3995: if (ctxt->nbErrors != 0)
! 3996: return (NULL);
! 3997:
! 3998: parent = NULL;
! 3999: cur = def;
! 4000: while (cur != NULL) {
! 4001: if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
! 4002: (cur->type == XML_RELAXNG_TEXT))) ||
! 4003: ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
! 4004: if (ret == NULL) {
! 4005: max = 10;
! 4006: ret = (xmlRelaxNGDefinePtr *)
! 4007: xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
! 4008: if (ret == NULL) {
! 4009: xmlRngPErrMemory(ctxt, "getting element list\n");
! 4010: return (NULL);
! 4011: }
! 4012: } else if (max <= len) {
! 4013: xmlRelaxNGDefinePtr *temp;
! 4014:
! 4015: max *= 2;
! 4016: temp = xmlRealloc(ret,
! 4017: (max + 1) * sizeof(xmlRelaxNGDefinePtr));
! 4018: if (temp == NULL) {
! 4019: xmlRngPErrMemory(ctxt, "getting element list\n");
! 4020: xmlFree(ret);
! 4021: return (NULL);
! 4022: }
! 4023: ret = temp;
! 4024: }
! 4025: ret[len++] = cur;
! 4026: ret[len] = NULL;
! 4027: } else if ((cur->type == XML_RELAXNG_CHOICE) ||
! 4028: (cur->type == XML_RELAXNG_INTERLEAVE) ||
! 4029: (cur->type == XML_RELAXNG_GROUP) ||
! 4030: (cur->type == XML_RELAXNG_ONEORMORE) ||
! 4031: (cur->type == XML_RELAXNG_ZEROORMORE) ||
! 4032: (cur->type == XML_RELAXNG_OPTIONAL) ||
! 4033: (cur->type == XML_RELAXNG_PARENTREF) ||
! 4034: (cur->type == XML_RELAXNG_REF) ||
! 4035: (cur->type == XML_RELAXNG_DEF) ||
! 4036: (cur->type == XML_RELAXNG_EXTERNALREF)) {
! 4037: /*
! 4038: * Don't go within elements or attributes or string values.
! 4039: * Just gather the element top list
! 4040: */
! 4041: if (cur->content != NULL) {
! 4042: parent = cur;
! 4043: cur = cur->content;
! 4044: tmp = cur;
! 4045: while (tmp != NULL) {
! 4046: tmp->parent = parent;
! 4047: tmp = tmp->next;
! 4048: }
! 4049: continue;
! 4050: }
! 4051: }
! 4052: if (cur == def)
! 4053: break;
! 4054: if (cur->next != NULL) {
! 4055: cur = cur->next;
! 4056: continue;
! 4057: }
! 4058: do {
! 4059: cur = cur->parent;
! 4060: if (cur == NULL)
! 4061: break;
! 4062: if (cur == def)
! 4063: return (ret);
! 4064: if (cur->next != NULL) {
! 4065: cur = cur->next;
! 4066: break;
! 4067: }
! 4068: } while (cur != NULL);
! 4069: }
! 4070: return (ret);
! 4071: }
! 4072:
! 4073: /**
! 4074: * xmlRelaxNGCheckChoiceDeterminism:
! 4075: * @ctxt: a Relax-NG parser context
! 4076: * @def: the choice definition
! 4077: *
! 4078: * Also used to find indeterministic pattern in choice
! 4079: */
! 4080: static void
! 4081: xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
! 4082: xmlRelaxNGDefinePtr def)
! 4083: {
! 4084: xmlRelaxNGDefinePtr **list;
! 4085: xmlRelaxNGDefinePtr cur;
! 4086: int nbchild = 0, i, j, ret;
! 4087: int is_nullable = 0;
! 4088: int is_indeterminist = 0;
! 4089: xmlHashTablePtr triage = NULL;
! 4090: int is_triable = 1;
! 4091:
! 4092: if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
! 4093: return;
! 4094:
! 4095: if (def->dflags & IS_PROCESSED)
! 4096: return;
! 4097:
! 4098: /*
! 4099: * Don't run that check in case of error. Infinite recursion
! 4100: * becomes possible.
! 4101: */
! 4102: if (ctxt->nbErrors != 0)
! 4103: return;
! 4104:
! 4105: is_nullable = xmlRelaxNGIsNullable(def);
! 4106:
! 4107: cur = def->content;
! 4108: while (cur != NULL) {
! 4109: nbchild++;
! 4110: cur = cur->next;
! 4111: }
! 4112:
! 4113: list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
! 4114: sizeof(xmlRelaxNGDefinePtr
! 4115: *));
! 4116: if (list == NULL) {
! 4117: xmlRngPErrMemory(ctxt, "building choice\n");
! 4118: return;
! 4119: }
! 4120: i = 0;
! 4121: /*
! 4122: * a bit strong but safe
! 4123: */
! 4124: if (is_nullable == 0) {
! 4125: triage = xmlHashCreate(10);
! 4126: } else {
! 4127: is_triable = 0;
! 4128: }
! 4129: cur = def->content;
! 4130: while (cur != NULL) {
! 4131: list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
! 4132: if ((list[i] == NULL) || (list[i][0] == NULL)) {
! 4133: is_triable = 0;
! 4134: } else if (is_triable == 1) {
! 4135: xmlRelaxNGDefinePtr *tmp;
! 4136: int res;
! 4137:
! 4138: tmp = list[i];
! 4139: while ((*tmp != NULL) && (is_triable == 1)) {
! 4140: if ((*tmp)->type == XML_RELAXNG_TEXT) {
! 4141: res = xmlHashAddEntry2(triage,
! 4142: BAD_CAST "#text", NULL,
! 4143: (void *) cur);
! 4144: if (res != 0)
! 4145: is_triable = -1;
! 4146: } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
! 4147: ((*tmp)->name != NULL)) {
! 4148: if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
! 4149: res = xmlHashAddEntry2(triage,
! 4150: (*tmp)->name, NULL,
! 4151: (void *) cur);
! 4152: else
! 4153: res = xmlHashAddEntry2(triage,
! 4154: (*tmp)->name, (*tmp)->ns,
! 4155: (void *) cur);
! 4156: if (res != 0)
! 4157: is_triable = -1;
! 4158: } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
! 4159: if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
! 4160: res = xmlHashAddEntry2(triage,
! 4161: BAD_CAST "#any", NULL,
! 4162: (void *) cur);
! 4163: else
! 4164: res = xmlHashAddEntry2(triage,
! 4165: BAD_CAST "#any", (*tmp)->ns,
! 4166: (void *) cur);
! 4167: if (res != 0)
! 4168: is_triable = -1;
! 4169: } else {
! 4170: is_triable = -1;
! 4171: }
! 4172: tmp++;
! 4173: }
! 4174: }
! 4175: i++;
! 4176: cur = cur->next;
! 4177: }
! 4178:
! 4179: for (i = 0; i < nbchild; i++) {
! 4180: if (list[i] == NULL)
! 4181: continue;
! 4182: for (j = 0; j < i; j++) {
! 4183: if (list[j] == NULL)
! 4184: continue;
! 4185: ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
! 4186: if (ret == 0) {
! 4187: is_indeterminist = 1;
! 4188: }
! 4189: }
! 4190: }
! 4191: for (i = 0; i < nbchild; i++) {
! 4192: if (list[i] != NULL)
! 4193: xmlFree(list[i]);
! 4194: }
! 4195:
! 4196: xmlFree(list);
! 4197: if (is_indeterminist) {
! 4198: def->dflags |= IS_INDETERMINIST;
! 4199: }
! 4200: if (is_triable == 1) {
! 4201: def->dflags |= IS_TRIABLE;
! 4202: def->data = triage;
! 4203: } else if (triage != NULL) {
! 4204: xmlHashFree(triage, NULL);
! 4205: }
! 4206: def->dflags |= IS_PROCESSED;
! 4207: }
! 4208:
! 4209: /**
! 4210: * xmlRelaxNGCheckGroupAttrs:
! 4211: * @ctxt: a Relax-NG parser context
! 4212: * @def: the group definition
! 4213: *
! 4214: * Detects violations of rule 7.3
! 4215: */
! 4216: static void
! 4217: xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
! 4218: xmlRelaxNGDefinePtr def)
! 4219: {
! 4220: xmlRelaxNGDefinePtr **list;
! 4221: xmlRelaxNGDefinePtr cur;
! 4222: int nbchild = 0, i, j, ret;
! 4223:
! 4224: if ((def == NULL) ||
! 4225: ((def->type != XML_RELAXNG_GROUP) &&
! 4226: (def->type != XML_RELAXNG_ELEMENT)))
! 4227: return;
! 4228:
! 4229: if (def->dflags & IS_PROCESSED)
! 4230: return;
! 4231:
! 4232: /*
! 4233: * Don't run that check in case of error. Infinite recursion
! 4234: * becomes possible.
! 4235: */
! 4236: if (ctxt->nbErrors != 0)
! 4237: return;
! 4238:
! 4239: cur = def->attrs;
! 4240: while (cur != NULL) {
! 4241: nbchild++;
! 4242: cur = cur->next;
! 4243: }
! 4244: cur = def->content;
! 4245: while (cur != NULL) {
! 4246: nbchild++;
! 4247: cur = cur->next;
! 4248: }
! 4249:
! 4250: list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
! 4251: sizeof(xmlRelaxNGDefinePtr
! 4252: *));
! 4253: if (list == NULL) {
! 4254: xmlRngPErrMemory(ctxt, "building group\n");
! 4255: return;
! 4256: }
! 4257: i = 0;
! 4258: cur = def->attrs;
! 4259: while (cur != NULL) {
! 4260: list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
! 4261: i++;
! 4262: cur = cur->next;
! 4263: }
! 4264: cur = def->content;
! 4265: while (cur != NULL) {
! 4266: list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
! 4267: i++;
! 4268: cur = cur->next;
! 4269: }
! 4270:
! 4271: for (i = 0; i < nbchild; i++) {
! 4272: if (list[i] == NULL)
! 4273: continue;
! 4274: for (j = 0; j < i; j++) {
! 4275: if (list[j] == NULL)
! 4276: continue;
! 4277: ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
! 4278: if (ret == 0) {
! 4279: xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
! 4280: "Attributes conflicts in group\n", NULL, NULL);
! 4281: }
! 4282: }
! 4283: }
! 4284: for (i = 0; i < nbchild; i++) {
! 4285: if (list[i] != NULL)
! 4286: xmlFree(list[i]);
! 4287: }
! 4288:
! 4289: xmlFree(list);
! 4290: def->dflags |= IS_PROCESSED;
! 4291: }
! 4292:
! 4293: /**
! 4294: * xmlRelaxNGComputeInterleaves:
! 4295: * @def: the interleave definition
! 4296: * @ctxt: a Relax-NG parser context
! 4297: * @name: the definition name
! 4298: *
! 4299: * A lot of work for preprocessing interleave definitions
! 4300: * is potentially needed to get a decent execution speed at runtime
! 4301: * - trying to get a total order on the element nodes generated
! 4302: * by the interleaves, order the list of interleave definitions
! 4303: * following that order.
! 4304: * - if <text/> is used to handle mixed content, it is better to
! 4305: * flag this in the define and simplify the runtime checking
! 4306: * algorithm
! 4307: */
! 4308: static void
! 4309: xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
! 4310: xmlRelaxNGParserCtxtPtr ctxt,
! 4311: xmlChar * name ATTRIBUTE_UNUSED)
! 4312: {
! 4313: xmlRelaxNGDefinePtr cur, *tmp;
! 4314:
! 4315: xmlRelaxNGPartitionPtr partitions = NULL;
! 4316: xmlRelaxNGInterleaveGroupPtr *groups = NULL;
! 4317: xmlRelaxNGInterleaveGroupPtr group;
! 4318: int i, j, ret, res;
! 4319: int nbgroups = 0;
! 4320: int nbchild = 0;
! 4321: int is_mixed = 0;
! 4322: int is_determinist = 1;
! 4323:
! 4324: /*
! 4325: * Don't run that check in case of error. Infinite recursion
! 4326: * becomes possible.
! 4327: */
! 4328: if (ctxt->nbErrors != 0)
! 4329: return;
! 4330:
! 4331: #ifdef DEBUG_INTERLEAVE
! 4332: xmlGenericError(xmlGenericErrorContext,
! 4333: "xmlRelaxNGComputeInterleaves(%s)\n", name);
! 4334: #endif
! 4335: cur = def->content;
! 4336: while (cur != NULL) {
! 4337: nbchild++;
! 4338: cur = cur->next;
! 4339: }
! 4340:
! 4341: #ifdef DEBUG_INTERLEAVE
! 4342: xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
! 4343: #endif
! 4344: groups = (xmlRelaxNGInterleaveGroupPtr *)
! 4345: xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
! 4346: if (groups == NULL)
! 4347: goto error;
! 4348: cur = def->content;
! 4349: while (cur != NULL) {
! 4350: groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
! 4351: xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
! 4352: if (groups[nbgroups] == NULL)
! 4353: goto error;
! 4354: if (cur->type == XML_RELAXNG_TEXT)
! 4355: is_mixed++;
! 4356: groups[nbgroups]->rule = cur;
! 4357: groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
! 4358: groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
! 4359: nbgroups++;
! 4360: cur = cur->next;
! 4361: }
! 4362: #ifdef DEBUG_INTERLEAVE
! 4363: xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
! 4364: #endif
! 4365:
! 4366: /*
! 4367: * Let's check that all rules makes a partitions according to 7.4
! 4368: */
! 4369: partitions = (xmlRelaxNGPartitionPtr)
! 4370: xmlMalloc(sizeof(xmlRelaxNGPartition));
! 4371: if (partitions == NULL)
! 4372: goto error;
! 4373: memset(partitions, 0, sizeof(xmlRelaxNGPartition));
! 4374: partitions->nbgroups = nbgroups;
! 4375: partitions->triage = xmlHashCreate(nbgroups);
! 4376: for (i = 0; i < nbgroups; i++) {
! 4377: group = groups[i];
! 4378: for (j = i + 1; j < nbgroups; j++) {
! 4379: if (groups[j] == NULL)
! 4380: continue;
! 4381:
! 4382: ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
! 4383: groups[j]->defs);
! 4384: if (ret == 0) {
! 4385: xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
! 4386: "Element or text conflicts in interleave\n",
! 4387: NULL, NULL);
! 4388: }
! 4389: ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
! 4390: groups[j]->attrs);
! 4391: if (ret == 0) {
! 4392: xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
! 4393: "Attributes conflicts in interleave\n", NULL,
! 4394: NULL);
! 4395: }
! 4396: }
! 4397: tmp = group->defs;
! 4398: if ((tmp != NULL) && (*tmp != NULL)) {
! 4399: while (*tmp != NULL) {
! 4400: if ((*tmp)->type == XML_RELAXNG_TEXT) {
! 4401: res = xmlHashAddEntry2(partitions->triage,
! 4402: BAD_CAST "#text", NULL,
! 4403: (void *) (long) (i + 1));
! 4404: if (res != 0)
! 4405: is_determinist = -1;
! 4406: } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
! 4407: ((*tmp)->name != NULL)) {
! 4408: if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
! 4409: res = xmlHashAddEntry2(partitions->triage,
! 4410: (*tmp)->name, NULL,
! 4411: (void *) (long) (i + 1));
! 4412: else
! 4413: res = xmlHashAddEntry2(partitions->triage,
! 4414: (*tmp)->name, (*tmp)->ns,
! 4415: (void *) (long) (i + 1));
! 4416: if (res != 0)
! 4417: is_determinist = -1;
! 4418: } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
! 4419: if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
! 4420: res = xmlHashAddEntry2(partitions->triage,
! 4421: BAD_CAST "#any", NULL,
! 4422: (void *) (long) (i + 1));
! 4423: else
! 4424: res = xmlHashAddEntry2(partitions->triage,
! 4425: BAD_CAST "#any", (*tmp)->ns,
! 4426: (void *) (long) (i + 1));
! 4427: if ((*tmp)->nameClass != NULL)
! 4428: is_determinist = 2;
! 4429: if (res != 0)
! 4430: is_determinist = -1;
! 4431: } else {
! 4432: is_determinist = -1;
! 4433: }
! 4434: tmp++;
! 4435: }
! 4436: } else {
! 4437: is_determinist = 0;
! 4438: }
! 4439: }
! 4440: partitions->groups = groups;
! 4441:
! 4442: /*
! 4443: * and save the partition list back in the def
! 4444: */
! 4445: def->data = partitions;
! 4446: if (is_mixed != 0)
! 4447: def->dflags |= IS_MIXED;
! 4448: if (is_determinist == 1)
! 4449: partitions->flags = IS_DETERMINIST;
! 4450: if (is_determinist == 2)
! 4451: partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
! 4452: return;
! 4453:
! 4454: error:
! 4455: xmlRngPErrMemory(ctxt, "in interleave computation\n");
! 4456: if (groups != NULL) {
! 4457: for (i = 0; i < nbgroups; i++)
! 4458: if (groups[i] != NULL) {
! 4459: if (groups[i]->defs != NULL)
! 4460: xmlFree(groups[i]->defs);
! 4461: xmlFree(groups[i]);
! 4462: }
! 4463: xmlFree(groups);
! 4464: }
! 4465: xmlRelaxNGFreePartition(partitions);
! 4466: }
! 4467:
! 4468: /**
! 4469: * xmlRelaxNGParseInterleave:
! 4470: * @ctxt: a Relax-NG parser context
! 4471: * @node: the data node.
! 4472: *
! 4473: * parse the content of a RelaxNG interleave node.
! 4474: *
! 4475: * Returns the definition pointer or NULL in case of error
! 4476: */
! 4477: static xmlRelaxNGDefinePtr
! 4478: xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 4479: {
! 4480: xmlRelaxNGDefinePtr def = NULL;
! 4481: xmlRelaxNGDefinePtr last = NULL, cur;
! 4482: xmlNodePtr child;
! 4483:
! 4484: def = xmlRelaxNGNewDefine(ctxt, node);
! 4485: if (def == NULL) {
! 4486: return (NULL);
! 4487: }
! 4488: def->type = XML_RELAXNG_INTERLEAVE;
! 4489:
! 4490: if (ctxt->interleaves == NULL)
! 4491: ctxt->interleaves = xmlHashCreate(10);
! 4492: if (ctxt->interleaves == NULL) {
! 4493: xmlRngPErrMemory(ctxt, "create interleaves\n");
! 4494: } else {
! 4495: char name[32];
! 4496:
! 4497: snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
! 4498: if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
! 4499: xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
! 4500: "Failed to add %s to hash table\n",
! 4501: (const xmlChar *) name, NULL);
! 4502: }
! 4503: }
! 4504: child = node->children;
! 4505: if (child == NULL) {
! 4506: xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
! 4507: "Element interleave is empty\n", NULL, NULL);
! 4508: }
! 4509: while (child != NULL) {
! 4510: if (IS_RELAXNG(child, "element")) {
! 4511: cur = xmlRelaxNGParseElement(ctxt, child);
! 4512: } else {
! 4513: cur = xmlRelaxNGParsePattern(ctxt, child);
! 4514: }
! 4515: if (cur != NULL) {
! 4516: cur->parent = def;
! 4517: if (last == NULL) {
! 4518: def->content = last = cur;
! 4519: } else {
! 4520: last->next = cur;
! 4521: last = cur;
! 4522: }
! 4523: }
! 4524: child = child->next;
! 4525: }
! 4526:
! 4527: return (def);
! 4528: }
! 4529:
! 4530: /**
! 4531: * xmlRelaxNGParseInclude:
! 4532: * @ctxt: a Relax-NG parser context
! 4533: * @node: the include node
! 4534: *
! 4535: * Integrate the content of an include node in the current grammar
! 4536: *
! 4537: * Returns 0 in case of success or -1 in case of error
! 4538: */
! 4539: static int
! 4540: xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 4541: {
! 4542: xmlRelaxNGIncludePtr incl;
! 4543: xmlNodePtr root;
! 4544: int ret = 0, tmp;
! 4545:
! 4546: incl = node->psvi;
! 4547: if (incl == NULL) {
! 4548: xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
! 4549: "Include node has no data\n", NULL, NULL);
! 4550: return (-1);
! 4551: }
! 4552: root = xmlDocGetRootElement(incl->doc);
! 4553: if (root == NULL) {
! 4554: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
! 4555: NULL, NULL);
! 4556: return (-1);
! 4557: }
! 4558: if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
! 4559: xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
! 4560: "Include document root is not a grammar\n", NULL, NULL);
! 4561: return (-1);
! 4562: }
! 4563:
! 4564: /*
! 4565: * Merge the definition from both the include and the internal list
! 4566: */
! 4567: if (root->children != NULL) {
! 4568: tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
! 4569: if (tmp != 0)
! 4570: ret = -1;
! 4571: }
! 4572: if (node->children != NULL) {
! 4573: tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
! 4574: if (tmp != 0)
! 4575: ret = -1;
! 4576: }
! 4577: return (ret);
! 4578: }
! 4579:
! 4580: /**
! 4581: * xmlRelaxNGParseDefine:
! 4582: * @ctxt: a Relax-NG parser context
! 4583: * @node: the define node
! 4584: *
! 4585: * parse the content of a RelaxNG define element node.
! 4586: *
! 4587: * Returns 0 in case of success or -1 in case of error
! 4588: */
! 4589: static int
! 4590: xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 4591: {
! 4592: xmlChar *name;
! 4593: int ret = 0, tmp;
! 4594: xmlRelaxNGDefinePtr def;
! 4595: const xmlChar *olddefine;
! 4596:
! 4597: name = xmlGetProp(node, BAD_CAST "name");
! 4598: if (name == NULL) {
! 4599: xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
! 4600: "define has no name\n", NULL, NULL);
! 4601: } else {
! 4602: xmlRelaxNGNormExtSpace(name);
! 4603: if (xmlValidateNCName(name, 0)) {
! 4604: xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
! 4605: "define name '%s' is not an NCName\n", name, NULL);
! 4606: }
! 4607: def = xmlRelaxNGNewDefine(ctxt, node);
! 4608: if (def == NULL) {
! 4609: xmlFree(name);
! 4610: return (-1);
! 4611: }
! 4612: def->type = XML_RELAXNG_DEF;
! 4613: def->name = name;
! 4614: if (node->children == NULL) {
! 4615: xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
! 4616: "define has no children\n", NULL, NULL);
! 4617: } else {
! 4618: olddefine = ctxt->define;
! 4619: ctxt->define = name;
! 4620: def->content =
! 4621: xmlRelaxNGParsePatterns(ctxt, node->children, 0);
! 4622: ctxt->define = olddefine;
! 4623: }
! 4624: if (ctxt->grammar->defs == NULL)
! 4625: ctxt->grammar->defs = xmlHashCreate(10);
! 4626: if (ctxt->grammar->defs == NULL) {
! 4627: xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
! 4628: "Could not create definition hash\n", NULL, NULL);
! 4629: ret = -1;
! 4630: } else {
! 4631: tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
! 4632: if (tmp < 0) {
! 4633: xmlRelaxNGDefinePtr prev;
! 4634:
! 4635: prev = xmlHashLookup(ctxt->grammar->defs, name);
! 4636: if (prev == NULL) {
! 4637: xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
! 4638: "Internal error on define aggregation of %s\n",
! 4639: name, NULL);
! 4640: ret = -1;
! 4641: } else {
! 4642: while (prev->nextHash != NULL)
! 4643: prev = prev->nextHash;
! 4644: prev->nextHash = def;
! 4645: }
! 4646: }
! 4647: }
! 4648: }
! 4649: return (ret);
! 4650: }
! 4651:
! 4652: /**
! 4653: * xmlRelaxNGParseImportRef:
! 4654: * @payload: the parser context
! 4655: * @data: the current grammar
! 4656: * @name: the reference name
! 4657: *
! 4658: * Import import one references into the current grammar
! 4659: */
! 4660: static void
! 4661: xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
! 4662: xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
! 4663: xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
! 4664: int tmp;
! 4665:
! 4666: def->dflags |= IS_EXTERNAL_REF;
! 4667:
! 4668: tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
! 4669: if (tmp < 0) {
! 4670: xmlRelaxNGDefinePtr prev;
! 4671:
! 4672: prev = (xmlRelaxNGDefinePtr)
! 4673: xmlHashLookup(ctxt->grammar->refs, def->name);
! 4674: if (prev == NULL) {
! 4675: if (def->name != NULL) {
! 4676: xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
! 4677: "Error refs definitions '%s'\n",
! 4678: def->name, NULL);
! 4679: } else {
! 4680: xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
! 4681: "Error refs definitions\n",
! 4682: NULL, NULL);
! 4683: }
! 4684: } else {
! 4685: def->nextHash = prev->nextHash;
! 4686: prev->nextHash = def;
! 4687: }
! 4688: }
! 4689: }
! 4690:
! 4691: /**
! 4692: * xmlRelaxNGParseImportRefs:
! 4693: * @ctxt: the parser context
! 4694: * @grammar: the sub grammar
! 4695: *
! 4696: * Import references from the subgrammar into the current grammar
! 4697: *
! 4698: * Returns 0 in case of success, -1 in case of failure
! 4699: */
! 4700: static int
! 4701: xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
! 4702: xmlRelaxNGGrammarPtr grammar) {
! 4703: if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
! 4704: return(-1);
! 4705: if (grammar->refs == NULL)
! 4706: return(0);
! 4707: if (ctxt->grammar->refs == NULL)
! 4708: ctxt->grammar->refs = xmlHashCreate(10);
! 4709: if (ctxt->grammar->refs == NULL) {
! 4710: xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
! 4711: "Could not create references hash\n", NULL, NULL);
! 4712: return(-1);
! 4713: }
! 4714: xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
! 4715: return(0);
! 4716: }
! 4717:
! 4718: /**
! 4719: * xmlRelaxNGProcessExternalRef:
! 4720: * @ctxt: the parser context
! 4721: * @node: the externlRef node
! 4722: *
! 4723: * Process and compile an externlRef node
! 4724: *
! 4725: * Returns the xmlRelaxNGDefinePtr or NULL in case of error
! 4726: */
! 4727: static xmlRelaxNGDefinePtr
! 4728: xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 4729: {
! 4730: xmlRelaxNGDocumentPtr docu;
! 4731: xmlNodePtr root, tmp;
! 4732: xmlChar *ns;
! 4733: int newNs = 0, oldflags;
! 4734: xmlRelaxNGDefinePtr def;
! 4735:
! 4736: docu = node->psvi;
! 4737: if (docu != NULL) {
! 4738: def = xmlRelaxNGNewDefine(ctxt, node);
! 4739: if (def == NULL)
! 4740: return (NULL);
! 4741: def->type = XML_RELAXNG_EXTERNALREF;
! 4742:
! 4743: if (docu->content == NULL) {
! 4744: /*
! 4745: * Then do the parsing for good
! 4746: */
! 4747: root = xmlDocGetRootElement(docu->doc);
! 4748: if (root == NULL) {
! 4749: xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
! 4750: "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
! 4751: NULL);
! 4752: return (NULL);
! 4753: }
! 4754: /*
! 4755: * ns transmission rules
! 4756: */
! 4757: ns = xmlGetProp(root, BAD_CAST "ns");
! 4758: if (ns == NULL) {
! 4759: tmp = node;
! 4760: while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
! 4761: ns = xmlGetProp(tmp, BAD_CAST "ns");
! 4762: if (ns != NULL) {
! 4763: break;
! 4764: }
! 4765: tmp = tmp->parent;
! 4766: }
! 4767: if (ns != NULL) {
! 4768: xmlSetProp(root, BAD_CAST "ns", ns);
! 4769: newNs = 1;
! 4770: xmlFree(ns);
! 4771: }
! 4772: } else {
! 4773: xmlFree(ns);
! 4774: }
! 4775:
! 4776: /*
! 4777: * Parsing to get a precompiled schemas.
! 4778: */
! 4779: oldflags = ctxt->flags;
! 4780: ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
! 4781: docu->schema = xmlRelaxNGParseDocument(ctxt, root);
! 4782: ctxt->flags = oldflags;
! 4783: if ((docu->schema != NULL) &&
! 4784: (docu->schema->topgrammar != NULL)) {
! 4785: docu->content = docu->schema->topgrammar->start;
! 4786: if (docu->schema->topgrammar->refs)
! 4787: xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
! 4788: }
! 4789:
! 4790: /*
! 4791: * the externalRef may be reused in a different ns context
! 4792: */
! 4793: if (newNs == 1) {
! 4794: xmlUnsetProp(root, BAD_CAST "ns");
! 4795: }
! 4796: }
! 4797: def->content = docu->content;
! 4798: } else {
! 4799: def = NULL;
! 4800: }
! 4801: return (def);
! 4802: }
! 4803:
! 4804: /**
! 4805: * xmlRelaxNGParsePattern:
! 4806: * @ctxt: a Relax-NG parser context
! 4807: * @node: the pattern node.
! 4808: *
! 4809: * parse the content of a RelaxNG pattern node.
! 4810: *
! 4811: * Returns the definition pointer or NULL in case of error or if no
! 4812: * pattern is generated.
! 4813: */
! 4814: static xmlRelaxNGDefinePtr
! 4815: xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 4816: {
! 4817: xmlRelaxNGDefinePtr def = NULL;
! 4818:
! 4819: if (node == NULL) {
! 4820: return (NULL);
! 4821: }
! 4822: if (IS_RELAXNG(node, "element")) {
! 4823: def = xmlRelaxNGParseElement(ctxt, node);
! 4824: } else if (IS_RELAXNG(node, "attribute")) {
! 4825: def = xmlRelaxNGParseAttribute(ctxt, node);
! 4826: } else if (IS_RELAXNG(node, "empty")) {
! 4827: def = xmlRelaxNGNewDefine(ctxt, node);
! 4828: if (def == NULL)
! 4829: return (NULL);
! 4830: def->type = XML_RELAXNG_EMPTY;
! 4831: if (node->children != NULL) {
! 4832: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
! 4833: "empty: had a child node\n", NULL, NULL);
! 4834: }
! 4835: } else if (IS_RELAXNG(node, "text")) {
! 4836: def = xmlRelaxNGNewDefine(ctxt, node);
! 4837: if (def == NULL)
! 4838: return (NULL);
! 4839: def->type = XML_RELAXNG_TEXT;
! 4840: if (node->children != NULL) {
! 4841: xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
! 4842: "text: had a child node\n", NULL, NULL);
! 4843: }
! 4844: } else if (IS_RELAXNG(node, "zeroOrMore")) {
! 4845: def = xmlRelaxNGNewDefine(ctxt, node);
! 4846: if (def == NULL)
! 4847: return (NULL);
! 4848: def->type = XML_RELAXNG_ZEROORMORE;
! 4849: if (node->children == NULL) {
! 4850: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4851: "Element %s is empty\n", node->name, NULL);
! 4852: } else {
! 4853: def->content =
! 4854: xmlRelaxNGParsePatterns(ctxt, node->children, 1);
! 4855: }
! 4856: } else if (IS_RELAXNG(node, "oneOrMore")) {
! 4857: def = xmlRelaxNGNewDefine(ctxt, node);
! 4858: if (def == NULL)
! 4859: return (NULL);
! 4860: def->type = XML_RELAXNG_ONEORMORE;
! 4861: if (node->children == NULL) {
! 4862: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4863: "Element %s is empty\n", node->name, NULL);
! 4864: } else {
! 4865: def->content =
! 4866: xmlRelaxNGParsePatterns(ctxt, node->children, 1);
! 4867: }
! 4868: } else if (IS_RELAXNG(node, "optional")) {
! 4869: def = xmlRelaxNGNewDefine(ctxt, node);
! 4870: if (def == NULL)
! 4871: return (NULL);
! 4872: def->type = XML_RELAXNG_OPTIONAL;
! 4873: if (node->children == NULL) {
! 4874: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4875: "Element %s is empty\n", node->name, NULL);
! 4876: } else {
! 4877: def->content =
! 4878: xmlRelaxNGParsePatterns(ctxt, node->children, 1);
! 4879: }
! 4880: } else if (IS_RELAXNG(node, "choice")) {
! 4881: def = xmlRelaxNGNewDefine(ctxt, node);
! 4882: if (def == NULL)
! 4883: return (NULL);
! 4884: def->type = XML_RELAXNG_CHOICE;
! 4885: if (node->children == NULL) {
! 4886: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4887: "Element %s is empty\n", node->name, NULL);
! 4888: } else {
! 4889: def->content =
! 4890: xmlRelaxNGParsePatterns(ctxt, node->children, 0);
! 4891: }
! 4892: } else if (IS_RELAXNG(node, "group")) {
! 4893: def = xmlRelaxNGNewDefine(ctxt, node);
! 4894: if (def == NULL)
! 4895: return (NULL);
! 4896: def->type = XML_RELAXNG_GROUP;
! 4897: if (node->children == NULL) {
! 4898: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4899: "Element %s is empty\n", node->name, NULL);
! 4900: } else {
! 4901: def->content =
! 4902: xmlRelaxNGParsePatterns(ctxt, node->children, 0);
! 4903: }
! 4904: } else if (IS_RELAXNG(node, "ref")) {
! 4905: def = xmlRelaxNGNewDefine(ctxt, node);
! 4906: if (def == NULL)
! 4907: return (NULL);
! 4908: def->type = XML_RELAXNG_REF;
! 4909: def->name = xmlGetProp(node, BAD_CAST "name");
! 4910: if (def->name == NULL) {
! 4911: xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
! 4912: NULL, NULL);
! 4913: } else {
! 4914: xmlRelaxNGNormExtSpace(def->name);
! 4915: if (xmlValidateNCName(def->name, 0)) {
! 4916: xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
! 4917: "ref name '%s' is not an NCName\n", def->name,
! 4918: NULL);
! 4919: }
! 4920: }
! 4921: if (node->children != NULL) {
! 4922: xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
! 4923: NULL, NULL);
! 4924: }
! 4925: if (ctxt->grammar->refs == NULL)
! 4926: ctxt->grammar->refs = xmlHashCreate(10);
! 4927: if (ctxt->grammar->refs == NULL) {
! 4928: xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
! 4929: "Could not create references hash\n", NULL, NULL);
! 4930: def = NULL;
! 4931: } else {
! 4932: int tmp;
! 4933:
! 4934: tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
! 4935: if (tmp < 0) {
! 4936: xmlRelaxNGDefinePtr prev;
! 4937:
! 4938: prev = (xmlRelaxNGDefinePtr)
! 4939: xmlHashLookup(ctxt->grammar->refs, def->name);
! 4940: if (prev == NULL) {
! 4941: if (def->name != NULL) {
! 4942: xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
! 4943: "Error refs definitions '%s'\n",
! 4944: def->name, NULL);
! 4945: } else {
! 4946: xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
! 4947: "Error refs definitions\n",
! 4948: NULL, NULL);
! 4949: }
! 4950: def = NULL;
! 4951: } else {
! 4952: def->nextHash = prev->nextHash;
! 4953: prev->nextHash = def;
! 4954: }
! 4955: }
! 4956: }
! 4957: } else if (IS_RELAXNG(node, "data")) {
! 4958: def = xmlRelaxNGParseData(ctxt, node);
! 4959: } else if (IS_RELAXNG(node, "value")) {
! 4960: def = xmlRelaxNGParseValue(ctxt, node);
! 4961: } else if (IS_RELAXNG(node, "list")) {
! 4962: def = xmlRelaxNGNewDefine(ctxt, node);
! 4963: if (def == NULL)
! 4964: return (NULL);
! 4965: def->type = XML_RELAXNG_LIST;
! 4966: if (node->children == NULL) {
! 4967: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
! 4968: "Element %s is empty\n", node->name, NULL);
! 4969: } else {
! 4970: def->content =
! 4971: xmlRelaxNGParsePatterns(ctxt, node->children, 0);
! 4972: }
! 4973: } else if (IS_RELAXNG(node, "interleave")) {
! 4974: def = xmlRelaxNGParseInterleave(ctxt, node);
! 4975: } else if (IS_RELAXNG(node, "externalRef")) {
! 4976: def = xmlRelaxNGProcessExternalRef(ctxt, node);
! 4977: } else if (IS_RELAXNG(node, "notAllowed")) {
! 4978: def = xmlRelaxNGNewDefine(ctxt, node);
! 4979: if (def == NULL)
! 4980: return (NULL);
! 4981: def->type = XML_RELAXNG_NOT_ALLOWED;
! 4982: if (node->children != NULL) {
! 4983: xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
! 4984: "xmlRelaxNGParse: notAllowed element is not empty\n",
! 4985: NULL, NULL);
! 4986: }
! 4987: } else if (IS_RELAXNG(node, "grammar")) {
! 4988: xmlRelaxNGGrammarPtr grammar, old;
! 4989: xmlRelaxNGGrammarPtr oldparent;
! 4990:
! 4991: #ifdef DEBUG_GRAMMAR
! 4992: xmlGenericError(xmlGenericErrorContext,
! 4993: "Found <grammar> pattern\n");
! 4994: #endif
! 4995:
! 4996: oldparent = ctxt->parentgrammar;
! 4997: old = ctxt->grammar;
! 4998: ctxt->parentgrammar = old;
! 4999: grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
! 5000: if (old != NULL) {
! 5001: ctxt->grammar = old;
! 5002: ctxt->parentgrammar = oldparent;
! 5003: #if 0
! 5004: if (grammar != NULL) {
! 5005: grammar->next = old->next;
! 5006: old->next = grammar;
! 5007: }
! 5008: #endif
! 5009: }
! 5010: if (grammar != NULL)
! 5011: def = grammar->start;
! 5012: else
! 5013: def = NULL;
! 5014: } else if (IS_RELAXNG(node, "parentRef")) {
! 5015: if (ctxt->parentgrammar == NULL) {
! 5016: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
! 5017: "Use of parentRef without a parent grammar\n", NULL,
! 5018: NULL);
! 5019: return (NULL);
! 5020: }
! 5021: def = xmlRelaxNGNewDefine(ctxt, node);
! 5022: if (def == NULL)
! 5023: return (NULL);
! 5024: def->type = XML_RELAXNG_PARENTREF;
! 5025: def->name = xmlGetProp(node, BAD_CAST "name");
! 5026: if (def->name == NULL) {
! 5027: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
! 5028: "parentRef has no name\n", NULL, NULL);
! 5029: } else {
! 5030: xmlRelaxNGNormExtSpace(def->name);
! 5031: if (xmlValidateNCName(def->name, 0)) {
! 5032: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
! 5033: "parentRef name '%s' is not an NCName\n",
! 5034: def->name, NULL);
! 5035: }
! 5036: }
! 5037: if (node->children != NULL) {
! 5038: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
! 5039: "parentRef is not empty\n", NULL, NULL);
! 5040: }
! 5041: if (ctxt->parentgrammar->refs == NULL)
! 5042: ctxt->parentgrammar->refs = xmlHashCreate(10);
! 5043: if (ctxt->parentgrammar->refs == NULL) {
! 5044: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
! 5045: "Could not create references hash\n", NULL, NULL);
! 5046: def = NULL;
! 5047: } else if (def->name != NULL) {
! 5048: int tmp;
! 5049:
! 5050: tmp =
! 5051: xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
! 5052: if (tmp < 0) {
! 5053: xmlRelaxNGDefinePtr prev;
! 5054:
! 5055: prev = (xmlRelaxNGDefinePtr)
! 5056: xmlHashLookup(ctxt->parentgrammar->refs, def->name);
! 5057: if (prev == NULL) {
! 5058: xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
! 5059: "Internal error parentRef definitions '%s'\n",
! 5060: def->name, NULL);
! 5061: def = NULL;
! 5062: } else {
! 5063: def->nextHash = prev->nextHash;
! 5064: prev->nextHash = def;
! 5065: }
! 5066: }
! 5067: }
! 5068: } else if (IS_RELAXNG(node, "mixed")) {
! 5069: if (node->children == NULL) {
! 5070: xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
! 5071: NULL, NULL);
! 5072: def = NULL;
! 5073: } else {
! 5074: def = xmlRelaxNGParseInterleave(ctxt, node);
! 5075: if (def != NULL) {
! 5076: xmlRelaxNGDefinePtr tmp;
! 5077:
! 5078: if ((def->content != NULL) && (def->content->next != NULL)) {
! 5079: tmp = xmlRelaxNGNewDefine(ctxt, node);
! 5080: if (tmp != NULL) {
! 5081: tmp->type = XML_RELAXNG_GROUP;
! 5082: tmp->content = def->content;
! 5083: def->content = tmp;
! 5084: }
! 5085: }
! 5086:
! 5087: tmp = xmlRelaxNGNewDefine(ctxt, node);
! 5088: if (tmp == NULL)
! 5089: return (def);
! 5090: tmp->type = XML_RELAXNG_TEXT;
! 5091: tmp->next = def->content;
! 5092: def->content = tmp;
! 5093: }
! 5094: }
! 5095: } else {
! 5096: xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
! 5097: "Unexpected node %s is not a pattern\n", node->name,
! 5098: NULL);
! 5099: def = NULL;
! 5100: }
! 5101: return (def);
! 5102: }
! 5103:
! 5104: /**
! 5105: * xmlRelaxNGParseAttribute:
! 5106: * @ctxt: a Relax-NG parser context
! 5107: * @node: the element node
! 5108: *
! 5109: * parse the content of a RelaxNG attribute node.
! 5110: *
! 5111: * Returns the definition pointer or NULL in case of error.
! 5112: */
! 5113: static xmlRelaxNGDefinePtr
! 5114: xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 5115: {
! 5116: xmlRelaxNGDefinePtr ret, cur;
! 5117: xmlNodePtr child;
! 5118: int old_flags;
! 5119:
! 5120: ret = xmlRelaxNGNewDefine(ctxt, node);
! 5121: if (ret == NULL)
! 5122: return (NULL);
! 5123: ret->type = XML_RELAXNG_ATTRIBUTE;
! 5124: ret->parent = ctxt->def;
! 5125: child = node->children;
! 5126: if (child == NULL) {
! 5127: xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
! 5128: "xmlRelaxNGParseattribute: attribute has no children\n",
! 5129: NULL, NULL);
! 5130: return (ret);
! 5131: }
! 5132: old_flags = ctxt->flags;
! 5133: ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
! 5134: cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
! 5135: if (cur != NULL)
! 5136: child = child->next;
! 5137:
! 5138: if (child != NULL) {
! 5139: cur = xmlRelaxNGParsePattern(ctxt, child);
! 5140: if (cur != NULL) {
! 5141: switch (cur->type) {
! 5142: case XML_RELAXNG_EMPTY:
! 5143: case XML_RELAXNG_NOT_ALLOWED:
! 5144: case XML_RELAXNG_TEXT:
! 5145: case XML_RELAXNG_ELEMENT:
! 5146: case XML_RELAXNG_DATATYPE:
! 5147: case XML_RELAXNG_VALUE:
! 5148: case XML_RELAXNG_LIST:
! 5149: case XML_RELAXNG_REF:
! 5150: case XML_RELAXNG_PARENTREF:
! 5151: case XML_RELAXNG_EXTERNALREF:
! 5152: case XML_RELAXNG_DEF:
! 5153: case XML_RELAXNG_ONEORMORE:
! 5154: case XML_RELAXNG_ZEROORMORE:
! 5155: case XML_RELAXNG_OPTIONAL:
! 5156: case XML_RELAXNG_CHOICE:
! 5157: case XML_RELAXNG_GROUP:
! 5158: case XML_RELAXNG_INTERLEAVE:
! 5159: case XML_RELAXNG_ATTRIBUTE:
! 5160: ret->content = cur;
! 5161: cur->parent = ret;
! 5162: break;
! 5163: case XML_RELAXNG_START:
! 5164: case XML_RELAXNG_PARAM:
! 5165: case XML_RELAXNG_EXCEPT:
! 5166: xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
! 5167: "attribute has invalid content\n", NULL,
! 5168: NULL);
! 5169: break;
! 5170: case XML_RELAXNG_NOOP:
! 5171: xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
! 5172: "RNG Internal error, noop found in attribute\n",
! 5173: NULL, NULL);
! 5174: break;
! 5175: }
! 5176: }
! 5177: child = child->next;
! 5178: }
! 5179: if (child != NULL) {
! 5180: xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
! 5181: "attribute has multiple children\n", NULL, NULL);
! 5182: }
! 5183: ctxt->flags = old_flags;
! 5184: return (ret);
! 5185: }
! 5186:
! 5187: /**
! 5188: * xmlRelaxNGParseExceptNameClass:
! 5189: * @ctxt: a Relax-NG parser context
! 5190: * @node: the except node
! 5191: * @attr: 1 if within an attribute, 0 if within an element
! 5192: *
! 5193: * parse the content of a RelaxNG nameClass node.
! 5194: *
! 5195: * Returns the definition pointer or NULL in case of error.
! 5196: */
! 5197: static xmlRelaxNGDefinePtr
! 5198: xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
! 5199: xmlNodePtr node, int attr)
! 5200: {
! 5201: xmlRelaxNGDefinePtr ret, cur, last = NULL;
! 5202: xmlNodePtr child;
! 5203:
! 5204: if (!IS_RELAXNG(node, "except")) {
! 5205: xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
! 5206: "Expecting an except node\n", NULL, NULL);
! 5207: return (NULL);
! 5208: }
! 5209: if (node->next != NULL) {
! 5210: xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
! 5211: "exceptNameClass allows only a single except node\n",
! 5212: NULL, NULL);
! 5213: }
! 5214: if (node->children == NULL) {
! 5215: xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
! 5216: NULL, NULL);
! 5217: return (NULL);
! 5218: }
! 5219:
! 5220: ret = xmlRelaxNGNewDefine(ctxt, node);
! 5221: if (ret == NULL)
! 5222: return (NULL);
! 5223: ret->type = XML_RELAXNG_EXCEPT;
! 5224: child = node->children;
! 5225: while (child != NULL) {
! 5226: cur = xmlRelaxNGNewDefine(ctxt, child);
! 5227: if (cur == NULL)
! 5228: break;
! 5229: if (attr)
! 5230: cur->type = XML_RELAXNG_ATTRIBUTE;
! 5231: else
! 5232: cur->type = XML_RELAXNG_ELEMENT;
! 5233:
! 5234: if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
! 5235: if (last == NULL) {
! 5236: ret->content = cur;
! 5237: } else {
! 5238: last->next = cur;
! 5239: }
! 5240: last = cur;
! 5241: }
! 5242: child = child->next;
! 5243: }
! 5244:
! 5245: return (ret);
! 5246: }
! 5247:
! 5248: /**
! 5249: * xmlRelaxNGParseNameClass:
! 5250: * @ctxt: a Relax-NG parser context
! 5251: * @node: the nameClass node
! 5252: * @def: the current definition
! 5253: *
! 5254: * parse the content of a RelaxNG nameClass node.
! 5255: *
! 5256: * Returns the definition pointer or NULL in case of error.
! 5257: */
! 5258: static xmlRelaxNGDefinePtr
! 5259: xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
! 5260: xmlRelaxNGDefinePtr def)
! 5261: {
! 5262: xmlRelaxNGDefinePtr ret, tmp;
! 5263: xmlChar *val;
! 5264:
! 5265: ret = def;
! 5266: if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
! 5267: (IS_RELAXNG(node, "nsName"))) {
! 5268: if ((def->type != XML_RELAXNG_ELEMENT) &&
! 5269: (def->type != XML_RELAXNG_ATTRIBUTE)) {
! 5270: ret = xmlRelaxNGNewDefine(ctxt, node);
! 5271: if (ret == NULL)
! 5272: return (NULL);
! 5273: ret->parent = def;
! 5274: if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
! 5275: ret->type = XML_RELAXNG_ATTRIBUTE;
! 5276: else
! 5277: ret->type = XML_RELAXNG_ELEMENT;
! 5278: }
! 5279: }
! 5280: if (IS_RELAXNG(node, "name")) {
! 5281: val = xmlNodeGetContent(node);
! 5282: xmlRelaxNGNormExtSpace(val);
! 5283: if (xmlValidateNCName(val, 0)) {
! 5284: if (node->parent != NULL)
! 5285: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
! 5286: "Element %s name '%s' is not an NCName\n",
! 5287: node->parent->name, val);
! 5288: else
! 5289: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
! 5290: "name '%s' is not an NCName\n",
! 5291: val, NULL);
! 5292: }
! 5293: ret->name = val;
! 5294: val = xmlGetProp(node, BAD_CAST "ns");
! 5295: ret->ns = val;
! 5296: if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
! 5297: (val != NULL) &&
! 5298: (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
! 5299: xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
! 5300: "Attribute with namespace '%s' is not allowed\n",
! 5301: val, NULL);
! 5302: }
! 5303: if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
! 5304: (val != NULL) &&
! 5305: (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
! 5306: xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
! 5307: "Attribute with QName 'xmlns' is not allowed\n",
! 5308: val, NULL);
! 5309: }
! 5310: } else if (IS_RELAXNG(node, "anyName")) {
! 5311: ret->name = NULL;
! 5312: ret->ns = NULL;
! 5313: if (node->children != NULL) {
! 5314: ret->nameClass =
! 5315: xmlRelaxNGParseExceptNameClass(ctxt, node->children,
! 5316: (def->type ==
! 5317: XML_RELAXNG_ATTRIBUTE));
! 5318: }
! 5319: } else if (IS_RELAXNG(node, "nsName")) {
! 5320: ret->name = NULL;
! 5321: ret->ns = xmlGetProp(node, BAD_CAST "ns");
! 5322: if (ret->ns == NULL) {
! 5323: xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
! 5324: "nsName has no ns attribute\n", NULL, NULL);
! 5325: }
! 5326: if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
! 5327: (ret->ns != NULL) &&
! 5328: (xmlStrEqual
! 5329: (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
! 5330: xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
! 5331: "Attribute with namespace '%s' is not allowed\n",
! 5332: ret->ns, NULL);
! 5333: }
! 5334: if (node->children != NULL) {
! 5335: ret->nameClass =
! 5336: xmlRelaxNGParseExceptNameClass(ctxt, node->children,
! 5337: (def->type ==
! 5338: XML_RELAXNG_ATTRIBUTE));
! 5339: }
! 5340: } else if (IS_RELAXNG(node, "choice")) {
! 5341: xmlNodePtr child;
! 5342: xmlRelaxNGDefinePtr last = NULL;
! 5343:
! 5344: ret = xmlRelaxNGNewDefine(ctxt, node);
! 5345: if (ret == NULL)
! 5346: return (NULL);
! 5347: ret->parent = def;
! 5348: ret->type = XML_RELAXNG_CHOICE;
! 5349:
! 5350: if (node->children == NULL) {
! 5351: xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
! 5352: "Element choice is empty\n", NULL, NULL);
! 5353: } else {
! 5354:
! 5355: child = node->children;
! 5356: while (child != NULL) {
! 5357: tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
! 5358: if (tmp != NULL) {
! 5359: if (last == NULL) {
! 5360: last = ret->nameClass = tmp;
! 5361: } else {
! 5362: last->next = tmp;
! 5363: last = tmp;
! 5364: }
! 5365: }
! 5366: child = child->next;
! 5367: }
! 5368: }
! 5369: } else {
! 5370: xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
! 5371: "expecting name, anyName, nsName or choice : got %s\n",
! 5372: (node == NULL ? (const xmlChar *) "nothing" : node->name),
! 5373: NULL);
! 5374: return (NULL);
! 5375: }
! 5376: if (ret != def) {
! 5377: if (def->nameClass == NULL) {
! 5378: def->nameClass = ret;
! 5379: } else {
! 5380: tmp = def->nameClass;
! 5381: while (tmp->next != NULL) {
! 5382: tmp = tmp->next;
! 5383: }
! 5384: tmp->next = ret;
! 5385: }
! 5386: }
! 5387: return (ret);
! 5388: }
! 5389:
! 5390: /**
! 5391: * xmlRelaxNGParseElement:
! 5392: * @ctxt: a Relax-NG parser context
! 5393: * @node: the element node
! 5394: *
! 5395: * parse the content of a RelaxNG element node.
! 5396: *
! 5397: * Returns the definition pointer or NULL in case of error.
! 5398: */
! 5399: static xmlRelaxNGDefinePtr
! 5400: xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 5401: {
! 5402: xmlRelaxNGDefinePtr ret, cur, last;
! 5403: xmlNodePtr child;
! 5404: const xmlChar *olddefine;
! 5405:
! 5406: ret = xmlRelaxNGNewDefine(ctxt, node);
! 5407: if (ret == NULL)
! 5408: return (NULL);
! 5409: ret->type = XML_RELAXNG_ELEMENT;
! 5410: ret->parent = ctxt->def;
! 5411: child = node->children;
! 5412: if (child == NULL) {
! 5413: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
! 5414: "xmlRelaxNGParseElement: element has no children\n",
! 5415: NULL, NULL);
! 5416: return (ret);
! 5417: }
! 5418: cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
! 5419: if (cur != NULL)
! 5420: child = child->next;
! 5421:
! 5422: if (child == NULL) {
! 5423: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
! 5424: "xmlRelaxNGParseElement: element has no content\n",
! 5425: NULL, NULL);
! 5426: return (ret);
! 5427: }
! 5428: olddefine = ctxt->define;
! 5429: ctxt->define = NULL;
! 5430: last = NULL;
! 5431: while (child != NULL) {
! 5432: cur = xmlRelaxNGParsePattern(ctxt, child);
! 5433: if (cur != NULL) {
! 5434: cur->parent = ret;
! 5435: switch (cur->type) {
! 5436: case XML_RELAXNG_EMPTY:
! 5437: case XML_RELAXNG_NOT_ALLOWED:
! 5438: case XML_RELAXNG_TEXT:
! 5439: case XML_RELAXNG_ELEMENT:
! 5440: case XML_RELAXNG_DATATYPE:
! 5441: case XML_RELAXNG_VALUE:
! 5442: case XML_RELAXNG_LIST:
! 5443: case XML_RELAXNG_REF:
! 5444: case XML_RELAXNG_PARENTREF:
! 5445: case XML_RELAXNG_EXTERNALREF:
! 5446: case XML_RELAXNG_DEF:
! 5447: case XML_RELAXNG_ZEROORMORE:
! 5448: case XML_RELAXNG_ONEORMORE:
! 5449: case XML_RELAXNG_OPTIONAL:
! 5450: case XML_RELAXNG_CHOICE:
! 5451: case XML_RELAXNG_GROUP:
! 5452: case XML_RELAXNG_INTERLEAVE:
! 5453: if (last == NULL) {
! 5454: ret->content = last = cur;
! 5455: } else {
! 5456: if ((last->type == XML_RELAXNG_ELEMENT) &&
! 5457: (ret->content == last)) {
! 5458: ret->content = xmlRelaxNGNewDefine(ctxt, node);
! 5459: if (ret->content != NULL) {
! 5460: ret->content->type = XML_RELAXNG_GROUP;
! 5461: ret->content->content = last;
! 5462: } else {
! 5463: ret->content = last;
! 5464: }
! 5465: }
! 5466: last->next = cur;
! 5467: last = cur;
! 5468: }
! 5469: break;
! 5470: case XML_RELAXNG_ATTRIBUTE:
! 5471: cur->next = ret->attrs;
! 5472: ret->attrs = cur;
! 5473: break;
! 5474: case XML_RELAXNG_START:
! 5475: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
! 5476: "RNG Internal error, start found in element\n",
! 5477: NULL, NULL);
! 5478: break;
! 5479: case XML_RELAXNG_PARAM:
! 5480: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
! 5481: "RNG Internal error, param found in element\n",
! 5482: NULL, NULL);
! 5483: break;
! 5484: case XML_RELAXNG_EXCEPT:
! 5485: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
! 5486: "RNG Internal error, except found in element\n",
! 5487: NULL, NULL);
! 5488: break;
! 5489: case XML_RELAXNG_NOOP:
! 5490: xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
! 5491: "RNG Internal error, noop found in element\n",
! 5492: NULL, NULL);
! 5493: break;
! 5494: }
! 5495: }
! 5496: child = child->next;
! 5497: }
! 5498: ctxt->define = olddefine;
! 5499: return (ret);
! 5500: }
! 5501:
! 5502: /**
! 5503: * xmlRelaxNGParsePatterns:
! 5504: * @ctxt: a Relax-NG parser context
! 5505: * @nodes: list of nodes
! 5506: * @group: use an implicit <group> for elements
! 5507: *
! 5508: * parse the content of a RelaxNG start node.
! 5509: *
! 5510: * Returns the definition pointer or NULL in case of error.
! 5511: */
! 5512: static xmlRelaxNGDefinePtr
! 5513: xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
! 5514: int group)
! 5515: {
! 5516: xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
! 5517:
! 5518: parent = ctxt->def;
! 5519: while (nodes != NULL) {
! 5520: if (IS_RELAXNG(nodes, "element")) {
! 5521: cur = xmlRelaxNGParseElement(ctxt, nodes);
! 5522: if (def == NULL) {
! 5523: def = last = cur;
! 5524: } else {
! 5525: if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
! 5526: (def == last)) {
! 5527: def = xmlRelaxNGNewDefine(ctxt, nodes);
! 5528: def->type = XML_RELAXNG_GROUP;
! 5529: def->content = last;
! 5530: }
! 5531: last->next = cur;
! 5532: last = cur;
! 5533: }
! 5534: cur->parent = parent;
! 5535: } else {
! 5536: cur = xmlRelaxNGParsePattern(ctxt, nodes);
! 5537: if (cur != NULL) {
! 5538: if (def == NULL) {
! 5539: def = last = cur;
! 5540: } else {
! 5541: last->next = cur;
! 5542: last = cur;
! 5543: }
! 5544: }
! 5545: }
! 5546: nodes = nodes->next;
! 5547: }
! 5548: return (def);
! 5549: }
! 5550:
! 5551: /**
! 5552: * xmlRelaxNGParseStart:
! 5553: * @ctxt: a Relax-NG parser context
! 5554: * @nodes: start children nodes
! 5555: *
! 5556: * parse the content of a RelaxNG start node.
! 5557: *
! 5558: * Returns 0 in case of success, -1 in case of error
! 5559: */
! 5560: static int
! 5561: xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
! 5562: {
! 5563: int ret = 0;
! 5564: xmlRelaxNGDefinePtr def = NULL, last;
! 5565:
! 5566: if (nodes == NULL) {
! 5567: xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
! 5568: NULL, NULL);
! 5569: return (-1);
! 5570: }
! 5571: if (IS_RELAXNG(nodes, "empty")) {
! 5572: def = xmlRelaxNGNewDefine(ctxt, nodes);
! 5573: if (def == NULL)
! 5574: return (-1);
! 5575: def->type = XML_RELAXNG_EMPTY;
! 5576: if (nodes->children != NULL) {
! 5577: xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
! 5578: "element empty is not empty\n", NULL, NULL);
! 5579: }
! 5580: } else if (IS_RELAXNG(nodes, "notAllowed")) {
! 5581: def = xmlRelaxNGNewDefine(ctxt, nodes);
! 5582: if (def == NULL)
! 5583: return (-1);
! 5584: def->type = XML_RELAXNG_NOT_ALLOWED;
! 5585: if (nodes->children != NULL) {
! 5586: xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
! 5587: "element notAllowed is not empty\n", NULL, NULL);
! 5588: }
! 5589: } else {
! 5590: def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
! 5591: }
! 5592: if (ctxt->grammar->start != NULL) {
! 5593: last = ctxt->grammar->start;
! 5594: while (last->next != NULL)
! 5595: last = last->next;
! 5596: last->next = def;
! 5597: } else {
! 5598: ctxt->grammar->start = def;
! 5599: }
! 5600: nodes = nodes->next;
! 5601: if (nodes != NULL) {
! 5602: xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
! 5603: "start more than one children\n", NULL, NULL);
! 5604: return (-1);
! 5605: }
! 5606: return (ret);
! 5607: }
! 5608:
! 5609: /**
! 5610: * xmlRelaxNGParseGrammarContent:
! 5611: * @ctxt: a Relax-NG parser context
! 5612: * @nodes: grammar children nodes
! 5613: *
! 5614: * parse the content of a RelaxNG grammar node.
! 5615: *
! 5616: * Returns 0 in case of success, -1 in case of error
! 5617: */
! 5618: static int
! 5619: xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
! 5620: xmlNodePtr nodes)
! 5621: {
! 5622: int ret = 0, tmp;
! 5623:
! 5624: if (nodes == NULL) {
! 5625: xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
! 5626: "grammar has no children\n", NULL, NULL);
! 5627: return (-1);
! 5628: }
! 5629: while (nodes != NULL) {
! 5630: if (IS_RELAXNG(nodes, "start")) {
! 5631: if (nodes->children == NULL) {
! 5632: xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
! 5633: "start has no children\n", NULL, NULL);
! 5634: } else {
! 5635: tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
! 5636: if (tmp != 0)
! 5637: ret = -1;
! 5638: }
! 5639: } else if (IS_RELAXNG(nodes, "define")) {
! 5640: tmp = xmlRelaxNGParseDefine(ctxt, nodes);
! 5641: if (tmp != 0)
! 5642: ret = -1;
! 5643: } else if (IS_RELAXNG(nodes, "include")) {
! 5644: tmp = xmlRelaxNGParseInclude(ctxt, nodes);
! 5645: if (tmp != 0)
! 5646: ret = -1;
! 5647: } else {
! 5648: xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
! 5649: "grammar has unexpected child %s\n", nodes->name,
! 5650: NULL);
! 5651: ret = -1;
! 5652: }
! 5653: nodes = nodes->next;
! 5654: }
! 5655: return (ret);
! 5656: }
! 5657:
! 5658: /**
! 5659: * xmlRelaxNGCheckReference:
! 5660: * @ref: the ref
! 5661: * @ctxt: a Relax-NG parser context
! 5662: * @name: the name associated to the defines
! 5663: *
! 5664: * Applies the 4.17. combine attribute rule for all the define
! 5665: * element of a given grammar using the same name.
! 5666: */
! 5667: static void
! 5668: xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
! 5669: xmlRelaxNGParserCtxtPtr ctxt,
! 5670: const xmlChar * name)
! 5671: {
! 5672: xmlRelaxNGGrammarPtr grammar;
! 5673: xmlRelaxNGDefinePtr def, cur;
! 5674:
! 5675: /*
! 5676: * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
! 5677: */
! 5678: if (ref->dflags & IS_EXTERNAL_REF)
! 5679: return;
! 5680:
! 5681: grammar = ctxt->grammar;
! 5682: if (grammar == NULL) {
! 5683: xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
! 5684: "Internal error: no grammar in CheckReference %s\n",
! 5685: name, NULL);
! 5686: return;
! 5687: }
! 5688: if (ref->content != NULL) {
! 5689: xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
! 5690: "Internal error: reference has content in CheckReference %s\n",
! 5691: name, NULL);
! 5692: return;
! 5693: }
! 5694: if (grammar->defs != NULL) {
! 5695: def = xmlHashLookup(grammar->defs, name);
! 5696: if (def != NULL) {
! 5697: cur = ref;
! 5698: while (cur != NULL) {
! 5699: cur->content = def;
! 5700: cur = cur->nextHash;
! 5701: }
! 5702: } else {
! 5703: xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
! 5704: "Reference %s has no matching definition\n", name,
! 5705: NULL);
! 5706: }
! 5707: } else {
! 5708: xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
! 5709: "Reference %s has no matching definition\n", name,
! 5710: NULL);
! 5711: }
! 5712: }
! 5713:
! 5714: /**
! 5715: * xmlRelaxNGCheckCombine:
! 5716: * @define: the define(s) list
! 5717: * @ctxt: a Relax-NG parser context
! 5718: * @name: the name associated to the defines
! 5719: *
! 5720: * Applies the 4.17. combine attribute rule for all the define
! 5721: * element of a given grammar using the same name.
! 5722: */
! 5723: static void
! 5724: xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
! 5725: xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
! 5726: {
! 5727: xmlChar *combine;
! 5728: int choiceOrInterleave = -1;
! 5729: int missing = 0;
! 5730: xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
! 5731:
! 5732: if (define->nextHash == NULL)
! 5733: return;
! 5734: cur = define;
! 5735: while (cur != NULL) {
! 5736: combine = xmlGetProp(cur->node, BAD_CAST "combine");
! 5737: if (combine != NULL) {
! 5738: if (xmlStrEqual(combine, BAD_CAST "choice")) {
! 5739: if (choiceOrInterleave == -1)
! 5740: choiceOrInterleave = 1;
! 5741: else if (choiceOrInterleave == 0) {
! 5742: xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
! 5743: "Defines for %s use both 'choice' and 'interleave'\n",
! 5744: name, NULL);
! 5745: }
! 5746: } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
! 5747: if (choiceOrInterleave == -1)
! 5748: choiceOrInterleave = 0;
! 5749: else if (choiceOrInterleave == 1) {
! 5750: xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
! 5751: "Defines for %s use both 'choice' and 'interleave'\n",
! 5752: name, NULL);
! 5753: }
! 5754: } else {
! 5755: xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
! 5756: "Defines for %s use unknown combine value '%s''\n",
! 5757: name, combine);
! 5758: }
! 5759: xmlFree(combine);
! 5760: } else {
! 5761: if (missing == 0)
! 5762: missing = 1;
! 5763: else {
! 5764: xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
! 5765: "Some defines for %s needs the combine attribute\n",
! 5766: name, NULL);
! 5767: }
! 5768: }
! 5769:
! 5770: cur = cur->nextHash;
! 5771: }
! 5772: #ifdef DEBUG
! 5773: xmlGenericError(xmlGenericErrorContext,
! 5774: "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
! 5775: name, choiceOrInterleave);
! 5776: #endif
! 5777: if (choiceOrInterleave == -1)
! 5778: choiceOrInterleave = 0;
! 5779: cur = xmlRelaxNGNewDefine(ctxt, define->node);
! 5780: if (cur == NULL)
! 5781: return;
! 5782: if (choiceOrInterleave == 0)
! 5783: cur->type = XML_RELAXNG_INTERLEAVE;
! 5784: else
! 5785: cur->type = XML_RELAXNG_CHOICE;
! 5786: tmp = define;
! 5787: last = NULL;
! 5788: while (tmp != NULL) {
! 5789: if (tmp->content != NULL) {
! 5790: if (tmp->content->next != NULL) {
! 5791: /*
! 5792: * we need first to create a wrapper.
! 5793: */
! 5794: tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
! 5795: if (tmp2 == NULL)
! 5796: break;
! 5797: tmp2->type = XML_RELAXNG_GROUP;
! 5798: tmp2->content = tmp->content;
! 5799: } else {
! 5800: tmp2 = tmp->content;
! 5801: }
! 5802: if (last == NULL) {
! 5803: cur->content = tmp2;
! 5804: } else {
! 5805: last->next = tmp2;
! 5806: }
! 5807: last = tmp2;
! 5808: }
! 5809: tmp->content = cur;
! 5810: tmp = tmp->nextHash;
! 5811: }
! 5812: define->content = cur;
! 5813: if (choiceOrInterleave == 0) {
! 5814: if (ctxt->interleaves == NULL)
! 5815: ctxt->interleaves = xmlHashCreate(10);
! 5816: if (ctxt->interleaves == NULL) {
! 5817: xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
! 5818: "Failed to create interleaves hash table\n", NULL,
! 5819: NULL);
! 5820: } else {
! 5821: char tmpname[32];
! 5822:
! 5823: snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
! 5824: if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
! 5825: 0) {
! 5826: xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
! 5827: "Failed to add %s to hash table\n",
! 5828: (const xmlChar *) tmpname, NULL);
! 5829: }
! 5830: }
! 5831: }
! 5832: }
! 5833:
! 5834: /**
! 5835: * xmlRelaxNGCombineStart:
! 5836: * @ctxt: a Relax-NG parser context
! 5837: * @grammar: the grammar
! 5838: *
! 5839: * Applies the 4.17. combine rule for all the start
! 5840: * element of a given grammar.
! 5841: */
! 5842: static void
! 5843: xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
! 5844: xmlRelaxNGGrammarPtr grammar)
! 5845: {
! 5846: xmlRelaxNGDefinePtr starts;
! 5847: xmlChar *combine;
! 5848: int choiceOrInterleave = -1;
! 5849: int missing = 0;
! 5850: xmlRelaxNGDefinePtr cur;
! 5851:
! 5852: starts = grammar->start;
! 5853: if ((starts == NULL) || (starts->next == NULL))
! 5854: return;
! 5855: cur = starts;
! 5856: while (cur != NULL) {
! 5857: if ((cur->node == NULL) || (cur->node->parent == NULL) ||
! 5858: (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
! 5859: combine = NULL;
! 5860: xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
! 5861: "Internal error: start element not found\n", NULL,
! 5862: NULL);
! 5863: } else {
! 5864: combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
! 5865: }
! 5866:
! 5867: if (combine != NULL) {
! 5868: if (xmlStrEqual(combine, BAD_CAST "choice")) {
! 5869: if (choiceOrInterleave == -1)
! 5870: choiceOrInterleave = 1;
! 5871: else if (choiceOrInterleave == 0) {
! 5872: xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
! 5873: "<start> use both 'choice' and 'interleave'\n",
! 5874: NULL, NULL);
! 5875: }
! 5876: } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
! 5877: if (choiceOrInterleave == -1)
! 5878: choiceOrInterleave = 0;
! 5879: else if (choiceOrInterleave == 1) {
! 5880: xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
! 5881: "<start> use both 'choice' and 'interleave'\n",
! 5882: NULL, NULL);
! 5883: }
! 5884: } else {
! 5885: xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
! 5886: "<start> uses unknown combine value '%s''\n",
! 5887: combine, NULL);
! 5888: }
! 5889: xmlFree(combine);
! 5890: } else {
! 5891: if (missing == 0)
! 5892: missing = 1;
! 5893: else {
! 5894: xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
! 5895: "Some <start> element miss the combine attribute\n",
! 5896: NULL, NULL);
! 5897: }
! 5898: }
! 5899:
! 5900: cur = cur->next;
! 5901: }
! 5902: #ifdef DEBUG
! 5903: xmlGenericError(xmlGenericErrorContext,
! 5904: "xmlRelaxNGCombineStart(): merging <start>: %d\n",
! 5905: choiceOrInterleave);
! 5906: #endif
! 5907: if (choiceOrInterleave == -1)
! 5908: choiceOrInterleave = 0;
! 5909: cur = xmlRelaxNGNewDefine(ctxt, starts->node);
! 5910: if (cur == NULL)
! 5911: return;
! 5912: if (choiceOrInterleave == 0)
! 5913: cur->type = XML_RELAXNG_INTERLEAVE;
! 5914: else
! 5915: cur->type = XML_RELAXNG_CHOICE;
! 5916: cur->content = grammar->start;
! 5917: grammar->start = cur;
! 5918: if (choiceOrInterleave == 0) {
! 5919: if (ctxt->interleaves == NULL)
! 5920: ctxt->interleaves = xmlHashCreate(10);
! 5921: if (ctxt->interleaves == NULL) {
! 5922: xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
! 5923: "Failed to create interleaves hash table\n", NULL,
! 5924: NULL);
! 5925: } else {
! 5926: char tmpname[32];
! 5927:
! 5928: snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
! 5929: if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
! 5930: 0) {
! 5931: xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
! 5932: "Failed to add %s to hash table\n",
! 5933: (const xmlChar *) tmpname, NULL);
! 5934: }
! 5935: }
! 5936: }
! 5937: }
! 5938:
! 5939: /**
! 5940: * xmlRelaxNGCheckCycles:
! 5941: * @ctxt: a Relax-NG parser context
! 5942: * @nodes: grammar children nodes
! 5943: * @depth: the counter
! 5944: *
! 5945: * Check for cycles.
! 5946: *
! 5947: * Returns 0 if check passed, and -1 in case of error
! 5948: */
! 5949: static int
! 5950: xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
! 5951: xmlRelaxNGDefinePtr cur, int depth)
! 5952: {
! 5953: int ret = 0;
! 5954:
! 5955: while ((ret == 0) && (cur != NULL)) {
! 5956: if ((cur->type == XML_RELAXNG_REF) ||
! 5957: (cur->type == XML_RELAXNG_PARENTREF)) {
! 5958: if (cur->depth == -1) {
! 5959: cur->depth = depth;
! 5960: ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
! 5961: cur->depth = -2;
! 5962: } else if (depth == cur->depth) {
! 5963: xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
! 5964: "Detected a cycle in %s references\n",
! 5965: cur->name, NULL);
! 5966: return (-1);
! 5967: }
! 5968: } else if (cur->type == XML_RELAXNG_ELEMENT) {
! 5969: ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
! 5970: } else {
! 5971: ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
! 5972: }
! 5973: cur = cur->next;
! 5974: }
! 5975: return (ret);
! 5976: }
! 5977:
! 5978: /**
! 5979: * xmlRelaxNGTryUnlink:
! 5980: * @ctxt: a Relax-NG parser context
! 5981: * @cur: the definition to unlink
! 5982: * @parent: the parent definition
! 5983: * @prev: the previous sibling definition
! 5984: *
! 5985: * Try to unlink a definition. If not possble make it a NOOP
! 5986: *
! 5987: * Returns the new prev definition
! 5988: */
! 5989: static xmlRelaxNGDefinePtr
! 5990: xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
! 5991: xmlRelaxNGDefinePtr cur,
! 5992: xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
! 5993: {
! 5994: if (prev != NULL) {
! 5995: prev->next = cur->next;
! 5996: } else {
! 5997: if (parent != NULL) {
! 5998: if (parent->content == cur)
! 5999: parent->content = cur->next;
! 6000: else if (parent->attrs == cur)
! 6001: parent->attrs = cur->next;
! 6002: else if (parent->nameClass == cur)
! 6003: parent->nameClass = cur->next;
! 6004: } else {
! 6005: cur->type = XML_RELAXNG_NOOP;
! 6006: prev = cur;
! 6007: }
! 6008: }
! 6009: return (prev);
! 6010: }
! 6011:
! 6012: /**
! 6013: * xmlRelaxNGSimplify:
! 6014: * @ctxt: a Relax-NG parser context
! 6015: * @nodes: grammar children nodes
! 6016: *
! 6017: * Check for simplification of empty and notAllowed
! 6018: */
! 6019: static void
! 6020: xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
! 6021: xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
! 6022: {
! 6023: xmlRelaxNGDefinePtr prev = NULL;
! 6024:
! 6025: while (cur != NULL) {
! 6026: if ((cur->type == XML_RELAXNG_REF) ||
! 6027: (cur->type == XML_RELAXNG_PARENTREF)) {
! 6028: if (cur->depth != -3) {
! 6029: cur->depth = -3;
! 6030: xmlRelaxNGSimplify(ctxt, cur->content, cur);
! 6031: }
! 6032: } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
! 6033: cur->parent = parent;
! 6034: if ((parent != NULL) &&
! 6035: ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
! 6036: (parent->type == XML_RELAXNG_LIST) ||
! 6037: (parent->type == XML_RELAXNG_GROUP) ||
! 6038: (parent->type == XML_RELAXNG_INTERLEAVE) ||
! 6039: (parent->type == XML_RELAXNG_ONEORMORE) ||
! 6040: (parent->type == XML_RELAXNG_ZEROORMORE))) {
! 6041: parent->type = XML_RELAXNG_NOT_ALLOWED;
! 6042: break;
! 6043: }
! 6044: if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
! 6045: prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
! 6046: } else
! 6047: prev = cur;
! 6048: } else if (cur->type == XML_RELAXNG_EMPTY) {
! 6049: cur->parent = parent;
! 6050: if ((parent != NULL) &&
! 6051: ((parent->type == XML_RELAXNG_ONEORMORE) ||
! 6052: (parent->type == XML_RELAXNG_ZEROORMORE))) {
! 6053: parent->type = XML_RELAXNG_EMPTY;
! 6054: break;
! 6055: }
! 6056: if ((parent != NULL) &&
! 6057: ((parent->type == XML_RELAXNG_GROUP) ||
! 6058: (parent->type == XML_RELAXNG_INTERLEAVE))) {
! 6059: prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
! 6060: } else
! 6061: prev = cur;
! 6062: } else {
! 6063: cur->parent = parent;
! 6064: if (cur->content != NULL)
! 6065: xmlRelaxNGSimplify(ctxt, cur->content, cur);
! 6066: if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
! 6067: xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
! 6068: if (cur->nameClass != NULL)
! 6069: xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
! 6070: /*
! 6071: * On Elements, try to move attribute only generating rules on
! 6072: * the attrs rules.
! 6073: */
! 6074: if (cur->type == XML_RELAXNG_ELEMENT) {
! 6075: int attronly;
! 6076: xmlRelaxNGDefinePtr tmp, pre;
! 6077:
! 6078: while (cur->content != NULL) {
! 6079: attronly =
! 6080: xmlRelaxNGGenerateAttributes(ctxt, cur->content);
! 6081: if (attronly == 1) {
! 6082: /*
! 6083: * migrate cur->content to attrs
! 6084: */
! 6085: tmp = cur->content;
! 6086: cur->content = tmp->next;
! 6087: tmp->next = cur->attrs;
! 6088: cur->attrs = tmp;
! 6089: } else {
! 6090: /*
! 6091: * cur->content can generate elements or text
! 6092: */
! 6093: break;
! 6094: }
! 6095: }
! 6096: pre = cur->content;
! 6097: while ((pre != NULL) && (pre->next != NULL)) {
! 6098: tmp = pre->next;
! 6099: attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
! 6100: if (attronly == 1) {
! 6101: /*
! 6102: * migrate tmp to attrs
! 6103: */
! 6104: pre->next = tmp->next;
! 6105: tmp->next = cur->attrs;
! 6106: cur->attrs = tmp;
! 6107: } else {
! 6108: pre = tmp;
! 6109: }
! 6110: }
! 6111: }
! 6112: /*
! 6113: * This may result in a simplification
! 6114: */
! 6115: if ((cur->type == XML_RELAXNG_GROUP) ||
! 6116: (cur->type == XML_RELAXNG_INTERLEAVE)) {
! 6117: if (cur->content == NULL)
! 6118: cur->type = XML_RELAXNG_EMPTY;
! 6119: else if (cur->content->next == NULL) {
! 6120: if ((parent == NULL) && (prev == NULL)) {
! 6121: cur->type = XML_RELAXNG_NOOP;
! 6122: } else if (prev == NULL) {
! 6123: parent->content = cur->content;
! 6124: cur->content->next = cur->next;
! 6125: cur = cur->content;
! 6126: } else {
! 6127: cur->content->next = cur->next;
! 6128: prev->next = cur->content;
! 6129: cur = cur->content;
! 6130: }
! 6131: }
! 6132: }
! 6133: /*
! 6134: * the current node may have been transformed back
! 6135: */
! 6136: if ((cur->type == XML_RELAXNG_EXCEPT) &&
! 6137: (cur->content != NULL) &&
! 6138: (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
! 6139: prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
! 6140: } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
! 6141: if ((parent != NULL) &&
! 6142: ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
! 6143: (parent->type == XML_RELAXNG_LIST) ||
! 6144: (parent->type == XML_RELAXNG_GROUP) ||
! 6145: (parent->type == XML_RELAXNG_INTERLEAVE) ||
! 6146: (parent->type == XML_RELAXNG_ONEORMORE) ||
! 6147: (parent->type == XML_RELAXNG_ZEROORMORE))) {
! 6148: parent->type = XML_RELAXNG_NOT_ALLOWED;
! 6149: break;
! 6150: }
! 6151: if ((parent != NULL) &&
! 6152: (parent->type == XML_RELAXNG_CHOICE)) {
! 6153: prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
! 6154: } else
! 6155: prev = cur;
! 6156: } else if (cur->type == XML_RELAXNG_EMPTY) {
! 6157: if ((parent != NULL) &&
! 6158: ((parent->type == XML_RELAXNG_ONEORMORE) ||
! 6159: (parent->type == XML_RELAXNG_ZEROORMORE))) {
! 6160: parent->type = XML_RELAXNG_EMPTY;
! 6161: break;
! 6162: }
! 6163: if ((parent != NULL) &&
! 6164: ((parent->type == XML_RELAXNG_GROUP) ||
! 6165: (parent->type == XML_RELAXNG_INTERLEAVE) ||
! 6166: (parent->type == XML_RELAXNG_CHOICE))) {
! 6167: prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
! 6168: } else
! 6169: prev = cur;
! 6170: } else {
! 6171: prev = cur;
! 6172: }
! 6173: }
! 6174: cur = cur->next;
! 6175: }
! 6176: }
! 6177:
! 6178: /**
! 6179: * xmlRelaxNGGroupContentType:
! 6180: * @ct1: the first content type
! 6181: * @ct2: the second content type
! 6182: *
! 6183: * Try to group 2 content types
! 6184: *
! 6185: * Returns the content type
! 6186: */
! 6187: static xmlRelaxNGContentType
! 6188: xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
! 6189: xmlRelaxNGContentType ct2)
! 6190: {
! 6191: if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
! 6192: (ct2 == XML_RELAXNG_CONTENT_ERROR))
! 6193: return (XML_RELAXNG_CONTENT_ERROR);
! 6194: if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
! 6195: return (ct2);
! 6196: if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
! 6197: return (ct1);
! 6198: if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
! 6199: (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
! 6200: return (XML_RELAXNG_CONTENT_COMPLEX);
! 6201: return (XML_RELAXNG_CONTENT_ERROR);
! 6202: }
! 6203:
! 6204: /**
! 6205: * xmlRelaxNGMaxContentType:
! 6206: * @ct1: the first content type
! 6207: * @ct2: the second content type
! 6208: *
! 6209: * Compute the max content-type
! 6210: *
! 6211: * Returns the content type
! 6212: */
! 6213: static xmlRelaxNGContentType
! 6214: xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
! 6215: xmlRelaxNGContentType ct2)
! 6216: {
! 6217: if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
! 6218: (ct2 == XML_RELAXNG_CONTENT_ERROR))
! 6219: return (XML_RELAXNG_CONTENT_ERROR);
! 6220: if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
! 6221: (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
! 6222: return (XML_RELAXNG_CONTENT_SIMPLE);
! 6223: if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
! 6224: (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
! 6225: return (XML_RELAXNG_CONTENT_COMPLEX);
! 6226: return (XML_RELAXNG_CONTENT_EMPTY);
! 6227: }
! 6228:
! 6229: /**
! 6230: * xmlRelaxNGCheckRules:
! 6231: * @ctxt: a Relax-NG parser context
! 6232: * @cur: the current definition
! 6233: * @flags: some accumulated flags
! 6234: * @ptype: the parent type
! 6235: *
! 6236: * Check for rules in section 7.1 and 7.2
! 6237: *
! 6238: * Returns the content type of @cur
! 6239: */
! 6240: static xmlRelaxNGContentType
! 6241: xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
! 6242: xmlRelaxNGDefinePtr cur, int flags,
! 6243: xmlRelaxNGType ptype)
! 6244: {
! 6245: int nflags;
! 6246: xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
! 6247:
! 6248: while (cur != NULL) {
! 6249: ret = XML_RELAXNG_CONTENT_EMPTY;
! 6250: if ((cur->type == XML_RELAXNG_REF) ||
! 6251: (cur->type == XML_RELAXNG_PARENTREF)) {
! 6252: /*
! 6253: * This should actually be caught by list//element(ref) at the
! 6254: * element boundaries, c.f. Bug #159968 local refs are dropped
! 6255: * in step 4.19.
! 6256: */
! 6257: #if 0
! 6258: if (flags & XML_RELAXNG_IN_LIST) {
! 6259: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
! 6260: "Found forbidden pattern list//ref\n", NULL,
! 6261: NULL);
! 6262: }
! 6263: #endif
! 6264: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6265: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
! 6266: "Found forbidden pattern data/except//ref\n",
! 6267: NULL, NULL);
! 6268: }
! 6269: if (cur->content == NULL) {
! 6270: if (cur->type == XML_RELAXNG_PARENTREF)
! 6271: xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
! 6272: "Internal found no define for parent refs\n",
! 6273: NULL, NULL);
! 6274: else
! 6275: xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
! 6276: "Internal found no define for ref %s\n",
! 6277: (cur->name ? cur->name: BAD_CAST "null"), NULL);
! 6278: }
! 6279: if (cur->depth > -4) {
! 6280: cur->depth = -4;
! 6281: ret = xmlRelaxNGCheckRules(ctxt, cur->content,
! 6282: flags, cur->type);
! 6283: cur->depth = ret - 15;
! 6284: } else if (cur->depth == -4) {
! 6285: ret = XML_RELAXNG_CONTENT_COMPLEX;
! 6286: } else {
! 6287: ret = (xmlRelaxNGContentType) (cur->depth + 15);
! 6288: }
! 6289: } else if (cur->type == XML_RELAXNG_ELEMENT) {
! 6290: /*
! 6291: * The 7.3 Attribute derivation rule for groups is plugged there
! 6292: */
! 6293: xmlRelaxNGCheckGroupAttrs(ctxt, cur);
! 6294: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6295: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
! 6296: "Found forbidden pattern data/except//element(ref)\n",
! 6297: NULL, NULL);
! 6298: }
! 6299: if (flags & XML_RELAXNG_IN_LIST) {
! 6300: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
! 6301: "Found forbidden pattern list//element(ref)\n",
! 6302: NULL, NULL);
! 6303: }
! 6304: if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
! 6305: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
! 6306: "Found forbidden pattern attribute//element(ref)\n",
! 6307: NULL, NULL);
! 6308: }
! 6309: if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
! 6310: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
! 6311: "Found forbidden pattern attribute//element(ref)\n",
! 6312: NULL, NULL);
! 6313: }
! 6314: /*
! 6315: * reset since in the simple form elements are only child
! 6316: * of grammar/define
! 6317: */
! 6318: nflags = 0;
! 6319: ret =
! 6320: xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
! 6321: if (ret != XML_RELAXNG_CONTENT_EMPTY) {
! 6322: xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
! 6323: "Element %s attributes have a content type error\n",
! 6324: cur->name, NULL);
! 6325: }
! 6326: ret =
! 6327: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6328: cur->type);
! 6329: if (ret == XML_RELAXNG_CONTENT_ERROR) {
! 6330: xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
! 6331: "Element %s has a content type error\n",
! 6332: cur->name, NULL);
! 6333: } else {
! 6334: ret = XML_RELAXNG_CONTENT_COMPLEX;
! 6335: }
! 6336: } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
! 6337: if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
! 6338: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
! 6339: "Found forbidden pattern attribute//attribute\n",
! 6340: NULL, NULL);
! 6341: }
! 6342: if (flags & XML_RELAXNG_IN_LIST) {
! 6343: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
! 6344: "Found forbidden pattern list//attribute\n",
! 6345: NULL, NULL);
! 6346: }
! 6347: if (flags & XML_RELAXNG_IN_OOMGROUP) {
! 6348: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
! 6349: "Found forbidden pattern oneOrMore//group//attribute\n",
! 6350: NULL, NULL);
! 6351: }
! 6352: if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
! 6353: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
! 6354: "Found forbidden pattern oneOrMore//interleave//attribute\n",
! 6355: NULL, NULL);
! 6356: }
! 6357: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6358: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
! 6359: "Found forbidden pattern data/except//attribute\n",
! 6360: NULL, NULL);
! 6361: }
! 6362: if (flags & XML_RELAXNG_IN_START) {
! 6363: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
! 6364: "Found forbidden pattern start//attribute\n",
! 6365: NULL, NULL);
! 6366: }
! 6367: if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
! 6368: && (cur->name == NULL)) {
! 6369: if (cur->ns == NULL) {
! 6370: xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
! 6371: "Found anyName attribute without oneOrMore ancestor\n",
! 6372: NULL, NULL);
! 6373: } else {
! 6374: xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
! 6375: "Found nsName attribute without oneOrMore ancestor\n",
! 6376: NULL, NULL);
! 6377: }
! 6378: }
! 6379: nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
! 6380: xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
! 6381: ret = XML_RELAXNG_CONTENT_EMPTY;
! 6382: } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
! 6383: (cur->type == XML_RELAXNG_ZEROORMORE)) {
! 6384: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6385: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
! 6386: "Found forbidden pattern data/except//oneOrMore\n",
! 6387: NULL, NULL);
! 6388: }
! 6389: if (flags & XML_RELAXNG_IN_START) {
! 6390: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
! 6391: "Found forbidden pattern start//oneOrMore\n",
! 6392: NULL, NULL);
! 6393: }
! 6394: nflags = flags | XML_RELAXNG_IN_ONEORMORE;
! 6395: ret =
! 6396: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6397: cur->type);
! 6398: ret = xmlRelaxNGGroupContentType(ret, ret);
! 6399: } else if (cur->type == XML_RELAXNG_LIST) {
! 6400: if (flags & XML_RELAXNG_IN_LIST) {
! 6401: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
! 6402: "Found forbidden pattern list//list\n", NULL,
! 6403: NULL);
! 6404: }
! 6405: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6406: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
! 6407: "Found forbidden pattern data/except//list\n",
! 6408: NULL, NULL);
! 6409: }
! 6410: if (flags & XML_RELAXNG_IN_START) {
! 6411: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
! 6412: "Found forbidden pattern start//list\n", NULL,
! 6413: NULL);
! 6414: }
! 6415: nflags = flags | XML_RELAXNG_IN_LIST;
! 6416: ret =
! 6417: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6418: cur->type);
! 6419: } else if (cur->type == XML_RELAXNG_GROUP) {
! 6420: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6421: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
! 6422: "Found forbidden pattern data/except//group\n",
! 6423: NULL, NULL);
! 6424: }
! 6425: if (flags & XML_RELAXNG_IN_START) {
! 6426: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
! 6427: "Found forbidden pattern start//group\n", NULL,
! 6428: NULL);
! 6429: }
! 6430: if (flags & XML_RELAXNG_IN_ONEORMORE)
! 6431: nflags = flags | XML_RELAXNG_IN_OOMGROUP;
! 6432: else
! 6433: nflags = flags;
! 6434: ret =
! 6435: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6436: cur->type);
! 6437: /*
! 6438: * The 7.3 Attribute derivation rule for groups is plugged there
! 6439: */
! 6440: xmlRelaxNGCheckGroupAttrs(ctxt, cur);
! 6441: } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
! 6442: if (flags & XML_RELAXNG_IN_LIST) {
! 6443: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
! 6444: "Found forbidden pattern list//interleave\n",
! 6445: NULL, NULL);
! 6446: }
! 6447: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6448: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
! 6449: "Found forbidden pattern data/except//interleave\n",
! 6450: NULL, NULL);
! 6451: }
! 6452: if (flags & XML_RELAXNG_IN_START) {
! 6453: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
! 6454: "Found forbidden pattern start//interleave\n",
! 6455: NULL, NULL);
! 6456: }
! 6457: if (flags & XML_RELAXNG_IN_ONEORMORE)
! 6458: nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
! 6459: else
! 6460: nflags = flags;
! 6461: ret =
! 6462: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6463: cur->type);
! 6464: } else if (cur->type == XML_RELAXNG_EXCEPT) {
! 6465: if ((cur->parent != NULL) &&
! 6466: (cur->parent->type == XML_RELAXNG_DATATYPE))
! 6467: nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
! 6468: else
! 6469: nflags = flags;
! 6470: ret =
! 6471: xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
! 6472: cur->type);
! 6473: } else if (cur->type == XML_RELAXNG_DATATYPE) {
! 6474: if (flags & XML_RELAXNG_IN_START) {
! 6475: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
! 6476: "Found forbidden pattern start//data\n", NULL,
! 6477: NULL);
! 6478: }
! 6479: xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
! 6480: ret = XML_RELAXNG_CONTENT_SIMPLE;
! 6481: } else if (cur->type == XML_RELAXNG_VALUE) {
! 6482: if (flags & XML_RELAXNG_IN_START) {
! 6483: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
! 6484: "Found forbidden pattern start//value\n", NULL,
! 6485: NULL);
! 6486: }
! 6487: xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
! 6488: ret = XML_RELAXNG_CONTENT_SIMPLE;
! 6489: } else if (cur->type == XML_RELAXNG_TEXT) {
! 6490: if (flags & XML_RELAXNG_IN_LIST) {
! 6491: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
! 6492: "Found forbidden pattern list//text\n", NULL,
! 6493: NULL);
! 6494: }
! 6495: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6496: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
! 6497: "Found forbidden pattern data/except//text\n",
! 6498: NULL, NULL);
! 6499: }
! 6500: if (flags & XML_RELAXNG_IN_START) {
! 6501: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
! 6502: "Found forbidden pattern start//text\n", NULL,
! 6503: NULL);
! 6504: }
! 6505: ret = XML_RELAXNG_CONTENT_COMPLEX;
! 6506: } else if (cur->type == XML_RELAXNG_EMPTY) {
! 6507: if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
! 6508: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
! 6509: "Found forbidden pattern data/except//empty\n",
! 6510: NULL, NULL);
! 6511: }
! 6512: if (flags & XML_RELAXNG_IN_START) {
! 6513: xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
! 6514: "Found forbidden pattern start//empty\n", NULL,
! 6515: NULL);
! 6516: }
! 6517: ret = XML_RELAXNG_CONTENT_EMPTY;
! 6518: } else if (cur->type == XML_RELAXNG_CHOICE) {
! 6519: xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
! 6520: ret =
! 6521: xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
! 6522: } else {
! 6523: ret =
! 6524: xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
! 6525: }
! 6526: cur = cur->next;
! 6527: if (ptype == XML_RELAXNG_GROUP) {
! 6528: val = xmlRelaxNGGroupContentType(val, ret);
! 6529: } else if (ptype == XML_RELAXNG_INTERLEAVE) {
! 6530: /*
! 6531: * TODO: scan complain that tmp is never used, seems on purpose
! 6532: * need double-checking
! 6533: */
! 6534: tmp = xmlRelaxNGGroupContentType(val, ret);
! 6535: if (tmp != XML_RELAXNG_CONTENT_ERROR)
! 6536: tmp = xmlRelaxNGMaxContentType(val, ret);
! 6537: } else if (ptype == XML_RELAXNG_CHOICE) {
! 6538: val = xmlRelaxNGMaxContentType(val, ret);
! 6539: } else if (ptype == XML_RELAXNG_LIST) {
! 6540: val = XML_RELAXNG_CONTENT_SIMPLE;
! 6541: } else if (ptype == XML_RELAXNG_EXCEPT) {
! 6542: if (ret == XML_RELAXNG_CONTENT_ERROR)
! 6543: val = XML_RELAXNG_CONTENT_ERROR;
! 6544: else
! 6545: val = XML_RELAXNG_CONTENT_SIMPLE;
! 6546: } else {
! 6547: val = xmlRelaxNGGroupContentType(val, ret);
! 6548: }
! 6549:
! 6550: }
! 6551: return (val);
! 6552: }
! 6553:
! 6554: /**
! 6555: * xmlRelaxNGParseGrammar:
! 6556: * @ctxt: a Relax-NG parser context
! 6557: * @nodes: grammar children nodes
! 6558: *
! 6559: * parse a Relax-NG <grammar> node
! 6560: *
! 6561: * Returns the internal xmlRelaxNGGrammarPtr built or
! 6562: * NULL in case of error
! 6563: */
! 6564: static xmlRelaxNGGrammarPtr
! 6565: xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
! 6566: {
! 6567: xmlRelaxNGGrammarPtr ret, tmp, old;
! 6568:
! 6569: #ifdef DEBUG_GRAMMAR
! 6570: xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
! 6571: #endif
! 6572:
! 6573: ret = xmlRelaxNGNewGrammar(ctxt);
! 6574: if (ret == NULL)
! 6575: return (NULL);
! 6576:
! 6577: /*
! 6578: * Link the new grammar in the tree
! 6579: */
! 6580: ret->parent = ctxt->grammar;
! 6581: if (ctxt->grammar != NULL) {
! 6582: tmp = ctxt->grammar->children;
! 6583: if (tmp == NULL) {
! 6584: ctxt->grammar->children = ret;
! 6585: } else {
! 6586: while (tmp->next != NULL)
! 6587: tmp = tmp->next;
! 6588: tmp->next = ret;
! 6589: }
! 6590: }
! 6591:
! 6592: old = ctxt->grammar;
! 6593: ctxt->grammar = ret;
! 6594: xmlRelaxNGParseGrammarContent(ctxt, nodes);
! 6595: ctxt->grammar = ret;
! 6596: if (ctxt->grammar == NULL) {
! 6597: xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
! 6598: "Failed to parse <grammar> content\n", NULL, NULL);
! 6599: } else if (ctxt->grammar->start == NULL) {
! 6600: xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
! 6601: "Element <grammar> has no <start>\n", NULL, NULL);
! 6602: }
! 6603:
! 6604: /*
! 6605: * Apply 4.17 mergingd rules to defines and starts
! 6606: */
! 6607: xmlRelaxNGCombineStart(ctxt, ret);
! 6608: if (ret->defs != NULL) {
! 6609: xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
! 6610: ctxt);
! 6611: }
! 6612:
! 6613: /*
! 6614: * link together defines and refs in this grammar
! 6615: */
! 6616: if (ret->refs != NULL) {
! 6617: xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
! 6618: ctxt);
! 6619: }
! 6620:
! 6621:
! 6622: /* @@@@ */
! 6623:
! 6624: ctxt->grammar = old;
! 6625: return (ret);
! 6626: }
! 6627:
! 6628: /**
! 6629: * xmlRelaxNGParseDocument:
! 6630: * @ctxt: a Relax-NG parser context
! 6631: * @node: the root node of the RelaxNG schema
! 6632: *
! 6633: * parse a Relax-NG definition resource and build an internal
! 6634: * xmlRelaxNG struture which can be used to validate instances.
! 6635: *
! 6636: * Returns the internal XML RelaxNG structure built or
! 6637: * NULL in case of error
! 6638: */
! 6639: static xmlRelaxNGPtr
! 6640: xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 6641: {
! 6642: xmlRelaxNGPtr schema = NULL;
! 6643: const xmlChar *olddefine;
! 6644: xmlRelaxNGGrammarPtr old;
! 6645:
! 6646: if ((ctxt == NULL) || (node == NULL))
! 6647: return (NULL);
! 6648:
! 6649: schema = xmlRelaxNGNewRelaxNG(ctxt);
! 6650: if (schema == NULL)
! 6651: return (NULL);
! 6652:
! 6653: olddefine = ctxt->define;
! 6654: ctxt->define = NULL;
! 6655: if (IS_RELAXNG(node, "grammar")) {
! 6656: schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
! 6657: } else {
! 6658: xmlRelaxNGGrammarPtr tmp, ret;
! 6659:
! 6660: schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
! 6661: if (schema->topgrammar == NULL) {
! 6662: return (schema);
! 6663: }
! 6664: /*
! 6665: * Link the new grammar in the tree
! 6666: */
! 6667: ret->parent = ctxt->grammar;
! 6668: if (ctxt->grammar != NULL) {
! 6669: tmp = ctxt->grammar->children;
! 6670: if (tmp == NULL) {
! 6671: ctxt->grammar->children = ret;
! 6672: } else {
! 6673: while (tmp->next != NULL)
! 6674: tmp = tmp->next;
! 6675: tmp->next = ret;
! 6676: }
! 6677: }
! 6678: old = ctxt->grammar;
! 6679: ctxt->grammar = ret;
! 6680: xmlRelaxNGParseStart(ctxt, node);
! 6681: if (old != NULL)
! 6682: ctxt->grammar = old;
! 6683: }
! 6684: ctxt->define = olddefine;
! 6685: if (schema->topgrammar->start != NULL) {
! 6686: xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
! 6687: if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
! 6688: xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
! 6689: while ((schema->topgrammar->start != NULL) &&
! 6690: (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
! 6691: (schema->topgrammar->start->next != NULL))
! 6692: schema->topgrammar->start =
! 6693: schema->topgrammar->start->content;
! 6694: xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
! 6695: XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
! 6696: }
! 6697: }
! 6698: #ifdef DEBUG
! 6699: if (schema == NULL)
! 6700: xmlGenericError(xmlGenericErrorContext,
! 6701: "xmlRelaxNGParseDocument() failed\n");
! 6702: #endif
! 6703:
! 6704: return (schema);
! 6705: }
! 6706:
! 6707: /************************************************************************
! 6708: * *
! 6709: * Reading RelaxNGs *
! 6710: * *
! 6711: ************************************************************************/
! 6712:
! 6713: /**
! 6714: * xmlRelaxNGNewParserCtxt:
! 6715: * @URL: the location of the schema
! 6716: *
! 6717: * Create an XML RelaxNGs parse context for that file/resource expected
! 6718: * to contain an XML RelaxNGs file.
! 6719: *
! 6720: * Returns the parser context or NULL in case of error
! 6721: */
! 6722: xmlRelaxNGParserCtxtPtr
! 6723: xmlRelaxNGNewParserCtxt(const char *URL)
! 6724: {
! 6725: xmlRelaxNGParserCtxtPtr ret;
! 6726:
! 6727: if (URL == NULL)
! 6728: return (NULL);
! 6729:
! 6730: ret =
! 6731: (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
! 6732: if (ret == NULL) {
! 6733: xmlRngPErrMemory(NULL, "building parser\n");
! 6734: return (NULL);
! 6735: }
! 6736: memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
! 6737: ret->URL = xmlStrdup((const xmlChar *) URL);
! 6738: ret->error = xmlGenericError;
! 6739: ret->userData = xmlGenericErrorContext;
! 6740: return (ret);
! 6741: }
! 6742:
! 6743: /**
! 6744: * xmlRelaxNGNewMemParserCtxt:
! 6745: * @buffer: a pointer to a char array containing the schemas
! 6746: * @size: the size of the array
! 6747: *
! 6748: * Create an XML RelaxNGs parse context for that memory buffer expected
! 6749: * to contain an XML RelaxNGs file.
! 6750: *
! 6751: * Returns the parser context or NULL in case of error
! 6752: */
! 6753: xmlRelaxNGParserCtxtPtr
! 6754: xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
! 6755: {
! 6756: xmlRelaxNGParserCtxtPtr ret;
! 6757:
! 6758: if ((buffer == NULL) || (size <= 0))
! 6759: return (NULL);
! 6760:
! 6761: ret =
! 6762: (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
! 6763: if (ret == NULL) {
! 6764: xmlRngPErrMemory(NULL, "building parser\n");
! 6765: return (NULL);
! 6766: }
! 6767: memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
! 6768: ret->buffer = buffer;
! 6769: ret->size = size;
! 6770: ret->error = xmlGenericError;
! 6771: ret->userData = xmlGenericErrorContext;
! 6772: return (ret);
! 6773: }
! 6774:
! 6775: /**
! 6776: * xmlRelaxNGNewDocParserCtxt:
! 6777: * @doc: a preparsed document tree
! 6778: *
! 6779: * Create an XML RelaxNGs parser context for that document.
! 6780: * Note: since the process of compiling a RelaxNG schemas modifies the
! 6781: * document, the @doc parameter is duplicated internally.
! 6782: *
! 6783: * Returns the parser context or NULL in case of error
! 6784: */
! 6785: xmlRelaxNGParserCtxtPtr
! 6786: xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
! 6787: {
! 6788: xmlRelaxNGParserCtxtPtr ret;
! 6789: xmlDocPtr copy;
! 6790:
! 6791: if (doc == NULL)
! 6792: return (NULL);
! 6793: copy = xmlCopyDoc(doc, 1);
! 6794: if (copy == NULL)
! 6795: return (NULL);
! 6796:
! 6797: ret =
! 6798: (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
! 6799: if (ret == NULL) {
! 6800: xmlRngPErrMemory(NULL, "building parser\n");
! 6801: return (NULL);
! 6802: }
! 6803: memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
! 6804: ret->document = copy;
! 6805: ret->freedoc = 1;
! 6806: ret->userData = xmlGenericErrorContext;
! 6807: return (ret);
! 6808: }
! 6809:
! 6810: /**
! 6811: * xmlRelaxNGFreeParserCtxt:
! 6812: * @ctxt: the schema parser context
! 6813: *
! 6814: * Free the resources associated to the schema parser context
! 6815: */
! 6816: void
! 6817: xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
! 6818: {
! 6819: if (ctxt == NULL)
! 6820: return;
! 6821: if (ctxt->URL != NULL)
! 6822: xmlFree(ctxt->URL);
! 6823: if (ctxt->doc != NULL)
! 6824: xmlRelaxNGFreeDocument(ctxt->doc);
! 6825: if (ctxt->interleaves != NULL)
! 6826: xmlHashFree(ctxt->interleaves, NULL);
! 6827: if (ctxt->documents != NULL)
! 6828: xmlRelaxNGFreeDocumentList(ctxt->documents);
! 6829: if (ctxt->includes != NULL)
! 6830: xmlRelaxNGFreeIncludeList(ctxt->includes);
! 6831: if (ctxt->docTab != NULL)
! 6832: xmlFree(ctxt->docTab);
! 6833: if (ctxt->incTab != NULL)
! 6834: xmlFree(ctxt->incTab);
! 6835: if (ctxt->defTab != NULL) {
! 6836: int i;
! 6837:
! 6838: for (i = 0; i < ctxt->defNr; i++)
! 6839: xmlRelaxNGFreeDefine(ctxt->defTab[i]);
! 6840: xmlFree(ctxt->defTab);
! 6841: }
! 6842: if ((ctxt->document != NULL) && (ctxt->freedoc))
! 6843: xmlFreeDoc(ctxt->document);
! 6844: xmlFree(ctxt);
! 6845: }
! 6846:
! 6847: /**
! 6848: * xmlRelaxNGNormExtSpace:
! 6849: * @value: a value
! 6850: *
! 6851: * Removes the leading and ending spaces of the value
! 6852: * The string is modified "in situ"
! 6853: */
! 6854: static void
! 6855: xmlRelaxNGNormExtSpace(xmlChar * value)
! 6856: {
! 6857: xmlChar *start = value;
! 6858: xmlChar *cur = value;
! 6859:
! 6860: if (value == NULL)
! 6861: return;
! 6862:
! 6863: while (IS_BLANK_CH(*cur))
! 6864: cur++;
! 6865: if (cur == start) {
! 6866: do {
! 6867: while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
! 6868: cur++;
! 6869: if (*cur == 0)
! 6870: return;
! 6871: start = cur;
! 6872: while (IS_BLANK_CH(*cur))
! 6873: cur++;
! 6874: if (*cur == 0) {
! 6875: *start = 0;
! 6876: return;
! 6877: }
! 6878: } while (1);
! 6879: } else {
! 6880: do {
! 6881: while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
! 6882: *start++ = *cur++;
! 6883: if (*cur == 0) {
! 6884: *start = 0;
! 6885: return;
! 6886: }
! 6887: /* don't try to normalize the inner spaces */
! 6888: while (IS_BLANK_CH(*cur))
! 6889: cur++;
! 6890: if (*cur == 0) {
! 6891: *start = 0;
! 6892: return;
! 6893: }
! 6894: *start++ = *cur++;
! 6895: } while (1);
! 6896: }
! 6897: }
! 6898:
! 6899: /**
! 6900: * xmlRelaxNGCleanupAttributes:
! 6901: * @ctxt: a Relax-NG parser context
! 6902: * @node: a Relax-NG node
! 6903: *
! 6904: * Check all the attributes on the given node
! 6905: */
! 6906: static void
! 6907: xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
! 6908: {
! 6909: xmlAttrPtr cur, next;
! 6910:
! 6911: cur = node->properties;
! 6912: while (cur != NULL) {
! 6913: next = cur->next;
! 6914: if ((cur->ns == NULL) ||
! 6915: (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
! 6916: if (xmlStrEqual(cur->name, BAD_CAST "name")) {
! 6917: if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
! 6918: (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
! 6919: (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
! 6920: (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
! 6921: (!xmlStrEqual(node->name, BAD_CAST "param")) &&
! 6922: (!xmlStrEqual(node->name, BAD_CAST "define"))) {
! 6923: xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
! 6924: "Attribute %s is not allowed on %s\n",
! 6925: cur->name, node->name);
! 6926: }
! 6927: } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
! 6928: if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
! 6929: (!xmlStrEqual(node->name, BAD_CAST "data"))) {
! 6930: xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
! 6931: "Attribute %s is not allowed on %s\n",
! 6932: cur->name, node->name);
! 6933: }
! 6934: } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
! 6935: if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
! 6936: (!xmlStrEqual(node->name, BAD_CAST "include"))) {
! 6937: xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
! 6938: "Attribute %s is not allowed on %s\n",
! 6939: cur->name, node->name);
! 6940: }
! 6941: } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
! 6942: if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
! 6943: (!xmlStrEqual(node->name, BAD_CAST "define"))) {
! 6944: xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
! 6945: "Attribute %s is not allowed on %s\n",
! 6946: cur->name, node->name);
! 6947: }
! 6948: } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
! 6949: xmlChar *val;
! 6950: xmlURIPtr uri;
! 6951:
! 6952: val = xmlNodeListGetString(node->doc, cur->children, 1);
! 6953: if (val != NULL) {
! 6954: if (val[0] != 0) {
! 6955: uri = xmlParseURI((const char *) val);
! 6956: if (uri == NULL) {
! 6957: xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
! 6958: "Attribute %s contains invalid URI %s\n",
! 6959: cur->name, val);
! 6960: } else {
! 6961: if (uri->scheme == NULL) {
! 6962: xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
! 6963: "Attribute %s URI %s is not absolute\n",
! 6964: cur->name, val);
! 6965: }
! 6966: if (uri->fragment != NULL) {
! 6967: xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
! 6968: "Attribute %s URI %s has a fragment ID\n",
! 6969: cur->name, val);
! 6970: }
! 6971: xmlFreeURI(uri);
! 6972: }
! 6973: }
! 6974: xmlFree(val);
! 6975: }
! 6976: } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
! 6977: xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
! 6978: "Unknown attribute %s on %s\n", cur->name,
! 6979: node->name);
! 6980: }
! 6981: }
! 6982: cur = next;
! 6983: }
! 6984: }
! 6985:
! 6986: /**
! 6987: * xmlRelaxNGCleanupTree:
! 6988: * @ctxt: a Relax-NG parser context
! 6989: * @root: an xmlNodePtr subtree
! 6990: *
! 6991: * Cleanup the subtree from unwanted nodes for parsing, resolve
! 6992: * Include and externalRef lookups.
! 6993: */
! 6994: static void
! 6995: xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
! 6996: {
! 6997: xmlNodePtr cur, delete;
! 6998:
! 6999: delete = NULL;
! 7000: cur = root;
! 7001: while (cur != NULL) {
! 7002: if (delete != NULL) {
! 7003: xmlUnlinkNode(delete);
! 7004: xmlFreeNode(delete);
! 7005: delete = NULL;
! 7006: }
! 7007: if (cur->type == XML_ELEMENT_NODE) {
! 7008: /*
! 7009: * Simplification 4.1. Annotations
! 7010: */
! 7011: if ((cur->ns == NULL) ||
! 7012: (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
! 7013: if ((cur->parent != NULL) &&
! 7014: (cur->parent->type == XML_ELEMENT_NODE) &&
! 7015: ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
! 7016: (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
! 7017: (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
! 7018: xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
! 7019: "element %s doesn't allow foreign elements\n",
! 7020: cur->parent->name, NULL);
! 7021: }
! 7022: delete = cur;
! 7023: goto skip_children;
! 7024: } else {
! 7025: xmlRelaxNGCleanupAttributes(ctxt, cur);
! 7026: if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
! 7027: xmlChar *href, *ns, *base, *URL;
! 7028: xmlRelaxNGDocumentPtr docu;
! 7029: xmlNodePtr tmp;
! 7030: xmlURIPtr uri;
! 7031:
! 7032: ns = xmlGetProp(cur, BAD_CAST "ns");
! 7033: if (ns == NULL) {
! 7034: tmp = cur->parent;
! 7035: while ((tmp != NULL) &&
! 7036: (tmp->type == XML_ELEMENT_NODE)) {
! 7037: ns = xmlGetProp(tmp, BAD_CAST "ns");
! 7038: if (ns != NULL)
! 7039: break;
! 7040: tmp = tmp->parent;
! 7041: }
! 7042: }
! 7043: href = xmlGetProp(cur, BAD_CAST "href");
! 7044: if (href == NULL) {
! 7045: xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
! 7046: "xmlRelaxNGParse: externalRef has no href attribute\n",
! 7047: NULL, NULL);
! 7048: if (ns != NULL)
! 7049: xmlFree(ns);
! 7050: delete = cur;
! 7051: goto skip_children;
! 7052: }
! 7053: uri = xmlParseURI((const char *) href);
! 7054: if (uri == NULL) {
! 7055: xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
! 7056: "Incorrect URI for externalRef %s\n",
! 7057: href, NULL);
! 7058: if (ns != NULL)
! 7059: xmlFree(ns);
! 7060: if (href != NULL)
! 7061: xmlFree(href);
! 7062: delete = cur;
! 7063: goto skip_children;
! 7064: }
! 7065: if (uri->fragment != NULL) {
! 7066: xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
! 7067: "Fragment forbidden in URI for externalRef %s\n",
! 7068: href, NULL);
! 7069: if (ns != NULL)
! 7070: xmlFree(ns);
! 7071: xmlFreeURI(uri);
! 7072: if (href != NULL)
! 7073: xmlFree(href);
! 7074: delete = cur;
! 7075: goto skip_children;
! 7076: }
! 7077: xmlFreeURI(uri);
! 7078: base = xmlNodeGetBase(cur->doc, cur);
! 7079: URL = xmlBuildURI(href, base);
! 7080: if (URL == NULL) {
! 7081: xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
! 7082: "Failed to compute URL for externalRef %s\n",
! 7083: href, NULL);
! 7084: if (ns != NULL)
! 7085: xmlFree(ns);
! 7086: if (href != NULL)
! 7087: xmlFree(href);
! 7088: if (base != NULL)
! 7089: xmlFree(base);
! 7090: delete = cur;
! 7091: goto skip_children;
! 7092: }
! 7093: if (href != NULL)
! 7094: xmlFree(href);
! 7095: if (base != NULL)
! 7096: xmlFree(base);
! 7097: docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
! 7098: if (docu == NULL) {
! 7099: xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
! 7100: "Failed to load externalRef %s\n", URL,
! 7101: NULL);
! 7102: if (ns != NULL)
! 7103: xmlFree(ns);
! 7104: xmlFree(URL);
! 7105: delete = cur;
! 7106: goto skip_children;
! 7107: }
! 7108: if (ns != NULL)
! 7109: xmlFree(ns);
! 7110: xmlFree(URL);
! 7111: cur->psvi = docu;
! 7112: } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
! 7113: xmlChar *href, *ns, *base, *URL;
! 7114: xmlRelaxNGIncludePtr incl;
! 7115: xmlNodePtr tmp;
! 7116:
! 7117: href = xmlGetProp(cur, BAD_CAST "href");
! 7118: if (href == NULL) {
! 7119: xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
! 7120: "xmlRelaxNGParse: include has no href attribute\n",
! 7121: NULL, NULL);
! 7122: delete = cur;
! 7123: goto skip_children;
! 7124: }
! 7125: base = xmlNodeGetBase(cur->doc, cur);
! 7126: URL = xmlBuildURI(href, base);
! 7127: if (URL == NULL) {
! 7128: xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
! 7129: "Failed to compute URL for include %s\n",
! 7130: href, NULL);
! 7131: if (href != NULL)
! 7132: xmlFree(href);
! 7133: if (base != NULL)
! 7134: xmlFree(base);
! 7135: delete = cur;
! 7136: goto skip_children;
! 7137: }
! 7138: if (href != NULL)
! 7139: xmlFree(href);
! 7140: if (base != NULL)
! 7141: xmlFree(base);
! 7142: ns = xmlGetProp(cur, BAD_CAST "ns");
! 7143: if (ns == NULL) {
! 7144: tmp = cur->parent;
! 7145: while ((tmp != NULL) &&
! 7146: (tmp->type == XML_ELEMENT_NODE)) {
! 7147: ns = xmlGetProp(tmp, BAD_CAST "ns");
! 7148: if (ns != NULL)
! 7149: break;
! 7150: tmp = tmp->parent;
! 7151: }
! 7152: }
! 7153: incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
! 7154: if (ns != NULL)
! 7155: xmlFree(ns);
! 7156: if (incl == NULL) {
! 7157: xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
! 7158: "Failed to load include %s\n", URL,
! 7159: NULL);
! 7160: xmlFree(URL);
! 7161: delete = cur;
! 7162: goto skip_children;
! 7163: }
! 7164: xmlFree(URL);
! 7165: cur->psvi = incl;
! 7166: } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
! 7167: (xmlStrEqual(cur->name, BAD_CAST "attribute")))
! 7168: {
! 7169: xmlChar *name, *ns;
! 7170: xmlNodePtr text = NULL;
! 7171:
! 7172: /*
! 7173: * Simplification 4.8. name attribute of element
! 7174: * and attribute elements
! 7175: */
! 7176: name = xmlGetProp(cur, BAD_CAST "name");
! 7177: if (name != NULL) {
! 7178: if (cur->children == NULL) {
! 7179: text =
! 7180: xmlNewChild(cur, cur->ns, BAD_CAST "name",
! 7181: name);
! 7182: } else {
! 7183: xmlNodePtr node;
! 7184:
! 7185: node = xmlNewDocNode(cur->doc, cur->ns,
! 7186: BAD_CAST "name", NULL);
! 7187: if (node != NULL) {
! 7188: xmlAddPrevSibling(cur->children, node);
! 7189: text = xmlNewText(name);
! 7190: xmlAddChild(node, text);
! 7191: text = node;
! 7192: }
! 7193: }
! 7194: if (text == NULL) {
! 7195: xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
! 7196: "Failed to create a name %s element\n",
! 7197: name, NULL);
! 7198: }
! 7199: xmlUnsetProp(cur, BAD_CAST "name");
! 7200: xmlFree(name);
! 7201: ns = xmlGetProp(cur, BAD_CAST "ns");
! 7202: if (ns != NULL) {
! 7203: if (text != NULL) {
! 7204: xmlSetProp(text, BAD_CAST "ns", ns);
! 7205: /* xmlUnsetProp(cur, BAD_CAST "ns"); */
! 7206: }
! 7207: xmlFree(ns);
! 7208: } else if (xmlStrEqual(cur->name,
! 7209: BAD_CAST "attribute")) {
! 7210: xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
! 7211: }
! 7212: }
! 7213: } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
! 7214: (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
! 7215: (xmlStrEqual(cur->name, BAD_CAST "value"))) {
! 7216: /*
! 7217: * Simplification 4.8. name attribute of element
! 7218: * and attribute elements
! 7219: */
! 7220: if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
! 7221: xmlNodePtr node;
! 7222: xmlChar *ns = NULL;
! 7223:
! 7224: node = cur->parent;
! 7225: while ((node != NULL) &&
! 7226: (node->type == XML_ELEMENT_NODE)) {
! 7227: ns = xmlGetProp(node, BAD_CAST "ns");
! 7228: if (ns != NULL) {
! 7229: break;
! 7230: }
! 7231: node = node->parent;
! 7232: }
! 7233: if (ns == NULL) {
! 7234: xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
! 7235: } else {
! 7236: xmlSetProp(cur, BAD_CAST "ns", ns);
! 7237: xmlFree(ns);
! 7238: }
! 7239: }
! 7240: if (xmlStrEqual(cur->name, BAD_CAST "name")) {
! 7241: xmlChar *name, *local, *prefix;
! 7242:
! 7243: /*
! 7244: * Simplification: 4.10. QNames
! 7245: */
! 7246: name = xmlNodeGetContent(cur);
! 7247: if (name != NULL) {
! 7248: local = xmlSplitQName2(name, &prefix);
! 7249: if (local != NULL) {
! 7250: xmlNsPtr ns;
! 7251:
! 7252: ns = xmlSearchNs(cur->doc, cur, prefix);
! 7253: if (ns == NULL) {
! 7254: xmlRngPErr(ctxt, cur,
! 7255: XML_RNGP_PREFIX_UNDEFINED,
! 7256: "xmlRelaxNGParse: no namespace for prefix %s\n",
! 7257: prefix, NULL);
! 7258: } else {
! 7259: xmlSetProp(cur, BAD_CAST "ns",
! 7260: ns->href);
! 7261: xmlNodeSetContent(cur, local);
! 7262: }
! 7263: xmlFree(local);
! 7264: xmlFree(prefix);
! 7265: }
! 7266: xmlFree(name);
! 7267: }
! 7268: }
! 7269: /*
! 7270: * 4.16
! 7271: */
! 7272: if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
! 7273: if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
! 7274: xmlRngPErr(ctxt, cur,
! 7275: XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
! 7276: "Found nsName/except//nsName forbidden construct\n",
! 7277: NULL, NULL);
! 7278: }
! 7279: }
! 7280: } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
! 7281: (cur != root)) {
! 7282: int oldflags = ctxt->flags;
! 7283:
! 7284: /*
! 7285: * 4.16
! 7286: */
! 7287: if ((cur->parent != NULL) &&
! 7288: (xmlStrEqual
! 7289: (cur->parent->name, BAD_CAST "anyName"))) {
! 7290: ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
! 7291: xmlRelaxNGCleanupTree(ctxt, cur);
! 7292: ctxt->flags = oldflags;
! 7293: goto skip_children;
! 7294: } else if ((cur->parent != NULL) &&
! 7295: (xmlStrEqual
! 7296: (cur->parent->name, BAD_CAST "nsName"))) {
! 7297: ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
! 7298: xmlRelaxNGCleanupTree(ctxt, cur);
! 7299: ctxt->flags = oldflags;
! 7300: goto skip_children;
! 7301: }
! 7302: } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
! 7303: /*
! 7304: * 4.16
! 7305: */
! 7306: if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
! 7307: xmlRngPErr(ctxt, cur,
! 7308: XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
! 7309: "Found anyName/except//anyName forbidden construct\n",
! 7310: NULL, NULL);
! 7311: } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
! 7312: xmlRngPErr(ctxt, cur,
! 7313: XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
! 7314: "Found nsName/except//anyName forbidden construct\n",
! 7315: NULL, NULL);
! 7316: }
! 7317: }
! 7318: /*
! 7319: * Thisd is not an else since "include" is transformed
! 7320: * into a div
! 7321: */
! 7322: if (xmlStrEqual(cur->name, BAD_CAST "div")) {
! 7323: xmlChar *ns;
! 7324: xmlNodePtr child, ins, tmp;
! 7325:
! 7326: /*
! 7327: * implements rule 4.11
! 7328: */
! 7329:
! 7330: ns = xmlGetProp(cur, BAD_CAST "ns");
! 7331:
! 7332: child = cur->children;
! 7333: ins = cur;
! 7334: while (child != NULL) {
! 7335: if (ns != NULL) {
! 7336: if (!xmlHasProp(child, BAD_CAST "ns")) {
! 7337: xmlSetProp(child, BAD_CAST "ns", ns);
! 7338: }
! 7339: }
! 7340: tmp = child->next;
! 7341: xmlUnlinkNode(child);
! 7342: ins = xmlAddNextSibling(ins, child);
! 7343: child = tmp;
! 7344: }
! 7345: if (ns != NULL)
! 7346: xmlFree(ns);
! 7347: /*
! 7348: * Since we are about to delete cur, if it's nsDef is non-NULL we
! 7349: * need to preserve it (it contains the ns definitions for the
! 7350: * children we just moved). We'll just stick it on to the end
! 7351: * of cur->parent's list, since it's never going to be re-serialized
! 7352: * (bug 143738).
! 7353: */
! 7354: if (cur->nsDef != NULL) {
! 7355: xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
! 7356: while (parDef->next != NULL)
! 7357: parDef = parDef->next;
! 7358: parDef->next = cur->nsDef;
! 7359: cur->nsDef = NULL;
! 7360: }
! 7361: delete = cur;
! 7362: goto skip_children;
! 7363: }
! 7364: }
! 7365: }
! 7366: /*
! 7367: * Simplification 4.2 whitespaces
! 7368: */
! 7369: else if ((cur->type == XML_TEXT_NODE) ||
! 7370: (cur->type == XML_CDATA_SECTION_NODE)) {
! 7371: if (IS_BLANK_NODE(cur)) {
! 7372: if (cur->parent->type == XML_ELEMENT_NODE) {
! 7373: if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
! 7374: &&
! 7375: (!xmlStrEqual
! 7376: (cur->parent->name, BAD_CAST "param")))
! 7377: delete = cur;
! 7378: } else {
! 7379: delete = cur;
! 7380: goto skip_children;
! 7381: }
! 7382: }
! 7383: } else {
! 7384: delete = cur;
! 7385: goto skip_children;
! 7386: }
! 7387:
! 7388: /*
! 7389: * Skip to next node
! 7390: */
! 7391: if (cur->children != NULL) {
! 7392: if ((cur->children->type != XML_ENTITY_DECL) &&
! 7393: (cur->children->type != XML_ENTITY_REF_NODE) &&
! 7394: (cur->children->type != XML_ENTITY_NODE)) {
! 7395: cur = cur->children;
! 7396: continue;
! 7397: }
! 7398: }
! 7399: skip_children:
! 7400: if (cur->next != NULL) {
! 7401: cur = cur->next;
! 7402: continue;
! 7403: }
! 7404:
! 7405: do {
! 7406: cur = cur->parent;
! 7407: if (cur == NULL)
! 7408: break;
! 7409: if (cur == root) {
! 7410: cur = NULL;
! 7411: break;
! 7412: }
! 7413: if (cur->next != NULL) {
! 7414: cur = cur->next;
! 7415: break;
! 7416: }
! 7417: } while (cur != NULL);
! 7418: }
! 7419: if (delete != NULL) {
! 7420: xmlUnlinkNode(delete);
! 7421: xmlFreeNode(delete);
! 7422: delete = NULL;
! 7423: }
! 7424: }
! 7425:
! 7426: /**
! 7427: * xmlRelaxNGCleanupDoc:
! 7428: * @ctxt: a Relax-NG parser context
! 7429: * @doc: an xmldocPtr document pointer
! 7430: *
! 7431: * Cleanup the document from unwanted nodes for parsing, resolve
! 7432: * Include and externalRef lookups.
! 7433: *
! 7434: * Returns the cleaned up document or NULL in case of error
! 7435: */
! 7436: static xmlDocPtr
! 7437: xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
! 7438: {
! 7439: xmlNodePtr root;
! 7440:
! 7441: /*
! 7442: * Extract the root
! 7443: */
! 7444: root = xmlDocGetRootElement(doc);
! 7445: if (root == NULL) {
! 7446: xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
! 7447: ctxt->URL, NULL);
! 7448: return (NULL);
! 7449: }
! 7450: xmlRelaxNGCleanupTree(ctxt, root);
! 7451: return (doc);
! 7452: }
! 7453:
! 7454: /**
! 7455: * xmlRelaxNGParse:
! 7456: * @ctxt: a Relax-NG parser context
! 7457: *
! 7458: * parse a schema definition resource and build an internal
! 7459: * XML Shema struture which can be used to validate instances.
! 7460: *
! 7461: * Returns the internal XML RelaxNG structure built from the resource or
! 7462: * NULL in case of error
! 7463: */
! 7464: xmlRelaxNGPtr
! 7465: xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
! 7466: {
! 7467: xmlRelaxNGPtr ret = NULL;
! 7468: xmlDocPtr doc;
! 7469: xmlNodePtr root;
! 7470:
! 7471: xmlRelaxNGInitTypes();
! 7472:
! 7473: if (ctxt == NULL)
! 7474: return (NULL);
! 7475:
! 7476: /*
! 7477: * First step is to parse the input document into an DOM/Infoset
! 7478: */
! 7479: if (ctxt->URL != NULL) {
! 7480: doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
! 7481: if (doc == NULL) {
! 7482: xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
! 7483: "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
! 7484: NULL);
! 7485: return (NULL);
! 7486: }
! 7487: } else if (ctxt->buffer != NULL) {
! 7488: doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
! 7489: if (doc == NULL) {
! 7490: xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
! 7491: "xmlRelaxNGParse: could not parse schemas\n", NULL,
! 7492: NULL);
! 7493: return (NULL);
! 7494: }
! 7495: doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
! 7496: ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
! 7497: } else if (ctxt->document != NULL) {
! 7498: doc = ctxt->document;
! 7499: } else {
! 7500: xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
! 7501: "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
! 7502: return (NULL);
! 7503: }
! 7504: ctxt->document = doc;
! 7505:
! 7506: /*
! 7507: * Some preprocessing of the document content
! 7508: */
! 7509: doc = xmlRelaxNGCleanupDoc(ctxt, doc);
! 7510: if (doc == NULL) {
! 7511: xmlFreeDoc(ctxt->document);
! 7512: ctxt->document = NULL;
! 7513: return (NULL);
! 7514: }
! 7515:
! 7516: /*
! 7517: * Then do the parsing for good
! 7518: */
! 7519: root = xmlDocGetRootElement(doc);
! 7520: if (root == NULL) {
! 7521: xmlRngPErr(ctxt, (xmlNodePtr) doc,
! 7522: XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
! 7523: (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
! 7524:
! 7525: xmlFreeDoc(ctxt->document);
! 7526: ctxt->document = NULL;
! 7527: return (NULL);
! 7528: }
! 7529: ret = xmlRelaxNGParseDocument(ctxt, root);
! 7530: if (ret == NULL) {
! 7531: xmlFreeDoc(ctxt->document);
! 7532: ctxt->document = NULL;
! 7533: return (NULL);
! 7534: }
! 7535:
! 7536: /*
! 7537: * Check the ref/defines links
! 7538: */
! 7539: /*
! 7540: * try to preprocess interleaves
! 7541: */
! 7542: if (ctxt->interleaves != NULL) {
! 7543: xmlHashScan(ctxt->interleaves,
! 7544: (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
! 7545: }
! 7546:
! 7547: /*
! 7548: * if there was a parsing error return NULL
! 7549: */
! 7550: if (ctxt->nbErrors > 0) {
! 7551: xmlRelaxNGFree(ret);
! 7552: ctxt->document = NULL;
! 7553: xmlFreeDoc(doc);
! 7554: return (NULL);
! 7555: }
! 7556:
! 7557: /*
! 7558: * try to compile (parts of) the schemas
! 7559: */
! 7560: if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
! 7561: if (ret->topgrammar->start->type != XML_RELAXNG_START) {
! 7562: xmlRelaxNGDefinePtr def;
! 7563:
! 7564: def = xmlRelaxNGNewDefine(ctxt, NULL);
! 7565: if (def != NULL) {
! 7566: def->type = XML_RELAXNG_START;
! 7567: def->content = ret->topgrammar->start;
! 7568: ret->topgrammar->start = def;
! 7569: }
! 7570: }
! 7571: xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
! 7572: }
! 7573:
! 7574: /*
! 7575: * Transfer the pointer for cleanup at the schema level.
! 7576: */
! 7577: ret->doc = doc;
! 7578: ctxt->document = NULL;
! 7579: ret->documents = ctxt->documents;
! 7580: ctxt->documents = NULL;
! 7581:
! 7582: ret->includes = ctxt->includes;
! 7583: ctxt->includes = NULL;
! 7584: ret->defNr = ctxt->defNr;
! 7585: ret->defTab = ctxt->defTab;
! 7586: ctxt->defTab = NULL;
! 7587: if (ctxt->idref == 1)
! 7588: ret->idref = 1;
! 7589:
! 7590: return (ret);
! 7591: }
! 7592:
! 7593: /**
! 7594: * xmlRelaxNGSetParserErrors:
! 7595: * @ctxt: a Relax-NG validation context
! 7596: * @err: the error callback
! 7597: * @warn: the warning callback
! 7598: * @ctx: contextual data for the callbacks
! 7599: *
! 7600: * Set the callback functions used to handle errors for a validation context
! 7601: */
! 7602: void
! 7603: xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
! 7604: xmlRelaxNGValidityErrorFunc err,
! 7605: xmlRelaxNGValidityWarningFunc warn, void *ctx)
! 7606: {
! 7607: if (ctxt == NULL)
! 7608: return;
! 7609: ctxt->error = err;
! 7610: ctxt->warning = warn;
! 7611: ctxt->serror = NULL;
! 7612: ctxt->userData = ctx;
! 7613: }
! 7614:
! 7615: /**
! 7616: * xmlRelaxNGGetParserErrors:
! 7617: * @ctxt: a Relax-NG validation context
! 7618: * @err: the error callback result
! 7619: * @warn: the warning callback result
! 7620: * @ctx: contextual data for the callbacks result
! 7621: *
! 7622: * Get the callback information used to handle errors for a validation context
! 7623: *
! 7624: * Returns -1 in case of failure, 0 otherwise.
! 7625: */
! 7626: int
! 7627: xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
! 7628: xmlRelaxNGValidityErrorFunc * err,
! 7629: xmlRelaxNGValidityWarningFunc * warn, void **ctx)
! 7630: {
! 7631: if (ctxt == NULL)
! 7632: return (-1);
! 7633: if (err != NULL)
! 7634: *err = ctxt->error;
! 7635: if (warn != NULL)
! 7636: *warn = ctxt->warning;
! 7637: if (ctx != NULL)
! 7638: *ctx = ctxt->userData;
! 7639: return (0);
! 7640: }
! 7641:
! 7642: /**
! 7643: * xmlRelaxNGSetParserStructuredErrors:
! 7644: * @ctxt: a Relax-NG parser context
! 7645: * @serror: the error callback
! 7646: * @ctx: contextual data for the callbacks
! 7647: *
! 7648: * Set the callback functions used to handle errors for a parsing context
! 7649: */
! 7650: void
! 7651: xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
! 7652: xmlStructuredErrorFunc serror,
! 7653: void *ctx)
! 7654: {
! 7655: if (ctxt == NULL)
! 7656: return;
! 7657: ctxt->serror = serror;
! 7658: ctxt->error = NULL;
! 7659: ctxt->warning = NULL;
! 7660: ctxt->userData = ctx;
! 7661: }
! 7662:
! 7663: #ifdef LIBXML_OUTPUT_ENABLED
! 7664:
! 7665: /************************************************************************
! 7666: * *
! 7667: * Dump back a compiled form *
! 7668: * *
! 7669: ************************************************************************/
! 7670: static void xmlRelaxNGDumpDefine(FILE * output,
! 7671: xmlRelaxNGDefinePtr define);
! 7672:
! 7673: /**
! 7674: * xmlRelaxNGDumpDefines:
! 7675: * @output: the file output
! 7676: * @defines: a list of define structures
! 7677: *
! 7678: * Dump a RelaxNG structure back
! 7679: */
! 7680: static void
! 7681: xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
! 7682: {
! 7683: while (defines != NULL) {
! 7684: xmlRelaxNGDumpDefine(output, defines);
! 7685: defines = defines->next;
! 7686: }
! 7687: }
! 7688:
! 7689: /**
! 7690: * xmlRelaxNGDumpDefine:
! 7691: * @output: the file output
! 7692: * @define: a define structure
! 7693: *
! 7694: * Dump a RelaxNG structure back
! 7695: */
! 7696: static void
! 7697: xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
! 7698: {
! 7699: if (define == NULL)
! 7700: return;
! 7701: switch (define->type) {
! 7702: case XML_RELAXNG_EMPTY:
! 7703: fprintf(output, "<empty/>\n");
! 7704: break;
! 7705: case XML_RELAXNG_NOT_ALLOWED:
! 7706: fprintf(output, "<notAllowed/>\n");
! 7707: break;
! 7708: case XML_RELAXNG_TEXT:
! 7709: fprintf(output, "<text/>\n");
! 7710: break;
! 7711: case XML_RELAXNG_ELEMENT:
! 7712: fprintf(output, "<element>\n");
! 7713: if (define->name != NULL) {
! 7714: fprintf(output, "<name");
! 7715: if (define->ns != NULL)
! 7716: fprintf(output, " ns=\"%s\"", define->ns);
! 7717: fprintf(output, ">%s</name>\n", define->name);
! 7718: }
! 7719: xmlRelaxNGDumpDefines(output, define->attrs);
! 7720: xmlRelaxNGDumpDefines(output, define->content);
! 7721: fprintf(output, "</element>\n");
! 7722: break;
! 7723: case XML_RELAXNG_LIST:
! 7724: fprintf(output, "<list>\n");
! 7725: xmlRelaxNGDumpDefines(output, define->content);
! 7726: fprintf(output, "</list>\n");
! 7727: break;
! 7728: case XML_RELAXNG_ONEORMORE:
! 7729: fprintf(output, "<oneOrMore>\n");
! 7730: xmlRelaxNGDumpDefines(output, define->content);
! 7731: fprintf(output, "</oneOrMore>\n");
! 7732: break;
! 7733: case XML_RELAXNG_ZEROORMORE:
! 7734: fprintf(output, "<zeroOrMore>\n");
! 7735: xmlRelaxNGDumpDefines(output, define->content);
! 7736: fprintf(output, "</zeroOrMore>\n");
! 7737: break;
! 7738: case XML_RELAXNG_CHOICE:
! 7739: fprintf(output, "<choice>\n");
! 7740: xmlRelaxNGDumpDefines(output, define->content);
! 7741: fprintf(output, "</choice>\n");
! 7742: break;
! 7743: case XML_RELAXNG_GROUP:
! 7744: fprintf(output, "<group>\n");
! 7745: xmlRelaxNGDumpDefines(output, define->content);
! 7746: fprintf(output, "</group>\n");
! 7747: break;
! 7748: case XML_RELAXNG_INTERLEAVE:
! 7749: fprintf(output, "<interleave>\n");
! 7750: xmlRelaxNGDumpDefines(output, define->content);
! 7751: fprintf(output, "</interleave>\n");
! 7752: break;
! 7753: case XML_RELAXNG_OPTIONAL:
! 7754: fprintf(output, "<optional>\n");
! 7755: xmlRelaxNGDumpDefines(output, define->content);
! 7756: fprintf(output, "</optional>\n");
! 7757: break;
! 7758: case XML_RELAXNG_ATTRIBUTE:
! 7759: fprintf(output, "<attribute>\n");
! 7760: xmlRelaxNGDumpDefines(output, define->content);
! 7761: fprintf(output, "</attribute>\n");
! 7762: break;
! 7763: case XML_RELAXNG_DEF:
! 7764: fprintf(output, "<define");
! 7765: if (define->name != NULL)
! 7766: fprintf(output, " name=\"%s\"", define->name);
! 7767: fprintf(output, ">\n");
! 7768: xmlRelaxNGDumpDefines(output, define->content);
! 7769: fprintf(output, "</define>\n");
! 7770: break;
! 7771: case XML_RELAXNG_REF:
! 7772: fprintf(output, "<ref");
! 7773: if (define->name != NULL)
! 7774: fprintf(output, " name=\"%s\"", define->name);
! 7775: fprintf(output, ">\n");
! 7776: xmlRelaxNGDumpDefines(output, define->content);
! 7777: fprintf(output, "</ref>\n");
! 7778: break;
! 7779: case XML_RELAXNG_PARENTREF:
! 7780: fprintf(output, "<parentRef");
! 7781: if (define->name != NULL)
! 7782: fprintf(output, " name=\"%s\"", define->name);
! 7783: fprintf(output, ">\n");
! 7784: xmlRelaxNGDumpDefines(output, define->content);
! 7785: fprintf(output, "</parentRef>\n");
! 7786: break;
! 7787: case XML_RELAXNG_EXTERNALREF:
! 7788: fprintf(output, "<externalRef>");
! 7789: xmlRelaxNGDumpDefines(output, define->content);
! 7790: fprintf(output, "</externalRef>\n");
! 7791: break;
! 7792: case XML_RELAXNG_DATATYPE:
! 7793: case XML_RELAXNG_VALUE:
! 7794: TODO break;
! 7795: case XML_RELAXNG_START:
! 7796: case XML_RELAXNG_EXCEPT:
! 7797: case XML_RELAXNG_PARAM:
! 7798: TODO break;
! 7799: case XML_RELAXNG_NOOP:
! 7800: xmlRelaxNGDumpDefines(output, define->content);
! 7801: break;
! 7802: }
! 7803: }
! 7804:
! 7805: /**
! 7806: * xmlRelaxNGDumpGrammar:
! 7807: * @output: the file output
! 7808: * @grammar: a grammar structure
! 7809: * @top: is this a top grammar
! 7810: *
! 7811: * Dump a RelaxNG structure back
! 7812: */
! 7813: static void
! 7814: xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
! 7815: {
! 7816: if (grammar == NULL)
! 7817: return;
! 7818:
! 7819: fprintf(output, "<grammar");
! 7820: if (top)
! 7821: fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
! 7822: switch (grammar->combine) {
! 7823: case XML_RELAXNG_COMBINE_UNDEFINED:
! 7824: break;
! 7825: case XML_RELAXNG_COMBINE_CHOICE:
! 7826: fprintf(output, " combine=\"choice\"");
! 7827: break;
! 7828: case XML_RELAXNG_COMBINE_INTERLEAVE:
! 7829: fprintf(output, " combine=\"interleave\"");
! 7830: break;
! 7831: default:
! 7832: fprintf(output, " <!-- invalid combine value -->");
! 7833: }
! 7834: fprintf(output, ">\n");
! 7835: if (grammar->start == NULL) {
! 7836: fprintf(output, " <!-- grammar had no start -->");
! 7837: } else {
! 7838: fprintf(output, "<start>\n");
! 7839: xmlRelaxNGDumpDefine(output, grammar->start);
! 7840: fprintf(output, "</start>\n");
! 7841: }
! 7842: /* TODO ? Dump the defines ? */
! 7843: fprintf(output, "</grammar>\n");
! 7844: }
! 7845:
! 7846: /**
! 7847: * xmlRelaxNGDump:
! 7848: * @output: the file output
! 7849: * @schema: a schema structure
! 7850: *
! 7851: * Dump a RelaxNG structure back
! 7852: */
! 7853: void
! 7854: xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
! 7855: {
! 7856: if (output == NULL)
! 7857: return;
! 7858: if (schema == NULL) {
! 7859: fprintf(output, "RelaxNG empty or failed to compile\n");
! 7860: return;
! 7861: }
! 7862: fprintf(output, "RelaxNG: ");
! 7863: if (schema->doc == NULL) {
! 7864: fprintf(output, "no document\n");
! 7865: } else if (schema->doc->URL != NULL) {
! 7866: fprintf(output, "%s\n", schema->doc->URL);
! 7867: } else {
! 7868: fprintf(output, "\n");
! 7869: }
! 7870: if (schema->topgrammar == NULL) {
! 7871: fprintf(output, "RelaxNG has no top grammar\n");
! 7872: return;
! 7873: }
! 7874: xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
! 7875: }
! 7876:
! 7877: /**
! 7878: * xmlRelaxNGDumpTree:
! 7879: * @output: the file output
! 7880: * @schema: a schema structure
! 7881: *
! 7882: * Dump the transformed RelaxNG tree.
! 7883: */
! 7884: void
! 7885: xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
! 7886: {
! 7887: if (output == NULL)
! 7888: return;
! 7889: if (schema == NULL) {
! 7890: fprintf(output, "RelaxNG empty or failed to compile\n");
! 7891: return;
! 7892: }
! 7893: if (schema->doc == NULL) {
! 7894: fprintf(output, "no document\n");
! 7895: } else {
! 7896: xmlDocDump(output, schema->doc);
! 7897: }
! 7898: }
! 7899: #endif /* LIBXML_OUTPUT_ENABLED */
! 7900:
! 7901: /************************************************************************
! 7902: * *
! 7903: * Validation of compiled content *
! 7904: * *
! 7905: ************************************************************************/
! 7906: static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
! 7907: xmlRelaxNGDefinePtr define);
! 7908:
! 7909: /**
! 7910: * xmlRelaxNGValidateCompiledCallback:
! 7911: * @exec: the regular expression instance
! 7912: * @token: the token which matched
! 7913: * @transdata: callback data, the define for the subelement if available
! 7914: @ @inputdata: callback data, the Relax NG validation context
! 7915: *
! 7916: * Handle the callback and if needed validate the element children.
! 7917: */
! 7918: static void
! 7919: xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
! 7920: const xmlChar * token,
! 7921: void *transdata, void *inputdata)
! 7922: {
! 7923: xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
! 7924: xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
! 7925: int ret;
! 7926:
! 7927: #ifdef DEBUG_COMPILE
! 7928: xmlGenericError(xmlGenericErrorContext,
! 7929: "Compiled callback for: '%s'\n", token);
! 7930: #endif
! 7931: if (ctxt == NULL) {
! 7932: fprintf(stderr, "callback on %s missing context\n", token);
! 7933: return;
! 7934: }
! 7935: if (define == NULL) {
! 7936: if (token[0] == '#')
! 7937: return;
! 7938: fprintf(stderr, "callback on %s missing define\n", token);
! 7939: if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
! 7940: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 7941: return;
! 7942: }
! 7943: if ((ctxt == NULL) || (define == NULL)) {
! 7944: fprintf(stderr, "callback on %s missing info\n", token);
! 7945: if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
! 7946: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 7947: return;
! 7948: } else if (define->type != XML_RELAXNG_ELEMENT) {
! 7949: fprintf(stderr, "callback on %s define is not element\n", token);
! 7950: if (ctxt->errNo == XML_RELAXNG_OK)
! 7951: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 7952: return;
! 7953: }
! 7954: ret = xmlRelaxNGValidateDefinition(ctxt, define);
! 7955: if (ret != 0)
! 7956: ctxt->perr = ret;
! 7957: }
! 7958:
! 7959: /**
! 7960: * xmlRelaxNGValidateCompiledContent:
! 7961: * @ctxt: the RelaxNG validation context
! 7962: * @regexp: the regular expression as compiled
! 7963: * @content: list of children to test against the regexp
! 7964: *
! 7965: * Validate the content model of an element or start using the regexp
! 7966: *
! 7967: * Returns 0 in case of success, -1 in case of error.
! 7968: */
! 7969: static int
! 7970: xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
! 7971: xmlRegexpPtr regexp, xmlNodePtr content)
! 7972: {
! 7973: xmlRegExecCtxtPtr exec;
! 7974: xmlNodePtr cur;
! 7975: int ret = 0;
! 7976: int oldperr;
! 7977:
! 7978: if ((ctxt == NULL) || (regexp == NULL))
! 7979: return (-1);
! 7980: oldperr = ctxt->perr;
! 7981: exec = xmlRegNewExecCtxt(regexp,
! 7982: xmlRelaxNGValidateCompiledCallback, ctxt);
! 7983: ctxt->perr = 0;
! 7984: cur = content;
! 7985: while (cur != NULL) {
! 7986: ctxt->state->seq = cur;
! 7987: switch (cur->type) {
! 7988: case XML_TEXT_NODE:
! 7989: case XML_CDATA_SECTION_NODE:
! 7990: if (xmlIsBlankNode(cur))
! 7991: break;
! 7992: ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
! 7993: if (ret < 0) {
! 7994: VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
! 7995: cur->parent->name);
! 7996: }
! 7997: break;
! 7998: case XML_ELEMENT_NODE:
! 7999: if (cur->ns != NULL) {
! 8000: ret = xmlRegExecPushString2(exec, cur->name,
! 8001: cur->ns->href, ctxt);
! 8002: } else {
! 8003: ret = xmlRegExecPushString(exec, cur->name, ctxt);
! 8004: }
! 8005: if (ret < 0) {
! 8006: VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
! 8007: }
! 8008: break;
! 8009: default:
! 8010: break;
! 8011: }
! 8012: if (ret < 0)
! 8013: break;
! 8014: /*
! 8015: * Switch to next element
! 8016: */
! 8017: cur = cur->next;
! 8018: }
! 8019: ret = xmlRegExecPushString(exec, NULL, NULL);
! 8020: if (ret == 1) {
! 8021: ret = 0;
! 8022: ctxt->state->seq = NULL;
! 8023: } else if (ret == 0) {
! 8024: /*
! 8025: * TODO: get some of the names needed to exit the current state of exec
! 8026: */
! 8027: VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
! 8028: ret = -1;
! 8029: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 8030: xmlRelaxNGDumpValidError(ctxt);
! 8031: } else {
! 8032: ret = -1;
! 8033: }
! 8034: xmlRegFreeExecCtxt(exec);
! 8035: /*
! 8036: * There might be content model errors outside of the pure
! 8037: * regexp validation, e.g. for attribute values.
! 8038: */
! 8039: if ((ret == 0) && (ctxt->perr != 0)) {
! 8040: ret = ctxt->perr;
! 8041: }
! 8042: ctxt->perr = oldperr;
! 8043: return (ret);
! 8044: }
! 8045:
! 8046: /************************************************************************
! 8047: * *
! 8048: * Progressive validation of when possible *
! 8049: * *
! 8050: ************************************************************************/
! 8051: static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
! 8052: xmlRelaxNGDefinePtr defines);
! 8053: static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
! 8054: int dolog);
! 8055: static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
! 8056:
! 8057: /**
! 8058: * xmlRelaxNGElemPush:
! 8059: * @ctxt: the validation context
! 8060: * @exec: the regexp runtime for the new content model
! 8061: *
! 8062: * Push a new regexp for the current node content model on the stack
! 8063: *
! 8064: * Returns 0 in case of success and -1 in case of error.
! 8065: */
! 8066: static int
! 8067: xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
! 8068: {
! 8069: if (ctxt->elemTab == NULL) {
! 8070: ctxt->elemMax = 10;
! 8071: ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
! 8072: sizeof
! 8073: (xmlRegExecCtxtPtr));
! 8074: if (ctxt->elemTab == NULL) {
! 8075: xmlRngVErrMemory(ctxt, "validating\n");
! 8076: return (-1);
! 8077: }
! 8078: }
! 8079: if (ctxt->elemNr >= ctxt->elemMax) {
! 8080: ctxt->elemMax *= 2;
! 8081: ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
! 8082: ctxt->elemMax *
! 8083: sizeof
! 8084: (xmlRegExecCtxtPtr));
! 8085: if (ctxt->elemTab == NULL) {
! 8086: xmlRngVErrMemory(ctxt, "validating\n");
! 8087: return (-1);
! 8088: }
! 8089: }
! 8090: ctxt->elemTab[ctxt->elemNr++] = exec;
! 8091: ctxt->elem = exec;
! 8092: return (0);
! 8093: }
! 8094:
! 8095: /**
! 8096: * xmlRelaxNGElemPop:
! 8097: * @ctxt: the validation context
! 8098: *
! 8099: * Pop the regexp of the current node content model from the stack
! 8100: *
! 8101: * Returns the exec or NULL if empty
! 8102: */
! 8103: static xmlRegExecCtxtPtr
! 8104: xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
! 8105: {
! 8106: xmlRegExecCtxtPtr ret;
! 8107:
! 8108: if (ctxt->elemNr <= 0)
! 8109: return (NULL);
! 8110: ctxt->elemNr--;
! 8111: ret = ctxt->elemTab[ctxt->elemNr];
! 8112: ctxt->elemTab[ctxt->elemNr] = NULL;
! 8113: if (ctxt->elemNr > 0)
! 8114: ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
! 8115: else
! 8116: ctxt->elem = NULL;
! 8117: return (ret);
! 8118: }
! 8119:
! 8120: /**
! 8121: * xmlRelaxNGValidateProgressiveCallback:
! 8122: * @exec: the regular expression instance
! 8123: * @token: the token which matched
! 8124: * @transdata: callback data, the define for the subelement if available
! 8125: @ @inputdata: callback data, the Relax NG validation context
! 8126: *
! 8127: * Handle the callback and if needed validate the element children.
! 8128: * some of the in/out informations are passed via the context in @inputdata.
! 8129: */
! 8130: static void
! 8131: xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
! 8132: ATTRIBUTE_UNUSED,
! 8133: const xmlChar * token,
! 8134: void *transdata, void *inputdata)
! 8135: {
! 8136: xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
! 8137: xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
! 8138: xmlRelaxNGValidStatePtr state, oldstate;
! 8139: xmlNodePtr node;
! 8140: int ret = 0, oldflags;
! 8141:
! 8142: #ifdef DEBUG_PROGRESSIVE
! 8143: xmlGenericError(xmlGenericErrorContext,
! 8144: "Progressive callback for: '%s'\n", token);
! 8145: #endif
! 8146: if (ctxt == NULL) {
! 8147: fprintf(stderr, "callback on %s missing context\n", token);
! 8148: return;
! 8149: }
! 8150: node = ctxt->pnode;
! 8151: ctxt->pstate = 1;
! 8152: if (define == NULL) {
! 8153: if (token[0] == '#')
! 8154: return;
! 8155: fprintf(stderr, "callback on %s missing define\n", token);
! 8156: if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
! 8157: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 8158: ctxt->pstate = -1;
! 8159: return;
! 8160: }
! 8161: if ((ctxt == NULL) || (define == NULL)) {
! 8162: fprintf(stderr, "callback on %s missing info\n", token);
! 8163: if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
! 8164: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 8165: ctxt->pstate = -1;
! 8166: return;
! 8167: } else if (define->type != XML_RELAXNG_ELEMENT) {
! 8168: fprintf(stderr, "callback on %s define is not element\n", token);
! 8169: if (ctxt->errNo == XML_RELAXNG_OK)
! 8170: ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
! 8171: ctxt->pstate = -1;
! 8172: return;
! 8173: }
! 8174: if (node->type != XML_ELEMENT_NODE) {
! 8175: VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
! 8176: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 8177: xmlRelaxNGDumpValidError(ctxt);
! 8178: ctxt->pstate = -1;
! 8179: return;
! 8180: }
! 8181: if (define->contModel == NULL) {
! 8182: /*
! 8183: * this node cannot be validated in a streamable fashion
! 8184: */
! 8185: #ifdef DEBUG_PROGRESSIVE
! 8186: xmlGenericError(xmlGenericErrorContext,
! 8187: "Element '%s' validation is not streamable\n",
! 8188: token);
! 8189: #endif
! 8190: ctxt->pstate = 0;
! 8191: ctxt->pdef = define;
! 8192: return;
! 8193: }
! 8194: exec = xmlRegNewExecCtxt(define->contModel,
! 8195: xmlRelaxNGValidateProgressiveCallback, ctxt);
! 8196: if (exec == NULL) {
! 8197: ctxt->pstate = -1;
! 8198: return;
! 8199: }
! 8200: xmlRelaxNGElemPush(ctxt, exec);
! 8201:
! 8202: /*
! 8203: * Validate the attributes part of the content.
! 8204: */
! 8205: state = xmlRelaxNGNewValidState(ctxt, node);
! 8206: if (state == NULL) {
! 8207: ctxt->pstate = -1;
! 8208: return;
! 8209: }
! 8210: oldstate = ctxt->state;
! 8211: ctxt->state = state;
! 8212: if (define->attrs != NULL) {
! 8213: ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
! 8214: if (ret != 0) {
! 8215: ctxt->pstate = -1;
! 8216: VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
! 8217: }
! 8218: }
! 8219: if (ctxt->state != NULL) {
! 8220: ctxt->state->seq = NULL;
! 8221: ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
! 8222: if (ret != 0) {
! 8223: ctxt->pstate = -1;
! 8224: }
! 8225: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 8226: } else if (ctxt->states != NULL) {
! 8227: int tmp = -1, i;
! 8228:
! 8229: oldflags = ctxt->flags;
! 8230:
! 8231: for (i = 0; i < ctxt->states->nbState; i++) {
! 8232: state = ctxt->states->tabState[i];
! 8233: ctxt->state = state;
! 8234: ctxt->state->seq = NULL;
! 8235:
! 8236: if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
! 8237: tmp = 0;
! 8238: break;
! 8239: }
! 8240: }
! 8241: if (tmp != 0) {
! 8242: /*
! 8243: * validation error, log the message for the "best" one
! 8244: */
! 8245: ctxt->flags |= FLAGS_IGNORABLE;
! 8246: xmlRelaxNGLogBestError(ctxt);
! 8247: }
! 8248: for (i = 0; i < ctxt->states->nbState; i++) {
! 8249: xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
! 8250: }
! 8251: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 8252: ctxt->states = NULL;
! 8253: if ((ret == 0) && (tmp == -1))
! 8254: ctxt->pstate = -1;
! 8255: ctxt->flags = oldflags;
! 8256: }
! 8257: if (ctxt->pstate == -1) {
! 8258: if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
! 8259: xmlRelaxNGDumpValidError(ctxt);
! 8260: }
! 8261: }
! 8262: ctxt->state = oldstate;
! 8263: }
! 8264:
! 8265: /**
! 8266: * xmlRelaxNGValidatePushElement:
! 8267: * @ctxt: the validation context
! 8268: * @doc: a document instance
! 8269: * @elem: an element instance
! 8270: *
! 8271: * Push a new element start on the RelaxNG validation stack.
! 8272: *
! 8273: * returns 1 if no validation problem was found or 0 if validating the
! 8274: * element requires a full node, and -1 in case of error.
! 8275: */
! 8276: int
! 8277: xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
! 8278: xmlDocPtr doc ATTRIBUTE_UNUSED,
! 8279: xmlNodePtr elem)
! 8280: {
! 8281: int ret = 1;
! 8282:
! 8283: if ((ctxt == NULL) || (elem == NULL))
! 8284: return (-1);
! 8285:
! 8286: #ifdef DEBUG_PROGRESSIVE
! 8287: xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
! 8288: #endif
! 8289: if (ctxt->elem == 0) {
! 8290: xmlRelaxNGPtr schema;
! 8291: xmlRelaxNGGrammarPtr grammar;
! 8292: xmlRegExecCtxtPtr exec;
! 8293: xmlRelaxNGDefinePtr define;
! 8294:
! 8295: schema = ctxt->schema;
! 8296: if (schema == NULL) {
! 8297: VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
! 8298: return (-1);
! 8299: }
! 8300: grammar = schema->topgrammar;
! 8301: if ((grammar == NULL) || (grammar->start == NULL)) {
! 8302: VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
! 8303: return (-1);
! 8304: }
! 8305: define = grammar->start;
! 8306: if (define->contModel == NULL) {
! 8307: ctxt->pdef = define;
! 8308: return (0);
! 8309: }
! 8310: exec = xmlRegNewExecCtxt(define->contModel,
! 8311: xmlRelaxNGValidateProgressiveCallback,
! 8312: ctxt);
! 8313: if (exec == NULL) {
! 8314: return (-1);
! 8315: }
! 8316: xmlRelaxNGElemPush(ctxt, exec);
! 8317: }
! 8318: ctxt->pnode = elem;
! 8319: ctxt->pstate = 0;
! 8320: if (elem->ns != NULL) {
! 8321: ret =
! 8322: xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
! 8323: ctxt);
! 8324: } else {
! 8325: ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
! 8326: }
! 8327: if (ret < 0) {
! 8328: VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
! 8329: } else {
! 8330: if (ctxt->pstate == 0)
! 8331: ret = 0;
! 8332: else if (ctxt->pstate < 0)
! 8333: ret = -1;
! 8334: else
! 8335: ret = 1;
! 8336: }
! 8337: #ifdef DEBUG_PROGRESSIVE
! 8338: if (ret < 0)
! 8339: xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
! 8340: elem->name);
! 8341: #endif
! 8342: return (ret);
! 8343: }
! 8344:
! 8345: /**
! 8346: * xmlRelaxNGValidatePushCData:
! 8347: * @ctxt: the RelaxNG validation context
! 8348: * @data: some character data read
! 8349: * @len: the lenght of the data
! 8350: *
! 8351: * check the CData parsed for validation in the current stack
! 8352: *
! 8353: * returns 1 if no validation problem was found or -1 otherwise
! 8354: */
! 8355: int
! 8356: xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
! 8357: const xmlChar * data, int len ATTRIBUTE_UNUSED)
! 8358: {
! 8359: int ret = 1;
! 8360:
! 8361: if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
! 8362: return (-1);
! 8363:
! 8364: #ifdef DEBUG_PROGRESSIVE
! 8365: xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
! 8366: #endif
! 8367:
! 8368: while (*data != 0) {
! 8369: if (!IS_BLANK_CH(*data))
! 8370: break;
! 8371: data++;
! 8372: }
! 8373: if (*data == 0)
! 8374: return (1);
! 8375:
! 8376: ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
! 8377: if (ret < 0) {
! 8378: VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
! 8379: #ifdef DEBUG_PROGRESSIVE
! 8380: xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
! 8381: #endif
! 8382:
! 8383: return (-1);
! 8384: }
! 8385: return (1);
! 8386: }
! 8387:
! 8388: /**
! 8389: * xmlRelaxNGValidatePopElement:
! 8390: * @ctxt: the RelaxNG validation context
! 8391: * @doc: a document instance
! 8392: * @elem: an element instance
! 8393: *
! 8394: * Pop the element end from the RelaxNG validation stack.
! 8395: *
! 8396: * returns 1 if no validation problem was found or 0 otherwise
! 8397: */
! 8398: int
! 8399: xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
! 8400: xmlDocPtr doc ATTRIBUTE_UNUSED,
! 8401: xmlNodePtr elem)
! 8402: {
! 8403: int ret;
! 8404: xmlRegExecCtxtPtr exec;
! 8405:
! 8406: if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
! 8407: return (-1);
! 8408: #ifdef DEBUG_PROGRESSIVE
! 8409: xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
! 8410: #endif
! 8411: /*
! 8412: * verify that we reached a terminal state of the content model.
! 8413: */
! 8414: exec = xmlRelaxNGElemPop(ctxt);
! 8415: ret = xmlRegExecPushString(exec, NULL, NULL);
! 8416: if (ret == 0) {
! 8417: /*
! 8418: * TODO: get some of the names needed to exit the current state of exec
! 8419: */
! 8420: VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
! 8421: ret = -1;
! 8422: } else if (ret < 0) {
! 8423: ret = -1;
! 8424: } else {
! 8425: ret = 1;
! 8426: }
! 8427: xmlRegFreeExecCtxt(exec);
! 8428: #ifdef DEBUG_PROGRESSIVE
! 8429: if (ret < 0)
! 8430: xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
! 8431: elem->name);
! 8432: #endif
! 8433: return (ret);
! 8434: }
! 8435:
! 8436: /**
! 8437: * xmlRelaxNGValidateFullElement:
! 8438: * @ctxt: the validation context
! 8439: * @doc: a document instance
! 8440: * @elem: an element instance
! 8441: *
! 8442: * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
! 8443: * 0 and the content of the node has been expanded.
! 8444: *
! 8445: * returns 1 if no validation problem was found or -1 in case of error.
! 8446: */
! 8447: int
! 8448: xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
! 8449: xmlDocPtr doc ATTRIBUTE_UNUSED,
! 8450: xmlNodePtr elem)
! 8451: {
! 8452: int ret;
! 8453: xmlRelaxNGValidStatePtr state;
! 8454:
! 8455: if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
! 8456: return (-1);
! 8457: #ifdef DEBUG_PROGRESSIVE
! 8458: xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
! 8459: #endif
! 8460: state = xmlRelaxNGNewValidState(ctxt, elem->parent);
! 8461: if (state == NULL) {
! 8462: return (-1);
! 8463: }
! 8464: state->seq = elem;
! 8465: ctxt->state = state;
! 8466: ctxt->errNo = XML_RELAXNG_OK;
! 8467: ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
! 8468: if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
! 8469: ret = -1;
! 8470: else
! 8471: ret = 1;
! 8472: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 8473: ctxt->state = NULL;
! 8474: #ifdef DEBUG_PROGRESSIVE
! 8475: if (ret < 0)
! 8476: xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
! 8477: elem->name);
! 8478: #endif
! 8479: return (ret);
! 8480: }
! 8481:
! 8482: /************************************************************************
! 8483: * *
! 8484: * Generic interpreted validation implementation *
! 8485: * *
! 8486: ************************************************************************/
! 8487: static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
! 8488: xmlRelaxNGDefinePtr define);
! 8489:
! 8490: /**
! 8491: * xmlRelaxNGSkipIgnored:
! 8492: * @ctxt: a schema validation context
! 8493: * @node: the top node.
! 8494: *
! 8495: * Skip ignorable nodes in that context
! 8496: *
! 8497: * Returns the new sibling or NULL in case of error.
! 8498: */
! 8499: static xmlNodePtr
! 8500: xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
! 8501: xmlNodePtr node)
! 8502: {
! 8503: /*
! 8504: * TODO complete and handle entities
! 8505: */
! 8506: while ((node != NULL) &&
! 8507: ((node->type == XML_COMMENT_NODE) ||
! 8508: (node->type == XML_PI_NODE) ||
! 8509: (node->type == XML_XINCLUDE_START) ||
! 8510: (node->type == XML_XINCLUDE_END) ||
! 8511: (((node->type == XML_TEXT_NODE) ||
! 8512: (node->type == XML_CDATA_SECTION_NODE)) &&
! 8513: ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
! 8514: (IS_BLANK_NODE(node)))))) {
! 8515: node = node->next;
! 8516: }
! 8517: return (node);
! 8518: }
! 8519:
! 8520: /**
! 8521: * xmlRelaxNGNormalize:
! 8522: * @ctxt: a schema validation context
! 8523: * @str: the string to normalize
! 8524: *
! 8525: * Implements the normalizeWhiteSpace( s ) function from
! 8526: * section 6.2.9 of the spec
! 8527: *
! 8528: * Returns the new string or NULL in case of error.
! 8529: */
! 8530: static xmlChar *
! 8531: xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
! 8532: {
! 8533: xmlChar *ret, *p;
! 8534: const xmlChar *tmp;
! 8535: int len;
! 8536:
! 8537: if (str == NULL)
! 8538: return (NULL);
! 8539: tmp = str;
! 8540: while (*tmp != 0)
! 8541: tmp++;
! 8542: len = tmp - str;
! 8543:
! 8544: ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
! 8545: if (ret == NULL) {
! 8546: xmlRngVErrMemory(ctxt, "validating\n");
! 8547: return (NULL);
! 8548: }
! 8549: p = ret;
! 8550: while (IS_BLANK_CH(*str))
! 8551: str++;
! 8552: while (*str != 0) {
! 8553: if (IS_BLANK_CH(*str)) {
! 8554: while (IS_BLANK_CH(*str))
! 8555: str++;
! 8556: if (*str == 0)
! 8557: break;
! 8558: *p++ = ' ';
! 8559: } else
! 8560: *p++ = *str++;
! 8561: }
! 8562: *p = 0;
! 8563: return (ret);
! 8564: }
! 8565:
! 8566: /**
! 8567: * xmlRelaxNGValidateDatatype:
! 8568: * @ctxt: a Relax-NG validation context
! 8569: * @value: the string value
! 8570: * @type: the datatype definition
! 8571: * @node: the node
! 8572: *
! 8573: * Validate the given value against the dataype
! 8574: *
! 8575: * Returns 0 if the validation succeeded or an error code.
! 8576: */
! 8577: static int
! 8578: xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
! 8579: const xmlChar * value,
! 8580: xmlRelaxNGDefinePtr define, xmlNodePtr node)
! 8581: {
! 8582: int ret, tmp;
! 8583: xmlRelaxNGTypeLibraryPtr lib;
! 8584: void *result = NULL;
! 8585: xmlRelaxNGDefinePtr cur;
! 8586:
! 8587: if ((define == NULL) || (define->data == NULL)) {
! 8588: return (-1);
! 8589: }
! 8590: lib = (xmlRelaxNGTypeLibraryPtr) define->data;
! 8591: if (lib->check != NULL) {
! 8592: if ((define->attrs != NULL) &&
! 8593: (define->attrs->type == XML_RELAXNG_PARAM)) {
! 8594: ret =
! 8595: lib->check(lib->data, define->name, value, &result, node);
! 8596: } else {
! 8597: ret = lib->check(lib->data, define->name, value, NULL, node);
! 8598: }
! 8599: } else
! 8600: ret = -1;
! 8601: if (ret < 0) {
! 8602: VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
! 8603: if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
! 8604: lib->freef(lib->data, result);
! 8605: return (-1);
! 8606: } else if (ret == 1) {
! 8607: ret = 0;
! 8608: } else if (ret == 2) {
! 8609: VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
! 8610: } else {
! 8611: VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
! 8612: ret = -1;
! 8613: }
! 8614: cur = define->attrs;
! 8615: while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
! 8616: if (lib->facet != NULL) {
! 8617: tmp = lib->facet(lib->data, define->name, cur->name,
! 8618: cur->value, value, result);
! 8619: if (tmp != 0)
! 8620: ret = -1;
! 8621: }
! 8622: cur = cur->next;
! 8623: }
! 8624: if ((ret == 0) && (define->content != NULL)) {
! 8625: const xmlChar *oldvalue, *oldendvalue;
! 8626:
! 8627: oldvalue = ctxt->state->value;
! 8628: oldendvalue = ctxt->state->endvalue;
! 8629: ctxt->state->value = (xmlChar *) value;
! 8630: ctxt->state->endvalue = NULL;
! 8631: ret = xmlRelaxNGValidateValue(ctxt, define->content);
! 8632: ctxt->state->value = (xmlChar *) oldvalue;
! 8633: ctxt->state->endvalue = (xmlChar *) oldendvalue;
! 8634: }
! 8635: if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
! 8636: lib->freef(lib->data, result);
! 8637: return (ret);
! 8638: }
! 8639:
! 8640: /**
! 8641: * xmlRelaxNGNextValue:
! 8642: * @ctxt: a Relax-NG validation context
! 8643: *
! 8644: * Skip to the next value when validating within a list
! 8645: *
! 8646: * Returns 0 if the operation succeeded or an error code.
! 8647: */
! 8648: static int
! 8649: xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
! 8650: {
! 8651: xmlChar *cur;
! 8652:
! 8653: cur = ctxt->state->value;
! 8654: if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
! 8655: ctxt->state->value = NULL;
! 8656: ctxt->state->endvalue = NULL;
! 8657: return (0);
! 8658: }
! 8659: while (*cur != 0)
! 8660: cur++;
! 8661: while ((cur != ctxt->state->endvalue) && (*cur == 0))
! 8662: cur++;
! 8663: if (cur == ctxt->state->endvalue)
! 8664: ctxt->state->value = NULL;
! 8665: else
! 8666: ctxt->state->value = cur;
! 8667: return (0);
! 8668: }
! 8669:
! 8670: /**
! 8671: * xmlRelaxNGValidateValueList:
! 8672: * @ctxt: a Relax-NG validation context
! 8673: * @defines: the list of definitions to verify
! 8674: *
! 8675: * Validate the given set of definitions for the current value
! 8676: *
! 8677: * Returns 0 if the validation succeeded or an error code.
! 8678: */
! 8679: static int
! 8680: xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
! 8681: xmlRelaxNGDefinePtr defines)
! 8682: {
! 8683: int ret = 0;
! 8684:
! 8685: while (defines != NULL) {
! 8686: ret = xmlRelaxNGValidateValue(ctxt, defines);
! 8687: if (ret != 0)
! 8688: break;
! 8689: defines = defines->next;
! 8690: }
! 8691: return (ret);
! 8692: }
! 8693:
! 8694: /**
! 8695: * xmlRelaxNGValidateValue:
! 8696: * @ctxt: a Relax-NG validation context
! 8697: * @define: the definition to verify
! 8698: *
! 8699: * Validate the given definition for the current value
! 8700: *
! 8701: * Returns 0 if the validation succeeded or an error code.
! 8702: */
! 8703: static int
! 8704: xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
! 8705: xmlRelaxNGDefinePtr define)
! 8706: {
! 8707: int ret = 0, oldflags;
! 8708: xmlChar *value;
! 8709:
! 8710: value = ctxt->state->value;
! 8711: switch (define->type) {
! 8712: case XML_RELAXNG_EMPTY:{
! 8713: if ((value != NULL) && (value[0] != 0)) {
! 8714: int idx = 0;
! 8715:
! 8716: while (IS_BLANK_CH(value[idx]))
! 8717: idx++;
! 8718: if (value[idx] != 0)
! 8719: ret = -1;
! 8720: }
! 8721: break;
! 8722: }
! 8723: case XML_RELAXNG_TEXT:
! 8724: break;
! 8725: case XML_RELAXNG_VALUE:{
! 8726: if (!xmlStrEqual(value, define->value)) {
! 8727: if (define->name != NULL) {
! 8728: xmlRelaxNGTypeLibraryPtr lib;
! 8729:
! 8730: lib = (xmlRelaxNGTypeLibraryPtr) define->data;
! 8731: if ((lib != NULL) && (lib->comp != NULL)) {
! 8732: ret = lib->comp(lib->data, define->name,
! 8733: define->value, define->node,
! 8734: (void *) define->attrs,
! 8735: value, ctxt->state->node);
! 8736: } else
! 8737: ret = -1;
! 8738: if (ret < 0) {
! 8739: VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
! 8740: define->name);
! 8741: return (-1);
! 8742: } else if (ret == 1) {
! 8743: ret = 0;
! 8744: } else {
! 8745: ret = -1;
! 8746: }
! 8747: } else {
! 8748: xmlChar *nval, *nvalue;
! 8749:
! 8750: /*
! 8751: * TODO: trivial optimizations are possible by
! 8752: * computing at compile-time
! 8753: */
! 8754: nval = xmlRelaxNGNormalize(ctxt, define->value);
! 8755: nvalue = xmlRelaxNGNormalize(ctxt, value);
! 8756:
! 8757: if ((nval == NULL) || (nvalue == NULL) ||
! 8758: (!xmlStrEqual(nval, nvalue)))
! 8759: ret = -1;
! 8760: if (nval != NULL)
! 8761: xmlFree(nval);
! 8762: if (nvalue != NULL)
! 8763: xmlFree(nvalue);
! 8764: }
! 8765: }
! 8766: if (ret == 0)
! 8767: xmlRelaxNGNextValue(ctxt);
! 8768: break;
! 8769: }
! 8770: case XML_RELAXNG_DATATYPE:{
! 8771: ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
! 8772: ctxt->state->seq);
! 8773: if (ret == 0)
! 8774: xmlRelaxNGNextValue(ctxt);
! 8775:
! 8776: break;
! 8777: }
! 8778: case XML_RELAXNG_CHOICE:{
! 8779: xmlRelaxNGDefinePtr list = define->content;
! 8780: xmlChar *oldvalue;
! 8781:
! 8782: oldflags = ctxt->flags;
! 8783: ctxt->flags |= FLAGS_IGNORABLE;
! 8784:
! 8785: oldvalue = ctxt->state->value;
! 8786: while (list != NULL) {
! 8787: ret = xmlRelaxNGValidateValue(ctxt, list);
! 8788: if (ret == 0) {
! 8789: break;
! 8790: }
! 8791: ctxt->state->value = oldvalue;
! 8792: list = list->next;
! 8793: }
! 8794: ctxt->flags = oldflags;
! 8795: if (ret != 0) {
! 8796: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 8797: xmlRelaxNGDumpValidError(ctxt);
! 8798: } else {
! 8799: if (ctxt->errNr > 0)
! 8800: xmlRelaxNGPopErrors(ctxt, 0);
! 8801: }
! 8802: break;
! 8803: }
! 8804: case XML_RELAXNG_LIST:{
! 8805: xmlRelaxNGDefinePtr list = define->content;
! 8806: xmlChar *oldvalue, *oldend, *val, *cur;
! 8807:
! 8808: #ifdef DEBUG_LIST
! 8809: int nb_values = 0;
! 8810: #endif
! 8811:
! 8812: oldvalue = ctxt->state->value;
! 8813: oldend = ctxt->state->endvalue;
! 8814:
! 8815: val = xmlStrdup(oldvalue);
! 8816: if (val == NULL) {
! 8817: val = xmlStrdup(BAD_CAST "");
! 8818: }
! 8819: if (val == NULL) {
! 8820: VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
! 8821: return (-1);
! 8822: }
! 8823: cur = val;
! 8824: while (*cur != 0) {
! 8825: if (IS_BLANK_CH(*cur)) {
! 8826: *cur = 0;
! 8827: cur++;
! 8828: #ifdef DEBUG_LIST
! 8829: nb_values++;
! 8830: #endif
! 8831: while (IS_BLANK_CH(*cur))
! 8832: *cur++ = 0;
! 8833: } else
! 8834: cur++;
! 8835: }
! 8836: #ifdef DEBUG_LIST
! 8837: xmlGenericError(xmlGenericErrorContext,
! 8838: "list value: '%s' found %d items\n",
! 8839: oldvalue, nb_values);
! 8840: nb_values = 0;
! 8841: #endif
! 8842: ctxt->state->endvalue = cur;
! 8843: cur = val;
! 8844: while ((*cur == 0) && (cur != ctxt->state->endvalue))
! 8845: cur++;
! 8846:
! 8847: ctxt->state->value = cur;
! 8848:
! 8849: while (list != NULL) {
! 8850: if (ctxt->state->value == ctxt->state->endvalue)
! 8851: ctxt->state->value = NULL;
! 8852: ret = xmlRelaxNGValidateValue(ctxt, list);
! 8853: if (ret != 0) {
! 8854: #ifdef DEBUG_LIST
! 8855: xmlGenericError(xmlGenericErrorContext,
! 8856: "Failed to validate value: '%s' with %d rule\n",
! 8857: ctxt->state->value, nb_values);
! 8858: #endif
! 8859: break;
! 8860: }
! 8861: #ifdef DEBUG_LIST
! 8862: nb_values++;
! 8863: #endif
! 8864: list = list->next;
! 8865: }
! 8866:
! 8867: if ((ret == 0) && (ctxt->state->value != NULL) &&
! 8868: (ctxt->state->value != ctxt->state->endvalue)) {
! 8869: VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
! 8870: ctxt->state->value);
! 8871: ret = -1;
! 8872: }
! 8873: xmlFree(val);
! 8874: ctxt->state->value = oldvalue;
! 8875: ctxt->state->endvalue = oldend;
! 8876: break;
! 8877: }
! 8878: case XML_RELAXNG_ONEORMORE:
! 8879: ret = xmlRelaxNGValidateValueList(ctxt, define->content);
! 8880: if (ret != 0) {
! 8881: break;
! 8882: }
! 8883: /* no break on purpose */
! 8884: case XML_RELAXNG_ZEROORMORE:{
! 8885: xmlChar *cur, *temp;
! 8886:
! 8887: oldflags = ctxt->flags;
! 8888: ctxt->flags |= FLAGS_IGNORABLE;
! 8889: cur = ctxt->state->value;
! 8890: temp = NULL;
! 8891: while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
! 8892: (temp != cur)) {
! 8893: temp = cur;
! 8894: ret =
! 8895: xmlRelaxNGValidateValueList(ctxt, define->content);
! 8896: if (ret != 0) {
! 8897: ctxt->state->value = temp;
! 8898: ret = 0;
! 8899: break;
! 8900: }
! 8901: cur = ctxt->state->value;
! 8902: }
! 8903: ctxt->flags = oldflags;
! 8904: if (ctxt->errNr > 0)
! 8905: xmlRelaxNGPopErrors(ctxt, 0);
! 8906: break;
! 8907: }
! 8908: case XML_RELAXNG_EXCEPT:{
! 8909: xmlRelaxNGDefinePtr list;
! 8910:
! 8911: list = define->content;
! 8912: while (list != NULL) {
! 8913: ret = xmlRelaxNGValidateValue(ctxt, list);
! 8914: if (ret == 0) {
! 8915: ret = -1;
! 8916: break;
! 8917: } else
! 8918: ret = 0;
! 8919: list = list->next;
! 8920: }
! 8921: break;
! 8922: }
! 8923: case XML_RELAXNG_DEF:
! 8924: case XML_RELAXNG_GROUP:{
! 8925: xmlRelaxNGDefinePtr list;
! 8926:
! 8927: list = define->content;
! 8928: while (list != NULL) {
! 8929: ret = xmlRelaxNGValidateValue(ctxt, list);
! 8930: if (ret != 0) {
! 8931: ret = -1;
! 8932: break;
! 8933: } else
! 8934: ret = 0;
! 8935: list = list->next;
! 8936: }
! 8937: break;
! 8938: }
! 8939: case XML_RELAXNG_REF:
! 8940: case XML_RELAXNG_PARENTREF:
! 8941: if (define->content == NULL) {
! 8942: VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
! 8943: ret = -1;
! 8944: } else {
! 8945: ret = xmlRelaxNGValidateValue(ctxt, define->content);
! 8946: }
! 8947: break;
! 8948: default:
! 8949: TODO ret = -1;
! 8950: }
! 8951: return (ret);
! 8952: }
! 8953:
! 8954: /**
! 8955: * xmlRelaxNGValidateValueContent:
! 8956: * @ctxt: a Relax-NG validation context
! 8957: * @defines: the list of definitions to verify
! 8958: *
! 8959: * Validate the given definitions for the current value
! 8960: *
! 8961: * Returns 0 if the validation succeeded or an error code.
! 8962: */
! 8963: static int
! 8964: xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
! 8965: xmlRelaxNGDefinePtr defines)
! 8966: {
! 8967: int ret = 0;
! 8968:
! 8969: while (defines != NULL) {
! 8970: ret = xmlRelaxNGValidateValue(ctxt, defines);
! 8971: if (ret != 0)
! 8972: break;
! 8973: defines = defines->next;
! 8974: }
! 8975: return (ret);
! 8976: }
! 8977:
! 8978: /**
! 8979: * xmlRelaxNGAttributeMatch:
! 8980: * @ctxt: a Relax-NG validation context
! 8981: * @define: the definition to check
! 8982: * @prop: the attribute
! 8983: *
! 8984: * Check if the attribute matches the definition nameClass
! 8985: *
! 8986: * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
! 8987: */
! 8988: static int
! 8989: xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
! 8990: xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
! 8991: {
! 8992: int ret;
! 8993:
! 8994: if (define->name != NULL) {
! 8995: if (!xmlStrEqual(define->name, prop->name))
! 8996: return (0);
! 8997: }
! 8998: if (define->ns != NULL) {
! 8999: if (define->ns[0] == 0) {
! 9000: if (prop->ns != NULL)
! 9001: return (0);
! 9002: } else {
! 9003: if ((prop->ns == NULL) ||
! 9004: (!xmlStrEqual(define->ns, prop->ns->href)))
! 9005: return (0);
! 9006: }
! 9007: }
! 9008: if (define->nameClass == NULL)
! 9009: return (1);
! 9010: define = define->nameClass;
! 9011: if (define->type == XML_RELAXNG_EXCEPT) {
! 9012: xmlRelaxNGDefinePtr list;
! 9013:
! 9014: list = define->content;
! 9015: while (list != NULL) {
! 9016: ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
! 9017: if (ret == 1)
! 9018: return (0);
! 9019: if (ret < 0)
! 9020: return (ret);
! 9021: list = list->next;
! 9022: }
! 9023: } else {
! 9024: TODO}
! 9025: return (1);
! 9026: }
! 9027:
! 9028: /**
! 9029: * xmlRelaxNGValidateAttribute:
! 9030: * @ctxt: a Relax-NG validation context
! 9031: * @define: the definition to verify
! 9032: *
! 9033: * Validate the given attribute definition for that node
! 9034: *
! 9035: * Returns 0 if the validation succeeded or an error code.
! 9036: */
! 9037: static int
! 9038: xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
! 9039: xmlRelaxNGDefinePtr define)
! 9040: {
! 9041: int ret = 0, i;
! 9042: xmlChar *value, *oldvalue;
! 9043: xmlAttrPtr prop = NULL, tmp;
! 9044: xmlNodePtr oldseq;
! 9045:
! 9046: if (ctxt->state->nbAttrLeft <= 0)
! 9047: return (-1);
! 9048: if (define->name != NULL) {
! 9049: for (i = 0; i < ctxt->state->nbAttrs; i++) {
! 9050: tmp = ctxt->state->attrs[i];
! 9051: if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
! 9052: if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
! 9053: (tmp->ns == NULL)) ||
! 9054: ((tmp->ns != NULL) &&
! 9055: (xmlStrEqual(define->ns, tmp->ns->href)))) {
! 9056: prop = tmp;
! 9057: break;
! 9058: }
! 9059: }
! 9060: }
! 9061: if (prop != NULL) {
! 9062: value = xmlNodeListGetString(prop->doc, prop->children, 1);
! 9063: oldvalue = ctxt->state->value;
! 9064: oldseq = ctxt->state->seq;
! 9065: ctxt->state->seq = (xmlNodePtr) prop;
! 9066: ctxt->state->value = value;
! 9067: ctxt->state->endvalue = NULL;
! 9068: ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
! 9069: if (ctxt->state->value != NULL)
! 9070: value = ctxt->state->value;
! 9071: if (value != NULL)
! 9072: xmlFree(value);
! 9073: ctxt->state->value = oldvalue;
! 9074: ctxt->state->seq = oldseq;
! 9075: if (ret == 0) {
! 9076: /*
! 9077: * flag the attribute as processed
! 9078: */
! 9079: ctxt->state->attrs[i] = NULL;
! 9080: ctxt->state->nbAttrLeft--;
! 9081: }
! 9082: } else {
! 9083: ret = -1;
! 9084: }
! 9085: #ifdef DEBUG
! 9086: xmlGenericError(xmlGenericErrorContext,
! 9087: "xmlRelaxNGValidateAttribute(%s): %d\n",
! 9088: define->name, ret);
! 9089: #endif
! 9090: } else {
! 9091: for (i = 0; i < ctxt->state->nbAttrs; i++) {
! 9092: tmp = ctxt->state->attrs[i];
! 9093: if ((tmp != NULL) &&
! 9094: (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
! 9095: prop = tmp;
! 9096: break;
! 9097: }
! 9098: }
! 9099: if (prop != NULL) {
! 9100: value = xmlNodeListGetString(prop->doc, prop->children, 1);
! 9101: oldvalue = ctxt->state->value;
! 9102: oldseq = ctxt->state->seq;
! 9103: ctxt->state->seq = (xmlNodePtr) prop;
! 9104: ctxt->state->value = value;
! 9105: ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
! 9106: if (ctxt->state->value != NULL)
! 9107: value = ctxt->state->value;
! 9108: if (value != NULL)
! 9109: xmlFree(value);
! 9110: ctxt->state->value = oldvalue;
! 9111: ctxt->state->seq = oldseq;
! 9112: if (ret == 0) {
! 9113: /*
! 9114: * flag the attribute as processed
! 9115: */
! 9116: ctxt->state->attrs[i] = NULL;
! 9117: ctxt->state->nbAttrLeft--;
! 9118: }
! 9119: } else {
! 9120: ret = -1;
! 9121: }
! 9122: #ifdef DEBUG
! 9123: if (define->ns != NULL) {
! 9124: xmlGenericError(xmlGenericErrorContext,
! 9125: "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
! 9126: define->ns, ret);
! 9127: } else {
! 9128: xmlGenericError(xmlGenericErrorContext,
! 9129: "xmlRelaxNGValidateAttribute(anyName): %d\n",
! 9130: ret);
! 9131: }
! 9132: #endif
! 9133: }
! 9134:
! 9135: return (ret);
! 9136: }
! 9137:
! 9138: /**
! 9139: * xmlRelaxNGValidateAttributeList:
! 9140: * @ctxt: a Relax-NG validation context
! 9141: * @define: the list of definition to verify
! 9142: *
! 9143: * Validate the given node against the list of attribute definitions
! 9144: *
! 9145: * Returns 0 if the validation succeeded or an error code.
! 9146: */
! 9147: static int
! 9148: xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
! 9149: xmlRelaxNGDefinePtr defines)
! 9150: {
! 9151: int ret = 0, res;
! 9152: int needmore = 0;
! 9153: xmlRelaxNGDefinePtr cur;
! 9154:
! 9155: cur = defines;
! 9156: while (cur != NULL) {
! 9157: if (cur->type == XML_RELAXNG_ATTRIBUTE) {
! 9158: if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
! 9159: ret = -1;
! 9160: } else
! 9161: needmore = 1;
! 9162: cur = cur->next;
! 9163: }
! 9164: if (!needmore)
! 9165: return (ret);
! 9166: cur = defines;
! 9167: while (cur != NULL) {
! 9168: if (cur->type != XML_RELAXNG_ATTRIBUTE) {
! 9169: if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
! 9170: res = xmlRelaxNGValidateDefinition(ctxt, cur);
! 9171: if (res < 0)
! 9172: ret = -1;
! 9173: } else {
! 9174: VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
! 9175: return (-1);
! 9176: }
! 9177: if (res == -1) /* continues on -2 */
! 9178: break;
! 9179: }
! 9180: cur = cur->next;
! 9181: }
! 9182:
! 9183: return (ret);
! 9184: }
! 9185:
! 9186: /**
! 9187: * xmlRelaxNGNodeMatchesList:
! 9188: * @node: the node
! 9189: * @list: a NULL terminated array of definitions
! 9190: *
! 9191: * Check if a node can be matched by one of the definitions
! 9192: *
! 9193: * Returns 1 if matches 0 otherwise
! 9194: */
! 9195: static int
! 9196: xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
! 9197: {
! 9198: xmlRelaxNGDefinePtr cur;
! 9199: int i = 0, tmp;
! 9200:
! 9201: if ((node == NULL) || (list == NULL))
! 9202: return (0);
! 9203:
! 9204: cur = list[i++];
! 9205: while (cur != NULL) {
! 9206: if ((node->type == XML_ELEMENT_NODE) &&
! 9207: (cur->type == XML_RELAXNG_ELEMENT)) {
! 9208: tmp = xmlRelaxNGElementMatch(NULL, cur, node);
! 9209: if (tmp == 1)
! 9210: return (1);
! 9211: } else if (((node->type == XML_TEXT_NODE) ||
! 9212: (node->type == XML_CDATA_SECTION_NODE)) &&
! 9213: (cur->type == XML_RELAXNG_TEXT)) {
! 9214: return (1);
! 9215: }
! 9216: cur = list[i++];
! 9217: }
! 9218: return (0);
! 9219: }
! 9220:
! 9221: /**
! 9222: * xmlRelaxNGValidateInterleave:
! 9223: * @ctxt: a Relax-NG validation context
! 9224: * @define: the definition to verify
! 9225: *
! 9226: * Validate an interleave definition for a node.
! 9227: *
! 9228: * Returns 0 if the validation succeeded or an error code.
! 9229: */
! 9230: static int
! 9231: xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
! 9232: xmlRelaxNGDefinePtr define)
! 9233: {
! 9234: int ret = 0, i, nbgroups;
! 9235: int errNr = ctxt->errNr;
! 9236: int oldflags;
! 9237:
! 9238: xmlRelaxNGValidStatePtr oldstate;
! 9239: xmlRelaxNGPartitionPtr partitions;
! 9240: xmlRelaxNGInterleaveGroupPtr group = NULL;
! 9241: xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
! 9242: xmlNodePtr *list = NULL, *lasts = NULL;
! 9243:
! 9244: if (define->data != NULL) {
! 9245: partitions = (xmlRelaxNGPartitionPtr) define->data;
! 9246: nbgroups = partitions->nbgroups;
! 9247: } else {
! 9248: VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
! 9249: return (-1);
! 9250: }
! 9251: /*
! 9252: * Optimizations for MIXED
! 9253: */
! 9254: oldflags = ctxt->flags;
! 9255: if (define->dflags & IS_MIXED) {
! 9256: ctxt->flags |= FLAGS_MIXED_CONTENT;
! 9257: if (nbgroups == 2) {
! 9258: /*
! 9259: * this is a pure <mixed> case
! 9260: */
! 9261: if (ctxt->state != NULL)
! 9262: ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
! 9263: ctxt->state->seq);
! 9264: if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
! 9265: ret = xmlRelaxNGValidateDefinition(ctxt,
! 9266: partitions->groups[1]->
! 9267: rule);
! 9268: else
! 9269: ret = xmlRelaxNGValidateDefinition(ctxt,
! 9270: partitions->groups[0]->
! 9271: rule);
! 9272: if (ret == 0) {
! 9273: if (ctxt->state != NULL)
! 9274: ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
! 9275: ctxt->state->
! 9276: seq);
! 9277: }
! 9278: ctxt->flags = oldflags;
! 9279: return (ret);
! 9280: }
! 9281: }
! 9282:
! 9283: /*
! 9284: * Build arrays to store the first and last node of the chain
! 9285: * pertaining to each group
! 9286: */
! 9287: list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
! 9288: if (list == NULL) {
! 9289: xmlRngVErrMemory(ctxt, "validating\n");
! 9290: return (-1);
! 9291: }
! 9292: memset(list, 0, nbgroups * sizeof(xmlNodePtr));
! 9293: lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
! 9294: if (lasts == NULL) {
! 9295: xmlRngVErrMemory(ctxt, "validating\n");
! 9296: return (-1);
! 9297: }
! 9298: memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
! 9299:
! 9300: /*
! 9301: * Walk the sequence of children finding the right group and
! 9302: * sorting them in sequences.
! 9303: */
! 9304: cur = ctxt->state->seq;
! 9305: cur = xmlRelaxNGSkipIgnored(ctxt, cur);
! 9306: start = cur;
! 9307: while (cur != NULL) {
! 9308: ctxt->state->seq = cur;
! 9309: if ((partitions->triage != NULL) &&
! 9310: (partitions->flags & IS_DETERMINIST)) {
! 9311: void *tmp = NULL;
! 9312:
! 9313: if ((cur->type == XML_TEXT_NODE) ||
! 9314: (cur->type == XML_CDATA_SECTION_NODE)) {
! 9315: tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
! 9316: NULL);
! 9317: } else if (cur->type == XML_ELEMENT_NODE) {
! 9318: if (cur->ns != NULL) {
! 9319: tmp = xmlHashLookup2(partitions->triage, cur->name,
! 9320: cur->ns->href);
! 9321: if (tmp == NULL)
! 9322: tmp = xmlHashLookup2(partitions->triage,
! 9323: BAD_CAST "#any",
! 9324: cur->ns->href);
! 9325: } else
! 9326: tmp =
! 9327: xmlHashLookup2(partitions->triage, cur->name,
! 9328: NULL);
! 9329: if (tmp == NULL)
! 9330: tmp =
! 9331: xmlHashLookup2(partitions->triage, BAD_CAST "#any",
! 9332: NULL);
! 9333: }
! 9334:
! 9335: if (tmp == NULL) {
! 9336: i = nbgroups;
! 9337: } else {
! 9338: i = ((long) tmp) - 1;
! 9339: if (partitions->flags & IS_NEEDCHECK) {
! 9340: group = partitions->groups[i];
! 9341: if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
! 9342: i = nbgroups;
! 9343: }
! 9344: }
! 9345: } else {
! 9346: for (i = 0; i < nbgroups; i++) {
! 9347: group = partitions->groups[i];
! 9348: if (group == NULL)
! 9349: continue;
! 9350: if (xmlRelaxNGNodeMatchesList(cur, group->defs))
! 9351: break;
! 9352: }
! 9353: }
! 9354: /*
! 9355: * We break as soon as an element not matched is found
! 9356: */
! 9357: if (i >= nbgroups) {
! 9358: break;
! 9359: }
! 9360: if (lasts[i] != NULL) {
! 9361: lasts[i]->next = cur;
! 9362: lasts[i] = cur;
! 9363: } else {
! 9364: list[i] = cur;
! 9365: lasts[i] = cur;
! 9366: }
! 9367: if (cur->next != NULL)
! 9368: lastchg = cur->next;
! 9369: else
! 9370: lastchg = cur;
! 9371: cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
! 9372: }
! 9373: if (ret != 0) {
! 9374: VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
! 9375: ret = -1;
! 9376: goto done;
! 9377: }
! 9378: lastelem = cur;
! 9379: oldstate = ctxt->state;
! 9380: for (i = 0; i < nbgroups; i++) {
! 9381: ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
! 9382: group = partitions->groups[i];
! 9383: if (lasts[i] != NULL) {
! 9384: last = lasts[i]->next;
! 9385: lasts[i]->next = NULL;
! 9386: }
! 9387: ctxt->state->seq = list[i];
! 9388: ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
! 9389: if (ret != 0)
! 9390: break;
! 9391: if (ctxt->state != NULL) {
! 9392: cur = ctxt->state->seq;
! 9393: cur = xmlRelaxNGSkipIgnored(ctxt, cur);
! 9394: xmlRelaxNGFreeValidState(ctxt, oldstate);
! 9395: oldstate = ctxt->state;
! 9396: ctxt->state = NULL;
! 9397: if (cur != NULL) {
! 9398: VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
! 9399: ret = -1;
! 9400: ctxt->state = oldstate;
! 9401: goto done;
! 9402: }
! 9403: } else if (ctxt->states != NULL) {
! 9404: int j;
! 9405: int found = 0;
! 9406: int best = -1;
! 9407: int lowattr = -1;
! 9408:
! 9409: /*
! 9410: * PBM: what happen if there is attributes checks in the interleaves
! 9411: */
! 9412:
! 9413: for (j = 0; j < ctxt->states->nbState; j++) {
! 9414: cur = ctxt->states->tabState[j]->seq;
! 9415: cur = xmlRelaxNGSkipIgnored(ctxt, cur);
! 9416: if (cur == NULL) {
! 9417: if (found == 0) {
! 9418: lowattr = ctxt->states->tabState[j]->nbAttrLeft;
! 9419: best = j;
! 9420: }
! 9421: found = 1;
! 9422: if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
! 9423: /* try to keep the latest one to mach old heuristic */
! 9424: lowattr = ctxt->states->tabState[j]->nbAttrLeft;
! 9425: best = j;
! 9426: }
! 9427: if (lowattr == 0)
! 9428: break;
! 9429: } else if (found == 0) {
! 9430: if (lowattr == -1) {
! 9431: lowattr = ctxt->states->tabState[j]->nbAttrLeft;
! 9432: best = j;
! 9433: } else
! 9434: if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
! 9435: /* try to keep the latest one to mach old heuristic */
! 9436: lowattr = ctxt->states->tabState[j]->nbAttrLeft;
! 9437: best = j;
! 9438: }
! 9439: }
! 9440: }
! 9441: /*
! 9442: * BIG PBM: here we pick only one restarting point :-(
! 9443: */
! 9444: if (ctxt->states->nbState > 0) {
! 9445: xmlRelaxNGFreeValidState(ctxt, oldstate);
! 9446: if (best != -1) {
! 9447: oldstate = ctxt->states->tabState[best];
! 9448: ctxt->states->tabState[best] = NULL;
! 9449: } else {
! 9450: oldstate =
! 9451: ctxt->states->tabState[ctxt->states->nbState - 1];
! 9452: ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
! 9453: ctxt->states->nbState--;
! 9454: }
! 9455: }
! 9456: for (j = 0; j < ctxt->states->nbState ; j++) {
! 9457: xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
! 9458: }
! 9459: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 9460: ctxt->states = NULL;
! 9461: if (found == 0) {
! 9462: if (cur == NULL) {
! 9463: VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
! 9464: (const xmlChar *) "noname");
! 9465: } else {
! 9466: VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
! 9467: }
! 9468: ret = -1;
! 9469: ctxt->state = oldstate;
! 9470: goto done;
! 9471: }
! 9472: } else {
! 9473: ret = -1;
! 9474: break;
! 9475: }
! 9476: if (lasts[i] != NULL) {
! 9477: lasts[i]->next = last;
! 9478: }
! 9479: }
! 9480: if (ctxt->state != NULL)
! 9481: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 9482: ctxt->state = oldstate;
! 9483: ctxt->state->seq = lastelem;
! 9484: if (ret != 0) {
! 9485: VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
! 9486: ret = -1;
! 9487: goto done;
! 9488: }
! 9489:
! 9490: done:
! 9491: ctxt->flags = oldflags;
! 9492: /*
! 9493: * builds the next links chain from the prev one
! 9494: */
! 9495: cur = lastchg;
! 9496: while (cur != NULL) {
! 9497: if ((cur == start) || (cur->prev == NULL))
! 9498: break;
! 9499: cur->prev->next = cur;
! 9500: cur = cur->prev;
! 9501: }
! 9502: if (ret == 0) {
! 9503: if (ctxt->errNr > errNr)
! 9504: xmlRelaxNGPopErrors(ctxt, errNr);
! 9505: }
! 9506:
! 9507: xmlFree(list);
! 9508: xmlFree(lasts);
! 9509: return (ret);
! 9510: }
! 9511:
! 9512: /**
! 9513: * xmlRelaxNGValidateDefinitionList:
! 9514: * @ctxt: a Relax-NG validation context
! 9515: * @define: the list of definition to verify
! 9516: *
! 9517: * Validate the given node content against the (list) of definitions
! 9518: *
! 9519: * Returns 0 if the validation succeeded or an error code.
! 9520: */
! 9521: static int
! 9522: xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
! 9523: xmlRelaxNGDefinePtr defines)
! 9524: {
! 9525: int ret = 0, res;
! 9526:
! 9527:
! 9528: if (defines == NULL) {
! 9529: VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
! 9530: BAD_CAST "NULL definition list");
! 9531: return (-1);
! 9532: }
! 9533: while (defines != NULL) {
! 9534: if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
! 9535: res = xmlRelaxNGValidateDefinition(ctxt, defines);
! 9536: if (res < 0)
! 9537: ret = -1;
! 9538: } else {
! 9539: VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
! 9540: return (-1);
! 9541: }
! 9542: if (res == -1) /* continues on -2 */
! 9543: break;
! 9544: defines = defines->next;
! 9545: }
! 9546:
! 9547: return (ret);
! 9548: }
! 9549:
! 9550: /**
! 9551: * xmlRelaxNGElementMatch:
! 9552: * @ctxt: a Relax-NG validation context
! 9553: * @define: the definition to check
! 9554: * @elem: the element
! 9555: *
! 9556: * Check if the element matches the definition nameClass
! 9557: *
! 9558: * Returns 1 if the element matches, 0 if no, or -1 in case of error
! 9559: */
! 9560: static int
! 9561: xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
! 9562: xmlRelaxNGDefinePtr define, xmlNodePtr elem)
! 9563: {
! 9564: int ret = 0, oldflags = 0;
! 9565:
! 9566: if (define->name != NULL) {
! 9567: if (!xmlStrEqual(elem->name, define->name)) {
! 9568: VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
! 9569: return (0);
! 9570: }
! 9571: }
! 9572: if ((define->ns != NULL) && (define->ns[0] != 0)) {
! 9573: if (elem->ns == NULL) {
! 9574: VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
! 9575: return (0);
! 9576: } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
! 9577: VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
! 9578: elem->name, define->ns);
! 9579: return (0);
! 9580: }
! 9581: } else if ((elem->ns != NULL) && (define->ns != NULL) &&
! 9582: (define->name == NULL)) {
! 9583: VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
! 9584: return (0);
! 9585: } else if ((elem->ns != NULL) && (define->name != NULL)) {
! 9586: VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
! 9587: return (0);
! 9588: }
! 9589:
! 9590: if (define->nameClass == NULL)
! 9591: return (1);
! 9592:
! 9593: define = define->nameClass;
! 9594: if (define->type == XML_RELAXNG_EXCEPT) {
! 9595: xmlRelaxNGDefinePtr list;
! 9596:
! 9597: if (ctxt != NULL) {
! 9598: oldflags = ctxt->flags;
! 9599: ctxt->flags |= FLAGS_IGNORABLE;
! 9600: }
! 9601:
! 9602: list = define->content;
! 9603: while (list != NULL) {
! 9604: ret = xmlRelaxNGElementMatch(ctxt, list, elem);
! 9605: if (ret == 1) {
! 9606: if (ctxt != NULL)
! 9607: ctxt->flags = oldflags;
! 9608: return (0);
! 9609: }
! 9610: if (ret < 0) {
! 9611: if (ctxt != NULL)
! 9612: ctxt->flags = oldflags;
! 9613: return (ret);
! 9614: }
! 9615: list = list->next;
! 9616: }
! 9617: ret = 1;
! 9618: if (ctxt != NULL) {
! 9619: ctxt->flags = oldflags;
! 9620: }
! 9621: } else if (define->type == XML_RELAXNG_CHOICE) {
! 9622: xmlRelaxNGDefinePtr list;
! 9623:
! 9624: if (ctxt != NULL) {
! 9625: oldflags = ctxt->flags;
! 9626: ctxt->flags |= FLAGS_IGNORABLE;
! 9627: }
! 9628:
! 9629: list = define->nameClass;
! 9630: while (list != NULL) {
! 9631: ret = xmlRelaxNGElementMatch(ctxt, list, elem);
! 9632: if (ret == 1) {
! 9633: if (ctxt != NULL)
! 9634: ctxt->flags = oldflags;
! 9635: return (1);
! 9636: }
! 9637: if (ret < 0) {
! 9638: if (ctxt != NULL)
! 9639: ctxt->flags = oldflags;
! 9640: return (ret);
! 9641: }
! 9642: list = list->next;
! 9643: }
! 9644: if (ctxt != NULL) {
! 9645: if (ret != 0) {
! 9646: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 9647: xmlRelaxNGDumpValidError(ctxt);
! 9648: } else {
! 9649: if (ctxt->errNr > 0)
! 9650: xmlRelaxNGPopErrors(ctxt, 0);
! 9651: }
! 9652: }
! 9653: ret = 0;
! 9654: if (ctxt != NULL) {
! 9655: ctxt->flags = oldflags;
! 9656: }
! 9657: } else {
! 9658: TODO ret = -1;
! 9659: }
! 9660: return (ret);
! 9661: }
! 9662:
! 9663: /**
! 9664: * xmlRelaxNGBestState:
! 9665: * @ctxt: a Relax-NG validation context
! 9666: *
! 9667: * Find the "best" state in the ctxt->states list of states to report
! 9668: * errors about. I.e. a state with no element left in the child list
! 9669: * or the one with the less attributes left.
! 9670: * This is called only if a falidation error was detected
! 9671: *
! 9672: * Returns the index of the "best" state or -1 in case of error
! 9673: */
! 9674: static int
! 9675: xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
! 9676: {
! 9677: xmlRelaxNGValidStatePtr state;
! 9678: int i, tmp;
! 9679: int best = -1;
! 9680: int value = 1000000;
! 9681:
! 9682: if ((ctxt == NULL) || (ctxt->states == NULL) ||
! 9683: (ctxt->states->nbState <= 0))
! 9684: return (-1);
! 9685:
! 9686: for (i = 0; i < ctxt->states->nbState; i++) {
! 9687: state = ctxt->states->tabState[i];
! 9688: if (state == NULL)
! 9689: continue;
! 9690: if (state->seq != NULL) {
! 9691: if ((best == -1) || (value > 100000)) {
! 9692: value = 100000;
! 9693: best = i;
! 9694: }
! 9695: } else {
! 9696: tmp = state->nbAttrLeft;
! 9697: if ((best == -1) || (value > tmp)) {
! 9698: value = tmp;
! 9699: best = i;
! 9700: }
! 9701: }
! 9702: }
! 9703: return (best);
! 9704: }
! 9705:
! 9706: /**
! 9707: * xmlRelaxNGLogBestError:
! 9708: * @ctxt: a Relax-NG validation context
! 9709: *
! 9710: * Find the "best" state in the ctxt->states list of states to report
! 9711: * errors about and log it.
! 9712: */
! 9713: static void
! 9714: xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
! 9715: {
! 9716: int best;
! 9717:
! 9718: if ((ctxt == NULL) || (ctxt->states == NULL) ||
! 9719: (ctxt->states->nbState <= 0))
! 9720: return;
! 9721:
! 9722: best = xmlRelaxNGBestState(ctxt);
! 9723: if ((best >= 0) && (best < ctxt->states->nbState)) {
! 9724: ctxt->state = ctxt->states->tabState[best];
! 9725:
! 9726: xmlRelaxNGValidateElementEnd(ctxt, 1);
! 9727: }
! 9728: }
! 9729:
! 9730: /**
! 9731: * xmlRelaxNGValidateElementEnd:
! 9732: * @ctxt: a Relax-NG validation context
! 9733: * @dolog: indicate that error logging should be done
! 9734: *
! 9735: * Validate the end of the element, implements check that
! 9736: * there is nothing left not consumed in the element content
! 9737: * or in the attribute list.
! 9738: *
! 9739: * Returns 0 if the validation succeeded or an error code.
! 9740: */
! 9741: static int
! 9742: xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
! 9743: {
! 9744: int i;
! 9745: xmlRelaxNGValidStatePtr state;
! 9746:
! 9747: state = ctxt->state;
! 9748: if (state->seq != NULL) {
! 9749: state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
! 9750: if (state->seq != NULL) {
! 9751: if (dolog) {
! 9752: VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
! 9753: state->node->name, state->seq->name);
! 9754: }
! 9755: return (-1);
! 9756: }
! 9757: }
! 9758: for (i = 0; i < state->nbAttrs; i++) {
! 9759: if (state->attrs[i] != NULL) {
! 9760: if (dolog) {
! 9761: VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
! 9762: state->attrs[i]->name, state->node->name);
! 9763: }
! 9764: return (-1 - i);
! 9765: }
! 9766: }
! 9767: return (0);
! 9768: }
! 9769:
! 9770: /**
! 9771: * xmlRelaxNGValidateState:
! 9772: * @ctxt: a Relax-NG validation context
! 9773: * @define: the definition to verify
! 9774: *
! 9775: * Validate the current state against the definition
! 9776: *
! 9777: * Returns 0 if the validation succeeded or an error code.
! 9778: */
! 9779: static int
! 9780: xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
! 9781: xmlRelaxNGDefinePtr define)
! 9782: {
! 9783: xmlNodePtr node;
! 9784: int ret = 0, i, tmp, oldflags, errNr;
! 9785: xmlRelaxNGValidStatePtr oldstate = NULL, state;
! 9786:
! 9787: if (define == NULL) {
! 9788: VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
! 9789: return (-1);
! 9790: }
! 9791:
! 9792: if (ctxt->state != NULL) {
! 9793: node = ctxt->state->seq;
! 9794: } else {
! 9795: node = NULL;
! 9796: }
! 9797: #ifdef DEBUG
! 9798: for (i = 0; i < ctxt->depth; i++)
! 9799: xmlGenericError(xmlGenericErrorContext, " ");
! 9800: xmlGenericError(xmlGenericErrorContext,
! 9801: "Start validating %s ", xmlRelaxNGDefName(define));
! 9802: if (define->name != NULL)
! 9803: xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
! 9804: if ((node != NULL) && (node->name != NULL))
! 9805: xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
! 9806: else
! 9807: xmlGenericError(xmlGenericErrorContext, "\n");
! 9808: #endif
! 9809: ctxt->depth++;
! 9810: switch (define->type) {
! 9811: case XML_RELAXNG_EMPTY:
! 9812: node = xmlRelaxNGSkipIgnored(ctxt, node);
! 9813: ret = 0;
! 9814: break;
! 9815: case XML_RELAXNG_NOT_ALLOWED:
! 9816: ret = -1;
! 9817: break;
! 9818: case XML_RELAXNG_TEXT:
! 9819: while ((node != NULL) &&
! 9820: ((node->type == XML_TEXT_NODE) ||
! 9821: (node->type == XML_COMMENT_NODE) ||
! 9822: (node->type == XML_PI_NODE) ||
! 9823: (node->type == XML_CDATA_SECTION_NODE)))
! 9824: node = node->next;
! 9825: ctxt->state->seq = node;
! 9826: break;
! 9827: case XML_RELAXNG_ELEMENT:
! 9828: errNr = ctxt->errNr;
! 9829: node = xmlRelaxNGSkipIgnored(ctxt, node);
! 9830: if (node == NULL) {
! 9831: VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
! 9832: ret = -1;
! 9833: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 9834: xmlRelaxNGDumpValidError(ctxt);
! 9835: break;
! 9836: }
! 9837: if (node->type != XML_ELEMENT_NODE) {
! 9838: VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
! 9839: ret = -1;
! 9840: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 9841: xmlRelaxNGDumpValidError(ctxt);
! 9842: break;
! 9843: }
! 9844: /*
! 9845: * This node was already validated successfully against
! 9846: * this definition.
! 9847: */
! 9848: if (node->psvi == define) {
! 9849: ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
! 9850: if (ctxt->errNr > errNr)
! 9851: xmlRelaxNGPopErrors(ctxt, errNr);
! 9852: if (ctxt->errNr != 0) {
! 9853: while ((ctxt->err != NULL) &&
! 9854: (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
! 9855: && (xmlStrEqual(ctxt->err->arg2, node->name)))
! 9856: ||
! 9857: ((ctxt->err->err ==
! 9858: XML_RELAXNG_ERR_ELEMEXTRANS)
! 9859: && (xmlStrEqual(ctxt->err->arg1, node->name)))
! 9860: || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
! 9861: || (ctxt->err->err ==
! 9862: XML_RELAXNG_ERR_NOTELEM)))
! 9863: xmlRelaxNGValidErrorPop(ctxt);
! 9864: }
! 9865: break;
! 9866: }
! 9867:
! 9868: ret = xmlRelaxNGElementMatch(ctxt, define, node);
! 9869: if (ret <= 0) {
! 9870: ret = -1;
! 9871: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 9872: xmlRelaxNGDumpValidError(ctxt);
! 9873: break;
! 9874: }
! 9875: ret = 0;
! 9876: if (ctxt->errNr != 0) {
! 9877: if (ctxt->errNr > errNr)
! 9878: xmlRelaxNGPopErrors(ctxt, errNr);
! 9879: while ((ctxt->err != NULL) &&
! 9880: (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
! 9881: (xmlStrEqual(ctxt->err->arg2, node->name))) ||
! 9882: ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
! 9883: (xmlStrEqual(ctxt->err->arg1, node->name))) ||
! 9884: (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
! 9885: (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
! 9886: xmlRelaxNGValidErrorPop(ctxt);
! 9887: }
! 9888: errNr = ctxt->errNr;
! 9889:
! 9890: oldflags = ctxt->flags;
! 9891: if (ctxt->flags & FLAGS_MIXED_CONTENT) {
! 9892: ctxt->flags -= FLAGS_MIXED_CONTENT;
! 9893: }
! 9894: state = xmlRelaxNGNewValidState(ctxt, node);
! 9895: if (state == NULL) {
! 9896: ret = -1;
! 9897: if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
! 9898: xmlRelaxNGDumpValidError(ctxt);
! 9899: break;
! 9900: }
! 9901:
! 9902: oldstate = ctxt->state;
! 9903: ctxt->state = state;
! 9904: if (define->attrs != NULL) {
! 9905: tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
! 9906: if (tmp != 0) {
! 9907: ret = -1;
! 9908: VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
! 9909: }
! 9910: }
! 9911: if (define->contModel != NULL) {
! 9912: xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
! 9913: xmlRelaxNGStatesPtr tmpstates = ctxt->states;
! 9914: xmlNodePtr nseq;
! 9915:
! 9916: nstate = xmlRelaxNGNewValidState(ctxt, node);
! 9917: ctxt->state = nstate;
! 9918: ctxt->states = NULL;
! 9919:
! 9920: tmp = xmlRelaxNGValidateCompiledContent(ctxt,
! 9921: define->contModel,
! 9922: ctxt->state->seq);
! 9923: nseq = ctxt->state->seq;
! 9924: ctxt->state = tmpstate;
! 9925: ctxt->states = tmpstates;
! 9926: xmlRelaxNGFreeValidState(ctxt, nstate);
! 9927:
! 9928: #ifdef DEBUG_COMPILE
! 9929: xmlGenericError(xmlGenericErrorContext,
! 9930: "Validating content of '%s' : %d\n",
! 9931: define->name, tmp);
! 9932: #endif
! 9933: if (tmp != 0)
! 9934: ret = -1;
! 9935:
! 9936: if (ctxt->states != NULL) {
! 9937: tmp = -1;
! 9938:
! 9939: for (i = 0; i < ctxt->states->nbState; i++) {
! 9940: state = ctxt->states->tabState[i];
! 9941: ctxt->state = state;
! 9942: ctxt->state->seq = nseq;
! 9943:
! 9944: if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
! 9945: tmp = 0;
! 9946: break;
! 9947: }
! 9948: }
! 9949: if (tmp != 0) {
! 9950: /*
! 9951: * validation error, log the message for the "best" one
! 9952: */
! 9953: ctxt->flags |= FLAGS_IGNORABLE;
! 9954: xmlRelaxNGLogBestError(ctxt);
! 9955: }
! 9956: for (i = 0; i < ctxt->states->nbState; i++) {
! 9957: xmlRelaxNGFreeValidState(ctxt,
! 9958: ctxt->states->
! 9959: tabState[i]);
! 9960: }
! 9961: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 9962: ctxt->flags = oldflags;
! 9963: ctxt->states = NULL;
! 9964: if ((ret == 0) && (tmp == -1))
! 9965: ret = -1;
! 9966: } else {
! 9967: state = ctxt->state;
! 9968: if (ctxt->state != NULL)
! 9969: ctxt->state->seq = nseq;
! 9970: if (ret == 0)
! 9971: ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
! 9972: xmlRelaxNGFreeValidState(ctxt, state);
! 9973: }
! 9974: } else {
! 9975: if (define->content != NULL) {
! 9976: tmp = xmlRelaxNGValidateDefinitionList(ctxt,
! 9977: define->
! 9978: content);
! 9979: if (tmp != 0) {
! 9980: ret = -1;
! 9981: if (ctxt->state == NULL) {
! 9982: ctxt->state = oldstate;
! 9983: VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
! 9984: node->name);
! 9985: ctxt->state = NULL;
! 9986: } else {
! 9987: VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
! 9988: node->name);
! 9989: }
! 9990:
! 9991: }
! 9992: }
! 9993: if (ctxt->states != NULL) {
! 9994: tmp = -1;
! 9995:
! 9996: for (i = 0; i < ctxt->states->nbState; i++) {
! 9997: state = ctxt->states->tabState[i];
! 9998: ctxt->state = state;
! 9999:
! 10000: if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
! 10001: tmp = 0;
! 10002: break;
! 10003: }
! 10004: }
! 10005: if (tmp != 0) {
! 10006: /*
! 10007: * validation error, log the message for the "best" one
! 10008: */
! 10009: ctxt->flags |= FLAGS_IGNORABLE;
! 10010: xmlRelaxNGLogBestError(ctxt);
! 10011: }
! 10012: for (i = 0; i < ctxt->states->nbState; i++) {
! 10013: xmlRelaxNGFreeValidState(ctxt,
! 10014: ctxt->states->tabState[i]);
! 10015: ctxt->states->tabState[i] = NULL;
! 10016: }
! 10017: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10018: ctxt->flags = oldflags;
! 10019: ctxt->states = NULL;
! 10020: if ((ret == 0) && (tmp == -1))
! 10021: ret = -1;
! 10022: } else {
! 10023: state = ctxt->state;
! 10024: if (ret == 0)
! 10025: ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
! 10026: xmlRelaxNGFreeValidState(ctxt, state);
! 10027: }
! 10028: }
! 10029: if (ret == 0) {
! 10030: node->psvi = define;
! 10031: }
! 10032: ctxt->flags = oldflags;
! 10033: ctxt->state = oldstate;
! 10034: if (oldstate != NULL)
! 10035: oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
! 10036: if (ret != 0) {
! 10037: if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
! 10038: xmlRelaxNGDumpValidError(ctxt);
! 10039: ret = 0;
! 10040: #if 0
! 10041: } else {
! 10042: ret = -2;
! 10043: #endif
! 10044: }
! 10045: } else {
! 10046: if (ctxt->errNr > errNr)
! 10047: xmlRelaxNGPopErrors(ctxt, errNr);
! 10048: }
! 10049:
! 10050: #ifdef DEBUG
! 10051: xmlGenericError(xmlGenericErrorContext,
! 10052: "xmlRelaxNGValidateDefinition(): validated %s : %d",
! 10053: node->name, ret);
! 10054: if (oldstate == NULL)
! 10055: xmlGenericError(xmlGenericErrorContext, ": no state\n");
! 10056: else if (oldstate->seq == NULL)
! 10057: xmlGenericError(xmlGenericErrorContext, ": done\n");
! 10058: else if (oldstate->seq->type == XML_ELEMENT_NODE)
! 10059: xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
! 10060: oldstate->seq->name);
! 10061: else
! 10062: xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
! 10063: oldstate->seq->name, oldstate->seq->type);
! 10064: #endif
! 10065: break;
! 10066: case XML_RELAXNG_OPTIONAL:{
! 10067: errNr = ctxt->errNr;
! 10068: oldflags = ctxt->flags;
! 10069: ctxt->flags |= FLAGS_IGNORABLE;
! 10070: oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
! 10071: ret =
! 10072: xmlRelaxNGValidateDefinitionList(ctxt,
! 10073: define->content);
! 10074: if (ret != 0) {
! 10075: if (ctxt->state != NULL)
! 10076: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10077: ctxt->state = oldstate;
! 10078: ctxt->flags = oldflags;
! 10079: ret = 0;
! 10080: if (ctxt->errNr > errNr)
! 10081: xmlRelaxNGPopErrors(ctxt, errNr);
! 10082: break;
! 10083: }
! 10084: if (ctxt->states != NULL) {
! 10085: xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
! 10086: } else {
! 10087: ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
! 10088: if (ctxt->states == NULL) {
! 10089: xmlRelaxNGFreeValidState(ctxt, oldstate);
! 10090: ctxt->flags = oldflags;
! 10091: ret = -1;
! 10092: if (ctxt->errNr > errNr)
! 10093: xmlRelaxNGPopErrors(ctxt, errNr);
! 10094: break;
! 10095: }
! 10096: xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
! 10097: xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
! 10098: ctxt->state = NULL;
! 10099: }
! 10100: ctxt->flags = oldflags;
! 10101: ret = 0;
! 10102: if (ctxt->errNr > errNr)
! 10103: xmlRelaxNGPopErrors(ctxt, errNr);
! 10104: break;
! 10105: }
! 10106: case XML_RELAXNG_ONEORMORE:
! 10107: errNr = ctxt->errNr;
! 10108: ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
! 10109: if (ret != 0) {
! 10110: break;
! 10111: }
! 10112: if (ctxt->errNr > errNr)
! 10113: xmlRelaxNGPopErrors(ctxt, errNr);
! 10114: /* no break on purpose */
! 10115: case XML_RELAXNG_ZEROORMORE:{
! 10116: int progress;
! 10117: xmlRelaxNGStatesPtr states = NULL, res = NULL;
! 10118: int base, j;
! 10119:
! 10120: errNr = ctxt->errNr;
! 10121: res = xmlRelaxNGNewStates(ctxt, 1);
! 10122: if (res == NULL) {
! 10123: ret = -1;
! 10124: break;
! 10125: }
! 10126: /*
! 10127: * All the input states are also exit states
! 10128: */
! 10129: if (ctxt->state != NULL) {
! 10130: xmlRelaxNGAddStates(ctxt, res,
! 10131: xmlRelaxNGCopyValidState(ctxt,
! 10132: ctxt->
! 10133: state));
! 10134: } else {
! 10135: for (j = 0; j < ctxt->states->nbState; j++) {
! 10136: xmlRelaxNGAddStates(ctxt, res,
! 10137: xmlRelaxNGCopyValidState(ctxt,
! 10138: ctxt->states->tabState[j]));
! 10139: }
! 10140: }
! 10141: oldflags = ctxt->flags;
! 10142: ctxt->flags |= FLAGS_IGNORABLE;
! 10143: do {
! 10144: progress = 0;
! 10145: base = res->nbState;
! 10146:
! 10147: if (ctxt->states != NULL) {
! 10148: states = ctxt->states;
! 10149: for (i = 0; i < states->nbState; i++) {
! 10150: ctxt->state = states->tabState[i];
! 10151: ctxt->states = NULL;
! 10152: ret = xmlRelaxNGValidateDefinitionList(ctxt,
! 10153: define->
! 10154: content);
! 10155: if (ret == 0) {
! 10156: if (ctxt->state != NULL) {
! 10157: tmp = xmlRelaxNGAddStates(ctxt, res,
! 10158: ctxt->state);
! 10159: ctxt->state = NULL;
! 10160: if (tmp == 1)
! 10161: progress = 1;
! 10162: } else if (ctxt->states != NULL) {
! 10163: for (j = 0; j < ctxt->states->nbState;
! 10164: j++) {
! 10165: tmp =
! 10166: xmlRelaxNGAddStates(ctxt, res,
! 10167: ctxt->states->tabState[j]);
! 10168: if (tmp == 1)
! 10169: progress = 1;
! 10170: }
! 10171: xmlRelaxNGFreeStates(ctxt,
! 10172: ctxt->states);
! 10173: ctxt->states = NULL;
! 10174: }
! 10175: } else {
! 10176: if (ctxt->state != NULL) {
! 10177: xmlRelaxNGFreeValidState(ctxt,
! 10178: ctxt->state);
! 10179: ctxt->state = NULL;
! 10180: }
! 10181: }
! 10182: }
! 10183: } else {
! 10184: ret = xmlRelaxNGValidateDefinitionList(ctxt,
! 10185: define->
! 10186: content);
! 10187: if (ret != 0) {
! 10188: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10189: ctxt->state = NULL;
! 10190: } else {
! 10191: base = res->nbState;
! 10192: if (ctxt->state != NULL) {
! 10193: tmp = xmlRelaxNGAddStates(ctxt, res,
! 10194: ctxt->state);
! 10195: ctxt->state = NULL;
! 10196: if (tmp == 1)
! 10197: progress = 1;
! 10198: } else if (ctxt->states != NULL) {
! 10199: for (j = 0; j < ctxt->states->nbState; j++) {
! 10200: tmp = xmlRelaxNGAddStates(ctxt, res,
! 10201: ctxt->states->tabState[j]);
! 10202: if (tmp == 1)
! 10203: progress = 1;
! 10204: }
! 10205: if (states == NULL) {
! 10206: states = ctxt->states;
! 10207: } else {
! 10208: xmlRelaxNGFreeStates(ctxt,
! 10209: ctxt->states);
! 10210: }
! 10211: ctxt->states = NULL;
! 10212: }
! 10213: }
! 10214: }
! 10215: if (progress) {
! 10216: /*
! 10217: * Collect all the new nodes added at that step
! 10218: * and make them the new node set
! 10219: */
! 10220: if (res->nbState - base == 1) {
! 10221: ctxt->state = xmlRelaxNGCopyValidState(ctxt,
! 10222: res->
! 10223: tabState
! 10224: [base]);
! 10225: } else {
! 10226: if (states == NULL) {
! 10227: xmlRelaxNGNewStates(ctxt,
! 10228: res->nbState - base);
! 10229: states = ctxt->states;
! 10230: if (states == NULL) {
! 10231: progress = 0;
! 10232: break;
! 10233: }
! 10234: }
! 10235: states->nbState = 0;
! 10236: for (i = base; i < res->nbState; i++)
! 10237: xmlRelaxNGAddStates(ctxt, states,
! 10238: xmlRelaxNGCopyValidState
! 10239: (ctxt, res->tabState[i]));
! 10240: ctxt->states = states;
! 10241: }
! 10242: }
! 10243: } while (progress == 1);
! 10244: if (states != NULL) {
! 10245: xmlRelaxNGFreeStates(ctxt, states);
! 10246: }
! 10247: ctxt->states = res;
! 10248: ctxt->flags = oldflags;
! 10249: #if 0
! 10250: /*
! 10251: * errors may have to be propagated back...
! 10252: */
! 10253: if (ctxt->errNr > errNr)
! 10254: xmlRelaxNGPopErrors(ctxt, errNr);
! 10255: #endif
! 10256: ret = 0;
! 10257: break;
! 10258: }
! 10259: case XML_RELAXNG_CHOICE:{
! 10260: xmlRelaxNGDefinePtr list = NULL;
! 10261: xmlRelaxNGStatesPtr states = NULL;
! 10262:
! 10263: node = xmlRelaxNGSkipIgnored(ctxt, node);
! 10264:
! 10265: errNr = ctxt->errNr;
! 10266: if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
! 10267: (node != NULL)) {
! 10268: /*
! 10269: * node == NULL can't be optimized since IS_TRIABLE
! 10270: * doesn't account for choice which may lead to
! 10271: * only attributes.
! 10272: */
! 10273: xmlHashTablePtr triage =
! 10274: (xmlHashTablePtr) define->data;
! 10275:
! 10276: /*
! 10277: * Something we can optimize cleanly there is only one
! 10278: * possble branch out !
! 10279: */
! 10280: if ((node->type == XML_TEXT_NODE) ||
! 10281: (node->type == XML_CDATA_SECTION_NODE)) {
! 10282: list =
! 10283: xmlHashLookup2(triage, BAD_CAST "#text", NULL);
! 10284: } else if (node->type == XML_ELEMENT_NODE) {
! 10285: if (node->ns != NULL) {
! 10286: list = xmlHashLookup2(triage, node->name,
! 10287: node->ns->href);
! 10288: if (list == NULL)
! 10289: list =
! 10290: xmlHashLookup2(triage, BAD_CAST "#any",
! 10291: node->ns->href);
! 10292: } else
! 10293: list =
! 10294: xmlHashLookup2(triage, node->name, NULL);
! 10295: if (list == NULL)
! 10296: list =
! 10297: xmlHashLookup2(triage, BAD_CAST "#any",
! 10298: NULL);
! 10299: }
! 10300: if (list == NULL) {
! 10301: ret = -1;
! 10302: VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
! 10303: break;
! 10304: }
! 10305: ret = xmlRelaxNGValidateDefinition(ctxt, list);
! 10306: if (ret == 0) {
! 10307: }
! 10308: break;
! 10309: }
! 10310:
! 10311: list = define->content;
! 10312: oldflags = ctxt->flags;
! 10313: ctxt->flags |= FLAGS_IGNORABLE;
! 10314:
! 10315: while (list != NULL) {
! 10316: oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
! 10317: ret = xmlRelaxNGValidateDefinition(ctxt, list);
! 10318: if (ret == 0) {
! 10319: if (states == NULL) {
! 10320: states = xmlRelaxNGNewStates(ctxt, 1);
! 10321: }
! 10322: if (ctxt->state != NULL) {
! 10323: xmlRelaxNGAddStates(ctxt, states, ctxt->state);
! 10324: } else if (ctxt->states != NULL) {
! 10325: for (i = 0; i < ctxt->states->nbState; i++) {
! 10326: xmlRelaxNGAddStates(ctxt, states,
! 10327: ctxt->states->
! 10328: tabState[i]);
! 10329: }
! 10330: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10331: ctxt->states = NULL;
! 10332: }
! 10333: } else {
! 10334: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10335: }
! 10336: ctxt->state = oldstate;
! 10337: list = list->next;
! 10338: }
! 10339: if (states != NULL) {
! 10340: xmlRelaxNGFreeValidState(ctxt, oldstate);
! 10341: ctxt->states = states;
! 10342: ctxt->state = NULL;
! 10343: ret = 0;
! 10344: } else {
! 10345: ctxt->states = NULL;
! 10346: }
! 10347: ctxt->flags = oldflags;
! 10348: if (ret != 0) {
! 10349: if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
! 10350: xmlRelaxNGDumpValidError(ctxt);
! 10351: }
! 10352: } else {
! 10353: if (ctxt->errNr > errNr)
! 10354: xmlRelaxNGPopErrors(ctxt, errNr);
! 10355: }
! 10356: break;
! 10357: }
! 10358: case XML_RELAXNG_DEF:
! 10359: case XML_RELAXNG_GROUP:
! 10360: ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
! 10361: break;
! 10362: case XML_RELAXNG_INTERLEAVE:
! 10363: ret = xmlRelaxNGValidateInterleave(ctxt, define);
! 10364: break;
! 10365: case XML_RELAXNG_ATTRIBUTE:
! 10366: ret = xmlRelaxNGValidateAttribute(ctxt, define);
! 10367: break;
! 10368: case XML_RELAXNG_START:
! 10369: case XML_RELAXNG_NOOP:
! 10370: case XML_RELAXNG_REF:
! 10371: case XML_RELAXNG_EXTERNALREF:
! 10372: case XML_RELAXNG_PARENTREF:
! 10373: ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
! 10374: break;
! 10375: case XML_RELAXNG_DATATYPE:{
! 10376: xmlNodePtr child;
! 10377: xmlChar *content = NULL;
! 10378:
! 10379: child = node;
! 10380: while (child != NULL) {
! 10381: if (child->type == XML_ELEMENT_NODE) {
! 10382: VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
! 10383: node->parent->name);
! 10384: ret = -1;
! 10385: break;
! 10386: } else if ((child->type == XML_TEXT_NODE) ||
! 10387: (child->type == XML_CDATA_SECTION_NODE)) {
! 10388: content = xmlStrcat(content, child->content);
! 10389: }
! 10390: /* TODO: handle entities ... */
! 10391: child = child->next;
! 10392: }
! 10393: if (ret == -1) {
! 10394: if (content != NULL)
! 10395: xmlFree(content);
! 10396: break;
! 10397: }
! 10398: if (content == NULL) {
! 10399: content = xmlStrdup(BAD_CAST "");
! 10400: if (content == NULL) {
! 10401: xmlRngVErrMemory(ctxt, "validating\n");
! 10402: ret = -1;
! 10403: break;
! 10404: }
! 10405: }
! 10406: ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
! 10407: ctxt->state->seq);
! 10408: if (ret == -1) {
! 10409: VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
! 10410: } else if (ret == 0) {
! 10411: ctxt->state->seq = NULL;
! 10412: }
! 10413: if (content != NULL)
! 10414: xmlFree(content);
! 10415: break;
! 10416: }
! 10417: case XML_RELAXNG_VALUE:{
! 10418: xmlChar *content = NULL;
! 10419: xmlChar *oldvalue;
! 10420: xmlNodePtr child;
! 10421:
! 10422: child = node;
! 10423: while (child != NULL) {
! 10424: if (child->type == XML_ELEMENT_NODE) {
! 10425: VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
! 10426: node->parent->name);
! 10427: ret = -1;
! 10428: break;
! 10429: } else if ((child->type == XML_TEXT_NODE) ||
! 10430: (child->type == XML_CDATA_SECTION_NODE)) {
! 10431: content = xmlStrcat(content, child->content);
! 10432: }
! 10433: /* TODO: handle entities ... */
! 10434: child = child->next;
! 10435: }
! 10436: if (ret == -1) {
! 10437: if (content != NULL)
! 10438: xmlFree(content);
! 10439: break;
! 10440: }
! 10441: if (content == NULL) {
! 10442: content = xmlStrdup(BAD_CAST "");
! 10443: if (content == NULL) {
! 10444: xmlRngVErrMemory(ctxt, "validating\n");
! 10445: ret = -1;
! 10446: break;
! 10447: }
! 10448: }
! 10449: oldvalue = ctxt->state->value;
! 10450: ctxt->state->value = content;
! 10451: ret = xmlRelaxNGValidateValue(ctxt, define);
! 10452: ctxt->state->value = oldvalue;
! 10453: if (ret == -1) {
! 10454: VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
! 10455: } else if (ret == 0) {
! 10456: ctxt->state->seq = NULL;
! 10457: }
! 10458: if (content != NULL)
! 10459: xmlFree(content);
! 10460: break;
! 10461: }
! 10462: case XML_RELAXNG_LIST:{
! 10463: xmlChar *content;
! 10464: xmlNodePtr child;
! 10465: xmlChar *oldvalue, *oldendvalue;
! 10466: int len;
! 10467:
! 10468: /*
! 10469: * Make sure it's only text nodes
! 10470: */
! 10471:
! 10472: content = NULL;
! 10473: child = node;
! 10474: while (child != NULL) {
! 10475: if (child->type == XML_ELEMENT_NODE) {
! 10476: VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
! 10477: node->parent->name);
! 10478: ret = -1;
! 10479: break;
! 10480: } else if ((child->type == XML_TEXT_NODE) ||
! 10481: (child->type == XML_CDATA_SECTION_NODE)) {
! 10482: content = xmlStrcat(content, child->content);
! 10483: }
! 10484: /* TODO: handle entities ... */
! 10485: child = child->next;
! 10486: }
! 10487: if (ret == -1) {
! 10488: if (content != NULL)
! 10489: xmlFree(content);
! 10490: break;
! 10491: }
! 10492: if (content == NULL) {
! 10493: content = xmlStrdup(BAD_CAST "");
! 10494: if (content == NULL) {
! 10495: xmlRngVErrMemory(ctxt, "validating\n");
! 10496: ret = -1;
! 10497: break;
! 10498: }
! 10499: }
! 10500: len = xmlStrlen(content);
! 10501: oldvalue = ctxt->state->value;
! 10502: oldendvalue = ctxt->state->endvalue;
! 10503: ctxt->state->value = content;
! 10504: ctxt->state->endvalue = content + len;
! 10505: ret = xmlRelaxNGValidateValue(ctxt, define);
! 10506: ctxt->state->value = oldvalue;
! 10507: ctxt->state->endvalue = oldendvalue;
! 10508: if (ret == -1) {
! 10509: VALID_ERR(XML_RELAXNG_ERR_LIST);
! 10510: } else if ((ret == 0) && (node != NULL)) {
! 10511: ctxt->state->seq = node->next;
! 10512: }
! 10513: if (content != NULL)
! 10514: xmlFree(content);
! 10515: break;
! 10516: }
! 10517: case XML_RELAXNG_EXCEPT:
! 10518: case XML_RELAXNG_PARAM:
! 10519: TODO ret = -1;
! 10520: break;
! 10521: }
! 10522: ctxt->depth--;
! 10523: #ifdef DEBUG
! 10524: for (i = 0; i < ctxt->depth; i++)
! 10525: xmlGenericError(xmlGenericErrorContext, " ");
! 10526: xmlGenericError(xmlGenericErrorContext,
! 10527: "Validating %s ", xmlRelaxNGDefName(define));
! 10528: if (define->name != NULL)
! 10529: xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
! 10530: if (ret == 0)
! 10531: xmlGenericError(xmlGenericErrorContext, "suceeded\n");
! 10532: else
! 10533: xmlGenericError(xmlGenericErrorContext, "failed\n");
! 10534: #endif
! 10535: return (ret);
! 10536: }
! 10537:
! 10538: /**
! 10539: * xmlRelaxNGValidateDefinition:
! 10540: * @ctxt: a Relax-NG validation context
! 10541: * @define: the definition to verify
! 10542: *
! 10543: * Validate the current node lists against the definition
! 10544: *
! 10545: * Returns 0 if the validation succeeded or an error code.
! 10546: */
! 10547: static int
! 10548: xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
! 10549: xmlRelaxNGDefinePtr define)
! 10550: {
! 10551: xmlRelaxNGStatesPtr states, res;
! 10552: int i, j, k, ret, oldflags;
! 10553:
! 10554: /*
! 10555: * We should NOT have both ctxt->state and ctxt->states
! 10556: */
! 10557: if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
! 10558: TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10559: ctxt->state = NULL;
! 10560: }
! 10561:
! 10562: if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
! 10563: if (ctxt->states != NULL) {
! 10564: ctxt->state = ctxt->states->tabState[0];
! 10565: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10566: ctxt->states = NULL;
! 10567: }
! 10568: ret = xmlRelaxNGValidateState(ctxt, define);
! 10569: if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
! 10570: TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10571: ctxt->state = NULL;
! 10572: }
! 10573: if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
! 10574: ctxt->state = ctxt->states->tabState[0];
! 10575: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10576: ctxt->states = NULL;
! 10577: }
! 10578: return (ret);
! 10579: }
! 10580:
! 10581: states = ctxt->states;
! 10582: ctxt->states = NULL;
! 10583: res = NULL;
! 10584: j = 0;
! 10585: oldflags = ctxt->flags;
! 10586: ctxt->flags |= FLAGS_IGNORABLE;
! 10587: for (i = 0; i < states->nbState; i++) {
! 10588: ctxt->state = states->tabState[i];
! 10589: ctxt->states = NULL;
! 10590: ret = xmlRelaxNGValidateState(ctxt, define);
! 10591: /*
! 10592: * We should NOT have both ctxt->state and ctxt->states
! 10593: */
! 10594: if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
! 10595: TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10596: ctxt->state = NULL;
! 10597: }
! 10598: if (ret == 0) {
! 10599: if (ctxt->states == NULL) {
! 10600: if (res != NULL) {
! 10601: /* add the state to the container */
! 10602: xmlRelaxNGAddStates(ctxt, res, ctxt->state);
! 10603: ctxt->state = NULL;
! 10604: } else {
! 10605: /* add the state directly in states */
! 10606: states->tabState[j++] = ctxt->state;
! 10607: ctxt->state = NULL;
! 10608: }
! 10609: } else {
! 10610: if (res == NULL) {
! 10611: /* make it the new container and copy other results */
! 10612: res = ctxt->states;
! 10613: ctxt->states = NULL;
! 10614: for (k = 0; k < j; k++)
! 10615: xmlRelaxNGAddStates(ctxt, res,
! 10616: states->tabState[k]);
! 10617: } else {
! 10618: /* add all the new results to res and reff the container */
! 10619: for (k = 0; k < ctxt->states->nbState; k++)
! 10620: xmlRelaxNGAddStates(ctxt, res,
! 10621: ctxt->states->tabState[k]);
! 10622: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10623: ctxt->states = NULL;
! 10624: }
! 10625: }
! 10626: } else {
! 10627: if (ctxt->state != NULL) {
! 10628: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10629: ctxt->state = NULL;
! 10630: } else if (ctxt->states != NULL) {
! 10631: for (k = 0; k < ctxt->states->nbState; k++)
! 10632: xmlRelaxNGFreeValidState(ctxt,
! 10633: ctxt->states->tabState[k]);
! 10634: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10635: ctxt->states = NULL;
! 10636: }
! 10637: }
! 10638: }
! 10639: ctxt->flags = oldflags;
! 10640: if (res != NULL) {
! 10641: xmlRelaxNGFreeStates(ctxt, states);
! 10642: ctxt->states = res;
! 10643: ret = 0;
! 10644: } else if (j > 1) {
! 10645: states->nbState = j;
! 10646: ctxt->states = states;
! 10647: ret = 0;
! 10648: } else if (j == 1) {
! 10649: ctxt->state = states->tabState[0];
! 10650: xmlRelaxNGFreeStates(ctxt, states);
! 10651: ret = 0;
! 10652: } else {
! 10653: ret = -1;
! 10654: xmlRelaxNGFreeStates(ctxt, states);
! 10655: if (ctxt->states != NULL) {
! 10656: xmlRelaxNGFreeStates(ctxt, ctxt->states);
! 10657: ctxt->states = NULL;
! 10658: }
! 10659: }
! 10660: if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
! 10661: TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10662: ctxt->state = NULL;
! 10663: }
! 10664: return (ret);
! 10665: }
! 10666:
! 10667: /**
! 10668: * xmlRelaxNGValidateDocument:
! 10669: * @ctxt: a Relax-NG validation context
! 10670: * @doc: the document
! 10671: *
! 10672: * Validate the given document
! 10673: *
! 10674: * Returns 0 if the validation succeeded or an error code.
! 10675: */
! 10676: static int
! 10677: xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
! 10678: {
! 10679: int ret;
! 10680: xmlRelaxNGPtr schema;
! 10681: xmlRelaxNGGrammarPtr grammar;
! 10682: xmlRelaxNGValidStatePtr state;
! 10683: xmlNodePtr node;
! 10684:
! 10685: if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
! 10686: return (-1);
! 10687:
! 10688: ctxt->errNo = XML_RELAXNG_OK;
! 10689: schema = ctxt->schema;
! 10690: grammar = schema->topgrammar;
! 10691: if (grammar == NULL) {
! 10692: VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
! 10693: return (-1);
! 10694: }
! 10695: state = xmlRelaxNGNewValidState(ctxt, NULL);
! 10696: ctxt->state = state;
! 10697: ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
! 10698: if ((ctxt->state != NULL) && (state->seq != NULL)) {
! 10699: state = ctxt->state;
! 10700: node = state->seq;
! 10701: node = xmlRelaxNGSkipIgnored(ctxt, node);
! 10702: if (node != NULL) {
! 10703: if (ret != -1) {
! 10704: VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
! 10705: ret = -1;
! 10706: }
! 10707: }
! 10708: } else if (ctxt->states != NULL) {
! 10709: int i;
! 10710: int tmp = -1;
! 10711:
! 10712: for (i = 0; i < ctxt->states->nbState; i++) {
! 10713: state = ctxt->states->tabState[i];
! 10714: node = state->seq;
! 10715: node = xmlRelaxNGSkipIgnored(ctxt, node);
! 10716: if (node == NULL)
! 10717: tmp = 0;
! 10718: xmlRelaxNGFreeValidState(ctxt, state);
! 10719: }
! 10720: if (tmp == -1) {
! 10721: if (ret != -1) {
! 10722: VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
! 10723: ret = -1;
! 10724: }
! 10725: }
! 10726: }
! 10727: if (ctxt->state != NULL) {
! 10728: xmlRelaxNGFreeValidState(ctxt, ctxt->state);
! 10729: ctxt->state = NULL;
! 10730: }
! 10731: if (ret != 0)
! 10732: xmlRelaxNGDumpValidError(ctxt);
! 10733: #ifdef DEBUG
! 10734: else if (ctxt->errNr != 0) {
! 10735: ctxt->error(ctxt->userData,
! 10736: "%d Extra error messages left on stack !\n",
! 10737: ctxt->errNr);
! 10738: xmlRelaxNGDumpValidError(ctxt);
! 10739: }
! 10740: #endif
! 10741: #ifdef LIBXML_VALID_ENABLED
! 10742: if (ctxt->idref == 1) {
! 10743: xmlValidCtxt vctxt;
! 10744:
! 10745: memset(&vctxt, 0, sizeof(xmlValidCtxt));
! 10746: vctxt.valid = 1;
! 10747: vctxt.error = ctxt->error;
! 10748: vctxt.warning = ctxt->warning;
! 10749: vctxt.userData = ctxt->userData;
! 10750:
! 10751: if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
! 10752: ret = -1;
! 10753: }
! 10754: #endif /* LIBXML_VALID_ENABLED */
! 10755: if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
! 10756: ret = -1;
! 10757:
! 10758: return (ret);
! 10759: }
! 10760:
! 10761: /**
! 10762: * xmlRelaxNGCleanPSVI:
! 10763: * @node: an input element or document
! 10764: *
! 10765: * Call this routine to speed up XPath computation on static documents.
! 10766: * This stamps all the element nodes with the document order
! 10767: * Like for line information, the order is kept in the element->content
! 10768: * field, the value stored is actually - the node number (starting at -1)
! 10769: * to be able to differentiate from line numbers.
! 10770: *
! 10771: * Returns the number of elements found in the document or -1 in case
! 10772: * of error.
! 10773: */
! 10774: static void
! 10775: xmlRelaxNGCleanPSVI(xmlNodePtr node) {
! 10776: xmlNodePtr cur;
! 10777:
! 10778: if ((node == NULL) ||
! 10779: ((node->type != XML_ELEMENT_NODE) &&
! 10780: (node->type != XML_DOCUMENT_NODE) &&
! 10781: (node->type != XML_HTML_DOCUMENT_NODE)))
! 10782: return;
! 10783: if (node->type == XML_ELEMENT_NODE)
! 10784: node->psvi = NULL;
! 10785:
! 10786: cur = node->children;
! 10787: while (cur != NULL) {
! 10788: if (cur->type == XML_ELEMENT_NODE) {
! 10789: cur->psvi = NULL;
! 10790: if (cur->children != NULL) {
! 10791: cur = cur->children;
! 10792: continue;
! 10793: }
! 10794: }
! 10795: if (cur->next != NULL) {
! 10796: cur = cur->next;
! 10797: continue;
! 10798: }
! 10799: do {
! 10800: cur = cur->parent;
! 10801: if (cur == NULL)
! 10802: break;
! 10803: if (cur == node) {
! 10804: cur = NULL;
! 10805: break;
! 10806: }
! 10807: if (cur->next != NULL) {
! 10808: cur = cur->next;
! 10809: break;
! 10810: }
! 10811: } while (cur != NULL);
! 10812: }
! 10813: return;
! 10814: }
! 10815: /************************************************************************
! 10816: * *
! 10817: * Validation interfaces *
! 10818: * *
! 10819: ************************************************************************/
! 10820:
! 10821: /**
! 10822: * xmlRelaxNGNewValidCtxt:
! 10823: * @schema: a precompiled XML RelaxNGs
! 10824: *
! 10825: * Create an XML RelaxNGs validation context based on the given schema
! 10826: *
! 10827: * Returns the validation context or NULL in case of error
! 10828: */
! 10829: xmlRelaxNGValidCtxtPtr
! 10830: xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
! 10831: {
! 10832: xmlRelaxNGValidCtxtPtr ret;
! 10833:
! 10834: ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
! 10835: if (ret == NULL) {
! 10836: xmlRngVErrMemory(NULL, "building context\n");
! 10837: return (NULL);
! 10838: }
! 10839: memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
! 10840: ret->schema = schema;
! 10841: ret->error = xmlGenericError;
! 10842: ret->userData = xmlGenericErrorContext;
! 10843: ret->errNr = 0;
! 10844: ret->errMax = 0;
! 10845: ret->err = NULL;
! 10846: ret->errTab = NULL;
! 10847: if (schema != NULL)
! 10848: ret->idref = schema->idref;
! 10849: ret->states = NULL;
! 10850: ret->freeState = NULL;
! 10851: ret->freeStates = NULL;
! 10852: ret->errNo = XML_RELAXNG_OK;
! 10853: return (ret);
! 10854: }
! 10855:
! 10856: /**
! 10857: * xmlRelaxNGFreeValidCtxt:
! 10858: * @ctxt: the schema validation context
! 10859: *
! 10860: * Free the resources associated to the schema validation context
! 10861: */
! 10862: void
! 10863: xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
! 10864: {
! 10865: int k;
! 10866:
! 10867: if (ctxt == NULL)
! 10868: return;
! 10869: if (ctxt->states != NULL)
! 10870: xmlRelaxNGFreeStates(NULL, ctxt->states);
! 10871: if (ctxt->freeState != NULL) {
! 10872: for (k = 0; k < ctxt->freeState->nbState; k++) {
! 10873: xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
! 10874: }
! 10875: xmlRelaxNGFreeStates(NULL, ctxt->freeState);
! 10876: }
! 10877: if (ctxt->freeStates != NULL) {
! 10878: for (k = 0; k < ctxt->freeStatesNr; k++) {
! 10879: xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
! 10880: }
! 10881: xmlFree(ctxt->freeStates);
! 10882: }
! 10883: if (ctxt->errTab != NULL)
! 10884: xmlFree(ctxt->errTab);
! 10885: if (ctxt->elemTab != NULL) {
! 10886: xmlRegExecCtxtPtr exec;
! 10887:
! 10888: exec = xmlRelaxNGElemPop(ctxt);
! 10889: while (exec != NULL) {
! 10890: xmlRegFreeExecCtxt(exec);
! 10891: exec = xmlRelaxNGElemPop(ctxt);
! 10892: }
! 10893: xmlFree(ctxt->elemTab);
! 10894: }
! 10895: xmlFree(ctxt);
! 10896: }
! 10897:
! 10898: /**
! 10899: * xmlRelaxNGSetValidErrors:
! 10900: * @ctxt: a Relax-NG validation context
! 10901: * @err: the error function
! 10902: * @warn: the warning function
! 10903: * @ctx: the functions context
! 10904: *
! 10905: * Set the error and warning callback informations
! 10906: */
! 10907: void
! 10908: xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
! 10909: xmlRelaxNGValidityErrorFunc err,
! 10910: xmlRelaxNGValidityWarningFunc warn, void *ctx)
! 10911: {
! 10912: if (ctxt == NULL)
! 10913: return;
! 10914: ctxt->error = err;
! 10915: ctxt->warning = warn;
! 10916: ctxt->userData = ctx;
! 10917: ctxt->serror = NULL;
! 10918: }
! 10919:
! 10920: /**
! 10921: * xmlRelaxNGSetValidStructuredErrors:
! 10922: * @ctxt: a Relax-NG validation context
! 10923: * @serror: the structured error function
! 10924: * @ctx: the functions context
! 10925: *
! 10926: * Set the structured error callback
! 10927: */
! 10928: void
! 10929: xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
! 10930: xmlStructuredErrorFunc serror, void *ctx)
! 10931: {
! 10932: if (ctxt == NULL)
! 10933: return;
! 10934: ctxt->serror = serror;
! 10935: ctxt->error = NULL;
! 10936: ctxt->warning = NULL;
! 10937: ctxt->userData = ctx;
! 10938: }
! 10939:
! 10940: /**
! 10941: * xmlRelaxNGGetValidErrors:
! 10942: * @ctxt: a Relax-NG validation context
! 10943: * @err: the error function result
! 10944: * @warn: the warning function result
! 10945: * @ctx: the functions context result
! 10946: *
! 10947: * Get the error and warning callback informations
! 10948: *
! 10949: * Returns -1 in case of error and 0 otherwise
! 10950: */
! 10951: int
! 10952: xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
! 10953: xmlRelaxNGValidityErrorFunc * err,
! 10954: xmlRelaxNGValidityWarningFunc * warn, void **ctx)
! 10955: {
! 10956: if (ctxt == NULL)
! 10957: return (-1);
! 10958: if (err != NULL)
! 10959: *err = ctxt->error;
! 10960: if (warn != NULL)
! 10961: *warn = ctxt->warning;
! 10962: if (ctx != NULL)
! 10963: *ctx = ctxt->userData;
! 10964: return (0);
! 10965: }
! 10966:
! 10967: /**
! 10968: * xmlRelaxNGValidateDoc:
! 10969: * @ctxt: a Relax-NG validation context
! 10970: * @doc: a parsed document tree
! 10971: *
! 10972: * Validate a document tree in memory.
! 10973: *
! 10974: * Returns 0 if the document is valid, a positive error code
! 10975: * number otherwise and -1 in case of internal or API error.
! 10976: */
! 10977: int
! 10978: xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
! 10979: {
! 10980: int ret;
! 10981:
! 10982: if ((ctxt == NULL) || (doc == NULL))
! 10983: return (-1);
! 10984:
! 10985: ctxt->doc = doc;
! 10986:
! 10987: ret = xmlRelaxNGValidateDocument(ctxt, doc);
! 10988: /*
! 10989: * Remove all left PSVI
! 10990: */
! 10991: xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
! 10992:
! 10993: /*
! 10994: * TODO: build error codes
! 10995: */
! 10996: if (ret == -1)
! 10997: return (1);
! 10998: return (ret);
! 10999: }
! 11000:
! 11001: #define bottom_relaxng
! 11002: #include "elfgcchack.h"
! 11003: #endif /* LIBXML_SCHEMAS_ENABLED */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>