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