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