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 * Cleanup the default Schemas type library associated to RelaxNG 2853 */ 2854 void 2855 xmlRelaxNGCleanupTypes(void) 2856 { 2857 xmlSchemaCleanupTypes(); 2858 if (xmlRelaxNGTypeInitialized == 0) 2859 return; 2860 xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary); 2861 xmlRelaxNGTypeInitialized = 0; 2862 } 2863 2864 /************************************************************************ 2865 * * 2866 * Compiling element content into regexp * 2867 * * 2868 * Sometime the element content can be compiled into a pure regexp, * 2869 * This allows a faster execution and streamability at that level * 2870 * * 2871 ************************************************************************/ 2872 2873 /* from automata.c but not exported */ 2874 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); 2875 2876 2877 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, 2878 xmlRelaxNGDefinePtr def); 2879 2880 /** 2881 * xmlRelaxNGIsCompilable: 2882 * @define: the definition to check 2883 * 2884 * Check if a definition is nullable. 2885 * 2886 * Returns 1 if yes, 0 if no and -1 in case of error 2887 */ 2888 static int 2889 xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def) 2890 { 2891 int ret = -1; 2892 2893 if (def == NULL) { 2894 return (-1); 2895 } 2896 if ((def->type != XML_RELAXNG_ELEMENT) && 2897 (def->dflags & IS_COMPILABLE)) 2898 return (1); 2899 if ((def->type != XML_RELAXNG_ELEMENT) && 2900 (def->dflags & IS_NOT_COMPILABLE)) 2901 return (0); 2902 switch (def->type) { 2903 case XML_RELAXNG_NOOP: 2904 ret = xmlRelaxNGIsCompilable(def->content); 2905 break; 2906 case XML_RELAXNG_TEXT: 2907 case XML_RELAXNG_EMPTY: 2908 ret = 1; 2909 break; 2910 case XML_RELAXNG_ELEMENT: 2911 /* 2912 * Check if the element content is compilable 2913 */ 2914 if (((def->dflags & IS_NOT_COMPILABLE) == 0) && 2915 ((def->dflags & IS_COMPILABLE) == 0)) { 2916 xmlRelaxNGDefinePtr list; 2917 2918 list = def->content; 2919 while (list != NULL) { 2920 ret = xmlRelaxNGIsCompilable(list); 2921 if (ret != 1) 2922 break; 2923 list = list->next; 2924 } 2925 /* 2926 * Because the routine is recursive, we must guard against 2927 * discovering both COMPILABLE and NOT_COMPILABLE 2928 */ 2929 if (ret == 0) { 2930 def->dflags &= ~IS_COMPILABLE; 2931 def->dflags |= IS_NOT_COMPILABLE; 2932 } 2933 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) 2934 def->dflags |= IS_COMPILABLE; 2935 #ifdef DEBUG_COMPILE 2936 if (ret == 1) { 2937 xmlGenericError(xmlGenericErrorContext, 2938 "element content for %s is compilable\n", 2939 def->name); 2940 } else if (ret == 0) { 2941 xmlGenericError(xmlGenericErrorContext, 2942 "element content for %s is not compilable\n", 2943 def->name); 2944 } else { 2945 xmlGenericError(xmlGenericErrorContext, 2946 "Problem in RelaxNGIsCompilable for element %s\n", 2947 def->name); 2948 } 2949 #endif 2950 } 2951 /* 2952 * All elements return a compilable status unless they 2953 * are generic like anyName 2954 */ 2955 if ((def->nameClass != NULL) || (def->name == NULL)) 2956 ret = 0; 2957 else 2958 ret = 1; 2959 return (ret); 2960 case XML_RELAXNG_REF: 2961 case XML_RELAXNG_EXTERNALREF: 2962 case XML_RELAXNG_PARENTREF: 2963 if (def->depth == -20) { 2964 return (1); 2965 } else { 2966 xmlRelaxNGDefinePtr list; 2967 2968 def->depth = -20; 2969 list = def->content; 2970 while (list != NULL) { 2971 ret = xmlRelaxNGIsCompilable(list); 2972 if (ret != 1) 2973 break; 2974 list = list->next; 2975 } 2976 } 2977 break; 2978 case XML_RELAXNG_START: 2979 case XML_RELAXNG_OPTIONAL: 2980 case XML_RELAXNG_ZEROORMORE: 2981 case XML_RELAXNG_ONEORMORE: 2982 case XML_RELAXNG_CHOICE: 2983 case XML_RELAXNG_GROUP: 2984 case XML_RELAXNG_DEF:{ 2985 xmlRelaxNGDefinePtr list; 2986 2987 list = def->content; 2988 while (list != NULL) { 2989 ret = xmlRelaxNGIsCompilable(list); 2990 if (ret != 1) 2991 break; 2992 list = list->next; 2993 } 2994 break; 2995 } 2996 case XML_RELAXNG_EXCEPT: 2997 case XML_RELAXNG_ATTRIBUTE: 2998 case XML_RELAXNG_INTERLEAVE: 2999 case XML_RELAXNG_DATATYPE: 3000 case XML_RELAXNG_LIST: 3001 case XML_RELAXNG_PARAM: 3002 case XML_RELAXNG_VALUE: 3003 case XML_RELAXNG_NOT_ALLOWED: 3004 ret = 0; 3005 break; 3006 } 3007 if (ret == 0) 3008 def->dflags |= IS_NOT_COMPILABLE; 3009 if (ret == 1) 3010 def->dflags |= IS_COMPILABLE; 3011 #ifdef DEBUG_COMPILE 3012 if (ret == 1) { 3013 xmlGenericError(xmlGenericErrorContext, 3014 "RelaxNGIsCompilable %s : true\n", 3015 xmlRelaxNGDefName(def)); 3016 } else if (ret == 0) { 3017 xmlGenericError(xmlGenericErrorContext, 3018 "RelaxNGIsCompilable %s : false\n", 3019 xmlRelaxNGDefName(def)); 3020 } else { 3021 xmlGenericError(xmlGenericErrorContext, 3022 "Problem in RelaxNGIsCompilable %s\n", 3023 xmlRelaxNGDefName(def)); 3024 } 3025 #endif 3026 return (ret); 3027 } 3028 3029 /** 3030 * xmlRelaxNGCompile: 3031 * ctxt: the RelaxNG parser context 3032 * @define: the definition tree to compile 3033 * 3034 * Compile the set of definitions, it works recursively, till the 3035 * element boundaries, where it tries to compile the content if possible 3036 * 3037 * Returns 0 if success and -1 in case of error 3038 */ 3039 static int 3040 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3041 { 3042 int ret = 0; 3043 xmlRelaxNGDefinePtr list; 3044 3045 if ((ctxt == NULL) || (def == NULL)) 3046 return (-1); 3047 3048 switch (def->type) { 3049 case XML_RELAXNG_START: 3050 if ((xmlRelaxNGIsCompilable(def) == 1) && (def->depth != -25)) { 3051 xmlAutomataPtr oldam = ctxt->am; 3052 xmlAutomataStatePtr oldstate = ctxt->state; 3053 3054 def->depth = -25; 3055 3056 list = def->content; 3057 ctxt->am = xmlNewAutomata(); 3058 if (ctxt->am == NULL) 3059 return (-1); 3060 3061 /* 3062 * assume identical strings but not same pointer are different 3063 * atoms, needed for non-determinism detection 3064 * That way if 2 elements with the same name are in a choice 3065 * branch the automata is found non-deterministic and 3066 * we fallback to the normal validation which does the right 3067 * thing of exploring both choices. 3068 */ 3069 xmlAutomataSetFlags(ctxt->am, 1); 3070 3071 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3072 while (list != NULL) { 3073 xmlRelaxNGCompile(ctxt, list); 3074 list = list->next; 3075 } 3076 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3077 if (xmlAutomataIsDeterminist(ctxt->am)) 3078 def->contModel = xmlAutomataCompile(ctxt->am); 3079 3080 xmlFreeAutomata(ctxt->am); 3081 ctxt->state = oldstate; 3082 ctxt->am = oldam; 3083 } 3084 break; 3085 case XML_RELAXNG_ELEMENT: 3086 if ((ctxt->am != NULL) && (def->name != NULL)) { 3087 ctxt->state = xmlAutomataNewTransition2(ctxt->am, 3088 ctxt->state, NULL, 3089 def->name, def->ns, 3090 def); 3091 } 3092 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3093 xmlAutomataPtr oldam = ctxt->am; 3094 xmlAutomataStatePtr oldstate = ctxt->state; 3095 3096 def->depth = -25; 3097 3098 list = def->content; 3099 ctxt->am = xmlNewAutomata(); 3100 if (ctxt->am == NULL) 3101 return (-1); 3102 xmlAutomataSetFlags(ctxt->am, 1); 3103 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3104 while (list != NULL) { 3105 xmlRelaxNGCompile(ctxt, list); 3106 list = list->next; 3107 } 3108 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3109 def->contModel = xmlAutomataCompile(ctxt->am); 3110 if (!xmlRegexpIsDeterminist(def->contModel)) { 3111 #ifdef DEBUG_COMPILE 3112 xmlGenericError(xmlGenericErrorContext, 3113 "Content model not determinist %s\n", 3114 def->name); 3115 #endif 3116 /* 3117 * we can only use the automata if it is determinist 3118 */ 3119 xmlRegFreeRegexp(def->contModel); 3120 def->contModel = NULL; 3121 } 3122 xmlFreeAutomata(ctxt->am); 3123 ctxt->state = oldstate; 3124 ctxt->am = oldam; 3125 } else { 3126 xmlAutomataPtr oldam = ctxt->am; 3127 3128 /* 3129 * we can't build the content model for this element content 3130 * but it still might be possible to build it for some of its 3131 * children, recurse. 3132 */ 3133 ret = xmlRelaxNGTryCompile(ctxt, def); 3134 ctxt->am = oldam; 3135 } 3136 break; 3137 case XML_RELAXNG_NOOP: 3138 ret = xmlRelaxNGCompile(ctxt, def->content); 3139 break; 3140 case XML_RELAXNG_OPTIONAL:{ 3141 xmlAutomataStatePtr oldstate = ctxt->state; 3142 3143 list = def->content; 3144 while (list != NULL) { 3145 xmlRelaxNGCompile(ctxt, list); 3146 list = list->next; 3147 } 3148 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 3149 break; 3150 } 3151 case XML_RELAXNG_ZEROORMORE:{ 3152 xmlAutomataStatePtr oldstate; 3153 3154 ctxt->state = 3155 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3156 oldstate = ctxt->state; 3157 list = def->content; 3158 while (list != NULL) { 3159 xmlRelaxNGCompile(ctxt, list); 3160 list = list->next; 3161 } 3162 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3163 ctxt->state = 3164 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3165 break; 3166 } 3167 case XML_RELAXNG_ONEORMORE:{ 3168 xmlAutomataStatePtr oldstate; 3169 3170 list = def->content; 3171 while (list != NULL) { 3172 xmlRelaxNGCompile(ctxt, list); 3173 list = list->next; 3174 } 3175 oldstate = ctxt->state; 3176 list = def->content; 3177 while (list != NULL) { 3178 xmlRelaxNGCompile(ctxt, list); 3179 list = list->next; 3180 } 3181 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3182 ctxt->state = 3183 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3184 break; 3185 } 3186 case XML_RELAXNG_CHOICE:{ 3187 xmlAutomataStatePtr target = NULL; 3188 xmlAutomataStatePtr oldstate = ctxt->state; 3189 3190 list = def->content; 3191 while (list != NULL) { 3192 ctxt->state = oldstate; 3193 ret = xmlRelaxNGCompile(ctxt, list); 3194 if (ret != 0) 3195 break; 3196 if (target == NULL) 3197 target = ctxt->state; 3198 else { 3199 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, 3200 target); 3201 } 3202 list = list->next; 3203 } 3204 ctxt->state = target; 3205 3206 break; 3207 } 3208 case XML_RELAXNG_REF: 3209 case XML_RELAXNG_EXTERNALREF: 3210 case XML_RELAXNG_PARENTREF: 3211 case XML_RELAXNG_GROUP: 3212 case XML_RELAXNG_DEF: 3213 list = def->content; 3214 while (list != NULL) { 3215 ret = xmlRelaxNGCompile(ctxt, list); 3216 if (ret != 0) 3217 break; 3218 list = list->next; 3219 } 3220 break; 3221 case XML_RELAXNG_TEXT:{ 3222 xmlAutomataStatePtr oldstate; 3223 3224 ctxt->state = 3225 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3226 oldstate = ctxt->state; 3227 xmlRelaxNGCompile(ctxt, def->content); 3228 xmlAutomataNewTransition(ctxt->am, ctxt->state, 3229 ctxt->state, BAD_CAST "#text", 3230 NULL); 3231 ctxt->state = 3232 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3233 break; 3234 } 3235 case XML_RELAXNG_EMPTY: 3236 ctxt->state = 3237 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3238 break; 3239 case XML_RELAXNG_EXCEPT: 3240 case XML_RELAXNG_ATTRIBUTE: 3241 case XML_RELAXNG_INTERLEAVE: 3242 case XML_RELAXNG_NOT_ALLOWED: 3243 case XML_RELAXNG_DATATYPE: 3244 case XML_RELAXNG_LIST: 3245 case XML_RELAXNG_PARAM: 3246 case XML_RELAXNG_VALUE: 3247 /* This should not happen and generate an internal error */ 3248 fprintf(stderr, "RNG internal error trying to compile %s\n", 3249 xmlRelaxNGDefName(def)); 3250 break; 3251 } 3252 return (ret); 3253 } 3254 3255 /** 3256 * xmlRelaxNGTryCompile: 3257 * ctxt: the RelaxNG parser context 3258 * @define: the definition tree to compile 3259 * 3260 * Try to compile the set of definitions, it works recursively, 3261 * possibly ignoring parts which cannot be compiled. 3262 * 3263 * Returns 0 if success and -1 in case of error 3264 */ 3265 static int 3266 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3267 { 3268 int ret = 0; 3269 xmlRelaxNGDefinePtr list; 3270 3271 if ((ctxt == NULL) || (def == NULL)) 3272 return (-1); 3273 3274 if ((def->type == XML_RELAXNG_START) || 3275 (def->type == XML_RELAXNG_ELEMENT)) { 3276 ret = xmlRelaxNGIsCompilable(def); 3277 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3278 ctxt->am = NULL; 3279 ret = xmlRelaxNGCompile(ctxt, def); 3280 #ifdef DEBUG_PROGRESSIVE 3281 if (ret == 0) { 3282 if (def->type == XML_RELAXNG_START) 3283 xmlGenericError(xmlGenericErrorContext, 3284 "compiled the start\n"); 3285 else 3286 xmlGenericError(xmlGenericErrorContext, 3287 "compiled element %s\n", def->name); 3288 } else { 3289 if (def->type == XML_RELAXNG_START) 3290 xmlGenericError(xmlGenericErrorContext, 3291 "failed to compile the start\n"); 3292 else 3293 xmlGenericError(xmlGenericErrorContext, 3294 "failed to compile element %s\n", 3295 def->name); 3296 } 3297 #endif 3298 return (ret); 3299 } 3300 } 3301 switch (def->type) { 3302 case XML_RELAXNG_NOOP: 3303 ret = xmlRelaxNGTryCompile(ctxt, def->content); 3304 break; 3305 case XML_RELAXNG_TEXT: 3306 case XML_RELAXNG_DATATYPE: 3307 case XML_RELAXNG_LIST: 3308 case XML_RELAXNG_PARAM: 3309 case XML_RELAXNG_VALUE: 3310 case XML_RELAXNG_EMPTY: 3311 case XML_RELAXNG_ELEMENT: 3312 ret = 0; 3313 break; 3314 case XML_RELAXNG_OPTIONAL: 3315 case XML_RELAXNG_ZEROORMORE: 3316 case XML_RELAXNG_ONEORMORE: 3317 case XML_RELAXNG_CHOICE: 3318 case XML_RELAXNG_GROUP: 3319 case XML_RELAXNG_DEF: 3320 case XML_RELAXNG_START: 3321 case XML_RELAXNG_REF: 3322 case XML_RELAXNG_EXTERNALREF: 3323 case XML_RELAXNG_PARENTREF: 3324 list = def->content; 3325 while (list != NULL) { 3326 ret = xmlRelaxNGTryCompile(ctxt, list); 3327 if (ret != 0) 3328 break; 3329 list = list->next; 3330 } 3331 break; 3332 case XML_RELAXNG_EXCEPT: 3333 case XML_RELAXNG_ATTRIBUTE: 3334 case XML_RELAXNG_INTERLEAVE: 3335 case XML_RELAXNG_NOT_ALLOWED: 3336 ret = 0; 3337 break; 3338 } 3339 return (ret); 3340 } 3341 3342 /************************************************************************ 3343 * * 3344 * Parsing functions * 3345 * * 3346 ************************************************************************/ 3347 3348 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr 3349 ctxt, xmlNodePtr node); 3350 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr 3351 ctxt, xmlNodePtr node); 3352 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr 3353 ctxt, xmlNodePtr nodes, 3354 int group); 3355 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr 3356 ctxt, xmlNodePtr node); 3357 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, 3358 xmlNodePtr node); 3359 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 3360 xmlNodePtr nodes); 3361 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr 3362 ctxt, xmlNodePtr node, 3363 xmlRelaxNGDefinePtr 3364 def); 3365 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr 3366 ctxt, xmlNodePtr nodes); 3367 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 3368 xmlRelaxNGDefinePtr define, 3369 xmlNodePtr elem); 3370 3371 3372 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) 3373 3374 /** 3375 * xmlRelaxNGIsNullable: 3376 * @define: the definition to verify 3377 * 3378 * Check if a definition is nullable. 3379 * 3380 * Returns 1 if yes, 0 if no and -1 in case of error 3381 */ 3382 static int 3383 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) 3384 { 3385 int ret; 3386 3387 if (define == NULL) 3388 return (-1); 3389 3390 if (define->dflags & IS_NULLABLE) 3391 return (1); 3392 if (define->dflags & IS_NOT_NULLABLE) 3393 return (0); 3394 switch (define->type) { 3395 case XML_RELAXNG_EMPTY: 3396 case XML_RELAXNG_TEXT: 3397 ret = 1; 3398 break; 3399 case XML_RELAXNG_NOOP: 3400 case XML_RELAXNG_DEF: 3401 case XML_RELAXNG_REF: 3402 case XML_RELAXNG_EXTERNALREF: 3403 case XML_RELAXNG_PARENTREF: 3404 case XML_RELAXNG_ONEORMORE: 3405 ret = xmlRelaxNGIsNullable(define->content); 3406 break; 3407 case XML_RELAXNG_EXCEPT: 3408 case XML_RELAXNG_NOT_ALLOWED: 3409 case XML_RELAXNG_ELEMENT: 3410 case XML_RELAXNG_DATATYPE: 3411 case XML_RELAXNG_PARAM: 3412 case XML_RELAXNG_VALUE: 3413 case XML_RELAXNG_LIST: 3414 case XML_RELAXNG_ATTRIBUTE: 3415 ret = 0; 3416 break; 3417 case XML_RELAXNG_CHOICE:{ 3418 xmlRelaxNGDefinePtr list = define->content; 3419 3420 while (list != NULL) { 3421 ret = xmlRelaxNGIsNullable(list); 3422 if (ret != 0) 3423 goto done; 3424 list = list->next; 3425 } 3426 ret = 0; 3427 break; 3428 } 3429 case XML_RELAXNG_START: 3430 case XML_RELAXNG_INTERLEAVE: 3431 case XML_RELAXNG_GROUP:{ 3432 xmlRelaxNGDefinePtr list = define->content; 3433 3434 while (list != NULL) { 3435 ret = xmlRelaxNGIsNullable(list); 3436 if (ret != 1) 3437 goto done; 3438 list = list->next; 3439 } 3440 return (1); 3441 } 3442 default: 3443 return (-1); 3444 } 3445 done: 3446 if (ret == 0) 3447 define->dflags |= IS_NOT_NULLABLE; 3448 if (ret == 1) 3449 define->dflags |= IS_NULLABLE; 3450 return (ret); 3451 } 3452 3453 /** 3454 * xmlRelaxNGIsBlank: 3455 * @str: a string 3456 * 3457 * Check if a string is ignorable c.f. 4.2. Whitespace 3458 * 3459 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise 3460 */ 3461 static int 3462 xmlRelaxNGIsBlank(xmlChar * str) 3463 { 3464 if (str == NULL) 3465 return (1); 3466 while (*str != 0) { 3467 if (!(IS_BLANK_CH(*str))) 3468 return (0); 3469 str++; 3470 } 3471 return (1); 3472 } 3473 3474 /** 3475 * xmlRelaxNGGetDataTypeLibrary: 3476 * @ctxt: a Relax-NG parser context 3477 * @node: the current data or value element 3478 * 3479 * Applies algorithm from 4.3. datatypeLibrary attribute 3480 * 3481 * Returns the datatypeLibrary value or NULL if not found 3482 */ 3483 static xmlChar * 3484 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 3485 xmlNodePtr node) 3486 { 3487 xmlChar *ret, *escape; 3488 3489 if (node == NULL) 3490 return(NULL); 3491 3492 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { 3493 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3494 if (ret != NULL) { 3495 if (ret[0] == 0) { 3496 xmlFree(ret); 3497 return (NULL); 3498 } 3499 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3500 if (escape == NULL) { 3501 return (ret); 3502 } 3503 xmlFree(ret); 3504 return (escape); 3505 } 3506 } 3507 node = node->parent; 3508 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { 3509 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3510 if (ret != NULL) { 3511 if (ret[0] == 0) { 3512 xmlFree(ret); 3513 return (NULL); 3514 } 3515 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3516 if (escape == NULL) { 3517 return (ret); 3518 } 3519 xmlFree(ret); 3520 return (escape); 3521 } 3522 node = node->parent; 3523 } 3524 return (NULL); 3525 } 3526 3527 /** 3528 * xmlRelaxNGParseValue: 3529 * @ctxt: a Relax-NG parser context 3530 * @node: the data node. 3531 * 3532 * parse the content of a RelaxNG value node. 3533 * 3534 * Returns the definition pointer or NULL in case of error 3535 */ 3536 static xmlRelaxNGDefinePtr 3537 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3538 { 3539 xmlRelaxNGDefinePtr def = NULL; 3540 xmlRelaxNGTypeLibraryPtr lib = NULL; 3541 xmlChar *type; 3542 xmlChar *library; 3543 int success = 0; 3544 3545 def = xmlRelaxNGNewDefine(ctxt, node); 3546 if (def == NULL) 3547 return (NULL); 3548 def->type = XML_RELAXNG_VALUE; 3549 3550 type = xmlGetProp(node, BAD_CAST "type"); 3551 if (type != NULL) { 3552 xmlRelaxNGNormExtSpace(type); 3553 if (xmlValidateNCName(type, 0)) { 3554 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3555 "value type '%s' is not an NCName\n", type, NULL); 3556 } 3557 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3558 if (library == NULL) 3559 library = 3560 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3561 3562 def->name = type; 3563 def->ns = library; 3564 3565 lib = (xmlRelaxNGTypeLibraryPtr) 3566 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3567 if (lib == NULL) { 3568 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3569 "Use of unregistered type library '%s'\n", library, 3570 NULL); 3571 def->data = NULL; 3572 } else { 3573 def->data = lib; 3574 if (lib->have == NULL) { 3575 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3576 "Internal error with type library '%s': no 'have'\n", 3577 library, NULL); 3578 } else { 3579 success = lib->have(lib->data, def->name); 3580 if (success != 1) { 3581 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3582 "Error type '%s' is not exported by type library '%s'\n", 3583 def->name, library); 3584 } 3585 } 3586 } 3587 } 3588 if (node->children == NULL) { 3589 def->value = xmlStrdup(BAD_CAST ""); 3590 } else if (((node->children->type != XML_TEXT_NODE) && 3591 (node->children->type != XML_CDATA_SECTION_NODE)) || 3592 (node->children->next != NULL)) { 3593 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, 3594 "Expecting a single text value for <value>content\n", 3595 NULL, NULL); 3596 } else if (def != NULL) { 3597 def->value = xmlNodeGetContent(node); 3598 if (def->value == NULL) { 3599 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, 3600 "Element <value> has no content\n", NULL, NULL); 3601 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { 3602 void *val = NULL; 3603 3604 success = 3605 lib->check(lib->data, def->name, def->value, &val, node); 3606 if (success != 1) { 3607 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, 3608 "Value '%s' is not acceptable for type '%s'\n", 3609 def->value, def->name); 3610 } else { 3611 if (val != NULL) 3612 def->attrs = val; 3613 } 3614 } 3615 } 3616 return (def); 3617 } 3618 3619 /** 3620 * xmlRelaxNGParseData: 3621 * @ctxt: a Relax-NG parser context 3622 * @node: the data node. 3623 * 3624 * parse the content of a RelaxNG data node. 3625 * 3626 * Returns the definition pointer or NULL in case of error 3627 */ 3628 static xmlRelaxNGDefinePtr 3629 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3630 { 3631 xmlRelaxNGDefinePtr def = NULL, except; 3632 xmlRelaxNGDefinePtr param, lastparam = NULL; 3633 xmlRelaxNGTypeLibraryPtr lib; 3634 xmlChar *type; 3635 xmlChar *library; 3636 xmlNodePtr content; 3637 int tmp; 3638 3639 type = xmlGetProp(node, BAD_CAST "type"); 3640 if (type == NULL) { 3641 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, 3642 NULL); 3643 return (NULL); 3644 } 3645 xmlRelaxNGNormExtSpace(type); 3646 if (xmlValidateNCName(type, 0)) { 3647 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3648 "data type '%s' is not an NCName\n", type, NULL); 3649 } 3650 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3651 if (library == NULL) 3652 library = 3653 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3654 3655 def = xmlRelaxNGNewDefine(ctxt, node); 3656 if (def == NULL) { 3657 xmlFree(type); 3658 return (NULL); 3659 } 3660 def->type = XML_RELAXNG_DATATYPE; 3661 def->name = type; 3662 def->ns = library; 3663 3664 lib = (xmlRelaxNGTypeLibraryPtr) 3665 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3666 if (lib == NULL) { 3667 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3668 "Use of unregistered type library '%s'\n", library, 3669 NULL); 3670 def->data = NULL; 3671 } else { 3672 def->data = lib; 3673 if (lib->have == NULL) { 3674 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3675 "Internal error with type library '%s': no 'have'\n", 3676 library, NULL); 3677 } else { 3678 tmp = lib->have(lib->data, def->name); 3679 if (tmp != 1) { 3680 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3681 "Error type '%s' is not exported by type library '%s'\n", 3682 def->name, library); 3683 } else 3684 if ((xmlStrEqual 3685 (library, 3686 BAD_CAST 3687 "http://www.w3.org/2001/XMLSchema-datatypes")) 3688 && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) 3689 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { 3690 ctxt->idref = 1; 3691 } 3692 } 3693 } 3694 content = node->children; 3695 3696 /* 3697 * Handle optional params 3698 */ 3699 while (content != NULL) { 3700 if (!xmlStrEqual(content->name, BAD_CAST "param")) 3701 break; 3702 if (xmlStrEqual(library, 3703 BAD_CAST "http://relaxng.org/ns/structure/1.0")) { 3704 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, 3705 "Type library '%s' does not allow type parameters\n", 3706 library, NULL); 3707 content = content->next; 3708 while ((content != NULL) && 3709 (xmlStrEqual(content->name, BAD_CAST "param"))) 3710 content = content->next; 3711 } else { 3712 param = xmlRelaxNGNewDefine(ctxt, node); 3713 if (param != NULL) { 3714 param->type = XML_RELAXNG_PARAM; 3715 param->name = xmlGetProp(content, BAD_CAST "name"); 3716 if (param->name == NULL) { 3717 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, 3718 "param has no name\n", NULL, NULL); 3719 } 3720 param->value = xmlNodeGetContent(content); 3721 if (lastparam == NULL) { 3722 def->attrs = lastparam = param; 3723 } else { 3724 lastparam->next = param; 3725 lastparam = param; 3726 } 3727 if (lib != NULL) { 3728 } 3729 } 3730 content = content->next; 3731 } 3732 } 3733 /* 3734 * Handle optional except 3735 */ 3736 if ((content != NULL) 3737 && (xmlStrEqual(content->name, BAD_CAST "except"))) { 3738 xmlNodePtr child; 3739 xmlRelaxNGDefinePtr tmp2, last = NULL; 3740 3741 except = xmlRelaxNGNewDefine(ctxt, node); 3742 if (except == NULL) { 3743 return (def); 3744 } 3745 except->type = XML_RELAXNG_EXCEPT; 3746 child = content->children; 3747 def->content = except; 3748 if (child == NULL) { 3749 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, 3750 "except has no content\n", NULL, NULL); 3751 } 3752 while (child != NULL) { 3753 tmp2 = xmlRelaxNGParsePattern(ctxt, child); 3754 if (tmp2 != NULL) { 3755 if (last == NULL) { 3756 except->content = last = tmp2; 3757 } else { 3758 last->next = tmp2; 3759 last = tmp2; 3760 } 3761 } 3762 child = child->next; 3763 } 3764 content = content->next; 3765 } 3766 /* 3767 * Check there is no unhandled data 3768 */ 3769 if (content != NULL) { 3770 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, 3771 "Element data has unexpected content %s\n", 3772 content->name, NULL); 3773 } 3774 3775 return (def); 3776 } 3777 3778 static const xmlChar *invalidName = BAD_CAST "\1"; 3779 3780 /** 3781 * xmlRelaxNGCompareNameClasses: 3782 * @defs1: the first element/attribute defs 3783 * @defs2: the second element/attribute defs 3784 * @name: the restriction on the name 3785 * @ns: the restriction on the namespace 3786 * 3787 * Compare the 2 lists of element definitions. The comparison is 3788 * that if both lists do not accept the same QNames, it returns 1 3789 * If the 2 lists can accept the same QName the comparison returns 0 3790 * 3791 * Returns 1 distinct, 0 if equal 3792 */ 3793 static int 3794 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, 3795 xmlRelaxNGDefinePtr def2) 3796 { 3797 int ret = 1; 3798 xmlNode node; 3799 xmlNs ns; 3800 xmlRelaxNGValidCtxt ctxt; 3801 3802 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); 3803 3804 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; 3805 3806 if ((def1->type == XML_RELAXNG_ELEMENT) || 3807 (def1->type == XML_RELAXNG_ATTRIBUTE)) { 3808 if (def2->type == XML_RELAXNG_TEXT) 3809 return (1); 3810 if (def1->name != NULL) { 3811 node.name = def1->name; 3812 } else { 3813 node.name = invalidName; 3814 } 3815 if (def1->ns != NULL) { 3816 if (def1->ns[0] == 0) { 3817 node.ns = NULL; 3818 } else { 3819 node.ns = &ns; 3820 ns.href = def1->ns; 3821 } 3822 } else { 3823 node.ns = NULL; 3824 } 3825 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { 3826 if (def1->nameClass != NULL) { 3827 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); 3828 } else { 3829 ret = 0; 3830 } 3831 } else { 3832 ret = 1; 3833 } 3834 } else if (def1->type == XML_RELAXNG_TEXT) { 3835 if (def2->type == XML_RELAXNG_TEXT) 3836 return (0); 3837 return (1); 3838 } else if (def1->type == XML_RELAXNG_EXCEPT) { 3839 ret = xmlRelaxNGCompareNameClasses(def1->content, def2); 3840 if (ret == 0) 3841 ret = 1; 3842 else if (ret == 1) 3843 ret = 0; 3844 } else { 3845 TODO ret = 0; 3846 } 3847 if (ret == 0) 3848 return (ret); 3849 if ((def2->type == XML_RELAXNG_ELEMENT) || 3850 (def2->type == XML_RELAXNG_ATTRIBUTE)) { 3851 if (def2->name != NULL) { 3852 node.name = def2->name; 3853 } else { 3854 node.name = invalidName; 3855 } 3856 node.ns = &ns; 3857 if (def2->ns != NULL) { 3858 if (def2->ns[0] == 0) { 3859 node.ns = NULL; 3860 } else { 3861 ns.href = def2->ns; 3862 } 3863 } else { 3864 ns.href = invalidName; 3865 } 3866 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { 3867 if (def2->nameClass != NULL) { 3868 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); 3869 } else { 3870 ret = 0; 3871 } 3872 } else { 3873 ret = 1; 3874 } 3875 } else { 3876 TODO ret = 0; 3877 } 3878 3879 return (ret); 3880 } 3881 3882 /** 3883 * xmlRelaxNGCompareElemDefLists: 3884 * @ctxt: a Relax-NG parser context 3885 * @defs1: the first list of element/attribute defs 3886 * @defs2: the second list of element/attribute defs 3887 * 3888 * Compare the 2 lists of element or attribute definitions. The comparison 3889 * is that if both lists do not accept the same QNames, it returns 1 3890 * If the 2 lists can accept the same QName the comparison returns 0 3891 * 3892 * Returns 1 distinct, 0 if equal 3893 */ 3894 static int 3895 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt 3896 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, 3897 xmlRelaxNGDefinePtr * def2) 3898 { 3899 xmlRelaxNGDefinePtr *basedef2 = def2; 3900 3901 if ((def1 == NULL) || (def2 == NULL)) 3902 return (1); 3903 if ((*def1 == NULL) || (*def2 == NULL)) 3904 return (1); 3905 while (*def1 != NULL) { 3906 while ((*def2) != NULL) { 3907 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) 3908 return (0); 3909 def2++; 3910 } 3911 def2 = basedef2; 3912 def1++; 3913 } 3914 return (1); 3915 } 3916 3917 /** 3918 * xmlRelaxNGGenerateAttributes: 3919 * @ctxt: a Relax-NG parser context 3920 * @def: the definition definition 3921 * 3922 * Check if the definition can only generate attributes 3923 * 3924 * Returns 1 if yes, 0 if no and -1 in case of error. 3925 */ 3926 static int 3927 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, 3928 xmlRelaxNGDefinePtr def) 3929 { 3930 xmlRelaxNGDefinePtr parent, cur, tmp; 3931 3932 /* 3933 * Don't run that check in case of error. Infinite recursion 3934 * becomes possible. 3935 */ 3936 if (ctxt->nbErrors != 0) 3937 return (-1); 3938 3939 parent = NULL; 3940 cur = def; 3941 while (cur != NULL) { 3942 if ((cur->type == XML_RELAXNG_ELEMENT) || 3943 (cur->type == XML_RELAXNG_TEXT) || 3944 (cur->type == XML_RELAXNG_DATATYPE) || 3945 (cur->type == XML_RELAXNG_PARAM) || 3946 (cur->type == XML_RELAXNG_LIST) || 3947 (cur->type == XML_RELAXNG_VALUE) || 3948 (cur->type == XML_RELAXNG_EMPTY)) 3949 return (0); 3950 if ((cur->type == XML_RELAXNG_CHOICE) || 3951 (cur->type == XML_RELAXNG_INTERLEAVE) || 3952 (cur->type == XML_RELAXNG_GROUP) || 3953 (cur->type == XML_RELAXNG_ONEORMORE) || 3954 (cur->type == XML_RELAXNG_ZEROORMORE) || 3955 (cur->type == XML_RELAXNG_OPTIONAL) || 3956 (cur->type == XML_RELAXNG_PARENTREF) || 3957 (cur->type == XML_RELAXNG_EXTERNALREF) || 3958 (cur->type == XML_RELAXNG_REF) || 3959 (cur->type == XML_RELAXNG_DEF)) { 3960 if (cur->content != NULL) { 3961 parent = cur; 3962 cur = cur->content; 3963 tmp = cur; 3964 while (tmp != NULL) { 3965 tmp->parent = parent; 3966 tmp = tmp->next; 3967 } 3968 continue; 3969 } 3970 } 3971 if (cur == def) 3972 break; 3973 if (cur->next != NULL) { 3974 cur = cur->next; 3975 continue; 3976 } 3977 do { 3978 cur = cur->parent; 3979 if (cur == NULL) 3980 break; 3981 if (cur == def) 3982 return (1); 3983 if (cur->next != NULL) { 3984 cur = cur->next; 3985 break; 3986 } 3987 } while (cur != NULL); 3988 } 3989 return (1); 3990 } 3991 3992 /** 3993 * xmlRelaxNGGetElements: 3994 * @ctxt: a Relax-NG parser context 3995 * @def: the definition definition 3996 * @eora: gather elements (0), attributes (1) or elements and text (2) 3997 * 3998 * Compute the list of top elements a definition can generate 3999 * 4000 * Returns a list of elements or NULL if none was found. 4001 */ 4002 static xmlRelaxNGDefinePtr * 4003 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, 4004 xmlRelaxNGDefinePtr def, int eora) 4005 { 4006 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; 4007 int len = 0; 4008 int max = 0; 4009 4010 /* 4011 * Don't run that check in case of error. Infinite recursion 4012 * becomes possible. 4013 */ 4014 if (ctxt->nbErrors != 0) 4015 return (NULL); 4016 4017 parent = NULL; 4018 cur = def; 4019 while (cur != NULL) { 4020 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || 4021 (cur->type == XML_RELAXNG_TEXT))) || 4022 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE)) || 4023 ((eora == 2) && ((cur->type == XML_RELAXNG_DATATYPE) || 4024 (cur->type == XML_RELAXNG_ELEMENT) || 4025 (cur->type == XML_RELAXNG_LIST) || 4026 (cur->type == XML_RELAXNG_TEXT) || 4027 (cur->type == XML_RELAXNG_VALUE)))) { 4028 if (ret == NULL) { 4029 max = 10; 4030 ret = (xmlRelaxNGDefinePtr *) 4031 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4032 if (ret == NULL) { 4033 xmlRngPErrMemory(ctxt, "getting element list\n"); 4034 return (NULL); 4035 } 4036 } else if (max <= len) { 4037 xmlRelaxNGDefinePtr *temp; 4038 4039 max *= 2; 4040 temp = xmlRealloc(ret, 4041 (max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4042 if (temp == NULL) { 4043 xmlRngPErrMemory(ctxt, "getting element list\n"); 4044 xmlFree(ret); 4045 return (NULL); 4046 } 4047 ret = temp; 4048 } 4049 ret[len++] = cur; 4050 ret[len] = NULL; 4051 } else if ((cur->type == XML_RELAXNG_CHOICE) || 4052 (cur->type == XML_RELAXNG_INTERLEAVE) || 4053 (cur->type == XML_RELAXNG_GROUP) || 4054 (cur->type == XML_RELAXNG_ONEORMORE) || 4055 (cur->type == XML_RELAXNG_ZEROORMORE) || 4056 (cur->type == XML_RELAXNG_OPTIONAL) || 4057 (cur->type == XML_RELAXNG_PARENTREF) || 4058 (cur->type == XML_RELAXNG_REF) || 4059 (cur->type == XML_RELAXNG_DEF) || 4060 (cur->type == XML_RELAXNG_EXTERNALREF)) { 4061 /* 4062 * Don't go within elements or attributes or string values. 4063 * Just gather the element top list 4064 */ 4065 if (cur->content != NULL) { 4066 parent = cur; 4067 cur = cur->content; 4068 tmp = cur; 4069 while (tmp != NULL) { 4070 tmp->parent = parent; 4071 tmp = tmp->next; 4072 } 4073 continue; 4074 } 4075 } 4076 if (cur == def) 4077 break; 4078 if (cur->next != NULL) { 4079 cur = cur->next; 4080 continue; 4081 } 4082 do { 4083 cur = cur->parent; 4084 if (cur == NULL) 4085 break; 4086 if (cur == def) 4087 return (ret); 4088 if (cur->next != NULL) { 4089 cur = cur->next; 4090 break; 4091 } 4092 } while (cur != NULL); 4093 } 4094 return (ret); 4095 } 4096 4097 /** 4098 * xmlRelaxNGCheckChoiceDeterminism: 4099 * @ctxt: a Relax-NG parser context 4100 * @def: the choice definition 4101 * 4102 * Also used to find indeterministic pattern in choice 4103 */ 4104 static void 4105 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, 4106 xmlRelaxNGDefinePtr def) 4107 { 4108 xmlRelaxNGDefinePtr **list; 4109 xmlRelaxNGDefinePtr cur; 4110 int nbchild = 0, i, j, ret; 4111 int is_nullable = 0; 4112 int is_indeterminist = 0; 4113 xmlHashTablePtr triage = NULL; 4114 int is_triable = 1; 4115 4116 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) 4117 return; 4118 4119 if (def->dflags & IS_PROCESSED) 4120 return; 4121 4122 /* 4123 * Don't run that check in case of error. Infinite recursion 4124 * becomes possible. 4125 */ 4126 if (ctxt->nbErrors != 0) 4127 return; 4128 4129 is_nullable = xmlRelaxNGIsNullable(def); 4130 4131 cur = def->content; 4132 while (cur != NULL) { 4133 nbchild++; 4134 cur = cur->next; 4135 } 4136 4137 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4138 sizeof(xmlRelaxNGDefinePtr 4139 *)); 4140 if (list == NULL) { 4141 xmlRngPErrMemory(ctxt, "building choice\n"); 4142 return; 4143 } 4144 i = 0; 4145 /* 4146 * a bit strong but safe 4147 */ 4148 if (is_nullable == 0) { 4149 triage = xmlHashCreate(10); 4150 } else { 4151 is_triable = 0; 4152 } 4153 cur = def->content; 4154 while (cur != NULL) { 4155 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); 4156 if ((list[i] == NULL) || (list[i][0] == NULL)) { 4157 is_triable = 0; 4158 } else if (is_triable == 1) { 4159 xmlRelaxNGDefinePtr *tmp; 4160 int res; 4161 4162 tmp = list[i]; 4163 while ((*tmp != NULL) && (is_triable == 1)) { 4164 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4165 res = xmlHashAddEntry2(triage, 4166 BAD_CAST "#text", NULL, 4167 (void *) cur); 4168 if (res != 0) 4169 is_triable = -1; 4170 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4171 ((*tmp)->name != NULL)) { 4172 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4173 res = xmlHashAddEntry2(triage, 4174 (*tmp)->name, NULL, 4175 (void *) cur); 4176 else 4177 res = xmlHashAddEntry2(triage, 4178 (*tmp)->name, (*tmp)->ns, 4179 (void *) cur); 4180 if (res != 0) 4181 is_triable = -1; 4182 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4183 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4184 res = xmlHashAddEntry2(triage, 4185 BAD_CAST "#any", NULL, 4186 (void *) cur); 4187 else 4188 res = xmlHashAddEntry2(triage, 4189 BAD_CAST "#any", (*tmp)->ns, 4190 (void *) cur); 4191 if (res != 0) 4192 is_triable = -1; 4193 } else { 4194 is_triable = -1; 4195 } 4196 tmp++; 4197 } 4198 } 4199 i++; 4200 cur = cur->next; 4201 } 4202 4203 for (i = 0; i < nbchild; i++) { 4204 if (list[i] == NULL) 4205 continue; 4206 for (j = 0; j < i; j++) { 4207 if (list[j] == NULL) 4208 continue; 4209 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4210 if (ret == 0) { 4211 is_indeterminist = 1; 4212 } 4213 } 4214 } 4215 for (i = 0; i < nbchild; i++) { 4216 if (list[i] != NULL) 4217 xmlFree(list[i]); 4218 } 4219 4220 xmlFree(list); 4221 if (is_indeterminist) { 4222 def->dflags |= IS_INDETERMINIST; 4223 } 4224 if (is_triable == 1) { 4225 def->dflags |= IS_TRIABLE; 4226 def->data = triage; 4227 } else if (triage != NULL) { 4228 xmlHashFree(triage, NULL); 4229 } 4230 def->dflags |= IS_PROCESSED; 4231 } 4232 4233 /** 4234 * xmlRelaxNGCheckGroupAttrs: 4235 * @ctxt: a Relax-NG parser context 4236 * @def: the group definition 4237 * 4238 * Detects violations of rule 7.3 4239 */ 4240 static void 4241 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, 4242 xmlRelaxNGDefinePtr def) 4243 { 4244 xmlRelaxNGDefinePtr **list; 4245 xmlRelaxNGDefinePtr cur; 4246 int nbchild = 0, i, j, ret; 4247 4248 if ((def == NULL) || 4249 ((def->type != XML_RELAXNG_GROUP) && 4250 (def->type != XML_RELAXNG_ELEMENT))) 4251 return; 4252 4253 if (def->dflags & IS_PROCESSED) 4254 return; 4255 4256 /* 4257 * Don't run that check in case of error. Infinite recursion 4258 * becomes possible. 4259 */ 4260 if (ctxt->nbErrors != 0) 4261 return; 4262 4263 cur = def->attrs; 4264 while (cur != NULL) { 4265 nbchild++; 4266 cur = cur->next; 4267 } 4268 cur = def->content; 4269 while (cur != NULL) { 4270 nbchild++; 4271 cur = cur->next; 4272 } 4273 4274 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4275 sizeof(xmlRelaxNGDefinePtr 4276 *)); 4277 if (list == NULL) { 4278 xmlRngPErrMemory(ctxt, "building group\n"); 4279 return; 4280 } 4281 i = 0; 4282 cur = def->attrs; 4283 while (cur != NULL) { 4284 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4285 i++; 4286 cur = cur->next; 4287 } 4288 cur = def->content; 4289 while (cur != NULL) { 4290 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4291 i++; 4292 cur = cur->next; 4293 } 4294 4295 for (i = 0; i < nbchild; i++) { 4296 if (list[i] == NULL) 4297 continue; 4298 for (j = 0; j < i; j++) { 4299 if (list[j] == NULL) 4300 continue; 4301 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4302 if (ret == 0) { 4303 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, 4304 "Attributes conflicts in group\n", NULL, NULL); 4305 } 4306 } 4307 } 4308 for (i = 0; i < nbchild; i++) { 4309 if (list[i] != NULL) 4310 xmlFree(list[i]); 4311 } 4312 4313 xmlFree(list); 4314 def->dflags |= IS_PROCESSED; 4315 } 4316 4317 /** 4318 * xmlRelaxNGComputeInterleaves: 4319 * @def: the interleave definition 4320 * @ctxt: a Relax-NG parser context 4321 * @name: the definition name 4322 * 4323 * A lot of work for preprocessing interleave definitions 4324 * is potentially needed to get a decent execution speed at runtime 4325 * - trying to get a total order on the element nodes generated 4326 * by the interleaves, order the list of interleave definitions 4327 * following that order. 4328 * - if <text/> is used to handle mixed content, it is better to 4329 * flag this in the define and simplify the runtime checking 4330 * algorithm 4331 */ 4332 static void 4333 xmlRelaxNGComputeInterleaves(void *payload, void *data, 4334 const xmlChar * name ATTRIBUTE_UNUSED) 4335 { 4336 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; 4337 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 4338 xmlRelaxNGDefinePtr cur, *tmp; 4339 4340 xmlRelaxNGPartitionPtr partitions = NULL; 4341 xmlRelaxNGInterleaveGroupPtr *groups = NULL; 4342 xmlRelaxNGInterleaveGroupPtr group; 4343 int i, j, ret, res; 4344 int nbgroups = 0; 4345 int nbchild = 0; 4346 int is_mixed = 0; 4347 int is_determinist = 1; 4348 4349 /* 4350 * Don't run that check in case of error. Infinite recursion 4351 * becomes possible. 4352 */ 4353 if (ctxt->nbErrors != 0) 4354 return; 4355 4356 #ifdef DEBUG_INTERLEAVE 4357 xmlGenericError(xmlGenericErrorContext, 4358 "xmlRelaxNGComputeInterleaves(%s)\n", name); 4359 #endif 4360 cur = def->content; 4361 while (cur != NULL) { 4362 nbchild++; 4363 cur = cur->next; 4364 } 4365 4366 #ifdef DEBUG_INTERLEAVE 4367 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); 4368 #endif 4369 groups = (xmlRelaxNGInterleaveGroupPtr *) 4370 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); 4371 if (groups == NULL) 4372 goto error; 4373 cur = def->content; 4374 while (cur != NULL) { 4375 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) 4376 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); 4377 if (groups[nbgroups] == NULL) 4378 goto error; 4379 if (cur->type == XML_RELAXNG_TEXT) 4380 is_mixed++; 4381 groups[nbgroups]->rule = cur; 4382 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 2); 4383 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); 4384 nbgroups++; 4385 cur = cur->next; 4386 } 4387 #ifdef DEBUG_INTERLEAVE 4388 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); 4389 #endif 4390 4391 /* 4392 * Let's check that all rules makes a partitions according to 7.4 4393 */ 4394 partitions = (xmlRelaxNGPartitionPtr) 4395 xmlMalloc(sizeof(xmlRelaxNGPartition)); 4396 if (partitions == NULL) 4397 goto error; 4398 memset(partitions, 0, sizeof(xmlRelaxNGPartition)); 4399 partitions->nbgroups = nbgroups; 4400 partitions->triage = xmlHashCreate(nbgroups); 4401 for (i = 0; i < nbgroups; i++) { 4402 group = groups[i]; 4403 for (j = i + 1; j < nbgroups; j++) { 4404 if (groups[j] == NULL) 4405 continue; 4406 4407 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, 4408 groups[j]->defs); 4409 if (ret == 0) { 4410 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, 4411 "Element or text conflicts in interleave\n", 4412 NULL, NULL); 4413 } 4414 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, 4415 groups[j]->attrs); 4416 if (ret == 0) { 4417 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, 4418 "Attributes conflicts in interleave\n", NULL, 4419 NULL); 4420 } 4421 } 4422 tmp = group->defs; 4423 if ((tmp != NULL) && (*tmp != NULL)) { 4424 while (*tmp != NULL) { 4425 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4426 res = xmlHashAddEntry2(partitions->triage, 4427 BAD_CAST "#text", NULL, 4428 (void *) (ptrdiff_t) (i + 1)); 4429 if (res != 0) 4430 is_determinist = -1; 4431 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4432 ((*tmp)->name != NULL)) { 4433 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4434 res = xmlHashAddEntry2(partitions->triage, 4435 (*tmp)->name, NULL, 4436 (void *) (ptrdiff_t) (i + 1)); 4437 else 4438 res = xmlHashAddEntry2(partitions->triage, 4439 (*tmp)->name, (*tmp)->ns, 4440 (void *) (ptrdiff_t) (i + 1)); 4441 if (res != 0) 4442 is_determinist = -1; 4443 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4444 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4445 res = xmlHashAddEntry2(partitions->triage, 4446 BAD_CAST "#any", NULL, 4447 (void *) (ptrdiff_t) (i + 1)); 4448 else 4449 res = xmlHashAddEntry2(partitions->triage, 4450 BAD_CAST "#any", (*tmp)->ns, 4451 (void *) (ptrdiff_t) (i + 1)); 4452 if ((*tmp)->nameClass != NULL) 4453 is_determinist = 2; 4454 if (res != 0) 4455 is_determinist = -1; 4456 } else { 4457 is_determinist = -1; 4458 } 4459 tmp++; 4460 } 4461 } else { 4462 is_determinist = 0; 4463 } 4464 } 4465 partitions->groups = groups; 4466 4467 /* 4468 * and save the partition list back in the def 4469 */ 4470 def->data = partitions; 4471 if (is_mixed != 0) 4472 def->dflags |= IS_MIXED; 4473 if (is_determinist == 1) 4474 partitions->flags = IS_DETERMINIST; 4475 if (is_determinist == 2) 4476 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; 4477 return; 4478 4479 error: 4480 xmlRngPErrMemory(ctxt, "in interleave computation\n"); 4481 if (groups != NULL) { 4482 for (i = 0; i < nbgroups; i++) 4483 if (groups[i] != NULL) { 4484 if (groups[i]->defs != NULL) 4485 xmlFree(groups[i]->defs); 4486 xmlFree(groups[i]); 4487 } 4488 xmlFree(groups); 4489 } 4490 xmlRelaxNGFreePartition(partitions); 4491 } 4492 4493 /** 4494 * xmlRelaxNGParseInterleave: 4495 * @ctxt: a Relax-NG parser context 4496 * @node: the data node. 4497 * 4498 * parse the content of a RelaxNG interleave node. 4499 * 4500 * Returns the definition pointer or NULL in case of error 4501 */ 4502 static xmlRelaxNGDefinePtr 4503 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4504 { 4505 xmlRelaxNGDefinePtr def = NULL; 4506 xmlRelaxNGDefinePtr last = NULL, cur; 4507 xmlNodePtr child; 4508 4509 def = xmlRelaxNGNewDefine(ctxt, node); 4510 if (def == NULL) { 4511 return (NULL); 4512 } 4513 def->type = XML_RELAXNG_INTERLEAVE; 4514 4515 if (ctxt->interleaves == NULL) 4516 ctxt->interleaves = xmlHashCreate(10); 4517 if (ctxt->interleaves == NULL) { 4518 xmlRngPErrMemory(ctxt, "create interleaves\n"); 4519 } else { 4520 char name[32]; 4521 4522 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); 4523 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { 4524 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, 4525 "Failed to add %s to hash table\n", 4526 (const xmlChar *) name, NULL); 4527 } 4528 } 4529 child = node->children; 4530 if (child == NULL) { 4531 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, 4532 "Element interleave is empty\n", NULL, NULL); 4533 } 4534 while (child != NULL) { 4535 if (IS_RELAXNG(child, "element")) { 4536 cur = xmlRelaxNGParseElement(ctxt, child); 4537 } else { 4538 cur = xmlRelaxNGParsePattern(ctxt, child); 4539 } 4540 if (cur != NULL) { 4541 cur->parent = def; 4542 if (last == NULL) { 4543 def->content = last = cur; 4544 } else { 4545 last->next = cur; 4546 last = cur; 4547 } 4548 } 4549 child = child->next; 4550 } 4551 4552 return (def); 4553 } 4554 4555 /** 4556 * xmlRelaxNGParseInclude: 4557 * @ctxt: a Relax-NG parser context 4558 * @node: the include node 4559 * 4560 * Integrate the content of an include node in the current grammar 4561 * 4562 * Returns 0 in case of success or -1 in case of error 4563 */ 4564 static int 4565 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4566 { 4567 xmlRelaxNGIncludePtr incl; 4568 xmlNodePtr root; 4569 int ret = 0, tmp; 4570 4571 incl = node->psvi; 4572 if (incl == NULL) { 4573 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, 4574 "Include node has no data\n", NULL, NULL); 4575 return (-1); 4576 } 4577 root = xmlDocGetRootElement(incl->doc); 4578 if (root == NULL) { 4579 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", 4580 NULL, NULL); 4581 return (-1); 4582 } 4583 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { 4584 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 4585 "Include document root is not a grammar\n", NULL, NULL); 4586 return (-1); 4587 } 4588 4589 /* 4590 * Merge the definition from both the include and the internal list 4591 */ 4592 if (root->children != NULL) { 4593 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); 4594 if (tmp != 0) 4595 ret = -1; 4596 } 4597 if (node->children != NULL) { 4598 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); 4599 if (tmp != 0) 4600 ret = -1; 4601 } 4602 return (ret); 4603 } 4604 4605 /** 4606 * xmlRelaxNGParseDefine: 4607 * @ctxt: a Relax-NG parser context 4608 * @node: the define node 4609 * 4610 * parse the content of a RelaxNG define element node. 4611 * 4612 * Returns 0 in case of success or -1 in case of error 4613 */ 4614 static int 4615 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4616 { 4617 xmlChar *name; 4618 int ret = 0, tmp; 4619 xmlRelaxNGDefinePtr def; 4620 const xmlChar *olddefine; 4621 4622 name = xmlGetProp(node, BAD_CAST "name"); 4623 if (name == NULL) { 4624 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, 4625 "define has no name\n", NULL, NULL); 4626 } else { 4627 xmlRelaxNGNormExtSpace(name); 4628 if (xmlValidateNCName(name, 0)) { 4629 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, 4630 "define name '%s' is not an NCName\n", name, NULL); 4631 } 4632 def = xmlRelaxNGNewDefine(ctxt, node); 4633 if (def == NULL) { 4634 xmlFree(name); 4635 return (-1); 4636 } 4637 def->type = XML_RELAXNG_DEF; 4638 def->name = name; 4639 if (node->children == NULL) { 4640 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, 4641 "define has no children\n", NULL, NULL); 4642 } else { 4643 olddefine = ctxt->define; 4644 ctxt->define = name; 4645 def->content = 4646 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4647 ctxt->define = olddefine; 4648 } 4649 if (ctxt->grammar->defs == NULL) 4650 ctxt->grammar->defs = xmlHashCreate(10); 4651 if (ctxt->grammar->defs == NULL) { 4652 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4653 "Could not create definition hash\n", NULL, NULL); 4654 ret = -1; 4655 } else { 4656 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); 4657 if (tmp < 0) { 4658 xmlRelaxNGDefinePtr prev; 4659 4660 prev = xmlHashLookup(ctxt->grammar->defs, name); 4661 if (prev == NULL) { 4662 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4663 "Internal error on define aggregation of %s\n", 4664 name, NULL); 4665 ret = -1; 4666 } else { 4667 while (prev->nextHash != NULL) 4668 prev = prev->nextHash; 4669 prev->nextHash = def; 4670 } 4671 } 4672 } 4673 } 4674 return (ret); 4675 } 4676 4677 /** 4678 * xmlRelaxNGParseImportRef: 4679 * @payload: the parser context 4680 * @data: the current grammar 4681 * @name: the reference name 4682 * 4683 * Import import one references into the current grammar 4684 */ 4685 static void 4686 xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) { 4687 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 4688 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; 4689 int tmp; 4690 4691 def->dflags |= IS_EXTERNAL_REF; 4692 4693 tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def); 4694 if (tmp < 0) { 4695 xmlRelaxNGDefinePtr prev; 4696 4697 prev = (xmlRelaxNGDefinePtr) 4698 xmlHashLookup(ctxt->grammar->refs, def->name); 4699 if (prev == NULL) { 4700 if (def->name != NULL) { 4701 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4702 "Error refs definitions '%s'\n", 4703 def->name, NULL); 4704 } else { 4705 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4706 "Error refs definitions\n", 4707 NULL, NULL); 4708 } 4709 } else { 4710 def->nextHash = prev->nextHash; 4711 prev->nextHash = def; 4712 } 4713 } 4714 } 4715 4716 /** 4717 * xmlRelaxNGParseImportRefs: 4718 * @ctxt: the parser context 4719 * @grammar: the sub grammar 4720 * 4721 * Import references from the subgrammar into the current grammar 4722 * 4723 * Returns 0 in case of success, -1 in case of failure 4724 */ 4725 static int 4726 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt, 4727 xmlRelaxNGGrammarPtr grammar) { 4728 if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL)) 4729 return(-1); 4730 if (grammar->refs == NULL) 4731 return(0); 4732 if (ctxt->grammar->refs == NULL) 4733 ctxt->grammar->refs = xmlHashCreate(10); 4734 if (ctxt->grammar->refs == NULL) { 4735 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4736 "Could not create references hash\n", NULL, NULL); 4737 return(-1); 4738 } 4739 xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt); 4740 return(0); 4741 } 4742 4743 /** 4744 * xmlRelaxNGProcessExternalRef: 4745 * @ctxt: the parser context 4746 * @node: the externalRef node 4747 * 4748 * Process and compile an externalRef node 4749 * 4750 * Returns the xmlRelaxNGDefinePtr or NULL in case of error 4751 */ 4752 static xmlRelaxNGDefinePtr 4753 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4754 { 4755 xmlRelaxNGDocumentPtr docu; 4756 xmlNodePtr root, tmp; 4757 xmlChar *ns; 4758 int newNs = 0, oldflags; 4759 xmlRelaxNGDefinePtr def; 4760 4761 docu = node->psvi; 4762 if (docu != NULL) { 4763 def = xmlRelaxNGNewDefine(ctxt, node); 4764 if (def == NULL) 4765 return (NULL); 4766 def->type = XML_RELAXNG_EXTERNALREF; 4767 4768 if (docu->content == NULL) { 4769 /* 4770 * Then do the parsing for good 4771 */ 4772 root = xmlDocGetRootElement(docu->doc); 4773 if (root == NULL) { 4774 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY, 4775 "xmlRelaxNGParse: %s is empty\n", ctxt->URL, 4776 NULL); 4777 return (NULL); 4778 } 4779 /* 4780 * ns transmission rules 4781 */ 4782 ns = xmlGetProp(root, BAD_CAST "ns"); 4783 if (ns == NULL) { 4784 tmp = node; 4785 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) { 4786 ns = xmlGetProp(tmp, BAD_CAST "ns"); 4787 if (ns != NULL) { 4788 break; 4789 } 4790 tmp = tmp->parent; 4791 } 4792 if (ns != NULL) { 4793 xmlSetProp(root, BAD_CAST "ns", ns); 4794 newNs = 1; 4795 xmlFree(ns); 4796 } 4797 } else { 4798 xmlFree(ns); 4799 } 4800 4801 /* 4802 * Parsing to get a precompiled schemas. 4803 */ 4804 oldflags = ctxt->flags; 4805 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; 4806 docu->schema = xmlRelaxNGParseDocument(ctxt, root); 4807 ctxt->flags = oldflags; 4808 if ((docu->schema != NULL) && 4809 (docu->schema->topgrammar != NULL)) { 4810 docu->content = docu->schema->topgrammar->start; 4811 if (docu->schema->topgrammar->refs) 4812 xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar); 4813 } 4814 4815 /* 4816 * the externalRef may be reused in a different ns context 4817 */ 4818 if (newNs == 1) { 4819 xmlUnsetProp(root, BAD_CAST "ns"); 4820 } 4821 } 4822 def->content = docu->content; 4823 } else { 4824 def = NULL; 4825 } 4826 return (def); 4827 } 4828 4829 /** 4830 * xmlRelaxNGParsePattern: 4831 * @ctxt: a Relax-NG parser context 4832 * @node: the pattern node. 4833 * 4834 * parse the content of a RelaxNG pattern node. 4835 * 4836 * Returns the definition pointer or NULL in case of error or if no 4837 * pattern is generated. 4838 */ 4839 static xmlRelaxNGDefinePtr 4840 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4841 { 4842 xmlRelaxNGDefinePtr def = NULL; 4843 4844 if (node == NULL) { 4845 return (NULL); 4846 } 4847 if (IS_RELAXNG(node, "element")) { 4848 def = xmlRelaxNGParseElement(ctxt, node); 4849 } else if (IS_RELAXNG(node, "attribute")) { 4850 def = xmlRelaxNGParseAttribute(ctxt, node); 4851 } else if (IS_RELAXNG(node, "empty")) { 4852 def = xmlRelaxNGNewDefine(ctxt, node); 4853 if (def == NULL) 4854 return (NULL); 4855 def->type = XML_RELAXNG_EMPTY; 4856 if (node->children != NULL) { 4857 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY, 4858 "empty: had a child node\n", NULL, NULL); 4859 } 4860 } else if (IS_RELAXNG(node, "text")) { 4861 def = xmlRelaxNGNewDefine(ctxt, node); 4862 if (def == NULL) 4863 return (NULL); 4864 def->type = XML_RELAXNG_TEXT; 4865 if (node->children != NULL) { 4866 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD, 4867 "text: had a child node\n", NULL, NULL); 4868 } 4869 } else if (IS_RELAXNG(node, "zeroOrMore")) { 4870 def = xmlRelaxNGNewDefine(ctxt, node); 4871 if (def == NULL) 4872 return (NULL); 4873 def->type = XML_RELAXNG_ZEROORMORE; 4874 if (node->children == NULL) { 4875 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4876 "Element %s is empty\n", node->name, NULL); 4877 } else { 4878 def->content = 4879 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4880 } 4881 } else if (IS_RELAXNG(node, "oneOrMore")) { 4882 def = xmlRelaxNGNewDefine(ctxt, node); 4883 if (def == NULL) 4884 return (NULL); 4885 def->type = XML_RELAXNG_ONEORMORE; 4886 if (node->children == NULL) { 4887 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4888 "Element %s is empty\n", node->name, NULL); 4889 } else { 4890 def->content = 4891 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4892 } 4893 } else if (IS_RELAXNG(node, "optional")) { 4894 def = xmlRelaxNGNewDefine(ctxt, node); 4895 if (def == NULL) 4896 return (NULL); 4897 def->type = XML_RELAXNG_OPTIONAL; 4898 if (node->children == NULL) { 4899 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4900 "Element %s is empty\n", node->name, NULL); 4901 } else { 4902 def->content = 4903 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4904 } 4905 } else if (IS_RELAXNG(node, "choice")) { 4906 def = xmlRelaxNGNewDefine(ctxt, node); 4907 if (def == NULL) 4908 return (NULL); 4909 def->type = XML_RELAXNG_CHOICE; 4910 if (node->children == NULL) { 4911 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4912 "Element %s is empty\n", node->name, NULL); 4913 } else { 4914 def->content = 4915 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4916 } 4917 } else if (IS_RELAXNG(node, "group")) { 4918 def = xmlRelaxNGNewDefine(ctxt, node); 4919 if (def == NULL) 4920 return (NULL); 4921 def->type = XML_RELAXNG_GROUP; 4922 if (node->children == NULL) { 4923 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4924 "Element %s is empty\n", node->name, NULL); 4925 } else { 4926 def->content = 4927 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4928 } 4929 } else if (IS_RELAXNG(node, "ref")) { 4930 def = xmlRelaxNGNewDefine(ctxt, node); 4931 if (def == NULL) 4932 return (NULL); 4933 def->type = XML_RELAXNG_REF; 4934 def->name = xmlGetProp(node, BAD_CAST "name"); 4935 if (def->name == NULL) { 4936 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n", 4937 NULL, NULL); 4938 } else { 4939 xmlRelaxNGNormExtSpace(def->name); 4940 if (xmlValidateNCName(def->name, 0)) { 4941 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID, 4942 "ref name '%s' is not an NCName\n", def->name, 4943 NULL); 4944 } 4945 } 4946 if (node->children != NULL) { 4947 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n", 4948 NULL, NULL); 4949 } 4950 if (ctxt->grammar->refs == NULL) 4951 ctxt->grammar->refs = xmlHashCreate(10); 4952 if (ctxt->grammar->refs == NULL) { 4953 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4954 "Could not create references hash\n", NULL, NULL); 4955 def = NULL; 4956 } else { 4957 int tmp; 4958 4959 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); 4960 if (tmp < 0) { 4961 xmlRelaxNGDefinePtr prev; 4962 4963 prev = (xmlRelaxNGDefinePtr) 4964 xmlHashLookup(ctxt->grammar->refs, def->name); 4965 if (prev == NULL) { 4966 if (def->name != NULL) { 4967 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4968 "Error refs definitions '%s'\n", 4969 def->name, NULL); 4970 } else { 4971 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4972 "Error refs definitions\n", 4973 NULL, NULL); 4974 } 4975 def = NULL; 4976 } else { 4977 def->nextHash = prev->nextHash; 4978 prev->nextHash = def; 4979 } 4980 } 4981 } 4982 } else if (IS_RELAXNG(node, "data")) { 4983 def = xmlRelaxNGParseData(ctxt, node); 4984 } else if (IS_RELAXNG(node, "value")) { 4985 def = xmlRelaxNGParseValue(ctxt, node); 4986 } else if (IS_RELAXNG(node, "list")) { 4987 def = xmlRelaxNGNewDefine(ctxt, node); 4988 if (def == NULL) 4989 return (NULL); 4990 def->type = XML_RELAXNG_LIST; 4991 if (node->children == NULL) { 4992 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4993 "Element %s is empty\n", node->name, NULL); 4994 } else { 4995 def->content = 4996 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4997 } 4998 } else if (IS_RELAXNG(node, "interleave")) { 4999 def = xmlRelaxNGParseInterleave(ctxt, node); 5000 } else if (IS_RELAXNG(node, "externalRef")) { 5001 def = xmlRelaxNGProcessExternalRef(ctxt, node); 5002 } else if (IS_RELAXNG(node, "notAllowed")) { 5003 def = xmlRelaxNGNewDefine(ctxt, node); 5004 if (def == NULL) 5005 return (NULL); 5006 def->type = XML_RELAXNG_NOT_ALLOWED; 5007 if (node->children != NULL) { 5008 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY, 5009 "xmlRelaxNGParse: notAllowed element is not empty\n", 5010 NULL, NULL); 5011 } 5012 } else if (IS_RELAXNG(node, "grammar")) { 5013 xmlRelaxNGGrammarPtr grammar, old; 5014 xmlRelaxNGGrammarPtr oldparent; 5015 5016 #ifdef DEBUG_GRAMMAR 5017 xmlGenericError(xmlGenericErrorContext, 5018 "Found <grammar> pattern\n"); 5019 #endif 5020 5021 oldparent = ctxt->parentgrammar; 5022 old = ctxt->grammar; 5023 ctxt->parentgrammar = old; 5024 grammar = xmlRelaxNGParseGrammar(ctxt, node->children); 5025 if (old != NULL) { 5026 ctxt->grammar = old; 5027 ctxt->parentgrammar = oldparent; 5028 #if 0 5029 if (grammar != NULL) { 5030 grammar->next = old->next; 5031 old->next = grammar; 5032 } 5033 #endif 5034 } 5035 if (grammar != NULL) 5036 def = grammar->start; 5037 else 5038 def = NULL; 5039 } else if (IS_RELAXNG(node, "parentRef")) { 5040 if (ctxt->parentgrammar == NULL) { 5041 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT, 5042 "Use of parentRef without a parent grammar\n", NULL, 5043 NULL); 5044 return (NULL); 5045 } 5046 def = xmlRelaxNGNewDefine(ctxt, node); 5047 if (def == NULL) 5048 return (NULL); 5049 def->type = XML_RELAXNG_PARENTREF; 5050 def->name = xmlGetProp(node, BAD_CAST "name"); 5051 if (def->name == NULL) { 5052 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME, 5053 "parentRef has no name\n", NULL, NULL); 5054 } else { 5055 xmlRelaxNGNormExtSpace(def->name); 5056 if (xmlValidateNCName(def->name, 0)) { 5057 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID, 5058 "parentRef name '%s' is not an NCName\n", 5059 def->name, NULL); 5060 } 5061 } 5062 if (node->children != NULL) { 5063 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY, 5064 "parentRef is not empty\n", NULL, NULL); 5065 } 5066 if (ctxt->parentgrammar->refs == NULL) 5067 ctxt->parentgrammar->refs = xmlHashCreate(10); 5068 if (ctxt->parentgrammar->refs == NULL) { 5069 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5070 "Could not create references hash\n", NULL, NULL); 5071 def = NULL; 5072 } else if (def->name != NULL) { 5073 int tmp; 5074 5075 tmp = 5076 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); 5077 if (tmp < 0) { 5078 xmlRelaxNGDefinePtr prev; 5079 5080 prev = (xmlRelaxNGDefinePtr) 5081 xmlHashLookup(ctxt->parentgrammar->refs, def->name); 5082 if (prev == NULL) { 5083 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5084 "Internal error parentRef definitions '%s'\n", 5085 def->name, NULL); 5086 def = NULL; 5087 } else { 5088 def->nextHash = prev->nextHash; 5089 prev->nextHash = def; 5090 } 5091 } 5092 } 5093 } else if (IS_RELAXNG(node, "mixed")) { 5094 if (node->children == NULL) { 5095 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n", 5096 NULL, NULL); 5097 def = NULL; 5098 } else { 5099 def = xmlRelaxNGParseInterleave(ctxt, node); 5100 if (def != NULL) { 5101 xmlRelaxNGDefinePtr tmp; 5102 5103 if ((def->content != NULL) && (def->content->next != NULL)) { 5104 tmp = xmlRelaxNGNewDefine(ctxt, node); 5105 if (tmp != NULL) { 5106 tmp->type = XML_RELAXNG_GROUP; 5107 tmp->content = def->content; 5108 def->content = tmp; 5109 } 5110 } 5111 5112 tmp = xmlRelaxNGNewDefine(ctxt, node); 5113 if (tmp == NULL) 5114 return (def); 5115 tmp->type = XML_RELAXNG_TEXT; 5116 tmp->next = def->content; 5117 def->content = tmp; 5118 } 5119 } 5120 } else { 5121 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT, 5122 "Unexpected node %s is not a pattern\n", node->name, 5123 NULL); 5124 def = NULL; 5125 } 5126 return (def); 5127 } 5128 5129 /** 5130 * xmlRelaxNGParseAttribute: 5131 * @ctxt: a Relax-NG parser context 5132 * @node: the element node 5133 * 5134 * parse the content of a RelaxNG attribute node. 5135 * 5136 * Returns the definition pointer or NULL in case of error. 5137 */ 5138 static xmlRelaxNGDefinePtr 5139 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5140 { 5141 xmlRelaxNGDefinePtr ret, cur; 5142 xmlNodePtr child; 5143 int old_flags; 5144 5145 ret = xmlRelaxNGNewDefine(ctxt, node); 5146 if (ret == NULL) 5147 return (NULL); 5148 ret->type = XML_RELAXNG_ATTRIBUTE; 5149 ret->parent = ctxt->def; 5150 child = node->children; 5151 if (child == NULL) { 5152 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY, 5153 "xmlRelaxNGParseattribute: attribute has no children\n", 5154 NULL, NULL); 5155 return (ret); 5156 } 5157 old_flags = ctxt->flags; 5158 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; 5159 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5160 if (cur != NULL) 5161 child = child->next; 5162 5163 if (child != NULL) { 5164 cur = xmlRelaxNGParsePattern(ctxt, child); 5165 if (cur != NULL) { 5166 switch (cur->type) { 5167 case XML_RELAXNG_EMPTY: 5168 case XML_RELAXNG_NOT_ALLOWED: 5169 case XML_RELAXNG_TEXT: 5170 case XML_RELAXNG_ELEMENT: 5171 case XML_RELAXNG_DATATYPE: 5172 case XML_RELAXNG_VALUE: 5173 case XML_RELAXNG_LIST: 5174 case XML_RELAXNG_REF: 5175 case XML_RELAXNG_PARENTREF: 5176 case XML_RELAXNG_EXTERNALREF: 5177 case XML_RELAXNG_DEF: 5178 case XML_RELAXNG_ONEORMORE: 5179 case XML_RELAXNG_ZEROORMORE: 5180 case XML_RELAXNG_OPTIONAL: 5181 case XML_RELAXNG_CHOICE: 5182 case XML_RELAXNG_GROUP: 5183 case XML_RELAXNG_INTERLEAVE: 5184 case XML_RELAXNG_ATTRIBUTE: 5185 ret->content = cur; 5186 cur->parent = ret; 5187 break; 5188 case XML_RELAXNG_START: 5189 case XML_RELAXNG_PARAM: 5190 case XML_RELAXNG_EXCEPT: 5191 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT, 5192 "attribute has invalid content\n", NULL, 5193 NULL); 5194 break; 5195 case XML_RELAXNG_NOOP: 5196 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP, 5197 "RNG Internal error, noop found in attribute\n", 5198 NULL, NULL); 5199 break; 5200 } 5201 } 5202 child = child->next; 5203 } 5204 if (child != NULL) { 5205 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN, 5206 "attribute has multiple children\n", NULL, NULL); 5207 } 5208 ctxt->flags = old_flags; 5209 return (ret); 5210 } 5211 5212 /** 5213 * xmlRelaxNGParseExceptNameClass: 5214 * @ctxt: a Relax-NG parser context 5215 * @node: the except node 5216 * @attr: 1 if within an attribute, 0 if within an element 5217 * 5218 * parse the content of a RelaxNG nameClass node. 5219 * 5220 * Returns the definition pointer or NULL in case of error. 5221 */ 5222 static xmlRelaxNGDefinePtr 5223 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, 5224 xmlNodePtr node, int attr) 5225 { 5226 xmlRelaxNGDefinePtr ret, cur, last = NULL; 5227 xmlNodePtr child; 5228 5229 if (!IS_RELAXNG(node, "except")) { 5230 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING, 5231 "Expecting an except node\n", NULL, NULL); 5232 return (NULL); 5233 } 5234 if (node->next != NULL) { 5235 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE, 5236 "exceptNameClass allows only a single except node\n", 5237 NULL, NULL); 5238 } 5239 if (node->children == NULL) { 5240 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n", 5241 NULL, NULL); 5242 return (NULL); 5243 } 5244 5245 ret = xmlRelaxNGNewDefine(ctxt, node); 5246 if (ret == NULL) 5247 return (NULL); 5248 ret->type = XML_RELAXNG_EXCEPT; 5249 child = node->children; 5250 while (child != NULL) { 5251 cur = xmlRelaxNGNewDefine(ctxt, child); 5252 if (cur == NULL) 5253 break; 5254 if (attr) 5255 cur->type = XML_RELAXNG_ATTRIBUTE; 5256 else 5257 cur->type = XML_RELAXNG_ELEMENT; 5258 5259 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) { 5260 if (last == NULL) { 5261 ret->content = cur; 5262 } else { 5263 last->next = cur; 5264 } 5265 last = cur; 5266 } 5267 child = child->next; 5268 } 5269 5270 return (ret); 5271 } 5272 5273 /** 5274 * xmlRelaxNGParseNameClass: 5275 * @ctxt: a Relax-NG parser context 5276 * @node: the nameClass node 5277 * @def: the current definition 5278 * 5279 * parse the content of a RelaxNG nameClass node. 5280 * 5281 * Returns the definition pointer or NULL in case of error. 5282 */ 5283 static xmlRelaxNGDefinePtr 5284 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, 5285 xmlRelaxNGDefinePtr def) 5286 { 5287 xmlRelaxNGDefinePtr ret, tmp; 5288 xmlChar *val; 5289 5290 ret = def; 5291 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) || 5292 (IS_RELAXNG(node, "nsName"))) { 5293 if ((def->type != XML_RELAXNG_ELEMENT) && 5294 (def->type != XML_RELAXNG_ATTRIBUTE)) { 5295 ret = xmlRelaxNGNewDefine(ctxt, node); 5296 if (ret == NULL) 5297 return (NULL); 5298 ret->parent = def; 5299 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) 5300 ret->type = XML_RELAXNG_ATTRIBUTE; 5301 else 5302 ret->type = XML_RELAXNG_ELEMENT; 5303 } 5304 } 5305 if (IS_RELAXNG(node, "name")) { 5306 val = xmlNodeGetContent(node); 5307 xmlRelaxNGNormExtSpace(val); 5308 if (xmlValidateNCName(val, 0)) { 5309 if (node->parent != NULL) 5310 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5311 "Element %s name '%s' is not an NCName\n", 5312 node->parent->name, val); 5313 else 5314 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5315 "name '%s' is not an NCName\n", 5316 val, NULL); 5317 } 5318 ret->name = val; 5319 val = xmlGetProp(node, BAD_CAST "ns"); 5320 ret->ns = val; 5321 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5322 (val != NULL) && 5323 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5324 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5325 "Attribute with namespace '%s' is not allowed\n", 5326 val, NULL); 5327 } 5328 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5329 (val != NULL) && 5330 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) { 5331 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME, 5332 "Attribute with QName 'xmlns' is not allowed\n", 5333 val, NULL); 5334 } 5335 } else if (IS_RELAXNG(node, "anyName")) { 5336 ret->name = NULL; 5337 ret->ns = NULL; 5338 if (node->children != NULL) { 5339 ret->nameClass = 5340 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5341 (def->type == 5342 XML_RELAXNG_ATTRIBUTE)); 5343 } 5344 } else if (IS_RELAXNG(node, "nsName")) { 5345 ret->name = NULL; 5346 ret->ns = xmlGetProp(node, BAD_CAST "ns"); 5347 if (ret->ns == NULL) { 5348 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS, 5349 "nsName has no ns attribute\n", NULL, NULL); 5350 } 5351 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5352 (ret->ns != NULL) && 5353 (xmlStrEqual 5354 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5355 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5356 "Attribute with namespace '%s' is not allowed\n", 5357 ret->ns, NULL); 5358 } 5359 if (node->children != NULL) { 5360 ret->nameClass = 5361 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5362 (def->type == 5363 XML_RELAXNG_ATTRIBUTE)); 5364 } 5365 } else if (IS_RELAXNG(node, "choice")) { 5366 xmlNodePtr child; 5367 xmlRelaxNGDefinePtr last = NULL; 5368 5369 if (def->type == XML_RELAXNG_CHOICE) { 5370 ret = def; 5371 } else { 5372 ret = xmlRelaxNGNewDefine(ctxt, node); 5373 if (ret == NULL) 5374 return (NULL); 5375 ret->parent = def; 5376 ret->type = XML_RELAXNG_CHOICE; 5377 } 5378 5379 if (node->children == NULL) { 5380 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY, 5381 "Element choice is empty\n", NULL, NULL); 5382 } else { 5383 5384 child = node->children; 5385 while (child != NULL) { 5386 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret); 5387 if (tmp != NULL) { 5388 if (last == NULL) { 5389 last = tmp; 5390 } else { 5391 last->next = tmp; 5392 last = tmp; 5393 } 5394 } 5395 child = child->next; 5396 } 5397 } 5398 } else { 5399 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT, 5400 "expecting name, anyName, nsName or choice : got %s\n", 5401 (node == NULL ? (const xmlChar *) "nothing" : node->name), 5402 NULL); 5403 return (NULL); 5404 } 5405 if (ret != def) { 5406 if (def->nameClass == NULL) { 5407 def->nameClass = ret; 5408 } else { 5409 tmp = def->nameClass; 5410 while (tmp->next != NULL) { 5411 tmp = tmp->next; 5412 } 5413 tmp->next = ret; 5414 } 5415 } 5416 return (ret); 5417 } 5418 5419 /** 5420 * xmlRelaxNGParseElement: 5421 * @ctxt: a Relax-NG parser context 5422 * @node: the element node 5423 * 5424 * parse the content of a RelaxNG element node. 5425 * 5426 * Returns the definition pointer or NULL in case of error. 5427 */ 5428 static xmlRelaxNGDefinePtr 5429 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5430 { 5431 xmlRelaxNGDefinePtr ret, cur, last; 5432 xmlNodePtr child; 5433 const xmlChar *olddefine; 5434 5435 ret = xmlRelaxNGNewDefine(ctxt, node); 5436 if (ret == NULL) 5437 return (NULL); 5438 ret->type = XML_RELAXNG_ELEMENT; 5439 ret->parent = ctxt->def; 5440 child = node->children; 5441 if (child == NULL) { 5442 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY, 5443 "xmlRelaxNGParseElement: element has no children\n", 5444 NULL, NULL); 5445 return (ret); 5446 } 5447 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5448 if (cur != NULL) 5449 child = child->next; 5450 5451 if (child == NULL) { 5452 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT, 5453 "xmlRelaxNGParseElement: element has no content\n", 5454 NULL, NULL); 5455 return (ret); 5456 } 5457 olddefine = ctxt->define; 5458 ctxt->define = NULL; 5459 last = NULL; 5460 while (child != NULL) { 5461 cur = xmlRelaxNGParsePattern(ctxt, child); 5462 if (cur != NULL) { 5463 cur->parent = ret; 5464 switch (cur->type) { 5465 case XML_RELAXNG_EMPTY: 5466 case XML_RELAXNG_NOT_ALLOWED: 5467 case XML_RELAXNG_TEXT: 5468 case XML_RELAXNG_ELEMENT: 5469 case XML_RELAXNG_DATATYPE: 5470 case XML_RELAXNG_VALUE: 5471 case XML_RELAXNG_LIST: 5472 case XML_RELAXNG_REF: 5473 case XML_RELAXNG_PARENTREF: 5474 case XML_RELAXNG_EXTERNALREF: 5475 case XML_RELAXNG_DEF: 5476 case XML_RELAXNG_ZEROORMORE: 5477 case XML_RELAXNG_ONEORMORE: 5478 case XML_RELAXNG_OPTIONAL: 5479 case XML_RELAXNG_CHOICE: 5480 case XML_RELAXNG_GROUP: 5481 case XML_RELAXNG_INTERLEAVE: 5482 if (last == NULL) { 5483 ret->content = last = cur; 5484 } else { 5485 if ((last->type == XML_RELAXNG_ELEMENT) && 5486 (ret->content == last)) { 5487 ret->content = xmlRelaxNGNewDefine(ctxt, node); 5488 if (ret->content != NULL) { 5489 ret->content->type = XML_RELAXNG_GROUP; 5490 ret->content->content = last; 5491 } else { 5492 ret->content = last; 5493 } 5494 } 5495 last->next = cur; 5496 last = cur; 5497 } 5498 break; 5499 case XML_RELAXNG_ATTRIBUTE: 5500 cur->next = ret->attrs; 5501 ret->attrs = cur; 5502 break; 5503 case XML_RELAXNG_START: 5504 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5505 "RNG Internal error, start found in element\n", 5506 NULL, NULL); 5507 break; 5508 case XML_RELAXNG_PARAM: 5509 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5510 "RNG Internal error, param found in element\n", 5511 NULL, NULL); 5512 break; 5513 case XML_RELAXNG_EXCEPT: 5514 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5515 "RNG Internal error, except found in element\n", 5516 NULL, NULL); 5517 break; 5518 case XML_RELAXNG_NOOP: 5519 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5520 "RNG Internal error, noop found in element\n", 5521 NULL, NULL); 5522 break; 5523 } 5524 } 5525 child = child->next; 5526 } 5527 ctxt->define = olddefine; 5528 return (ret); 5529 } 5530 5531 /** 5532 * xmlRelaxNGParsePatterns: 5533 * @ctxt: a Relax-NG parser context 5534 * @nodes: list of nodes 5535 * @group: use an implicit <group> for elements 5536 * 5537 * parse the content of a RelaxNG start node. 5538 * 5539 * Returns the definition pointer or NULL in case of error. 5540 */ 5541 static xmlRelaxNGDefinePtr 5542 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, 5543 int group) 5544 { 5545 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent; 5546 5547 parent = ctxt->def; 5548 while (nodes != NULL) { 5549 if (IS_RELAXNG(nodes, "element")) { 5550 cur = xmlRelaxNGParseElement(ctxt, nodes); 5551 if (cur == NULL) 5552 return (NULL); 5553 if (def == NULL) { 5554 def = last = cur; 5555 } else { 5556 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) && 5557 (def == last)) { 5558 def = xmlRelaxNGNewDefine(ctxt, nodes); 5559 if (def == NULL) 5560 return (NULL); 5561 def->type = XML_RELAXNG_GROUP; 5562 def->content = last; 5563 } 5564 last->next = cur; 5565 last = cur; 5566 } 5567 cur->parent = parent; 5568 } else { 5569 cur = xmlRelaxNGParsePattern(ctxt, nodes); 5570 if (cur != NULL) { 5571 if (def == NULL) { 5572 def = last = cur; 5573 } else { 5574 last->next = cur; 5575 last = cur; 5576 } 5577 } 5578 } 5579 nodes = nodes->next; 5580 } 5581 return (def); 5582 } 5583 5584 /** 5585 * xmlRelaxNGParseStart: 5586 * @ctxt: a Relax-NG parser context 5587 * @nodes: start children nodes 5588 * 5589 * parse the content of a RelaxNG start node. 5590 * 5591 * Returns 0 in case of success, -1 in case of error 5592 */ 5593 static int 5594 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 5595 { 5596 int ret = 0; 5597 xmlRelaxNGDefinePtr def = NULL, last; 5598 5599 if (nodes == NULL) { 5600 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n", 5601 NULL, NULL); 5602 return (-1); 5603 } 5604 if (IS_RELAXNG(nodes, "empty")) { 5605 def = xmlRelaxNGNewDefine(ctxt, nodes); 5606 if (def == NULL) 5607 return (-1); 5608 def->type = XML_RELAXNG_EMPTY; 5609 if (nodes->children != NULL) { 5610 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT, 5611 "element empty is not empty\n", NULL, NULL); 5612 } 5613 } else if (IS_RELAXNG(nodes, "notAllowed")) { 5614 def = xmlRelaxNGNewDefine(ctxt, nodes); 5615 if (def == NULL) 5616 return (-1); 5617 def->type = XML_RELAXNG_NOT_ALLOWED; 5618 if (nodes->children != NULL) { 5619 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY, 5620 "element notAllowed is not empty\n", NULL, NULL); 5621 } 5622 } else { 5623 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1); 5624 } 5625 if (ctxt->grammar->start != NULL) { 5626 last = ctxt->grammar->start; 5627 while (last->next != NULL) 5628 last = last->next; 5629 last->next = def; 5630 } else { 5631 ctxt->grammar->start = def; 5632 } 5633 nodes = nodes->next; 5634 if (nodes != NULL) { 5635 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT, 5636 "start more than one children\n", NULL, NULL); 5637 return (-1); 5638 } 5639 return (ret); 5640 } 5641 5642 /** 5643 * xmlRelaxNGParseGrammarContent: 5644 * @ctxt: a Relax-NG parser context 5645 * @nodes: grammar children nodes 5646 * 5647 * parse the content of a RelaxNG grammar node. 5648 * 5649 * Returns 0 in case of success, -1 in case of error 5650 */ 5651 static int 5652 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 5653 xmlNodePtr nodes) 5654 { 5655 int ret = 0, tmp; 5656 5657 if (nodes == NULL) { 5658 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY, 5659 "grammar has no children\n", NULL, NULL); 5660 return (-1); 5661 } 5662 while (nodes != NULL) { 5663 if (IS_RELAXNG(nodes, "start")) { 5664 if (nodes->children == NULL) { 5665 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, 5666 "start has no children\n", NULL, NULL); 5667 } else { 5668 tmp = xmlRelaxNGParseStart(ctxt, nodes->children); 5669 if (tmp != 0) 5670 ret = -1; 5671 } 5672 } else if (IS_RELAXNG(nodes, "define")) { 5673 tmp = xmlRelaxNGParseDefine(ctxt, nodes); 5674 if (tmp != 0) 5675 ret = -1; 5676 } else if (IS_RELAXNG(nodes, "include")) { 5677 tmp = xmlRelaxNGParseInclude(ctxt, nodes); 5678 if (tmp != 0) 5679 ret = -1; 5680 } else { 5681 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 5682 "grammar has unexpected child %s\n", nodes->name, 5683 NULL); 5684 ret = -1; 5685 } 5686 nodes = nodes->next; 5687 } 5688 return (ret); 5689 } 5690 5691 /** 5692 * xmlRelaxNGCheckReference: 5693 * @ref: the ref 5694 * @ctxt: a Relax-NG parser context 5695 * @name: the name associated to the defines 5696 * 5697 * Applies the 4.17. combine attribute rule for all the define 5698 * element of a given grammar using the same name. 5699 */ 5700 static void 5701 xmlRelaxNGCheckReference(void *payload, void *data, const xmlChar * name) 5702 { 5703 xmlRelaxNGDefinePtr ref = (xmlRelaxNGDefinePtr) payload; 5704 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 5705 xmlRelaxNGGrammarPtr grammar; 5706 xmlRelaxNGDefinePtr def, cur; 5707 5708 /* 5709 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef 5710 */ 5711 if (ref->dflags & IS_EXTERNAL_REF) 5712 return; 5713 5714 grammar = ctxt->grammar; 5715 if (grammar == NULL) { 5716 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5717 "Internal error: no grammar in CheckReference %s\n", 5718 name, NULL); 5719 return; 5720 } 5721 if (ref->content != NULL) { 5722 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5723 "Internal error: reference has content in CheckReference %s\n", 5724 name, NULL); 5725 return; 5726 } 5727 if (grammar->defs != NULL) { 5728 def = xmlHashLookup(grammar->defs, name); 5729 if (def != NULL) { 5730 cur = ref; 5731 while (cur != NULL) { 5732 cur->content = def; 5733 cur = cur->nextHash; 5734 } 5735 } else { 5736 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5737 "Reference %s has no matching definition\n", name, 5738 NULL); 5739 } 5740 } else { 5741 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5742 "Reference %s has no matching definition\n", name, 5743 NULL); 5744 } 5745 } 5746 5747 /** 5748 * xmlRelaxNGCheckCombine: 5749 * @define: the define(s) list 5750 * @ctxt: a Relax-NG parser context 5751 * @name: the name associated to the defines 5752 * 5753 * Applies the 4.17. combine attribute rule for all the define 5754 * element of a given grammar using the same name. 5755 */ 5756 static void 5757 xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name) 5758 { 5759 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) payload; 5760 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 5761 xmlChar *combine; 5762 int choiceOrInterleave = -1; 5763 int missing = 0; 5764 xmlRelaxNGDefinePtr cur, last, tmp, tmp2; 5765 5766 if (define->nextHash == NULL) 5767 return; 5768 cur = define; 5769 while (cur != NULL) { 5770 combine = xmlGetProp(cur->node, BAD_CAST "combine"); 5771 if (combine != NULL) { 5772 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5773 if (choiceOrInterleave == -1) 5774 choiceOrInterleave = 1; 5775 else if (choiceOrInterleave == 0) { 5776 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5777 "Defines for %s use both 'choice' and 'interleave'\n", 5778 name, NULL); 5779 } 5780 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5781 if (choiceOrInterleave == -1) 5782 choiceOrInterleave = 0; 5783 else if (choiceOrInterleave == 1) { 5784 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5785 "Defines for %s use both 'choice' and 'interleave'\n", 5786 name, NULL); 5787 } 5788 } else { 5789 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE, 5790 "Defines for %s use unknown combine value '%s''\n", 5791 name, combine); 5792 } 5793 xmlFree(combine); 5794 } else { 5795 if (missing == 0) 5796 missing = 1; 5797 else { 5798 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE, 5799 "Some defines for %s needs the combine attribute\n", 5800 name, NULL); 5801 } 5802 } 5803 5804 cur = cur->nextHash; 5805 } 5806 #ifdef DEBUG 5807 xmlGenericError(xmlGenericErrorContext, 5808 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", 5809 name, choiceOrInterleave); 5810 #endif 5811 if (choiceOrInterleave == -1) 5812 choiceOrInterleave = 0; 5813 cur = xmlRelaxNGNewDefine(ctxt, define->node); 5814 if (cur == NULL) 5815 return; 5816 if (choiceOrInterleave == 0) 5817 cur->type = XML_RELAXNG_INTERLEAVE; 5818 else 5819 cur->type = XML_RELAXNG_CHOICE; 5820 tmp = define; 5821 last = NULL; 5822 while (tmp != NULL) { 5823 if (tmp->content != NULL) { 5824 if (tmp->content->next != NULL) { 5825 /* 5826 * we need first to create a wrapper. 5827 */ 5828 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node); 5829 if (tmp2 == NULL) 5830 break; 5831 tmp2->type = XML_RELAXNG_GROUP; 5832 tmp2->content = tmp->content; 5833 } else { 5834 tmp2 = tmp->content; 5835 } 5836 if (last == NULL) { 5837 cur->content = tmp2; 5838 } else { 5839 last->next = tmp2; 5840 } 5841 last = tmp2; 5842 } 5843 tmp->content = cur; 5844 tmp = tmp->nextHash; 5845 } 5846 define->content = cur; 5847 if (choiceOrInterleave == 0) { 5848 if (ctxt->interleaves == NULL) 5849 ctxt->interleaves = xmlHashCreate(10); 5850 if (ctxt->interleaves == NULL) { 5851 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5852 "Failed to create interleaves hash table\n", NULL, 5853 NULL); 5854 } else { 5855 char tmpname[32]; 5856 5857 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5858 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5859 0) { 5860 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5861 "Failed to add %s to hash table\n", 5862 (const xmlChar *) tmpname, NULL); 5863 } 5864 } 5865 } 5866 } 5867 5868 /** 5869 * xmlRelaxNGCombineStart: 5870 * @ctxt: a Relax-NG parser context 5871 * @grammar: the grammar 5872 * 5873 * Applies the 4.17. combine rule for all the start 5874 * element of a given grammar. 5875 */ 5876 static void 5877 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, 5878 xmlRelaxNGGrammarPtr grammar) 5879 { 5880 xmlRelaxNGDefinePtr starts; 5881 xmlChar *combine; 5882 int choiceOrInterleave = -1; 5883 int missing = 0; 5884 xmlRelaxNGDefinePtr cur; 5885 5886 starts = grammar->start; 5887 if ((starts == NULL) || (starts->next == NULL)) 5888 return; 5889 cur = starts; 5890 while (cur != NULL) { 5891 if ((cur->node == NULL) || (cur->node->parent == NULL) || 5892 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) { 5893 combine = NULL; 5894 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING, 5895 "Internal error: start element not found\n", NULL, 5896 NULL); 5897 } else { 5898 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine"); 5899 } 5900 5901 if (combine != NULL) { 5902 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5903 if (choiceOrInterleave == -1) 5904 choiceOrInterleave = 1; 5905 else if (choiceOrInterleave == 0) { 5906 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5907 "<start> use both 'choice' and 'interleave'\n", 5908 NULL, NULL); 5909 } 5910 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5911 if (choiceOrInterleave == -1) 5912 choiceOrInterleave = 0; 5913 else if (choiceOrInterleave == 1) { 5914 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5915 "<start> use both 'choice' and 'interleave'\n", 5916 NULL, NULL); 5917 } 5918 } else { 5919 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE, 5920 "<start> uses unknown combine value '%s''\n", 5921 combine, NULL); 5922 } 5923 xmlFree(combine); 5924 } else { 5925 if (missing == 0) 5926 missing = 1; 5927 else { 5928 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE, 5929 "Some <start> element miss the combine attribute\n", 5930 NULL, NULL); 5931 } 5932 } 5933 5934 cur = cur->next; 5935 } 5936 #ifdef DEBUG 5937 xmlGenericError(xmlGenericErrorContext, 5938 "xmlRelaxNGCombineStart(): merging <start>: %d\n", 5939 choiceOrInterleave); 5940 #endif 5941 if (choiceOrInterleave == -1) 5942 choiceOrInterleave = 0; 5943 cur = xmlRelaxNGNewDefine(ctxt, starts->node); 5944 if (cur == NULL) 5945 return; 5946 if (choiceOrInterleave == 0) 5947 cur->type = XML_RELAXNG_INTERLEAVE; 5948 else 5949 cur->type = XML_RELAXNG_CHOICE; 5950 cur->content = grammar->start; 5951 grammar->start = cur; 5952 if (choiceOrInterleave == 0) { 5953 if (ctxt->interleaves == NULL) 5954 ctxt->interleaves = xmlHashCreate(10); 5955 if (ctxt->interleaves == NULL) { 5956 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5957 "Failed to create interleaves hash table\n", NULL, 5958 NULL); 5959 } else { 5960 char tmpname[32]; 5961 5962 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5963 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5964 0) { 5965 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5966 "Failed to add %s to hash table\n", 5967 (const xmlChar *) tmpname, NULL); 5968 } 5969 } 5970 } 5971 } 5972 5973 /** 5974 * xmlRelaxNGCheckCycles: 5975 * @ctxt: a Relax-NG parser context 5976 * @nodes: grammar children nodes 5977 * @depth: the counter 5978 * 5979 * Check for cycles. 5980 * 5981 * Returns 0 if check passed, and -1 in case of error 5982 */ 5983 static int 5984 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 5985 xmlRelaxNGDefinePtr cur, int depth) 5986 { 5987 int ret = 0; 5988 5989 while ((ret == 0) && (cur != NULL)) { 5990 if ((cur->type == XML_RELAXNG_REF) || 5991 (cur->type == XML_RELAXNG_PARENTREF)) { 5992 if (cur->depth == -1) { 5993 cur->depth = depth; 5994 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 5995 cur->depth = -2; 5996 } else if (depth == cur->depth) { 5997 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE, 5998 "Detected a cycle in %s references\n", 5999 cur->name, NULL); 6000 return (-1); 6001 } 6002 } else if (cur->type == XML_RELAXNG_ELEMENT) { 6003 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1); 6004 } else { 6005 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 6006 } 6007 cur = cur->next; 6008 } 6009 return (ret); 6010 } 6011 6012 /** 6013 * xmlRelaxNGTryUnlink: 6014 * @ctxt: a Relax-NG parser context 6015 * @cur: the definition to unlink 6016 * @parent: the parent definition 6017 * @prev: the previous sibling definition 6018 * 6019 * Try to unlink a definition. If not possible make it a NOOP 6020 * 6021 * Returns the new prev definition 6022 */ 6023 static xmlRelaxNGDefinePtr 6024 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 6025 xmlRelaxNGDefinePtr cur, 6026 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev) 6027 { 6028 if (prev != NULL) { 6029 prev->next = cur->next; 6030 } else { 6031 if (parent != NULL) { 6032 if (parent->content == cur) 6033 parent->content = cur->next; 6034 else if (parent->attrs == cur) 6035 parent->attrs = cur->next; 6036 else if (parent->nameClass == cur) 6037 parent->nameClass = cur->next; 6038 } else { 6039 cur->type = XML_RELAXNG_NOOP; 6040 prev = cur; 6041 } 6042 } 6043 return (prev); 6044 } 6045 6046 /** 6047 * xmlRelaxNGSimplify: 6048 * @ctxt: a Relax-NG parser context 6049 * @nodes: grammar children nodes 6050 * 6051 * Check for simplification of empty and notAllowed 6052 */ 6053 static void 6054 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, 6055 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent) 6056 { 6057 xmlRelaxNGDefinePtr prev = NULL; 6058 6059 while (cur != NULL) { 6060 if ((cur->type == XML_RELAXNG_REF) || 6061 (cur->type == XML_RELAXNG_PARENTREF)) { 6062 if (cur->depth != -3) { 6063 cur->depth = -3; 6064 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6065 } 6066 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6067 cur->parent = parent; 6068 if ((parent != NULL) && 6069 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6070 (parent->type == XML_RELAXNG_LIST) || 6071 (parent->type == XML_RELAXNG_GROUP) || 6072 (parent->type == XML_RELAXNG_INTERLEAVE) || 6073 (parent->type == XML_RELAXNG_ONEORMORE) || 6074 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6075 parent->type = XML_RELAXNG_NOT_ALLOWED; 6076 break; 6077 } 6078 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) { 6079 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6080 } else 6081 prev = cur; 6082 } else if (cur->type == XML_RELAXNG_EMPTY) { 6083 cur->parent = parent; 6084 if ((parent != NULL) && 6085 ((parent->type == XML_RELAXNG_ONEORMORE) || 6086 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6087 parent->type = XML_RELAXNG_EMPTY; 6088 break; 6089 } 6090 if ((parent != NULL) && 6091 ((parent->type == XML_RELAXNG_GROUP) || 6092 (parent->type == XML_RELAXNG_INTERLEAVE))) { 6093 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6094 } else 6095 prev = cur; 6096 } else { 6097 cur->parent = parent; 6098 if (cur->content != NULL) 6099 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6100 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL)) 6101 xmlRelaxNGSimplify(ctxt, cur->attrs, cur); 6102 if (cur->nameClass != NULL) 6103 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur); 6104 /* 6105 * On Elements, try to move attribute only generating rules on 6106 * the attrs rules. 6107 */ 6108 if (cur->type == XML_RELAXNG_ELEMENT) { 6109 int attronly; 6110 xmlRelaxNGDefinePtr tmp, pre; 6111 6112 while (cur->content != NULL) { 6113 attronly = 6114 xmlRelaxNGGenerateAttributes(ctxt, cur->content); 6115 if (attronly == 1) { 6116 /* 6117 * migrate cur->content to attrs 6118 */ 6119 tmp = cur->content; 6120 cur->content = tmp->next; 6121 tmp->next = cur->attrs; 6122 cur->attrs = tmp; 6123 } else { 6124 /* 6125 * cur->content can generate elements or text 6126 */ 6127 break; 6128 } 6129 } 6130 pre = cur->content; 6131 while ((pre != NULL) && (pre->next != NULL)) { 6132 tmp = pre->next; 6133 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp); 6134 if (attronly == 1) { 6135 /* 6136 * migrate tmp to attrs 6137 */ 6138 pre->next = tmp->next; 6139 tmp->next = cur->attrs; 6140 cur->attrs = tmp; 6141 } else { 6142 pre = tmp; 6143 } 6144 } 6145 } 6146 /* 6147 * This may result in a simplification 6148 */ 6149 if ((cur->type == XML_RELAXNG_GROUP) || 6150 (cur->type == XML_RELAXNG_INTERLEAVE)) { 6151 if (cur->content == NULL) 6152 cur->type = XML_RELAXNG_EMPTY; 6153 else if (cur->content->next == NULL) { 6154 if ((parent == NULL) && (prev == NULL)) { 6155 cur->type = XML_RELAXNG_NOOP; 6156 } else if (prev == NULL) { 6157 parent->content = cur->content; 6158 cur->content->next = cur->next; 6159 cur = cur->content; 6160 } else { 6161 cur->content->next = cur->next; 6162 prev->next = cur->content; 6163 cur = cur->content; 6164 } 6165 } 6166 } 6167 /* 6168 * the current node may have been transformed back 6169 */ 6170 if ((cur->type == XML_RELAXNG_EXCEPT) && 6171 (cur->content != NULL) && 6172 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) { 6173 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6174 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6175 if ((parent != NULL) && 6176 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6177 (parent->type == XML_RELAXNG_LIST) || 6178 (parent->type == XML_RELAXNG_GROUP) || 6179 (parent->type == XML_RELAXNG_INTERLEAVE) || 6180 (parent->type == XML_RELAXNG_ONEORMORE) || 6181 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6182 parent->type = XML_RELAXNG_NOT_ALLOWED; 6183 break; 6184 } 6185 if ((parent != NULL) && 6186 (parent->type == XML_RELAXNG_CHOICE)) { 6187 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6188 } else 6189 prev = cur; 6190 } else if (cur->type == XML_RELAXNG_EMPTY) { 6191 if ((parent != NULL) && 6192 ((parent->type == XML_RELAXNG_ONEORMORE) || 6193 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6194 parent->type = XML_RELAXNG_EMPTY; 6195 break; 6196 } 6197 if ((parent != NULL) && 6198 ((parent->type == XML_RELAXNG_GROUP) || 6199 (parent->type == XML_RELAXNG_INTERLEAVE) || 6200 (parent->type == XML_RELAXNG_CHOICE))) { 6201 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6202 } else 6203 prev = cur; 6204 } else { 6205 prev = cur; 6206 } 6207 } 6208 cur = cur->next; 6209 } 6210 } 6211 6212 /** 6213 * xmlRelaxNGGroupContentType: 6214 * @ct1: the first content type 6215 * @ct2: the second content type 6216 * 6217 * Try to group 2 content types 6218 * 6219 * Returns the content type 6220 */ 6221 static xmlRelaxNGContentType 6222 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1, 6223 xmlRelaxNGContentType ct2) 6224 { 6225 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6226 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6227 return (XML_RELAXNG_CONTENT_ERROR); 6228 if (ct1 == XML_RELAXNG_CONTENT_EMPTY) 6229 return (ct2); 6230 if (ct2 == XML_RELAXNG_CONTENT_EMPTY) 6231 return (ct1); 6232 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) && 6233 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6234 return (XML_RELAXNG_CONTENT_COMPLEX); 6235 return (XML_RELAXNG_CONTENT_ERROR); 6236 } 6237 6238 /** 6239 * xmlRelaxNGMaxContentType: 6240 * @ct1: the first content type 6241 * @ct2: the second content type 6242 * 6243 * Compute the max content-type 6244 * 6245 * Returns the content type 6246 */ 6247 static xmlRelaxNGContentType 6248 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1, 6249 xmlRelaxNGContentType ct2) 6250 { 6251 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6252 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6253 return (XML_RELAXNG_CONTENT_ERROR); 6254 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) || 6255 (ct2 == XML_RELAXNG_CONTENT_SIMPLE)) 6256 return (XML_RELAXNG_CONTENT_SIMPLE); 6257 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) || 6258 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6259 return (XML_RELAXNG_CONTENT_COMPLEX); 6260 return (XML_RELAXNG_CONTENT_EMPTY); 6261 } 6262 6263 /** 6264 * xmlRelaxNGCheckRules: 6265 * @ctxt: a Relax-NG parser context 6266 * @cur: the current definition 6267 * @flags: some accumulated flags 6268 * @ptype: the parent type 6269 * 6270 * Check for rules in section 7.1 and 7.2 6271 * 6272 * Returns the content type of @cur 6273 */ 6274 static xmlRelaxNGContentType 6275 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, 6276 xmlRelaxNGDefinePtr cur, int flags, 6277 xmlRelaxNGType ptype) 6278 { 6279 int nflags; 6280 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY; 6281 6282 while (cur != NULL) { 6283 ret = XML_RELAXNG_CONTENT_EMPTY; 6284 if ((cur->type == XML_RELAXNG_REF) || 6285 (cur->type == XML_RELAXNG_PARENTREF)) { 6286 /* 6287 * This should actually be caught by list//element(ref) at the 6288 * element boundaries, c.f. Bug #159968 local refs are dropped 6289 * in step 4.19. 6290 */ 6291 #if 0 6292 if (flags & XML_RELAXNG_IN_LIST) { 6293 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF, 6294 "Found forbidden pattern list//ref\n", NULL, 6295 NULL); 6296 } 6297 #endif 6298 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6299 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF, 6300 "Found forbidden pattern data/except//ref\n", 6301 NULL, NULL); 6302 } 6303 if (cur->content == NULL) { 6304 if (cur->type == XML_RELAXNG_PARENTREF) 6305 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6306 "Internal found no define for parent refs\n", 6307 NULL, NULL); 6308 else 6309 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6310 "Internal found no define for ref %s\n", 6311 (cur->name ? cur->name: BAD_CAST "null"), NULL); 6312 } 6313 if (cur->depth > -4) { 6314 cur->depth = -4; 6315 ret = xmlRelaxNGCheckRules(ctxt, cur->content, 6316 flags, cur->type); 6317 cur->depth = ret - 15; 6318 } else if (cur->depth == -4) { 6319 ret = XML_RELAXNG_CONTENT_COMPLEX; 6320 } else { 6321 ret = (xmlRelaxNGContentType) (cur->depth + 15); 6322 } 6323 } else if (cur->type == XML_RELAXNG_ELEMENT) { 6324 /* 6325 * The 7.3 Attribute derivation rule for groups is plugged there 6326 */ 6327 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6328 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6329 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM, 6330 "Found forbidden pattern data/except//element(ref)\n", 6331 NULL, NULL); 6332 } 6333 if (flags & XML_RELAXNG_IN_LIST) { 6334 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM, 6335 "Found forbidden pattern list//element(ref)\n", 6336 NULL, NULL); 6337 } 6338 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6339 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6340 "Found forbidden pattern attribute//element(ref)\n", 6341 NULL, NULL); 6342 } 6343 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6344 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6345 "Found forbidden pattern attribute//element(ref)\n", 6346 NULL, NULL); 6347 } 6348 /* 6349 * reset since in the simple form elements are only child 6350 * of grammar/define 6351 */ 6352 nflags = 0; 6353 ret = 6354 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type); 6355 if (ret != XML_RELAXNG_CONTENT_EMPTY) { 6356 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY, 6357 "Element %s attributes have a content type error\n", 6358 cur->name, NULL); 6359 } 6360 ret = 6361 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6362 cur->type); 6363 if (ret == XML_RELAXNG_CONTENT_ERROR) { 6364 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR, 6365 "Element %s has a content type error\n", 6366 cur->name, NULL); 6367 } else { 6368 ret = XML_RELAXNG_CONTENT_COMPLEX; 6369 } 6370 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) { 6371 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6372 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR, 6373 "Found forbidden pattern attribute//attribute\n", 6374 NULL, NULL); 6375 } 6376 if (flags & XML_RELAXNG_IN_LIST) { 6377 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR, 6378 "Found forbidden pattern list//attribute\n", 6379 NULL, NULL); 6380 } 6381 if (flags & XML_RELAXNG_IN_OOMGROUP) { 6382 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR, 6383 "Found forbidden pattern oneOrMore//group//attribute\n", 6384 NULL, NULL); 6385 } 6386 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) { 6387 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, 6388 "Found forbidden pattern oneOrMore//interleave//attribute\n", 6389 NULL, NULL); 6390 } 6391 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6392 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR, 6393 "Found forbidden pattern data/except//attribute\n", 6394 NULL, NULL); 6395 } 6396 if (flags & XML_RELAXNG_IN_START) { 6397 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR, 6398 "Found forbidden pattern start//attribute\n", 6399 NULL, NULL); 6400 } 6401 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) 6402 && cur->name == NULL 6403 /* following is checking alternative name class readiness 6404 in case it went the "choice" route */ 6405 && cur->nameClass == NULL) { 6406 if (cur->ns == NULL) { 6407 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR, 6408 "Found anyName attribute without oneOrMore ancestor\n", 6409 NULL, NULL); 6410 } else { 6411 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR, 6412 "Found nsName attribute without oneOrMore ancestor\n", 6413 NULL, NULL); 6414 } 6415 } 6416 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE; 6417 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); 6418 ret = XML_RELAXNG_CONTENT_EMPTY; 6419 } else if ((cur->type == XML_RELAXNG_ONEORMORE) || 6420 (cur->type == XML_RELAXNG_ZEROORMORE)) { 6421 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6422 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, 6423 "Found forbidden pattern data/except//oneOrMore\n", 6424 NULL, NULL); 6425 } 6426 if (flags & XML_RELAXNG_IN_START) { 6427 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE, 6428 "Found forbidden pattern start//oneOrMore\n", 6429 NULL, NULL); 6430 } 6431 nflags = flags | XML_RELAXNG_IN_ONEORMORE; 6432 ret = 6433 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6434 cur->type); 6435 ret = xmlRelaxNGGroupContentType(ret, ret); 6436 } else if (cur->type == XML_RELAXNG_LIST) { 6437 if (flags & XML_RELAXNG_IN_LIST) { 6438 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST, 6439 "Found forbidden pattern list//list\n", NULL, 6440 NULL); 6441 } 6442 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6443 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST, 6444 "Found forbidden pattern data/except//list\n", 6445 NULL, NULL); 6446 } 6447 if (flags & XML_RELAXNG_IN_START) { 6448 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST, 6449 "Found forbidden pattern start//list\n", NULL, 6450 NULL); 6451 } 6452 nflags = flags | XML_RELAXNG_IN_LIST; 6453 ret = 6454 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6455 cur->type); 6456 } else if (cur->type == XML_RELAXNG_GROUP) { 6457 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6458 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP, 6459 "Found forbidden pattern data/except//group\n", 6460 NULL, NULL); 6461 } 6462 if (flags & XML_RELAXNG_IN_START) { 6463 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP, 6464 "Found forbidden pattern start//group\n", NULL, 6465 NULL); 6466 } 6467 if (flags & XML_RELAXNG_IN_ONEORMORE) 6468 nflags = flags | XML_RELAXNG_IN_OOMGROUP; 6469 else 6470 nflags = flags; 6471 ret = 6472 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6473 cur->type); 6474 /* 6475 * The 7.3 Attribute derivation rule for groups is plugged there 6476 */ 6477 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6478 } else if (cur->type == XML_RELAXNG_INTERLEAVE) { 6479 if (flags & XML_RELAXNG_IN_LIST) { 6480 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE, 6481 "Found forbidden pattern list//interleave\n", 6482 NULL, NULL); 6483 } 6484 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6485 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6486 "Found forbidden pattern data/except//interleave\n", 6487 NULL, NULL); 6488 } 6489 if (flags & XML_RELAXNG_IN_START) { 6490 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6491 "Found forbidden pattern start//interleave\n", 6492 NULL, NULL); 6493 } 6494 if (flags & XML_RELAXNG_IN_ONEORMORE) 6495 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE; 6496 else 6497 nflags = flags; 6498 ret = 6499 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6500 cur->type); 6501 } else if (cur->type == XML_RELAXNG_EXCEPT) { 6502 if ((cur->parent != NULL) && 6503 (cur->parent->type == XML_RELAXNG_DATATYPE)) 6504 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT; 6505 else 6506 nflags = flags; 6507 ret = 6508 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6509 cur->type); 6510 } else if (cur->type == XML_RELAXNG_DATATYPE) { 6511 if (flags & XML_RELAXNG_IN_START) { 6512 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA, 6513 "Found forbidden pattern start//data\n", NULL, 6514 NULL); 6515 } 6516 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6517 ret = XML_RELAXNG_CONTENT_SIMPLE; 6518 } else if (cur->type == XML_RELAXNG_VALUE) { 6519 if (flags & XML_RELAXNG_IN_START) { 6520 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE, 6521 "Found forbidden pattern start//value\n", NULL, 6522 NULL); 6523 } 6524 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6525 ret = XML_RELAXNG_CONTENT_SIMPLE; 6526 } else if (cur->type == XML_RELAXNG_TEXT) { 6527 if (flags & XML_RELAXNG_IN_LIST) { 6528 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT, 6529 "Found forbidden pattern list//text\n", NULL, 6530 NULL); 6531 } 6532 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6533 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT, 6534 "Found forbidden pattern data/except//text\n", 6535 NULL, NULL); 6536 } 6537 if (flags & XML_RELAXNG_IN_START) { 6538 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT, 6539 "Found forbidden pattern start//text\n", NULL, 6540 NULL); 6541 } 6542 ret = XML_RELAXNG_CONTENT_COMPLEX; 6543 } else if (cur->type == XML_RELAXNG_EMPTY) { 6544 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6545 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY, 6546 "Found forbidden pattern data/except//empty\n", 6547 NULL, NULL); 6548 } 6549 if (flags & XML_RELAXNG_IN_START) { 6550 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY, 6551 "Found forbidden pattern start//empty\n", NULL, 6552 NULL); 6553 } 6554 ret = XML_RELAXNG_CONTENT_EMPTY; 6555 } else if (cur->type == XML_RELAXNG_CHOICE) { 6556 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur); 6557 ret = 6558 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6559 } else { 6560 ret = 6561 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6562 } 6563 cur = cur->next; 6564 if (ptype == XML_RELAXNG_GROUP) { 6565 val = xmlRelaxNGGroupContentType(val, ret); 6566 } else if (ptype == XML_RELAXNG_INTERLEAVE) { 6567 /* 6568 * TODO: scan complain that tmp is never used, seems on purpose 6569 * need double-checking 6570 */ 6571 tmp = xmlRelaxNGGroupContentType(val, ret); 6572 if (tmp != XML_RELAXNG_CONTENT_ERROR) 6573 tmp = xmlRelaxNGMaxContentType(val, ret); 6574 } else if (ptype == XML_RELAXNG_CHOICE) { 6575 val = xmlRelaxNGMaxContentType(val, ret); 6576 } else if (ptype == XML_RELAXNG_LIST) { 6577 val = XML_RELAXNG_CONTENT_SIMPLE; 6578 } else if (ptype == XML_RELAXNG_EXCEPT) { 6579 if (ret == XML_RELAXNG_CONTENT_ERROR) 6580 val = XML_RELAXNG_CONTENT_ERROR; 6581 else 6582 val = XML_RELAXNG_CONTENT_SIMPLE; 6583 } else { 6584 val = xmlRelaxNGGroupContentType(val, ret); 6585 } 6586 6587 } 6588 return (val); 6589 } 6590 6591 /** 6592 * xmlRelaxNGParseGrammar: 6593 * @ctxt: a Relax-NG parser context 6594 * @nodes: grammar children nodes 6595 * 6596 * parse a Relax-NG <grammar> node 6597 * 6598 * Returns the internal xmlRelaxNGGrammarPtr built or 6599 * NULL in case of error 6600 */ 6601 static xmlRelaxNGGrammarPtr 6602 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 6603 { 6604 xmlRelaxNGGrammarPtr ret, tmp, old; 6605 6606 #ifdef DEBUG_GRAMMAR 6607 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n"); 6608 #endif 6609 6610 ret = xmlRelaxNGNewGrammar(ctxt); 6611 if (ret == NULL) 6612 return (NULL); 6613 6614 /* 6615 * Link the new grammar in the tree 6616 */ 6617 ret->parent = ctxt->grammar; 6618 if (ctxt->grammar != NULL) { 6619 tmp = ctxt->grammar->children; 6620 if (tmp == NULL) { 6621 ctxt->grammar->children = ret; 6622 } else { 6623 while (tmp->next != NULL) 6624 tmp = tmp->next; 6625 tmp->next = ret; 6626 } 6627 } 6628 6629 old = ctxt->grammar; 6630 ctxt->grammar = ret; 6631 xmlRelaxNGParseGrammarContent(ctxt, nodes); 6632 ctxt->grammar = ret; 6633 if (ctxt->grammar == NULL) { 6634 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 6635 "Failed to parse <grammar> content\n", NULL, NULL); 6636 } else if (ctxt->grammar->start == NULL) { 6637 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START, 6638 "Element <grammar> has no <start>\n", NULL, NULL); 6639 } 6640 6641 /* 6642 * Apply 4.17 merging rules to defines and starts 6643 */ 6644 xmlRelaxNGCombineStart(ctxt, ret); 6645 if (ret->defs != NULL) { 6646 xmlHashScan(ret->defs, xmlRelaxNGCheckCombine, ctxt); 6647 } 6648 6649 /* 6650 * link together defines and refs in this grammar 6651 */ 6652 if (ret->refs != NULL) { 6653 xmlHashScan(ret->refs, xmlRelaxNGCheckReference, ctxt); 6654 } 6655 6656 6657 /* @@@@ */ 6658 6659 ctxt->grammar = old; 6660 return (ret); 6661 } 6662 6663 /** 6664 * xmlRelaxNGParseDocument: 6665 * @ctxt: a Relax-NG parser context 6666 * @node: the root node of the RelaxNG schema 6667 * 6668 * parse a Relax-NG definition resource and build an internal 6669 * xmlRelaxNG structure which can be used to validate instances. 6670 * 6671 * Returns the internal XML RelaxNG structure built or 6672 * NULL in case of error 6673 */ 6674 static xmlRelaxNGPtr 6675 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6676 { 6677 xmlRelaxNGPtr schema = NULL; 6678 const xmlChar *olddefine; 6679 xmlRelaxNGGrammarPtr old; 6680 6681 if ((ctxt == NULL) || (node == NULL)) 6682 return (NULL); 6683 6684 schema = xmlRelaxNGNewRelaxNG(ctxt); 6685 if (schema == NULL) 6686 return (NULL); 6687 6688 olddefine = ctxt->define; 6689 ctxt->define = NULL; 6690 if (IS_RELAXNG(node, "grammar")) { 6691 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children); 6692 if (schema->topgrammar == NULL) { 6693 xmlRelaxNGFree(schema); 6694 return (NULL); 6695 } 6696 } else { 6697 xmlRelaxNGGrammarPtr tmp, ret; 6698 6699 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt); 6700 if (schema->topgrammar == NULL) { 6701 xmlRelaxNGFree(schema); 6702 return (NULL); 6703 } 6704 /* 6705 * Link the new grammar in the tree 6706 */ 6707 ret->parent = ctxt->grammar; 6708 if (ctxt->grammar != NULL) { 6709 tmp = ctxt->grammar->children; 6710 if (tmp == NULL) { 6711 ctxt->grammar->children = ret; 6712 } else { 6713 while (tmp->next != NULL) 6714 tmp = tmp->next; 6715 tmp->next = ret; 6716 } 6717 } 6718 old = ctxt->grammar; 6719 ctxt->grammar = ret; 6720 xmlRelaxNGParseStart(ctxt, node); 6721 if (old != NULL) 6722 ctxt->grammar = old; 6723 } 6724 ctxt->define = olddefine; 6725 if (schema->topgrammar->start != NULL) { 6726 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0); 6727 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) { 6728 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL); 6729 while ((schema->topgrammar->start != NULL) && 6730 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) && 6731 (schema->topgrammar->start->next != NULL)) 6732 schema->topgrammar->start = 6733 schema->topgrammar->start->content; 6734 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start, 6735 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); 6736 } 6737 } 6738 #ifdef DEBUG 6739 if (schema == NULL) 6740 xmlGenericError(xmlGenericErrorContext, 6741 "xmlRelaxNGParseDocument() failed\n"); 6742 #endif 6743 6744 return (schema); 6745 } 6746 6747 /************************************************************************ 6748 * * 6749 * Reading RelaxNGs * 6750 * * 6751 ************************************************************************/ 6752 6753 /** 6754 * xmlRelaxNGNewParserCtxt: 6755 * @URL: the location of the schema 6756 * 6757 * Create an XML RelaxNGs parse context for that file/resource expected 6758 * to contain an XML RelaxNGs file. 6759 * 6760 * Returns the parser context or NULL in case of error 6761 */ 6762 xmlRelaxNGParserCtxtPtr 6763 xmlRelaxNGNewParserCtxt(const char *URL) 6764 { 6765 xmlRelaxNGParserCtxtPtr ret; 6766 6767 if (URL == NULL) 6768 return (NULL); 6769 6770 ret = 6771 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6772 if (ret == NULL) { 6773 xmlRngPErrMemory(NULL, "building parser\n"); 6774 return (NULL); 6775 } 6776 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6777 ret->URL = xmlStrdup((const xmlChar *) URL); 6778 ret->error = xmlGenericError; 6779 ret->userData = xmlGenericErrorContext; 6780 return (ret); 6781 } 6782 6783 /** 6784 * xmlRelaxNGNewMemParserCtxt: 6785 * @buffer: a pointer to a char array containing the schemas 6786 * @size: the size of the array 6787 * 6788 * Create an XML RelaxNGs parse context for that memory buffer expected 6789 * to contain an XML RelaxNGs file. 6790 * 6791 * Returns the parser context or NULL in case of error 6792 */ 6793 xmlRelaxNGParserCtxtPtr 6794 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) 6795 { 6796 xmlRelaxNGParserCtxtPtr ret; 6797 6798 if ((buffer == NULL) || (size <= 0)) 6799 return (NULL); 6800 6801 ret = 6802 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6803 if (ret == NULL) { 6804 xmlRngPErrMemory(NULL, "building parser\n"); 6805 return (NULL); 6806 } 6807 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6808 ret->buffer = buffer; 6809 ret->size = size; 6810 ret->error = xmlGenericError; 6811 ret->userData = xmlGenericErrorContext; 6812 return (ret); 6813 } 6814 6815 /** 6816 * xmlRelaxNGNewDocParserCtxt: 6817 * @doc: a preparsed document tree 6818 * 6819 * Create an XML RelaxNGs parser context for that document. 6820 * Note: since the process of compiling a RelaxNG schemas modifies the 6821 * document, the @doc parameter is duplicated internally. 6822 * 6823 * Returns the parser context or NULL in case of error 6824 */ 6825 xmlRelaxNGParserCtxtPtr 6826 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) 6827 { 6828 xmlRelaxNGParserCtxtPtr ret; 6829 xmlDocPtr copy; 6830 6831 if (doc == NULL) 6832 return (NULL); 6833 copy = xmlCopyDoc(doc, 1); 6834 if (copy == NULL) 6835 return (NULL); 6836 6837 ret = 6838 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6839 if (ret == NULL) { 6840 xmlRngPErrMemory(NULL, "building parser\n"); 6841 return (NULL); 6842 } 6843 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6844 ret->document = copy; 6845 ret->freedoc = 1; 6846 ret->userData = xmlGenericErrorContext; 6847 return (ret); 6848 } 6849 6850 /** 6851 * xmlRelaxNGFreeParserCtxt: 6852 * @ctxt: the schema parser context 6853 * 6854 * Free the resources associated to the schema parser context 6855 */ 6856 void 6857 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) 6858 { 6859 if (ctxt == NULL) 6860 return; 6861 if (ctxt->URL != NULL) 6862 xmlFree(ctxt->URL); 6863 if (ctxt->doc != NULL) 6864 xmlRelaxNGFreeDocument(ctxt->doc); 6865 if (ctxt->interleaves != NULL) 6866 xmlHashFree(ctxt->interleaves, NULL); 6867 if (ctxt->documents != NULL) 6868 xmlRelaxNGFreeDocumentList(ctxt->documents); 6869 if (ctxt->includes != NULL) 6870 xmlRelaxNGFreeIncludeList(ctxt->includes); 6871 if (ctxt->docTab != NULL) 6872 xmlFree(ctxt->docTab); 6873 if (ctxt->incTab != NULL) 6874 xmlFree(ctxt->incTab); 6875 if (ctxt->defTab != NULL) { 6876 int i; 6877 6878 for (i = 0; i < ctxt->defNr; i++) 6879 xmlRelaxNGFreeDefine(ctxt->defTab[i]); 6880 xmlFree(ctxt->defTab); 6881 } 6882 if ((ctxt->document != NULL) && (ctxt->freedoc)) 6883 xmlFreeDoc(ctxt->document); 6884 xmlFree(ctxt); 6885 } 6886 6887 /** 6888 * xmlRelaxNGNormExtSpace: 6889 * @value: a value 6890 * 6891 * Removes the leading and ending spaces of the value 6892 * The string is modified "in situ" 6893 */ 6894 static void 6895 xmlRelaxNGNormExtSpace(xmlChar * value) 6896 { 6897 xmlChar *start = value; 6898 xmlChar *cur = value; 6899 6900 if (value == NULL) 6901 return; 6902 6903 while (IS_BLANK_CH(*cur)) 6904 cur++; 6905 if (cur == start) { 6906 do { 6907 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6908 cur++; 6909 if (*cur == 0) 6910 return; 6911 start = cur; 6912 while (IS_BLANK_CH(*cur)) 6913 cur++; 6914 if (*cur == 0) { 6915 *start = 0; 6916 return; 6917 } 6918 } while (1); 6919 } else { 6920 do { 6921 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6922 *start++ = *cur++; 6923 if (*cur == 0) { 6924 *start = 0; 6925 return; 6926 } 6927 /* don't try to normalize the inner spaces */ 6928 while (IS_BLANK_CH(*cur)) 6929 cur++; 6930 if (*cur == 0) { 6931 *start = 0; 6932 return; 6933 } 6934 *start++ = *cur++; 6935 } while (1); 6936 } 6937 } 6938 6939 /** 6940 * xmlRelaxNGCleanupAttributes: 6941 * @ctxt: a Relax-NG parser context 6942 * @node: a Relax-NG node 6943 * 6944 * Check all the attributes on the given node 6945 */ 6946 static void 6947 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6948 { 6949 xmlAttrPtr cur, next; 6950 6951 cur = node->properties; 6952 while (cur != NULL) { 6953 next = cur->next; 6954 if ((cur->ns == NULL) || 6955 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 6956 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 6957 if ((!xmlStrEqual(node->name, BAD_CAST "element")) && 6958 (!xmlStrEqual(node->name, BAD_CAST "attribute")) && 6959 (!xmlStrEqual(node->name, BAD_CAST "ref")) && 6960 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) && 6961 (!xmlStrEqual(node->name, BAD_CAST "param")) && 6962 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 6963 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6964 "Attribute %s is not allowed on %s\n", 6965 cur->name, node->name); 6966 } 6967 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) { 6968 if ((!xmlStrEqual(node->name, BAD_CAST "value")) && 6969 (!xmlStrEqual(node->name, BAD_CAST "data"))) { 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 "href")) { 6975 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) && 6976 (!xmlStrEqual(node->name, BAD_CAST "include"))) { 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 "combine")) { 6982 if ((!xmlStrEqual(node->name, BAD_CAST "start")) && 6983 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 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 "datatypeLibrary")) { 6989 xmlChar *val; 6990 xmlURIPtr uri; 6991 6992 val = xmlNodeListGetString(node->doc, cur->children, 1); 6993 if (val != NULL) { 6994 if (val[0] != 0) { 6995 uri = xmlParseURI((const char *) val); 6996 if (uri == NULL) { 6997 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI, 6998 "Attribute %s contains invalid URI %s\n", 6999 cur->name, val); 7000 } else { 7001 if (uri->scheme == NULL) { 7002 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE, 7003 "Attribute %s URI %s is not absolute\n", 7004 cur->name, val); 7005 } 7006 if (uri->fragment != NULL) { 7007 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT, 7008 "Attribute %s URI %s has a fragment ID\n", 7009 cur->name, val); 7010 } 7011 xmlFreeURI(uri); 7012 } 7013 } 7014 xmlFree(val); 7015 } 7016 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) { 7017 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE, 7018 "Unknown attribute %s on %s\n", cur->name, 7019 node->name); 7020 } 7021 } 7022 cur = next; 7023 } 7024 } 7025 7026 /** 7027 * xmlRelaxNGCleanupTree: 7028 * @ctxt: a Relax-NG parser context 7029 * @root: an xmlNodePtr subtree 7030 * 7031 * Cleanup the subtree from unwanted nodes for parsing, resolve 7032 * Include and externalRef lookups. 7033 */ 7034 static void 7035 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) 7036 { 7037 xmlNodePtr cur, delete; 7038 7039 delete = NULL; 7040 cur = root; 7041 while (cur != NULL) { 7042 if (delete != NULL) { 7043 xmlUnlinkNode(delete); 7044 xmlFreeNode(delete); 7045 delete = NULL; 7046 } 7047 if (cur->type == XML_ELEMENT_NODE) { 7048 /* 7049 * Simplification 4.1. Annotations 7050 */ 7051 if ((cur->ns == NULL) || 7052 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 7053 if ((cur->parent != NULL) && 7054 (cur->parent->type == XML_ELEMENT_NODE) && 7055 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) || 7056 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) || 7057 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) { 7058 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT, 7059 "element %s doesn't allow foreign elements\n", 7060 cur->parent->name, NULL); 7061 } 7062 delete = cur; 7063 goto skip_children; 7064 } else { 7065 xmlRelaxNGCleanupAttributes(ctxt, cur); 7066 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) { 7067 xmlChar *href, *ns, *base, *URL; 7068 xmlRelaxNGDocumentPtr docu; 7069 xmlNodePtr tmp; 7070 xmlURIPtr uri; 7071 7072 ns = xmlGetProp(cur, BAD_CAST "ns"); 7073 if (ns == NULL) { 7074 tmp = cur->parent; 7075 while ((tmp != NULL) && 7076 (tmp->type == XML_ELEMENT_NODE)) { 7077 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7078 if (ns != NULL) 7079 break; 7080 tmp = tmp->parent; 7081 } 7082 } 7083 href = xmlGetProp(cur, BAD_CAST "href"); 7084 if (href == NULL) { 7085 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7086 "xmlRelaxNGParse: externalRef has no href attribute\n", 7087 NULL, NULL); 7088 if (ns != NULL) 7089 xmlFree(ns); 7090 delete = cur; 7091 goto skip_children; 7092 } 7093 uri = xmlParseURI((const char *) href); 7094 if (uri == NULL) { 7095 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7096 "Incorrect URI for externalRef %s\n", 7097 href, NULL); 7098 if (ns != NULL) 7099 xmlFree(ns); 7100 if (href != NULL) 7101 xmlFree(href); 7102 delete = cur; 7103 goto skip_children; 7104 } 7105 if (uri->fragment != NULL) { 7106 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7107 "Fragment forbidden in URI for externalRef %s\n", 7108 href, NULL); 7109 if (ns != NULL) 7110 xmlFree(ns); 7111 xmlFreeURI(uri); 7112 if (href != NULL) 7113 xmlFree(href); 7114 delete = cur; 7115 goto skip_children; 7116 } 7117 xmlFreeURI(uri); 7118 base = xmlNodeGetBase(cur->doc, cur); 7119 URL = xmlBuildURI(href, base); 7120 if (URL == NULL) { 7121 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7122 "Failed to compute URL for externalRef %s\n", 7123 href, NULL); 7124 if (ns != NULL) 7125 xmlFree(ns); 7126 if (href != NULL) 7127 xmlFree(href); 7128 if (base != NULL) 7129 xmlFree(base); 7130 delete = cur; 7131 goto skip_children; 7132 } 7133 if (href != NULL) 7134 xmlFree(href); 7135 if (base != NULL) 7136 xmlFree(base); 7137 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns); 7138 if (docu == NULL) { 7139 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE, 7140 "Failed to load externalRef %s\n", URL, 7141 NULL); 7142 if (ns != NULL) 7143 xmlFree(ns); 7144 xmlFree(URL); 7145 delete = cur; 7146 goto skip_children; 7147 } 7148 if (ns != NULL) 7149 xmlFree(ns); 7150 xmlFree(URL); 7151 cur->psvi = docu; 7152 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { 7153 xmlChar *href, *ns, *base, *URL; 7154 xmlRelaxNGIncludePtr incl; 7155 xmlNodePtr tmp; 7156 7157 href = xmlGetProp(cur, BAD_CAST "href"); 7158 if (href == NULL) { 7159 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7160 "xmlRelaxNGParse: include has no href attribute\n", 7161 NULL, NULL); 7162 delete = cur; 7163 goto skip_children; 7164 } 7165 base = xmlNodeGetBase(cur->doc, cur); 7166 URL = xmlBuildURI(href, base); 7167 if (URL == NULL) { 7168 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7169 "Failed to compute URL for include %s\n", 7170 href, NULL); 7171 if (href != NULL) 7172 xmlFree(href); 7173 if (base != NULL) 7174 xmlFree(base); 7175 delete = cur; 7176 goto skip_children; 7177 } 7178 if (href != NULL) 7179 xmlFree(href); 7180 if (base != NULL) 7181 xmlFree(base); 7182 ns = xmlGetProp(cur, BAD_CAST "ns"); 7183 if (ns == NULL) { 7184 tmp = cur->parent; 7185 while ((tmp != NULL) && 7186 (tmp->type == XML_ELEMENT_NODE)) { 7187 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7188 if (ns != NULL) 7189 break; 7190 tmp = tmp->parent; 7191 } 7192 } 7193 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns); 7194 if (ns != NULL) 7195 xmlFree(ns); 7196 if (incl == NULL) { 7197 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE, 7198 "Failed to load include %s\n", URL, 7199 NULL); 7200 xmlFree(URL); 7201 delete = cur; 7202 goto skip_children; 7203 } 7204 xmlFree(URL); 7205 cur->psvi = incl; 7206 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) || 7207 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) 7208 { 7209 xmlChar *name, *ns; 7210 xmlNodePtr text = NULL; 7211 7212 /* 7213 * Simplification 4.8. name attribute of element 7214 * and attribute elements 7215 */ 7216 name = xmlGetProp(cur, BAD_CAST "name"); 7217 if (name != NULL) { 7218 if (cur->children == NULL) { 7219 text = 7220 xmlNewChild(cur, cur->ns, BAD_CAST "name", 7221 name); 7222 } else { 7223 xmlNodePtr node; 7224 7225 node = xmlNewDocNode(cur->doc, cur->ns, 7226 BAD_CAST "name", NULL); 7227 if (node != NULL) { 7228 xmlAddPrevSibling(cur->children, node); 7229 text = xmlNewText(name); 7230 xmlAddChild(node, text); 7231 text = node; 7232 } 7233 } 7234 if (text == NULL) { 7235 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE, 7236 "Failed to create a name %s element\n", 7237 name, NULL); 7238 } 7239 xmlUnsetProp(cur, BAD_CAST "name"); 7240 xmlFree(name); 7241 ns = xmlGetProp(cur, BAD_CAST "ns"); 7242 if (ns != NULL) { 7243 if (text != NULL) { 7244 xmlSetProp(text, BAD_CAST "ns", ns); 7245 /* xmlUnsetProp(cur, BAD_CAST "ns"); */ 7246 } 7247 xmlFree(ns); 7248 } else if (xmlStrEqual(cur->name, 7249 BAD_CAST "attribute")) { 7250 xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); 7251 } 7252 } 7253 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) || 7254 (xmlStrEqual(cur->name, BAD_CAST "nsName")) || 7255 (xmlStrEqual(cur->name, BAD_CAST "value"))) { 7256 /* 7257 * Simplification 4.8. name attribute of element 7258 * and attribute elements 7259 */ 7260 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) { 7261 xmlNodePtr node; 7262 xmlChar *ns = NULL; 7263 7264 node = cur->parent; 7265 while ((node != NULL) && 7266 (node->type == XML_ELEMENT_NODE)) { 7267 ns = xmlGetProp(node, BAD_CAST "ns"); 7268 if (ns != NULL) { 7269 break; 7270 } 7271 node = node->parent; 7272 } 7273 if (ns == NULL) { 7274 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); 7275 } else { 7276 xmlSetProp(cur, BAD_CAST "ns", ns); 7277 xmlFree(ns); 7278 } 7279 } 7280 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 7281 xmlChar *name, *local, *prefix; 7282 7283 /* 7284 * Simplification: 4.10. QNames 7285 */ 7286 name = xmlNodeGetContent(cur); 7287 if (name != NULL) { 7288 local = xmlSplitQName2(name, &prefix); 7289 if (local != NULL) { 7290 xmlNsPtr ns; 7291 7292 ns = xmlSearchNs(cur->doc, cur, prefix); 7293 if (ns == NULL) { 7294 xmlRngPErr(ctxt, cur, 7295 XML_RNGP_PREFIX_UNDEFINED, 7296 "xmlRelaxNGParse: no namespace for prefix %s\n", 7297 prefix, NULL); 7298 } else { 7299 xmlSetProp(cur, BAD_CAST "ns", 7300 ns->href); 7301 xmlNodeSetContent(cur, local); 7302 } 7303 xmlFree(local); 7304 xmlFree(prefix); 7305 } 7306 xmlFree(name); 7307 } 7308 } 7309 /* 7310 * 4.16 7311 */ 7312 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) { 7313 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7314 xmlRngPErr(ctxt, cur, 7315 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, 7316 "Found nsName/except//nsName forbidden construct\n", 7317 NULL, NULL); 7318 } 7319 } 7320 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) && 7321 (cur != root)) { 7322 int oldflags = ctxt->flags; 7323 7324 /* 7325 * 4.16 7326 */ 7327 if ((cur->parent != NULL) && 7328 (xmlStrEqual 7329 (cur->parent->name, BAD_CAST "anyName"))) { 7330 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT; 7331 xmlRelaxNGCleanupTree(ctxt, cur); 7332 ctxt->flags = oldflags; 7333 goto skip_children; 7334 } else if ((cur->parent != NULL) && 7335 (xmlStrEqual 7336 (cur->parent->name, BAD_CAST "nsName"))) { 7337 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT; 7338 xmlRelaxNGCleanupTree(ctxt, cur); 7339 ctxt->flags = oldflags; 7340 goto skip_children; 7341 } 7342 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) { 7343 /* 7344 * 4.16 7345 */ 7346 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) { 7347 xmlRngPErr(ctxt, cur, 7348 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, 7349 "Found anyName/except//anyName forbidden construct\n", 7350 NULL, NULL); 7351 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7352 xmlRngPErr(ctxt, cur, 7353 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, 7354 "Found nsName/except//anyName forbidden construct\n", 7355 NULL, NULL); 7356 } 7357 } 7358 /* 7359 * This is not an else since "include" is transformed 7360 * into a div 7361 */ 7362 if (xmlStrEqual(cur->name, BAD_CAST "div")) { 7363 xmlChar *ns; 7364 xmlNodePtr child, ins, tmp; 7365 7366 /* 7367 * implements rule 4.11 7368 */ 7369 7370 ns = xmlGetProp(cur, BAD_CAST "ns"); 7371 7372 child = cur->children; 7373 ins = cur; 7374 while (child != NULL) { 7375 if (ns != NULL) { 7376 if (!xmlHasProp(child, BAD_CAST "ns")) { 7377 xmlSetProp(child, BAD_CAST "ns", ns); 7378 } 7379 } 7380 tmp = child->next; 7381 xmlUnlinkNode(child); 7382 ins = xmlAddNextSibling(ins, child); 7383 child = tmp; 7384 } 7385 if (ns != NULL) 7386 xmlFree(ns); 7387 /* 7388 * Since we are about to delete cur, if its nsDef is non-NULL we 7389 * need to preserve it (it contains the ns definitions for the 7390 * children we just moved). We'll just stick it on to the end 7391 * of cur->parent's list, since it's never going to be re-serialized 7392 * (bug 143738). 7393 */ 7394 if ((cur->nsDef != NULL) && (cur->parent != NULL)) { 7395 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef; 7396 while (parDef->next != NULL) 7397 parDef = parDef->next; 7398 parDef->next = cur->nsDef; 7399 cur->nsDef = NULL; 7400 } 7401 delete = cur; 7402 goto skip_children; 7403 } 7404 } 7405 } 7406 /* 7407 * Simplification 4.2 whitespaces 7408 */ 7409 else if ((cur->type == XML_TEXT_NODE) || 7410 (cur->type == XML_CDATA_SECTION_NODE)) { 7411 if (IS_BLANK_NODE(cur)) { 7412 if ((cur->parent != NULL) && 7413 (cur->parent->type == XML_ELEMENT_NODE)) { 7414 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) 7415 && 7416 (!xmlStrEqual 7417 (cur->parent->name, BAD_CAST "param"))) 7418 delete = cur; 7419 } else { 7420 delete = cur; 7421 goto skip_children; 7422 } 7423 } 7424 } else { 7425 delete = cur; 7426 goto skip_children; 7427 } 7428 7429 /* 7430 * Skip to next node 7431 */ 7432 if (cur->children != NULL) { 7433 if ((cur->children->type != XML_ENTITY_DECL) && 7434 (cur->children->type != XML_ENTITY_REF_NODE) && 7435 (cur->children->type != XML_ENTITY_NODE)) { 7436 cur = cur->children; 7437 continue; 7438 } 7439 } 7440 skip_children: 7441 if (cur->next != NULL) { 7442 cur = cur->next; 7443 continue; 7444 } 7445 7446 do { 7447 cur = cur->parent; 7448 if (cur == NULL) 7449 break; 7450 if (cur == root) { 7451 cur = NULL; 7452 break; 7453 } 7454 if (cur->next != NULL) { 7455 cur = cur->next; 7456 break; 7457 } 7458 } while (cur != NULL); 7459 } 7460 if (delete != NULL) { 7461 xmlUnlinkNode(delete); 7462 xmlFreeNode(delete); 7463 delete = NULL; 7464 } 7465 } 7466 7467 /** 7468 * xmlRelaxNGCleanupDoc: 7469 * @ctxt: a Relax-NG parser context 7470 * @doc: an xmldocPtr document pointer 7471 * 7472 * Cleanup the document from unwanted nodes for parsing, resolve 7473 * Include and externalRef lookups. 7474 * 7475 * Returns the cleaned up document or NULL in case of error 7476 */ 7477 static xmlDocPtr 7478 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) 7479 { 7480 xmlNodePtr root; 7481 7482 /* 7483 * Extract the root 7484 */ 7485 root = xmlDocGetRootElement(doc); 7486 if (root == NULL) { 7487 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7488 ctxt->URL, NULL); 7489 return (NULL); 7490 } 7491 xmlRelaxNGCleanupTree(ctxt, root); 7492 return (doc); 7493 } 7494 7495 /** 7496 * xmlRelaxNGParse: 7497 * @ctxt: a Relax-NG parser context 7498 * 7499 * parse a schema definition resource and build an internal 7500 * XML Schema structure which can be used to validate instances. 7501 * 7502 * Returns the internal XML RelaxNG structure built from the resource or 7503 * NULL in case of error 7504 */ 7505 xmlRelaxNGPtr 7506 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) 7507 { 7508 xmlRelaxNGPtr ret = NULL; 7509 xmlDocPtr doc; 7510 xmlNodePtr root; 7511 7512 xmlRelaxNGInitTypes(); 7513 7514 if (ctxt == NULL) 7515 return (NULL); 7516 7517 /* 7518 * First step is to parse the input document into an DOM/Infoset 7519 */ 7520 if (ctxt->URL != NULL) { 7521 doc = xmlReadFile((const char *) ctxt->URL,NULL,0); 7522 if (doc == NULL) { 7523 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7524 "xmlRelaxNGParse: could not load %s\n", ctxt->URL, 7525 NULL); 7526 return (NULL); 7527 } 7528 } else if (ctxt->buffer != NULL) { 7529 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); 7530 if (doc == NULL) { 7531 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7532 "xmlRelaxNGParse: could not parse schemas\n", NULL, 7533 NULL); 7534 return (NULL); 7535 } 7536 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7537 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7538 } else if (ctxt->document != NULL) { 7539 doc = ctxt->document; 7540 } else { 7541 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY, 7542 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL); 7543 return (NULL); 7544 } 7545 ctxt->document = doc; 7546 7547 /* 7548 * Some preprocessing of the document content 7549 */ 7550 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 7551 if (doc == NULL) { 7552 xmlFreeDoc(ctxt->document); 7553 ctxt->document = NULL; 7554 return (NULL); 7555 } 7556 7557 /* 7558 * Then do the parsing for good 7559 */ 7560 root = xmlDocGetRootElement(doc); 7561 if (root == NULL) { 7562 xmlRngPErr(ctxt, (xmlNodePtr) doc, 7563 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7564 (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL); 7565 7566 xmlFreeDoc(ctxt->document); 7567 ctxt->document = NULL; 7568 return (NULL); 7569 } 7570 ret = xmlRelaxNGParseDocument(ctxt, root); 7571 if (ret == NULL) { 7572 xmlFreeDoc(ctxt->document); 7573 ctxt->document = NULL; 7574 return (NULL); 7575 } 7576 7577 /* 7578 * Check the ref/defines links 7579 */ 7580 /* 7581 * try to preprocess interleaves 7582 */ 7583 if (ctxt->interleaves != NULL) { 7584 xmlHashScan(ctxt->interleaves, xmlRelaxNGComputeInterleaves, ctxt); 7585 } 7586 7587 /* 7588 * if there was a parsing error return NULL 7589 */ 7590 if (ctxt->nbErrors > 0) { 7591 xmlRelaxNGFree(ret); 7592 ctxt->document = NULL; 7593 xmlFreeDoc(doc); 7594 return (NULL); 7595 } 7596 7597 /* 7598 * try to compile (parts of) the schemas 7599 */ 7600 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) { 7601 if (ret->topgrammar->start->type != XML_RELAXNG_START) { 7602 xmlRelaxNGDefinePtr def; 7603 7604 def = xmlRelaxNGNewDefine(ctxt, NULL); 7605 if (def != NULL) { 7606 def->type = XML_RELAXNG_START; 7607 def->content = ret->topgrammar->start; 7608 ret->topgrammar->start = def; 7609 } 7610 } 7611 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start); 7612 } 7613 7614 /* 7615 * Transfer the pointer for cleanup at the schema level. 7616 */ 7617 ret->doc = doc; 7618 ctxt->document = NULL; 7619 ret->documents = ctxt->documents; 7620 ctxt->documents = NULL; 7621 7622 ret->includes = ctxt->includes; 7623 ctxt->includes = NULL; 7624 ret->defNr = ctxt->defNr; 7625 ret->defTab = ctxt->defTab; 7626 ctxt->defTab = NULL; 7627 if (ctxt->idref == 1) 7628 ret->idref = 1; 7629 7630 return (ret); 7631 } 7632 7633 /** 7634 * xmlRelaxNGSetParserErrors: 7635 * @ctxt: a Relax-NG validation context 7636 * @err: the error callback 7637 * @warn: the warning callback 7638 * @ctx: contextual data for the callbacks 7639 * 7640 * Set the callback functions used to handle errors for a validation context 7641 */ 7642 void 7643 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, 7644 xmlRelaxNGValidityErrorFunc err, 7645 xmlRelaxNGValidityWarningFunc warn, void *ctx) 7646 { 7647 if (ctxt == NULL) 7648 return; 7649 ctxt->error = err; 7650 ctxt->warning = warn; 7651 ctxt->serror = NULL; 7652 ctxt->userData = ctx; 7653 } 7654 7655 /** 7656 * xmlRelaxNGGetParserErrors: 7657 * @ctxt: a Relax-NG validation context 7658 * @err: the error callback result 7659 * @warn: the warning callback result 7660 * @ctx: contextual data for the callbacks result 7661 * 7662 * Get the callback information used to handle errors for a validation context 7663 * 7664 * Returns -1 in case of failure, 0 otherwise. 7665 */ 7666 int 7667 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, 7668 xmlRelaxNGValidityErrorFunc * err, 7669 xmlRelaxNGValidityWarningFunc * warn, void **ctx) 7670 { 7671 if (ctxt == NULL) 7672 return (-1); 7673 if (err != NULL) 7674 *err = ctxt->error; 7675 if (warn != NULL) 7676 *warn = ctxt->warning; 7677 if (ctx != NULL) 7678 *ctx = ctxt->userData; 7679 return (0); 7680 } 7681 7682 /** 7683 * xmlRelaxNGSetParserStructuredErrors: 7684 * @ctxt: a Relax-NG parser context 7685 * @serror: the error callback 7686 * @ctx: contextual data for the callbacks 7687 * 7688 * Set the callback functions used to handle errors for a parsing context 7689 */ 7690 void 7691 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt, 7692 xmlStructuredErrorFunc serror, 7693 void *ctx) 7694 { 7695 if (ctxt == NULL) 7696 return; 7697 ctxt->serror = serror; 7698 ctxt->error = NULL; 7699 ctxt->warning = NULL; 7700 ctxt->userData = ctx; 7701 } 7702 7703 #ifdef LIBXML_OUTPUT_ENABLED 7704 7705 /************************************************************************ 7706 * * 7707 * Dump back a compiled form * 7708 * * 7709 ************************************************************************/ 7710 static void xmlRelaxNGDumpDefine(FILE * output, 7711 xmlRelaxNGDefinePtr define); 7712 7713 /** 7714 * xmlRelaxNGDumpDefines: 7715 * @output: the file output 7716 * @defines: a list of define structures 7717 * 7718 * Dump a RelaxNG structure back 7719 */ 7720 static void 7721 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) 7722 { 7723 while (defines != NULL) { 7724 xmlRelaxNGDumpDefine(output, defines); 7725 defines = defines->next; 7726 } 7727 } 7728 7729 /** 7730 * xmlRelaxNGDumpDefine: 7731 * @output: the file output 7732 * @define: a define structure 7733 * 7734 * Dump a RelaxNG structure back 7735 */ 7736 static void 7737 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) 7738 { 7739 if (define == NULL) 7740 return; 7741 switch (define->type) { 7742 case XML_RELAXNG_EMPTY: 7743 fprintf(output, "<empty/>\n"); 7744 break; 7745 case XML_RELAXNG_NOT_ALLOWED: 7746 fprintf(output, "<notAllowed/>\n"); 7747 break; 7748 case XML_RELAXNG_TEXT: 7749 fprintf(output, "<text/>\n"); 7750 break; 7751 case XML_RELAXNG_ELEMENT: 7752 fprintf(output, "<element>\n"); 7753 if (define->name != NULL) { 7754 fprintf(output, "<name"); 7755 if (define->ns != NULL) 7756 fprintf(output, " ns=\"%s\"", define->ns); 7757 fprintf(output, ">%s</name>\n", define->name); 7758 } 7759 xmlRelaxNGDumpDefines(output, define->attrs); 7760 xmlRelaxNGDumpDefines(output, define->content); 7761 fprintf(output, "</element>\n"); 7762 break; 7763 case XML_RELAXNG_LIST: 7764 fprintf(output, "<list>\n"); 7765 xmlRelaxNGDumpDefines(output, define->content); 7766 fprintf(output, "</list>\n"); 7767 break; 7768 case XML_RELAXNG_ONEORMORE: 7769 fprintf(output, "<oneOrMore>\n"); 7770 xmlRelaxNGDumpDefines(output, define->content); 7771 fprintf(output, "</oneOrMore>\n"); 7772 break; 7773 case XML_RELAXNG_ZEROORMORE: 7774 fprintf(output, "<zeroOrMore>\n"); 7775 xmlRelaxNGDumpDefines(output, define->content); 7776 fprintf(output, "</zeroOrMore>\n"); 7777 break; 7778 case XML_RELAXNG_CHOICE: 7779 fprintf(output, "<choice>\n"); 7780 xmlRelaxNGDumpDefines(output, define->content); 7781 fprintf(output, "</choice>\n"); 7782 break; 7783 case XML_RELAXNG_GROUP: 7784 fprintf(output, "<group>\n"); 7785 xmlRelaxNGDumpDefines(output, define->content); 7786 fprintf(output, "</group>\n"); 7787 break; 7788 case XML_RELAXNG_INTERLEAVE: 7789 fprintf(output, "<interleave>\n"); 7790 xmlRelaxNGDumpDefines(output, define->content); 7791 fprintf(output, "</interleave>\n"); 7792 break; 7793 case XML_RELAXNG_OPTIONAL: 7794 fprintf(output, "<optional>\n"); 7795 xmlRelaxNGDumpDefines(output, define->content); 7796 fprintf(output, "</optional>\n"); 7797 break; 7798 case XML_RELAXNG_ATTRIBUTE: 7799 fprintf(output, "<attribute>\n"); 7800 xmlRelaxNGDumpDefines(output, define->content); 7801 fprintf(output, "</attribute>\n"); 7802 break; 7803 case XML_RELAXNG_DEF: 7804 fprintf(output, "<define"); 7805 if (define->name != NULL) 7806 fprintf(output, " name=\"%s\"", define->name); 7807 fprintf(output, ">\n"); 7808 xmlRelaxNGDumpDefines(output, define->content); 7809 fprintf(output, "</define>\n"); 7810 break; 7811 case XML_RELAXNG_REF: 7812 fprintf(output, "<ref"); 7813 if (define->name != NULL) 7814 fprintf(output, " name=\"%s\"", define->name); 7815 fprintf(output, ">\n"); 7816 xmlRelaxNGDumpDefines(output, define->content); 7817 fprintf(output, "</ref>\n"); 7818 break; 7819 case XML_RELAXNG_PARENTREF: 7820 fprintf(output, "<parentRef"); 7821 if (define->name != NULL) 7822 fprintf(output, " name=\"%s\"", define->name); 7823 fprintf(output, ">\n"); 7824 xmlRelaxNGDumpDefines(output, define->content); 7825 fprintf(output, "</parentRef>\n"); 7826 break; 7827 case XML_RELAXNG_EXTERNALREF: 7828 fprintf(output, "<externalRef>"); 7829 xmlRelaxNGDumpDefines(output, define->content); 7830 fprintf(output, "</externalRef>\n"); 7831 break; 7832 case XML_RELAXNG_DATATYPE: 7833 case XML_RELAXNG_VALUE: 7834 TODO break; 7835 case XML_RELAXNG_START: 7836 case XML_RELAXNG_EXCEPT: 7837 case XML_RELAXNG_PARAM: 7838 TODO break; 7839 case XML_RELAXNG_NOOP: 7840 xmlRelaxNGDumpDefines(output, define->content); 7841 break; 7842 } 7843 } 7844 7845 /** 7846 * xmlRelaxNGDumpGrammar: 7847 * @output: the file output 7848 * @grammar: a grammar structure 7849 * @top: is this a top grammar 7850 * 7851 * Dump a RelaxNG structure back 7852 */ 7853 static void 7854 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top) 7855 { 7856 if (grammar == NULL) 7857 return; 7858 7859 fprintf(output, "<grammar"); 7860 if (top) 7861 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\""); 7862 switch (grammar->combine) { 7863 case XML_RELAXNG_COMBINE_UNDEFINED: 7864 break; 7865 case XML_RELAXNG_COMBINE_CHOICE: 7866 fprintf(output, " combine=\"choice\""); 7867 break; 7868 case XML_RELAXNG_COMBINE_INTERLEAVE: 7869 fprintf(output, " combine=\"interleave\""); 7870 break; 7871 default: 7872 fprintf(output, " <!-- invalid combine value -->"); 7873 } 7874 fprintf(output, ">\n"); 7875 if (grammar->start == NULL) { 7876 fprintf(output, " <!-- grammar had no start -->"); 7877 } else { 7878 fprintf(output, "<start>\n"); 7879 xmlRelaxNGDumpDefine(output, grammar->start); 7880 fprintf(output, "</start>\n"); 7881 } 7882 /* TODO ? Dump the defines ? */ 7883 fprintf(output, "</grammar>\n"); 7884 } 7885 7886 /** 7887 * xmlRelaxNGDump: 7888 * @output: the file output 7889 * @schema: a schema structure 7890 * 7891 * Dump a RelaxNG structure back 7892 */ 7893 void 7894 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema) 7895 { 7896 if (output == NULL) 7897 return; 7898 if (schema == NULL) { 7899 fprintf(output, "RelaxNG empty or failed to compile\n"); 7900 return; 7901 } 7902 fprintf(output, "RelaxNG: "); 7903 if (schema->doc == NULL) { 7904 fprintf(output, "no document\n"); 7905 } else if (schema->doc->URL != NULL) { 7906 fprintf(output, "%s\n", schema->doc->URL); 7907 } else { 7908 fprintf(output, "\n"); 7909 } 7910 if (schema->topgrammar == NULL) { 7911 fprintf(output, "RelaxNG has no top grammar\n"); 7912 return; 7913 } 7914 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1); 7915 } 7916 7917 /** 7918 * xmlRelaxNGDumpTree: 7919 * @output: the file output 7920 * @schema: a schema structure 7921 * 7922 * Dump the transformed RelaxNG tree. 7923 */ 7924 void 7925 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema) 7926 { 7927 if (output == NULL) 7928 return; 7929 if (schema == NULL) { 7930 fprintf(output, "RelaxNG empty or failed to compile\n"); 7931 return; 7932 } 7933 if (schema->doc == NULL) { 7934 fprintf(output, "no document\n"); 7935 } else { 7936 xmlDocDump(output, schema->doc); 7937 } 7938 } 7939 #endif /* LIBXML_OUTPUT_ENABLED */ 7940 7941 /************************************************************************ 7942 * * 7943 * Validation of compiled content * 7944 * * 7945 ************************************************************************/ 7946 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 7947 xmlRelaxNGDefinePtr define); 7948 7949 /** 7950 * xmlRelaxNGValidateCompiledCallback: 7951 * @exec: the regular expression instance 7952 * @token: the token which matched 7953 * @transdata: callback data, the define for the subelement if available 7954 @ @inputdata: callback data, the Relax NG validation context 7955 * 7956 * Handle the callback and if needed validate the element children. 7957 */ 7958 static void 7959 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, 7960 const xmlChar * token, 7961 void *transdata, void *inputdata) 7962 { 7963 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; 7964 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; 7965 int ret; 7966 7967 #ifdef DEBUG_COMPILE 7968 xmlGenericError(xmlGenericErrorContext, 7969 "Compiled callback for: '%s'\n", token); 7970 #endif 7971 if (ctxt == NULL) { 7972 fprintf(stderr, "callback on %s missing context\n", token); 7973 return; 7974 } 7975 if (define == NULL) { 7976 if (token[0] == '#') 7977 return; 7978 fprintf(stderr, "callback on %s missing define\n", token); 7979 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 7980 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7981 return; 7982 } 7983 if ((ctxt == NULL) || (define == NULL)) { 7984 fprintf(stderr, "callback on %s missing info\n", token); 7985 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 7986 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7987 return; 7988 } else if (define->type != XML_RELAXNG_ELEMENT) { 7989 fprintf(stderr, "callback on %s define is not element\n", token); 7990 if (ctxt->errNo == XML_RELAXNG_OK) 7991 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7992 return; 7993 } 7994 ret = xmlRelaxNGValidateDefinition(ctxt, define); 7995 if (ret != 0) 7996 ctxt->perr = ret; 7997 } 7998 7999 /** 8000 * xmlRelaxNGValidateCompiledContent: 8001 * @ctxt: the RelaxNG validation context 8002 * @regexp: the regular expression as compiled 8003 * @content: list of children to test against the regexp 8004 * 8005 * Validate the content model of an element or start using the regexp 8006 * 8007 * Returns 0 in case of success, -1 in case of error. 8008 */ 8009 static int 8010 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt, 8011 xmlRegexpPtr regexp, xmlNodePtr content) 8012 { 8013 xmlRegExecCtxtPtr exec; 8014 xmlNodePtr cur; 8015 int ret = 0; 8016 int oldperr; 8017 8018 if ((ctxt == NULL) || (regexp == NULL)) 8019 return (-1); 8020 oldperr = ctxt->perr; 8021 exec = xmlRegNewExecCtxt(regexp, 8022 xmlRelaxNGValidateCompiledCallback, ctxt); 8023 ctxt->perr = 0; 8024 cur = content; 8025 while (cur != NULL) { 8026 ctxt->state->seq = cur; 8027 switch (cur->type) { 8028 case XML_TEXT_NODE: 8029 case XML_CDATA_SECTION_NODE: 8030 if (xmlIsBlankNode(cur)) 8031 break; 8032 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt); 8033 if (ret < 0) { 8034 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, 8035 cur->parent->name); 8036 } 8037 break; 8038 case XML_ELEMENT_NODE: 8039 if (cur->ns != NULL) { 8040 ret = xmlRegExecPushString2(exec, cur->name, 8041 cur->ns->href, ctxt); 8042 } else { 8043 ret = xmlRegExecPushString(exec, cur->name, ctxt); 8044 } 8045 if (ret < 0) { 8046 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name); 8047 } 8048 break; 8049 default: 8050 break; 8051 } 8052 if (ret < 0) 8053 break; 8054 /* 8055 * Switch to next element 8056 */ 8057 cur = cur->next; 8058 } 8059 ret = xmlRegExecPushString(exec, NULL, NULL); 8060 if (ret == 1) { 8061 ret = 0; 8062 ctxt->state->seq = NULL; 8063 } else if (ret == 0) { 8064 /* 8065 * TODO: get some of the names needed to exit the current state of exec 8066 */ 8067 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); 8068 ret = -1; 8069 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8070 xmlRelaxNGDumpValidError(ctxt); 8071 } else { 8072 ret = -1; 8073 } 8074 xmlRegFreeExecCtxt(exec); 8075 /* 8076 * There might be content model errors outside of the pure 8077 * regexp validation, e.g. for attribute values. 8078 */ 8079 if ((ret == 0) && (ctxt->perr != 0)) { 8080 ret = ctxt->perr; 8081 } 8082 ctxt->perr = oldperr; 8083 return (ret); 8084 } 8085 8086 /************************************************************************ 8087 * * 8088 * Progressive validation of when possible * 8089 * * 8090 ************************************************************************/ 8091 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 8092 xmlRelaxNGDefinePtr defines); 8093 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, 8094 int dolog); 8095 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt); 8096 8097 /** 8098 * xmlRelaxNGElemPush: 8099 * @ctxt: the validation context 8100 * @exec: the regexp runtime for the new content model 8101 * 8102 * Push a new regexp for the current node content model on the stack 8103 * 8104 * Returns 0 in case of success and -1 in case of error. 8105 */ 8106 static int 8107 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) 8108 { 8109 if (ctxt->elemTab == NULL) { 8110 ctxt->elemMax = 10; 8111 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax * 8112 sizeof 8113 (xmlRegExecCtxtPtr)); 8114 if (ctxt->elemTab == NULL) { 8115 xmlRngVErrMemory(ctxt, "validating\n"); 8116 return (-1); 8117 } 8118 } 8119 if (ctxt->elemNr >= ctxt->elemMax) { 8120 ctxt->elemMax *= 2; 8121 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab, 8122 ctxt->elemMax * 8123 sizeof 8124 (xmlRegExecCtxtPtr)); 8125 if (ctxt->elemTab == NULL) { 8126 xmlRngVErrMemory(ctxt, "validating\n"); 8127 return (-1); 8128 } 8129 } 8130 ctxt->elemTab[ctxt->elemNr++] = exec; 8131 ctxt->elem = exec; 8132 return (0); 8133 } 8134 8135 /** 8136 * xmlRelaxNGElemPop: 8137 * @ctxt: the validation context 8138 * 8139 * Pop the regexp of the current node content model from the stack 8140 * 8141 * Returns the exec or NULL if empty 8142 */ 8143 static xmlRegExecCtxtPtr 8144 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) 8145 { 8146 xmlRegExecCtxtPtr ret; 8147 8148 if (ctxt->elemNr <= 0) 8149 return (NULL); 8150 ctxt->elemNr--; 8151 ret = ctxt->elemTab[ctxt->elemNr]; 8152 ctxt->elemTab[ctxt->elemNr] = NULL; 8153 if (ctxt->elemNr > 0) 8154 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1]; 8155 else 8156 ctxt->elem = NULL; 8157 return (ret); 8158 } 8159 8160 /** 8161 * xmlRelaxNGValidateProgressiveCallback: 8162 * @exec: the regular expression instance 8163 * @token: the token which matched 8164 * @transdata: callback data, the define for the subelement if available 8165 @ @inputdata: callback data, the Relax NG validation context 8166 * 8167 * Handle the callback and if needed validate the element children. 8168 * some of the in/out information are passed via the context in @inputdata. 8169 */ 8170 static void 8171 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec 8172 ATTRIBUTE_UNUSED, 8173 const xmlChar * token, 8174 void *transdata, void *inputdata) 8175 { 8176 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; 8177 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; 8178 xmlRelaxNGValidStatePtr state, oldstate; 8179 xmlNodePtr node; 8180 int ret = 0, oldflags; 8181 8182 #ifdef DEBUG_PROGRESSIVE 8183 xmlGenericError(xmlGenericErrorContext, 8184 "Progressive callback for: '%s'\n", token); 8185 #endif 8186 if (ctxt == NULL) { 8187 fprintf(stderr, "callback on %s missing context\n", token); 8188 return; 8189 } 8190 node = ctxt->pnode; 8191 ctxt->pstate = 1; 8192 if (define == NULL) { 8193 if (token[0] == '#') 8194 return; 8195 fprintf(stderr, "callback on %s missing define\n", token); 8196 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 8197 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 8198 ctxt->pstate = -1; 8199 return; 8200 } 8201 if ((ctxt == NULL) || (define == NULL)) { 8202 fprintf(stderr, "callback on %s missing info\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 } else if (define->type != XML_RELAXNG_ELEMENT) { 8208 fprintf(stderr, "callback on %s define is not element\n", token); 8209 if (ctxt->errNo == XML_RELAXNG_OK) 8210 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 8211 ctxt->pstate = -1; 8212 return; 8213 } 8214 if (node->type != XML_ELEMENT_NODE) { 8215 VALID_ERR(XML_RELAXNG_ERR_NOTELEM); 8216 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8217 xmlRelaxNGDumpValidError(ctxt); 8218 ctxt->pstate = -1; 8219 return; 8220 } 8221 if (define->contModel == NULL) { 8222 /* 8223 * this node cannot be validated in a streamable fashion 8224 */ 8225 #ifdef DEBUG_PROGRESSIVE 8226 xmlGenericError(xmlGenericErrorContext, 8227 "Element '%s' validation is not streamable\n", 8228 token); 8229 #endif 8230 ctxt->pstate = 0; 8231 ctxt->pdef = define; 8232 return; 8233 } 8234 exec = xmlRegNewExecCtxt(define->contModel, 8235 xmlRelaxNGValidateProgressiveCallback, ctxt); 8236 if (exec == NULL) { 8237 ctxt->pstate = -1; 8238 return; 8239 } 8240 xmlRelaxNGElemPush(ctxt, exec); 8241 8242 /* 8243 * Validate the attributes part of the content. 8244 */ 8245 state = xmlRelaxNGNewValidState(ctxt, node); 8246 if (state == NULL) { 8247 ctxt->pstate = -1; 8248 return; 8249 } 8250 oldstate = ctxt->state; 8251 ctxt->state = state; 8252 if (define->attrs != NULL) { 8253 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); 8254 if (ret != 0) { 8255 ctxt->pstate = -1; 8256 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); 8257 } 8258 } 8259 if (ctxt->state != NULL) { 8260 ctxt->state->seq = NULL; 8261 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 8262 if (ret != 0) { 8263 ctxt->pstate = -1; 8264 } 8265 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 8266 } else if (ctxt->states != NULL) { 8267 int tmp = -1, i; 8268 8269 oldflags = ctxt->flags; 8270 8271 for (i = 0; i < ctxt->states->nbState; i++) { 8272 state = ctxt->states->tabState[i]; 8273 ctxt->state = state; 8274 ctxt->state->seq = NULL; 8275 8276 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 8277 tmp = 0; 8278 break; 8279 } 8280 } 8281 if (tmp != 0) { 8282 /* 8283 * validation error, log the message for the "best" one 8284 */ 8285 ctxt->flags |= FLAGS_IGNORABLE; 8286 xmlRelaxNGLogBestError(ctxt); 8287 } 8288 for (i = 0; i < ctxt->states->nbState; i++) { 8289 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]); 8290 } 8291 xmlRelaxNGFreeStates(ctxt, ctxt->states); 8292 ctxt->states = NULL; 8293 if ((ret == 0) && (tmp == -1)) 8294 ctxt->pstate = -1; 8295 ctxt->flags = oldflags; 8296 } 8297 if (ctxt->pstate == -1) { 8298 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 8299 xmlRelaxNGDumpValidError(ctxt); 8300 } 8301 } 8302 ctxt->state = oldstate; 8303 } 8304 8305 /** 8306 * xmlRelaxNGValidatePushElement: 8307 * @ctxt: the validation context 8308 * @doc: a document instance 8309 * @elem: an element instance 8310 * 8311 * Push a new element start on the RelaxNG validation stack. 8312 * 8313 * returns 1 if no validation problem was found or 0 if validating the 8314 * element requires a full node, and -1 in case of error. 8315 */ 8316 int 8317 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, 8318 xmlDocPtr doc ATTRIBUTE_UNUSED, 8319 xmlNodePtr elem) 8320 { 8321 int ret = 1; 8322 8323 if ((ctxt == NULL) || (elem == NULL)) 8324 return (-1); 8325 8326 #ifdef DEBUG_PROGRESSIVE 8327 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name); 8328 #endif 8329 if (ctxt->elem == 0) { 8330 xmlRelaxNGPtr schema; 8331 xmlRelaxNGGrammarPtr grammar; 8332 xmlRegExecCtxtPtr exec; 8333 xmlRelaxNGDefinePtr define; 8334 8335 schema = ctxt->schema; 8336 if (schema == NULL) { 8337 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 8338 return (-1); 8339 } 8340 grammar = schema->topgrammar; 8341 if ((grammar == NULL) || (grammar->start == NULL)) { 8342 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 8343 return (-1); 8344 } 8345 define = grammar->start; 8346 if (define->contModel == NULL) { 8347 ctxt->pdef = define; 8348 return (0); 8349 } 8350 exec = xmlRegNewExecCtxt(define->contModel, 8351 xmlRelaxNGValidateProgressiveCallback, 8352 ctxt); 8353 if (exec == NULL) { 8354 return (-1); 8355 } 8356 xmlRelaxNGElemPush(ctxt, exec); 8357 } 8358 ctxt->pnode = elem; 8359 ctxt->pstate = 0; 8360 if (elem->ns != NULL) { 8361 ret = 8362 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href, 8363 ctxt); 8364 } else { 8365 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt); 8366 } 8367 if (ret < 0) { 8368 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name); 8369 } else { 8370 if (ctxt->pstate == 0) 8371 ret = 0; 8372 else if (ctxt->pstate < 0) 8373 ret = -1; 8374 else 8375 ret = 1; 8376 } 8377 #ifdef DEBUG_PROGRESSIVE 8378 if (ret < 0) 8379 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n", 8380 elem->name); 8381 #endif 8382 return (ret); 8383 } 8384 8385 /** 8386 * xmlRelaxNGValidatePushCData: 8387 * @ctxt: the RelaxNG validation context 8388 * @data: some character data read 8389 * @len: the length of the data 8390 * 8391 * check the CData parsed for validation in the current stack 8392 * 8393 * returns 1 if no validation problem was found or -1 otherwise 8394 */ 8395 int 8396 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, 8397 const xmlChar * data, int len ATTRIBUTE_UNUSED) 8398 { 8399 int ret = 1; 8400 8401 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL)) 8402 return (-1); 8403 8404 #ifdef DEBUG_PROGRESSIVE 8405 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len); 8406 #endif 8407 8408 while (*data != 0) { 8409 if (!IS_BLANK_CH(*data)) 8410 break; 8411 data++; 8412 } 8413 if (*data == 0) 8414 return (1); 8415 8416 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt); 8417 if (ret < 0) { 8418 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO "); 8419 #ifdef DEBUG_PROGRESSIVE 8420 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n"); 8421 #endif 8422 8423 return (-1); 8424 } 8425 return (1); 8426 } 8427 8428 /** 8429 * xmlRelaxNGValidatePopElement: 8430 * @ctxt: the RelaxNG validation context 8431 * @doc: a document instance 8432 * @elem: an element instance 8433 * 8434 * Pop the element end from the RelaxNG validation stack. 8435 * 8436 * returns 1 if no validation problem was found or 0 otherwise 8437 */ 8438 int 8439 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, 8440 xmlDocPtr doc ATTRIBUTE_UNUSED, 8441 xmlNodePtr elem) 8442 { 8443 int ret; 8444 xmlRegExecCtxtPtr exec; 8445 8446 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) 8447 return (-1); 8448 #ifdef DEBUG_PROGRESSIVE 8449 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name); 8450 #endif 8451 /* 8452 * verify that we reached a terminal state of the content model. 8453 */ 8454 exec = xmlRelaxNGElemPop(ctxt); 8455 ret = xmlRegExecPushString(exec, NULL, NULL); 8456 if (ret == 0) { 8457 /* 8458 * TODO: get some of the names needed to exit the current state of exec 8459 */ 8460 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); 8461 ret = -1; 8462 } else if (ret < 0) { 8463 ret = -1; 8464 } else { 8465 ret = 1; 8466 } 8467 xmlRegFreeExecCtxt(exec); 8468 #ifdef DEBUG_PROGRESSIVE 8469 if (ret < 0) 8470 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n", 8471 elem->name); 8472 #endif 8473 return (ret); 8474 } 8475 8476 /** 8477 * xmlRelaxNGValidateFullElement: 8478 * @ctxt: the validation context 8479 * @doc: a document instance 8480 * @elem: an element instance 8481 * 8482 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned 8483 * 0 and the content of the node has been expanded. 8484 * 8485 * returns 1 if no validation problem was found or -1 in case of error. 8486 */ 8487 int 8488 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, 8489 xmlDocPtr doc ATTRIBUTE_UNUSED, 8490 xmlNodePtr elem) 8491 { 8492 int ret; 8493 xmlRelaxNGValidStatePtr state; 8494 8495 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) 8496 return (-1); 8497 #ifdef DEBUG_PROGRESSIVE 8498 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name); 8499 #endif 8500 state = xmlRelaxNGNewValidState(ctxt, elem->parent); 8501 if (state == NULL) { 8502 return (-1); 8503 } 8504 state->seq = elem; 8505 ctxt->state = state; 8506 ctxt->errNo = XML_RELAXNG_OK; 8507 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef); 8508 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) 8509 ret = -1; 8510 else 8511 ret = 1; 8512 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 8513 ctxt->state = NULL; 8514 #ifdef DEBUG_PROGRESSIVE 8515 if (ret < 0) 8516 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n", 8517 elem->name); 8518 #endif 8519 return (ret); 8520 } 8521 8522 /************************************************************************ 8523 * * 8524 * Generic interpreted validation implementation * 8525 * * 8526 ************************************************************************/ 8527 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 8528 xmlRelaxNGDefinePtr define); 8529 8530 /** 8531 * xmlRelaxNGSkipIgnored: 8532 * @ctxt: a schema validation context 8533 * @node: the top node. 8534 * 8535 * Skip ignorable nodes in that context 8536 * 8537 * Returns the new sibling or NULL in case of error. 8538 */ 8539 static xmlNodePtr 8540 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 8541 xmlNodePtr node) 8542 { 8543 /* 8544 * TODO complete and handle entities 8545 */ 8546 while ((node != NULL) && 8547 ((node->type == XML_COMMENT_NODE) || 8548 (node->type == XML_PI_NODE) || 8549 (node->type == XML_XINCLUDE_START) || 8550 (node->type == XML_XINCLUDE_END) || 8551 (((node->type == XML_TEXT_NODE) || 8552 (node->type == XML_CDATA_SECTION_NODE)) && 8553 ((ctxt->flags & FLAGS_MIXED_CONTENT) || 8554 (IS_BLANK_NODE(node)))))) { 8555 node = node->next; 8556 } 8557 return (node); 8558 } 8559 8560 /** 8561 * xmlRelaxNGNormalize: 8562 * @ctxt: a schema validation context 8563 * @str: the string to normalize 8564 * 8565 * Implements the normalizeWhiteSpace( s ) function from 8566 * section 6.2.9 of the spec 8567 * 8568 * Returns the new string or NULL in case of error. 8569 */ 8570 static xmlChar * 8571 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str) 8572 { 8573 xmlChar *ret, *p; 8574 const xmlChar *tmp; 8575 int len; 8576 8577 if (str == NULL) 8578 return (NULL); 8579 tmp = str; 8580 while (*tmp != 0) 8581 tmp++; 8582 len = tmp - str; 8583 8584 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); 8585 if (ret == NULL) { 8586 xmlRngVErrMemory(ctxt, "validating\n"); 8587 return (NULL); 8588 } 8589 p = ret; 8590 while (IS_BLANK_CH(*str)) 8591 str++; 8592 while (*str != 0) { 8593 if (IS_BLANK_CH(*str)) { 8594 while (IS_BLANK_CH(*str)) 8595 str++; 8596 if (*str == 0) 8597 break; 8598 *p++ = ' '; 8599 } else 8600 *p++ = *str++; 8601 } 8602 *p = 0; 8603 return (ret); 8604 } 8605 8606 /** 8607 * xmlRelaxNGValidateDatatype: 8608 * @ctxt: a Relax-NG validation context 8609 * @value: the string value 8610 * @type: the datatype definition 8611 * @node: the node 8612 * 8613 * Validate the given value against the datatype 8614 * 8615 * Returns 0 if the validation succeeded or an error code. 8616 */ 8617 static int 8618 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, 8619 const xmlChar * value, 8620 xmlRelaxNGDefinePtr define, xmlNodePtr node) 8621 { 8622 int ret, tmp; 8623 xmlRelaxNGTypeLibraryPtr lib; 8624 void *result = NULL; 8625 xmlRelaxNGDefinePtr cur; 8626 8627 if ((define == NULL) || (define->data == NULL)) { 8628 return (-1); 8629 } 8630 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 8631 if (lib->check != NULL) { 8632 if ((define->attrs != NULL) && 8633 (define->attrs->type == XML_RELAXNG_PARAM)) { 8634 ret = 8635 lib->check(lib->data, define->name, value, &result, node); 8636 } else { 8637 ret = lib->check(lib->data, define->name, value, NULL, node); 8638 } 8639 } else 8640 ret = -1; 8641 if (ret < 0) { 8642 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name); 8643 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) 8644 lib->freef(lib->data, result); 8645 return (-1); 8646 } else if (ret == 1) { 8647 ret = 0; 8648 } else if (ret == 2) { 8649 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value); 8650 } else { 8651 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value); 8652 ret = -1; 8653 } 8654 cur = define->attrs; 8655 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) { 8656 if (lib->facet != NULL) { 8657 tmp = lib->facet(lib->data, define->name, cur->name, 8658 cur->value, value, result); 8659 if (tmp != 0) 8660 ret = -1; 8661 } 8662 cur = cur->next; 8663 } 8664 if ((ret == 0) && (define->content != NULL)) { 8665 const xmlChar *oldvalue, *oldendvalue; 8666 8667 oldvalue = ctxt->state->value; 8668 oldendvalue = ctxt->state->endvalue; 8669 ctxt->state->value = (xmlChar *) value; 8670 ctxt->state->endvalue = NULL; 8671 ret = xmlRelaxNGValidateValue(ctxt, define->content); 8672 ctxt->state->value = (xmlChar *) oldvalue; 8673 ctxt->state->endvalue = (xmlChar *) oldendvalue; 8674 } 8675 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) 8676 lib->freef(lib->data, result); 8677 return (ret); 8678 } 8679 8680 /** 8681 * xmlRelaxNGNextValue: 8682 * @ctxt: a Relax-NG validation context 8683 * 8684 * Skip to the next value when validating within a list 8685 * 8686 * Returns 0 if the operation succeeded or an error code. 8687 */ 8688 static int 8689 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) 8690 { 8691 xmlChar *cur; 8692 8693 cur = ctxt->state->value; 8694 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) { 8695 ctxt->state->value = NULL; 8696 ctxt->state->endvalue = NULL; 8697 return (0); 8698 } 8699 while (*cur != 0) 8700 cur++; 8701 while ((cur != ctxt->state->endvalue) && (*cur == 0)) 8702 cur++; 8703 if (cur == ctxt->state->endvalue) 8704 ctxt->state->value = NULL; 8705 else 8706 ctxt->state->value = cur; 8707 return (0); 8708 } 8709 8710 /** 8711 * xmlRelaxNGValidateValueList: 8712 * @ctxt: a Relax-NG validation context 8713 * @defines: the list of definitions to verify 8714 * 8715 * Validate the given set of definitions for the current value 8716 * 8717 * Returns 0 if the validation succeeded or an error code. 8718 */ 8719 static int 8720 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, 8721 xmlRelaxNGDefinePtr defines) 8722 { 8723 int ret = 0; 8724 8725 while (defines != NULL) { 8726 ret = xmlRelaxNGValidateValue(ctxt, defines); 8727 if (ret != 0) 8728 break; 8729 defines = defines->next; 8730 } 8731 return (ret); 8732 } 8733 8734 /** 8735 * xmlRelaxNGValidateValue: 8736 * @ctxt: a Relax-NG validation context 8737 * @define: the definition to verify 8738 * 8739 * Validate the given definition for the current value 8740 * 8741 * Returns 0 if the validation succeeded or an error code. 8742 */ 8743 static int 8744 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 8745 xmlRelaxNGDefinePtr define) 8746 { 8747 int ret = 0, oldflags; 8748 xmlChar *value; 8749 8750 value = ctxt->state->value; 8751 switch (define->type) { 8752 case XML_RELAXNG_EMPTY:{ 8753 if ((value != NULL) && (value[0] != 0)) { 8754 int idx = 0; 8755 8756 while (IS_BLANK_CH(value[idx])) 8757 idx++; 8758 if (value[idx] != 0) 8759 ret = -1; 8760 } 8761 break; 8762 } 8763 case XML_RELAXNG_TEXT: 8764 break; 8765 case XML_RELAXNG_VALUE:{ 8766 if (!xmlStrEqual(value, define->value)) { 8767 if (define->name != NULL) { 8768 xmlRelaxNGTypeLibraryPtr lib; 8769 8770 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 8771 if ((lib != NULL) && (lib->comp != NULL)) { 8772 ret = lib->comp(lib->data, define->name, 8773 define->value, define->node, 8774 (void *) define->attrs, 8775 value, ctxt->state->node); 8776 } else 8777 ret = -1; 8778 if (ret < 0) { 8779 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, 8780 define->name); 8781 return (-1); 8782 } else if (ret == 1) { 8783 ret = 0; 8784 } else { 8785 ret = -1; 8786 } 8787 } else { 8788 xmlChar *nval, *nvalue; 8789 8790 /* 8791 * TODO: trivial optimizations are possible by 8792 * computing at compile-time 8793 */ 8794 nval = xmlRelaxNGNormalize(ctxt, define->value); 8795 nvalue = xmlRelaxNGNormalize(ctxt, value); 8796 8797 if ((nval == NULL) || (nvalue == NULL) || 8798 (!xmlStrEqual(nval, nvalue))) 8799 ret = -1; 8800 if (nval != NULL) 8801 xmlFree(nval); 8802 if (nvalue != NULL) 8803 xmlFree(nvalue); 8804 } 8805 } 8806 if (ret == 0) 8807 xmlRelaxNGNextValue(ctxt); 8808 break; 8809 } 8810 case XML_RELAXNG_DATATYPE:{ 8811 ret = xmlRelaxNGValidateDatatype(ctxt, value, define, 8812 ctxt->state->seq); 8813 if (ret == 0) 8814 xmlRelaxNGNextValue(ctxt); 8815 8816 break; 8817 } 8818 case XML_RELAXNG_CHOICE:{ 8819 xmlRelaxNGDefinePtr list = define->content; 8820 xmlChar *oldvalue; 8821 8822 oldflags = ctxt->flags; 8823 ctxt->flags |= FLAGS_IGNORABLE; 8824 8825 oldvalue = ctxt->state->value; 8826 while (list != NULL) { 8827 ret = xmlRelaxNGValidateValue(ctxt, list); 8828 if (ret == 0) { 8829 break; 8830 } 8831 ctxt->state->value = oldvalue; 8832 list = list->next; 8833 } 8834 ctxt->flags = oldflags; 8835 if (ret != 0) { 8836 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8837 xmlRelaxNGDumpValidError(ctxt); 8838 } else { 8839 if (ctxt->errNr > 0) 8840 xmlRelaxNGPopErrors(ctxt, 0); 8841 } 8842 break; 8843 } 8844 case XML_RELAXNG_LIST:{ 8845 xmlRelaxNGDefinePtr list = define->content; 8846 xmlChar *oldvalue, *oldend, *val, *cur; 8847 8848 #ifdef DEBUG_LIST 8849 int nb_values = 0; 8850 #endif 8851 8852 oldvalue = ctxt->state->value; 8853 oldend = ctxt->state->endvalue; 8854 8855 val = xmlStrdup(oldvalue); 8856 if (val == NULL) { 8857 val = xmlStrdup(BAD_CAST ""); 8858 } 8859 if (val == NULL) { 8860 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 8861 return (-1); 8862 } 8863 cur = val; 8864 while (*cur != 0) { 8865 if (IS_BLANK_CH(*cur)) { 8866 *cur = 0; 8867 cur++; 8868 #ifdef DEBUG_LIST 8869 nb_values++; 8870 #endif 8871 while (IS_BLANK_CH(*cur)) 8872 *cur++ = 0; 8873 } else 8874 cur++; 8875 } 8876 #ifdef DEBUG_LIST 8877 xmlGenericError(xmlGenericErrorContext, 8878 "list value: '%s' found %d items\n", 8879 oldvalue, nb_values); 8880 nb_values = 0; 8881 #endif 8882 ctxt->state->endvalue = cur; 8883 cur = val; 8884 while ((*cur == 0) && (cur != ctxt->state->endvalue)) 8885 cur++; 8886 8887 ctxt->state->value = cur; 8888 8889 while (list != NULL) { 8890 if (ctxt->state->value == ctxt->state->endvalue) 8891 ctxt->state->value = NULL; 8892 ret = xmlRelaxNGValidateValue(ctxt, list); 8893 if (ret != 0) { 8894 #ifdef DEBUG_LIST 8895 xmlGenericError(xmlGenericErrorContext, 8896 "Failed to validate value: '%s' with %d rule\n", 8897 ctxt->state->value, nb_values); 8898 #endif 8899 break; 8900 } 8901 #ifdef DEBUG_LIST 8902 nb_values++; 8903 #endif 8904 list = list->next; 8905 } 8906 8907 if ((ret == 0) && (ctxt->state->value != NULL) && 8908 (ctxt->state->value != ctxt->state->endvalue)) { 8909 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, 8910 ctxt->state->value); 8911 ret = -1; 8912 } 8913 xmlFree(val); 8914 ctxt->state->value = oldvalue; 8915 ctxt->state->endvalue = oldend; 8916 break; 8917 } 8918 case XML_RELAXNG_ONEORMORE: 8919 ret = xmlRelaxNGValidateValueList(ctxt, define->content); 8920 if (ret != 0) { 8921 break; 8922 } 8923 /* Falls through. */ 8924 case XML_RELAXNG_ZEROORMORE:{ 8925 xmlChar *cur, *temp; 8926 8927 if ((ctxt->state->value == NULL) || 8928 (*ctxt->state->value == 0)) { 8929 ret = 0; 8930 break; 8931 } 8932 oldflags = ctxt->flags; 8933 ctxt->flags |= FLAGS_IGNORABLE; 8934 cur = ctxt->state->value; 8935 temp = NULL; 8936 while ((cur != NULL) && (cur != ctxt->state->endvalue) && 8937 (temp != cur)) { 8938 temp = cur; 8939 ret = 8940 xmlRelaxNGValidateValueList(ctxt, define->content); 8941 if (ret != 0) { 8942 ctxt->state->value = temp; 8943 ret = 0; 8944 break; 8945 } 8946 cur = ctxt->state->value; 8947 } 8948 ctxt->flags = oldflags; 8949 if (ctxt->errNr > 0) 8950 xmlRelaxNGPopErrors(ctxt, 0); 8951 break; 8952 } 8953 case XML_RELAXNG_OPTIONAL:{ 8954 xmlChar *temp; 8955 8956 if ((ctxt->state->value == NULL) || 8957 (*ctxt->state->value == 0)) { 8958 ret = 0; 8959 break; 8960 } 8961 oldflags = ctxt->flags; 8962 ctxt->flags |= FLAGS_IGNORABLE; 8963 temp = ctxt->state->value; 8964 ret = xmlRelaxNGValidateValue(ctxt, define->content); 8965 ctxt->flags = oldflags; 8966 if (ret != 0) { 8967 ctxt->state->value = temp; 8968 if (ctxt->errNr > 0) 8969 xmlRelaxNGPopErrors(ctxt, 0); 8970 ret = 0; 8971 break; 8972 } 8973 if (ctxt->errNr > 0) 8974 xmlRelaxNGPopErrors(ctxt, 0); 8975 break; 8976 } 8977 case XML_RELAXNG_EXCEPT:{ 8978 xmlRelaxNGDefinePtr list; 8979 8980 list = define->content; 8981 while (list != NULL) { 8982 ret = xmlRelaxNGValidateValue(ctxt, list); 8983 if (ret == 0) { 8984 ret = -1; 8985 break; 8986 } else 8987 ret = 0; 8988 list = list->next; 8989 } 8990 break; 8991 } 8992 case XML_RELAXNG_DEF: 8993 case XML_RELAXNG_GROUP:{ 8994 xmlRelaxNGDefinePtr list; 8995 8996 list = define->content; 8997 while (list != NULL) { 8998 ret = xmlRelaxNGValidateValue(ctxt, list); 8999 if (ret != 0) { 9000 ret = -1; 9001 break; 9002 } else 9003 ret = 0; 9004 list = list->next; 9005 } 9006 break; 9007 } 9008 case XML_RELAXNG_REF: 9009 case XML_RELAXNG_PARENTREF: 9010 if (define->content == NULL) { 9011 VALID_ERR(XML_RELAXNG_ERR_NODEFINE); 9012 ret = -1; 9013 } else { 9014 ret = xmlRelaxNGValidateValue(ctxt, define->content); 9015 } 9016 break; 9017 default: 9018 TODO ret = -1; 9019 } 9020 return (ret); 9021 } 9022 9023 /** 9024 * xmlRelaxNGValidateValueContent: 9025 * @ctxt: a Relax-NG validation context 9026 * @defines: the list of definitions to verify 9027 * 9028 * Validate the given definitions for the current value 9029 * 9030 * Returns 0 if the validation succeeded or an error code. 9031 */ 9032 static int 9033 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, 9034 xmlRelaxNGDefinePtr defines) 9035 { 9036 int ret = 0; 9037 9038 while (defines != NULL) { 9039 ret = xmlRelaxNGValidateValue(ctxt, defines); 9040 if (ret != 0) 9041 break; 9042 defines = defines->next; 9043 } 9044 return (ret); 9045 } 9046 9047 /** 9048 * xmlRelaxNGAttributeMatch: 9049 * @ctxt: a Relax-NG validation context 9050 * @define: the definition to check 9051 * @prop: the attribute 9052 * 9053 * Check if the attribute matches the definition nameClass 9054 * 9055 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error 9056 */ 9057 static int 9058 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, 9059 xmlRelaxNGDefinePtr define, xmlAttrPtr prop) 9060 { 9061 int ret; 9062 9063 if (define->name != NULL) { 9064 if (!xmlStrEqual(define->name, prop->name)) 9065 return (0); 9066 } 9067 if (define->ns != NULL) { 9068 if (define->ns[0] == 0) { 9069 if (prop->ns != NULL) 9070 return (0); 9071 } else { 9072 if ((prop->ns == NULL) || 9073 (!xmlStrEqual(define->ns, prop->ns->href))) 9074 return (0); 9075 } 9076 } 9077 if (define->nameClass == NULL) 9078 return (1); 9079 define = define->nameClass; 9080 if (define->type == XML_RELAXNG_EXCEPT) { 9081 xmlRelaxNGDefinePtr list; 9082 9083 list = define->content; 9084 while (list != NULL) { 9085 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); 9086 if (ret == 1) 9087 return (0); 9088 if (ret < 0) 9089 return (ret); 9090 list = list->next; 9091 } 9092 } else if (define->type == XML_RELAXNG_CHOICE) { 9093 xmlRelaxNGDefinePtr list; 9094 9095 list = define->nameClass; 9096 while (list != NULL) { 9097 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); 9098 if (ret == 1) 9099 return (1); 9100 if (ret < 0) 9101 return (ret); 9102 list = list->next; 9103 } 9104 return (0); 9105 } else { 9106 TODO} 9107 return (1); 9108 } 9109 9110 /** 9111 * xmlRelaxNGValidateAttribute: 9112 * @ctxt: a Relax-NG validation context 9113 * @define: the definition to verify 9114 * 9115 * Validate the given attribute definition for that node 9116 * 9117 * Returns 0 if the validation succeeded or an error code. 9118 */ 9119 static int 9120 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, 9121 xmlRelaxNGDefinePtr define) 9122 { 9123 int ret = 0, i; 9124 xmlChar *value, *oldvalue; 9125 xmlAttrPtr prop = NULL, tmp; 9126 xmlNodePtr oldseq; 9127 9128 if (ctxt->state->nbAttrLeft <= 0) 9129 return (-1); 9130 if (define->name != NULL) { 9131 for (i = 0; i < ctxt->state->nbAttrs; i++) { 9132 tmp = ctxt->state->attrs[i]; 9133 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) { 9134 if ((((define->ns == NULL) || (define->ns[0] == 0)) && 9135 (tmp->ns == NULL)) || 9136 ((tmp->ns != NULL) && 9137 (xmlStrEqual(define->ns, tmp->ns->href)))) { 9138 prop = tmp; 9139 break; 9140 } 9141 } 9142 } 9143 if (prop != NULL) { 9144 value = xmlNodeListGetString(prop->doc, prop->children, 1); 9145 oldvalue = ctxt->state->value; 9146 oldseq = ctxt->state->seq; 9147 ctxt->state->seq = (xmlNodePtr) prop; 9148 ctxt->state->value = value; 9149 ctxt->state->endvalue = NULL; 9150 ret = xmlRelaxNGValidateValueContent(ctxt, define->content); 9151 if (ctxt->state->value != NULL) 9152 value = ctxt->state->value; 9153 if (value != NULL) 9154 xmlFree(value); 9155 ctxt->state->value = oldvalue; 9156 ctxt->state->seq = oldseq; 9157 if (ret == 0) { 9158 /* 9159 * flag the attribute as processed 9160 */ 9161 ctxt->state->attrs[i] = NULL; 9162 ctxt->state->nbAttrLeft--; 9163 } 9164 } else { 9165 ret = -1; 9166 } 9167 #ifdef DEBUG 9168 xmlGenericError(xmlGenericErrorContext, 9169 "xmlRelaxNGValidateAttribute(%s): %d\n", 9170 define->name, ret); 9171 #endif 9172 } else { 9173 for (i = 0; i < ctxt->state->nbAttrs; i++) { 9174 tmp = ctxt->state->attrs[i]; 9175 if ((tmp != NULL) && 9176 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) { 9177 prop = tmp; 9178 break; 9179 } 9180 } 9181 if (prop != NULL) { 9182 value = xmlNodeListGetString(prop->doc, prop->children, 1); 9183 oldvalue = ctxt->state->value; 9184 oldseq = ctxt->state->seq; 9185 ctxt->state->seq = (xmlNodePtr) prop; 9186 ctxt->state->value = value; 9187 ret = xmlRelaxNGValidateValueContent(ctxt, define->content); 9188 if (ctxt->state->value != NULL) 9189 value = ctxt->state->value; 9190 if (value != NULL) 9191 xmlFree(value); 9192 ctxt->state->value = oldvalue; 9193 ctxt->state->seq = oldseq; 9194 if (ret == 0) { 9195 /* 9196 * flag the attribute as processed 9197 */ 9198 ctxt->state->attrs[i] = NULL; 9199 ctxt->state->nbAttrLeft--; 9200 } 9201 } else { 9202 ret = -1; 9203 } 9204 #ifdef DEBUG 9205 if (define->ns != NULL) { 9206 xmlGenericError(xmlGenericErrorContext, 9207 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", 9208 define->ns, ret); 9209 } else { 9210 xmlGenericError(xmlGenericErrorContext, 9211 "xmlRelaxNGValidateAttribute(anyName): %d\n", 9212 ret); 9213 } 9214 #endif 9215 } 9216 9217 return (ret); 9218 } 9219 9220 /** 9221 * xmlRelaxNGValidateAttributeList: 9222 * @ctxt: a Relax-NG validation context 9223 * @define: the list of definition to verify 9224 * 9225 * Validate the given node against the list of attribute definitions 9226 * 9227 * Returns 0 if the validation succeeded or an error code. 9228 */ 9229 static int 9230 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 9231 xmlRelaxNGDefinePtr defines) 9232 { 9233 int ret = 0, res; 9234 int needmore = 0; 9235 xmlRelaxNGDefinePtr cur; 9236 9237 cur = defines; 9238 while (cur != NULL) { 9239 if (cur->type == XML_RELAXNG_ATTRIBUTE) { 9240 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0) 9241 ret = -1; 9242 } else 9243 needmore = 1; 9244 cur = cur->next; 9245 } 9246 if (!needmore) 9247 return (ret); 9248 cur = defines; 9249 while (cur != NULL) { 9250 if (cur->type != XML_RELAXNG_ATTRIBUTE) { 9251 if ((ctxt->state != NULL) || (ctxt->states != NULL)) { 9252 res = xmlRelaxNGValidateDefinition(ctxt, cur); 9253 if (res < 0) 9254 ret = -1; 9255 } else { 9256 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 9257 return (-1); 9258 } 9259 if (res == -1) /* continues on -2 */ 9260 break; 9261 } 9262 cur = cur->next; 9263 } 9264 9265 return (ret); 9266 } 9267 9268 /** 9269 * xmlRelaxNGNodeMatchesList: 9270 * @node: the node 9271 * @list: a NULL terminated array of definitions 9272 * 9273 * Check if a node can be matched by one of the definitions 9274 * 9275 * Returns 1 if matches 0 otherwise 9276 */ 9277 static int 9278 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list) 9279 { 9280 xmlRelaxNGDefinePtr cur; 9281 int i = 0, tmp; 9282 9283 if ((node == NULL) || (list == NULL)) 9284 return (0); 9285 9286 cur = list[i++]; 9287 while (cur != NULL) { 9288 if ((node->type == XML_ELEMENT_NODE) && 9289 (cur->type == XML_RELAXNG_ELEMENT)) { 9290 tmp = xmlRelaxNGElementMatch(NULL, cur, node); 9291 if (tmp == 1) 9292 return (1); 9293 } else if (((node->type == XML_TEXT_NODE) || 9294 (node->type == XML_CDATA_SECTION_NODE)) && 9295 ((cur->type == XML_RELAXNG_DATATYPE) || 9296 (cur->type == XML_RELAXNG_LIST) || 9297 (cur->type == XML_RELAXNG_TEXT) || 9298 (cur->type == XML_RELAXNG_VALUE))) { 9299 return (1); 9300 } 9301 cur = list[i++]; 9302 } 9303 return (0); 9304 } 9305 9306 /** 9307 * xmlRelaxNGValidateInterleave: 9308 * @ctxt: a Relax-NG validation context 9309 * @define: the definition to verify 9310 * 9311 * Validate an interleave definition for a node. 9312 * 9313 * Returns 0 if the validation succeeded or an error code. 9314 */ 9315 static int 9316 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, 9317 xmlRelaxNGDefinePtr define) 9318 { 9319 int ret = 0, i, nbgroups; 9320 int errNr = ctxt->errNr; 9321 int oldflags; 9322 9323 xmlRelaxNGValidStatePtr oldstate; 9324 xmlRelaxNGPartitionPtr partitions; 9325 xmlRelaxNGInterleaveGroupPtr group = NULL; 9326 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem; 9327 xmlNodePtr *list = NULL, *lasts = NULL; 9328 9329 if (define->data != NULL) { 9330 partitions = (xmlRelaxNGPartitionPtr) define->data; 9331 nbgroups = partitions->nbgroups; 9332 } else { 9333 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA); 9334 return (-1); 9335 } 9336 /* 9337 * Optimizations for MIXED 9338 */ 9339 oldflags = ctxt->flags; 9340 if (define->dflags & IS_MIXED) { 9341 ctxt->flags |= FLAGS_MIXED_CONTENT; 9342 if (nbgroups == 2) { 9343 /* 9344 * this is a pure <mixed> case 9345 */ 9346 if (ctxt->state != NULL) 9347 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, 9348 ctxt->state->seq); 9349 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT) 9350 ret = xmlRelaxNGValidateDefinition(ctxt, 9351 partitions->groups[1]-> 9352 rule); 9353 else 9354 ret = xmlRelaxNGValidateDefinition(ctxt, 9355 partitions->groups[0]-> 9356 rule); 9357 if (ret == 0) { 9358 if (ctxt->state != NULL) 9359 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, 9360 ctxt->state-> 9361 seq); 9362 } 9363 ctxt->flags = oldflags; 9364 return (ret); 9365 } 9366 } 9367 9368 /* 9369 * Build arrays to store the first and last node of the chain 9370 * pertaining to each group 9371 */ 9372 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); 9373 if (list == NULL) { 9374 xmlRngVErrMemory(ctxt, "validating\n"); 9375 return (-1); 9376 } 9377 memset(list, 0, nbgroups * sizeof(xmlNodePtr)); 9378 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); 9379 if (lasts == NULL) { 9380 xmlRngVErrMemory(ctxt, "validating\n"); 9381 return (-1); 9382 } 9383 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); 9384 9385 /* 9386 * Walk the sequence of children finding the right group and 9387 * sorting them in sequences. 9388 */ 9389 cur = ctxt->state->seq; 9390 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9391 start = cur; 9392 while (cur != NULL) { 9393 ctxt->state->seq = cur; 9394 if ((partitions->triage != NULL) && 9395 (partitions->flags & IS_DETERMINIST)) { 9396 void *tmp = NULL; 9397 9398 if ((cur->type == XML_TEXT_NODE) || 9399 (cur->type == XML_CDATA_SECTION_NODE)) { 9400 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text", 9401 NULL); 9402 } else if (cur->type == XML_ELEMENT_NODE) { 9403 if (cur->ns != NULL) { 9404 tmp = xmlHashLookup2(partitions->triage, cur->name, 9405 cur->ns->href); 9406 if (tmp == NULL) 9407 tmp = xmlHashLookup2(partitions->triage, 9408 BAD_CAST "#any", 9409 cur->ns->href); 9410 } else 9411 tmp = 9412 xmlHashLookup2(partitions->triage, cur->name, 9413 NULL); 9414 if (tmp == NULL) 9415 tmp = 9416 xmlHashLookup2(partitions->triage, BAD_CAST "#any", 9417 NULL); 9418 } 9419 9420 if (tmp == NULL) { 9421 i = nbgroups; 9422 } else { 9423 i = ((ptrdiff_t) tmp) - 1; 9424 if (partitions->flags & IS_NEEDCHECK) { 9425 group = partitions->groups[i]; 9426 if (!xmlRelaxNGNodeMatchesList(cur, group->defs)) 9427 i = nbgroups; 9428 } 9429 } 9430 } else { 9431 for (i = 0; i < nbgroups; i++) { 9432 group = partitions->groups[i]; 9433 if (group == NULL) 9434 continue; 9435 if (xmlRelaxNGNodeMatchesList(cur, group->defs)) 9436 break; 9437 } 9438 } 9439 /* 9440 * We break as soon as an element not matched is found 9441 */ 9442 if (i >= nbgroups) { 9443 break; 9444 } 9445 if (lasts[i] != NULL) { 9446 lasts[i]->next = cur; 9447 lasts[i] = cur; 9448 } else { 9449 list[i] = cur; 9450 lasts[i] = cur; 9451 } 9452 if (cur->next != NULL) 9453 lastchg = cur->next; 9454 else 9455 lastchg = cur; 9456 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next); 9457 } 9458 if (ret != 0) { 9459 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); 9460 ret = -1; 9461 goto done; 9462 } 9463 lastelem = cur; 9464 oldstate = ctxt->state; 9465 for (i = 0; i < nbgroups; i++) { 9466 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate); 9467 if (ctxt->state == NULL) { 9468 ret = -1; 9469 break; 9470 } 9471 group = partitions->groups[i]; 9472 if (lasts[i] != NULL) { 9473 last = lasts[i]->next; 9474 lasts[i]->next = NULL; 9475 } 9476 ctxt->state->seq = list[i]; 9477 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule); 9478 if (ret != 0) 9479 break; 9480 if (ctxt->state != NULL) { 9481 cur = ctxt->state->seq; 9482 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9483 xmlRelaxNGFreeValidState(ctxt, oldstate); 9484 oldstate = ctxt->state; 9485 ctxt->state = NULL; 9486 if (cur != NULL 9487 /* there's a nasty violation of context-free unambiguities, 9488 since in open-name-class context, interleave in the 9489 production shall finish without caring about anything 9490 else that is OK to follow in that case -- it would 9491 otherwise get marked as "extra content" and would 9492 hence fail the validation, hence this perhaps 9493 dirty attempt to rectify such a situation */ 9494 && (define->parent->type != XML_RELAXNG_DEF 9495 || !xmlStrEqual(define->parent->name, 9496 (const xmlChar *) "open-name-class"))) { 9497 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); 9498 ret = -1; 9499 ctxt->state = oldstate; 9500 goto done; 9501 } 9502 } else if (ctxt->states != NULL) { 9503 int j; 9504 int found = 0; 9505 int best = -1; 9506 int lowattr = -1; 9507 9508 /* 9509 * PBM: what happen if there is attributes checks in the interleaves 9510 */ 9511 9512 for (j = 0; j < ctxt->states->nbState; j++) { 9513 cur = ctxt->states->tabState[j]->seq; 9514 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9515 if (cur == NULL) { 9516 if (found == 0) { 9517 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9518 best = j; 9519 } 9520 found = 1; 9521 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { 9522 /* try to keep the latest one to mach old heuristic */ 9523 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9524 best = j; 9525 } 9526 if (lowattr == 0) 9527 break; 9528 } else if (found == 0) { 9529 if (lowattr == -1) { 9530 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9531 best = j; 9532 } else 9533 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { 9534 /* try to keep the latest one to mach old heuristic */ 9535 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9536 best = j; 9537 } 9538 } 9539 } 9540 /* 9541 * BIG PBM: here we pick only one restarting point :-( 9542 */ 9543 if (ctxt->states->nbState > 0) { 9544 xmlRelaxNGFreeValidState(ctxt, oldstate); 9545 if (best != -1) { 9546 oldstate = ctxt->states->tabState[best]; 9547 ctxt->states->tabState[best] = NULL; 9548 } else { 9549 oldstate = 9550 ctxt->states->tabState[ctxt->states->nbState - 1]; 9551 ctxt->states->tabState[ctxt->states->nbState - 1] = NULL; 9552 ctxt->states->nbState--; 9553 } 9554 } 9555 for (j = 0; j < ctxt->states->nbState ; j++) { 9556 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]); 9557 } 9558 xmlRelaxNGFreeStates(ctxt, ctxt->states); 9559 ctxt->states = NULL; 9560 if (found == 0) { 9561 if (cur == NULL) { 9562 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, 9563 (const xmlChar *) "noname"); 9564 } else { 9565 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); 9566 } 9567 ret = -1; 9568 ctxt->state = oldstate; 9569 goto done; 9570 } 9571 } else { 9572 ret = -1; 9573 break; 9574 } 9575 if (lasts[i] != NULL) { 9576 lasts[i]->next = last; 9577 } 9578 } 9579 if (ctxt->state != NULL) 9580 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 9581 ctxt->state = oldstate; 9582 ctxt->state->seq = lastelem; 9583 if (ret != 0) { 9584 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); 9585 ret = -1; 9586 goto done; 9587 } 9588 9589 done: 9590 ctxt->flags = oldflags; 9591 /* 9592 * builds the next links chain from the prev one 9593 */ 9594 cur = lastchg; 9595 while (cur != NULL) { 9596 if ((cur == start) || (cur->prev == NULL)) 9597 break; 9598 cur->prev->next = cur; 9599 cur = cur->prev; 9600 } 9601 if (ret == 0) { 9602 if (ctxt->errNr > errNr) 9603 xmlRelaxNGPopErrors(ctxt, errNr); 9604 } 9605 9606 xmlFree(list); 9607 xmlFree(lasts); 9608 return (ret); 9609 } 9610 9611 /** 9612 * xmlRelaxNGValidateDefinitionList: 9613 * @ctxt: a Relax-NG validation context 9614 * @define: the list of definition to verify 9615 * 9616 * Validate the given node content against the (list) of definitions 9617 * 9618 * Returns 0 if the validation succeeded or an error code. 9619 */ 9620 static int 9621 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt, 9622 xmlRelaxNGDefinePtr defines) 9623 { 9624 int ret = 0, res; 9625 9626 9627 if (defines == NULL) { 9628 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, 9629 BAD_CAST "NULL definition list"); 9630 return (-1); 9631 } 9632 while (defines != NULL) { 9633 if ((ctxt->state != NULL) || (ctxt->states != NULL)) { 9634 res = xmlRelaxNGValidateDefinition(ctxt, defines); 9635 if (res < 0) 9636 ret = -1; 9637 } else { 9638 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 9639 return (-1); 9640 } 9641 if (res == -1) /* continues on -2 */ 9642 break; 9643 defines = defines->next; 9644 } 9645 9646 return (ret); 9647 } 9648 9649 /** 9650 * xmlRelaxNGElementMatch: 9651 * @ctxt: a Relax-NG validation context 9652 * @define: the definition to check 9653 * @elem: the element 9654 * 9655 * Check if the element matches the definition nameClass 9656 * 9657 * Returns 1 if the element matches, 0 if no, or -1 in case of error 9658 */ 9659 static int 9660 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 9661 xmlRelaxNGDefinePtr define, xmlNodePtr elem) 9662 { 9663 int ret = 0, oldflags = 0; 9664 9665 if (define->name != NULL) { 9666 if (!xmlStrEqual(elem->name, define->name)) { 9667 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name); 9668 return (0); 9669 } 9670 } 9671 if ((define->ns != NULL) && (define->ns[0] != 0)) { 9672 if (elem->ns == NULL) { 9673 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name); 9674 return (0); 9675 } else if (!xmlStrEqual(elem->ns->href, define->ns)) { 9676 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS, 9677 elem->name, define->ns); 9678 return (0); 9679 } 9680 } else if ((elem->ns != NULL) && (define->ns != NULL) && 9681 (define->name == NULL)) { 9682 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name); 9683 return (0); 9684 } else if ((elem->ns != NULL) && (define->name != NULL)) { 9685 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name); 9686 return (0); 9687 } 9688 9689 if (define->nameClass == NULL) 9690 return (1); 9691 9692 define = define->nameClass; 9693 if (define->type == XML_RELAXNG_EXCEPT) { 9694 xmlRelaxNGDefinePtr list; 9695 9696 if (ctxt != NULL) { 9697 oldflags = ctxt->flags; 9698 ctxt->flags |= FLAGS_IGNORABLE; 9699 } 9700 9701 list = define->content; 9702 while (list != NULL) { 9703 ret = xmlRelaxNGElementMatch(ctxt, list, elem); 9704 if (ret == 1) { 9705 if (ctxt != NULL) 9706 ctxt->flags = oldflags; 9707 return (0); 9708 } 9709 if (ret < 0) { 9710 if (ctxt != NULL) 9711 ctxt->flags = oldflags; 9712 return (ret); 9713 } 9714 list = list->next; 9715 } 9716 ret = 1; 9717 if (ctxt != NULL) { 9718 ctxt->flags = oldflags; 9719 } 9720 } else if (define->type == XML_RELAXNG_CHOICE) { 9721 xmlRelaxNGDefinePtr list; 9722 9723 if (ctxt != NULL) { 9724 oldflags = ctxt->flags; 9725 ctxt->flags |= FLAGS_IGNORABLE; 9726 } 9727 9728 list = define->nameClass; 9729 while (list != NULL) { 9730 ret = xmlRelaxNGElementMatch(ctxt, list, elem); 9731 if (ret == 1) { 9732 if (ctxt != NULL) 9733 ctxt->flags = oldflags; 9734 return (1); 9735 } 9736 if (ret < 0) { 9737 if (ctxt != NULL) 9738 ctxt->flags = oldflags; 9739 return (ret); 9740 } 9741 list = list->next; 9742 } 9743 if (ctxt != NULL) { 9744 if (ret != 0) { 9745 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9746 xmlRelaxNGDumpValidError(ctxt); 9747 } else { 9748 if (ctxt->errNr > 0) 9749 xmlRelaxNGPopErrors(ctxt, 0); 9750 } 9751 } 9752 ret = 0; 9753 if (ctxt != NULL) { 9754 ctxt->flags = oldflags; 9755 } 9756 } else { 9757 TODO ret = -1; 9758 } 9759 return (ret); 9760 } 9761 9762 /** 9763 * xmlRelaxNGBestState: 9764 * @ctxt: a Relax-NG validation context 9765 * 9766 * Find the "best" state in the ctxt->states list of states to report 9767 * errors about. I.e. a state with no element left in the child list 9768 * or the one with the less attributes left. 9769 * This is called only if a validation error was detected 9770 * 9771 * Returns the index of the "best" state or -1 in case of error 9772 */ 9773 static int 9774 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt) 9775 { 9776 xmlRelaxNGValidStatePtr state; 9777 int i, tmp; 9778 int best = -1; 9779 int value = 1000000; 9780 9781 if ((ctxt == NULL) || (ctxt->states == NULL) || 9782 (ctxt->states->nbState <= 0)) 9783 return (-1); 9784 9785 for (i = 0; i < ctxt->states->nbState; i++) { 9786 state = ctxt->states->tabState[i]; 9787 if (state == NULL) 9788 continue; 9789 if (state->seq != NULL) { 9790 if ((best == -1) || (value > 100000)) { 9791 value = 100000; 9792 best = i; 9793 } 9794 } else { 9795 tmp = state->nbAttrLeft; 9796 if ((best == -1) || (value > tmp)) { 9797 value = tmp; 9798 best = i; 9799 } 9800 } 9801 } 9802 return (best); 9803 } 9804 9805 /** 9806 * xmlRelaxNGLogBestError: 9807 * @ctxt: a Relax-NG validation context 9808 * 9809 * Find the "best" state in the ctxt->states list of states to report 9810 * errors about and log it. 9811 */ 9812 static void 9813 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt) 9814 { 9815 int best; 9816 9817 if ((ctxt == NULL) || (ctxt->states == NULL) || 9818 (ctxt->states->nbState <= 0)) 9819 return; 9820 9821 best = xmlRelaxNGBestState(ctxt); 9822 if ((best >= 0) && (best < ctxt->states->nbState)) { 9823 ctxt->state = ctxt->states->tabState[best]; 9824 9825 xmlRelaxNGValidateElementEnd(ctxt, 1); 9826 } 9827 } 9828 9829 /** 9830 * xmlRelaxNGValidateElementEnd: 9831 * @ctxt: a Relax-NG validation context 9832 * @dolog: indicate that error logging should be done 9833 * 9834 * Validate the end of the element, implements check that 9835 * there is nothing left not consumed in the element content 9836 * or in the attribute list. 9837 * 9838 * Returns 0 if the validation succeeded or an error code. 9839 */ 9840 static int 9841 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog) 9842 { 9843 int i; 9844 xmlRelaxNGValidStatePtr state; 9845 9846 state = ctxt->state; 9847 if (state->seq != NULL) { 9848 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq); 9849 if (state->seq != NULL) { 9850 if (dolog) { 9851 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT, 9852 state->node->name, state->seq->name); 9853 } 9854 return (-1); 9855 } 9856 } 9857 for (i = 0; i < state->nbAttrs; i++) { 9858 if (state->attrs[i] != NULL) { 9859 if (dolog) { 9860 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR, 9861 state->attrs[i]->name, state->node->name); 9862 } 9863 return (-1 - i); 9864 } 9865 } 9866 return (0); 9867 } 9868 9869 /** 9870 * xmlRelaxNGValidateState: 9871 * @ctxt: a Relax-NG validation context 9872 * @define: the definition to verify 9873 * 9874 * Validate the current state against the definition 9875 * 9876 * Returns 0 if the validation succeeded or an error code. 9877 */ 9878 static int 9879 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, 9880 xmlRelaxNGDefinePtr define) 9881 { 9882 xmlNodePtr node; 9883 int ret = 0, i, tmp, oldflags, errNr; 9884 xmlRelaxNGValidStatePtr oldstate = NULL, state; 9885 9886 if (define == NULL) { 9887 VALID_ERR(XML_RELAXNG_ERR_NODEFINE); 9888 return (-1); 9889 } 9890 9891 if (ctxt->state != NULL) { 9892 node = ctxt->state->seq; 9893 } else { 9894 node = NULL; 9895 } 9896 #ifdef DEBUG 9897 for (i = 0; i < ctxt->depth; i++) 9898 xmlGenericError(xmlGenericErrorContext, " "); 9899 xmlGenericError(xmlGenericErrorContext, 9900 "Start validating %s ", xmlRelaxNGDefName(define)); 9901 if (define->name != NULL) 9902 xmlGenericError(xmlGenericErrorContext, "%s ", define->name); 9903 if ((node != NULL) && (node->name != NULL)) 9904 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name); 9905 else 9906 xmlGenericError(xmlGenericErrorContext, "\n"); 9907 #endif 9908 ctxt->depth++; 9909 switch (define->type) { 9910 case XML_RELAXNG_EMPTY: 9911 ret = 0; 9912 break; 9913 case XML_RELAXNG_NOT_ALLOWED: 9914 ret = -1; 9915 break; 9916 case XML_RELAXNG_TEXT: 9917 while ((node != NULL) && 9918 ((node->type == XML_TEXT_NODE) || 9919 (node->type == XML_COMMENT_NODE) || 9920 (node->type == XML_PI_NODE) || 9921 (node->type == XML_CDATA_SECTION_NODE))) 9922 node = node->next; 9923 ctxt->state->seq = node; 9924 break; 9925 case XML_RELAXNG_ELEMENT: 9926 errNr = ctxt->errNr; 9927 node = xmlRelaxNGSkipIgnored(ctxt, node); 9928 if (node == NULL) { 9929 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name); 9930 ret = -1; 9931 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9932 xmlRelaxNGDumpValidError(ctxt); 9933 break; 9934 } 9935 if (node->type != XML_ELEMENT_NODE) { 9936 VALID_ERR(XML_RELAXNG_ERR_NOTELEM); 9937 ret = -1; 9938 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9939 xmlRelaxNGDumpValidError(ctxt); 9940 break; 9941 } 9942 /* 9943 * This node was already validated successfully against 9944 * this definition. 9945 */ 9946 if (node->psvi == define) { 9947 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); 9948 if (ctxt->errNr > errNr) 9949 xmlRelaxNGPopErrors(ctxt, errNr); 9950 if (ctxt->errNr != 0) { 9951 while ((ctxt->err != NULL) && 9952 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) 9953 && (xmlStrEqual(ctxt->err->arg2, node->name))) 9954 || 9955 ((ctxt->err->err == 9956 XML_RELAXNG_ERR_ELEMEXTRANS) 9957 && (xmlStrEqual(ctxt->err->arg1, node->name))) 9958 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) 9959 || (ctxt->err->err == 9960 XML_RELAXNG_ERR_NOTELEM))) 9961 xmlRelaxNGValidErrorPop(ctxt); 9962 } 9963 break; 9964 } 9965 9966 ret = xmlRelaxNGElementMatch(ctxt, define, node); 9967 if (ret <= 0) { 9968 ret = -1; 9969 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9970 xmlRelaxNGDumpValidError(ctxt); 9971 break; 9972 } 9973 ret = 0; 9974 if (ctxt->errNr != 0) { 9975 if (ctxt->errNr > errNr) 9976 xmlRelaxNGPopErrors(ctxt, errNr); 9977 while ((ctxt->err != NULL) && 9978 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) && 9979 (xmlStrEqual(ctxt->err->arg2, node->name))) || 9980 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) && 9981 (xmlStrEqual(ctxt->err->arg1, node->name))) || 9982 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) || 9983 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM))) 9984 xmlRelaxNGValidErrorPop(ctxt); 9985 } 9986 errNr = ctxt->errNr; 9987 9988 oldflags = ctxt->flags; 9989 if (ctxt->flags & FLAGS_MIXED_CONTENT) { 9990 ctxt->flags -= FLAGS_MIXED_CONTENT; 9991 } 9992 state = xmlRelaxNGNewValidState(ctxt, node); 9993 if (state == NULL) { 9994 ret = -1; 9995 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9996 xmlRelaxNGDumpValidError(ctxt); 9997 break; 9998 } 9999 10000 oldstate = ctxt->state; 10001 ctxt->state = state; 10002 if (define->attrs != NULL) { 10003 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); 10004 if (tmp != 0) { 10005 ret = -1; 10006 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); 10007 } 10008 } 10009 if (define->contModel != NULL) { 10010 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state; 10011 xmlRelaxNGStatesPtr tmpstates = ctxt->states; 10012 xmlNodePtr nseq; 10013 10014 nstate = xmlRelaxNGNewValidState(ctxt, node); 10015 ctxt->state = nstate; 10016 ctxt->states = NULL; 10017 10018 tmp = xmlRelaxNGValidateCompiledContent(ctxt, 10019 define->contModel, 10020 ctxt->state->seq); 10021 nseq = ctxt->state->seq; 10022 ctxt->state = tmpstate; 10023 ctxt->states = tmpstates; 10024 xmlRelaxNGFreeValidState(ctxt, nstate); 10025 10026 #ifdef DEBUG_COMPILE 10027 xmlGenericError(xmlGenericErrorContext, 10028 "Validating content of '%s' : %d\n", 10029 define->name, tmp); 10030 #endif 10031 if (tmp != 0) 10032 ret = -1; 10033 10034 if (ctxt->states != NULL) { 10035 tmp = -1; 10036 10037 for (i = 0; i < ctxt->states->nbState; i++) { 10038 state = ctxt->states->tabState[i]; 10039 ctxt->state = state; 10040 ctxt->state->seq = nseq; 10041 10042 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 10043 tmp = 0; 10044 break; 10045 } 10046 } 10047 if (tmp != 0) { 10048 /* 10049 * validation error, log the message for the "best" one 10050 */ 10051 ctxt->flags |= FLAGS_IGNORABLE; 10052 xmlRelaxNGLogBestError(ctxt); 10053 } 10054 for (i = 0; i < ctxt->states->nbState; i++) { 10055 xmlRelaxNGFreeValidState(ctxt, 10056 ctxt->states-> 10057 tabState[i]); 10058 } 10059 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10060 ctxt->flags = oldflags; 10061 ctxt->states = NULL; 10062 if ((ret == 0) && (tmp == -1)) 10063 ret = -1; 10064 } else { 10065 state = ctxt->state; 10066 if (ctxt->state != NULL) 10067 ctxt->state->seq = nseq; 10068 if (ret == 0) 10069 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 10070 xmlRelaxNGFreeValidState(ctxt, state); 10071 } 10072 } else { 10073 if (define->content != NULL) { 10074 tmp = xmlRelaxNGValidateDefinitionList(ctxt, 10075 define-> 10076 content); 10077 if (tmp != 0) { 10078 ret = -1; 10079 if (ctxt->state == NULL) { 10080 ctxt->state = oldstate; 10081 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, 10082 node->name); 10083 ctxt->state = NULL; 10084 } else { 10085 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, 10086 node->name); 10087 } 10088 10089 } 10090 } 10091 if (ctxt->states != NULL) { 10092 tmp = -1; 10093 10094 for (i = 0; i < ctxt->states->nbState; i++) { 10095 state = ctxt->states->tabState[i]; 10096 ctxt->state = state; 10097 10098 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 10099 tmp = 0; 10100 break; 10101 } 10102 } 10103 if (tmp != 0) { 10104 /* 10105 * validation error, log the message for the "best" one 10106 */ 10107 ctxt->flags |= FLAGS_IGNORABLE; 10108 xmlRelaxNGLogBestError(ctxt); 10109 } 10110 for (i = 0; i < ctxt->states->nbState; i++) { 10111 xmlRelaxNGFreeValidState(ctxt, 10112 ctxt->states->tabState[i]); 10113 ctxt->states->tabState[i] = NULL; 10114 } 10115 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10116 ctxt->flags = oldflags; 10117 ctxt->states = NULL; 10118 if ((ret == 0) && (tmp == -1)) 10119 ret = -1; 10120 } else { 10121 state = ctxt->state; 10122 if (ret == 0) 10123 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 10124 xmlRelaxNGFreeValidState(ctxt, state); 10125 } 10126 } 10127 if (ret == 0) { 10128 node->psvi = define; 10129 } 10130 ctxt->flags = oldflags; 10131 ctxt->state = oldstate; 10132 if (oldstate != NULL) 10133 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); 10134 if (ret != 0) { 10135 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 10136 xmlRelaxNGDumpValidError(ctxt); 10137 ret = 0; 10138 #if 0 10139 } else { 10140 ret = -2; 10141 #endif 10142 } 10143 } else { 10144 if (ctxt->errNr > errNr) 10145 xmlRelaxNGPopErrors(ctxt, errNr); 10146 } 10147 10148 #ifdef DEBUG 10149 xmlGenericError(xmlGenericErrorContext, 10150 "xmlRelaxNGValidateDefinition(): validated %s : %d", 10151 node->name, ret); 10152 if (oldstate == NULL) 10153 xmlGenericError(xmlGenericErrorContext, ": no state\n"); 10154 else if (oldstate->seq == NULL) 10155 xmlGenericError(xmlGenericErrorContext, ": done\n"); 10156 else if (oldstate->seq->type == XML_ELEMENT_NODE) 10157 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n", 10158 oldstate->seq->name); 10159 else 10160 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n", 10161 oldstate->seq->name, oldstate->seq->type); 10162 #endif 10163 break; 10164 case XML_RELAXNG_OPTIONAL:{ 10165 errNr = ctxt->errNr; 10166 oldflags = ctxt->flags; 10167 ctxt->flags |= FLAGS_IGNORABLE; 10168 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); 10169 ret = 10170 xmlRelaxNGValidateDefinitionList(ctxt, 10171 define->content); 10172 if (ret != 0) { 10173 if (ctxt->state != NULL) 10174 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10175 ctxt->state = oldstate; 10176 ctxt->flags = oldflags; 10177 ret = 0; 10178 if (ctxt->errNr > errNr) 10179 xmlRelaxNGPopErrors(ctxt, errNr); 10180 break; 10181 } 10182 if (ctxt->states != NULL) { 10183 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); 10184 } else { 10185 ctxt->states = xmlRelaxNGNewStates(ctxt, 1); 10186 if (ctxt->states == NULL) { 10187 xmlRelaxNGFreeValidState(ctxt, oldstate); 10188 ctxt->flags = oldflags; 10189 ret = -1; 10190 if (ctxt->errNr > errNr) 10191 xmlRelaxNGPopErrors(ctxt, errNr); 10192 break; 10193 } 10194 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); 10195 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state); 10196 ctxt->state = NULL; 10197 } 10198 ctxt->flags = oldflags; 10199 ret = 0; 10200 if (ctxt->errNr > errNr) 10201 xmlRelaxNGPopErrors(ctxt, errNr); 10202 break; 10203 } 10204 case XML_RELAXNG_ONEORMORE: 10205 errNr = ctxt->errNr; 10206 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); 10207 if (ret != 0) { 10208 break; 10209 } 10210 if (ctxt->errNr > errNr) 10211 xmlRelaxNGPopErrors(ctxt, errNr); 10212 /* Falls through. */ 10213 case XML_RELAXNG_ZEROORMORE:{ 10214 int progress; 10215 xmlRelaxNGStatesPtr states = NULL, res = NULL; 10216 int base, j; 10217 10218 errNr = ctxt->errNr; 10219 res = xmlRelaxNGNewStates(ctxt, 1); 10220 if (res == NULL) { 10221 ret = -1; 10222 break; 10223 } 10224 /* 10225 * All the input states are also exit states 10226 */ 10227 if (ctxt->state != NULL) { 10228 xmlRelaxNGAddStates(ctxt, res, 10229 xmlRelaxNGCopyValidState(ctxt, 10230 ctxt-> 10231 state)); 10232 } else { 10233 for (j = 0; j < ctxt->states->nbState; j++) { 10234 xmlRelaxNGAddStates(ctxt, res, 10235 xmlRelaxNGCopyValidState(ctxt, 10236 ctxt->states->tabState[j])); 10237 } 10238 } 10239 oldflags = ctxt->flags; 10240 ctxt->flags |= FLAGS_IGNORABLE; 10241 do { 10242 progress = 0; 10243 base = res->nbState; 10244 10245 if (ctxt->states != NULL) { 10246 states = ctxt->states; 10247 for (i = 0; i < states->nbState; i++) { 10248 ctxt->state = states->tabState[i]; 10249 ctxt->states = NULL; 10250 ret = xmlRelaxNGValidateDefinitionList(ctxt, 10251 define-> 10252 content); 10253 if (ret == 0) { 10254 if (ctxt->state != NULL) { 10255 tmp = xmlRelaxNGAddStates(ctxt, res, 10256 ctxt->state); 10257 ctxt->state = NULL; 10258 if (tmp == 1) 10259 progress = 1; 10260 } else if (ctxt->states != NULL) { 10261 for (j = 0; j < ctxt->states->nbState; 10262 j++) { 10263 tmp = 10264 xmlRelaxNGAddStates(ctxt, res, 10265 ctxt->states->tabState[j]); 10266 if (tmp == 1) 10267 progress = 1; 10268 } 10269 xmlRelaxNGFreeStates(ctxt, 10270 ctxt->states); 10271 ctxt->states = NULL; 10272 } 10273 } else { 10274 if (ctxt->state != NULL) { 10275 xmlRelaxNGFreeValidState(ctxt, 10276 ctxt->state); 10277 ctxt->state = NULL; 10278 } 10279 } 10280 } 10281 } else { 10282 ret = xmlRelaxNGValidateDefinitionList(ctxt, 10283 define-> 10284 content); 10285 if (ret != 0) { 10286 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10287 ctxt->state = NULL; 10288 } else { 10289 base = res->nbState; 10290 if (ctxt->state != NULL) { 10291 tmp = xmlRelaxNGAddStates(ctxt, res, 10292 ctxt->state); 10293 ctxt->state = NULL; 10294 if (tmp == 1) 10295 progress = 1; 10296 } else if (ctxt->states != NULL) { 10297 for (j = 0; j < ctxt->states->nbState; j++) { 10298 tmp = xmlRelaxNGAddStates(ctxt, res, 10299 ctxt->states->tabState[j]); 10300 if (tmp == 1) 10301 progress = 1; 10302 } 10303 if (states == NULL) { 10304 states = ctxt->states; 10305 } else { 10306 xmlRelaxNGFreeStates(ctxt, 10307 ctxt->states); 10308 } 10309 ctxt->states = NULL; 10310 } 10311 } 10312 } 10313 if (progress) { 10314 /* 10315 * Collect all the new nodes added at that step 10316 * and make them the new node set 10317 */ 10318 if (res->nbState - base == 1) { 10319 ctxt->state = xmlRelaxNGCopyValidState(ctxt, 10320 res-> 10321 tabState 10322 [base]); 10323 } else { 10324 if (states == NULL) { 10325 xmlRelaxNGNewStates(ctxt, 10326 res->nbState - base); 10327 states = ctxt->states; 10328 if (states == NULL) { 10329 progress = 0; 10330 break; 10331 } 10332 } 10333 states->nbState = 0; 10334 for (i = base; i < res->nbState; i++) 10335 xmlRelaxNGAddStates(ctxt, states, 10336 xmlRelaxNGCopyValidState 10337 (ctxt, res->tabState[i])); 10338 ctxt->states = states; 10339 } 10340 } 10341 } while (progress == 1); 10342 if (states != NULL) { 10343 xmlRelaxNGFreeStates(ctxt, states); 10344 } 10345 ctxt->states = res; 10346 ctxt->flags = oldflags; 10347 #if 0 10348 /* 10349 * errors may have to be propagated back... 10350 */ 10351 if (ctxt->errNr > errNr) 10352 xmlRelaxNGPopErrors(ctxt, errNr); 10353 #endif 10354 ret = 0; 10355 break; 10356 } 10357 case XML_RELAXNG_CHOICE:{ 10358 xmlRelaxNGDefinePtr list = NULL; 10359 xmlRelaxNGStatesPtr states = NULL; 10360 10361 node = xmlRelaxNGSkipIgnored(ctxt, node); 10362 10363 errNr = ctxt->errNr; 10364 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) && 10365 (node != NULL)) { 10366 /* 10367 * node == NULL can't be optimized since IS_TRIABLE 10368 * doesn't account for choice which may lead to 10369 * only attributes. 10370 */ 10371 xmlHashTablePtr triage = 10372 (xmlHashTablePtr) define->data; 10373 10374 /* 10375 * Something we can optimize cleanly there is only one 10376 * possible branch out ! 10377 */ 10378 if ((node->type == XML_TEXT_NODE) || 10379 (node->type == XML_CDATA_SECTION_NODE)) { 10380 list = 10381 xmlHashLookup2(triage, BAD_CAST "#text", NULL); 10382 } else if (node->type == XML_ELEMENT_NODE) { 10383 if (node->ns != NULL) { 10384 list = xmlHashLookup2(triage, node->name, 10385 node->ns->href); 10386 if (list == NULL) 10387 list = 10388 xmlHashLookup2(triage, BAD_CAST "#any", 10389 node->ns->href); 10390 } else 10391 list = 10392 xmlHashLookup2(triage, node->name, NULL); 10393 if (list == NULL) 10394 list = 10395 xmlHashLookup2(triage, BAD_CAST "#any", 10396 NULL); 10397 } 10398 if (list == NULL) { 10399 ret = -1; 10400 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name); 10401 break; 10402 } 10403 ret = xmlRelaxNGValidateDefinition(ctxt, list); 10404 if (ret == 0) { 10405 } 10406 break; 10407 } 10408 10409 list = define->content; 10410 oldflags = ctxt->flags; 10411 ctxt->flags |= FLAGS_IGNORABLE; 10412 10413 while (list != NULL) { 10414 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); 10415 ret = xmlRelaxNGValidateDefinition(ctxt, list); 10416 if (ret == 0) { 10417 if (states == NULL) { 10418 states = xmlRelaxNGNewStates(ctxt, 1); 10419 } 10420 if (ctxt->state != NULL) { 10421 xmlRelaxNGAddStates(ctxt, states, ctxt->state); 10422 } else if (ctxt->states != NULL) { 10423 for (i = 0; i < ctxt->states->nbState; i++) { 10424 xmlRelaxNGAddStates(ctxt, states, 10425 ctxt->states-> 10426 tabState[i]); 10427 } 10428 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10429 ctxt->states = NULL; 10430 } 10431 } else { 10432 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10433 } 10434 ctxt->state = oldstate; 10435 list = list->next; 10436 } 10437 if (states != NULL) { 10438 xmlRelaxNGFreeValidState(ctxt, oldstate); 10439 ctxt->states = states; 10440 ctxt->state = NULL; 10441 ret = 0; 10442 } else { 10443 ctxt->states = NULL; 10444 } 10445 ctxt->flags = oldflags; 10446 if (ret != 0) { 10447 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 10448 xmlRelaxNGDumpValidError(ctxt); 10449 } 10450 } else { 10451 if (ctxt->errNr > errNr) 10452 xmlRelaxNGPopErrors(ctxt, errNr); 10453 } 10454 break; 10455 } 10456 case XML_RELAXNG_DEF: 10457 case XML_RELAXNG_GROUP: 10458 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); 10459 break; 10460 case XML_RELAXNG_INTERLEAVE: 10461 ret = xmlRelaxNGValidateInterleave(ctxt, define); 10462 break; 10463 case XML_RELAXNG_ATTRIBUTE: 10464 ret = xmlRelaxNGValidateAttribute(ctxt, define); 10465 break; 10466 case XML_RELAXNG_START: 10467 case XML_RELAXNG_NOOP: 10468 case XML_RELAXNG_REF: 10469 case XML_RELAXNG_EXTERNALREF: 10470 case XML_RELAXNG_PARENTREF: 10471 ret = xmlRelaxNGValidateDefinition(ctxt, define->content); 10472 break; 10473 case XML_RELAXNG_DATATYPE:{ 10474 xmlNodePtr child; 10475 xmlChar *content = NULL; 10476 10477 child = node; 10478 while (child != NULL) { 10479 if (child->type == XML_ELEMENT_NODE) { 10480 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM, 10481 node->parent->name); 10482 ret = -1; 10483 break; 10484 } else if ((child->type == XML_TEXT_NODE) || 10485 (child->type == XML_CDATA_SECTION_NODE)) { 10486 content = xmlStrcat(content, child->content); 10487 } 10488 /* TODO: handle entities ... */ 10489 child = child->next; 10490 } 10491 if (ret == -1) { 10492 if (content != NULL) 10493 xmlFree(content); 10494 break; 10495 } 10496 if (content == NULL) { 10497 content = xmlStrdup(BAD_CAST ""); 10498 if (content == NULL) { 10499 xmlRngVErrMemory(ctxt, "validating\n"); 10500 ret = -1; 10501 break; 10502 } 10503 } 10504 ret = xmlRelaxNGValidateDatatype(ctxt, content, define, 10505 ctxt->state->seq); 10506 if (ret == -1) { 10507 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name); 10508 } else if (ret == 0) { 10509 ctxt->state->seq = NULL; 10510 } 10511 if (content != NULL) 10512 xmlFree(content); 10513 break; 10514 } 10515 case XML_RELAXNG_VALUE:{ 10516 xmlChar *content = NULL; 10517 xmlChar *oldvalue; 10518 xmlNodePtr child; 10519 10520 child = node; 10521 while (child != NULL) { 10522 if (child->type == XML_ELEMENT_NODE) { 10523 VALID_ERR2(XML_RELAXNG_ERR_VALELEM, 10524 node->parent->name); 10525 ret = -1; 10526 break; 10527 } else if ((child->type == XML_TEXT_NODE) || 10528 (child->type == XML_CDATA_SECTION_NODE)) { 10529 content = xmlStrcat(content, child->content); 10530 } 10531 /* TODO: handle entities ... */ 10532 child = child->next; 10533 } 10534 if (ret == -1) { 10535 if (content != NULL) 10536 xmlFree(content); 10537 break; 10538 } 10539 if (content == NULL) { 10540 content = xmlStrdup(BAD_CAST ""); 10541 if (content == NULL) { 10542 xmlRngVErrMemory(ctxt, "validating\n"); 10543 ret = -1; 10544 break; 10545 } 10546 } 10547 oldvalue = ctxt->state->value; 10548 ctxt->state->value = content; 10549 ret = xmlRelaxNGValidateValue(ctxt, define); 10550 ctxt->state->value = oldvalue; 10551 if (ret == -1) { 10552 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name); 10553 } else if (ret == 0) { 10554 ctxt->state->seq = NULL; 10555 } 10556 if (content != NULL) 10557 xmlFree(content); 10558 break; 10559 } 10560 case XML_RELAXNG_LIST:{ 10561 xmlChar *content; 10562 xmlNodePtr child; 10563 xmlChar *oldvalue, *oldendvalue; 10564 int len; 10565 10566 /* 10567 * Make sure it's only text nodes 10568 */ 10569 10570 content = NULL; 10571 child = node; 10572 while (child != NULL) { 10573 if (child->type == XML_ELEMENT_NODE) { 10574 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM, 10575 node->parent->name); 10576 ret = -1; 10577 break; 10578 } else if ((child->type == XML_TEXT_NODE) || 10579 (child->type == XML_CDATA_SECTION_NODE)) { 10580 content = xmlStrcat(content, child->content); 10581 } 10582 /* TODO: handle entities ... */ 10583 child = child->next; 10584 } 10585 if (ret == -1) { 10586 if (content != NULL) 10587 xmlFree(content); 10588 break; 10589 } 10590 if (content == NULL) { 10591 content = xmlStrdup(BAD_CAST ""); 10592 if (content == NULL) { 10593 xmlRngVErrMemory(ctxt, "validating\n"); 10594 ret = -1; 10595 break; 10596 } 10597 } 10598 len = xmlStrlen(content); 10599 oldvalue = ctxt->state->value; 10600 oldendvalue = ctxt->state->endvalue; 10601 ctxt->state->value = content; 10602 ctxt->state->endvalue = content + len; 10603 ret = xmlRelaxNGValidateValue(ctxt, define); 10604 ctxt->state->value = oldvalue; 10605 ctxt->state->endvalue = oldendvalue; 10606 if (ret == -1) { 10607 VALID_ERR(XML_RELAXNG_ERR_LIST); 10608 } else if ((ret == 0) && (node != NULL)) { 10609 ctxt->state->seq = node->next; 10610 } 10611 if (content != NULL) 10612 xmlFree(content); 10613 break; 10614 } 10615 case XML_RELAXNG_EXCEPT: 10616 case XML_RELAXNG_PARAM: 10617 TODO ret = -1; 10618 break; 10619 } 10620 ctxt->depth--; 10621 #ifdef DEBUG 10622 for (i = 0; i < ctxt->depth; i++) 10623 xmlGenericError(xmlGenericErrorContext, " "); 10624 xmlGenericError(xmlGenericErrorContext, 10625 "Validating %s ", xmlRelaxNGDefName(define)); 10626 if (define->name != NULL) 10627 xmlGenericError(xmlGenericErrorContext, "%s ", define->name); 10628 if (ret == 0) 10629 xmlGenericError(xmlGenericErrorContext, "succeeded\n"); 10630 else 10631 xmlGenericError(xmlGenericErrorContext, "failed\n"); 10632 #endif 10633 return (ret); 10634 } 10635 10636 /** 10637 * xmlRelaxNGValidateDefinition: 10638 * @ctxt: a Relax-NG validation context 10639 * @define: the definition to verify 10640 * 10641 * Validate the current node lists against the definition 10642 * 10643 * Returns 0 if the validation succeeded or an error code. 10644 */ 10645 static int 10646 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 10647 xmlRelaxNGDefinePtr define) 10648 { 10649 xmlRelaxNGStatesPtr states, res; 10650 int i, j, k, ret, oldflags; 10651 10652 /* 10653 * We should NOT have both ctxt->state and ctxt->states 10654 */ 10655 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10656 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10657 ctxt->state = NULL; 10658 } 10659 10660 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) { 10661 if (ctxt->states != NULL) { 10662 ctxt->state = ctxt->states->tabState[0]; 10663 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10664 ctxt->states = NULL; 10665 } 10666 ret = xmlRelaxNGValidateState(ctxt, define); 10667 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10668 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10669 ctxt->state = NULL; 10670 } 10671 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { 10672 ctxt->state = ctxt->states->tabState[0]; 10673 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10674 ctxt->states = NULL; 10675 } 10676 return (ret); 10677 } 10678 10679 states = ctxt->states; 10680 ctxt->states = NULL; 10681 res = NULL; 10682 j = 0; 10683 oldflags = ctxt->flags; 10684 ctxt->flags |= FLAGS_IGNORABLE; 10685 for (i = 0; i < states->nbState; i++) { 10686 ctxt->state = states->tabState[i]; 10687 ctxt->states = NULL; 10688 ret = xmlRelaxNGValidateState(ctxt, define); 10689 /* 10690 * We should NOT have both ctxt->state and ctxt->states 10691 */ 10692 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10693 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10694 ctxt->state = NULL; 10695 } 10696 if (ret == 0) { 10697 if (ctxt->states == NULL) { 10698 if (res != NULL) { 10699 /* add the state to the container */ 10700 xmlRelaxNGAddStates(ctxt, res, ctxt->state); 10701 ctxt->state = NULL; 10702 } else { 10703 /* add the state directly in states */ 10704 states->tabState[j++] = ctxt->state; 10705 ctxt->state = NULL; 10706 } 10707 } else { 10708 if (res == NULL) { 10709 /* make it the new container and copy other results */ 10710 res = ctxt->states; 10711 ctxt->states = NULL; 10712 for (k = 0; k < j; k++) 10713 xmlRelaxNGAddStates(ctxt, res, 10714 states->tabState[k]); 10715 } else { 10716 /* add all the new results to res and reff the container */ 10717 for (k = 0; k < ctxt->states->nbState; k++) 10718 xmlRelaxNGAddStates(ctxt, res, 10719 ctxt->states->tabState[k]); 10720 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10721 ctxt->states = NULL; 10722 } 10723 } 10724 } else { 10725 if (ctxt->state != NULL) { 10726 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10727 ctxt->state = NULL; 10728 } else if (ctxt->states != NULL) { 10729 for (k = 0; k < ctxt->states->nbState; k++) 10730 xmlRelaxNGFreeValidState(ctxt, 10731 ctxt->states->tabState[k]); 10732 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10733 ctxt->states = NULL; 10734 } 10735 } 10736 } 10737 ctxt->flags = oldflags; 10738 if (res != NULL) { 10739 xmlRelaxNGFreeStates(ctxt, states); 10740 ctxt->states = res; 10741 ret = 0; 10742 } else if (j > 1) { 10743 states->nbState = j; 10744 ctxt->states = states; 10745 ret = 0; 10746 } else if (j == 1) { 10747 ctxt->state = states->tabState[0]; 10748 xmlRelaxNGFreeStates(ctxt, states); 10749 ret = 0; 10750 } else { 10751 ret = -1; 10752 xmlRelaxNGFreeStates(ctxt, states); 10753 if (ctxt->states != NULL) { 10754 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10755 ctxt->states = NULL; 10756 } 10757 } 10758 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10759 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10760 ctxt->state = NULL; 10761 } 10762 return (ret); 10763 } 10764 10765 /** 10766 * xmlRelaxNGValidateDocument: 10767 * @ctxt: a Relax-NG validation context 10768 * @doc: the document 10769 * 10770 * Validate the given document 10771 * 10772 * Returns 0 if the validation succeeded or an error code. 10773 */ 10774 static int 10775 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) 10776 { 10777 int ret; 10778 xmlRelaxNGPtr schema; 10779 xmlRelaxNGGrammarPtr grammar; 10780 xmlRelaxNGValidStatePtr state; 10781 xmlNodePtr node; 10782 10783 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL)) 10784 return (-1); 10785 10786 ctxt->errNo = XML_RELAXNG_OK; 10787 schema = ctxt->schema; 10788 grammar = schema->topgrammar; 10789 if (grammar == NULL) { 10790 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 10791 return (-1); 10792 } 10793 state = xmlRelaxNGNewValidState(ctxt, NULL); 10794 ctxt->state = state; 10795 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start); 10796 if ((ctxt->state != NULL) && (state->seq != NULL)) { 10797 state = ctxt->state; 10798 node = state->seq; 10799 node = xmlRelaxNGSkipIgnored(ctxt, node); 10800 if (node != NULL) { 10801 if (ret != -1) { 10802 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); 10803 ret = -1; 10804 } 10805 } 10806 } else if (ctxt->states != NULL) { 10807 int i; 10808 int tmp = -1; 10809 10810 for (i = 0; i < ctxt->states->nbState; i++) { 10811 state = ctxt->states->tabState[i]; 10812 node = state->seq; 10813 node = xmlRelaxNGSkipIgnored(ctxt, node); 10814 if (node == NULL) 10815 tmp = 0; 10816 xmlRelaxNGFreeValidState(ctxt, state); 10817 } 10818 if (tmp == -1) { 10819 if (ret != -1) { 10820 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); 10821 ret = -1; 10822 } 10823 } 10824 } 10825 if (ctxt->state != NULL) { 10826 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10827 ctxt->state = NULL; 10828 } 10829 if (ret != 0) 10830 xmlRelaxNGDumpValidError(ctxt); 10831 #ifdef DEBUG 10832 else if (ctxt->errNr != 0) { 10833 ctxt->error(ctxt->userData, 10834 "%d Extra error messages left on stack !\n", 10835 ctxt->errNr); 10836 xmlRelaxNGDumpValidError(ctxt); 10837 } 10838 #endif 10839 #ifdef LIBXML_VALID_ENABLED 10840 if (ctxt->idref == 1) { 10841 xmlValidCtxt vctxt; 10842 10843 memset(&vctxt, 0, sizeof(xmlValidCtxt)); 10844 vctxt.valid = 1; 10845 vctxt.error = ctxt->error; 10846 vctxt.warning = ctxt->warning; 10847 vctxt.userData = ctxt->userData; 10848 10849 if (xmlValidateDocumentFinal(&vctxt, doc) != 1) 10850 ret = -1; 10851 } 10852 #endif /* LIBXML_VALID_ENABLED */ 10853 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK)) 10854 ret = -1; 10855 10856 return (ret); 10857 } 10858 10859 /** 10860 * xmlRelaxNGCleanPSVI: 10861 * @node: an input element or document 10862 * 10863 * Call this routine to speed up XPath computation on static documents. 10864 * This stamps all the element nodes with the document order 10865 * Like for line information, the order is kept in the element->content 10866 * field, the value stored is actually - the node number (starting at -1) 10867 * to be able to differentiate from line numbers. 10868 * 10869 * Returns the number of elements found in the document or -1 in case 10870 * of error. 10871 */ 10872 static void 10873 xmlRelaxNGCleanPSVI(xmlNodePtr node) { 10874 xmlNodePtr cur; 10875 10876 if ((node == NULL) || 10877 ((node->type != XML_ELEMENT_NODE) && 10878 (node->type != XML_DOCUMENT_NODE) && 10879 (node->type != XML_HTML_DOCUMENT_NODE))) 10880 return; 10881 if (node->type == XML_ELEMENT_NODE) 10882 node->psvi = NULL; 10883 10884 cur = node->children; 10885 while (cur != NULL) { 10886 if (cur->type == XML_ELEMENT_NODE) { 10887 cur->psvi = NULL; 10888 if (cur->children != NULL) { 10889 cur = cur->children; 10890 continue; 10891 } 10892 } 10893 if (cur->next != NULL) { 10894 cur = cur->next; 10895 continue; 10896 } 10897 do { 10898 cur = cur->parent; 10899 if (cur == NULL) 10900 break; 10901 if (cur == node) { 10902 cur = NULL; 10903 break; 10904 } 10905 if (cur->next != NULL) { 10906 cur = cur->next; 10907 break; 10908 } 10909 } while (cur != NULL); 10910 } 10911 return; 10912 } 10913 /************************************************************************ 10914 * * 10915 * Validation interfaces * 10916 * * 10917 ************************************************************************/ 10918 10919 /** 10920 * xmlRelaxNGNewValidCtxt: 10921 * @schema: a precompiled XML RelaxNGs 10922 * 10923 * Create an XML RelaxNGs validation context based on the given schema 10924 * 10925 * Returns the validation context or NULL in case of error 10926 */ 10927 xmlRelaxNGValidCtxtPtr 10928 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) 10929 { 10930 xmlRelaxNGValidCtxtPtr ret; 10931 10932 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); 10933 if (ret == NULL) { 10934 xmlRngVErrMemory(NULL, "building context\n"); 10935 return (NULL); 10936 } 10937 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); 10938 ret->schema = schema; 10939 ret->error = xmlGenericError; 10940 ret->userData = xmlGenericErrorContext; 10941 ret->errNr = 0; 10942 ret->errMax = 0; 10943 ret->err = NULL; 10944 ret->errTab = NULL; 10945 if (schema != NULL) 10946 ret->idref = schema->idref; 10947 ret->states = NULL; 10948 ret->freeState = NULL; 10949 ret->freeStates = NULL; 10950 ret->errNo = XML_RELAXNG_OK; 10951 return (ret); 10952 } 10953 10954 /** 10955 * xmlRelaxNGFreeValidCtxt: 10956 * @ctxt: the schema validation context 10957 * 10958 * Free the resources associated to the schema validation context 10959 */ 10960 void 10961 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) 10962 { 10963 int k; 10964 10965 if (ctxt == NULL) 10966 return; 10967 if (ctxt->states != NULL) 10968 xmlRelaxNGFreeStates(NULL, ctxt->states); 10969 if (ctxt->freeState != NULL) { 10970 for (k = 0; k < ctxt->freeState->nbState; k++) { 10971 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]); 10972 } 10973 xmlRelaxNGFreeStates(NULL, ctxt->freeState); 10974 } 10975 if (ctxt->freeStates != NULL) { 10976 for (k = 0; k < ctxt->freeStatesNr; k++) { 10977 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]); 10978 } 10979 xmlFree(ctxt->freeStates); 10980 } 10981 if (ctxt->errTab != NULL) 10982 xmlFree(ctxt->errTab); 10983 if (ctxt->elemTab != NULL) { 10984 xmlRegExecCtxtPtr exec; 10985 10986 exec = xmlRelaxNGElemPop(ctxt); 10987 while (exec != NULL) { 10988 xmlRegFreeExecCtxt(exec); 10989 exec = xmlRelaxNGElemPop(ctxt); 10990 } 10991 xmlFree(ctxt->elemTab); 10992 } 10993 xmlFree(ctxt); 10994 } 10995 10996 /** 10997 * xmlRelaxNGSetValidErrors: 10998 * @ctxt: a Relax-NG validation context 10999 * @err: the error function 11000 * @warn: the warning function 11001 * @ctx: the functions context 11002 * 11003 * Set the error and warning callback information 11004 */ 11005 void 11006 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, 11007 xmlRelaxNGValidityErrorFunc err, 11008 xmlRelaxNGValidityWarningFunc warn, void *ctx) 11009 { 11010 if (ctxt == NULL) 11011 return; 11012 ctxt->error = err; 11013 ctxt->warning = warn; 11014 ctxt->userData = ctx; 11015 ctxt->serror = NULL; 11016 } 11017 11018 /** 11019 * xmlRelaxNGSetValidStructuredErrors: 11020 * @ctxt: a Relax-NG validation context 11021 * @serror: the structured error function 11022 * @ctx: the functions context 11023 * 11024 * Set the structured error callback 11025 */ 11026 void 11027 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, 11028 xmlStructuredErrorFunc serror, void *ctx) 11029 { 11030 if (ctxt == NULL) 11031 return; 11032 ctxt->serror = serror; 11033 ctxt->error = NULL; 11034 ctxt->warning = NULL; 11035 ctxt->userData = ctx; 11036 } 11037 11038 /** 11039 * xmlRelaxNGGetValidErrors: 11040 * @ctxt: a Relax-NG validation context 11041 * @err: the error function result 11042 * @warn: the warning function result 11043 * @ctx: the functions context result 11044 * 11045 * Get the error and warning callback information 11046 * 11047 * Returns -1 in case of error and 0 otherwise 11048 */ 11049 int 11050 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, 11051 xmlRelaxNGValidityErrorFunc * err, 11052 xmlRelaxNGValidityWarningFunc * warn, void **ctx) 11053 { 11054 if (ctxt == NULL) 11055 return (-1); 11056 if (err != NULL) 11057 *err = ctxt->error; 11058 if (warn != NULL) 11059 *warn = ctxt->warning; 11060 if (ctx != NULL) 11061 *ctx = ctxt->userData; 11062 return (0); 11063 } 11064 11065 /** 11066 * xmlRelaxNGValidateDoc: 11067 * @ctxt: a Relax-NG validation context 11068 * @doc: a parsed document tree 11069 * 11070 * Validate a document tree in memory. 11071 * 11072 * Returns 0 if the document is valid, a positive error code 11073 * number otherwise and -1 in case of internal or API error. 11074 */ 11075 int 11076 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) 11077 { 11078 int ret; 11079 11080 if ((ctxt == NULL) || (doc == NULL)) 11081 return (-1); 11082 11083 ctxt->doc = doc; 11084 11085 ret = xmlRelaxNGValidateDocument(ctxt, doc); 11086 /* 11087 * Remove all left PSVI 11088 */ 11089 xmlRelaxNGCleanPSVI((xmlNodePtr) doc); 11090 11091 /* 11092 * TODO: build error codes 11093 */ 11094 if (ret == -1) 11095 return (1); 11096 return (ret); 11097 } 11098 11099 #define bottom_relaxng 11100 #include "elfgcchack.h" 11101 #endif /* LIBXML_SCHEMAS_ENABLED */ 11102