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