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