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