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