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