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