1 /* 2 * relaxng.c : implementation of the Relax-NG handling and validity checking 3 * 4 * See Copyright for the status of this software. 5 * 6 * Daniel Veillard <veillard@redhat.com> 7 */ 8 9 /** 10 * TODO: 11 * - add support for DTD compatibility spec 12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html 13 * - report better mem allocations pbms at runtime and abort immediately. 14 */ 15 16 #define IN_LIBXML 17 #include "libxml.h" 18 19 #ifdef LIBXML_SCHEMAS_ENABLED 20 21 #include <string.h> 22 #include <stdio.h> 23 #include <stddef.h> 24 #include <libxml/xmlmemory.h> 25 #include <libxml/parser.h> 26 #include <libxml/parserInternals.h> 27 #include <libxml/hash.h> 28 #include <libxml/uri.h> 29 30 #include <libxml/relaxng.h> 31 32 #include <libxml/xmlschemastypes.h> 33 #include <libxml/xmlautomata.h> 34 #include <libxml/xmlregexp.h> 35 #include <libxml/xmlschemastypes.h> 36 37 /* 38 * The Relax-NG namespace 39 */ 40 static const xmlChar *xmlRelaxNGNs = (const xmlChar *) 41 "http://relaxng.org/ns/structure/1.0"; 42 43 #define IS_RELAXNG(node, typ) \ 44 ((node != NULL) && (node->ns != NULL) && \ 45 (node->type == XML_ELEMENT_NODE) && \ 46 (xmlStrEqual(node->name, (const xmlChar *) typ)) && \ 47 (xmlStrEqual(node->ns->href, xmlRelaxNGNs))) 48 49 50 #if 0 51 #define DEBUG 1 52 53 #define DEBUG_GRAMMAR 1 54 55 #define DEBUG_CONTENT 1 56 57 #define DEBUG_TYPE 1 58 59 #define DEBUG_VALID 1 60 61 #define DEBUG_INTERLEAVE 1 62 63 #define DEBUG_LIST 1 64 65 #define DEBUG_INCLUDE 1 66 67 #define DEBUG_ERROR 1 68 69 #define DEBUG_COMPILE 1 70 71 #define DEBUG_PROGRESSIVE 1 72 #endif 73 74 #define MAX_ERROR 5 75 76 #define TODO \ 77 xmlGenericError(xmlGenericErrorContext, \ 78 "Unimplemented block at %s:%d\n", \ 79 __FILE__, __LINE__); 80 81 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; 82 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; 83 84 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine; 85 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr; 86 87 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument; 88 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr; 89 90 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude; 91 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr; 92 93 typedef enum { 94 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */ 95 XML_RELAXNG_COMBINE_CHOICE, /* choice */ 96 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */ 97 } xmlRelaxNGCombine; 98 99 typedef enum { 100 XML_RELAXNG_CONTENT_ERROR = -1, 101 XML_RELAXNG_CONTENT_EMPTY = 0, 102 XML_RELAXNG_CONTENT_SIMPLE, 103 XML_RELAXNG_CONTENT_COMPLEX 104 } xmlRelaxNGContentType; 105 106 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar; 107 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr; 108 109 struct _xmlRelaxNGGrammar { 110 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */ 111 xmlRelaxNGGrammarPtr children; /* the children grammar if any */ 112 xmlRelaxNGGrammarPtr next; /* the next grammar if any */ 113 xmlRelaxNGDefinePtr start; /* <start> content */ 114 xmlRelaxNGCombine combine; /* the default combine value */ 115 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */ 116 xmlHashTablePtr defs; /* define* */ 117 xmlHashTablePtr refs; /* references */ 118 }; 119 120 121 typedef enum { 122 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */ 123 XML_RELAXNG_EMPTY = 0, /* an empty pattern */ 124 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */ 125 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */ 126 XML_RELAXNG_TEXT, /* textual content */ 127 XML_RELAXNG_ELEMENT, /* an element */ 128 XML_RELAXNG_DATATYPE, /* extenal data type definition */ 129 XML_RELAXNG_PARAM, /* extenal data type parameter */ 130 XML_RELAXNG_VALUE, /* value from an extenal data type definition */ 131 XML_RELAXNG_LIST, /* a list of patterns */ 132 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */ 133 XML_RELAXNG_DEF, /* a definition */ 134 XML_RELAXNG_REF, /* reference to a definition */ 135 XML_RELAXNG_EXTERNALREF, /* reference to an external def */ 136 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */ 137 XML_RELAXNG_OPTIONAL, /* optional patterns */ 138 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */ 139 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */ 140 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */ 141 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */ 142 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */ 143 XML_RELAXNG_START /* Used to keep track of starts on grammars */ 144 } xmlRelaxNGType; 145 146 #define IS_NULLABLE (1 << 0) 147 #define IS_NOT_NULLABLE (1 << 1) 148 #define IS_INDETERMINIST (1 << 2) 149 #define IS_MIXED (1 << 3) 150 #define IS_TRIABLE (1 << 4) 151 #define IS_PROCESSED (1 << 5) 152 #define IS_COMPILABLE (1 << 6) 153 #define IS_NOT_COMPILABLE (1 << 7) 154 #define IS_EXTERNAL_REF (1 << 8) 155 156 struct _xmlRelaxNGDefine { 157 xmlRelaxNGType type; /* the type of definition */ 158 xmlNodePtr node; /* the node in the source */ 159 xmlChar *name; /* the element local name if present */ 160 xmlChar *ns; /* the namespace local name if present */ 161 xmlChar *value; /* value when available */ 162 void *data; /* data lib or specific pointer */ 163 xmlRelaxNGDefinePtr content; /* the expected content */ 164 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */ 165 xmlRelaxNGDefinePtr next; /* list within grouping sequences */ 166 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */ 167 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */ 168 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */ 169 short depth; /* used for the cycle detection */ 170 short dflags; /* define related flags */ 171 xmlRegexpPtr contModel; /* a compiled content model if available */ 172 }; 173 174 /** 175 * _xmlRelaxNG: 176 * 177 * A RelaxNGs definition 178 */ 179 struct _xmlRelaxNG { 180 void *_private; /* unused by the library for users or bindings */ 181 xmlRelaxNGGrammarPtr topgrammar; 182 xmlDocPtr doc; 183 184 int idref; /* requires idref checking */ 185 186 xmlHashTablePtr defs; /* define */ 187 xmlHashTablePtr refs; /* references */ 188 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */ 189 xmlRelaxNGIncludePtr includes; /* all the includes loaded */ 190 int defNr; /* number of defines used */ 191 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */ 192 193 }; 194 195 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0) 196 #define XML_RELAXNG_IN_ONEORMORE (1 << 1) 197 #define XML_RELAXNG_IN_LIST (1 << 2) 198 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3) 199 #define XML_RELAXNG_IN_START (1 << 4) 200 #define XML_RELAXNG_IN_OOMGROUP (1 << 5) 201 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6) 202 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7) 203 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8) 204 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9) 205 206 struct _xmlRelaxNGParserCtxt { 207 void *userData; /* user specific data block */ 208 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ 209 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */ 210 xmlStructuredErrorFunc serror; 211 xmlRelaxNGValidErr err; 212 213 xmlRelaxNGPtr schema; /* The schema in use */ 214 xmlRelaxNGGrammarPtr grammar; /* the current grammar */ 215 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */ 216 int flags; /* parser flags */ 217 int nbErrors; /* number of errors at parse time */ 218 int nbWarnings; /* number of warnings at parse time */ 219 const xmlChar *define; /* the current define scope */ 220 xmlRelaxNGDefinePtr def; /* the current define */ 221 222 int nbInterleaves; 223 xmlHashTablePtr interleaves; /* keep track of all the interleaves */ 224 225 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */ 226 xmlRelaxNGIncludePtr includes; /* all the includes loaded */ 227 xmlChar *URL; 228 xmlDocPtr document; 229 230 int defNr; /* number of defines used */ 231 int defMax; /* number of defines aloocated */ 232 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */ 233 234 const char *buffer; 235 int size; 236 237 /* the document stack */ 238 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */ 239 int docNr; /* Depth of the parsing stack */ 240 int docMax; /* Max depth of the parsing stack */ 241 xmlRelaxNGDocumentPtr *docTab; /* array of docs */ 242 243 /* the include stack */ 244 xmlRelaxNGIncludePtr inc; /* Current parsed include */ 245 int incNr; /* Depth of the include parsing stack */ 246 int incMax; /* Max depth of the parsing stack */ 247 xmlRelaxNGIncludePtr *incTab; /* array of incs */ 248 249 int idref; /* requires idref checking */ 250 251 /* used to compile content models */ 252 xmlAutomataPtr am; /* the automata */ 253 xmlAutomataStatePtr state; /* used to build the automata */ 254 255 int crng; /* compact syntax and other flags */ 256 int freedoc; /* need to free the document */ 257 }; 258 259 #define FLAGS_IGNORABLE 1 260 #define FLAGS_NEGATIVE 2 261 #define FLAGS_MIXED_CONTENT 4 262 #define FLAGS_NOERROR 8 263 264 /** 265 * xmlRelaxNGInterleaveGroup: 266 * 267 * A RelaxNGs partition set associated to lists of definitions 268 */ 269 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup; 270 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr; 271 struct _xmlRelaxNGInterleaveGroup { 272 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */ 273 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */ 274 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */ 275 }; 276 277 #define IS_DETERMINIST 1 278 #define IS_NEEDCHECK 2 279 280 /** 281 * xmlRelaxNGPartitions: 282 * 283 * A RelaxNGs partition associated to an interleave group 284 */ 285 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition; 286 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr; 287 struct _xmlRelaxNGPartition { 288 int nbgroups; /* number of groups in the partitions */ 289 xmlHashTablePtr triage; /* hash table used to direct nodes to the 290 * right group when possible */ 291 int flags; /* determinist ? */ 292 xmlRelaxNGInterleaveGroupPtr *groups; 293 }; 294 295 /** 296 * xmlRelaxNGValidState: 297 * 298 * A RelaxNGs validation state 299 */ 300 #define MAX_ATTR 20 301 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState; 302 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr; 303 struct _xmlRelaxNGValidState { 304 xmlNodePtr node; /* the current node */ 305 xmlNodePtr seq; /* the sequence of children left to validate */ 306 int nbAttrs; /* the number of attributes */ 307 int maxAttrs; /* the size of attrs */ 308 int nbAttrLeft; /* the number of attributes left to validate */ 309 xmlChar *value; /* the value when operating on string */ 310 xmlChar *endvalue; /* the end value when operating on string */ 311 xmlAttrPtr *attrs; /* the array of attributes */ 312 }; 313 314 /** 315 * xmlRelaxNGStates: 316 * 317 * A RelaxNGs container for validation state 318 */ 319 typedef struct _xmlRelaxNGStates xmlRelaxNGStates; 320 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr; 321 struct _xmlRelaxNGStates { 322 int nbState; /* the number of states */ 323 int maxState; /* the size of the array */ 324 xmlRelaxNGValidStatePtr *tabState; 325 }; 326 327 #define ERROR_IS_DUP 1 328 329 /** 330 * xmlRelaxNGValidError: 331 * 332 * A RelaxNGs validation error 333 */ 334 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError; 335 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr; 336 struct _xmlRelaxNGValidError { 337 xmlRelaxNGValidErr err; /* the error number */ 338 int flags; /* flags */ 339 xmlNodePtr node; /* the current node */ 340 xmlNodePtr seq; /* the current child */ 341 const xmlChar *arg1; /* first arg */ 342 const xmlChar *arg2; /* second arg */ 343 }; 344 345 /** 346 * xmlRelaxNGValidCtxt: 347 * 348 * A RelaxNGs validation context 349 */ 350 351 struct _xmlRelaxNGValidCtxt { 352 void *userData; /* user specific data block */ 353 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ 354 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */ 355 xmlStructuredErrorFunc serror; 356 int nbErrors; /* number of errors in validation */ 357 358 xmlRelaxNGPtr schema; /* The schema in use */ 359 xmlDocPtr doc; /* the document being validated */ 360 int flags; /* validation flags */ 361 int depth; /* validation depth */ 362 int idref; /* requires idref checking */ 363 int errNo; /* the first error found */ 364 365 /* 366 * Errors accumulated in branches may have to be stacked to be 367 * provided back when it's sure they affect validation. 368 */ 369 xmlRelaxNGValidErrorPtr err; /* Last error */ 370 int errNr; /* Depth of the error stack */ 371 int errMax; /* Max depth of the error stack */ 372 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */ 373 374 xmlRelaxNGValidStatePtr state; /* the current validation state */ 375 xmlRelaxNGStatesPtr states; /* the accumulated state list */ 376 377 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */ 378 int freeStatesNr; 379 int freeStatesMax; 380 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */ 381 382 /* 383 * This is used for "progressive" validation 384 */ 385 xmlRegExecCtxtPtr elem; /* the current element regexp */ 386 int elemNr; /* the number of element validated */ 387 int elemMax; /* the max depth of elements */ 388 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */ 389 int pstate; /* progressive state */ 390 xmlNodePtr pnode; /* the current node */ 391 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */ 392 int perr; /* signal error in content model 393 * outside the regexp */ 394 }; 395 396 /** 397 * xmlRelaxNGInclude: 398 * 399 * Structure associated to a RelaxNGs document element 400 */ 401 struct _xmlRelaxNGInclude { 402 xmlRelaxNGIncludePtr next; /* keep a chain of includes */ 403 xmlChar *href; /* the normalized href value */ 404 xmlDocPtr doc; /* the associated XML document */ 405 xmlRelaxNGDefinePtr content; /* the definitions */ 406 xmlRelaxNGPtr schema; /* the schema */ 407 }; 408 409 /** 410 * xmlRelaxNGDocument: 411 * 412 * Structure associated to a RelaxNGs document element 413 */ 414 struct _xmlRelaxNGDocument { 415 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */ 416 xmlChar *href; /* the normalized href value */ 417 xmlDocPtr doc; /* the associated XML document */ 418 xmlRelaxNGDefinePtr content; /* the definitions */ 419 xmlRelaxNGPtr schema; /* the schema */ 420 int externalRef; /* 1 if an external ref */ 421 }; 422 423 424 /************************************************************************ 425 * * 426 * Some factorized error routines * 427 * * 428 ************************************************************************/ 429 430 /** 431 * xmlRngPErrMemory: 432 * @ctxt: an Relax-NG parser context 433 * @extra: extra informations 434 * 435 * Handle a redefinition of attribute error 436 */ 437 static void 438 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) 439 { 440 xmlStructuredErrorFunc schannel = NULL; 441 xmlGenericErrorFunc channel = NULL; 442 void *data = NULL; 443 444 if (ctxt != NULL) { 445 if (ctxt->serror != NULL) 446 schannel = ctxt->serror; 447 else 448 channel = ctxt->error; 449 data = ctxt->userData; 450 ctxt->nbErrors++; 451 } 452 if (extra) 453 __xmlRaiseError(schannel, channel, data, 454 NULL, NULL, XML_FROM_RELAXNGP, 455 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 456 NULL, NULL, 0, 0, 457 "Memory allocation failed : %s\n", extra); 458 else 459 __xmlRaiseError(schannel, channel, data, 460 NULL, NULL, XML_FROM_RELAXNGP, 461 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 462 NULL, NULL, 0, 0, "Memory allocation failed\n"); 463 } 464 465 /** 466 * xmlRngVErrMemory: 467 * @ctxt: a Relax-NG validation context 468 * @extra: extra informations 469 * 470 * Handle a redefinition of attribute error 471 */ 472 static void 473 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) 474 { 475 xmlStructuredErrorFunc schannel = NULL; 476 xmlGenericErrorFunc channel = NULL; 477 void *data = NULL; 478 479 if (ctxt != NULL) { 480 if (ctxt->serror != NULL) 481 schannel = ctxt->serror; 482 else 483 channel = ctxt->error; 484 data = ctxt->userData; 485 ctxt->nbErrors++; 486 } 487 if (extra) 488 __xmlRaiseError(schannel, channel, data, 489 NULL, NULL, XML_FROM_RELAXNGV, 490 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 491 NULL, NULL, 0, 0, 492 "Memory allocation failed : %s\n", extra); 493 else 494 __xmlRaiseError(schannel, channel, data, 495 NULL, NULL, XML_FROM_RELAXNGV, 496 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 497 NULL, NULL, 0, 0, "Memory allocation failed\n"); 498 } 499 500 /** 501 * xmlRngPErr: 502 * @ctxt: a Relax-NG parser context 503 * @node: the node raising the error 504 * @error: the error code 505 * @msg: message 506 * @str1: extra info 507 * @str2: extra info 508 * 509 * Handle a Relax NG Parsing error 510 */ 511 static void LIBXML_ATTR_FORMAT(4,0) 512 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, 513 const char *msg, const xmlChar * str1, const xmlChar * str2) 514 { 515 xmlStructuredErrorFunc schannel = NULL; 516 xmlGenericErrorFunc channel = NULL; 517 void *data = NULL; 518 519 if (ctxt != NULL) { 520 if (ctxt->serror != NULL) 521 schannel = ctxt->serror; 522 else 523 channel = ctxt->error; 524 data = ctxt->userData; 525 ctxt->nbErrors++; 526 } 527 __xmlRaiseError(schannel, channel, data, 528 NULL, node, XML_FROM_RELAXNGP, 529 error, XML_ERR_ERROR, NULL, 0, 530 (const char *) str1, (const char *) str2, NULL, 0, 0, 531 msg, str1, str2); 532 } 533 534 /** 535 * xmlRngVErr: 536 * @ctxt: a Relax-NG validation context 537 * @node: the node raising the error 538 * @error: the error code 539 * @msg: message 540 * @str1: extra info 541 * @str2: extra info 542 * 543 * Handle a Relax NG Validation error 544 */ 545 static void LIBXML_ATTR_FORMAT(4,0) 546 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, 547 const char *msg, const xmlChar * str1, const xmlChar * str2) 548 { 549 xmlStructuredErrorFunc schannel = NULL; 550 xmlGenericErrorFunc channel = NULL; 551 void *data = NULL; 552 553 if (ctxt != NULL) { 554 if (ctxt->serror != NULL) 555 schannel = ctxt->serror; 556 else 557 channel = ctxt->error; 558 data = ctxt->userData; 559 ctxt->nbErrors++; 560 } 561 __xmlRaiseError(schannel, channel, data, 562 NULL, node, XML_FROM_RELAXNGV, 563 error, XML_ERR_ERROR, NULL, 0, 564 (const char *) str1, (const char *) str2, NULL, 0, 0, 565 msg, str1, str2); 566 } 567 568 /************************************************************************ 569 * * 570 * Preliminary type checking interfaces * 571 * * 572 ************************************************************************/ 573 574 /** 575 * xmlRelaxNGTypeHave: 576 * @data: data needed for the library 577 * @type: the type name 578 * @value: the value to check 579 * 580 * Function provided by a type library to check if a type is exported 581 * 582 * Returns 1 if yes, 0 if no and -1 in case of error. 583 */ 584 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type); 585 586 /** 587 * xmlRelaxNGTypeCheck: 588 * @data: data needed for the library 589 * @type: the type name 590 * @value: the value to check 591 * @result: place to store the result if needed 592 * 593 * Function provided by a type library to check if a value match a type 594 * 595 * Returns 1 if yes, 0 if no and -1 in case of error. 596 */ 597 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type, 598 const xmlChar * value, void **result, 599 xmlNodePtr node); 600 601 /** 602 * xmlRelaxNGFacetCheck: 603 * @data: data needed for the library 604 * @type: the type name 605 * @facet: the facet name 606 * @val: the facet value 607 * @strval: the string value 608 * @value: the value to check 609 * 610 * Function provided by a type library to check a value facet 611 * 612 * Returns 1 if yes, 0 if no and -1 in case of error. 613 */ 614 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type, 615 const xmlChar * facet, 616 const xmlChar * val, 617 const xmlChar * strval, void *value); 618 619 /** 620 * xmlRelaxNGTypeFree: 621 * @data: data needed for the library 622 * @result: the value to free 623 * 624 * Function provided by a type library to free a returned result 625 */ 626 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result); 627 628 /** 629 * xmlRelaxNGTypeCompare: 630 * @data: data needed for the library 631 * @type: the type name 632 * @value1: the first value 633 * @value2: the second value 634 * 635 * Function provided by a type library to compare two values accordingly 636 * to a type. 637 * 638 * Returns 1 if yes, 0 if no and -1 in case of error. 639 */ 640 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type, 641 const xmlChar * value1, 642 xmlNodePtr ctxt1, 643 void *comp1, 644 const xmlChar * value2, 645 xmlNodePtr ctxt2); 646 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary; 647 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr; 648 struct _xmlRelaxNGTypeLibrary { 649 const xmlChar *namespace; /* the datatypeLibrary value */ 650 void *data; /* data needed for the library */ 651 xmlRelaxNGTypeHave have; /* the export function */ 652 xmlRelaxNGTypeCheck check; /* the checking function */ 653 xmlRelaxNGTypeCompare comp; /* the compare function */ 654 xmlRelaxNGFacetCheck facet; /* the facet check function */ 655 xmlRelaxNGTypeFree freef; /* the freeing function */ 656 }; 657 658 /************************************************************************ 659 * * 660 * Allocation functions * 661 * * 662 ************************************************************************/ 663 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar); 664 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define); 665 static void xmlRelaxNGNormExtSpace(xmlChar * value); 666 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema); 667 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt 668 ATTRIBUTE_UNUSED, 669 xmlRelaxNGValidStatePtr state1, 670 xmlRelaxNGValidStatePtr state2); 671 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, 672 xmlRelaxNGValidStatePtr state); 673 674 /** 675 * xmlRelaxNGFreeDocument: 676 * @docu: a document structure 677 * 678 * Deallocate a RelaxNG document structure. 679 */ 680 static void 681 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu) 682 { 683 if (docu == NULL) 684 return; 685 686 if (docu->href != NULL) 687 xmlFree(docu->href); 688 if (docu->doc != NULL) 689 xmlFreeDoc(docu->doc); 690 if (docu->schema != NULL) 691 xmlRelaxNGFreeInnerSchema(docu->schema); 692 xmlFree(docu); 693 } 694 695 /** 696 * xmlRelaxNGFreeDocumentList: 697 * @docu: a list of document structure 698 * 699 * Deallocate a RelaxNG document structures. 700 */ 701 static void 702 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu) 703 { 704 xmlRelaxNGDocumentPtr next; 705 706 while (docu != NULL) { 707 next = docu->next; 708 xmlRelaxNGFreeDocument(docu); 709 docu = next; 710 } 711 } 712 713 /** 714 * xmlRelaxNGFreeInclude: 715 * @incl: a include structure 716 * 717 * Deallocate a RelaxNG include structure. 718 */ 719 static void 720 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl) 721 { 722 if (incl == NULL) 723 return; 724 725 if (incl->href != NULL) 726 xmlFree(incl->href); 727 if (incl->doc != NULL) 728 xmlFreeDoc(incl->doc); 729 if (incl->schema != NULL) 730 xmlRelaxNGFree(incl->schema); 731 xmlFree(incl); 732 } 733 734 /** 735 * xmlRelaxNGFreeIncludeList: 736 * @incl: a include structure list 737 * 738 * Deallocate a RelaxNG include structure. 739 */ 740 static void 741 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl) 742 { 743 xmlRelaxNGIncludePtr next; 744 745 while (incl != NULL) { 746 next = incl->next; 747 xmlRelaxNGFreeInclude(incl); 748 incl = next; 749 } 750 } 751 752 /** 753 * xmlRelaxNGNewRelaxNG: 754 * @ctxt: a Relax-NG validation context (optional) 755 * 756 * Allocate a new RelaxNG structure. 757 * 758 * Returns the newly allocated structure or NULL in case or error 759 */ 760 static xmlRelaxNGPtr 761 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) 762 { 763 xmlRelaxNGPtr ret; 764 765 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); 766 if (ret == NULL) { 767 xmlRngPErrMemory(ctxt, NULL); 768 return (NULL); 769 } 770 memset(ret, 0, sizeof(xmlRelaxNG)); 771 772 return (ret); 773 } 774 775 /** 776 * xmlRelaxNGFreeInnerSchema: 777 * @schema: a schema structure 778 * 779 * Deallocate a RelaxNG schema structure. 780 */ 781 static void 782 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema) 783 { 784 if (schema == NULL) 785 return; 786 787 if (schema->doc != NULL) 788 xmlFreeDoc(schema->doc); 789 if (schema->defTab != NULL) { 790 int i; 791 792 for (i = 0; i < schema->defNr; i++) 793 xmlRelaxNGFreeDefine(schema->defTab[i]); 794 xmlFree(schema->defTab); 795 } 796 797 xmlFree(schema); 798 } 799 800 /** 801 * xmlRelaxNGFree: 802 * @schema: a schema structure 803 * 804 * Deallocate a RelaxNG structure. 805 */ 806 void 807 xmlRelaxNGFree(xmlRelaxNGPtr schema) 808 { 809 if (schema == NULL) 810 return; 811 812 if (schema->topgrammar != NULL) 813 xmlRelaxNGFreeGrammar(schema->topgrammar); 814 if (schema->doc != NULL) 815 xmlFreeDoc(schema->doc); 816 if (schema->documents != NULL) 817 xmlRelaxNGFreeDocumentList(schema->documents); 818 if (schema->includes != NULL) 819 xmlRelaxNGFreeIncludeList(schema->includes); 820 if (schema->defTab != NULL) { 821 int i; 822 823 for (i = 0; i < schema->defNr; i++) 824 xmlRelaxNGFreeDefine(schema->defTab[i]); 825 xmlFree(schema->defTab); 826 } 827 828 xmlFree(schema); 829 } 830 831 /** 832 * xmlRelaxNGNewGrammar: 833 * @ctxt: a Relax-NG validation context (optional) 834 * 835 * Allocate a new RelaxNG grammar. 836 * 837 * Returns the newly allocated structure or NULL in case or error 838 */ 839 static xmlRelaxNGGrammarPtr 840 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) 841 { 842 xmlRelaxNGGrammarPtr ret; 843 844 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); 845 if (ret == NULL) { 846 xmlRngPErrMemory(ctxt, NULL); 847 return (NULL); 848 } 849 memset(ret, 0, sizeof(xmlRelaxNGGrammar)); 850 851 return (ret); 852 } 853 854 /** 855 * xmlRelaxNGFreeGrammar: 856 * @grammar: a grammar structure 857 * 858 * Deallocate a RelaxNG grammar structure. 859 */ 860 static void 861 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar) 862 { 863 if (grammar == NULL) 864 return; 865 866 if (grammar->children != NULL) { 867 xmlRelaxNGFreeGrammar(grammar->children); 868 } 869 if (grammar->next != NULL) { 870 xmlRelaxNGFreeGrammar(grammar->next); 871 } 872 if (grammar->refs != NULL) { 873 xmlHashFree(grammar->refs, NULL); 874 } 875 if (grammar->defs != NULL) { 876 xmlHashFree(grammar->defs, NULL); 877 } 878 879 xmlFree(grammar); 880 } 881 882 /** 883 * xmlRelaxNGNewDefine: 884 * @ctxt: a Relax-NG validation context 885 * @node: the node in the input document. 886 * 887 * Allocate a new RelaxNG define. 888 * 889 * Returns the newly allocated structure or NULL in case or error 890 */ 891 static xmlRelaxNGDefinePtr 892 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 893 { 894 xmlRelaxNGDefinePtr ret; 895 896 if (ctxt->defMax == 0) { 897 ctxt->defMax = 16; 898 ctxt->defNr = 0; 899 ctxt->defTab = (xmlRelaxNGDefinePtr *) 900 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); 901 if (ctxt->defTab == NULL) { 902 xmlRngPErrMemory(ctxt, "allocating define\n"); 903 return (NULL); 904 } 905 } else if (ctxt->defMax <= ctxt->defNr) { 906 xmlRelaxNGDefinePtr *tmp; 907 908 ctxt->defMax *= 2; 909 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab, 910 ctxt->defMax * 911 sizeof 912 (xmlRelaxNGDefinePtr)); 913 if (tmp == NULL) { 914 xmlRngPErrMemory(ctxt, "allocating define\n"); 915 return (NULL); 916 } 917 ctxt->defTab = tmp; 918 } 919 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); 920 if (ret == NULL) { 921 xmlRngPErrMemory(ctxt, "allocating define\n"); 922 return (NULL); 923 } 924 memset(ret, 0, sizeof(xmlRelaxNGDefine)); 925 ctxt->defTab[ctxt->defNr++] = ret; 926 ret->node = node; 927 ret->depth = -1; 928 return (ret); 929 } 930 931 /** 932 * xmlRelaxNGFreePartition: 933 * @partitions: a partition set structure 934 * 935 * Deallocate RelaxNG partition set structures. 936 */ 937 static void 938 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) 939 { 940 xmlRelaxNGInterleaveGroupPtr group; 941 int j; 942 943 if (partitions != NULL) { 944 if (partitions->groups != NULL) { 945 for (j = 0; j < partitions->nbgroups; j++) { 946 group = partitions->groups[j]; 947 if (group != NULL) { 948 if (group->defs != NULL) 949 xmlFree(group->defs); 950 if (group->attrs != NULL) 951 xmlFree(group->attrs); 952 xmlFree(group); 953 } 954 } 955 xmlFree(partitions->groups); 956 } 957 if (partitions->triage != NULL) { 958 xmlHashFree(partitions->triage, NULL); 959 } 960 xmlFree(partitions); 961 } 962 } 963 964 /** 965 * xmlRelaxNGFreeDefine: 966 * @define: a define structure 967 * 968 * Deallocate a RelaxNG define structure. 969 */ 970 static void 971 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define) 972 { 973 if (define == NULL) 974 return; 975 976 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) { 977 xmlRelaxNGTypeLibraryPtr lib; 978 979 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 980 if ((lib != NULL) && (lib->freef != NULL)) 981 lib->freef(lib->data, (void *) define->attrs); 982 } 983 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE)) 984 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data); 985 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE)) 986 xmlHashFree((xmlHashTablePtr) define->data, NULL); 987 if (define->name != NULL) 988 xmlFree(define->name); 989 if (define->ns != NULL) 990 xmlFree(define->ns); 991 if (define->value != NULL) 992 xmlFree(define->value); 993 if (define->contModel != NULL) 994 xmlRegFreeRegexp(define->contModel); 995 xmlFree(define); 996 } 997 998 /** 999 * xmlRelaxNGNewStates: 1000 * @ctxt: a Relax-NG validation context 1001 * @size: the default size for the container 1002 * 1003 * Allocate a new RelaxNG validation state container 1004 * 1005 * Returns the newly allocated structure or NULL in case or error 1006 */ 1007 static xmlRelaxNGStatesPtr 1008 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) 1009 { 1010 xmlRelaxNGStatesPtr ret; 1011 1012 if ((ctxt != NULL) && 1013 (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) { 1014 ctxt->freeStatesNr--; 1015 ret = ctxt->freeStates[ctxt->freeStatesNr]; 1016 ret->nbState = 0; 1017 return (ret); 1018 } 1019 if (size < 16) 1020 size = 16; 1021 1022 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) + 1023 (size - 1024 1) * 1025 sizeof(xmlRelaxNGValidStatePtr)); 1026 if (ret == NULL) { 1027 xmlRngVErrMemory(ctxt, "allocating states\n"); 1028 return (NULL); 1029 } 1030 ret->nbState = 0; 1031 ret->maxState = size; 1032 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) * 1033 sizeof 1034 (xmlRelaxNGValidStatePtr)); 1035 if (ret->tabState == NULL) { 1036 xmlRngVErrMemory(ctxt, "allocating states\n"); 1037 xmlFree(ret); 1038 return (NULL); 1039 } 1040 return (ret); 1041 } 1042 1043 /** 1044 * xmlRelaxNGAddStateUniq: 1045 * @ctxt: a Relax-NG validation context 1046 * @states: the states container 1047 * @state: the validation state 1048 * 1049 * Add a RelaxNG validation state to the container without checking 1050 * for unicity. 1051 * 1052 * Return 1 in case of success and 0 if this is a duplicate and -1 on error 1053 */ 1054 static int 1055 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, 1056 xmlRelaxNGStatesPtr states, 1057 xmlRelaxNGValidStatePtr state) 1058 { 1059 if (state == NULL) { 1060 return (-1); 1061 } 1062 if (states->nbState >= states->maxState) { 1063 xmlRelaxNGValidStatePtr *tmp; 1064 int size; 1065 1066 size = states->maxState * 2; 1067 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, 1068 (size) * 1069 sizeof 1070 (xmlRelaxNGValidStatePtr)); 1071 if (tmp == NULL) { 1072 xmlRngVErrMemory(ctxt, "adding states\n"); 1073 return (-1); 1074 } 1075 states->tabState = tmp; 1076 states->maxState = size; 1077 } 1078 states->tabState[states->nbState++] = state; 1079 return (1); 1080 } 1081 1082 /** 1083 * xmlRelaxNGAddState: 1084 * @ctxt: a Relax-NG validation context 1085 * @states: the states container 1086 * @state: the validation state 1087 * 1088 * Add a RelaxNG validation state to the container 1089 * 1090 * Return 1 in case of success and 0 if this is a duplicate and -1 on error 1091 */ 1092 static int 1093 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, 1094 xmlRelaxNGStatesPtr states, 1095 xmlRelaxNGValidStatePtr state) 1096 { 1097 int i; 1098 1099 if (state == NULL || states == NULL) { 1100 return (-1); 1101 } 1102 if (states->nbState >= states->maxState) { 1103 xmlRelaxNGValidStatePtr *tmp; 1104 int size; 1105 1106 size = states->maxState * 2; 1107 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, 1108 (size) * 1109 sizeof 1110 (xmlRelaxNGValidStatePtr)); 1111 if (tmp == NULL) { 1112 xmlRngVErrMemory(ctxt, "adding states\n"); 1113 return (-1); 1114 } 1115 states->tabState = tmp; 1116 states->maxState = size; 1117 } 1118 for (i = 0; i < states->nbState; i++) { 1119 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) { 1120 xmlRelaxNGFreeValidState(ctxt, state); 1121 return (0); 1122 } 1123 } 1124 states->tabState[states->nbState++] = state; 1125 return (1); 1126 } 1127 1128 /** 1129 * xmlRelaxNGFreeStates: 1130 * @ctxt: a Relax-NG validation context 1131 * @states: teh container 1132 * 1133 * Free a RelaxNG validation state container 1134 */ 1135 static void 1136 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, 1137 xmlRelaxNGStatesPtr states) 1138 { 1139 if (states == NULL) 1140 return; 1141 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) { 1142 ctxt->freeStatesMax = 40; 1143 ctxt->freeStatesNr = 0; 1144 ctxt->freeStates = (xmlRelaxNGStatesPtr *) 1145 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); 1146 if (ctxt->freeStates == NULL) { 1147 xmlRngVErrMemory(ctxt, "storing states\n"); 1148 } 1149 } else if ((ctxt != NULL) 1150 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { 1151 xmlRelaxNGStatesPtr *tmp; 1152 1153 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates, 1154 2 * ctxt->freeStatesMax * 1155 sizeof 1156 (xmlRelaxNGStatesPtr)); 1157 if (tmp == NULL) { 1158 xmlRngVErrMemory(ctxt, "storing states\n"); 1159 xmlFree(states->tabState); 1160 xmlFree(states); 1161 return; 1162 } 1163 ctxt->freeStates = tmp; 1164 ctxt->freeStatesMax *= 2; 1165 } 1166 if ((ctxt == NULL) || (ctxt->freeStates == NULL)) { 1167 xmlFree(states->tabState); 1168 xmlFree(states); 1169 } else { 1170 ctxt->freeStates[ctxt->freeStatesNr++] = states; 1171 } 1172 } 1173 1174 /** 1175 * xmlRelaxNGNewValidState: 1176 * @ctxt: a Relax-NG validation context 1177 * @node: the current node or NULL for the document 1178 * 1179 * Allocate a new RelaxNG validation state 1180 * 1181 * Returns the newly allocated structure or NULL in case or error 1182 */ 1183 static xmlRelaxNGValidStatePtr 1184 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) 1185 { 1186 xmlRelaxNGValidStatePtr ret; 1187 xmlAttrPtr attr; 1188 xmlAttrPtr attrs[MAX_ATTR]; 1189 int nbAttrs = 0; 1190 xmlNodePtr root = NULL; 1191 1192 if (node == NULL) { 1193 root = xmlDocGetRootElement(ctxt->doc); 1194 if (root == NULL) 1195 return (NULL); 1196 } else { 1197 attr = node->properties; 1198 while (attr != NULL) { 1199 if (nbAttrs < MAX_ATTR) 1200 attrs[nbAttrs++] = attr; 1201 else 1202 nbAttrs++; 1203 attr = attr->next; 1204 } 1205 } 1206 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { 1207 ctxt->freeState->nbState--; 1208 ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; 1209 } else { 1210 ret = 1211 (xmlRelaxNGValidStatePtr) 1212 xmlMalloc(sizeof(xmlRelaxNGValidState)); 1213 if (ret == NULL) { 1214 xmlRngVErrMemory(ctxt, "allocating states\n"); 1215 return (NULL); 1216 } 1217 memset(ret, 0, sizeof(xmlRelaxNGValidState)); 1218 } 1219 ret->value = NULL; 1220 ret->endvalue = NULL; 1221 if (node == NULL) { 1222 ret->node = (xmlNodePtr) ctxt->doc; 1223 ret->seq = root; 1224 } else { 1225 ret->node = node; 1226 ret->seq = node->children; 1227 } 1228 ret->nbAttrs = 0; 1229 if (nbAttrs > 0) { 1230 if (ret->attrs == NULL) { 1231 if (nbAttrs < 4) 1232 ret->maxAttrs = 4; 1233 else 1234 ret->maxAttrs = nbAttrs; 1235 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * 1236 sizeof(xmlAttrPtr)); 1237 if (ret->attrs == NULL) { 1238 xmlRngVErrMemory(ctxt, "allocating states\n"); 1239 return (ret); 1240 } 1241 } else if (ret->maxAttrs < nbAttrs) { 1242 xmlAttrPtr *tmp; 1243 1244 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * 1245 sizeof(xmlAttrPtr)); 1246 if (tmp == NULL) { 1247 xmlRngVErrMemory(ctxt, "allocating states\n"); 1248 return (ret); 1249 } 1250 ret->attrs = tmp; 1251 ret->maxAttrs = nbAttrs; 1252 } 1253 ret->nbAttrs = nbAttrs; 1254 if (nbAttrs < MAX_ATTR) { 1255 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs); 1256 } else { 1257 attr = node->properties; 1258 nbAttrs = 0; 1259 while (attr != NULL) { 1260 ret->attrs[nbAttrs++] = attr; 1261 attr = attr->next; 1262 } 1263 } 1264 } 1265 ret->nbAttrLeft = ret->nbAttrs; 1266 return (ret); 1267 } 1268 1269 /** 1270 * xmlRelaxNGCopyValidState: 1271 * @ctxt: a Relax-NG validation context 1272 * @state: a validation state 1273 * 1274 * Copy the validation state 1275 * 1276 * Returns the newly allocated structure or NULL in case or error 1277 */ 1278 static xmlRelaxNGValidStatePtr 1279 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, 1280 xmlRelaxNGValidStatePtr state) 1281 { 1282 xmlRelaxNGValidStatePtr ret; 1283 unsigned int maxAttrs; 1284 xmlAttrPtr *attrs; 1285 1286 if (state == NULL) 1287 return (NULL); 1288 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { 1289 ctxt->freeState->nbState--; 1290 ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; 1291 } else { 1292 ret = 1293 (xmlRelaxNGValidStatePtr) 1294 xmlMalloc(sizeof(xmlRelaxNGValidState)); 1295 if (ret == NULL) { 1296 xmlRngVErrMemory(ctxt, "allocating states\n"); 1297 return (NULL); 1298 } 1299 memset(ret, 0, sizeof(xmlRelaxNGValidState)); 1300 } 1301 attrs = ret->attrs; 1302 maxAttrs = ret->maxAttrs; 1303 memcpy(ret, state, sizeof(xmlRelaxNGValidState)); 1304 ret->attrs = attrs; 1305 ret->maxAttrs = maxAttrs; 1306 if (state->nbAttrs > 0) { 1307 if (ret->attrs == NULL) { 1308 ret->maxAttrs = state->maxAttrs; 1309 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * 1310 sizeof(xmlAttrPtr)); 1311 if (ret->attrs == NULL) { 1312 xmlRngVErrMemory(ctxt, "allocating states\n"); 1313 ret->nbAttrs = 0; 1314 return (ret); 1315 } 1316 } else if (ret->maxAttrs < state->nbAttrs) { 1317 xmlAttrPtr *tmp; 1318 1319 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * 1320 sizeof(xmlAttrPtr)); 1321 if (tmp == NULL) { 1322 xmlRngVErrMemory(ctxt, "allocating states\n"); 1323 ret->nbAttrs = 0; 1324 return (ret); 1325 } 1326 ret->maxAttrs = state->maxAttrs; 1327 ret->attrs = tmp; 1328 } 1329 memcpy(ret->attrs, state->attrs, 1330 state->nbAttrs * sizeof(xmlAttrPtr)); 1331 } 1332 return (ret); 1333 } 1334 1335 /** 1336 * xmlRelaxNGEqualValidState: 1337 * @ctxt: a Relax-NG validation context 1338 * @state1: a validation state 1339 * @state2: a validation state 1340 * 1341 * Compare the validation states for equality 1342 * 1343 * Returns 1 if equald, 0 otherwise 1344 */ 1345 static int 1346 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 1347 xmlRelaxNGValidStatePtr state1, 1348 xmlRelaxNGValidStatePtr state2) 1349 { 1350 int i; 1351 1352 if ((state1 == NULL) || (state2 == NULL)) 1353 return (0); 1354 if (state1 == state2) 1355 return (1); 1356 if (state1->node != state2->node) 1357 return (0); 1358 if (state1->seq != state2->seq) 1359 return (0); 1360 if (state1->nbAttrLeft != state2->nbAttrLeft) 1361 return (0); 1362 if (state1->nbAttrs != state2->nbAttrs) 1363 return (0); 1364 if (state1->endvalue != state2->endvalue) 1365 return (0); 1366 if ((state1->value != state2->value) && 1367 (!xmlStrEqual(state1->value, state2->value))) 1368 return (0); 1369 for (i = 0; i < state1->nbAttrs; i++) { 1370 if (state1->attrs[i] != state2->attrs[i]) 1371 return (0); 1372 } 1373 return (1); 1374 } 1375 1376 /** 1377 * xmlRelaxNGFreeValidState: 1378 * @state: a validation state structure 1379 * 1380 * Deallocate a RelaxNG validation state structure. 1381 */ 1382 static void 1383 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, 1384 xmlRelaxNGValidStatePtr state) 1385 { 1386 if (state == NULL) 1387 return; 1388 1389 if ((ctxt != NULL) && (ctxt->freeState == NULL)) { 1390 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40); 1391 } 1392 if ((ctxt == NULL) || (ctxt->freeState == NULL)) { 1393 if (state->attrs != NULL) 1394 xmlFree(state->attrs); 1395 xmlFree(state); 1396 } else { 1397 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state); 1398 } 1399 } 1400 1401 /************************************************************************ 1402 * * 1403 * Semi internal functions * 1404 * * 1405 ************************************************************************/ 1406 1407 /** 1408 * xmlRelaxParserSetFlag: 1409 * @ctxt: a RelaxNG parser context 1410 * @flags: a set of flags values 1411 * 1412 * Semi private function used to pass informations to a parser context 1413 * which are a combination of xmlRelaxNGParserFlag . 1414 * 1415 * Returns 0 if success and -1 in case of error 1416 */ 1417 int 1418 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) 1419 { 1420 if (ctxt == NULL) return(-1); 1421 if (flags & XML_RELAXNGP_FREE_DOC) { 1422 ctxt->crng |= XML_RELAXNGP_FREE_DOC; 1423 flags -= XML_RELAXNGP_FREE_DOC; 1424 } 1425 if (flags & XML_RELAXNGP_CRNG) { 1426 ctxt->crng |= XML_RELAXNGP_CRNG; 1427 flags -= XML_RELAXNGP_CRNG; 1428 } 1429 if (flags != 0) return(-1); 1430 return(0); 1431 } 1432 1433 /************************************************************************ 1434 * * 1435 * Document functions * 1436 * * 1437 ************************************************************************/ 1438 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, 1439 xmlDocPtr doc); 1440 1441 /** 1442 * xmlRelaxNGIncludePush: 1443 * @ctxt: the parser context 1444 * @value: the element doc 1445 * 1446 * Pushes a new include on top of the include stack 1447 * 1448 * Returns 0 in case of error, the index in the stack otherwise 1449 */ 1450 static int 1451 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, 1452 xmlRelaxNGIncludePtr value) 1453 { 1454 if (ctxt->incTab == NULL) { 1455 ctxt->incMax = 4; 1456 ctxt->incNr = 0; 1457 ctxt->incTab = 1458 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * 1459 sizeof(ctxt->incTab[0])); 1460 if (ctxt->incTab == NULL) { 1461 xmlRngPErrMemory(ctxt, "allocating include\n"); 1462 return (0); 1463 } 1464 } 1465 if (ctxt->incNr >= ctxt->incMax) { 1466 ctxt->incMax *= 2; 1467 ctxt->incTab = 1468 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab, 1469 ctxt->incMax * 1470 sizeof(ctxt->incTab[0])); 1471 if (ctxt->incTab == NULL) { 1472 xmlRngPErrMemory(ctxt, "allocating include\n"); 1473 return (0); 1474 } 1475 } 1476 ctxt->incTab[ctxt->incNr] = value; 1477 ctxt->inc = value; 1478 return (ctxt->incNr++); 1479 } 1480 1481 /** 1482 * xmlRelaxNGIncludePop: 1483 * @ctxt: the parser context 1484 * 1485 * Pops the top include from the include stack 1486 * 1487 * Returns the include just removed 1488 */ 1489 static xmlRelaxNGIncludePtr 1490 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt) 1491 { 1492 xmlRelaxNGIncludePtr ret; 1493 1494 if (ctxt->incNr <= 0) 1495 return (NULL); 1496 ctxt->incNr--; 1497 if (ctxt->incNr > 0) 1498 ctxt->inc = ctxt->incTab[ctxt->incNr - 1]; 1499 else 1500 ctxt->inc = NULL; 1501 ret = ctxt->incTab[ctxt->incNr]; 1502 ctxt->incTab[ctxt->incNr] = NULL; 1503 return (ret); 1504 } 1505 1506 /** 1507 * xmlRelaxNGRemoveRedefine: 1508 * @ctxt: the parser context 1509 * @URL: the normalized URL 1510 * @target: the included target 1511 * @name: the define name to eliminate 1512 * 1513 * Applies the elimination algorithm of 4.7 1514 * 1515 * Returns 0 in case of error, 1 in case of success. 1516 */ 1517 static int 1518 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, 1519 const xmlChar * URL ATTRIBUTE_UNUSED, 1520 xmlNodePtr target, const xmlChar * name) 1521 { 1522 int found = 0; 1523 xmlNodePtr tmp, tmp2; 1524 xmlChar *name2; 1525 1526 #ifdef DEBUG_INCLUDE 1527 if (name == NULL) 1528 xmlGenericError(xmlGenericErrorContext, 1529 "Elimination of <include> start from %s\n", URL); 1530 else 1531 xmlGenericError(xmlGenericErrorContext, 1532 "Elimination of <include> define %s from %s\n", 1533 name, URL); 1534 #endif 1535 tmp = target; 1536 while (tmp != NULL) { 1537 tmp2 = tmp->next; 1538 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) { 1539 found = 1; 1540 xmlUnlinkNode(tmp); 1541 xmlFreeNode(tmp); 1542 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) { 1543 name2 = xmlGetProp(tmp, BAD_CAST "name"); 1544 xmlRelaxNGNormExtSpace(name2); 1545 if (name2 != NULL) { 1546 if (xmlStrEqual(name, name2)) { 1547 found = 1; 1548 xmlUnlinkNode(tmp); 1549 xmlFreeNode(tmp); 1550 } 1551 xmlFree(name2); 1552 } 1553 } else if (IS_RELAXNG(tmp, "include")) { 1554 xmlChar *href = NULL; 1555 xmlRelaxNGDocumentPtr inc = tmp->psvi; 1556 1557 if ((inc != NULL) && (inc->doc != NULL) && 1558 (inc->doc->children != NULL)) { 1559 1560 if (xmlStrEqual 1561 (inc->doc->children->name, BAD_CAST "grammar")) { 1562 #ifdef DEBUG_INCLUDE 1563 href = xmlGetProp(tmp, BAD_CAST "href"); 1564 #endif 1565 if (xmlRelaxNGRemoveRedefine(ctxt, href, 1566 xmlDocGetRootElement(inc->doc)->children, 1567 name) == 1) { 1568 found = 1; 1569 } 1570 #ifdef DEBUG_INCLUDE 1571 if (href != NULL) 1572 xmlFree(href); 1573 #endif 1574 } 1575 } 1576 } 1577 tmp = tmp2; 1578 } 1579 return (found); 1580 } 1581 1582 /** 1583 * xmlRelaxNGLoadInclude: 1584 * @ctxt: the parser context 1585 * @URL: the normalized URL 1586 * @node: the include node. 1587 * @ns: the namespace passed from the context. 1588 * 1589 * First lookup if the document is already loaded into the parser context, 1590 * check against recursion. If not found the resource is loaded and 1591 * the content is preprocessed before being returned back to the caller. 1592 * 1593 * Returns the xmlRelaxNGIncludePtr or NULL in case of error 1594 */ 1595 static xmlRelaxNGIncludePtr 1596 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, 1597 xmlNodePtr node, const xmlChar * ns) 1598 { 1599 xmlRelaxNGIncludePtr ret = NULL; 1600 xmlDocPtr doc; 1601 int i; 1602 xmlNodePtr root, cur; 1603 1604 #ifdef DEBUG_INCLUDE 1605 xmlGenericError(xmlGenericErrorContext, 1606 "xmlRelaxNGLoadInclude(%s)\n", URL); 1607 #endif 1608 1609 /* 1610 * check against recursion in the stack 1611 */ 1612 for (i = 0; i < ctxt->incNr; i++) { 1613 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) { 1614 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE, 1615 "Detected an Include recursion for %s\n", URL, 1616 NULL); 1617 return (NULL); 1618 } 1619 } 1620 1621 /* 1622 * load the document 1623 */ 1624 doc = xmlReadFile((const char *) URL,NULL,0); 1625 if (doc == NULL) { 1626 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, 1627 "xmlRelaxNG: could not load %s\n", URL, NULL); 1628 return (NULL); 1629 } 1630 #ifdef DEBUG_INCLUDE 1631 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL); 1632 #endif 1633 1634 /* 1635 * Allocate the document structures and register it first. 1636 */ 1637 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); 1638 if (ret == NULL) { 1639 xmlRngPErrMemory(ctxt, "allocating include\n"); 1640 xmlFreeDoc(doc); 1641 return (NULL); 1642 } 1643 memset(ret, 0, sizeof(xmlRelaxNGInclude)); 1644 ret->doc = doc; 1645 ret->href = xmlStrdup(URL); 1646 ret->next = ctxt->includes; 1647 ctxt->includes = ret; 1648 1649 /* 1650 * transmit the ns if needed 1651 */ 1652 if (ns != NULL) { 1653 root = xmlDocGetRootElement(doc); 1654 if (root != NULL) { 1655 if (xmlHasProp(root, BAD_CAST "ns") == NULL) { 1656 xmlSetProp(root, BAD_CAST "ns", ns); 1657 } 1658 } 1659 } 1660 1661 /* 1662 * push it on the stack 1663 */ 1664 xmlRelaxNGIncludePush(ctxt, ret); 1665 1666 /* 1667 * Some preprocessing of the document content, this include recursing 1668 * in the include stack. 1669 */ 1670 #ifdef DEBUG_INCLUDE 1671 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL); 1672 #endif 1673 1674 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 1675 if (doc == NULL) { 1676 ctxt->inc = NULL; 1677 return (NULL); 1678 } 1679 1680 /* 1681 * Pop up the include from the stack 1682 */ 1683 xmlRelaxNGIncludePop(ctxt); 1684 1685 #ifdef DEBUG_INCLUDE 1686 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL); 1687 #endif 1688 /* 1689 * Check that the top element is a grammar 1690 */ 1691 root = xmlDocGetRootElement(doc); 1692 if (root == NULL) { 1693 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, 1694 "xmlRelaxNG: included document is empty %s\n", URL, 1695 NULL); 1696 return (NULL); 1697 } 1698 if (!IS_RELAXNG(root, "grammar")) { 1699 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 1700 "xmlRelaxNG: included document %s root is not a grammar\n", 1701 URL, NULL); 1702 return (NULL); 1703 } 1704 1705 /* 1706 * Elimination of redefined rules in the include. 1707 */ 1708 cur = node->children; 1709 while (cur != NULL) { 1710 if (IS_RELAXNG(cur, "start")) { 1711 int found = 0; 1712 1713 found = 1714 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL); 1715 if (!found) { 1716 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING, 1717 "xmlRelaxNG: include %s has a start but not the included grammar\n", 1718 URL, NULL); 1719 } 1720 } else if (IS_RELAXNG(cur, "define")) { 1721 xmlChar *name; 1722 1723 name = xmlGetProp(cur, BAD_CAST "name"); 1724 if (name == NULL) { 1725 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING, 1726 "xmlRelaxNG: include %s has define without name\n", 1727 URL, NULL); 1728 } else { 1729 int found; 1730 1731 xmlRelaxNGNormExtSpace(name); 1732 found = xmlRelaxNGRemoveRedefine(ctxt, URL, 1733 root->children, name); 1734 if (!found) { 1735 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING, 1736 "xmlRelaxNG: include %s has a define %s but not the included grammar\n", 1737 URL, name); 1738 } 1739 xmlFree(name); 1740 } 1741 } 1742 cur = cur->next; 1743 } 1744 1745 1746 return (ret); 1747 } 1748 1749 /** 1750 * xmlRelaxNGValidErrorPush: 1751 * @ctxt: the validation context 1752 * @err: the error code 1753 * @arg1: the first string argument 1754 * @arg2: the second string argument 1755 * @dup: arg need to be duplicated 1756 * 1757 * Pushes a new error on top of the error stack 1758 * 1759 * Returns 0 in case of error, the index in the stack otherwise 1760 */ 1761 static int 1762 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, 1763 xmlRelaxNGValidErr err, const xmlChar * arg1, 1764 const xmlChar * arg2, int dup) 1765 { 1766 xmlRelaxNGValidErrorPtr cur; 1767 1768 #ifdef DEBUG_ERROR 1769 xmlGenericError(xmlGenericErrorContext, 1770 "Pushing error %d at %d on stack\n", err, ctxt->errNr); 1771 #endif 1772 if (ctxt->errTab == NULL) { 1773 ctxt->errMax = 8; 1774 ctxt->errNr = 0; 1775 ctxt->errTab = 1776 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax * 1777 sizeof 1778 (xmlRelaxNGValidError)); 1779 if (ctxt->errTab == NULL) { 1780 xmlRngVErrMemory(ctxt, "pushing error\n"); 1781 return (0); 1782 } 1783 ctxt->err = NULL; 1784 } 1785 if (ctxt->errNr >= ctxt->errMax) { 1786 ctxt->errMax *= 2; 1787 ctxt->errTab = 1788 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab, 1789 ctxt->errMax * 1790 sizeof 1791 (xmlRelaxNGValidError)); 1792 if (ctxt->errTab == NULL) { 1793 xmlRngVErrMemory(ctxt, "pushing error\n"); 1794 return (0); 1795 } 1796 ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; 1797 } 1798 if ((ctxt->err != NULL) && (ctxt->state != NULL) && 1799 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err)) 1800 return (ctxt->errNr); 1801 cur = &ctxt->errTab[ctxt->errNr]; 1802 cur->err = err; 1803 if (dup) { 1804 cur->arg1 = xmlStrdup(arg1); 1805 cur->arg2 = xmlStrdup(arg2); 1806 cur->flags = ERROR_IS_DUP; 1807 } else { 1808 cur->arg1 = arg1; 1809 cur->arg2 = arg2; 1810 cur->flags = 0; 1811 } 1812 if (ctxt->state != NULL) { 1813 cur->node = ctxt->state->node; 1814 cur->seq = ctxt->state->seq; 1815 } else { 1816 cur->node = NULL; 1817 cur->seq = NULL; 1818 } 1819 ctxt->err = cur; 1820 return (ctxt->errNr++); 1821 } 1822 1823 /** 1824 * xmlRelaxNGValidErrorPop: 1825 * @ctxt: the validation context 1826 * 1827 * Pops the top error from the error stack 1828 */ 1829 static void 1830 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt) 1831 { 1832 xmlRelaxNGValidErrorPtr cur; 1833 1834 if (ctxt->errNr <= 0) { 1835 ctxt->err = NULL; 1836 return; 1837 } 1838 ctxt->errNr--; 1839 if (ctxt->errNr > 0) 1840 ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; 1841 else 1842 ctxt->err = NULL; 1843 cur = &ctxt->errTab[ctxt->errNr]; 1844 if (cur->flags & ERROR_IS_DUP) { 1845 if (cur->arg1 != NULL) 1846 xmlFree((xmlChar *) cur->arg1); 1847 cur->arg1 = NULL; 1848 if (cur->arg2 != NULL) 1849 xmlFree((xmlChar *) cur->arg2); 1850 cur->arg2 = NULL; 1851 cur->flags = 0; 1852 } 1853 } 1854 1855 /** 1856 * xmlRelaxNGDocumentPush: 1857 * @ctxt: the parser context 1858 * @value: the element doc 1859 * 1860 * Pushes a new doc on top of the doc stack 1861 * 1862 * Returns 0 in case of error, the index in the stack otherwise 1863 */ 1864 static int 1865 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, 1866 xmlRelaxNGDocumentPtr value) 1867 { 1868 if (ctxt->docTab == NULL) { 1869 ctxt->docMax = 4; 1870 ctxt->docNr = 0; 1871 ctxt->docTab = 1872 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * 1873 sizeof(ctxt->docTab[0])); 1874 if (ctxt->docTab == NULL) { 1875 xmlRngPErrMemory(ctxt, "adding document\n"); 1876 return (0); 1877 } 1878 } 1879 if (ctxt->docNr >= ctxt->docMax) { 1880 ctxt->docMax *= 2; 1881 ctxt->docTab = 1882 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab, 1883 ctxt->docMax * 1884 sizeof(ctxt->docTab[0])); 1885 if (ctxt->docTab == NULL) { 1886 xmlRngPErrMemory(ctxt, "adding document\n"); 1887 return (0); 1888 } 1889 } 1890 ctxt->docTab[ctxt->docNr] = value; 1891 ctxt->doc = value; 1892 return (ctxt->docNr++); 1893 } 1894 1895 /** 1896 * xmlRelaxNGDocumentPop: 1897 * @ctxt: the parser context 1898 * 1899 * Pops the top doc from the doc stack 1900 * 1901 * Returns the doc just removed 1902 */ 1903 static xmlRelaxNGDocumentPtr 1904 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt) 1905 { 1906 xmlRelaxNGDocumentPtr ret; 1907 1908 if (ctxt->docNr <= 0) 1909 return (NULL); 1910 ctxt->docNr--; 1911 if (ctxt->docNr > 0) 1912 ctxt->doc = ctxt->docTab[ctxt->docNr - 1]; 1913 else 1914 ctxt->doc = NULL; 1915 ret = ctxt->docTab[ctxt->docNr]; 1916 ctxt->docTab[ctxt->docNr] = NULL; 1917 return (ret); 1918 } 1919 1920 /** 1921 * xmlRelaxNGLoadExternalRef: 1922 * @ctxt: the parser context 1923 * @URL: the normalized URL 1924 * @ns: the inherited ns if any 1925 * 1926 * First lookup if the document is already loaded into the parser context, 1927 * check against recursion. If not found the resource is loaded and 1928 * the content is preprocessed before being returned back to the caller. 1929 * 1930 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error 1931 */ 1932 static xmlRelaxNGDocumentPtr 1933 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, 1934 const xmlChar * URL, const xmlChar * ns) 1935 { 1936 xmlRelaxNGDocumentPtr ret = NULL; 1937 xmlDocPtr doc; 1938 xmlNodePtr root; 1939 int i; 1940 1941 /* 1942 * check against recursion in the stack 1943 */ 1944 for (i = 0; i < ctxt->docNr; i++) { 1945 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) { 1946 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE, 1947 "Detected an externalRef recursion for %s\n", URL, 1948 NULL); 1949 return (NULL); 1950 } 1951 } 1952 1953 /* 1954 * load the document 1955 */ 1956 doc = xmlReadFile((const char *) URL,NULL,0); 1957 if (doc == NULL) { 1958 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 1959 "xmlRelaxNG: could not load %s\n", URL, NULL); 1960 return (NULL); 1961 } 1962 1963 /* 1964 * Allocate the document structures and register it first. 1965 */ 1966 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); 1967 if (ret == NULL) { 1968 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, 1969 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); 1970 xmlFreeDoc(doc); 1971 return (NULL); 1972 } 1973 memset(ret, 0, sizeof(xmlRelaxNGDocument)); 1974 ret->doc = doc; 1975 ret->href = xmlStrdup(URL); 1976 ret->next = ctxt->documents; 1977 ret->externalRef = 1; 1978 ctxt->documents = ret; 1979 1980 /* 1981 * transmit the ns if needed 1982 */ 1983 if (ns != NULL) { 1984 root = xmlDocGetRootElement(doc); 1985 if (root != NULL) { 1986 if (xmlHasProp(root, BAD_CAST "ns") == NULL) { 1987 xmlSetProp(root, BAD_CAST "ns", ns); 1988 } 1989 } 1990 } 1991 1992 /* 1993 * push it on the stack and register it in the hash table 1994 */ 1995 xmlRelaxNGDocumentPush(ctxt, ret); 1996 1997 /* 1998 * Some preprocessing of the document content 1999 */ 2000 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 2001 if (doc == NULL) { 2002 ctxt->doc = NULL; 2003 return (NULL); 2004 } 2005 2006 xmlRelaxNGDocumentPop(ctxt); 2007 2008 return (ret); 2009 } 2010 2011 /************************************************************************ 2012 * * 2013 * Error functions * 2014 * * 2015 ************************************************************************/ 2016 2017 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0); 2018 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0); 2019 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0); 2020 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1); 2021 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1); 2022 2023 static const char * 2024 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) 2025 { 2026 if (def == NULL) 2027 return ("none"); 2028 switch (def->type) { 2029 case XML_RELAXNG_EMPTY: 2030 return ("empty"); 2031 case XML_RELAXNG_NOT_ALLOWED: 2032 return ("notAllowed"); 2033 case XML_RELAXNG_EXCEPT: 2034 return ("except"); 2035 case XML_RELAXNG_TEXT: 2036 return ("text"); 2037 case XML_RELAXNG_ELEMENT: 2038 return ("element"); 2039 case XML_RELAXNG_DATATYPE: 2040 return ("datatype"); 2041 case XML_RELAXNG_VALUE: 2042 return ("value"); 2043 case XML_RELAXNG_LIST: 2044 return ("list"); 2045 case XML_RELAXNG_ATTRIBUTE: 2046 return ("attribute"); 2047 case XML_RELAXNG_DEF: 2048 return ("def"); 2049 case XML_RELAXNG_REF: 2050 return ("ref"); 2051 case XML_RELAXNG_EXTERNALREF: 2052 return ("externalRef"); 2053 case XML_RELAXNG_PARENTREF: 2054 return ("parentRef"); 2055 case XML_RELAXNG_OPTIONAL: 2056 return ("optional"); 2057 case XML_RELAXNG_ZEROORMORE: 2058 return ("zeroOrMore"); 2059 case XML_RELAXNG_ONEORMORE: 2060 return ("oneOrMore"); 2061 case XML_RELAXNG_CHOICE: 2062 return ("choice"); 2063 case XML_RELAXNG_GROUP: 2064 return ("group"); 2065 case XML_RELAXNG_INTERLEAVE: 2066 return ("interleave"); 2067 case XML_RELAXNG_START: 2068 return ("start"); 2069 case XML_RELAXNG_NOOP: 2070 return ("noop"); 2071 case XML_RELAXNG_PARAM: 2072 return ("param"); 2073 } 2074 return ("unknown"); 2075 } 2076 2077 /** 2078 * xmlRelaxNGGetErrorString: 2079 * @err: the error code 2080 * @arg1: the first string argument 2081 * @arg2: the second string argument 2082 * 2083 * computes a formatted error string for the given error code and args 2084 * 2085 * Returns the error string, it must be deallocated by the caller 2086 */ 2087 static xmlChar * 2088 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1, 2089 const xmlChar * arg2) 2090 { 2091 char msg[1000]; 2092 xmlChar *result; 2093 2094 if (arg1 == NULL) 2095 arg1 = BAD_CAST ""; 2096 if (arg2 == NULL) 2097 arg2 = BAD_CAST ""; 2098 2099 msg[0] = 0; 2100 switch (err) { 2101 case XML_RELAXNG_OK: 2102 return (NULL); 2103 case XML_RELAXNG_ERR_MEMORY: 2104 return (xmlCharStrdup("out of memory\n")); 2105 case XML_RELAXNG_ERR_TYPE: 2106 snprintf(msg, 1000, "failed to validate type %s\n", arg1); 2107 break; 2108 case XML_RELAXNG_ERR_TYPEVAL: 2109 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1, 2110 arg2); 2111 break; 2112 case XML_RELAXNG_ERR_DUPID: 2113 snprintf(msg, 1000, "ID %s redefined\n", arg1); 2114 break; 2115 case XML_RELAXNG_ERR_TYPECMP: 2116 snprintf(msg, 1000, "failed to compare type %s\n", arg1); 2117 break; 2118 case XML_RELAXNG_ERR_NOSTATE: 2119 return (xmlCharStrdup("Internal error: no state\n")); 2120 case XML_RELAXNG_ERR_NODEFINE: 2121 return (xmlCharStrdup("Internal error: no define\n")); 2122 case XML_RELAXNG_ERR_INTERNAL: 2123 snprintf(msg, 1000, "Internal error: %s\n", arg1); 2124 break; 2125 case XML_RELAXNG_ERR_LISTEXTRA: 2126 snprintf(msg, 1000, "Extra data in list: %s\n", arg1); 2127 break; 2128 case XML_RELAXNG_ERR_INTERNODATA: 2129 return (xmlCharStrdup 2130 ("Internal: interleave block has no data\n")); 2131 case XML_RELAXNG_ERR_INTERSEQ: 2132 return (xmlCharStrdup("Invalid sequence in interleave\n")); 2133 case XML_RELAXNG_ERR_INTEREXTRA: 2134 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1); 2135 break; 2136 case XML_RELAXNG_ERR_ELEMNAME: 2137 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1, 2138 arg2); 2139 break; 2140 case XML_RELAXNG_ERR_ELEMNONS: 2141 snprintf(msg, 1000, "Expecting a namespace for element %s\n", 2142 arg1); 2143 break; 2144 case XML_RELAXNG_ERR_ELEMWRONGNS: 2145 snprintf(msg, 1000, 2146 "Element %s has wrong namespace: expecting %s\n", arg1, 2147 arg2); 2148 break; 2149 case XML_RELAXNG_ERR_ELEMWRONG: 2150 snprintf(msg, 1000, "Did not expect element %s there\n", arg1); 2151 break; 2152 case XML_RELAXNG_ERR_TEXTWRONG: 2153 snprintf(msg, 1000, 2154 "Did not expect text in element %s content\n", arg1); 2155 break; 2156 case XML_RELAXNG_ERR_ELEMEXTRANS: 2157 snprintf(msg, 1000, "Expecting no namespace for element %s\n", 2158 arg1); 2159 break; 2160 case XML_RELAXNG_ERR_ELEMNOTEMPTY: 2161 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1); 2162 break; 2163 case XML_RELAXNG_ERR_NOELEM: 2164 snprintf(msg, 1000, "Expecting an element %s, got nothing\n", 2165 arg1); 2166 break; 2167 case XML_RELAXNG_ERR_NOTELEM: 2168 return (xmlCharStrdup("Expecting an element got text\n")); 2169 case XML_RELAXNG_ERR_ATTRVALID: 2170 snprintf(msg, 1000, "Element %s failed to validate attributes\n", 2171 arg1); 2172 break; 2173 case XML_RELAXNG_ERR_CONTENTVALID: 2174 snprintf(msg, 1000, "Element %s failed to validate content\n", 2175 arg1); 2176 break; 2177 case XML_RELAXNG_ERR_EXTRACONTENT: 2178 snprintf(msg, 1000, "Element %s has extra content: %s\n", 2179 arg1, arg2); 2180 break; 2181 case XML_RELAXNG_ERR_INVALIDATTR: 2182 snprintf(msg, 1000, "Invalid attribute %s for element %s\n", 2183 arg1, arg2); 2184 break; 2185 case XML_RELAXNG_ERR_LACKDATA: 2186 snprintf(msg, 1000, "Datatype element %s contains no data\n", 2187 arg1); 2188 break; 2189 case XML_RELAXNG_ERR_DATAELEM: 2190 snprintf(msg, 1000, "Datatype element %s has child elements\n", 2191 arg1); 2192 break; 2193 case XML_RELAXNG_ERR_VALELEM: 2194 snprintf(msg, 1000, "Value element %s has child elements\n", 2195 arg1); 2196 break; 2197 case XML_RELAXNG_ERR_LISTELEM: 2198 snprintf(msg, 1000, "List element %s has child elements\n", 2199 arg1); 2200 break; 2201 case XML_RELAXNG_ERR_DATATYPE: 2202 snprintf(msg, 1000, "Error validating datatype %s\n", arg1); 2203 break; 2204 case XML_RELAXNG_ERR_VALUE: 2205 snprintf(msg, 1000, "Error validating value %s\n", arg1); 2206 break; 2207 case XML_RELAXNG_ERR_LIST: 2208 return (xmlCharStrdup("Error validating list\n")); 2209 case XML_RELAXNG_ERR_NOGRAMMAR: 2210 return (xmlCharStrdup("No top grammar defined\n")); 2211 case XML_RELAXNG_ERR_EXTRADATA: 2212 return (xmlCharStrdup("Extra data in the document\n")); 2213 default: 2214 return (xmlCharStrdup("Unknown error !\n")); 2215 } 2216 if (msg[0] == 0) { 2217 snprintf(msg, 1000, "Unknown error code %d\n", err); 2218 } 2219 msg[1000 - 1] = 0; 2220 result = xmlCharStrdup(msg); 2221 return (xmlEscapeFormatString(&result)); 2222 } 2223 2224 /** 2225 * xmlRelaxNGShowValidError: 2226 * @ctxt: the validation context 2227 * @err: the error number 2228 * @node: the node 2229 * @child: the node child generating the problem. 2230 * @arg1: the first argument 2231 * @arg2: the second argument 2232 * 2233 * Show a validation error. 2234 */ 2235 static void 2236 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, 2237 xmlRelaxNGValidErr err, xmlNodePtr node, 2238 xmlNodePtr child, const xmlChar * arg1, 2239 const xmlChar * arg2) 2240 { 2241 xmlChar *msg; 2242 2243 if (ctxt->flags & FLAGS_NOERROR) 2244 return; 2245 2246 #ifdef DEBUG_ERROR 2247 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err); 2248 #endif 2249 msg = xmlRelaxNGGetErrorString(err, arg1, arg2); 2250 if (msg == NULL) 2251 return; 2252 2253 if (ctxt->errNo == XML_RELAXNG_OK) 2254 ctxt->errNo = err; 2255 xmlRngVErr(ctxt, (child == NULL ? node : child), err, 2256 (const char *) msg, arg1, arg2); 2257 xmlFree(msg); 2258 } 2259 2260 /** 2261 * xmlRelaxNGPopErrors: 2262 * @ctxt: the validation context 2263 * @level: the error level in the stack 2264 * 2265 * pop and discard all errors until the given level is reached 2266 */ 2267 static void 2268 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) 2269 { 2270 int i; 2271 xmlRelaxNGValidErrorPtr err; 2272 2273 #ifdef DEBUG_ERROR 2274 xmlGenericError(xmlGenericErrorContext, 2275 "Pop errors till level %d\n", level); 2276 #endif 2277 for (i = level; i < ctxt->errNr; i++) { 2278 err = &ctxt->errTab[i]; 2279 if (err->flags & ERROR_IS_DUP) { 2280 if (err->arg1 != NULL) 2281 xmlFree((xmlChar *) err->arg1); 2282 err->arg1 = NULL; 2283 if (err->arg2 != NULL) 2284 xmlFree((xmlChar *) err->arg2); 2285 err->arg2 = NULL; 2286 err->flags = 0; 2287 } 2288 } 2289 ctxt->errNr = level; 2290 if (ctxt->errNr <= 0) 2291 ctxt->err = NULL; 2292 } 2293 2294 /** 2295 * xmlRelaxNGDumpValidError: 2296 * @ctxt: the validation context 2297 * 2298 * Show all validation error over a given index. 2299 */ 2300 static void 2301 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) 2302 { 2303 int i, j, k; 2304 xmlRelaxNGValidErrorPtr err, dup; 2305 2306 #ifdef DEBUG_ERROR 2307 xmlGenericError(xmlGenericErrorContext, 2308 "Dumping error stack %d errors\n", ctxt->errNr); 2309 #endif 2310 for (i = 0, k = 0; i < ctxt->errNr; i++) { 2311 err = &ctxt->errTab[i]; 2312 if (k < MAX_ERROR) { 2313 for (j = 0; j < i; j++) { 2314 dup = &ctxt->errTab[j]; 2315 if ((err->err == dup->err) && (err->node == dup->node) && 2316 (xmlStrEqual(err->arg1, dup->arg1)) && 2317 (xmlStrEqual(err->arg2, dup->arg2))) { 2318 goto skip; 2319 } 2320 } 2321 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq, 2322 err->arg1, err->arg2); 2323 k++; 2324 } 2325 skip: 2326 if (err->flags & ERROR_IS_DUP) { 2327 if (err->arg1 != NULL) 2328 xmlFree((xmlChar *) err->arg1); 2329 err->arg1 = NULL; 2330 if (err->arg2 != NULL) 2331 xmlFree((xmlChar *) err->arg2); 2332 err->arg2 = NULL; 2333 err->flags = 0; 2334 } 2335 } 2336 ctxt->errNr = 0; 2337 } 2338 2339 /** 2340 * xmlRelaxNGAddValidError: 2341 * @ctxt: the validation context 2342 * @err: the error number 2343 * @arg1: the first argument 2344 * @arg2: the second argument 2345 * @dup: need to dup the args 2346 * 2347 * Register a validation error, either generating it if it's sure 2348 * or stacking it for later handling if unsure. 2349 */ 2350 static void 2351 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, 2352 xmlRelaxNGValidErr err, const xmlChar * arg1, 2353 const xmlChar * arg2, int dup) 2354 { 2355 if (ctxt == NULL) 2356 return; 2357 if (ctxt->flags & FLAGS_NOERROR) 2358 return; 2359 2360 #ifdef DEBUG_ERROR 2361 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err); 2362 #endif 2363 /* 2364 * generate the error directly 2365 */ 2366 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) || 2367 (ctxt->flags & FLAGS_NEGATIVE)) { 2368 xmlNodePtr node, seq; 2369 2370 /* 2371 * Flush first any stacked error which might be the 2372 * real cause of the problem. 2373 */ 2374 if (ctxt->errNr != 0) 2375 xmlRelaxNGDumpValidError(ctxt); 2376 if (ctxt->state != NULL) { 2377 node = ctxt->state->node; 2378 seq = ctxt->state->seq; 2379 } else { 2380 node = seq = NULL; 2381 } 2382 if ((node == NULL) && (seq == NULL)) { 2383 node = ctxt->pnode; 2384 } 2385 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2); 2386 } 2387 /* 2388 * Stack the error for later processing if needed 2389 */ 2390 else { 2391 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup); 2392 } 2393 } 2394 2395 2396 /************************************************************************ 2397 * * 2398 * Type library hooks * 2399 * * 2400 ************************************************************************/ 2401 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, 2402 const xmlChar * str); 2403 2404 /** 2405 * xmlRelaxNGSchemaTypeHave: 2406 * @data: data needed for the library 2407 * @type: the type name 2408 * 2409 * Check if the given type is provided by 2410 * the W3C XMLSchema Datatype library. 2411 * 2412 * Returns 1 if yes, 0 if no and -1 in case of error. 2413 */ 2414 static int 2415 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type) 2416 { 2417 xmlSchemaTypePtr typ; 2418 2419 if (type == NULL) 2420 return (-1); 2421 typ = xmlSchemaGetPredefinedType(type, 2422 BAD_CAST 2423 "http://www.w3.org/2001/XMLSchema"); 2424 if (typ == NULL) 2425 return (0); 2426 return (1); 2427 } 2428 2429 /** 2430 * xmlRelaxNGSchemaTypeCheck: 2431 * @data: data needed for the library 2432 * @type: the type name 2433 * @value: the value to check 2434 * @node: the node 2435 * 2436 * Check if the given type and value are validated by 2437 * the W3C XMLSchema Datatype library. 2438 * 2439 * Returns 1 if yes, 0 if no and -1 in case of error. 2440 */ 2441 static int 2442 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED, 2443 const xmlChar * type, 2444 const xmlChar * value, 2445 void **result, xmlNodePtr node) 2446 { 2447 xmlSchemaTypePtr typ; 2448 int ret; 2449 2450 if ((type == NULL) || (value == NULL)) 2451 return (-1); 2452 typ = xmlSchemaGetPredefinedType(type, 2453 BAD_CAST 2454 "http://www.w3.org/2001/XMLSchema"); 2455 if (typ == NULL) 2456 return (-1); 2457 ret = xmlSchemaValPredefTypeNode(typ, value, 2458 (xmlSchemaValPtr *) result, node); 2459 if (ret == 2) /* special ID error code */ 2460 return (2); 2461 if (ret == 0) 2462 return (1); 2463 if (ret > 0) 2464 return (0); 2465 return (-1); 2466 } 2467 2468 /** 2469 * xmlRelaxNGSchemaFacetCheck: 2470 * @data: data needed for the library 2471 * @type: the type name 2472 * @facet: the facet name 2473 * @val: the facet value 2474 * @strval: the string value 2475 * @value: the value to check 2476 * 2477 * Function provided by a type library to check a value facet 2478 * 2479 * Returns 1 if yes, 0 if no and -1 in case of error. 2480 */ 2481 static int 2482 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED, 2483 const xmlChar * type, const xmlChar * facetname, 2484 const xmlChar * val, const xmlChar * strval, 2485 void *value) 2486 { 2487 xmlSchemaFacetPtr facet; 2488 xmlSchemaTypePtr typ; 2489 int ret; 2490 2491 if ((type == NULL) || (strval == NULL)) 2492 return (-1); 2493 typ = xmlSchemaGetPredefinedType(type, 2494 BAD_CAST 2495 "http://www.w3.org/2001/XMLSchema"); 2496 if (typ == NULL) 2497 return (-1); 2498 2499 facet = xmlSchemaNewFacet(); 2500 if (facet == NULL) 2501 return (-1); 2502 2503 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) { 2504 facet->type = XML_SCHEMA_FACET_MININCLUSIVE; 2505 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) { 2506 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; 2507 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) { 2508 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; 2509 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) { 2510 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; 2511 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) { 2512 facet->type = XML_SCHEMA_FACET_TOTALDIGITS; 2513 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) { 2514 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; 2515 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) { 2516 facet->type = XML_SCHEMA_FACET_PATTERN; 2517 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) { 2518 facet->type = XML_SCHEMA_FACET_ENUMERATION; 2519 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) { 2520 facet->type = XML_SCHEMA_FACET_WHITESPACE; 2521 } else if (xmlStrEqual(facetname, BAD_CAST "length")) { 2522 facet->type = XML_SCHEMA_FACET_LENGTH; 2523 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) { 2524 facet->type = XML_SCHEMA_FACET_MAXLENGTH; 2525 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) { 2526 facet->type = XML_SCHEMA_FACET_MINLENGTH; 2527 } else { 2528 xmlSchemaFreeFacet(facet); 2529 return (-1); 2530 } 2531 facet->value = val; 2532 ret = xmlSchemaCheckFacet(facet, typ, NULL, type); 2533 if (ret != 0) { 2534 xmlSchemaFreeFacet(facet); 2535 return (-1); 2536 } 2537 ret = xmlSchemaValidateFacet(typ, facet, strval, value); 2538 xmlSchemaFreeFacet(facet); 2539 if (ret != 0) 2540 return (-1); 2541 return (0); 2542 } 2543 2544 /** 2545 * xmlRelaxNGSchemaFreeValue: 2546 * @data: data needed for the library 2547 * @value: the value to free 2548 * 2549 * Function provided by a type library to free a Schemas value 2550 * 2551 * Returns 1 if yes, 0 if no and -1 in case of error. 2552 */ 2553 static void 2554 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value) 2555 { 2556 xmlSchemaFreeValue(value); 2557 } 2558 2559 /** 2560 * xmlRelaxNGSchemaTypeCompare: 2561 * @data: data needed for the library 2562 * @type: the type name 2563 * @value1: the first value 2564 * @value2: the second value 2565 * 2566 * Compare two values for equality accordingly a type from the W3C XMLSchema 2567 * Datatype library. 2568 * 2569 * Returns 1 if equal, 0 if no and -1 in case of error. 2570 */ 2571 static int 2572 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED, 2573 const xmlChar * type, 2574 const xmlChar * value1, 2575 xmlNodePtr ctxt1, 2576 void *comp1, 2577 const xmlChar * value2, xmlNodePtr ctxt2) 2578 { 2579 int ret; 2580 xmlSchemaTypePtr typ; 2581 xmlSchemaValPtr res1 = NULL, res2 = NULL; 2582 2583 if ((type == NULL) || (value1 == NULL) || (value2 == NULL)) 2584 return (-1); 2585 typ = xmlSchemaGetPredefinedType(type, 2586 BAD_CAST 2587 "http://www.w3.org/2001/XMLSchema"); 2588 if (typ == NULL) 2589 return (-1); 2590 if (comp1 == NULL) { 2591 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1); 2592 if (ret != 0) 2593 return (-1); 2594 if (res1 == NULL) 2595 return (-1); 2596 } else { 2597 res1 = (xmlSchemaValPtr) comp1; 2598 } 2599 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2); 2600 if (ret != 0) { 2601 if (res1 != (xmlSchemaValPtr) comp1) 2602 xmlSchemaFreeValue(res1); 2603 return (-1); 2604 } 2605 ret = xmlSchemaCompareValues(res1, res2); 2606 if (res1 != (xmlSchemaValPtr) comp1) 2607 xmlSchemaFreeValue(res1); 2608 xmlSchemaFreeValue(res2); 2609 if (ret == -2) 2610 return (-1); 2611 if (ret == 0) 2612 return (1); 2613 return (0); 2614 } 2615 2616 /** 2617 * xmlRelaxNGDefaultTypeHave: 2618 * @data: data needed for the library 2619 * @type: the type name 2620 * 2621 * Check if the given type is provided by 2622 * the default datatype library. 2623 * 2624 * Returns 1 if yes, 0 if no and -1 in case of error. 2625 */ 2626 static int 2627 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, 2628 const xmlChar * type) 2629 { 2630 if (type == NULL) 2631 return (-1); 2632 if (xmlStrEqual(type, BAD_CAST "string")) 2633 return (1); 2634 if (xmlStrEqual(type, BAD_CAST "token")) 2635 return (1); 2636 return (0); 2637 } 2638 2639 /** 2640 * xmlRelaxNGDefaultTypeCheck: 2641 * @data: data needed for the library 2642 * @type: the type name 2643 * @value: the value to check 2644 * @node: the node 2645 * 2646 * Check if the given type and value are validated by 2647 * the default datatype library. 2648 * 2649 * Returns 1 if yes, 0 if no and -1 in case of error. 2650 */ 2651 static int 2652 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, 2653 const xmlChar * type ATTRIBUTE_UNUSED, 2654 const xmlChar * value ATTRIBUTE_UNUSED, 2655 void **result ATTRIBUTE_UNUSED, 2656 xmlNodePtr node ATTRIBUTE_UNUSED) 2657 { 2658 if (value == NULL) 2659 return (-1); 2660 if (xmlStrEqual(type, BAD_CAST "string")) 2661 return (1); 2662 if (xmlStrEqual(type, BAD_CAST "token")) { 2663 return (1); 2664 } 2665 2666 return (0); 2667 } 2668 2669 /** 2670 * xmlRelaxNGDefaultTypeCompare: 2671 * @data: data needed for the library 2672 * @type: the type name 2673 * @value1: the first value 2674 * @value2: the second value 2675 * 2676 * Compare two values accordingly a type from the default 2677 * datatype library. 2678 * 2679 * Returns 1 if yes, 0 if no and -1 in case of error. 2680 */ 2681 static int 2682 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, 2683 const xmlChar * type, 2684 const xmlChar * value1, 2685 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED, 2686 void *comp1 ATTRIBUTE_UNUSED, 2687 const xmlChar * value2, 2688 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) 2689 { 2690 int ret = -1; 2691 2692 if (xmlStrEqual(type, BAD_CAST "string")) { 2693 ret = xmlStrEqual(value1, value2); 2694 } else if (xmlStrEqual(type, BAD_CAST "token")) { 2695 if (!xmlStrEqual(value1, value2)) { 2696 xmlChar *nval, *nvalue; 2697 2698 /* 2699 * TODO: trivial optimizations are possible by 2700 * computing at compile-time 2701 */ 2702 nval = xmlRelaxNGNormalize(NULL, value1); 2703 nvalue = xmlRelaxNGNormalize(NULL, value2); 2704 2705 if ((nval == NULL) || (nvalue == NULL)) 2706 ret = -1; 2707 else if (xmlStrEqual(nval, nvalue)) 2708 ret = 1; 2709 else 2710 ret = 0; 2711 if (nval != NULL) 2712 xmlFree(nval); 2713 if (nvalue != NULL) 2714 xmlFree(nvalue); 2715 } else 2716 ret = 1; 2717 } 2718 return (ret); 2719 } 2720 2721 static int xmlRelaxNGTypeInitialized = 0; 2722 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; 2723 2724 /** 2725 * xmlRelaxNGFreeTypeLibrary: 2726 * @lib: the type library structure 2727 * @namespace: the URI bound to the library 2728 * 2729 * Free the structure associated to the type library 2730 */ 2731 static void 2732 xmlRelaxNGFreeTypeLibrary(void *payload, 2733 const xmlChar * namespace ATTRIBUTE_UNUSED) 2734 { 2735 xmlRelaxNGTypeLibraryPtr lib = (xmlRelaxNGTypeLibraryPtr) payload; 2736 if (lib == NULL) 2737 return; 2738 if (lib->namespace != NULL) 2739 xmlFree((xmlChar *) lib->namespace); 2740 xmlFree(lib); 2741 } 2742 2743 /** 2744 * xmlRelaxNGRegisterTypeLibrary: 2745 * @namespace: the URI bound to the library 2746 * @data: data associated to the library 2747 * @have: the provide function 2748 * @check: the checking function 2749 * @comp: the comparison function 2750 * 2751 * Register a new type library 2752 * 2753 * Returns 0 in case of success and -1 in case of error. 2754 */ 2755 static int 2756 xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, 2757 xmlRelaxNGTypeHave have, 2758 xmlRelaxNGTypeCheck check, 2759 xmlRelaxNGTypeCompare comp, 2760 xmlRelaxNGFacetCheck facet, 2761 xmlRelaxNGTypeFree freef) 2762 { 2763 xmlRelaxNGTypeLibraryPtr lib; 2764 int ret; 2765 2766 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || 2767 (check == NULL) || (comp == NULL)) 2768 return (-1); 2769 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { 2770 xmlGenericError(xmlGenericErrorContext, 2771 "Relax-NG types library '%s' already registered\n", 2772 namespace); 2773 return (-1); 2774 } 2775 lib = 2776 (xmlRelaxNGTypeLibraryPtr) 2777 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); 2778 if (lib == NULL) { 2779 xmlRngVErrMemory(NULL, "adding types library\n"); 2780 return (-1); 2781 } 2782 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); 2783 lib->namespace = xmlStrdup(namespace); 2784 lib->data = data; 2785 lib->have = have; 2786 lib->comp = comp; 2787 lib->check = check; 2788 lib->facet = facet; 2789 lib->freef = freef; 2790 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); 2791 if (ret < 0) { 2792 xmlGenericError(xmlGenericErrorContext, 2793 "Relax-NG types library failed to register '%s'\n", 2794 namespace); 2795 xmlRelaxNGFreeTypeLibrary(lib, namespace); 2796 return (-1); 2797 } 2798 return (0); 2799 } 2800 2801 /** 2802 * xmlRelaxNGInitTypes: 2803 * 2804 * Initilize the default type libraries. 2805 * 2806 * Returns 0 in case of success and -1 in case of error. 2807 */ 2808 int 2809 xmlRelaxNGInitTypes(void) 2810 { 2811 if (xmlRelaxNGTypeInitialized != 0) 2812 return (0); 2813 xmlRelaxNGRegisteredTypes = xmlHashCreate(10); 2814 if (xmlRelaxNGRegisteredTypes == NULL) { 2815 xmlGenericError(xmlGenericErrorContext, 2816 "Failed to allocate sh table for Relax-NG types\n"); 2817 return (-1); 2818 } 2819 xmlRelaxNGRegisterTypeLibrary(BAD_CAST 2820 "http://www.w3.org/2001/XMLSchema-datatypes", 2821 NULL, xmlRelaxNGSchemaTypeHave, 2822 xmlRelaxNGSchemaTypeCheck, 2823 xmlRelaxNGSchemaTypeCompare, 2824 xmlRelaxNGSchemaFacetCheck, 2825 xmlRelaxNGSchemaFreeValue); 2826 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL, 2827 xmlRelaxNGDefaultTypeHave, 2828 xmlRelaxNGDefaultTypeCheck, 2829 xmlRelaxNGDefaultTypeCompare, NULL, 2830 NULL); 2831 xmlRelaxNGTypeInitialized = 1; 2832 return (0); 2833 } 2834 2835 /** 2836 * xmlRelaxNGCleanupTypes: 2837 * 2838 * Cleanup the default Schemas type library associated to RelaxNG 2839 */ 2840 void 2841 xmlRelaxNGCleanupTypes(void) 2842 { 2843 xmlSchemaCleanupTypes(); 2844 if (xmlRelaxNGTypeInitialized == 0) 2845 return; 2846 xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary); 2847 xmlRelaxNGTypeInitialized = 0; 2848 } 2849 2850 /************************************************************************ 2851 * * 2852 * Compiling element content into regexp * 2853 * * 2854 * Sometime the element content can be compiled into a pure regexp, * 2855 * This allows a faster execution and streamability at that level * 2856 * * 2857 ************************************************************************/ 2858 2859 /* from automata.c but not exported */ 2860 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); 2861 2862 2863 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, 2864 xmlRelaxNGDefinePtr def); 2865 2866 /** 2867 * xmlRelaxNGIsCompileable: 2868 * @define: the definition to check 2869 * 2870 * Check if a definition is nullable. 2871 * 2872 * Returns 1 if yes, 0 if no and -1 in case of error 2873 */ 2874 static int 2875 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) 2876 { 2877 int ret = -1; 2878 2879 if (def == NULL) { 2880 return (-1); 2881 } 2882 if ((def->type != XML_RELAXNG_ELEMENT) && 2883 (def->dflags & IS_COMPILABLE)) 2884 return (1); 2885 if ((def->type != XML_RELAXNG_ELEMENT) && 2886 (def->dflags & IS_NOT_COMPILABLE)) 2887 return (0); 2888 switch (def->type) { 2889 case XML_RELAXNG_NOOP: 2890 ret = xmlRelaxNGIsCompileable(def->content); 2891 break; 2892 case XML_RELAXNG_TEXT: 2893 case XML_RELAXNG_EMPTY: 2894 ret = 1; 2895 break; 2896 case XML_RELAXNG_ELEMENT: 2897 /* 2898 * Check if the element content is compileable 2899 */ 2900 if (((def->dflags & IS_NOT_COMPILABLE) == 0) && 2901 ((def->dflags & IS_COMPILABLE) == 0)) { 2902 xmlRelaxNGDefinePtr list; 2903 2904 list = def->content; 2905 while (list != NULL) { 2906 ret = xmlRelaxNGIsCompileable(list); 2907 if (ret != 1) 2908 break; 2909 list = list->next; 2910 } 2911 /* 2912 * Because the routine is recursive, we must guard against 2913 * discovering both COMPILABLE and NOT_COMPILABLE 2914 */ 2915 if (ret == 0) { 2916 def->dflags &= ~IS_COMPILABLE; 2917 def->dflags |= IS_NOT_COMPILABLE; 2918 } 2919 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) 2920 def->dflags |= IS_COMPILABLE; 2921 #ifdef DEBUG_COMPILE 2922 if (ret == 1) { 2923 xmlGenericError(xmlGenericErrorContext, 2924 "element content for %s is compilable\n", 2925 def->name); 2926 } else if (ret == 0) { 2927 xmlGenericError(xmlGenericErrorContext, 2928 "element content for %s is not compilable\n", 2929 def->name); 2930 } else { 2931 xmlGenericError(xmlGenericErrorContext, 2932 "Problem in RelaxNGIsCompileable for element %s\n", 2933 def->name); 2934 } 2935 #endif 2936 } 2937 /* 2938 * All elements return a compileable status unless they 2939 * are generic like anyName 2940 */ 2941 if ((def->nameClass != NULL) || (def->name == NULL)) 2942 ret = 0; 2943 else 2944 ret = 1; 2945 return (ret); 2946 case XML_RELAXNG_REF: 2947 case XML_RELAXNG_EXTERNALREF: 2948 case XML_RELAXNG_PARENTREF: 2949 if (def->depth == -20) { 2950 return (1); 2951 } else { 2952 xmlRelaxNGDefinePtr list; 2953 2954 def->depth = -20; 2955 list = def->content; 2956 while (list != NULL) { 2957 ret = xmlRelaxNGIsCompileable(list); 2958 if (ret != 1) 2959 break; 2960 list = list->next; 2961 } 2962 } 2963 break; 2964 case XML_RELAXNG_START: 2965 case XML_RELAXNG_OPTIONAL: 2966 case XML_RELAXNG_ZEROORMORE: 2967 case XML_RELAXNG_ONEORMORE: 2968 case XML_RELAXNG_CHOICE: 2969 case XML_RELAXNG_GROUP: 2970 case XML_RELAXNG_DEF:{ 2971 xmlRelaxNGDefinePtr list; 2972 2973 list = def->content; 2974 while (list != NULL) { 2975 ret = xmlRelaxNGIsCompileable(list); 2976 if (ret != 1) 2977 break; 2978 list = list->next; 2979 } 2980 break; 2981 } 2982 case XML_RELAXNG_EXCEPT: 2983 case XML_RELAXNG_ATTRIBUTE: 2984 case XML_RELAXNG_INTERLEAVE: 2985 case XML_RELAXNG_DATATYPE: 2986 case XML_RELAXNG_LIST: 2987 case XML_RELAXNG_PARAM: 2988 case XML_RELAXNG_VALUE: 2989 case XML_RELAXNG_NOT_ALLOWED: 2990 ret = 0; 2991 break; 2992 } 2993 if (ret == 0) 2994 def->dflags |= IS_NOT_COMPILABLE; 2995 if (ret == 1) 2996 def->dflags |= IS_COMPILABLE; 2997 #ifdef DEBUG_COMPILE 2998 if (ret == 1) { 2999 xmlGenericError(xmlGenericErrorContext, 3000 "RelaxNGIsCompileable %s : true\n", 3001 xmlRelaxNGDefName(def)); 3002 } else if (ret == 0) { 3003 xmlGenericError(xmlGenericErrorContext, 3004 "RelaxNGIsCompileable %s : false\n", 3005 xmlRelaxNGDefName(def)); 3006 } else { 3007 xmlGenericError(xmlGenericErrorContext, 3008 "Problem in RelaxNGIsCompileable %s\n", 3009 xmlRelaxNGDefName(def)); 3010 } 3011 #endif 3012 return (ret); 3013 } 3014 3015 /** 3016 * xmlRelaxNGCompile: 3017 * ctxt: the RelaxNG parser context 3018 * @define: the definition tree to compile 3019 * 3020 * Compile the set of definitions, it works recursively, till the 3021 * element boundaries, where it tries to compile the content if possible 3022 * 3023 * Returns 0 if success and -1 in case of error 3024 */ 3025 static int 3026 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3027 { 3028 int ret = 0; 3029 xmlRelaxNGDefinePtr list; 3030 3031 if ((ctxt == NULL) || (def == NULL)) 3032 return (-1); 3033 3034 switch (def->type) { 3035 case XML_RELAXNG_START: 3036 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) { 3037 xmlAutomataPtr oldam = ctxt->am; 3038 xmlAutomataStatePtr oldstate = ctxt->state; 3039 3040 def->depth = -25; 3041 3042 list = def->content; 3043 ctxt->am = xmlNewAutomata(); 3044 if (ctxt->am == NULL) 3045 return (-1); 3046 3047 /* 3048 * assume identical strings but not same pointer are different 3049 * atoms, needed for non-determinism detection 3050 * That way if 2 elements with the same name are in a choice 3051 * branch the automata is found non-deterministic and 3052 * we fallback to the normal validation which does the right 3053 * thing of exploring both choices. 3054 */ 3055 xmlAutomataSetFlags(ctxt->am, 1); 3056 3057 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3058 while (list != NULL) { 3059 xmlRelaxNGCompile(ctxt, list); 3060 list = list->next; 3061 } 3062 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3063 if (xmlAutomataIsDeterminist(ctxt->am)) 3064 def->contModel = xmlAutomataCompile(ctxt->am); 3065 3066 xmlFreeAutomata(ctxt->am); 3067 ctxt->state = oldstate; 3068 ctxt->am = oldam; 3069 } 3070 break; 3071 case XML_RELAXNG_ELEMENT: 3072 if ((ctxt->am != NULL) && (def->name != NULL)) { 3073 ctxt->state = xmlAutomataNewTransition2(ctxt->am, 3074 ctxt->state, NULL, 3075 def->name, def->ns, 3076 def); 3077 } 3078 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3079 xmlAutomataPtr oldam = ctxt->am; 3080 xmlAutomataStatePtr oldstate = ctxt->state; 3081 3082 def->depth = -25; 3083 3084 list = def->content; 3085 ctxt->am = xmlNewAutomata(); 3086 if (ctxt->am == NULL) 3087 return (-1); 3088 xmlAutomataSetFlags(ctxt->am, 1); 3089 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3090 while (list != NULL) { 3091 xmlRelaxNGCompile(ctxt, list); 3092 list = list->next; 3093 } 3094 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3095 def->contModel = xmlAutomataCompile(ctxt->am); 3096 if (!xmlRegexpIsDeterminist(def->contModel)) { 3097 #ifdef DEBUG_COMPILE 3098 xmlGenericError(xmlGenericErrorContext, 3099 "Content model not determinist %s\n", 3100 def->name); 3101 #endif 3102 /* 3103 * we can only use the automata if it is determinist 3104 */ 3105 xmlRegFreeRegexp(def->contModel); 3106 def->contModel = NULL; 3107 } 3108 xmlFreeAutomata(ctxt->am); 3109 ctxt->state = oldstate; 3110 ctxt->am = oldam; 3111 } else { 3112 xmlAutomataPtr oldam = ctxt->am; 3113 3114 /* 3115 * we can't build the content model for this element content 3116 * but it still might be possible to build it for some of its 3117 * children, recurse. 3118 */ 3119 ret = xmlRelaxNGTryCompile(ctxt, def); 3120 ctxt->am = oldam; 3121 } 3122 break; 3123 case XML_RELAXNG_NOOP: 3124 ret = xmlRelaxNGCompile(ctxt, def->content); 3125 break; 3126 case XML_RELAXNG_OPTIONAL:{ 3127 xmlAutomataStatePtr oldstate = ctxt->state; 3128 3129 list = def->content; 3130 while (list != NULL) { 3131 xmlRelaxNGCompile(ctxt, list); 3132 list = list->next; 3133 } 3134 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 3135 break; 3136 } 3137 case XML_RELAXNG_ZEROORMORE:{ 3138 xmlAutomataStatePtr oldstate; 3139 3140 ctxt->state = 3141 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3142 oldstate = ctxt->state; 3143 list = def->content; 3144 while (list != NULL) { 3145 xmlRelaxNGCompile(ctxt, list); 3146 list = list->next; 3147 } 3148 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3149 ctxt->state = 3150 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3151 break; 3152 } 3153 case XML_RELAXNG_ONEORMORE:{ 3154 xmlAutomataStatePtr oldstate; 3155 3156 list = def->content; 3157 while (list != NULL) { 3158 xmlRelaxNGCompile(ctxt, list); 3159 list = list->next; 3160 } 3161 oldstate = ctxt->state; 3162 list = def->content; 3163 while (list != NULL) { 3164 xmlRelaxNGCompile(ctxt, list); 3165 list = list->next; 3166 } 3167 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3168 ctxt->state = 3169 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3170 break; 3171 } 3172 case XML_RELAXNG_CHOICE:{ 3173 xmlAutomataStatePtr target = NULL; 3174 xmlAutomataStatePtr oldstate = ctxt->state; 3175 3176 list = def->content; 3177 while (list != NULL) { 3178 ctxt->state = oldstate; 3179 ret = xmlRelaxNGCompile(ctxt, list); 3180 if (ret != 0) 3181 break; 3182 if (target == NULL) 3183 target = ctxt->state; 3184 else { 3185 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, 3186 target); 3187 } 3188 list = list->next; 3189 } 3190 ctxt->state = target; 3191 3192 break; 3193 } 3194 case XML_RELAXNG_REF: 3195 case XML_RELAXNG_EXTERNALREF: 3196 case XML_RELAXNG_PARENTREF: 3197 case XML_RELAXNG_GROUP: 3198 case XML_RELAXNG_DEF: 3199 list = def->content; 3200 while (list != NULL) { 3201 ret = xmlRelaxNGCompile(ctxt, list); 3202 if (ret != 0) 3203 break; 3204 list = list->next; 3205 } 3206 break; 3207 case XML_RELAXNG_TEXT:{ 3208 xmlAutomataStatePtr oldstate; 3209 3210 ctxt->state = 3211 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3212 oldstate = ctxt->state; 3213 xmlRelaxNGCompile(ctxt, def->content); 3214 xmlAutomataNewTransition(ctxt->am, ctxt->state, 3215 ctxt->state, BAD_CAST "#text", 3216 NULL); 3217 ctxt->state = 3218 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3219 break; 3220 } 3221 case XML_RELAXNG_EMPTY: 3222 ctxt->state = 3223 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3224 break; 3225 case XML_RELAXNG_EXCEPT: 3226 case XML_RELAXNG_ATTRIBUTE: 3227 case XML_RELAXNG_INTERLEAVE: 3228 case XML_RELAXNG_NOT_ALLOWED: 3229 case XML_RELAXNG_DATATYPE: 3230 case XML_RELAXNG_LIST: 3231 case XML_RELAXNG_PARAM: 3232 case XML_RELAXNG_VALUE: 3233 /* This should not happen and generate an internal error */ 3234 fprintf(stderr, "RNG internal error trying to compile %s\n", 3235 xmlRelaxNGDefName(def)); 3236 break; 3237 } 3238 return (ret); 3239 } 3240 3241 /** 3242 * xmlRelaxNGTryCompile: 3243 * ctxt: the RelaxNG parser context 3244 * @define: the definition tree to compile 3245 * 3246 * Try to compile the set of definitions, it works recursively, 3247 * possibly ignoring parts which cannot be compiled. 3248 * 3249 * Returns 0 if success and -1 in case of error 3250 */ 3251 static int 3252 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3253 { 3254 int ret = 0; 3255 xmlRelaxNGDefinePtr list; 3256 3257 if ((ctxt == NULL) || (def == NULL)) 3258 return (-1); 3259 3260 if ((def->type == XML_RELAXNG_START) || 3261 (def->type == XML_RELAXNG_ELEMENT)) { 3262 ret = xmlRelaxNGIsCompileable(def); 3263 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3264 ctxt->am = NULL; 3265 ret = xmlRelaxNGCompile(ctxt, def); 3266 #ifdef DEBUG_PROGRESSIVE 3267 if (ret == 0) { 3268 if (def->type == XML_RELAXNG_START) 3269 xmlGenericError(xmlGenericErrorContext, 3270 "compiled the start\n"); 3271 else 3272 xmlGenericError(xmlGenericErrorContext, 3273 "compiled element %s\n", def->name); 3274 } else { 3275 if (def->type == XML_RELAXNG_START) 3276 xmlGenericError(xmlGenericErrorContext, 3277 "failed to compile the start\n"); 3278 else 3279 xmlGenericError(xmlGenericErrorContext, 3280 "failed to compile element %s\n", 3281 def->name); 3282 } 3283 #endif 3284 return (ret); 3285 } 3286 } 3287 switch (def->type) { 3288 case XML_RELAXNG_NOOP: 3289 ret = xmlRelaxNGTryCompile(ctxt, def->content); 3290 break; 3291 case XML_RELAXNG_TEXT: 3292 case XML_RELAXNG_DATATYPE: 3293 case XML_RELAXNG_LIST: 3294 case XML_RELAXNG_PARAM: 3295 case XML_RELAXNG_VALUE: 3296 case XML_RELAXNG_EMPTY: 3297 case XML_RELAXNG_ELEMENT: 3298 ret = 0; 3299 break; 3300 case XML_RELAXNG_OPTIONAL: 3301 case XML_RELAXNG_ZEROORMORE: 3302 case XML_RELAXNG_ONEORMORE: 3303 case XML_RELAXNG_CHOICE: 3304 case XML_RELAXNG_GROUP: 3305 case XML_RELAXNG_DEF: 3306 case XML_RELAXNG_START: 3307 case XML_RELAXNG_REF: 3308 case XML_RELAXNG_EXTERNALREF: 3309 case XML_RELAXNG_PARENTREF: 3310 list = def->content; 3311 while (list != NULL) { 3312 ret = xmlRelaxNGTryCompile(ctxt, list); 3313 if (ret != 0) 3314 break; 3315 list = list->next; 3316 } 3317 break; 3318 case XML_RELAXNG_EXCEPT: 3319 case XML_RELAXNG_ATTRIBUTE: 3320 case XML_RELAXNG_INTERLEAVE: 3321 case XML_RELAXNG_NOT_ALLOWED: 3322 ret = 0; 3323 break; 3324 } 3325 return (ret); 3326 } 3327 3328 /************************************************************************ 3329 * * 3330 * Parsing functions * 3331 * * 3332 ************************************************************************/ 3333 3334 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr 3335 ctxt, xmlNodePtr node); 3336 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr 3337 ctxt, xmlNodePtr node); 3338 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr 3339 ctxt, xmlNodePtr nodes, 3340 int group); 3341 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr 3342 ctxt, xmlNodePtr node); 3343 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, 3344 xmlNodePtr node); 3345 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 3346 xmlNodePtr nodes); 3347 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr 3348 ctxt, xmlNodePtr node, 3349 xmlRelaxNGDefinePtr 3350 def); 3351 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr 3352 ctxt, xmlNodePtr nodes); 3353 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 3354 xmlRelaxNGDefinePtr define, 3355 xmlNodePtr elem); 3356 3357 3358 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) 3359 3360 /** 3361 * xmlRelaxNGIsNullable: 3362 * @define: the definition to verify 3363 * 3364 * Check if a definition is nullable. 3365 * 3366 * Returns 1 if yes, 0 if no and -1 in case of error 3367 */ 3368 static int 3369 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) 3370 { 3371 int ret; 3372 3373 if (define == NULL) 3374 return (-1); 3375 3376 if (define->dflags & IS_NULLABLE) 3377 return (1); 3378 if (define->dflags & IS_NOT_NULLABLE) 3379 return (0); 3380 switch (define->type) { 3381 case XML_RELAXNG_EMPTY: 3382 case XML_RELAXNG_TEXT: 3383 ret = 1; 3384 break; 3385 case XML_RELAXNG_NOOP: 3386 case XML_RELAXNG_DEF: 3387 case XML_RELAXNG_REF: 3388 case XML_RELAXNG_EXTERNALREF: 3389 case XML_RELAXNG_PARENTREF: 3390 case XML_RELAXNG_ONEORMORE: 3391 ret = xmlRelaxNGIsNullable(define->content); 3392 break; 3393 case XML_RELAXNG_EXCEPT: 3394 case XML_RELAXNG_NOT_ALLOWED: 3395 case XML_RELAXNG_ELEMENT: 3396 case XML_RELAXNG_DATATYPE: 3397 case XML_RELAXNG_PARAM: 3398 case XML_RELAXNG_VALUE: 3399 case XML_RELAXNG_LIST: 3400 case XML_RELAXNG_ATTRIBUTE: 3401 ret = 0; 3402 break; 3403 case XML_RELAXNG_CHOICE:{ 3404 xmlRelaxNGDefinePtr list = define->content; 3405 3406 while (list != NULL) { 3407 ret = xmlRelaxNGIsNullable(list); 3408 if (ret != 0) 3409 goto done; 3410 list = list->next; 3411 } 3412 ret = 0; 3413 break; 3414 } 3415 case XML_RELAXNG_START: 3416 case XML_RELAXNG_INTERLEAVE: 3417 case XML_RELAXNG_GROUP:{ 3418 xmlRelaxNGDefinePtr list = define->content; 3419 3420 while (list != NULL) { 3421 ret = xmlRelaxNGIsNullable(list); 3422 if (ret != 1) 3423 goto done; 3424 list = list->next; 3425 } 3426 return (1); 3427 } 3428 default: 3429 return (-1); 3430 } 3431 done: 3432 if (ret == 0) 3433 define->dflags |= IS_NOT_NULLABLE; 3434 if (ret == 1) 3435 define->dflags |= IS_NULLABLE; 3436 return (ret); 3437 } 3438 3439 /** 3440 * xmlRelaxNGIsBlank: 3441 * @str: a string 3442 * 3443 * Check if a string is ignorable c.f. 4.2. Whitespace 3444 * 3445 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise 3446 */ 3447 static int 3448 xmlRelaxNGIsBlank(xmlChar * str) 3449 { 3450 if (str == NULL) 3451 return (1); 3452 while (*str != 0) { 3453 if (!(IS_BLANK_CH(*str))) 3454 return (0); 3455 str++; 3456 } 3457 return (1); 3458 } 3459 3460 /** 3461 * xmlRelaxNGGetDataTypeLibrary: 3462 * @ctxt: a Relax-NG parser context 3463 * @node: the current data or value element 3464 * 3465 * Applies algorithm from 4.3. datatypeLibrary attribute 3466 * 3467 * Returns the datatypeLibary value or NULL if not found 3468 */ 3469 static xmlChar * 3470 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 3471 xmlNodePtr node) 3472 { 3473 xmlChar *ret, *escape; 3474 3475 if (node == NULL) 3476 return(NULL); 3477 3478 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { 3479 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3480 if (ret != NULL) { 3481 if (ret[0] == 0) { 3482 xmlFree(ret); 3483 return (NULL); 3484 } 3485 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3486 if (escape == NULL) { 3487 return (ret); 3488 } 3489 xmlFree(ret); 3490 return (escape); 3491 } 3492 } 3493 node = node->parent; 3494 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { 3495 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3496 if (ret != NULL) { 3497 if (ret[0] == 0) { 3498 xmlFree(ret); 3499 return (NULL); 3500 } 3501 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3502 if (escape == NULL) { 3503 return (ret); 3504 } 3505 xmlFree(ret); 3506 return (escape); 3507 } 3508 node = node->parent; 3509 } 3510 return (NULL); 3511 } 3512 3513 /** 3514 * xmlRelaxNGParseValue: 3515 * @ctxt: a Relax-NG parser context 3516 * @node: the data node. 3517 * 3518 * parse the content of a RelaxNG value node. 3519 * 3520 * Returns the definition pointer or NULL in case of error 3521 */ 3522 static xmlRelaxNGDefinePtr 3523 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3524 { 3525 xmlRelaxNGDefinePtr def = NULL; 3526 xmlRelaxNGTypeLibraryPtr lib = NULL; 3527 xmlChar *type; 3528 xmlChar *library; 3529 int success = 0; 3530 3531 def = xmlRelaxNGNewDefine(ctxt, node); 3532 if (def == NULL) 3533 return (NULL); 3534 def->type = XML_RELAXNG_VALUE; 3535 3536 type = xmlGetProp(node, BAD_CAST "type"); 3537 if (type != NULL) { 3538 xmlRelaxNGNormExtSpace(type); 3539 if (xmlValidateNCName(type, 0)) { 3540 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3541 "value type '%s' is not an NCName\n", type, NULL); 3542 } 3543 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3544 if (library == NULL) 3545 library = 3546 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3547 3548 def->name = type; 3549 def->ns = library; 3550 3551 lib = (xmlRelaxNGTypeLibraryPtr) 3552 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3553 if (lib == NULL) { 3554 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3555 "Use of unregistered type library '%s'\n", library, 3556 NULL); 3557 def->data = NULL; 3558 } else { 3559 def->data = lib; 3560 if (lib->have == NULL) { 3561 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3562 "Internal error with type library '%s': no 'have'\n", 3563 library, NULL); 3564 } else { 3565 success = lib->have(lib->data, def->name); 3566 if (success != 1) { 3567 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3568 "Error type '%s' is not exported by type library '%s'\n", 3569 def->name, library); 3570 } 3571 } 3572 } 3573 } 3574 if (node->children == NULL) { 3575 def->value = xmlStrdup(BAD_CAST ""); 3576 } else if (((node->children->type != XML_TEXT_NODE) && 3577 (node->children->type != XML_CDATA_SECTION_NODE)) || 3578 (node->children->next != NULL)) { 3579 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, 3580 "Expecting a single text value for <value>content\n", 3581 NULL, NULL); 3582 } else if (def != NULL) { 3583 def->value = xmlNodeGetContent(node); 3584 if (def->value == NULL) { 3585 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, 3586 "Element <value> has no content\n", NULL, NULL); 3587 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { 3588 void *val = NULL; 3589 3590 success = 3591 lib->check(lib->data, def->name, def->value, &val, node); 3592 if (success != 1) { 3593 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, 3594 "Value '%s' is not acceptable for type '%s'\n", 3595 def->value, def->name); 3596 } else { 3597 if (val != NULL) 3598 def->attrs = val; 3599 } 3600 } 3601 } 3602 return (def); 3603 } 3604 3605 /** 3606 * xmlRelaxNGParseData: 3607 * @ctxt: a Relax-NG parser context 3608 * @node: the data node. 3609 * 3610 * parse the content of a RelaxNG data node. 3611 * 3612 * Returns the definition pointer or NULL in case of error 3613 */ 3614 static xmlRelaxNGDefinePtr 3615 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3616 { 3617 xmlRelaxNGDefinePtr def = NULL, except; 3618 xmlRelaxNGDefinePtr param, lastparam = NULL; 3619 xmlRelaxNGTypeLibraryPtr lib; 3620 xmlChar *type; 3621 xmlChar *library; 3622 xmlNodePtr content; 3623 int tmp; 3624 3625 type = xmlGetProp(node, BAD_CAST "type"); 3626 if (type == NULL) { 3627 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, 3628 NULL); 3629 return (NULL); 3630 } 3631 xmlRelaxNGNormExtSpace(type); 3632 if (xmlValidateNCName(type, 0)) { 3633 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3634 "data type '%s' is not an NCName\n", type, NULL); 3635 } 3636 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3637 if (library == NULL) 3638 library = 3639 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3640 3641 def = xmlRelaxNGNewDefine(ctxt, node); 3642 if (def == NULL) { 3643 xmlFree(type); 3644 return (NULL); 3645 } 3646 def->type = XML_RELAXNG_DATATYPE; 3647 def->name = type; 3648 def->ns = library; 3649 3650 lib = (xmlRelaxNGTypeLibraryPtr) 3651 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3652 if (lib == NULL) { 3653 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3654 "Use of unregistered type library '%s'\n", library, 3655 NULL); 3656 def->data = NULL; 3657 } else { 3658 def->data = lib; 3659 if (lib->have == NULL) { 3660 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3661 "Internal error with type library '%s': no 'have'\n", 3662 library, NULL); 3663 } else { 3664 tmp = lib->have(lib->data, def->name); 3665 if (tmp != 1) { 3666 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3667 "Error type '%s' is not exported by type library '%s'\n", 3668 def->name, library); 3669 } else 3670 if ((xmlStrEqual 3671 (library, 3672 BAD_CAST 3673 "http://www.w3.org/2001/XMLSchema-datatypes")) 3674 && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) 3675 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { 3676 ctxt->idref = 1; 3677 } 3678 } 3679 } 3680 content = node->children; 3681 3682 /* 3683 * Handle optional params 3684 */ 3685 while (content != NULL) { 3686 if (!xmlStrEqual(content->name, BAD_CAST "param")) 3687 break; 3688 if (xmlStrEqual(library, 3689 BAD_CAST "http://relaxng.org/ns/structure/1.0")) { 3690 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, 3691 "Type library '%s' does not allow type parameters\n", 3692 library, NULL); 3693 content = content->next; 3694 while ((content != NULL) && 3695 (xmlStrEqual(content->name, BAD_CAST "param"))) 3696 content = content->next; 3697 } else { 3698 param = xmlRelaxNGNewDefine(ctxt, node); 3699 if (param != NULL) { 3700 param->type = XML_RELAXNG_PARAM; 3701 param->name = xmlGetProp(content, BAD_CAST "name"); 3702 if (param->name == NULL) { 3703 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, 3704 "param has no name\n", NULL, NULL); 3705 } 3706 param->value = xmlNodeGetContent(content); 3707 if (lastparam == NULL) { 3708 def->attrs = lastparam = param; 3709 } else { 3710 lastparam->next = param; 3711 lastparam = param; 3712 } 3713 if (lib != NULL) { 3714 } 3715 } 3716 content = content->next; 3717 } 3718 } 3719 /* 3720 * Handle optional except 3721 */ 3722 if ((content != NULL) 3723 && (xmlStrEqual(content->name, BAD_CAST "except"))) { 3724 xmlNodePtr child; 3725 xmlRelaxNGDefinePtr tmp2, last = NULL; 3726 3727 except = xmlRelaxNGNewDefine(ctxt, node); 3728 if (except == NULL) { 3729 return (def); 3730 } 3731 except->type = XML_RELAXNG_EXCEPT; 3732 child = content->children; 3733 def->content = except; 3734 if (child == NULL) { 3735 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, 3736 "except has no content\n", NULL, NULL); 3737 } 3738 while (child != NULL) { 3739 tmp2 = xmlRelaxNGParsePattern(ctxt, child); 3740 if (tmp2 != NULL) { 3741 if (last == NULL) { 3742 except->content = last = tmp2; 3743 } else { 3744 last->next = tmp2; 3745 last = tmp2; 3746 } 3747 } 3748 child = child->next; 3749 } 3750 content = content->next; 3751 } 3752 /* 3753 * Check there is no unhandled data 3754 */ 3755 if (content != NULL) { 3756 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, 3757 "Element data has unexpected content %s\n", 3758 content->name, NULL); 3759 } 3760 3761 return (def); 3762 } 3763 3764 static const xmlChar *invalidName = BAD_CAST "\1"; 3765 3766 /** 3767 * xmlRelaxNGCompareNameClasses: 3768 * @defs1: the first element/attribute defs 3769 * @defs2: the second element/attribute defs 3770 * @name: the restriction on the name 3771 * @ns: the restriction on the namespace 3772 * 3773 * Compare the 2 lists of element definitions. The comparison is 3774 * that if both lists do not accept the same QNames, it returns 1 3775 * If the 2 lists can accept the same QName the comparison returns 0 3776 * 3777 * Returns 1 disttinct, 0 if equal 3778 */ 3779 static int 3780 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, 3781 xmlRelaxNGDefinePtr def2) 3782 { 3783 int ret = 1; 3784 xmlNode node; 3785 xmlNs ns; 3786 xmlRelaxNGValidCtxt ctxt; 3787 3788 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); 3789 3790 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; 3791 3792 if ((def1->type == XML_RELAXNG_ELEMENT) || 3793 (def1->type == XML_RELAXNG_ATTRIBUTE)) { 3794 if (def2->type == XML_RELAXNG_TEXT) 3795 return (1); 3796 if (def1->name != NULL) { 3797 node.name = def1->name; 3798 } else { 3799 node.name = invalidName; 3800 } 3801 if (def1->ns != NULL) { 3802 if (def1->ns[0] == 0) { 3803 node.ns = NULL; 3804 } else { 3805 node.ns = &ns; 3806 ns.href = def1->ns; 3807 } 3808 } else { 3809 node.ns = NULL; 3810 } 3811 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { 3812 if (def1->nameClass != NULL) { 3813 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); 3814 } else { 3815 ret = 0; 3816 } 3817 } else { 3818 ret = 1; 3819 } 3820 } else if (def1->type == XML_RELAXNG_TEXT) { 3821 if (def2->type == XML_RELAXNG_TEXT) 3822 return (0); 3823 return (1); 3824 } else if (def1->type == XML_RELAXNG_EXCEPT) { 3825 ret = xmlRelaxNGCompareNameClasses(def1->content, def2); 3826 if (ret == 0) 3827 ret = 1; 3828 else if (ret == 1) 3829 ret = 0; 3830 } else { 3831 TODO ret = 0; 3832 } 3833 if (ret == 0) 3834 return (ret); 3835 if ((def2->type == XML_RELAXNG_ELEMENT) || 3836 (def2->type == XML_RELAXNG_ATTRIBUTE)) { 3837 if (def2->name != NULL) { 3838 node.name = def2->name; 3839 } else { 3840 node.name = invalidName; 3841 } 3842 node.ns = &ns; 3843 if (def2->ns != NULL) { 3844 if (def2->ns[0] == 0) { 3845 node.ns = NULL; 3846 } else { 3847 ns.href = def2->ns; 3848 } 3849 } else { 3850 ns.href = invalidName; 3851 } 3852 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { 3853 if (def2->nameClass != NULL) { 3854 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); 3855 } else { 3856 ret = 0; 3857 } 3858 } else { 3859 ret = 1; 3860 } 3861 } else { 3862 TODO ret = 0; 3863 } 3864 3865 return (ret); 3866 } 3867 3868 /** 3869 * xmlRelaxNGCompareElemDefLists: 3870 * @ctxt: a Relax-NG parser context 3871 * @defs1: the first list of element/attribute defs 3872 * @defs2: the second list of element/attribute defs 3873 * 3874 * Compare the 2 lists of element or attribute definitions. The comparison 3875 * is that if both lists do not accept the same QNames, it returns 1 3876 * If the 2 lists can accept the same QName the comparison returns 0 3877 * 3878 * Returns 1 disttinct, 0 if equal 3879 */ 3880 static int 3881 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt 3882 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, 3883 xmlRelaxNGDefinePtr * def2) 3884 { 3885 xmlRelaxNGDefinePtr *basedef2 = def2; 3886 3887 if ((def1 == NULL) || (def2 == NULL)) 3888 return (1); 3889 if ((*def1 == NULL) || (*def2 == NULL)) 3890 return (1); 3891 while (*def1 != NULL) { 3892 while ((*def2) != NULL) { 3893 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) 3894 return (0); 3895 def2++; 3896 } 3897 def2 = basedef2; 3898 def1++; 3899 } 3900 return (1); 3901 } 3902 3903 /** 3904 * xmlRelaxNGGenerateAttributes: 3905 * @ctxt: a Relax-NG parser context 3906 * @def: the definition definition 3907 * 3908 * Check if the definition can only generate attributes 3909 * 3910 * Returns 1 if yes, 0 if no and -1 in case of error. 3911 */ 3912 static int 3913 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, 3914 xmlRelaxNGDefinePtr def) 3915 { 3916 xmlRelaxNGDefinePtr parent, cur, tmp; 3917 3918 /* 3919 * Don't run that check in case of error. Infinite recursion 3920 * becomes possible. 3921 */ 3922 if (ctxt->nbErrors != 0) 3923 return (-1); 3924 3925 parent = NULL; 3926 cur = def; 3927 while (cur != NULL) { 3928 if ((cur->type == XML_RELAXNG_ELEMENT) || 3929 (cur->type == XML_RELAXNG_TEXT) || 3930 (cur->type == XML_RELAXNG_DATATYPE) || 3931 (cur->type == XML_RELAXNG_PARAM) || 3932 (cur->type == XML_RELAXNG_LIST) || 3933 (cur->type == XML_RELAXNG_VALUE) || 3934 (cur->type == XML_RELAXNG_EMPTY)) 3935 return (0); 3936 if ((cur->type == XML_RELAXNG_CHOICE) || 3937 (cur->type == XML_RELAXNG_INTERLEAVE) || 3938 (cur->type == XML_RELAXNG_GROUP) || 3939 (cur->type == XML_RELAXNG_ONEORMORE) || 3940 (cur->type == XML_RELAXNG_ZEROORMORE) || 3941 (cur->type == XML_RELAXNG_OPTIONAL) || 3942 (cur->type == XML_RELAXNG_PARENTREF) || 3943 (cur->type == XML_RELAXNG_EXTERNALREF) || 3944 (cur->type == XML_RELAXNG_REF) || 3945 (cur->type == XML_RELAXNG_DEF)) { 3946 if (cur->content != NULL) { 3947 parent = cur; 3948 cur = cur->content; 3949 tmp = cur; 3950 while (tmp != NULL) { 3951 tmp->parent = parent; 3952 tmp = tmp->next; 3953 } 3954 continue; 3955 } 3956 } 3957 if (cur == def) 3958 break; 3959 if (cur->next != NULL) { 3960 cur = cur->next; 3961 continue; 3962 } 3963 do { 3964 cur = cur->parent; 3965 if (cur == NULL) 3966 break; 3967 if (cur == def) 3968 return (1); 3969 if (cur->next != NULL) { 3970 cur = cur->next; 3971 break; 3972 } 3973 } while (cur != NULL); 3974 } 3975 return (1); 3976 } 3977 3978 /** 3979 * xmlRelaxNGGetElements: 3980 * @ctxt: a Relax-NG parser context 3981 * @def: the definition definition 3982 * @eora: gather elements (0) or attributes (1) 3983 * 3984 * Compute the list of top elements a definition can generate 3985 * 3986 * Returns a list of elements or NULL if none was found. 3987 */ 3988 static xmlRelaxNGDefinePtr * 3989 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, 3990 xmlRelaxNGDefinePtr def, int eora) 3991 { 3992 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; 3993 int len = 0; 3994 int max = 0; 3995 3996 /* 3997 * Don't run that check in case of error. Infinite recursion 3998 * becomes possible. 3999 */ 4000 if (ctxt->nbErrors != 0) 4001 return (NULL); 4002 4003 parent = NULL; 4004 cur = def; 4005 while (cur != NULL) { 4006 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || 4007 (cur->type == XML_RELAXNG_TEXT))) || 4008 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) { 4009 if (ret == NULL) { 4010 max = 10; 4011 ret = (xmlRelaxNGDefinePtr *) 4012 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4013 if (ret == NULL) { 4014 xmlRngPErrMemory(ctxt, "getting element list\n"); 4015 return (NULL); 4016 } 4017 } else if (max <= len) { 4018 xmlRelaxNGDefinePtr *temp; 4019 4020 max *= 2; 4021 temp = xmlRealloc(ret, 4022 (max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4023 if (temp == NULL) { 4024 xmlRngPErrMemory(ctxt, "getting element list\n"); 4025 xmlFree(ret); 4026 return (NULL); 4027 } 4028 ret = temp; 4029 } 4030 ret[len++] = cur; 4031 ret[len] = NULL; 4032 } else if ((cur->type == XML_RELAXNG_CHOICE) || 4033 (cur->type == XML_RELAXNG_INTERLEAVE) || 4034 (cur->type == XML_RELAXNG_GROUP) || 4035 (cur->type == XML_RELAXNG_ONEORMORE) || 4036 (cur->type == XML_RELAXNG_ZEROORMORE) || 4037 (cur->type == XML_RELAXNG_OPTIONAL) || 4038 (cur->type == XML_RELAXNG_PARENTREF) || 4039 (cur->type == XML_RELAXNG_REF) || 4040 (cur->type == XML_RELAXNG_DEF) || 4041 (cur->type == XML_RELAXNG_EXTERNALREF)) { 4042 /* 4043 * Don't go within elements or attributes or string values. 4044 * Just gather the element top list 4045 */ 4046 if (cur->content != NULL) { 4047 parent = cur; 4048 cur = cur->content; 4049 tmp = cur; 4050 while (tmp != NULL) { 4051 tmp->parent = parent; 4052 tmp = tmp->next; 4053 } 4054 continue; 4055 } 4056 } 4057 if (cur == def) 4058 break; 4059 if (cur->next != NULL) { 4060 cur = cur->next; 4061 continue; 4062 } 4063 do { 4064 cur = cur->parent; 4065 if (cur == NULL) 4066 break; 4067 if (cur == def) 4068 return (ret); 4069 if (cur->next != NULL) { 4070 cur = cur->next; 4071 break; 4072 } 4073 } while (cur != NULL); 4074 } 4075 return (ret); 4076 } 4077 4078 /** 4079 * xmlRelaxNGCheckChoiceDeterminism: 4080 * @ctxt: a Relax-NG parser context 4081 * @def: the choice definition 4082 * 4083 * Also used to find indeterministic pattern in choice 4084 */ 4085 static void 4086 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, 4087 xmlRelaxNGDefinePtr def) 4088 { 4089 xmlRelaxNGDefinePtr **list; 4090 xmlRelaxNGDefinePtr cur; 4091 int nbchild = 0, i, j, ret; 4092 int is_nullable = 0; 4093 int is_indeterminist = 0; 4094 xmlHashTablePtr triage = NULL; 4095 int is_triable = 1; 4096 4097 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) 4098 return; 4099 4100 if (def->dflags & IS_PROCESSED) 4101 return; 4102 4103 /* 4104 * Don't run that check in case of error. Infinite recursion 4105 * becomes possible. 4106 */ 4107 if (ctxt->nbErrors != 0) 4108 return; 4109 4110 is_nullable = xmlRelaxNGIsNullable(def); 4111 4112 cur = def->content; 4113 while (cur != NULL) { 4114 nbchild++; 4115 cur = cur->next; 4116 } 4117 4118 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4119 sizeof(xmlRelaxNGDefinePtr 4120 *)); 4121 if (list == NULL) { 4122 xmlRngPErrMemory(ctxt, "building choice\n"); 4123 return; 4124 } 4125 i = 0; 4126 /* 4127 * a bit strong but safe 4128 */ 4129 if (is_nullable == 0) { 4130 triage = xmlHashCreate(10); 4131 } else { 4132 is_triable = 0; 4133 } 4134 cur = def->content; 4135 while (cur != NULL) { 4136 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); 4137 if ((list[i] == NULL) || (list[i][0] == NULL)) { 4138 is_triable = 0; 4139 } else if (is_triable == 1) { 4140 xmlRelaxNGDefinePtr *tmp; 4141 int res; 4142 4143 tmp = list[i]; 4144 while ((*tmp != NULL) && (is_triable == 1)) { 4145 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4146 res = xmlHashAddEntry2(triage, 4147 BAD_CAST "#text", NULL, 4148 (void *) cur); 4149 if (res != 0) 4150 is_triable = -1; 4151 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4152 ((*tmp)->name != NULL)) { 4153 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4154 res = xmlHashAddEntry2(triage, 4155 (*tmp)->name, NULL, 4156 (void *) cur); 4157 else 4158 res = xmlHashAddEntry2(triage, 4159 (*tmp)->name, (*tmp)->ns, 4160 (void *) cur); 4161 if (res != 0) 4162 is_triable = -1; 4163 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4164 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4165 res = xmlHashAddEntry2(triage, 4166 BAD_CAST "#any", NULL, 4167 (void *) cur); 4168 else 4169 res = xmlHashAddEntry2(triage, 4170 BAD_CAST "#any", (*tmp)->ns, 4171 (void *) cur); 4172 if (res != 0) 4173 is_triable = -1; 4174 } else { 4175 is_triable = -1; 4176 } 4177 tmp++; 4178 } 4179 } 4180 i++; 4181 cur = cur->next; 4182 } 4183 4184 for (i = 0; i < nbchild; i++) { 4185 if (list[i] == NULL) 4186 continue; 4187 for (j = 0; j < i; j++) { 4188 if (list[j] == NULL) 4189 continue; 4190 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4191 if (ret == 0) { 4192 is_indeterminist = 1; 4193 } 4194 } 4195 } 4196 for (i = 0; i < nbchild; i++) { 4197 if (list[i] != NULL) 4198 xmlFree(list[i]); 4199 } 4200 4201 xmlFree(list); 4202 if (is_indeterminist) { 4203 def->dflags |= IS_INDETERMINIST; 4204 } 4205 if (is_triable == 1) { 4206 def->dflags |= IS_TRIABLE; 4207 def->data = triage; 4208 } else if (triage != NULL) { 4209 xmlHashFree(triage, NULL); 4210 } 4211 def->dflags |= IS_PROCESSED; 4212 } 4213 4214 /** 4215 * xmlRelaxNGCheckGroupAttrs: 4216 * @ctxt: a Relax-NG parser context 4217 * @def: the group definition 4218 * 4219 * Detects violations of rule 7.3 4220 */ 4221 static void 4222 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, 4223 xmlRelaxNGDefinePtr def) 4224 { 4225 xmlRelaxNGDefinePtr **list; 4226 xmlRelaxNGDefinePtr cur; 4227 int nbchild = 0, i, j, ret; 4228 4229 if ((def == NULL) || 4230 ((def->type != XML_RELAXNG_GROUP) && 4231 (def->type != XML_RELAXNG_ELEMENT))) 4232 return; 4233 4234 if (def->dflags & IS_PROCESSED) 4235 return; 4236 4237 /* 4238 * Don't run that check in case of error. Infinite recursion 4239 * becomes possible. 4240 */ 4241 if (ctxt->nbErrors != 0) 4242 return; 4243 4244 cur = def->attrs; 4245 while (cur != NULL) { 4246 nbchild++; 4247 cur = cur->next; 4248 } 4249 cur = def->content; 4250 while (cur != NULL) { 4251 nbchild++; 4252 cur = cur->next; 4253 } 4254 4255 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4256 sizeof(xmlRelaxNGDefinePtr 4257 *)); 4258 if (list == NULL) { 4259 xmlRngPErrMemory(ctxt, "building group\n"); 4260 return; 4261 } 4262 i = 0; 4263 cur = def->attrs; 4264 while (cur != NULL) { 4265 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4266 i++; 4267 cur = cur->next; 4268 } 4269 cur = def->content; 4270 while (cur != NULL) { 4271 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4272 i++; 4273 cur = cur->next; 4274 } 4275 4276 for (i = 0; i < nbchild; i++) { 4277 if (list[i] == NULL) 4278 continue; 4279 for (j = 0; j < i; j++) { 4280 if (list[j] == NULL) 4281 continue; 4282 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4283 if (ret == 0) { 4284 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, 4285 "Attributes conflicts in group\n", NULL, NULL); 4286 } 4287 } 4288 } 4289 for (i = 0; i < nbchild; i++) { 4290 if (list[i] != NULL) 4291 xmlFree(list[i]); 4292 } 4293 4294 xmlFree(list); 4295 def->dflags |= IS_PROCESSED; 4296 } 4297 4298 /** 4299 * xmlRelaxNGComputeInterleaves: 4300 * @def: the interleave definition 4301 * @ctxt: a Relax-NG parser context 4302 * @name: the definition name 4303 * 4304 * A lot of work for preprocessing interleave definitions 4305 * is potentially needed to get a decent execution speed at runtime 4306 * - trying to get a total order on the element nodes generated 4307 * by the interleaves, order the list of interleave definitions 4308 * following that order. 4309 * - if <text/> is used to handle mixed content, it is better to 4310 * flag this in the define and simplify the runtime checking 4311 * algorithm 4312 */ 4313 static void 4314 xmlRelaxNGComputeInterleaves(void *payload, void *data, 4315 const xmlChar * name ATTRIBUTE_UNUSED) 4316 { 4317 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; 4318 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 4319 xmlRelaxNGDefinePtr cur, *tmp; 4320 4321 xmlRelaxNGPartitionPtr partitions = NULL; 4322 xmlRelaxNGInterleaveGroupPtr *groups = NULL; 4323 xmlRelaxNGInterleaveGroupPtr group; 4324 int i, j, ret, res; 4325 int nbgroups = 0; 4326 int nbchild = 0; 4327 int is_mixed = 0; 4328 int is_determinist = 1; 4329 4330 /* 4331 * Don't run that check in case of error. Infinite recursion 4332 * becomes possible. 4333 */ 4334 if (ctxt->nbErrors != 0) 4335 return; 4336 4337 #ifdef DEBUG_INTERLEAVE 4338 xmlGenericError(xmlGenericErrorContext, 4339 "xmlRelaxNGComputeInterleaves(%s)\n", name); 4340 #endif 4341 cur = def->content; 4342 while (cur != NULL) { 4343 nbchild++; 4344 cur = cur->next; 4345 } 4346 4347 #ifdef DEBUG_INTERLEAVE 4348 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); 4349 #endif 4350 groups = (xmlRelaxNGInterleaveGroupPtr *) 4351 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); 4352 if (groups == NULL) 4353 goto error; 4354 cur = def->content; 4355 while (cur != NULL) { 4356 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) 4357 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); 4358 if (groups[nbgroups] == NULL) 4359 goto error; 4360 if (cur->type == XML_RELAXNG_TEXT) 4361 is_mixed++; 4362 groups[nbgroups]->rule = cur; 4363 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0); 4364 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); 4365 nbgroups++; 4366 cur = cur->next; 4367 } 4368 #ifdef DEBUG_INTERLEAVE 4369 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); 4370 #endif 4371 4372 /* 4373 * Let's check that all rules makes a partitions according to 7.4 4374 */ 4375 partitions = (xmlRelaxNGPartitionPtr) 4376 xmlMalloc(sizeof(xmlRelaxNGPartition)); 4377 if (partitions == NULL) 4378 goto error; 4379 memset(partitions, 0, sizeof(xmlRelaxNGPartition)); 4380 partitions->nbgroups = nbgroups; 4381 partitions->triage = xmlHashCreate(nbgroups); 4382 for (i = 0; i < nbgroups; i++) { 4383 group = groups[i]; 4384 for (j = i + 1; j < nbgroups; j++) { 4385 if (groups[j] == NULL) 4386 continue; 4387 4388 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, 4389 groups[j]->defs); 4390 if (ret == 0) { 4391 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, 4392 "Element or text conflicts in interleave\n", 4393 NULL, NULL); 4394 } 4395 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, 4396 groups[j]->attrs); 4397 if (ret == 0) { 4398 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, 4399 "Attributes conflicts in interleave\n", NULL, 4400 NULL); 4401 } 4402 } 4403 tmp = group->defs; 4404 if ((tmp != NULL) && (*tmp != NULL)) { 4405 while (*tmp != NULL) { 4406 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4407 res = xmlHashAddEntry2(partitions->triage, 4408 BAD_CAST "#text", NULL, 4409 (void *) (ptrdiff_t) (i + 1)); 4410 if (res != 0) 4411 is_determinist = -1; 4412 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4413 ((*tmp)->name != NULL)) { 4414 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4415 res = xmlHashAddEntry2(partitions->triage, 4416 (*tmp)->name, NULL, 4417 (void *) (ptrdiff_t) (i + 1)); 4418 else 4419 res = xmlHashAddEntry2(partitions->triage, 4420 (*tmp)->name, (*tmp)->ns, 4421 (void *) (ptrdiff_t) (i + 1)); 4422 if (res != 0) 4423 is_determinist = -1; 4424 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4425 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4426 res = xmlHashAddEntry2(partitions->triage, 4427 BAD_CAST "#any", NULL, 4428 (void *) (ptrdiff_t) (i + 1)); 4429 else 4430 res = xmlHashAddEntry2(partitions->triage, 4431 BAD_CAST "#any", (*tmp)->ns, 4432 (void *) (ptrdiff_t) (i + 1)); 4433 if ((*tmp)->nameClass != NULL) 4434 is_determinist = 2; 4435 if (res != 0) 4436 is_determinist = -1; 4437 } else { 4438 is_determinist = -1; 4439 } 4440 tmp++; 4441 } 4442 } else { 4443 is_determinist = 0; 4444 } 4445 } 4446 partitions->groups = groups; 4447 4448 /* 4449 * and save the partition list back in the def 4450 */ 4451 def->data = partitions; 4452 if (is_mixed != 0) 4453 def->dflags |= IS_MIXED; 4454 if (is_determinist == 1) 4455 partitions->flags = IS_DETERMINIST; 4456 if (is_determinist == 2) 4457 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; 4458 return; 4459 4460 error: 4461 xmlRngPErrMemory(ctxt, "in interleave computation\n"); 4462 if (groups != NULL) { 4463 for (i = 0; i < nbgroups; i++) 4464 if (groups[i] != NULL) { 4465 if (groups[i]->defs != NULL) 4466 xmlFree(groups[i]->defs); 4467 xmlFree(groups[i]); 4468 } 4469 xmlFree(groups); 4470 } 4471 xmlRelaxNGFreePartition(partitions); 4472 } 4473 4474 /** 4475 * xmlRelaxNGParseInterleave: 4476 * @ctxt: a Relax-NG parser context 4477 * @node: the data node. 4478 * 4479 * parse the content of a RelaxNG interleave node. 4480 * 4481 * Returns the definition pointer or NULL in case of error 4482 */ 4483 static xmlRelaxNGDefinePtr 4484 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4485 { 4486 xmlRelaxNGDefinePtr def = NULL; 4487 xmlRelaxNGDefinePtr last = NULL, cur; 4488 xmlNodePtr child; 4489 4490 def = xmlRelaxNGNewDefine(ctxt, node); 4491 if (def == NULL) { 4492 return (NULL); 4493 } 4494 def->type = XML_RELAXNG_INTERLEAVE; 4495 4496 if (ctxt->interleaves == NULL) 4497 ctxt->interleaves = xmlHashCreate(10); 4498 if (ctxt->interleaves == NULL) { 4499 xmlRngPErrMemory(ctxt, "create interleaves\n"); 4500 } else { 4501 char name[32]; 4502 4503 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); 4504 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { 4505 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, 4506 "Failed to add %s to hash table\n", 4507 (const xmlChar *) name, NULL); 4508 } 4509 } 4510 child = node->children; 4511 if (child == NULL) { 4512 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, 4513 "Element interleave is empty\n", NULL, NULL); 4514 } 4515 while (child != NULL) { 4516 if (IS_RELAXNG(child, "element")) { 4517 cur = xmlRelaxNGParseElement(ctxt, child); 4518 } else { 4519 cur = xmlRelaxNGParsePattern(ctxt, child); 4520 } 4521 if (cur != NULL) { 4522 cur->parent = def; 4523 if (last == NULL) { 4524 def->content = last = cur; 4525 } else { 4526 last->next = cur; 4527 last = cur; 4528 } 4529 } 4530 child = child->next; 4531 } 4532 4533 return (def); 4534 } 4535 4536 /** 4537 * xmlRelaxNGParseInclude: 4538 * @ctxt: a Relax-NG parser context 4539 * @node: the include node 4540 * 4541 * Integrate the content of an include node in the current grammar 4542 * 4543 * Returns 0 in case of success or -1 in case of error 4544 */ 4545 static int 4546 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4547 { 4548 xmlRelaxNGIncludePtr incl; 4549 xmlNodePtr root; 4550 int ret = 0, tmp; 4551 4552 incl = node->psvi; 4553 if (incl == NULL) { 4554 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, 4555 "Include node has no data\n", NULL, NULL); 4556 return (-1); 4557 } 4558 root = xmlDocGetRootElement(incl->doc); 4559 if (root == NULL) { 4560 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", 4561 NULL, NULL); 4562 return (-1); 4563 } 4564 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { 4565 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 4566 "Include document root is not a grammar\n", NULL, NULL); 4567 return (-1); 4568 } 4569 4570 /* 4571 * Merge the definition from both the include and the internal list 4572 */ 4573 if (root->children != NULL) { 4574 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); 4575 if (tmp != 0) 4576 ret = -1; 4577 } 4578 if (node->children != NULL) { 4579 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); 4580 if (tmp != 0) 4581 ret = -1; 4582 } 4583 return (ret); 4584 } 4585 4586 /** 4587 * xmlRelaxNGParseDefine: 4588 * @ctxt: a Relax-NG parser context 4589 * @node: the define node 4590 * 4591 * parse the content of a RelaxNG define element node. 4592 * 4593 * Returns 0 in case of success or -1 in case of error 4594 */ 4595 static int 4596 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4597 { 4598 xmlChar *name; 4599 int ret = 0, tmp; 4600 xmlRelaxNGDefinePtr def; 4601 const xmlChar *olddefine; 4602 4603 name = xmlGetProp(node, BAD_CAST "name"); 4604 if (name == NULL) { 4605 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, 4606 "define has no name\n", NULL, NULL); 4607 } else { 4608 xmlRelaxNGNormExtSpace(name); 4609 if (xmlValidateNCName(name, 0)) { 4610 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, 4611 "define name '%s' is not an NCName\n", name, NULL); 4612 } 4613 def = xmlRelaxNGNewDefine(ctxt, node); 4614 if (def == NULL) { 4615 xmlFree(name); 4616 return (-1); 4617 } 4618 def->type = XML_RELAXNG_DEF; 4619 def->name = name; 4620 if (node->children == NULL) { 4621 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, 4622 "define has no children\n", NULL, NULL); 4623 } else { 4624 olddefine = ctxt->define; 4625 ctxt->define = name; 4626 def->content = 4627 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4628 ctxt->define = olddefine; 4629 } 4630 if (ctxt->grammar->defs == NULL) 4631 ctxt->grammar->defs = xmlHashCreate(10); 4632 if (ctxt->grammar->defs == NULL) { 4633 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4634 "Could not create definition hash\n", NULL, NULL); 4635 ret = -1; 4636 } else { 4637 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); 4638 if (tmp < 0) { 4639 xmlRelaxNGDefinePtr prev; 4640 4641 prev = xmlHashLookup(ctxt->grammar->defs, name); 4642 if (prev == NULL) { 4643 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4644 "Internal error on define aggregation of %s\n", 4645 name, NULL); 4646 ret = -1; 4647 } else { 4648 while (prev->nextHash != NULL) 4649 prev = prev->nextHash; 4650 prev->nextHash = def; 4651 } 4652 } 4653 } 4654 } 4655 return (ret); 4656 } 4657 4658 /** 4659 * xmlRelaxNGParseImportRef: 4660 * @payload: the parser context 4661 * @data: the current grammar 4662 * @name: the reference name 4663 * 4664 * Import import one references into the current grammar 4665 */ 4666 static void 4667 xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) { 4668 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 4669 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; 4670 int tmp; 4671 4672 def->dflags |= IS_EXTERNAL_REF; 4673 4674 tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def); 4675 if (tmp < 0) { 4676 xmlRelaxNGDefinePtr prev; 4677 4678 prev = (xmlRelaxNGDefinePtr) 4679 xmlHashLookup(ctxt->grammar->refs, def->name); 4680 if (prev == NULL) { 4681 if (def->name != NULL) { 4682 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4683 "Error refs definitions '%s'\n", 4684 def->name, NULL); 4685 } else { 4686 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4687 "Error refs definitions\n", 4688 NULL, NULL); 4689 } 4690 } else { 4691 def->nextHash = prev->nextHash; 4692 prev->nextHash = def; 4693 } 4694 } 4695 } 4696 4697 /** 4698 * xmlRelaxNGParseImportRefs: 4699 * @ctxt: the parser context 4700 * @grammar: the sub grammar 4701 * 4702 * Import references from the subgrammar into the current grammar 4703 * 4704 * Returns 0 in case of success, -1 in case of failure 4705 */ 4706 static int 4707 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt, 4708 xmlRelaxNGGrammarPtr grammar) { 4709 if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL)) 4710 return(-1); 4711 if (grammar->refs == NULL) 4712 return(0); 4713 if (ctxt->grammar->refs == NULL) 4714 ctxt->grammar->refs = xmlHashCreate(10); 4715 if (ctxt->grammar->refs == NULL) { 4716 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4717 "Could not create references hash\n", NULL, NULL); 4718 return(-1); 4719 } 4720 xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt); 4721 return(0); 4722 } 4723 4724 /** 4725 * xmlRelaxNGProcessExternalRef: 4726 * @ctxt: the parser context 4727 * @node: the externlRef node 4728 * 4729 * Process and compile an externlRef node 4730 * 4731 * Returns the xmlRelaxNGDefinePtr or NULL in case of error 4732 */ 4733 static xmlRelaxNGDefinePtr 4734 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4735 { 4736 xmlRelaxNGDocumentPtr docu; 4737 xmlNodePtr root, tmp; 4738 xmlChar *ns; 4739 int newNs = 0, oldflags; 4740 xmlRelaxNGDefinePtr def; 4741 4742 docu = node->psvi; 4743 if (docu != NULL) { 4744 def = xmlRelaxNGNewDefine(ctxt, node); 4745 if (def == NULL) 4746 return (NULL); 4747 def->type = XML_RELAXNG_EXTERNALREF; 4748 4749 if (docu->content == NULL) { 4750 /* 4751 * Then do the parsing for good 4752 */ 4753 root = xmlDocGetRootElement(docu->doc); 4754 if (root == NULL) { 4755 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY, 4756 "xmlRelaxNGParse: %s is empty\n", ctxt->URL, 4757 NULL); 4758 return (NULL); 4759 } 4760 /* 4761 * ns transmission rules 4762 */ 4763 ns = xmlGetProp(root, BAD_CAST "ns"); 4764 if (ns == NULL) { 4765 tmp = node; 4766 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) { 4767 ns = xmlGetProp(tmp, BAD_CAST "ns"); 4768 if (ns != NULL) { 4769 break; 4770 } 4771 tmp = tmp->parent; 4772 } 4773 if (ns != NULL) { 4774 xmlSetProp(root, BAD_CAST "ns", ns); 4775 newNs = 1; 4776 xmlFree(ns); 4777 } 4778 } else { 4779 xmlFree(ns); 4780 } 4781 4782 /* 4783 * Parsing to get a precompiled schemas. 4784 */ 4785 oldflags = ctxt->flags; 4786 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; 4787 docu->schema = xmlRelaxNGParseDocument(ctxt, root); 4788 ctxt->flags = oldflags; 4789 if ((docu->schema != NULL) && 4790 (docu->schema->topgrammar != NULL)) { 4791 docu->content = docu->schema->topgrammar->start; 4792 if (docu->schema->topgrammar->refs) 4793 xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar); 4794 } 4795 4796 /* 4797 * the externalRef may be reused in a different ns context 4798 */ 4799 if (newNs == 1) { 4800 xmlUnsetProp(root, BAD_CAST "ns"); 4801 } 4802 } 4803 def->content = docu->content; 4804 } else { 4805 def = NULL; 4806 } 4807 return (def); 4808 } 4809 4810 /** 4811 * xmlRelaxNGParsePattern: 4812 * @ctxt: a Relax-NG parser context 4813 * @node: the pattern node. 4814 * 4815 * parse the content of a RelaxNG pattern node. 4816 * 4817 * Returns the definition pointer or NULL in case of error or if no 4818 * pattern is generated. 4819 */ 4820 static xmlRelaxNGDefinePtr 4821 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4822 { 4823 xmlRelaxNGDefinePtr def = NULL; 4824 4825 if (node == NULL) { 4826 return (NULL); 4827 } 4828 if (IS_RELAXNG(node, "element")) { 4829 def = xmlRelaxNGParseElement(ctxt, node); 4830 } else if (IS_RELAXNG(node, "attribute")) { 4831 def = xmlRelaxNGParseAttribute(ctxt, node); 4832 } else if (IS_RELAXNG(node, "empty")) { 4833 def = xmlRelaxNGNewDefine(ctxt, node); 4834 if (def == NULL) 4835 return (NULL); 4836 def->type = XML_RELAXNG_EMPTY; 4837 if (node->children != NULL) { 4838 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY, 4839 "empty: had a child node\n", NULL, NULL); 4840 } 4841 } else if (IS_RELAXNG(node, "text")) { 4842 def = xmlRelaxNGNewDefine(ctxt, node); 4843 if (def == NULL) 4844 return (NULL); 4845 def->type = XML_RELAXNG_TEXT; 4846 if (node->children != NULL) { 4847 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD, 4848 "text: had a child node\n", NULL, NULL); 4849 } 4850 } else if (IS_RELAXNG(node, "zeroOrMore")) { 4851 def = xmlRelaxNGNewDefine(ctxt, node); 4852 if (def == NULL) 4853 return (NULL); 4854 def->type = XML_RELAXNG_ZEROORMORE; 4855 if (node->children == NULL) { 4856 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4857 "Element %s is empty\n", node->name, NULL); 4858 } else { 4859 def->content = 4860 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4861 } 4862 } else if (IS_RELAXNG(node, "oneOrMore")) { 4863 def = xmlRelaxNGNewDefine(ctxt, node); 4864 if (def == NULL) 4865 return (NULL); 4866 def->type = XML_RELAXNG_ONEORMORE; 4867 if (node->children == NULL) { 4868 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4869 "Element %s is empty\n", node->name, NULL); 4870 } else { 4871 def->content = 4872 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4873 } 4874 } else if (IS_RELAXNG(node, "optional")) { 4875 def = xmlRelaxNGNewDefine(ctxt, node); 4876 if (def == NULL) 4877 return (NULL); 4878 def->type = XML_RELAXNG_OPTIONAL; 4879 if (node->children == NULL) { 4880 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4881 "Element %s is empty\n", node->name, NULL); 4882 } else { 4883 def->content = 4884 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4885 } 4886 } else if (IS_RELAXNG(node, "choice")) { 4887 def = xmlRelaxNGNewDefine(ctxt, node); 4888 if (def == NULL) 4889 return (NULL); 4890 def->type = XML_RELAXNG_CHOICE; 4891 if (node->children == NULL) { 4892 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4893 "Element %s is empty\n", node->name, NULL); 4894 } else { 4895 def->content = 4896 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4897 } 4898 } else if (IS_RELAXNG(node, "group")) { 4899 def = xmlRelaxNGNewDefine(ctxt, node); 4900 if (def == NULL) 4901 return (NULL); 4902 def->type = XML_RELAXNG_GROUP; 4903 if (node->children == NULL) { 4904 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4905 "Element %s is empty\n", node->name, NULL); 4906 } else { 4907 def->content = 4908 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4909 } 4910 } else if (IS_RELAXNG(node, "ref")) { 4911 def = xmlRelaxNGNewDefine(ctxt, node); 4912 if (def == NULL) 4913 return (NULL); 4914 def->type = XML_RELAXNG_REF; 4915 def->name = xmlGetProp(node, BAD_CAST "name"); 4916 if (def->name == NULL) { 4917 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n", 4918 NULL, NULL); 4919 } else { 4920 xmlRelaxNGNormExtSpace(def->name); 4921 if (xmlValidateNCName(def->name, 0)) { 4922 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID, 4923 "ref name '%s' is not an NCName\n", def->name, 4924 NULL); 4925 } 4926 } 4927 if (node->children != NULL) { 4928 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n", 4929 NULL, NULL); 4930 } 4931 if (ctxt->grammar->refs == NULL) 4932 ctxt->grammar->refs = xmlHashCreate(10); 4933 if (ctxt->grammar->refs == NULL) { 4934 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4935 "Could not create references hash\n", NULL, NULL); 4936 def = NULL; 4937 } else { 4938 int tmp; 4939 4940 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); 4941 if (tmp < 0) { 4942 xmlRelaxNGDefinePtr prev; 4943 4944 prev = (xmlRelaxNGDefinePtr) 4945 xmlHashLookup(ctxt->grammar->refs, def->name); 4946 if (prev == NULL) { 4947 if (def->name != NULL) { 4948 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4949 "Error refs definitions '%s'\n", 4950 def->name, NULL); 4951 } else { 4952 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4953 "Error refs definitions\n", 4954 NULL, NULL); 4955 } 4956 def = NULL; 4957 } else { 4958 def->nextHash = prev->nextHash; 4959 prev->nextHash = def; 4960 } 4961 } 4962 } 4963 } else if (IS_RELAXNG(node, "data")) { 4964 def = xmlRelaxNGParseData(ctxt, node); 4965 } else if (IS_RELAXNG(node, "value")) { 4966 def = xmlRelaxNGParseValue(ctxt, node); 4967 } else if (IS_RELAXNG(node, "list")) { 4968 def = xmlRelaxNGNewDefine(ctxt, node); 4969 if (def == NULL) 4970 return (NULL); 4971 def->type = XML_RELAXNG_LIST; 4972 if (node->children == NULL) { 4973 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4974 "Element %s is empty\n", node->name, NULL); 4975 } else { 4976 def->content = 4977 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4978 } 4979 } else if (IS_RELAXNG(node, "interleave")) { 4980 def = xmlRelaxNGParseInterleave(ctxt, node); 4981 } else if (IS_RELAXNG(node, "externalRef")) { 4982 def = xmlRelaxNGProcessExternalRef(ctxt, node); 4983 } else if (IS_RELAXNG(node, "notAllowed")) { 4984 def = xmlRelaxNGNewDefine(ctxt, node); 4985 if (def == NULL) 4986 return (NULL); 4987 def->type = XML_RELAXNG_NOT_ALLOWED; 4988 if (node->children != NULL) { 4989 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY, 4990 "xmlRelaxNGParse: notAllowed element is not empty\n", 4991 NULL, NULL); 4992 } 4993 } else if (IS_RELAXNG(node, "grammar")) { 4994 xmlRelaxNGGrammarPtr grammar, old; 4995 xmlRelaxNGGrammarPtr oldparent; 4996 4997 #ifdef DEBUG_GRAMMAR 4998 xmlGenericError(xmlGenericErrorContext, 4999 "Found <grammar> pattern\n"); 5000 #endif 5001 5002 oldparent = ctxt->parentgrammar; 5003 old = ctxt->grammar; 5004 ctxt->parentgrammar = old; 5005 grammar = xmlRelaxNGParseGrammar(ctxt, node->children); 5006 if (old != NULL) { 5007 ctxt->grammar = old; 5008 ctxt->parentgrammar = oldparent; 5009 #if 0 5010 if (grammar != NULL) { 5011 grammar->next = old->next; 5012 old->next = grammar; 5013 } 5014 #endif 5015 } 5016 if (grammar != NULL) 5017 def = grammar->start; 5018 else 5019 def = NULL; 5020 } else if (IS_RELAXNG(node, "parentRef")) { 5021 if (ctxt->parentgrammar == NULL) { 5022 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT, 5023 "Use of parentRef without a parent grammar\n", NULL, 5024 NULL); 5025 return (NULL); 5026 } 5027 def = xmlRelaxNGNewDefine(ctxt, node); 5028 if (def == NULL) 5029 return (NULL); 5030 def->type = XML_RELAXNG_PARENTREF; 5031 def->name = xmlGetProp(node, BAD_CAST "name"); 5032 if (def->name == NULL) { 5033 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME, 5034 "parentRef has no name\n", NULL, NULL); 5035 } else { 5036 xmlRelaxNGNormExtSpace(def->name); 5037 if (xmlValidateNCName(def->name, 0)) { 5038 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID, 5039 "parentRef name '%s' is not an NCName\n", 5040 def->name, NULL); 5041 } 5042 } 5043 if (node->children != NULL) { 5044 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY, 5045 "parentRef is not empty\n", NULL, NULL); 5046 } 5047 if (ctxt->parentgrammar->refs == NULL) 5048 ctxt->parentgrammar->refs = xmlHashCreate(10); 5049 if (ctxt->parentgrammar->refs == NULL) { 5050 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5051 "Could not create references hash\n", NULL, NULL); 5052 def = NULL; 5053 } else if (def->name != NULL) { 5054 int tmp; 5055 5056 tmp = 5057 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); 5058 if (tmp < 0) { 5059 xmlRelaxNGDefinePtr prev; 5060 5061 prev = (xmlRelaxNGDefinePtr) 5062 xmlHashLookup(ctxt->parentgrammar->refs, def->name); 5063 if (prev == NULL) { 5064 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5065 "Internal error parentRef definitions '%s'\n", 5066 def->name, NULL); 5067 def = NULL; 5068 } else { 5069 def->nextHash = prev->nextHash; 5070 prev->nextHash = def; 5071 } 5072 } 5073 } 5074 } else if (IS_RELAXNG(node, "mixed")) { 5075 if (node->children == NULL) { 5076 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n", 5077 NULL, NULL); 5078 def = NULL; 5079 } else { 5080 def = xmlRelaxNGParseInterleave(ctxt, node); 5081 if (def != NULL) { 5082 xmlRelaxNGDefinePtr tmp; 5083 5084 if ((def->content != NULL) && (def->content->next != NULL)) { 5085 tmp = xmlRelaxNGNewDefine(ctxt, node); 5086 if (tmp != NULL) { 5087 tmp->type = XML_RELAXNG_GROUP; 5088 tmp->content = def->content; 5089 def->content = tmp; 5090 } 5091 } 5092 5093 tmp = xmlRelaxNGNewDefine(ctxt, node); 5094 if (tmp == NULL) 5095 return (def); 5096 tmp->type = XML_RELAXNG_TEXT; 5097 tmp->next = def->content; 5098 def->content = tmp; 5099 } 5100 } 5101 } else { 5102 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT, 5103 "Unexpected node %s is not a pattern\n", node->name, 5104 NULL); 5105 def = NULL; 5106 } 5107 return (def); 5108 } 5109 5110 /** 5111 * xmlRelaxNGParseAttribute: 5112 * @ctxt: a Relax-NG parser context 5113 * @node: the element node 5114 * 5115 * parse the content of a RelaxNG attribute node. 5116 * 5117 * Returns the definition pointer or NULL in case of error. 5118 */ 5119 static xmlRelaxNGDefinePtr 5120 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5121 { 5122 xmlRelaxNGDefinePtr ret, cur; 5123 xmlNodePtr child; 5124 int old_flags; 5125 5126 ret = xmlRelaxNGNewDefine(ctxt, node); 5127 if (ret == NULL) 5128 return (NULL); 5129 ret->type = XML_RELAXNG_ATTRIBUTE; 5130 ret->parent = ctxt->def; 5131 child = node->children; 5132 if (child == NULL) { 5133 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY, 5134 "xmlRelaxNGParseattribute: attribute has no children\n", 5135 NULL, NULL); 5136 return (ret); 5137 } 5138 old_flags = ctxt->flags; 5139 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; 5140 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5141 if (cur != NULL) 5142 child = child->next; 5143 5144 if (child != NULL) { 5145 cur = xmlRelaxNGParsePattern(ctxt, child); 5146 if (cur != NULL) { 5147 switch (cur->type) { 5148 case XML_RELAXNG_EMPTY: 5149 case XML_RELAXNG_NOT_ALLOWED: 5150 case XML_RELAXNG_TEXT: 5151 case XML_RELAXNG_ELEMENT: 5152 case XML_RELAXNG_DATATYPE: 5153 case XML_RELAXNG_VALUE: 5154 case XML_RELAXNG_LIST: 5155 case XML_RELAXNG_REF: 5156 case XML_RELAXNG_PARENTREF: 5157 case XML_RELAXNG_EXTERNALREF: 5158 case XML_RELAXNG_DEF: 5159 case XML_RELAXNG_ONEORMORE: 5160 case XML_RELAXNG_ZEROORMORE: 5161 case XML_RELAXNG_OPTIONAL: 5162 case XML_RELAXNG_CHOICE: 5163 case XML_RELAXNG_GROUP: 5164 case XML_RELAXNG_INTERLEAVE: 5165 case XML_RELAXNG_ATTRIBUTE: 5166 ret->content = cur; 5167 cur->parent = ret; 5168 break; 5169 case XML_RELAXNG_START: 5170 case XML_RELAXNG_PARAM: 5171 case XML_RELAXNG_EXCEPT: 5172 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT, 5173 "attribute has invalid content\n", NULL, 5174 NULL); 5175 break; 5176 case XML_RELAXNG_NOOP: 5177 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP, 5178 "RNG Internal error, noop found in attribute\n", 5179 NULL, NULL); 5180 break; 5181 } 5182 } 5183 child = child->next; 5184 } 5185 if (child != NULL) { 5186 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN, 5187 "attribute has multiple children\n", NULL, NULL); 5188 } 5189 ctxt->flags = old_flags; 5190 return (ret); 5191 } 5192 5193 /** 5194 * xmlRelaxNGParseExceptNameClass: 5195 * @ctxt: a Relax-NG parser context 5196 * @node: the except node 5197 * @attr: 1 if within an attribute, 0 if within an element 5198 * 5199 * parse the content of a RelaxNG nameClass node. 5200 * 5201 * Returns the definition pointer or NULL in case of error. 5202 */ 5203 static xmlRelaxNGDefinePtr 5204 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, 5205 xmlNodePtr node, int attr) 5206 { 5207 xmlRelaxNGDefinePtr ret, cur, last = NULL; 5208 xmlNodePtr child; 5209 5210 if (!IS_RELAXNG(node, "except")) { 5211 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING, 5212 "Expecting an except node\n", NULL, NULL); 5213 return (NULL); 5214 } 5215 if (node->next != NULL) { 5216 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE, 5217 "exceptNameClass allows only a single except node\n", 5218 NULL, NULL); 5219 } 5220 if (node->children == NULL) { 5221 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n", 5222 NULL, NULL); 5223 return (NULL); 5224 } 5225 5226 ret = xmlRelaxNGNewDefine(ctxt, node); 5227 if (ret == NULL) 5228 return (NULL); 5229 ret->type = XML_RELAXNG_EXCEPT; 5230 child = node->children; 5231 while (child != NULL) { 5232 cur = xmlRelaxNGNewDefine(ctxt, child); 5233 if (cur == NULL) 5234 break; 5235 if (attr) 5236 cur->type = XML_RELAXNG_ATTRIBUTE; 5237 else 5238 cur->type = XML_RELAXNG_ELEMENT; 5239 5240 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) { 5241 if (last == NULL) { 5242 ret->content = cur; 5243 } else { 5244 last->next = cur; 5245 } 5246 last = cur; 5247 } 5248 child = child->next; 5249 } 5250 5251 return (ret); 5252 } 5253 5254 /** 5255 * xmlRelaxNGParseNameClass: 5256 * @ctxt: a Relax-NG parser context 5257 * @node: the nameClass node 5258 * @def: the current definition 5259 * 5260 * parse the content of a RelaxNG nameClass node. 5261 * 5262 * Returns the definition pointer or NULL in case of error. 5263 */ 5264 static xmlRelaxNGDefinePtr 5265 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, 5266 xmlRelaxNGDefinePtr def) 5267 { 5268 xmlRelaxNGDefinePtr ret, tmp; 5269 xmlChar *val; 5270 5271 ret = def; 5272 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) || 5273 (IS_RELAXNG(node, "nsName"))) { 5274 if ((def->type != XML_RELAXNG_ELEMENT) && 5275 (def->type != XML_RELAXNG_ATTRIBUTE)) { 5276 ret = xmlRelaxNGNewDefine(ctxt, node); 5277 if (ret == NULL) 5278 return (NULL); 5279 ret->parent = def; 5280 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) 5281 ret->type = XML_RELAXNG_ATTRIBUTE; 5282 else 5283 ret->type = XML_RELAXNG_ELEMENT; 5284 } 5285 } 5286 if (IS_RELAXNG(node, "name")) { 5287 val = xmlNodeGetContent(node); 5288 xmlRelaxNGNormExtSpace(val); 5289 if (xmlValidateNCName(val, 0)) { 5290 if (node->parent != NULL) 5291 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5292 "Element %s name '%s' is not an NCName\n", 5293 node->parent->name, val); 5294 else 5295 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5296 "name '%s' is not an NCName\n", 5297 val, NULL); 5298 } 5299 ret->name = val; 5300 val = xmlGetProp(node, BAD_CAST "ns"); 5301 ret->ns = val; 5302 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5303 (val != NULL) && 5304 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5305 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5306 "Attribute with namespace '%s' is not allowed\n", 5307 val, NULL); 5308 } 5309 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5310 (val != NULL) && 5311 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) { 5312 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME, 5313 "Attribute with QName 'xmlns' is not allowed\n", 5314 val, NULL); 5315 } 5316 } else if (IS_RELAXNG(node, "anyName")) { 5317 ret->name = NULL; 5318 ret->ns = NULL; 5319 if (node->children != NULL) { 5320 ret->nameClass = 5321 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5322 (def->type == 5323 XML_RELAXNG_ATTRIBUTE)); 5324 } 5325 } else if (IS_RELAXNG(node, "nsName")) { 5326 ret->name = NULL; 5327 ret->ns = xmlGetProp(node, BAD_CAST "ns"); 5328 if (ret->ns == NULL) { 5329 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS, 5330 "nsName has no ns attribute\n", NULL, NULL); 5331 } 5332 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5333 (ret->ns != NULL) && 5334 (xmlStrEqual 5335 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5336 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5337 "Attribute with namespace '%s' is not allowed\n", 5338 ret->ns, NULL); 5339 } 5340 if (node->children != NULL) { 5341 ret->nameClass = 5342 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5343 (def->type == 5344 XML_RELAXNG_ATTRIBUTE)); 5345 } 5346 } else if (IS_RELAXNG(node, "choice")) { 5347 xmlNodePtr child; 5348 xmlRelaxNGDefinePtr last = NULL; 5349 5350 ret = xmlRelaxNGNewDefine(ctxt, node); 5351 if (ret == NULL) 5352 return (NULL); 5353 ret->parent = def; 5354 ret->type = XML_RELAXNG_CHOICE; 5355 5356 if (node->children == NULL) { 5357 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY, 5358 "Element choice is empty\n", NULL, NULL); 5359 } else { 5360 5361 child = node->children; 5362 while (child != NULL) { 5363 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret); 5364 if (tmp != NULL) { 5365 if (last == NULL) { 5366 last = ret->nameClass = tmp; 5367 } else { 5368 last->next = tmp; 5369 last = tmp; 5370 } 5371 } 5372 child = child->next; 5373 } 5374 } 5375 } else { 5376 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT, 5377 "expecting name, anyName, nsName or choice : got %s\n", 5378 (node == NULL ? (const xmlChar *) "nothing" : node->name), 5379 NULL); 5380 return (NULL); 5381 } 5382 if (ret != def) { 5383 if (def->nameClass == NULL) { 5384 def->nameClass = ret; 5385 } else { 5386 tmp = def->nameClass; 5387 while (tmp->next != NULL) { 5388 tmp = tmp->next; 5389 } 5390 tmp->next = ret; 5391 } 5392 } 5393 return (ret); 5394 } 5395 5396 /** 5397 * xmlRelaxNGParseElement: 5398 * @ctxt: a Relax-NG parser context 5399 * @node: the element node 5400 * 5401 * parse the content of a RelaxNG element node. 5402 * 5403 * Returns the definition pointer or NULL in case of error. 5404 */ 5405 static xmlRelaxNGDefinePtr 5406 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5407 { 5408 xmlRelaxNGDefinePtr ret, cur, last; 5409 xmlNodePtr child; 5410 const xmlChar *olddefine; 5411 5412 ret = xmlRelaxNGNewDefine(ctxt, node); 5413 if (ret == NULL) 5414 return (NULL); 5415 ret->type = XML_RELAXNG_ELEMENT; 5416 ret->parent = ctxt->def; 5417 child = node->children; 5418 if (child == NULL) { 5419 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY, 5420 "xmlRelaxNGParseElement: element has no children\n", 5421 NULL, NULL); 5422 return (ret); 5423 } 5424 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5425 if (cur != NULL) 5426 child = child->next; 5427 5428 if (child == NULL) { 5429 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT, 5430 "xmlRelaxNGParseElement: element has no content\n", 5431 NULL, NULL); 5432 return (ret); 5433 } 5434 olddefine = ctxt->define; 5435 ctxt->define = NULL; 5436 last = NULL; 5437 while (child != NULL) { 5438 cur = xmlRelaxNGParsePattern(ctxt, child); 5439 if (cur != NULL) { 5440 cur->parent = ret; 5441 switch (cur->type) { 5442 case XML_RELAXNG_EMPTY: 5443 case XML_RELAXNG_NOT_ALLOWED: 5444 case XML_RELAXNG_TEXT: 5445 case XML_RELAXNG_ELEMENT: 5446 case XML_RELAXNG_DATATYPE: 5447 case XML_RELAXNG_VALUE: 5448 case XML_RELAXNG_LIST: 5449 case XML_RELAXNG_REF: 5450 case XML_RELAXNG_PARENTREF: 5451 case XML_RELAXNG_EXTERNALREF: 5452 case XML_RELAXNG_DEF: 5453 case XML_RELAXNG_ZEROORMORE: 5454 case XML_RELAXNG_ONEORMORE: 5455 case XML_RELAXNG_OPTIONAL: 5456 case XML_RELAXNG_CHOICE: 5457 case XML_RELAXNG_GROUP: 5458 case XML_RELAXNG_INTERLEAVE: 5459 if (last == NULL) { 5460 ret->content = last = cur; 5461 } else { 5462 if ((last->type == XML_RELAXNG_ELEMENT) && 5463 (ret->content == last)) { 5464 ret->content = xmlRelaxNGNewDefine(ctxt, node); 5465 if (ret->content != NULL) { 5466 ret->content->type = XML_RELAXNG_GROUP; 5467 ret->content->content = last; 5468 } else { 5469 ret->content = last; 5470 } 5471 } 5472 last->next = cur; 5473 last = cur; 5474 } 5475 break; 5476 case XML_RELAXNG_ATTRIBUTE: 5477 cur->next = ret->attrs; 5478 ret->attrs = cur; 5479 break; 5480 case XML_RELAXNG_START: 5481 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5482 "RNG Internal error, start found in element\n", 5483 NULL, NULL); 5484 break; 5485 case XML_RELAXNG_PARAM: 5486 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5487 "RNG Internal error, param found in element\n", 5488 NULL, NULL); 5489 break; 5490 case XML_RELAXNG_EXCEPT: 5491 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5492 "RNG Internal error, except found in element\n", 5493 NULL, NULL); 5494 break; 5495 case XML_RELAXNG_NOOP: 5496 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5497 "RNG Internal error, noop found in element\n", 5498 NULL, NULL); 5499 break; 5500 } 5501 } 5502 child = child->next; 5503 } 5504 ctxt->define = olddefine; 5505 return (ret); 5506 } 5507 5508 /** 5509 * xmlRelaxNGParsePatterns: 5510 * @ctxt: a Relax-NG parser context 5511 * @nodes: list of nodes 5512 * @group: use an implicit <group> for elements 5513 * 5514 * parse the content of a RelaxNG start node. 5515 * 5516 * Returns the definition pointer or NULL in case of error. 5517 */ 5518 static xmlRelaxNGDefinePtr 5519 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, 5520 int group) 5521 { 5522 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent; 5523 5524 parent = ctxt->def; 5525 while (nodes != NULL) { 5526 if (IS_RELAXNG(nodes, "element")) { 5527 cur = xmlRelaxNGParseElement(ctxt, nodes); 5528 if (def == NULL) { 5529 def = last = cur; 5530 } else { 5531 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) && 5532 (def == last)) { 5533 def = xmlRelaxNGNewDefine(ctxt, nodes); 5534 def->type = XML_RELAXNG_GROUP; 5535 def->content = last; 5536 } 5537 last->next = cur; 5538 last = cur; 5539 } 5540 cur->parent = parent; 5541 } else { 5542 cur = xmlRelaxNGParsePattern(ctxt, nodes); 5543 if (cur != NULL) { 5544 if (def == NULL) { 5545 def = last = cur; 5546 } else { 5547 last->next = cur; 5548 last = cur; 5549 } 5550 } 5551 } 5552 nodes = nodes->next; 5553 } 5554 return (def); 5555 } 5556 5557 /** 5558 * xmlRelaxNGParseStart: 5559 * @ctxt: a Relax-NG parser context 5560 * @nodes: start children nodes 5561 * 5562 * parse the content of a RelaxNG start node. 5563 * 5564 * Returns 0 in case of success, -1 in case of error 5565 */ 5566 static int 5567 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 5568 { 5569 int ret = 0; 5570 xmlRelaxNGDefinePtr def = NULL, last; 5571 5572 if (nodes == NULL) { 5573 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n", 5574 NULL, NULL); 5575 return (-1); 5576 } 5577 if (IS_RELAXNG(nodes, "empty")) { 5578 def = xmlRelaxNGNewDefine(ctxt, nodes); 5579 if (def == NULL) 5580 return (-1); 5581 def->type = XML_RELAXNG_EMPTY; 5582 if (nodes->children != NULL) { 5583 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT, 5584 "element empty is not empty\n", NULL, NULL); 5585 } 5586 } else if (IS_RELAXNG(nodes, "notAllowed")) { 5587 def = xmlRelaxNGNewDefine(ctxt, nodes); 5588 if (def == NULL) 5589 return (-1); 5590 def->type = XML_RELAXNG_NOT_ALLOWED; 5591 if (nodes->children != NULL) { 5592 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY, 5593 "element notAllowed is not empty\n", NULL, NULL); 5594 } 5595 } else { 5596 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1); 5597 } 5598 if (ctxt->grammar->start != NULL) { 5599 last = ctxt->grammar->start; 5600 while (last->next != NULL) 5601 last = last->next; 5602 last->next = def; 5603 } else { 5604 ctxt->grammar->start = def; 5605 } 5606 nodes = nodes->next; 5607 if (nodes != NULL) { 5608 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT, 5609 "start more than one children\n", NULL, NULL); 5610 return (-1); 5611 } 5612 return (ret); 5613 } 5614 5615 /** 5616 * xmlRelaxNGParseGrammarContent: 5617 * @ctxt: a Relax-NG parser context 5618 * @nodes: grammar children nodes 5619 * 5620 * parse the content of a RelaxNG grammar node. 5621 * 5622 * Returns 0 in case of success, -1 in case of error 5623 */ 5624 static int 5625 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 5626 xmlNodePtr nodes) 5627 { 5628 int ret = 0, tmp; 5629 5630 if (nodes == NULL) { 5631 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY, 5632 "grammar has no children\n", NULL, NULL); 5633 return (-1); 5634 } 5635 while (nodes != NULL) { 5636 if (IS_RELAXNG(nodes, "start")) { 5637 if (nodes->children == NULL) { 5638 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, 5639 "start has no children\n", NULL, NULL); 5640 } else { 5641 tmp = xmlRelaxNGParseStart(ctxt, nodes->children); 5642 if (tmp != 0) 5643 ret = -1; 5644 } 5645 } else if (IS_RELAXNG(nodes, "define")) { 5646 tmp = xmlRelaxNGParseDefine(ctxt, nodes); 5647 if (tmp != 0) 5648 ret = -1; 5649 } else if (IS_RELAXNG(nodes, "include")) { 5650 tmp = xmlRelaxNGParseInclude(ctxt, nodes); 5651 if (tmp != 0) 5652 ret = -1; 5653 } else { 5654 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 5655 "grammar has unexpected child %s\n", nodes->name, 5656 NULL); 5657 ret = -1; 5658 } 5659 nodes = nodes->next; 5660 } 5661 return (ret); 5662 } 5663 5664 /** 5665 * xmlRelaxNGCheckReference: 5666 * @ref: the ref 5667 * @ctxt: a Relax-NG parser context 5668 * @name: the name associated to the defines 5669 * 5670 * Applies the 4.17. combine attribute rule for all the define 5671 * element of a given grammar using the same name. 5672 */ 5673 static void 5674 xmlRelaxNGCheckReference(void *payload, void *data, const xmlChar * name) 5675 { 5676 xmlRelaxNGDefinePtr ref = (xmlRelaxNGDefinePtr) payload; 5677 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 5678 xmlRelaxNGGrammarPtr grammar; 5679 xmlRelaxNGDefinePtr def, cur; 5680 5681 /* 5682 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef 5683 */ 5684 if (ref->dflags & IS_EXTERNAL_REF) 5685 return; 5686 5687 grammar = ctxt->grammar; 5688 if (grammar == NULL) { 5689 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5690 "Internal error: no grammar in CheckReference %s\n", 5691 name, NULL); 5692 return; 5693 } 5694 if (ref->content != NULL) { 5695 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5696 "Internal error: reference has content in CheckReference %s\n", 5697 name, NULL); 5698 return; 5699 } 5700 if (grammar->defs != NULL) { 5701 def = xmlHashLookup(grammar->defs, name); 5702 if (def != NULL) { 5703 cur = ref; 5704 while (cur != NULL) { 5705 cur->content = def; 5706 cur = cur->nextHash; 5707 } 5708 } else { 5709 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5710 "Reference %s has no matching definition\n", name, 5711 NULL); 5712 } 5713 } else { 5714 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5715 "Reference %s has no matching definition\n", name, 5716 NULL); 5717 } 5718 } 5719 5720 /** 5721 * xmlRelaxNGCheckCombine: 5722 * @define: the define(s) list 5723 * @ctxt: a Relax-NG parser context 5724 * @name: the name associated to the defines 5725 * 5726 * Applies the 4.17. combine attribute rule for all the define 5727 * element of a given grammar using the same name. 5728 */ 5729 static void 5730 xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name) 5731 { 5732 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) payload; 5733 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 5734 xmlChar *combine; 5735 int choiceOrInterleave = -1; 5736 int missing = 0; 5737 xmlRelaxNGDefinePtr cur, last, tmp, tmp2; 5738 5739 if (define->nextHash == NULL) 5740 return; 5741 cur = define; 5742 while (cur != NULL) { 5743 combine = xmlGetProp(cur->node, BAD_CAST "combine"); 5744 if (combine != NULL) { 5745 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5746 if (choiceOrInterleave == -1) 5747 choiceOrInterleave = 1; 5748 else if (choiceOrInterleave == 0) { 5749 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5750 "Defines for %s use both 'choice' and 'interleave'\n", 5751 name, NULL); 5752 } 5753 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5754 if (choiceOrInterleave == -1) 5755 choiceOrInterleave = 0; 5756 else if (choiceOrInterleave == 1) { 5757 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5758 "Defines for %s use both 'choice' and 'interleave'\n", 5759 name, NULL); 5760 } 5761 } else { 5762 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE, 5763 "Defines for %s use unknown combine value '%s''\n", 5764 name, combine); 5765 } 5766 xmlFree(combine); 5767 } else { 5768 if (missing == 0) 5769 missing = 1; 5770 else { 5771 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE, 5772 "Some defines for %s needs the combine attribute\n", 5773 name, NULL); 5774 } 5775 } 5776 5777 cur = cur->nextHash; 5778 } 5779 #ifdef DEBUG 5780 xmlGenericError(xmlGenericErrorContext, 5781 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", 5782 name, choiceOrInterleave); 5783 #endif 5784 if (choiceOrInterleave == -1) 5785 choiceOrInterleave = 0; 5786 cur = xmlRelaxNGNewDefine(ctxt, define->node); 5787 if (cur == NULL) 5788 return; 5789 if (choiceOrInterleave == 0) 5790 cur->type = XML_RELAXNG_INTERLEAVE; 5791 else 5792 cur->type = XML_RELAXNG_CHOICE; 5793 tmp = define; 5794 last = NULL; 5795 while (tmp != NULL) { 5796 if (tmp->content != NULL) { 5797 if (tmp->content->next != NULL) { 5798 /* 5799 * we need first to create a wrapper. 5800 */ 5801 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node); 5802 if (tmp2 == NULL) 5803 break; 5804 tmp2->type = XML_RELAXNG_GROUP; 5805 tmp2->content = tmp->content; 5806 } else { 5807 tmp2 = tmp->content; 5808 } 5809 if (last == NULL) { 5810 cur->content = tmp2; 5811 } else { 5812 last->next = tmp2; 5813 } 5814 last = tmp2; 5815 } 5816 tmp->content = cur; 5817 tmp = tmp->nextHash; 5818 } 5819 define->content = cur; 5820 if (choiceOrInterleave == 0) { 5821 if (ctxt->interleaves == NULL) 5822 ctxt->interleaves = xmlHashCreate(10); 5823 if (ctxt->interleaves == NULL) { 5824 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5825 "Failed to create interleaves hash table\n", NULL, 5826 NULL); 5827 } else { 5828 char tmpname[32]; 5829 5830 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5831 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5832 0) { 5833 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5834 "Failed to add %s to hash table\n", 5835 (const xmlChar *) tmpname, NULL); 5836 } 5837 } 5838 } 5839 } 5840 5841 /** 5842 * xmlRelaxNGCombineStart: 5843 * @ctxt: a Relax-NG parser context 5844 * @grammar: the grammar 5845 * 5846 * Applies the 4.17. combine rule for all the start 5847 * element of a given grammar. 5848 */ 5849 static void 5850 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, 5851 xmlRelaxNGGrammarPtr grammar) 5852 { 5853 xmlRelaxNGDefinePtr starts; 5854 xmlChar *combine; 5855 int choiceOrInterleave = -1; 5856 int missing = 0; 5857 xmlRelaxNGDefinePtr cur; 5858 5859 starts = grammar->start; 5860 if ((starts == NULL) || (starts->next == NULL)) 5861 return; 5862 cur = starts; 5863 while (cur != NULL) { 5864 if ((cur->node == NULL) || (cur->node->parent == NULL) || 5865 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) { 5866 combine = NULL; 5867 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING, 5868 "Internal error: start element not found\n", NULL, 5869 NULL); 5870 } else { 5871 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine"); 5872 } 5873 5874 if (combine != NULL) { 5875 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5876 if (choiceOrInterleave == -1) 5877 choiceOrInterleave = 1; 5878 else if (choiceOrInterleave == 0) { 5879 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5880 "<start> use both 'choice' and 'interleave'\n", 5881 NULL, NULL); 5882 } 5883 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5884 if (choiceOrInterleave == -1) 5885 choiceOrInterleave = 0; 5886 else if (choiceOrInterleave == 1) { 5887 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5888 "<start> use both 'choice' and 'interleave'\n", 5889 NULL, NULL); 5890 } 5891 } else { 5892 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE, 5893 "<start> uses unknown combine value '%s''\n", 5894 combine, NULL); 5895 } 5896 xmlFree(combine); 5897 } else { 5898 if (missing == 0) 5899 missing = 1; 5900 else { 5901 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE, 5902 "Some <start> element miss the combine attribute\n", 5903 NULL, NULL); 5904 } 5905 } 5906 5907 cur = cur->next; 5908 } 5909 #ifdef DEBUG 5910 xmlGenericError(xmlGenericErrorContext, 5911 "xmlRelaxNGCombineStart(): merging <start>: %d\n", 5912 choiceOrInterleave); 5913 #endif 5914 if (choiceOrInterleave == -1) 5915 choiceOrInterleave = 0; 5916 cur = xmlRelaxNGNewDefine(ctxt, starts->node); 5917 if (cur == NULL) 5918 return; 5919 if (choiceOrInterleave == 0) 5920 cur->type = XML_RELAXNG_INTERLEAVE; 5921 else 5922 cur->type = XML_RELAXNG_CHOICE; 5923 cur->content = grammar->start; 5924 grammar->start = cur; 5925 if (choiceOrInterleave == 0) { 5926 if (ctxt->interleaves == NULL) 5927 ctxt->interleaves = xmlHashCreate(10); 5928 if (ctxt->interleaves == NULL) { 5929 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5930 "Failed to create interleaves hash table\n", NULL, 5931 NULL); 5932 } else { 5933 char tmpname[32]; 5934 5935 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5936 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5937 0) { 5938 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5939 "Failed to add %s to hash table\n", 5940 (const xmlChar *) tmpname, NULL); 5941 } 5942 } 5943 } 5944 } 5945 5946 /** 5947 * xmlRelaxNGCheckCycles: 5948 * @ctxt: a Relax-NG parser context 5949 * @nodes: grammar children nodes 5950 * @depth: the counter 5951 * 5952 * Check for cycles. 5953 * 5954 * Returns 0 if check passed, and -1 in case of error 5955 */ 5956 static int 5957 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 5958 xmlRelaxNGDefinePtr cur, int depth) 5959 { 5960 int ret = 0; 5961 5962 while ((ret == 0) && (cur != NULL)) { 5963 if ((cur->type == XML_RELAXNG_REF) || 5964 (cur->type == XML_RELAXNG_PARENTREF)) { 5965 if (cur->depth == -1) { 5966 cur->depth = depth; 5967 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 5968 cur->depth = -2; 5969 } else if (depth == cur->depth) { 5970 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE, 5971 "Detected a cycle in %s references\n", 5972 cur->name, NULL); 5973 return (-1); 5974 } 5975 } else if (cur->type == XML_RELAXNG_ELEMENT) { 5976 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1); 5977 } else { 5978 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 5979 } 5980 cur = cur->next; 5981 } 5982 return (ret); 5983 } 5984 5985 /** 5986 * xmlRelaxNGTryUnlink: 5987 * @ctxt: a Relax-NG parser context 5988 * @cur: the definition to unlink 5989 * @parent: the parent definition 5990 * @prev: the previous sibling definition 5991 * 5992 * Try to unlink a definition. If not possble make it a NOOP 5993 * 5994 * Returns the new prev definition 5995 */ 5996 static xmlRelaxNGDefinePtr 5997 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 5998 xmlRelaxNGDefinePtr cur, 5999 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev) 6000 { 6001 if (prev != NULL) { 6002 prev->next = cur->next; 6003 } else { 6004 if (parent != NULL) { 6005 if (parent->content == cur) 6006 parent->content = cur->next; 6007 else if (parent->attrs == cur) 6008 parent->attrs = cur->next; 6009 else if (parent->nameClass == cur) 6010 parent->nameClass = cur->next; 6011 } else { 6012 cur->type = XML_RELAXNG_NOOP; 6013 prev = cur; 6014 } 6015 } 6016 return (prev); 6017 } 6018 6019 /** 6020 * xmlRelaxNGSimplify: 6021 * @ctxt: a Relax-NG parser context 6022 * @nodes: grammar children nodes 6023 * 6024 * Check for simplification of empty and notAllowed 6025 */ 6026 static void 6027 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, 6028 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent) 6029 { 6030 xmlRelaxNGDefinePtr prev = NULL; 6031 6032 while (cur != NULL) { 6033 if ((cur->type == XML_RELAXNG_REF) || 6034 (cur->type == XML_RELAXNG_PARENTREF)) { 6035 if (cur->depth != -3) { 6036 cur->depth = -3; 6037 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6038 } 6039 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6040 cur->parent = parent; 6041 if ((parent != NULL) && 6042 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6043 (parent->type == XML_RELAXNG_LIST) || 6044 (parent->type == XML_RELAXNG_GROUP) || 6045 (parent->type == XML_RELAXNG_INTERLEAVE) || 6046 (parent->type == XML_RELAXNG_ONEORMORE) || 6047 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6048 parent->type = XML_RELAXNG_NOT_ALLOWED; 6049 break; 6050 } 6051 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) { 6052 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6053 } else 6054 prev = cur; 6055 } else if (cur->type == XML_RELAXNG_EMPTY) { 6056 cur->parent = parent; 6057 if ((parent != NULL) && 6058 ((parent->type == XML_RELAXNG_ONEORMORE) || 6059 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6060 parent->type = XML_RELAXNG_EMPTY; 6061 break; 6062 } 6063 if ((parent != NULL) && 6064 ((parent->type == XML_RELAXNG_GROUP) || 6065 (parent->type == XML_RELAXNG_INTERLEAVE))) { 6066 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6067 } else 6068 prev = cur; 6069 } else { 6070 cur->parent = parent; 6071 if (cur->content != NULL) 6072 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6073 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL)) 6074 xmlRelaxNGSimplify(ctxt, cur->attrs, cur); 6075 if (cur->nameClass != NULL) 6076 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur); 6077 /* 6078 * On Elements, try to move attribute only generating rules on 6079 * the attrs rules. 6080 */ 6081 if (cur->type == XML_RELAXNG_ELEMENT) { 6082 int attronly; 6083 xmlRelaxNGDefinePtr tmp, pre; 6084 6085 while (cur->content != NULL) { 6086 attronly = 6087 xmlRelaxNGGenerateAttributes(ctxt, cur->content); 6088 if (attronly == 1) { 6089 /* 6090 * migrate cur->content to attrs 6091 */ 6092 tmp = cur->content; 6093 cur->content = tmp->next; 6094 tmp->next = cur->attrs; 6095 cur->attrs = tmp; 6096 } else { 6097 /* 6098 * cur->content can generate elements or text 6099 */ 6100 break; 6101 } 6102 } 6103 pre = cur->content; 6104 while ((pre != NULL) && (pre->next != NULL)) { 6105 tmp = pre->next; 6106 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp); 6107 if (attronly == 1) { 6108 /* 6109 * migrate tmp to attrs 6110 */ 6111 pre->next = tmp->next; 6112 tmp->next = cur->attrs; 6113 cur->attrs = tmp; 6114 } else { 6115 pre = tmp; 6116 } 6117 } 6118 } 6119 /* 6120 * This may result in a simplification 6121 */ 6122 if ((cur->type == XML_RELAXNG_GROUP) || 6123 (cur->type == XML_RELAXNG_INTERLEAVE)) { 6124 if (cur->content == NULL) 6125 cur->type = XML_RELAXNG_EMPTY; 6126 else if (cur->content->next == NULL) { 6127 if ((parent == NULL) && (prev == NULL)) { 6128 cur->type = XML_RELAXNG_NOOP; 6129 } else if (prev == NULL) { 6130 parent->content = cur->content; 6131 cur->content->next = cur->next; 6132 cur = cur->content; 6133 } else { 6134 cur->content->next = cur->next; 6135 prev->next = cur->content; 6136 cur = cur->content; 6137 } 6138 } 6139 } 6140 /* 6141 * the current node may have been transformed back 6142 */ 6143 if ((cur->type == XML_RELAXNG_EXCEPT) && 6144 (cur->content != NULL) && 6145 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) { 6146 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6147 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6148 if ((parent != NULL) && 6149 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6150 (parent->type == XML_RELAXNG_LIST) || 6151 (parent->type == XML_RELAXNG_GROUP) || 6152 (parent->type == XML_RELAXNG_INTERLEAVE) || 6153 (parent->type == XML_RELAXNG_ONEORMORE) || 6154 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6155 parent->type = XML_RELAXNG_NOT_ALLOWED; 6156 break; 6157 } 6158 if ((parent != NULL) && 6159 (parent->type == XML_RELAXNG_CHOICE)) { 6160 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6161 } else 6162 prev = cur; 6163 } else if (cur->type == XML_RELAXNG_EMPTY) { 6164 if ((parent != NULL) && 6165 ((parent->type == XML_RELAXNG_ONEORMORE) || 6166 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6167 parent->type = XML_RELAXNG_EMPTY; 6168 break; 6169 } 6170 if ((parent != NULL) && 6171 ((parent->type == XML_RELAXNG_GROUP) || 6172 (parent->type == XML_RELAXNG_INTERLEAVE) || 6173 (parent->type == XML_RELAXNG_CHOICE))) { 6174 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6175 } else 6176 prev = cur; 6177 } else { 6178 prev = cur; 6179 } 6180 } 6181 cur = cur->next; 6182 } 6183 } 6184 6185 /** 6186 * xmlRelaxNGGroupContentType: 6187 * @ct1: the first content type 6188 * @ct2: the second content type 6189 * 6190 * Try to group 2 content types 6191 * 6192 * Returns the content type 6193 */ 6194 static xmlRelaxNGContentType 6195 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1, 6196 xmlRelaxNGContentType ct2) 6197 { 6198 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6199 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6200 return (XML_RELAXNG_CONTENT_ERROR); 6201 if (ct1 == XML_RELAXNG_CONTENT_EMPTY) 6202 return (ct2); 6203 if (ct2 == XML_RELAXNG_CONTENT_EMPTY) 6204 return (ct1); 6205 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) && 6206 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6207 return (XML_RELAXNG_CONTENT_COMPLEX); 6208 return (XML_RELAXNG_CONTENT_ERROR); 6209 } 6210 6211 /** 6212 * xmlRelaxNGMaxContentType: 6213 * @ct1: the first content type 6214 * @ct2: the second content type 6215 * 6216 * Compute the max content-type 6217 * 6218 * Returns the content type 6219 */ 6220 static xmlRelaxNGContentType 6221 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1, 6222 xmlRelaxNGContentType ct2) 6223 { 6224 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6225 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6226 return (XML_RELAXNG_CONTENT_ERROR); 6227 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) || 6228 (ct2 == XML_RELAXNG_CONTENT_SIMPLE)) 6229 return (XML_RELAXNG_CONTENT_SIMPLE); 6230 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) || 6231 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6232 return (XML_RELAXNG_CONTENT_COMPLEX); 6233 return (XML_RELAXNG_CONTENT_EMPTY); 6234 } 6235 6236 /** 6237 * xmlRelaxNGCheckRules: 6238 * @ctxt: a Relax-NG parser context 6239 * @cur: the current definition 6240 * @flags: some accumulated flags 6241 * @ptype: the parent type 6242 * 6243 * Check for rules in section 7.1 and 7.2 6244 * 6245 * Returns the content type of @cur 6246 */ 6247 static xmlRelaxNGContentType 6248 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, 6249 xmlRelaxNGDefinePtr cur, int flags, 6250 xmlRelaxNGType ptype) 6251 { 6252 int nflags; 6253 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY; 6254 6255 while (cur != NULL) { 6256 ret = XML_RELAXNG_CONTENT_EMPTY; 6257 if ((cur->type == XML_RELAXNG_REF) || 6258 (cur->type == XML_RELAXNG_PARENTREF)) { 6259 /* 6260 * This should actually be caught by list//element(ref) at the 6261 * element boundaries, c.f. Bug #159968 local refs are dropped 6262 * in step 4.19. 6263 */ 6264 #if 0 6265 if (flags & XML_RELAXNG_IN_LIST) { 6266 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF, 6267 "Found forbidden pattern list//ref\n", NULL, 6268 NULL); 6269 } 6270 #endif 6271 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6272 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF, 6273 "Found forbidden pattern data/except//ref\n", 6274 NULL, NULL); 6275 } 6276 if (cur->content == NULL) { 6277 if (cur->type == XML_RELAXNG_PARENTREF) 6278 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6279 "Internal found no define for parent refs\n", 6280 NULL, NULL); 6281 else 6282 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6283 "Internal found no define for ref %s\n", 6284 (cur->name ? cur->name: BAD_CAST "null"), NULL); 6285 } 6286 if (cur->depth > -4) { 6287 cur->depth = -4; 6288 ret = xmlRelaxNGCheckRules(ctxt, cur->content, 6289 flags, cur->type); 6290 cur->depth = ret - 15; 6291 } else if (cur->depth == -4) { 6292 ret = XML_RELAXNG_CONTENT_COMPLEX; 6293 } else { 6294 ret = (xmlRelaxNGContentType) (cur->depth + 15); 6295 } 6296 } else if (cur->type == XML_RELAXNG_ELEMENT) { 6297 /* 6298 * The 7.3 Attribute derivation rule for groups is plugged there 6299 */ 6300 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6301 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6302 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM, 6303 "Found forbidden pattern data/except//element(ref)\n", 6304 NULL, NULL); 6305 } 6306 if (flags & XML_RELAXNG_IN_LIST) { 6307 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM, 6308 "Found forbidden pattern list//element(ref)\n", 6309 NULL, NULL); 6310 } 6311 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6312 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6313 "Found forbidden pattern attribute//element(ref)\n", 6314 NULL, NULL); 6315 } 6316 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6317 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6318 "Found forbidden pattern attribute//element(ref)\n", 6319 NULL, NULL); 6320 } 6321 /* 6322 * reset since in the simple form elements are only child 6323 * of grammar/define 6324 */ 6325 nflags = 0; 6326 ret = 6327 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type); 6328 if (ret != XML_RELAXNG_CONTENT_EMPTY) { 6329 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY, 6330 "Element %s attributes have a content type error\n", 6331 cur->name, NULL); 6332 } 6333 ret = 6334 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6335 cur->type); 6336 if (ret == XML_RELAXNG_CONTENT_ERROR) { 6337 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR, 6338 "Element %s has a content type error\n", 6339 cur->name, NULL); 6340 } else { 6341 ret = XML_RELAXNG_CONTENT_COMPLEX; 6342 } 6343 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) { 6344 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR, 6346 "Found forbidden pattern attribute//attribute\n", 6347 NULL, NULL); 6348 } 6349 if (flags & XML_RELAXNG_IN_LIST) { 6350 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR, 6351 "Found forbidden pattern list//attribute\n", 6352 NULL, NULL); 6353 } 6354 if (flags & XML_RELAXNG_IN_OOMGROUP) { 6355 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR, 6356 "Found forbidden pattern oneOrMore//group//attribute\n", 6357 NULL, NULL); 6358 } 6359 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) { 6360 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, 6361 "Found forbidden pattern oneOrMore//interleave//attribute\n", 6362 NULL, NULL); 6363 } 6364 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6365 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR, 6366 "Found forbidden pattern data/except//attribute\n", 6367 NULL, NULL); 6368 } 6369 if (flags & XML_RELAXNG_IN_START) { 6370 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR, 6371 "Found forbidden pattern start//attribute\n", 6372 NULL, NULL); 6373 } 6374 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) 6375 && (cur->name == NULL)) { 6376 if (cur->ns == NULL) { 6377 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR, 6378 "Found anyName attribute without oneOrMore ancestor\n", 6379 NULL, NULL); 6380 } else { 6381 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR, 6382 "Found nsName attribute without oneOrMore ancestor\n", 6383 NULL, NULL); 6384 } 6385 } 6386 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE; 6387 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); 6388 ret = XML_RELAXNG_CONTENT_EMPTY; 6389 } else if ((cur->type == XML_RELAXNG_ONEORMORE) || 6390 (cur->type == XML_RELAXNG_ZEROORMORE)) { 6391 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6392 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, 6393 "Found forbidden pattern data/except//oneOrMore\n", 6394 NULL, NULL); 6395 } 6396 if (flags & XML_RELAXNG_IN_START) { 6397 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE, 6398 "Found forbidden pattern start//oneOrMore\n", 6399 NULL, NULL); 6400 } 6401 nflags = flags | XML_RELAXNG_IN_ONEORMORE; 6402 ret = 6403 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6404 cur->type); 6405 ret = xmlRelaxNGGroupContentType(ret, ret); 6406 } else if (cur->type == XML_RELAXNG_LIST) { 6407 if (flags & XML_RELAXNG_IN_LIST) { 6408 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST, 6409 "Found forbidden pattern list//list\n", NULL, 6410 NULL); 6411 } 6412 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6413 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST, 6414 "Found forbidden pattern data/except//list\n", 6415 NULL, NULL); 6416 } 6417 if (flags & XML_RELAXNG_IN_START) { 6418 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST, 6419 "Found forbidden pattern start//list\n", NULL, 6420 NULL); 6421 } 6422 nflags = flags | XML_RELAXNG_IN_LIST; 6423 ret = 6424 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6425 cur->type); 6426 } else if (cur->type == XML_RELAXNG_GROUP) { 6427 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6428 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP, 6429 "Found forbidden pattern data/except//group\n", 6430 NULL, NULL); 6431 } 6432 if (flags & XML_RELAXNG_IN_START) { 6433 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP, 6434 "Found forbidden pattern start//group\n", NULL, 6435 NULL); 6436 } 6437 if (flags & XML_RELAXNG_IN_ONEORMORE) 6438 nflags = flags | XML_RELAXNG_IN_OOMGROUP; 6439 else 6440 nflags = flags; 6441 ret = 6442 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6443 cur->type); 6444 /* 6445 * The 7.3 Attribute derivation rule for groups is plugged there 6446 */ 6447 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6448 } else if (cur->type == XML_RELAXNG_INTERLEAVE) { 6449 if (flags & XML_RELAXNG_IN_LIST) { 6450 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE, 6451 "Found forbidden pattern list//interleave\n", 6452 NULL, NULL); 6453 } 6454 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6455 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6456 "Found forbidden pattern data/except//interleave\n", 6457 NULL, NULL); 6458 } 6459 if (flags & XML_RELAXNG_IN_START) { 6460 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6461 "Found forbidden pattern start//interleave\n", 6462 NULL, NULL); 6463 } 6464 if (flags & XML_RELAXNG_IN_ONEORMORE) 6465 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE; 6466 else 6467 nflags = flags; 6468 ret = 6469 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6470 cur->type); 6471 } else if (cur->type == XML_RELAXNG_EXCEPT) { 6472 if ((cur->parent != NULL) && 6473 (cur->parent->type == XML_RELAXNG_DATATYPE)) 6474 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT; 6475 else 6476 nflags = flags; 6477 ret = 6478 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6479 cur->type); 6480 } else if (cur->type == XML_RELAXNG_DATATYPE) { 6481 if (flags & XML_RELAXNG_IN_START) { 6482 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA, 6483 "Found forbidden pattern start//data\n", NULL, 6484 NULL); 6485 } 6486 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6487 ret = XML_RELAXNG_CONTENT_SIMPLE; 6488 } else if (cur->type == XML_RELAXNG_VALUE) { 6489 if (flags & XML_RELAXNG_IN_START) { 6490 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE, 6491 "Found forbidden pattern start//value\n", NULL, 6492 NULL); 6493 } 6494 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6495 ret = XML_RELAXNG_CONTENT_SIMPLE; 6496 } else if (cur->type == XML_RELAXNG_TEXT) { 6497 if (flags & XML_RELAXNG_IN_LIST) { 6498 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT, 6499 "Found forbidden pattern list//text\n", NULL, 6500 NULL); 6501 } 6502 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6503 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT, 6504 "Found forbidden pattern data/except//text\n", 6505 NULL, NULL); 6506 } 6507 if (flags & XML_RELAXNG_IN_START) { 6508 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT, 6509 "Found forbidden pattern start//text\n", NULL, 6510 NULL); 6511 } 6512 ret = XML_RELAXNG_CONTENT_COMPLEX; 6513 } else if (cur->type == XML_RELAXNG_EMPTY) { 6514 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6515 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY, 6516 "Found forbidden pattern data/except//empty\n", 6517 NULL, NULL); 6518 } 6519 if (flags & XML_RELAXNG_IN_START) { 6520 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY, 6521 "Found forbidden pattern start//empty\n", NULL, 6522 NULL); 6523 } 6524 ret = XML_RELAXNG_CONTENT_EMPTY; 6525 } else if (cur->type == XML_RELAXNG_CHOICE) { 6526 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur); 6527 ret = 6528 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6529 } else { 6530 ret = 6531 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6532 } 6533 cur = cur->next; 6534 if (ptype == XML_RELAXNG_GROUP) { 6535 val = xmlRelaxNGGroupContentType(val, ret); 6536 } else if (ptype == XML_RELAXNG_INTERLEAVE) { 6537 /* 6538 * TODO: scan complain that tmp is never used, seems on purpose 6539 * need double-checking 6540 */ 6541 tmp = xmlRelaxNGGroupContentType(val, ret); 6542 if (tmp != XML_RELAXNG_CONTENT_ERROR) 6543 tmp = xmlRelaxNGMaxContentType(val, ret); 6544 } else if (ptype == XML_RELAXNG_CHOICE) { 6545 val = xmlRelaxNGMaxContentType(val, ret); 6546 } else if (ptype == XML_RELAXNG_LIST) { 6547 val = XML_RELAXNG_CONTENT_SIMPLE; 6548 } else if (ptype == XML_RELAXNG_EXCEPT) { 6549 if (ret == XML_RELAXNG_CONTENT_ERROR) 6550 val = XML_RELAXNG_CONTENT_ERROR; 6551 else 6552 val = XML_RELAXNG_CONTENT_SIMPLE; 6553 } else { 6554 val = xmlRelaxNGGroupContentType(val, ret); 6555 } 6556 6557 } 6558 return (val); 6559 } 6560 6561 /** 6562 * xmlRelaxNGParseGrammar: 6563 * @ctxt: a Relax-NG parser context 6564 * @nodes: grammar children nodes 6565 * 6566 * parse a Relax-NG <grammar> node 6567 * 6568 * Returns the internal xmlRelaxNGGrammarPtr built or 6569 * NULL in case of error 6570 */ 6571 static xmlRelaxNGGrammarPtr 6572 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 6573 { 6574 xmlRelaxNGGrammarPtr ret, tmp, old; 6575 6576 #ifdef DEBUG_GRAMMAR 6577 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n"); 6578 #endif 6579 6580 ret = xmlRelaxNGNewGrammar(ctxt); 6581 if (ret == NULL) 6582 return (NULL); 6583 6584 /* 6585 * Link the new grammar in the tree 6586 */ 6587 ret->parent = ctxt->grammar; 6588 if (ctxt->grammar != NULL) { 6589 tmp = ctxt->grammar->children; 6590 if (tmp == NULL) { 6591 ctxt->grammar->children = ret; 6592 } else { 6593 while (tmp->next != NULL) 6594 tmp = tmp->next; 6595 tmp->next = ret; 6596 } 6597 } 6598 6599 old = ctxt->grammar; 6600 ctxt->grammar = ret; 6601 xmlRelaxNGParseGrammarContent(ctxt, nodes); 6602 ctxt->grammar = ret; 6603 if (ctxt->grammar == NULL) { 6604 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 6605 "Failed to parse <grammar> content\n", NULL, NULL); 6606 } else if (ctxt->grammar->start == NULL) { 6607 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START, 6608 "Element <grammar> has no <start>\n", NULL, NULL); 6609 } 6610 6611 /* 6612 * Apply 4.17 merging rules to defines and starts 6613 */ 6614 xmlRelaxNGCombineStart(ctxt, ret); 6615 if (ret->defs != NULL) { 6616 xmlHashScan(ret->defs, xmlRelaxNGCheckCombine, ctxt); 6617 } 6618 6619 /* 6620 * link together defines and refs in this grammar 6621 */ 6622 if (ret->refs != NULL) { 6623 xmlHashScan(ret->refs, xmlRelaxNGCheckReference, ctxt); 6624 } 6625 6626 6627 /* @@@@ */ 6628 6629 ctxt->grammar = old; 6630 return (ret); 6631 } 6632 6633 /** 6634 * xmlRelaxNGParseDocument: 6635 * @ctxt: a Relax-NG parser context 6636 * @node: the root node of the RelaxNG schema 6637 * 6638 * parse a Relax-NG definition resource and build an internal 6639 * xmlRelaxNG struture which can be used to validate instances. 6640 * 6641 * Returns the internal XML RelaxNG structure built or 6642 * NULL in case of error 6643 */ 6644 static xmlRelaxNGPtr 6645 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6646 { 6647 xmlRelaxNGPtr schema = NULL; 6648 const xmlChar *olddefine; 6649 xmlRelaxNGGrammarPtr old; 6650 6651 if ((ctxt == NULL) || (node == NULL)) 6652 return (NULL); 6653 6654 schema = xmlRelaxNGNewRelaxNG(ctxt); 6655 if (schema == NULL) 6656 return (NULL); 6657 6658 olddefine = ctxt->define; 6659 ctxt->define = NULL; 6660 if (IS_RELAXNG(node, "grammar")) { 6661 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children); 6662 if (schema->topgrammar == NULL) { 6663 xmlRelaxNGFree(schema); 6664 return (NULL); 6665 } 6666 } else { 6667 xmlRelaxNGGrammarPtr tmp, ret; 6668 6669 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt); 6670 if (schema->topgrammar == NULL) { 6671 xmlRelaxNGFree(schema); 6672 return (NULL); 6673 } 6674 /* 6675 * Link the new grammar in the tree 6676 */ 6677 ret->parent = ctxt->grammar; 6678 if (ctxt->grammar != NULL) { 6679 tmp = ctxt->grammar->children; 6680 if (tmp == NULL) { 6681 ctxt->grammar->children = ret; 6682 } else { 6683 while (tmp->next != NULL) 6684 tmp = tmp->next; 6685 tmp->next = ret; 6686 } 6687 } 6688 old = ctxt->grammar; 6689 ctxt->grammar = ret; 6690 xmlRelaxNGParseStart(ctxt, node); 6691 if (old != NULL) 6692 ctxt->grammar = old; 6693 } 6694 ctxt->define = olddefine; 6695 if (schema->topgrammar->start != NULL) { 6696 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0); 6697 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) { 6698 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL); 6699 while ((schema->topgrammar->start != NULL) && 6700 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) && 6701 (schema->topgrammar->start->next != NULL)) 6702 schema->topgrammar->start = 6703 schema->topgrammar->start->content; 6704 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start, 6705 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); 6706 } 6707 } 6708 #ifdef DEBUG 6709 if (schema == NULL) 6710 xmlGenericError(xmlGenericErrorContext, 6711 "xmlRelaxNGParseDocument() failed\n"); 6712 #endif 6713 6714 return (schema); 6715 } 6716 6717 /************************************************************************ 6718 * * 6719 * Reading RelaxNGs * 6720 * * 6721 ************************************************************************/ 6722 6723 /** 6724 * xmlRelaxNGNewParserCtxt: 6725 * @URL: the location of the schema 6726 * 6727 * Create an XML RelaxNGs parse context for that file/resource expected 6728 * to contain an XML RelaxNGs file. 6729 * 6730 * Returns the parser context or NULL in case of error 6731 */ 6732 xmlRelaxNGParserCtxtPtr 6733 xmlRelaxNGNewParserCtxt(const char *URL) 6734 { 6735 xmlRelaxNGParserCtxtPtr ret; 6736 6737 if (URL == NULL) 6738 return (NULL); 6739 6740 ret = 6741 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6742 if (ret == NULL) { 6743 xmlRngPErrMemory(NULL, "building parser\n"); 6744 return (NULL); 6745 } 6746 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6747 ret->URL = xmlStrdup((const xmlChar *) URL); 6748 ret->error = xmlGenericError; 6749 ret->userData = xmlGenericErrorContext; 6750 return (ret); 6751 } 6752 6753 /** 6754 * xmlRelaxNGNewMemParserCtxt: 6755 * @buffer: a pointer to a char array containing the schemas 6756 * @size: the size of the array 6757 * 6758 * Create an XML RelaxNGs parse context for that memory buffer expected 6759 * to contain an XML RelaxNGs file. 6760 * 6761 * Returns the parser context or NULL in case of error 6762 */ 6763 xmlRelaxNGParserCtxtPtr 6764 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) 6765 { 6766 xmlRelaxNGParserCtxtPtr ret; 6767 6768 if ((buffer == NULL) || (size <= 0)) 6769 return (NULL); 6770 6771 ret = 6772 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6773 if (ret == NULL) { 6774 xmlRngPErrMemory(NULL, "building parser\n"); 6775 return (NULL); 6776 } 6777 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6778 ret->buffer = buffer; 6779 ret->size = size; 6780 ret->error = xmlGenericError; 6781 ret->userData = xmlGenericErrorContext; 6782 return (ret); 6783 } 6784 6785 /** 6786 * xmlRelaxNGNewDocParserCtxt: 6787 * @doc: a preparsed document tree 6788 * 6789 * Create an XML RelaxNGs parser context for that document. 6790 * Note: since the process of compiling a RelaxNG schemas modifies the 6791 * document, the @doc parameter is duplicated internally. 6792 * 6793 * Returns the parser context or NULL in case of error 6794 */ 6795 xmlRelaxNGParserCtxtPtr 6796 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) 6797 { 6798 xmlRelaxNGParserCtxtPtr ret; 6799 xmlDocPtr copy; 6800 6801 if (doc == NULL) 6802 return (NULL); 6803 copy = xmlCopyDoc(doc, 1); 6804 if (copy == NULL) 6805 return (NULL); 6806 6807 ret = 6808 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6809 if (ret == NULL) { 6810 xmlRngPErrMemory(NULL, "building parser\n"); 6811 return (NULL); 6812 } 6813 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6814 ret->document = copy; 6815 ret->freedoc = 1; 6816 ret->userData = xmlGenericErrorContext; 6817 return (ret); 6818 } 6819 6820 /** 6821 * xmlRelaxNGFreeParserCtxt: 6822 * @ctxt: the schema parser context 6823 * 6824 * Free the resources associated to the schema parser context 6825 */ 6826 void 6827 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) 6828 { 6829 if (ctxt == NULL) 6830 return; 6831 if (ctxt->URL != NULL) 6832 xmlFree(ctxt->URL); 6833 if (ctxt->doc != NULL) 6834 xmlRelaxNGFreeDocument(ctxt->doc); 6835 if (ctxt->interleaves != NULL) 6836 xmlHashFree(ctxt->interleaves, NULL); 6837 if (ctxt->documents != NULL) 6838 xmlRelaxNGFreeDocumentList(ctxt->documents); 6839 if (ctxt->includes != NULL) 6840 xmlRelaxNGFreeIncludeList(ctxt->includes); 6841 if (ctxt->docTab != NULL) 6842 xmlFree(ctxt->docTab); 6843 if (ctxt->incTab != NULL) 6844 xmlFree(ctxt->incTab); 6845 if (ctxt->defTab != NULL) { 6846 int i; 6847 6848 for (i = 0; i < ctxt->defNr; i++) 6849 xmlRelaxNGFreeDefine(ctxt->defTab[i]); 6850 xmlFree(ctxt->defTab); 6851 } 6852 if ((ctxt->document != NULL) && (ctxt->freedoc)) 6853 xmlFreeDoc(ctxt->document); 6854 xmlFree(ctxt); 6855 } 6856 6857 /** 6858 * xmlRelaxNGNormExtSpace: 6859 * @value: a value 6860 * 6861 * Removes the leading and ending spaces of the value 6862 * The string is modified "in situ" 6863 */ 6864 static void 6865 xmlRelaxNGNormExtSpace(xmlChar * value) 6866 { 6867 xmlChar *start = value; 6868 xmlChar *cur = value; 6869 6870 if (value == NULL) 6871 return; 6872 6873 while (IS_BLANK_CH(*cur)) 6874 cur++; 6875 if (cur == start) { 6876 do { 6877 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6878 cur++; 6879 if (*cur == 0) 6880 return; 6881 start = cur; 6882 while (IS_BLANK_CH(*cur)) 6883 cur++; 6884 if (*cur == 0) { 6885 *start = 0; 6886 return; 6887 } 6888 } while (1); 6889 } else { 6890 do { 6891 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6892 *start++ = *cur++; 6893 if (*cur == 0) { 6894 *start = 0; 6895 return; 6896 } 6897 /* don't try to normalize the inner spaces */ 6898 while (IS_BLANK_CH(*cur)) 6899 cur++; 6900 if (*cur == 0) { 6901 *start = 0; 6902 return; 6903 } 6904 *start++ = *cur++; 6905 } while (1); 6906 } 6907 } 6908 6909 /** 6910 * xmlRelaxNGCleanupAttributes: 6911 * @ctxt: a Relax-NG parser context 6912 * @node: a Relax-NG node 6913 * 6914 * Check all the attributes on the given node 6915 */ 6916 static void 6917 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6918 { 6919 xmlAttrPtr cur, next; 6920 6921 cur = node->properties; 6922 while (cur != NULL) { 6923 next = cur->next; 6924 if ((cur->ns == NULL) || 6925 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 6926 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 6927 if ((!xmlStrEqual(node->name, BAD_CAST "element")) && 6928 (!xmlStrEqual(node->name, BAD_CAST "attribute")) && 6929 (!xmlStrEqual(node->name, BAD_CAST "ref")) && 6930 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) && 6931 (!xmlStrEqual(node->name, BAD_CAST "param")) && 6932 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 6933 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6934 "Attribute %s is not allowed on %s\n", 6935 cur->name, node->name); 6936 } 6937 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) { 6938 if ((!xmlStrEqual(node->name, BAD_CAST "value")) && 6939 (!xmlStrEqual(node->name, BAD_CAST "data"))) { 6940 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6941 "Attribute %s is not allowed on %s\n", 6942 cur->name, node->name); 6943 } 6944 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) { 6945 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) && 6946 (!xmlStrEqual(node->name, BAD_CAST "include"))) { 6947 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6948 "Attribute %s is not allowed on %s\n", 6949 cur->name, node->name); 6950 } 6951 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) { 6952 if ((!xmlStrEqual(node->name, BAD_CAST "start")) && 6953 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 6954 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6955 "Attribute %s is not allowed on %s\n", 6956 cur->name, node->name); 6957 } 6958 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) { 6959 xmlChar *val; 6960 xmlURIPtr uri; 6961 6962 val = xmlNodeListGetString(node->doc, cur->children, 1); 6963 if (val != NULL) { 6964 if (val[0] != 0) { 6965 uri = xmlParseURI((const char *) val); 6966 if (uri == NULL) { 6967 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI, 6968 "Attribute %s contains invalid URI %s\n", 6969 cur->name, val); 6970 } else { 6971 if (uri->scheme == NULL) { 6972 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE, 6973 "Attribute %s URI %s is not absolute\n", 6974 cur->name, val); 6975 } 6976 if (uri->fragment != NULL) { 6977 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT, 6978 "Attribute %s URI %s has a fragment ID\n", 6979 cur->name, val); 6980 } 6981 xmlFreeURI(uri); 6982 } 6983 } 6984 xmlFree(val); 6985 } 6986 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) { 6987 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE, 6988 "Unknown attribute %s on %s\n", cur->name, 6989 node->name); 6990 } 6991 } 6992 cur = next; 6993 } 6994 } 6995 6996 /** 6997 * xmlRelaxNGCleanupTree: 6998 * @ctxt: a Relax-NG parser context 6999 * @root: an xmlNodePtr subtree 7000 * 7001 * Cleanup the subtree from unwanted nodes for parsing, resolve 7002 * Include and externalRef lookups. 7003 */ 7004 static void 7005 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) 7006 { 7007 xmlNodePtr cur, delete; 7008 7009 delete = NULL; 7010 cur = root; 7011 while (cur != NULL) { 7012 if (delete != NULL) { 7013 xmlUnlinkNode(delete); 7014 xmlFreeNode(delete); 7015 delete = NULL; 7016 } 7017 if (cur->type == XML_ELEMENT_NODE) { 7018 /* 7019 * Simplification 4.1. Annotations 7020 */ 7021 if ((cur->ns == NULL) || 7022 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 7023 if ((cur->parent != NULL) && 7024 (cur->parent->type == XML_ELEMENT_NODE) && 7025 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) || 7026 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) || 7027 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) { 7028 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT, 7029 "element %s doesn't allow foreign elements\n", 7030 cur->parent->name, NULL); 7031 } 7032 delete = cur; 7033 goto skip_children; 7034 } else { 7035 xmlRelaxNGCleanupAttributes(ctxt, cur); 7036 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) { 7037 xmlChar *href, *ns, *base, *URL; 7038 xmlRelaxNGDocumentPtr docu; 7039 xmlNodePtr tmp; 7040 xmlURIPtr uri; 7041 7042 ns = xmlGetProp(cur, BAD_CAST "ns"); 7043 if (ns == NULL) { 7044 tmp = cur->parent; 7045 while ((tmp != NULL) && 7046 (tmp->type == XML_ELEMENT_NODE)) { 7047 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7048 if (ns != NULL) 7049 break; 7050 tmp = tmp->parent; 7051 } 7052 } 7053 href = xmlGetProp(cur, BAD_CAST "href"); 7054 if (href == NULL) { 7055 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7056 "xmlRelaxNGParse: externalRef has no href attribute\n", 7057 NULL, NULL); 7058 if (ns != NULL) 7059 xmlFree(ns); 7060 delete = cur; 7061 goto skip_children; 7062 } 7063 uri = xmlParseURI((const char *) href); 7064 if (uri == NULL) { 7065 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7066 "Incorrect URI for externalRef %s\n", 7067 href, NULL); 7068 if (ns != NULL) 7069 xmlFree(ns); 7070 if (href != NULL) 7071 xmlFree(href); 7072 delete = cur; 7073 goto skip_children; 7074 } 7075 if (uri->fragment != NULL) { 7076 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7077 "Fragment forbidden in URI for externalRef %s\n", 7078 href, NULL); 7079 if (ns != NULL) 7080 xmlFree(ns); 7081 xmlFreeURI(uri); 7082 if (href != NULL) 7083 xmlFree(href); 7084 delete = cur; 7085 goto skip_children; 7086 } 7087 xmlFreeURI(uri); 7088 base = xmlNodeGetBase(cur->doc, cur); 7089 URL = xmlBuildURI(href, base); 7090 if (URL == NULL) { 7091 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7092 "Failed to compute URL for externalRef %s\n", 7093 href, NULL); 7094 if (ns != NULL) 7095 xmlFree(ns); 7096 if (href != NULL) 7097 xmlFree(href); 7098 if (base != NULL) 7099 xmlFree(base); 7100 delete = cur; 7101 goto skip_children; 7102 } 7103 if (href != NULL) 7104 xmlFree(href); 7105 if (base != NULL) 7106 xmlFree(base); 7107 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns); 7108 if (docu == NULL) { 7109 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE, 7110 "Failed to load externalRef %s\n", URL, 7111 NULL); 7112 if (ns != NULL) 7113 xmlFree(ns); 7114 xmlFree(URL); 7115 delete = cur; 7116 goto skip_children; 7117 } 7118 if (ns != NULL) 7119 xmlFree(ns); 7120 xmlFree(URL); 7121 cur->psvi = docu; 7122 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { 7123 xmlChar *href, *ns, *base, *URL; 7124 xmlRelaxNGIncludePtr incl; 7125 xmlNodePtr tmp; 7126 7127 href = xmlGetProp(cur, BAD_CAST "href"); 7128 if (href == NULL) { 7129 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7130 "xmlRelaxNGParse: include has no href attribute\n", 7131 NULL, NULL); 7132 delete = cur; 7133 goto skip_children; 7134 } 7135 base = xmlNodeGetBase(cur->doc, cur); 7136 URL = xmlBuildURI(href, base); 7137 if (URL == NULL) { 7138 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7139 "Failed to compute URL for include %s\n", 7140 href, NULL); 7141 if (href != NULL) 7142 xmlFree(href); 7143 if (base != NULL) 7144 xmlFree(base); 7145 delete = cur; 7146 goto skip_children; 7147 } 7148 if (href != NULL) 7149 xmlFree(href); 7150 if (base != NULL) 7151 xmlFree(base); 7152 ns = xmlGetProp(cur, BAD_CAST "ns"); 7153 if (ns == NULL) { 7154 tmp = cur->parent; 7155 while ((tmp != NULL) && 7156 (tmp->type == XML_ELEMENT_NODE)) { 7157 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7158 if (ns != NULL) 7159 break; 7160 tmp = tmp->parent; 7161 } 7162 } 7163 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns); 7164 if (ns != NULL) 7165 xmlFree(ns); 7166 if (incl == NULL) { 7167 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE, 7168 "Failed to load include %s\n", URL, 7169 NULL); 7170 xmlFree(URL); 7171 delete = cur; 7172 goto skip_children; 7173 } 7174 xmlFree(URL); 7175 cur->psvi = incl; 7176 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) || 7177 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) 7178 { 7179 xmlChar *name, *ns; 7180 xmlNodePtr text = NULL; 7181 7182 /* 7183 * Simplification 4.8. name attribute of element 7184 * and attribute elements 7185 */ 7186 name = xmlGetProp(cur, BAD_CAST "name"); 7187 if (name != NULL) { 7188 if (cur->children == NULL) { 7189 text = 7190 xmlNewChild(cur, cur->ns, BAD_CAST "name", 7191 name); 7192 } else { 7193 xmlNodePtr node; 7194 7195 node = xmlNewDocNode(cur->doc, cur->ns, 7196 BAD_CAST "name", NULL); 7197 if (node != NULL) { 7198 xmlAddPrevSibling(cur->children, node); 7199 text = xmlNewText(name); 7200 xmlAddChild(node, text); 7201 text = node; 7202 } 7203 } 7204 if (text == NULL) { 7205 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE, 7206 "Failed to create a name %s element\n", 7207 name, NULL); 7208 } 7209 xmlUnsetProp(cur, BAD_CAST "name"); 7210 xmlFree(name); 7211 ns = xmlGetProp(cur, BAD_CAST "ns"); 7212 if (ns != NULL) { 7213 if (text != NULL) { 7214 xmlSetProp(text, BAD_CAST "ns", ns); 7215 /* xmlUnsetProp(cur, BAD_CAST "ns"); */ 7216 } 7217 xmlFree(ns); 7218 } else if (xmlStrEqual(cur->name, 7219 BAD_CAST "attribute")) { 7220 xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); 7221 } 7222 } 7223 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) || 7224 (xmlStrEqual(cur->name, BAD_CAST "nsName")) || 7225 (xmlStrEqual(cur->name, BAD_CAST "value"))) { 7226 /* 7227 * Simplification 4.8. name attribute of element 7228 * and attribute elements 7229 */ 7230 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) { 7231 xmlNodePtr node; 7232 xmlChar *ns = NULL; 7233 7234 node = cur->parent; 7235 while ((node != NULL) && 7236 (node->type == XML_ELEMENT_NODE)) { 7237 ns = xmlGetProp(node, BAD_CAST "ns"); 7238 if (ns != NULL) { 7239 break; 7240 } 7241 node = node->parent; 7242 } 7243 if (ns == NULL) { 7244 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); 7245 } else { 7246 xmlSetProp(cur, BAD_CAST "ns", ns); 7247 xmlFree(ns); 7248 } 7249 } 7250 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 7251 xmlChar *name, *local, *prefix; 7252 7253 /* 7254 * Simplification: 4.10. QNames 7255 */ 7256 name = xmlNodeGetContent(cur); 7257 if (name != NULL) { 7258 local = xmlSplitQName2(name, &prefix); 7259 if (local != NULL) { 7260 xmlNsPtr ns; 7261 7262 ns = xmlSearchNs(cur->doc, cur, prefix); 7263 if (ns == NULL) { 7264 xmlRngPErr(ctxt, cur, 7265 XML_RNGP_PREFIX_UNDEFINED, 7266 "xmlRelaxNGParse: no namespace for prefix %s\n", 7267 prefix, NULL); 7268 } else { 7269 xmlSetProp(cur, BAD_CAST "ns", 7270 ns->href); 7271 xmlNodeSetContent(cur, local); 7272 } 7273 xmlFree(local); 7274 xmlFree(prefix); 7275 } 7276 xmlFree(name); 7277 } 7278 } 7279 /* 7280 * 4.16 7281 */ 7282 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) { 7283 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7284 xmlRngPErr(ctxt, cur, 7285 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, 7286 "Found nsName/except//nsName forbidden construct\n", 7287 NULL, NULL); 7288 } 7289 } 7290 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) && 7291 (cur != root)) { 7292 int oldflags = ctxt->flags; 7293 7294 /* 7295 * 4.16 7296 */ 7297 if ((cur->parent != NULL) && 7298 (xmlStrEqual 7299 (cur->parent->name, BAD_CAST "anyName"))) { 7300 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT; 7301 xmlRelaxNGCleanupTree(ctxt, cur); 7302 ctxt->flags = oldflags; 7303 goto skip_children; 7304 } else if ((cur->parent != NULL) && 7305 (xmlStrEqual 7306 (cur->parent->name, BAD_CAST "nsName"))) { 7307 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT; 7308 xmlRelaxNGCleanupTree(ctxt, cur); 7309 ctxt->flags = oldflags; 7310 goto skip_children; 7311 } 7312 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) { 7313 /* 7314 * 4.16 7315 */ 7316 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) { 7317 xmlRngPErr(ctxt, cur, 7318 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, 7319 "Found anyName/except//anyName forbidden construct\n", 7320 NULL, NULL); 7321 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7322 xmlRngPErr(ctxt, cur, 7323 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, 7324 "Found nsName/except//anyName forbidden construct\n", 7325 NULL, NULL); 7326 } 7327 } 7328 /* 7329 * This is not an else since "include" is transformed 7330 * into a div 7331 */ 7332 if (xmlStrEqual(cur->name, BAD_CAST "div")) { 7333 xmlChar *ns; 7334 xmlNodePtr child, ins, tmp; 7335 7336 /* 7337 * implements rule 4.11 7338 */ 7339 7340 ns = xmlGetProp(cur, BAD_CAST "ns"); 7341 7342 child = cur->children; 7343 ins = cur; 7344 while (child != NULL) { 7345 if (ns != NULL) { 7346 if (!xmlHasProp(child, BAD_CAST "ns")) { 7347 xmlSetProp(child, BAD_CAST "ns", ns); 7348 } 7349 } 7350 tmp = child->next; 7351 xmlUnlinkNode(child); 7352 ins = xmlAddNextSibling(ins, child); 7353 child = tmp; 7354 } 7355 if (ns != NULL) 7356 xmlFree(ns); 7357 /* 7358 * Since we are about to delete cur, if its nsDef is non-NULL we 7359 * need to preserve it (it contains the ns definitions for the 7360 * children we just moved). We'll just stick it on to the end 7361 * of cur->parent's list, since it's never going to be re-serialized 7362 * (bug 143738). 7363 */ 7364 if ((cur->nsDef != NULL) && (cur->parent != NULL)) { 7365 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef; 7366 while (parDef->next != NULL) 7367 parDef = parDef->next; 7368 parDef->next = cur->nsDef; 7369 cur->nsDef = NULL; 7370 } 7371 delete = cur; 7372 goto skip_children; 7373 } 7374 } 7375 } 7376 /* 7377 * Simplification 4.2 whitespaces 7378 */ 7379 else if ((cur->type == XML_TEXT_NODE) || 7380 (cur->type == XML_CDATA_SECTION_NODE)) { 7381 if (IS_BLANK_NODE(cur)) { 7382 if ((cur->parent != NULL) && 7383 (cur->parent->type == XML_ELEMENT_NODE)) { 7384 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) 7385 && 7386 (!xmlStrEqual 7387 (cur->parent->name, BAD_CAST "param"))) 7388 delete = cur; 7389 } else { 7390 delete = cur; 7391 goto skip_children; 7392 } 7393 } 7394 } else { 7395 delete = cur; 7396 goto skip_children; 7397 } 7398 7399 /* 7400 * Skip to next node 7401 */ 7402 if (cur->children != NULL) { 7403 if ((cur->children->type != XML_ENTITY_DECL) && 7404 (cur->children->type != XML_ENTITY_REF_NODE) && 7405 (cur->children->type != XML_ENTITY_NODE)) { 7406 cur = cur->children; 7407 continue; 7408 } 7409 } 7410 skip_children: 7411 if (cur->next != NULL) { 7412 cur = cur->next; 7413 continue; 7414 } 7415 7416 do { 7417 cur = cur->parent; 7418 if (cur == NULL) 7419 break; 7420 if (cur == root) { 7421 cur = NULL; 7422 break; 7423 } 7424 if (cur->next != NULL) { 7425 cur = cur->next; 7426 break; 7427 } 7428 } while (cur != NULL); 7429 } 7430 if (delete != NULL) { 7431 xmlUnlinkNode(delete); 7432 xmlFreeNode(delete); 7433 delete = NULL; 7434 } 7435 } 7436 7437 /** 7438 * xmlRelaxNGCleanupDoc: 7439 * @ctxt: a Relax-NG parser context 7440 * @doc: an xmldocPtr document pointer 7441 * 7442 * Cleanup the document from unwanted nodes for parsing, resolve 7443 * Include and externalRef lookups. 7444 * 7445 * Returns the cleaned up document or NULL in case of error 7446 */ 7447 static xmlDocPtr 7448 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) 7449 { 7450 xmlNodePtr root; 7451 7452 /* 7453 * Extract the root 7454 */ 7455 root = xmlDocGetRootElement(doc); 7456 if (root == NULL) { 7457 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7458 ctxt->URL, NULL); 7459 return (NULL); 7460 } 7461 xmlRelaxNGCleanupTree(ctxt, root); 7462 return (doc); 7463 } 7464 7465 /** 7466 * xmlRelaxNGParse: 7467 * @ctxt: a Relax-NG parser context 7468 * 7469 * parse a schema definition resource and build an internal 7470 * XML Shema struture which can be used to validate instances. 7471 * 7472 * Returns the internal XML RelaxNG structure built from the resource or 7473 * NULL in case of error 7474 */ 7475 xmlRelaxNGPtr 7476 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) 7477 { 7478 xmlRelaxNGPtr ret = NULL; 7479 xmlDocPtr doc; 7480 xmlNodePtr root; 7481 7482 xmlRelaxNGInitTypes(); 7483 7484 if (ctxt == NULL) 7485 return (NULL); 7486 7487 /* 7488 * First step is to parse the input document into an DOM/Infoset 7489 */ 7490 if (ctxt->URL != NULL) { 7491 doc = xmlReadFile((const char *) ctxt->URL,NULL,0); 7492 if (doc == NULL) { 7493 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7494 "xmlRelaxNGParse: could not load %s\n", ctxt->URL, 7495 NULL); 7496 return (NULL); 7497 } 7498 } else if (ctxt->buffer != NULL) { 7499 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); 7500 if (doc == NULL) { 7501 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7502 "xmlRelaxNGParse: could not parse schemas\n", NULL, 7503 NULL); 7504 return (NULL); 7505 } 7506 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7507 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7508 } else if (ctxt->document != NULL) { 7509 doc = ctxt->document; 7510 } else { 7511 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY, 7512 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL); 7513 return (NULL); 7514 } 7515 ctxt->document = doc; 7516 7517 /* 7518 * Some preprocessing of the document content 7519 */ 7520 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 7521 if (doc == NULL) { 7522 xmlFreeDoc(ctxt->document); 7523 ctxt->document = NULL; 7524 return (NULL); 7525 } 7526 7527 /* 7528 * Then do the parsing for good 7529 */ 7530 root = xmlDocGetRootElement(doc); 7531 if (root == NULL) { 7532 xmlRngPErr(ctxt, (xmlNodePtr) doc, 7533 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7534 (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL); 7535 7536 xmlFreeDoc(ctxt->document); 7537 ctxt->document = NULL; 7538 return (NULL); 7539 } 7540 ret = xmlRelaxNGParseDocument(ctxt, root); 7541 if (ret == NULL) { 7542 xmlFreeDoc(ctxt->document); 7543 ctxt->document = NULL; 7544 return (NULL); 7545 } 7546 7547 /* 7548 * Check the ref/defines links 7549 */ 7550 /* 7551 * try to preprocess interleaves 7552 */ 7553 if (ctxt->interleaves != NULL) { 7554 xmlHashScan(ctxt->interleaves, 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 /* Falls through. */ 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 = ((ptrdiff_t) 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 /* Falls through. */ 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