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