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