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