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 || states == 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 (res1 != (xmlSchemaValPtr) comp1) 2599 xmlSchemaFreeValue(res1); 2600 return (-1); 2601 } 2602 ret = xmlSchemaCompareValues(res1, res2); 2603 if (res1 != (xmlSchemaValPtr) comp1) 2604 xmlSchemaFreeValue(res1); 2605 xmlSchemaFreeValue(res2); 2606 if (ret == -2) 2607 return (-1); 2608 if (ret == 0) 2609 return (1); 2610 return (0); 2611} 2612 2613/** 2614 * xmlRelaxNGDefaultTypeHave: 2615 * @data: data needed for the library 2616 * @type: the type name 2617 * 2618 * Check if the given type is provided by 2619 * the default datatype library. 2620 * 2621 * Returns 1 if yes, 0 if no and -1 in case of error. 2622 */ 2623static int 2624xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, 2625 const xmlChar * type) 2626{ 2627 if (type == NULL) 2628 return (-1); 2629 if (xmlStrEqual(type, BAD_CAST "string")) 2630 return (1); 2631 if (xmlStrEqual(type, BAD_CAST "token")) 2632 return (1); 2633 return (0); 2634} 2635 2636/** 2637 * xmlRelaxNGDefaultTypeCheck: 2638 * @data: data needed for the library 2639 * @type: the type name 2640 * @value: the value to check 2641 * @node: the node 2642 * 2643 * Check if the given type and value are validated by 2644 * the default datatype library. 2645 * 2646 * Returns 1 if yes, 0 if no and -1 in case of error. 2647 */ 2648static int 2649xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, 2650 const xmlChar * type ATTRIBUTE_UNUSED, 2651 const xmlChar * value ATTRIBUTE_UNUSED, 2652 void **result ATTRIBUTE_UNUSED, 2653 xmlNodePtr node ATTRIBUTE_UNUSED) 2654{ 2655 if (value == NULL) 2656 return (-1); 2657 if (xmlStrEqual(type, BAD_CAST "string")) 2658 return (1); 2659 if (xmlStrEqual(type, BAD_CAST "token")) { 2660 return (1); 2661 } 2662 2663 return (0); 2664} 2665 2666/** 2667 * xmlRelaxNGDefaultTypeCompare: 2668 * @data: data needed for the library 2669 * @type: the type name 2670 * @value1: the first value 2671 * @value2: the second value 2672 * 2673 * Compare two values accordingly a type from the default 2674 * datatype library. 2675 * 2676 * Returns 1 if yes, 0 if no and -1 in case of error. 2677 */ 2678static int 2679xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, 2680 const xmlChar * type, 2681 const xmlChar * value1, 2682 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED, 2683 void *comp1 ATTRIBUTE_UNUSED, 2684 const xmlChar * value2, 2685 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) 2686{ 2687 int ret = -1; 2688 2689 if (xmlStrEqual(type, BAD_CAST "string")) { 2690 ret = xmlStrEqual(value1, value2); 2691 } else if (xmlStrEqual(type, BAD_CAST "token")) { 2692 if (!xmlStrEqual(value1, value2)) { 2693 xmlChar *nval, *nvalue; 2694 2695 /* 2696 * TODO: trivial optimizations are possible by 2697 * computing at compile-time 2698 */ 2699 nval = xmlRelaxNGNormalize(NULL, value1); 2700 nvalue = xmlRelaxNGNormalize(NULL, value2); 2701 2702 if ((nval == NULL) || (nvalue == NULL)) 2703 ret = -1; 2704 else if (xmlStrEqual(nval, nvalue)) 2705 ret = 1; 2706 else 2707 ret = 0; 2708 if (nval != NULL) 2709 xmlFree(nval); 2710 if (nvalue != NULL) 2711 xmlFree(nvalue); 2712 } else 2713 ret = 1; 2714 } 2715 return (ret); 2716} 2717 2718static int xmlRelaxNGTypeInitialized = 0; 2719static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; 2720 2721/** 2722 * xmlRelaxNGFreeTypeLibrary: 2723 * @lib: the type library structure 2724 * @namespace: the URI bound to the library 2725 * 2726 * Free the structure associated to the type library 2727 */ 2728static void 2729xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib, 2730 const xmlChar * namespace ATTRIBUTE_UNUSED) 2731{ 2732 if (lib == NULL) 2733 return; 2734 if (lib->namespace != NULL) 2735 xmlFree((xmlChar *) lib->namespace); 2736 xmlFree(lib); 2737} 2738 2739/** 2740 * xmlRelaxNGRegisterTypeLibrary: 2741 * @namespace: the URI bound to the library 2742 * @data: data associated to the library 2743 * @have: the provide function 2744 * @check: the checking function 2745 * @comp: the comparison function 2746 * 2747 * Register a new type library 2748 * 2749 * Returns 0 in case of success and -1 in case of error. 2750 */ 2751static int 2752xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, 2753 xmlRelaxNGTypeHave have, 2754 xmlRelaxNGTypeCheck check, 2755 xmlRelaxNGTypeCompare comp, 2756 xmlRelaxNGFacetCheck facet, 2757 xmlRelaxNGTypeFree freef) 2758{ 2759 xmlRelaxNGTypeLibraryPtr lib; 2760 int ret; 2761 2762 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || 2763 (check == NULL) || (comp == NULL)) 2764 return (-1); 2765 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { 2766 xmlGenericError(xmlGenericErrorContext, 2767 "Relax-NG types library '%s' already registered\n", 2768 namespace); 2769 return (-1); 2770 } 2771 lib = 2772 (xmlRelaxNGTypeLibraryPtr) 2773 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); 2774 if (lib == NULL) { 2775 xmlRngVErrMemory(NULL, "adding types library\n"); 2776 return (-1); 2777 } 2778 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); 2779 lib->namespace = xmlStrdup(namespace); 2780 lib->data = data; 2781 lib->have = have; 2782 lib->comp = comp; 2783 lib->check = check; 2784 lib->facet = facet; 2785 lib->freef = freef; 2786 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); 2787 if (ret < 0) { 2788 xmlGenericError(xmlGenericErrorContext, 2789 "Relax-NG types library failed to register '%s'\n", 2790 namespace); 2791 xmlRelaxNGFreeTypeLibrary(lib, namespace); 2792 return (-1); 2793 } 2794 return (0); 2795} 2796 2797/** 2798 * xmlRelaxNGInitTypes: 2799 * 2800 * Initilize the default type libraries. 2801 * 2802 * Returns 0 in case of success and -1 in case of error. 2803 */ 2804int 2805xmlRelaxNGInitTypes(void) 2806{ 2807 if (xmlRelaxNGTypeInitialized != 0) 2808 return (0); 2809 xmlRelaxNGRegisteredTypes = xmlHashCreate(10); 2810 if (xmlRelaxNGRegisteredTypes == NULL) { 2811 xmlGenericError(xmlGenericErrorContext, 2812 "Failed to allocate sh table for Relax-NG types\n"); 2813 return (-1); 2814 } 2815 xmlRelaxNGRegisterTypeLibrary(BAD_CAST 2816 "http://www.w3.org/2001/XMLSchema-datatypes", 2817 NULL, xmlRelaxNGSchemaTypeHave, 2818 xmlRelaxNGSchemaTypeCheck, 2819 xmlRelaxNGSchemaTypeCompare, 2820 xmlRelaxNGSchemaFacetCheck, 2821 xmlRelaxNGSchemaFreeValue); 2822 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL, 2823 xmlRelaxNGDefaultTypeHave, 2824 xmlRelaxNGDefaultTypeCheck, 2825 xmlRelaxNGDefaultTypeCompare, NULL, 2826 NULL); 2827 xmlRelaxNGTypeInitialized = 1; 2828 return (0); 2829} 2830 2831/** 2832 * xmlRelaxNGCleanupTypes: 2833 * 2834 * Cleanup the default Schemas type library associated to RelaxNG 2835 */ 2836void 2837xmlRelaxNGCleanupTypes(void) 2838{ 2839 xmlSchemaCleanupTypes(); 2840 if (xmlRelaxNGTypeInitialized == 0) 2841 return; 2842 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator) 2843 xmlRelaxNGFreeTypeLibrary); 2844 xmlRelaxNGTypeInitialized = 0; 2845} 2846 2847/************************************************************************ 2848 * * 2849 * Compiling element content into regexp * 2850 * * 2851 * Sometime the element content can be compiled into a pure regexp, * 2852 * This allows a faster execution and streamability at that level * 2853 * * 2854 ************************************************************************/ 2855 2856/* from automata.c but not exported */ 2857void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); 2858 2859 2860static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, 2861 xmlRelaxNGDefinePtr def); 2862 2863/** 2864 * xmlRelaxNGIsCompileable: 2865 * @define: the definition to check 2866 * 2867 * Check if a definition is nullable. 2868 * 2869 * Returns 1 if yes, 0 if no and -1 in case of error 2870 */ 2871static int 2872xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) 2873{ 2874 int ret = -1; 2875 2876 if (def == NULL) { 2877 return (-1); 2878 } 2879 if ((def->type != XML_RELAXNG_ELEMENT) && 2880 (def->dflags & IS_COMPILABLE)) 2881 return (1); 2882 if ((def->type != XML_RELAXNG_ELEMENT) && 2883 (def->dflags & IS_NOT_COMPILABLE)) 2884 return (0); 2885 switch (def->type) { 2886 case XML_RELAXNG_NOOP: 2887 ret = xmlRelaxNGIsCompileable(def->content); 2888 break; 2889 case XML_RELAXNG_TEXT: 2890 case XML_RELAXNG_EMPTY: 2891 ret = 1; 2892 break; 2893 case XML_RELAXNG_ELEMENT: 2894 /* 2895 * Check if the element content is compileable 2896 */ 2897 if (((def->dflags & IS_NOT_COMPILABLE) == 0) && 2898 ((def->dflags & IS_COMPILABLE) == 0)) { 2899 xmlRelaxNGDefinePtr list; 2900 2901 list = def->content; 2902 while (list != NULL) { 2903 ret = xmlRelaxNGIsCompileable(list); 2904 if (ret != 1) 2905 break; 2906 list = list->next; 2907 } 2908 /* 2909 * Because the routine is recursive, we must guard against 2910 * discovering both COMPILABLE and NOT_COMPILABLE 2911 */ 2912 if (ret == 0) { 2913 def->dflags &= ~IS_COMPILABLE; 2914 def->dflags |= IS_NOT_COMPILABLE; 2915 } 2916 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) 2917 def->dflags |= IS_COMPILABLE; 2918#ifdef DEBUG_COMPILE 2919 if (ret == 1) { 2920 xmlGenericError(xmlGenericErrorContext, 2921 "element content for %s is compilable\n", 2922 def->name); 2923 } else if (ret == 0) { 2924 xmlGenericError(xmlGenericErrorContext, 2925 "element content for %s is not compilable\n", 2926 def->name); 2927 } else { 2928 xmlGenericError(xmlGenericErrorContext, 2929 "Problem in RelaxNGIsCompileable for element %s\n", 2930 def->name); 2931 } 2932#endif 2933 } 2934 /* 2935 * All elements return a compileable status unless they 2936 * are generic like anyName 2937 */ 2938 if ((def->nameClass != NULL) || (def->name == NULL)) 2939 ret = 0; 2940 else 2941 ret = 1; 2942 return (ret); 2943 case XML_RELAXNG_REF: 2944 case XML_RELAXNG_EXTERNALREF: 2945 case XML_RELAXNG_PARENTREF: 2946 if (def->depth == -20) { 2947 return (1); 2948 } else { 2949 xmlRelaxNGDefinePtr list; 2950 2951 def->depth = -20; 2952 list = def->content; 2953 while (list != NULL) { 2954 ret = xmlRelaxNGIsCompileable(list); 2955 if (ret != 1) 2956 break; 2957 list = list->next; 2958 } 2959 } 2960 break; 2961 case XML_RELAXNG_START: 2962 case XML_RELAXNG_OPTIONAL: 2963 case XML_RELAXNG_ZEROORMORE: 2964 case XML_RELAXNG_ONEORMORE: 2965 case XML_RELAXNG_CHOICE: 2966 case XML_RELAXNG_GROUP: 2967 case XML_RELAXNG_DEF:{ 2968 xmlRelaxNGDefinePtr list; 2969 2970 list = def->content; 2971 while (list != NULL) { 2972 ret = xmlRelaxNGIsCompileable(list); 2973 if (ret != 1) 2974 break; 2975 list = list->next; 2976 } 2977 break; 2978 } 2979 case XML_RELAXNG_EXCEPT: 2980 case XML_RELAXNG_ATTRIBUTE: 2981 case XML_RELAXNG_INTERLEAVE: 2982 case XML_RELAXNG_DATATYPE: 2983 case XML_RELAXNG_LIST: 2984 case XML_RELAXNG_PARAM: 2985 case XML_RELAXNG_VALUE: 2986 case XML_RELAXNG_NOT_ALLOWED: 2987 ret = 0; 2988 break; 2989 } 2990 if (ret == 0) 2991 def->dflags |= IS_NOT_COMPILABLE; 2992 if (ret == 1) 2993 def->dflags |= IS_COMPILABLE; 2994#ifdef DEBUG_COMPILE 2995 if (ret == 1) { 2996 xmlGenericError(xmlGenericErrorContext, 2997 "RelaxNGIsCompileable %s : true\n", 2998 xmlRelaxNGDefName(def)); 2999 } else if (ret == 0) { 3000 xmlGenericError(xmlGenericErrorContext, 3001 "RelaxNGIsCompileable %s : false\n", 3002 xmlRelaxNGDefName(def)); 3003 } else { 3004 xmlGenericError(xmlGenericErrorContext, 3005 "Problem in RelaxNGIsCompileable %s\n", 3006 xmlRelaxNGDefName(def)); 3007 } 3008#endif 3009 return (ret); 3010} 3011 3012/** 3013 * xmlRelaxNGCompile: 3014 * ctxt: the RelaxNG parser context 3015 * @define: the definition tree to compile 3016 * 3017 * Compile the set of definitions, it works recursively, till the 3018 * element boundaries, where it tries to compile the content if possible 3019 * 3020 * Returns 0 if success and -1 in case of error 3021 */ 3022static int 3023xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3024{ 3025 int ret = 0; 3026 xmlRelaxNGDefinePtr list; 3027 3028 if ((ctxt == NULL) || (def == NULL)) 3029 return (-1); 3030 3031 switch (def->type) { 3032 case XML_RELAXNG_START: 3033 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) { 3034 xmlAutomataPtr oldam = ctxt->am; 3035 xmlAutomataStatePtr oldstate = ctxt->state; 3036 3037 def->depth = -25; 3038 3039 list = def->content; 3040 ctxt->am = xmlNewAutomata(); 3041 if (ctxt->am == NULL) 3042 return (-1); 3043 3044 /* 3045 * assume identical strings but not same pointer are different 3046 * atoms, needed for non-determinism detection 3047 * That way if 2 elements with the same name are in a choice 3048 * branch the automata is found non-deterministic and 3049 * we fallback to the normal validation which does the right 3050 * thing of exploring both choices. 3051 */ 3052 xmlAutomataSetFlags(ctxt->am, 1); 3053 3054 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3055 while (list != NULL) { 3056 xmlRelaxNGCompile(ctxt, list); 3057 list = list->next; 3058 } 3059 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3060 if (xmlAutomataIsDeterminist(ctxt->am)) 3061 def->contModel = xmlAutomataCompile(ctxt->am); 3062 3063 xmlFreeAutomata(ctxt->am); 3064 ctxt->state = oldstate; 3065 ctxt->am = oldam; 3066 } 3067 break; 3068 case XML_RELAXNG_ELEMENT: 3069 if ((ctxt->am != NULL) && (def->name != NULL)) { 3070 ctxt->state = xmlAutomataNewTransition2(ctxt->am, 3071 ctxt->state, NULL, 3072 def->name, def->ns, 3073 def); 3074 } 3075 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3076 xmlAutomataPtr oldam = ctxt->am; 3077 xmlAutomataStatePtr oldstate = ctxt->state; 3078 3079 def->depth = -25; 3080 3081 list = def->content; 3082 ctxt->am = xmlNewAutomata(); 3083 if (ctxt->am == NULL) 3084 return (-1); 3085 xmlAutomataSetFlags(ctxt->am, 1); 3086 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3087 while (list != NULL) { 3088 xmlRelaxNGCompile(ctxt, list); 3089 list = list->next; 3090 } 3091 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3092 def->contModel = xmlAutomataCompile(ctxt->am); 3093 if (!xmlRegexpIsDeterminist(def->contModel)) { 3094#ifdef DEBUG_COMPILE 3095 xmlGenericError(xmlGenericErrorContext, 3096 "Content model not determinist %s\n", 3097 def->name); 3098#endif 3099 /* 3100 * we can only use the automata if it is determinist 3101 */ 3102 xmlRegFreeRegexp(def->contModel); 3103 def->contModel = NULL; 3104 } 3105 xmlFreeAutomata(ctxt->am); 3106 ctxt->state = oldstate; 3107 ctxt->am = oldam; 3108 } else { 3109 xmlAutomataPtr oldam = ctxt->am; 3110 3111 /* 3112 * we can't build the content model for this element content 3113 * but it still might be possible to build it for some of its 3114 * children, recurse. 3115 */ 3116 ret = xmlRelaxNGTryCompile(ctxt, def); 3117 ctxt->am = oldam; 3118 } 3119 break; 3120 case XML_RELAXNG_NOOP: 3121 ret = xmlRelaxNGCompile(ctxt, def->content); 3122 break; 3123 case XML_RELAXNG_OPTIONAL:{ 3124 xmlAutomataStatePtr oldstate = ctxt->state; 3125 3126 list = def->content; 3127 while (list != NULL) { 3128 xmlRelaxNGCompile(ctxt, list); 3129 list = list->next; 3130 } 3131 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 3132 break; 3133 } 3134 case XML_RELAXNG_ZEROORMORE:{ 3135 xmlAutomataStatePtr oldstate; 3136 3137 ctxt->state = 3138 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3139 oldstate = ctxt->state; 3140 list = def->content; 3141 while (list != NULL) { 3142 xmlRelaxNGCompile(ctxt, list); 3143 list = list->next; 3144 } 3145 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3146 ctxt->state = 3147 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3148 break; 3149 } 3150 case XML_RELAXNG_ONEORMORE:{ 3151 xmlAutomataStatePtr oldstate; 3152 3153 list = def->content; 3154 while (list != NULL) { 3155 xmlRelaxNGCompile(ctxt, list); 3156 list = list->next; 3157 } 3158 oldstate = ctxt->state; 3159 list = def->content; 3160 while (list != NULL) { 3161 xmlRelaxNGCompile(ctxt, list); 3162 list = list->next; 3163 } 3164 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3165 ctxt->state = 3166 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3167 break; 3168 } 3169 case XML_RELAXNG_CHOICE:{ 3170 xmlAutomataStatePtr target = NULL; 3171 xmlAutomataStatePtr oldstate = ctxt->state; 3172 3173 list = def->content; 3174 while (list != NULL) { 3175 ctxt->state = oldstate; 3176 ret = xmlRelaxNGCompile(ctxt, list); 3177 if (ret != 0) 3178 break; 3179 if (target == NULL) 3180 target = ctxt->state; 3181 else { 3182 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, 3183 target); 3184 } 3185 list = list->next; 3186 } 3187 ctxt->state = target; 3188 3189 break; 3190 } 3191 case XML_RELAXNG_REF: 3192 case XML_RELAXNG_EXTERNALREF: 3193 case XML_RELAXNG_PARENTREF: 3194 case XML_RELAXNG_GROUP: 3195 case XML_RELAXNG_DEF: 3196 list = def->content; 3197 while (list != NULL) { 3198 ret = xmlRelaxNGCompile(ctxt, list); 3199 if (ret != 0) 3200 break; 3201 list = list->next; 3202 } 3203 break; 3204 case XML_RELAXNG_TEXT:{ 3205 xmlAutomataStatePtr oldstate; 3206 3207 ctxt->state = 3208 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3209 oldstate = ctxt->state; 3210 xmlRelaxNGCompile(ctxt, def->content); 3211 xmlAutomataNewTransition(ctxt->am, ctxt->state, 3212 ctxt->state, BAD_CAST "#text", 3213 NULL); 3214 ctxt->state = 3215 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3216 break; 3217 } 3218 case XML_RELAXNG_EMPTY: 3219 ctxt->state = 3220 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3221 break; 3222 case XML_RELAXNG_EXCEPT: 3223 case XML_RELAXNG_ATTRIBUTE: 3224 case XML_RELAXNG_INTERLEAVE: 3225 case XML_RELAXNG_NOT_ALLOWED: 3226 case XML_RELAXNG_DATATYPE: 3227 case XML_RELAXNG_LIST: 3228 case XML_RELAXNG_PARAM: 3229 case XML_RELAXNG_VALUE: 3230 /* This should not happen and generate an internal error */ 3231 fprintf(stderr, "RNG internal error trying to compile %s\n", 3232 xmlRelaxNGDefName(def)); 3233 break; 3234 } 3235 return (ret); 3236} 3237 3238/** 3239 * xmlRelaxNGTryCompile: 3240 * ctxt: the RelaxNG parser context 3241 * @define: the definition tree to compile 3242 * 3243 * Try to compile the set of definitions, it works recursively, 3244 * possibly ignoring parts which cannot be compiled. 3245 * 3246 * Returns 0 if success and -1 in case of error 3247 */ 3248static int 3249xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3250{ 3251 int ret = 0; 3252 xmlRelaxNGDefinePtr list; 3253 3254 if ((ctxt == NULL) || (def == NULL)) 3255 return (-1); 3256 3257 if ((def->type == XML_RELAXNG_START) || 3258 (def->type == XML_RELAXNG_ELEMENT)) { 3259 ret = xmlRelaxNGIsCompileable(def); 3260 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3261 ctxt->am = NULL; 3262 ret = xmlRelaxNGCompile(ctxt, def); 3263#ifdef DEBUG_PROGRESSIVE 3264 if (ret == 0) { 3265 if (def->type == XML_RELAXNG_START) 3266 xmlGenericError(xmlGenericErrorContext, 3267 "compiled the start\n"); 3268 else 3269 xmlGenericError(xmlGenericErrorContext, 3270 "compiled element %s\n", def->name); 3271 } else { 3272 if (def->type == XML_RELAXNG_START) 3273 xmlGenericError(xmlGenericErrorContext, 3274 "failed to compile the start\n"); 3275 else 3276 xmlGenericError(xmlGenericErrorContext, 3277 "failed to compile element %s\n", 3278 def->name); 3279 } 3280#endif 3281 return (ret); 3282 } 3283 } 3284 switch (def->type) { 3285 case XML_RELAXNG_NOOP: 3286 ret = xmlRelaxNGTryCompile(ctxt, def->content); 3287 break; 3288 case XML_RELAXNG_TEXT: 3289 case XML_RELAXNG_DATATYPE: 3290 case XML_RELAXNG_LIST: 3291 case XML_RELAXNG_PARAM: 3292 case XML_RELAXNG_VALUE: 3293 case XML_RELAXNG_EMPTY: 3294 case XML_RELAXNG_ELEMENT: 3295 ret = 0; 3296 break; 3297 case XML_RELAXNG_OPTIONAL: 3298 case XML_RELAXNG_ZEROORMORE: 3299 case XML_RELAXNG_ONEORMORE: 3300 case XML_RELAXNG_CHOICE: 3301 case XML_RELAXNG_GROUP: 3302 case XML_RELAXNG_DEF: 3303 case XML_RELAXNG_START: 3304 case XML_RELAXNG_REF: 3305 case XML_RELAXNG_EXTERNALREF: 3306 case XML_RELAXNG_PARENTREF: 3307 list = def->content; 3308 while (list != NULL) { 3309 ret = xmlRelaxNGTryCompile(ctxt, list); 3310 if (ret != 0) 3311 break; 3312 list = list->next; 3313 } 3314 break; 3315 case XML_RELAXNG_EXCEPT: 3316 case XML_RELAXNG_ATTRIBUTE: 3317 case XML_RELAXNG_INTERLEAVE: 3318 case XML_RELAXNG_NOT_ALLOWED: 3319 ret = 0; 3320 break; 3321 } 3322 return (ret); 3323} 3324 3325/************************************************************************ 3326 * * 3327 * Parsing functions * 3328 * * 3329 ************************************************************************/ 3330 3331static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr 3332 ctxt, xmlNodePtr node); 3333static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr 3334 ctxt, xmlNodePtr node); 3335static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr 3336 ctxt, xmlNodePtr nodes, 3337 int group); 3338static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr 3339 ctxt, xmlNodePtr node); 3340static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, 3341 xmlNodePtr node); 3342static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 3343 xmlNodePtr nodes); 3344static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr 3345 ctxt, xmlNodePtr node, 3346 xmlRelaxNGDefinePtr 3347 def); 3348static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr 3349 ctxt, xmlNodePtr nodes); 3350static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 3351 xmlRelaxNGDefinePtr define, 3352 xmlNodePtr elem); 3353 3354 3355#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) 3356 3357/** 3358 * xmlRelaxNGIsNullable: 3359 * @define: the definition to verify 3360 * 3361 * Check if a definition is nullable. 3362 * 3363 * Returns 1 if yes, 0 if no and -1 in case of error 3364 */ 3365static int 3366xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) 3367{ 3368 int ret; 3369 3370 if (define == NULL) 3371 return (-1); 3372 3373 if (define->dflags & IS_NULLABLE) 3374 return (1); 3375 if (define->dflags & IS_NOT_NULLABLE) 3376 return (0); 3377 switch (define->type) { 3378 case XML_RELAXNG_EMPTY: 3379 case XML_RELAXNG_TEXT: 3380 ret = 1; 3381 break; 3382 case XML_RELAXNG_NOOP: 3383 case XML_RELAXNG_DEF: 3384 case XML_RELAXNG_REF: 3385 case XML_RELAXNG_EXTERNALREF: 3386 case XML_RELAXNG_PARENTREF: 3387 case XML_RELAXNG_ONEORMORE: 3388 ret = xmlRelaxNGIsNullable(define->content); 3389 break; 3390 case XML_RELAXNG_EXCEPT: 3391 case XML_RELAXNG_NOT_ALLOWED: 3392 case XML_RELAXNG_ELEMENT: 3393 case XML_RELAXNG_DATATYPE: 3394 case XML_RELAXNG_PARAM: 3395 case XML_RELAXNG_VALUE: 3396 case XML_RELAXNG_LIST: 3397 case XML_RELAXNG_ATTRIBUTE: 3398 ret = 0; 3399 break; 3400 case XML_RELAXNG_CHOICE:{ 3401 xmlRelaxNGDefinePtr list = define->content; 3402 3403 while (list != NULL) { 3404 ret = xmlRelaxNGIsNullable(list); 3405 if (ret != 0) 3406 goto done; 3407 list = list->next; 3408 } 3409 ret = 0; 3410 break; 3411 } 3412 case XML_RELAXNG_START: 3413 case XML_RELAXNG_INTERLEAVE: 3414 case XML_RELAXNG_GROUP:{ 3415 xmlRelaxNGDefinePtr list = define->content; 3416 3417 while (list != NULL) { 3418 ret = xmlRelaxNGIsNullable(list); 3419 if (ret != 1) 3420 goto done; 3421 list = list->next; 3422 } 3423 return (1); 3424 } 3425 default: 3426 return (-1); 3427 } 3428 done: 3429 if (ret == 0) 3430 define->dflags |= IS_NOT_NULLABLE; 3431 if (ret == 1) 3432 define->dflags |= IS_NULLABLE; 3433 return (ret); 3434} 3435 3436/** 3437 * xmlRelaxNGIsBlank: 3438 * @str: a string 3439 * 3440 * Check if a string is ignorable c.f. 4.2. Whitespace 3441 * 3442 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise 3443 */ 3444static int 3445xmlRelaxNGIsBlank(xmlChar * str) 3446{ 3447 if (str == NULL) 3448 return (1); 3449 while (*str != 0) { 3450 if (!(IS_BLANK_CH(*str))) 3451 return (0); 3452 str++; 3453 } 3454 return (1); 3455} 3456 3457/** 3458 * xmlRelaxNGGetDataTypeLibrary: 3459 * @ctxt: a Relax-NG parser context 3460 * @node: the current data or value element 3461 * 3462 * Applies algorithm from 4.3. datatypeLibrary attribute 3463 * 3464 * Returns the datatypeLibary value or NULL if not found 3465 */ 3466static xmlChar * 3467xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 3468 xmlNodePtr node) 3469{ 3470 xmlChar *ret, *escape; 3471 3472 if (node == NULL) 3473 return(NULL); 3474 3475 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { 3476 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3477 if (ret != NULL) { 3478 if (ret[0] == 0) { 3479 xmlFree(ret); 3480 return (NULL); 3481 } 3482 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3483 if (escape == NULL) { 3484 return (ret); 3485 } 3486 xmlFree(ret); 3487 return (escape); 3488 } 3489 } 3490 node = node->parent; 3491 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { 3492 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3493 if (ret != NULL) { 3494 if (ret[0] == 0) { 3495 xmlFree(ret); 3496 return (NULL); 3497 } 3498 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3499 if (escape == NULL) { 3500 return (ret); 3501 } 3502 xmlFree(ret); 3503 return (escape); 3504 } 3505 node = node->parent; 3506 } 3507 return (NULL); 3508} 3509 3510/** 3511 * xmlRelaxNGParseValue: 3512 * @ctxt: a Relax-NG parser context 3513 * @node: the data node. 3514 * 3515 * parse the content of a RelaxNG value node. 3516 * 3517 * Returns the definition pointer or NULL in case of error 3518 */ 3519static xmlRelaxNGDefinePtr 3520xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3521{ 3522 xmlRelaxNGDefinePtr def = NULL; 3523 xmlRelaxNGTypeLibraryPtr lib = NULL; 3524 xmlChar *type; 3525 xmlChar *library; 3526 int success = 0; 3527 3528 def = xmlRelaxNGNewDefine(ctxt, node); 3529 if (def == NULL) 3530 return (NULL); 3531 def->type = XML_RELAXNG_VALUE; 3532 3533 type = xmlGetProp(node, BAD_CAST "type"); 3534 if (type != NULL) { 3535 xmlRelaxNGNormExtSpace(type); 3536 if (xmlValidateNCName(type, 0)) { 3537 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3538 "value type '%s' is not an NCName\n", type, NULL); 3539 } 3540 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3541 if (library == NULL) 3542 library = 3543 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3544 3545 def->name = type; 3546 def->ns = library; 3547 3548 lib = (xmlRelaxNGTypeLibraryPtr) 3549 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3550 if (lib == NULL) { 3551 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3552 "Use of unregistered type library '%s'\n", library, 3553 NULL); 3554 def->data = NULL; 3555 } else { 3556 def->data = lib; 3557 if (lib->have == NULL) { 3558 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3559 "Internal error with type library '%s': no 'have'\n", 3560 library, NULL); 3561 } else { 3562 success = lib->have(lib->data, def->name); 3563 if (success != 1) { 3564 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3565 "Error type '%s' is not exported by type library '%s'\n", 3566 def->name, library); 3567 } 3568 } 3569 } 3570 } 3571 if (node->children == NULL) { 3572 def->value = xmlStrdup(BAD_CAST ""); 3573 } else if (((node->children->type != XML_TEXT_NODE) && 3574 (node->children->type != XML_CDATA_SECTION_NODE)) || 3575 (node->children->next != NULL)) { 3576 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, 3577 "Expecting a single text value for <value>content\n", 3578 NULL, NULL); 3579 } else if (def != NULL) { 3580 def->value = xmlNodeGetContent(node); 3581 if (def->value == NULL) { 3582 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, 3583 "Element <value> has no content\n", NULL, NULL); 3584 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { 3585 void *val = NULL; 3586 3587 success = 3588 lib->check(lib->data, def->name, def->value, &val, node); 3589 if (success != 1) { 3590 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, 3591 "Value '%s' is not acceptable for type '%s'\n", 3592 def->value, def->name); 3593 } else { 3594 if (val != NULL) 3595 def->attrs = val; 3596 } 3597 } 3598 } 3599 return (def); 3600} 3601 3602/** 3603 * xmlRelaxNGParseData: 3604 * @ctxt: a Relax-NG parser context 3605 * @node: the data node. 3606 * 3607 * parse the content of a RelaxNG data node. 3608 * 3609 * Returns the definition pointer or NULL in case of error 3610 */ 3611static xmlRelaxNGDefinePtr 3612xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3613{ 3614 xmlRelaxNGDefinePtr def = NULL, except; 3615 xmlRelaxNGDefinePtr param, lastparam = NULL; 3616 xmlRelaxNGTypeLibraryPtr lib; 3617 xmlChar *type; 3618 xmlChar *library; 3619 xmlNodePtr content; 3620 int tmp; 3621 3622 type = xmlGetProp(node, BAD_CAST "type"); 3623 if (type == NULL) { 3624 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, 3625 NULL); 3626 return (NULL); 3627 } 3628 xmlRelaxNGNormExtSpace(type); 3629 if (xmlValidateNCName(type, 0)) { 3630 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3631 "data type '%s' is not an NCName\n", type, NULL); 3632 } 3633 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3634 if (library == NULL) 3635 library = 3636 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3637 3638 def = xmlRelaxNGNewDefine(ctxt, node); 3639 if (def == NULL) { 3640 xmlFree(type); 3641 return (NULL); 3642 } 3643 def->type = XML_RELAXNG_DATATYPE; 3644 def->name = type; 3645 def->ns = library; 3646 3647 lib = (xmlRelaxNGTypeLibraryPtr) 3648 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3649 if (lib == NULL) { 3650 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3651 "Use of unregistered type library '%s'\n", library, 3652 NULL); 3653 def->data = NULL; 3654 } else { 3655 def->data = lib; 3656 if (lib->have == NULL) { 3657 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3658 "Internal error with type library '%s': no 'have'\n", 3659 library, NULL); 3660 } else { 3661 tmp = lib->have(lib->data, def->name); 3662 if (tmp != 1) { 3663 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3664 "Error type '%s' is not exported by type library '%s'\n", 3665 def->name, library); 3666 } else 3667 if ((xmlStrEqual 3668 (library, 3669 BAD_CAST 3670 "http://www.w3.org/2001/XMLSchema-datatypes")) 3671 && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) 3672 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { 3673 ctxt->idref = 1; 3674 } 3675 } 3676 } 3677 content = node->children; 3678 3679 /* 3680 * Handle optional params 3681 */ 3682 while (content != NULL) { 3683 if (!xmlStrEqual(content->name, BAD_CAST "param")) 3684 break; 3685 if (xmlStrEqual(library, 3686 BAD_CAST "http://relaxng.org/ns/structure/1.0")) { 3687 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, 3688 "Type library '%s' does not allow type parameters\n", 3689 library, NULL); 3690 content = content->next; 3691 while ((content != NULL) && 3692 (xmlStrEqual(content->name, BAD_CAST "param"))) 3693 content = content->next; 3694 } else { 3695 param = xmlRelaxNGNewDefine(ctxt, node); 3696 if (param != NULL) { 3697 param->type = XML_RELAXNG_PARAM; 3698 param->name = xmlGetProp(content, BAD_CAST "name"); 3699 if (param->name == NULL) { 3700 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, 3701 "param has no name\n", NULL, NULL); 3702 } 3703 param->value = xmlNodeGetContent(content); 3704 if (lastparam == NULL) { 3705 def->attrs = lastparam = param; 3706 } else { 3707 lastparam->next = param; 3708 lastparam = param; 3709 } 3710 if (lib != NULL) { 3711 } 3712 } 3713 content = content->next; 3714 } 3715 } 3716 /* 3717 * Handle optional except 3718 */ 3719 if ((content != NULL) 3720 && (xmlStrEqual(content->name, BAD_CAST "except"))) { 3721 xmlNodePtr child; 3722 xmlRelaxNGDefinePtr tmp2, last = NULL; 3723 3724 except = xmlRelaxNGNewDefine(ctxt, node); 3725 if (except == NULL) { 3726 return (def); 3727 } 3728 except->type = XML_RELAXNG_EXCEPT; 3729 child = content->children; 3730 def->content = except; 3731 if (child == NULL) { 3732 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, 3733 "except has no content\n", NULL, NULL); 3734 } 3735 while (child != NULL) { 3736 tmp2 = xmlRelaxNGParsePattern(ctxt, child); 3737 if (tmp2 != NULL) { 3738 if (last == NULL) { 3739 except->content = last = tmp2; 3740 } else { 3741 last->next = tmp2; 3742 last = tmp2; 3743 } 3744 } 3745 child = child->next; 3746 } 3747 content = content->next; 3748 } 3749 /* 3750 * Check there is no unhandled data 3751 */ 3752 if (content != NULL) { 3753 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, 3754 "Element data has unexpected content %s\n", 3755 content->name, NULL); 3756 } 3757 3758 return (def); 3759} 3760 3761static const xmlChar *invalidName = BAD_CAST "\1"; 3762 3763/** 3764 * xmlRelaxNGCompareNameClasses: 3765 * @defs1: the first element/attribute defs 3766 * @defs2: the second element/attribute defs 3767 * @name: the restriction on the name 3768 * @ns: the restriction on the namespace 3769 * 3770 * Compare the 2 lists of element definitions. The comparison is 3771 * that if both lists do not accept the same QNames, it returns 1 3772 * If the 2 lists can accept the same QName the comparison returns 0 3773 * 3774 * Returns 1 disttinct, 0 if equal 3775 */ 3776static int 3777xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, 3778 xmlRelaxNGDefinePtr def2) 3779{ 3780 int ret = 1; 3781 xmlNode node; 3782 xmlNs ns; 3783 xmlRelaxNGValidCtxt ctxt; 3784 3785 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); 3786 3787 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; 3788 3789 if ((def1->type == XML_RELAXNG_ELEMENT) || 3790 (def1->type == XML_RELAXNG_ATTRIBUTE)) { 3791 if (def2->type == XML_RELAXNG_TEXT) 3792 return (1); 3793 if (def1->name != NULL) { 3794 node.name = def1->name; 3795 } else { 3796 node.name = invalidName; 3797 } 3798 if (def1->ns != NULL) { 3799 if (def1->ns[0] == 0) { 3800 node.ns = NULL; 3801 } else { 3802 node.ns = &ns; 3803 ns.href = def1->ns; 3804 } 3805 } else { 3806 node.ns = NULL; 3807 } 3808 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { 3809 if (def1->nameClass != NULL) { 3810 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); 3811 } else { 3812 ret = 0; 3813 } 3814 } else { 3815 ret = 1; 3816 } 3817 } else if (def1->type == XML_RELAXNG_TEXT) { 3818 if (def2->type == XML_RELAXNG_TEXT) 3819 return (0); 3820 return (1); 3821 } else if (def1->type == XML_RELAXNG_EXCEPT) { 3822 TODO ret = 0; 3823 } else { 3824 TODO ret = 0; 3825 } 3826 if (ret == 0) 3827 return (ret); 3828 if ((def2->type == XML_RELAXNG_ELEMENT) || 3829 (def2->type == XML_RELAXNG_ATTRIBUTE)) { 3830 if (def2->name != NULL) { 3831 node.name = def2->name; 3832 } else { 3833 node.name = invalidName; 3834 } 3835 node.ns = &ns; 3836 if (def2->ns != NULL) { 3837 if (def2->ns[0] == 0) { 3838 node.ns = NULL; 3839 } else { 3840 ns.href = def2->ns; 3841 } 3842 } else { 3843 ns.href = invalidName; 3844 } 3845 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { 3846 if (def2->nameClass != NULL) { 3847 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); 3848 } else { 3849 ret = 0; 3850 } 3851 } else { 3852 ret = 1; 3853 } 3854 } else { 3855 TODO ret = 0; 3856 } 3857 3858 return (ret); 3859} 3860 3861/** 3862 * xmlRelaxNGCompareElemDefLists: 3863 * @ctxt: a Relax-NG parser context 3864 * @defs1: the first list of element/attribute defs 3865 * @defs2: the second list of element/attribute defs 3866 * 3867 * Compare the 2 lists of element or attribute definitions. The comparison 3868 * is that if both lists do not accept the same QNames, it returns 1 3869 * If the 2 lists can accept the same QName the comparison returns 0 3870 * 3871 * Returns 1 disttinct, 0 if equal 3872 */ 3873static int 3874xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt 3875 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, 3876 xmlRelaxNGDefinePtr * def2) 3877{ 3878 xmlRelaxNGDefinePtr *basedef2 = def2; 3879 3880 if ((def1 == NULL) || (def2 == NULL)) 3881 return (1); 3882 if ((*def1 == NULL) || (*def2 == NULL)) 3883 return (1); 3884 while (*def1 != NULL) { 3885 while ((*def2) != NULL) { 3886 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) 3887 return (0); 3888 def2++; 3889 } 3890 def2 = basedef2; 3891 def1++; 3892 } 3893 return (1); 3894} 3895 3896/** 3897 * xmlRelaxNGGenerateAttributes: 3898 * @ctxt: a Relax-NG parser context 3899 * @def: the definition definition 3900 * 3901 * Check if the definition can only generate attributes 3902 * 3903 * Returns 1 if yes, 0 if no and -1 in case of error. 3904 */ 3905static int 3906xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, 3907 xmlRelaxNGDefinePtr def) 3908{ 3909 xmlRelaxNGDefinePtr parent, cur, tmp; 3910 3911 /* 3912 * Don't run that check in case of error. Infinite recursion 3913 * becomes possible. 3914 */ 3915 if (ctxt->nbErrors != 0) 3916 return (-1); 3917 3918 parent = NULL; 3919 cur = def; 3920 while (cur != NULL) { 3921 if ((cur->type == XML_RELAXNG_ELEMENT) || 3922 (cur->type == XML_RELAXNG_TEXT) || 3923 (cur->type == XML_RELAXNG_DATATYPE) || 3924 (cur->type == XML_RELAXNG_PARAM) || 3925 (cur->type == XML_RELAXNG_LIST) || 3926 (cur->type == XML_RELAXNG_VALUE) || 3927 (cur->type == XML_RELAXNG_EMPTY)) 3928 return (0); 3929 if ((cur->type == XML_RELAXNG_CHOICE) || 3930 (cur->type == XML_RELAXNG_INTERLEAVE) || 3931 (cur->type == XML_RELAXNG_GROUP) || 3932 (cur->type == XML_RELAXNG_ONEORMORE) || 3933 (cur->type == XML_RELAXNG_ZEROORMORE) || 3934 (cur->type == XML_RELAXNG_OPTIONAL) || 3935 (cur->type == XML_RELAXNG_PARENTREF) || 3936 (cur->type == XML_RELAXNG_EXTERNALREF) || 3937 (cur->type == XML_RELAXNG_REF) || 3938 (cur->type == XML_RELAXNG_DEF)) { 3939 if (cur->content != NULL) { 3940 parent = cur; 3941 cur = cur->content; 3942 tmp = cur; 3943 while (tmp != NULL) { 3944 tmp->parent = parent; 3945 tmp = tmp->next; 3946 } 3947 continue; 3948 } 3949 } 3950 if (cur == def) 3951 break; 3952 if (cur->next != NULL) { 3953 cur = cur->next; 3954 continue; 3955 } 3956 do { 3957 cur = cur->parent; 3958 if (cur == NULL) 3959 break; 3960 if (cur == def) 3961 return (1); 3962 if (cur->next != NULL) { 3963 cur = cur->next; 3964 break; 3965 } 3966 } while (cur != NULL); 3967 } 3968 return (1); 3969} 3970 3971/** 3972 * xmlRelaxNGGetElements: 3973 * @ctxt: a Relax-NG parser context 3974 * @def: the definition definition 3975 * @eora: gather elements (0) or attributes (1) 3976 * 3977 * Compute the list of top elements a definition can generate 3978 * 3979 * Returns a list of elements or NULL if none was found. 3980 */ 3981static xmlRelaxNGDefinePtr * 3982xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, 3983 xmlRelaxNGDefinePtr def, int eora) 3984{ 3985 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; 3986 int len = 0; 3987 int max = 0; 3988 3989 /* 3990 * Don't run that check in case of error. Infinite recursion 3991 * becomes possible. 3992 */ 3993 if (ctxt->nbErrors != 0) 3994 return (NULL); 3995 3996 parent = NULL; 3997 cur = def; 3998 while (cur != NULL) { 3999 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || 4000 (cur->type == XML_RELAXNG_TEXT))) || 4001 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) { 4002 if (ret == NULL) { 4003 max = 10; 4004 ret = (xmlRelaxNGDefinePtr *) 4005 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4006 if (ret == NULL) { 4007 xmlRngPErrMemory(ctxt, "getting element list\n"); 4008 return (NULL); 4009 } 4010 } else if (max <= len) { 4011 xmlRelaxNGDefinePtr *temp; 4012 4013 max *= 2; 4014 temp = xmlRealloc(ret, 4015 (max + 1) * sizeof(xmlRelaxNGDefinePtr)); 4016 if (temp == NULL) { 4017 xmlRngPErrMemory(ctxt, "getting element list\n"); 4018 xmlFree(ret); 4019 return (NULL); 4020 } 4021 ret = temp; 4022 } 4023 ret[len++] = cur; 4024 ret[len] = NULL; 4025 } else if ((cur->type == XML_RELAXNG_CHOICE) || 4026 (cur->type == XML_RELAXNG_INTERLEAVE) || 4027 (cur->type == XML_RELAXNG_GROUP) || 4028 (cur->type == XML_RELAXNG_ONEORMORE) || 4029 (cur->type == XML_RELAXNG_ZEROORMORE) || 4030 (cur->type == XML_RELAXNG_OPTIONAL) || 4031 (cur->type == XML_RELAXNG_PARENTREF) || 4032 (cur->type == XML_RELAXNG_REF) || 4033 (cur->type == XML_RELAXNG_DEF) || 4034 (cur->type == XML_RELAXNG_EXTERNALREF)) { 4035 /* 4036 * Don't go within elements or attributes or string values. 4037 * Just gather the element top list 4038 */ 4039 if (cur->content != NULL) { 4040 parent = cur; 4041 cur = cur->content; 4042 tmp = cur; 4043 while (tmp != NULL) { 4044 tmp->parent = parent; 4045 tmp = tmp->next; 4046 } 4047 continue; 4048 } 4049 } 4050 if (cur == def) 4051 break; 4052 if (cur->next != NULL) { 4053 cur = cur->next; 4054 continue; 4055 } 4056 do { 4057 cur = cur->parent; 4058 if (cur == NULL) 4059 break; 4060 if (cur == def) 4061 return (ret); 4062 if (cur->next != NULL) { 4063 cur = cur->next; 4064 break; 4065 } 4066 } while (cur != NULL); 4067 } 4068 return (ret); 4069} 4070 4071/** 4072 * xmlRelaxNGCheckChoiceDeterminism: 4073 * @ctxt: a Relax-NG parser context 4074 * @def: the choice definition 4075 * 4076 * Also used to find indeterministic pattern in choice 4077 */ 4078static void 4079xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, 4080 xmlRelaxNGDefinePtr def) 4081{ 4082 xmlRelaxNGDefinePtr **list; 4083 xmlRelaxNGDefinePtr cur; 4084 int nbchild = 0, i, j, ret; 4085 int is_nullable = 0; 4086 int is_indeterminist = 0; 4087 xmlHashTablePtr triage = NULL; 4088 int is_triable = 1; 4089 4090 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) 4091 return; 4092 4093 if (def->dflags & IS_PROCESSED) 4094 return; 4095 4096 /* 4097 * Don't run that check in case of error. Infinite recursion 4098 * becomes possible. 4099 */ 4100 if (ctxt->nbErrors != 0) 4101 return; 4102 4103 is_nullable = xmlRelaxNGIsNullable(def); 4104 4105 cur = def->content; 4106 while (cur != NULL) { 4107 nbchild++; 4108 cur = cur->next; 4109 } 4110 4111 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4112 sizeof(xmlRelaxNGDefinePtr 4113 *)); 4114 if (list == NULL) { 4115 xmlRngPErrMemory(ctxt, "building choice\n"); 4116 return; 4117 } 4118 i = 0; 4119 /* 4120 * a bit strong but safe 4121 */ 4122 if (is_nullable == 0) { 4123 triage = xmlHashCreate(10); 4124 } else { 4125 is_triable = 0; 4126 } 4127 cur = def->content; 4128 while (cur != NULL) { 4129 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); 4130 if ((list[i] == NULL) || (list[i][0] == NULL)) { 4131 is_triable = 0; 4132 } else if (is_triable == 1) { 4133 xmlRelaxNGDefinePtr *tmp; 4134 int res; 4135 4136 tmp = list[i]; 4137 while ((*tmp != NULL) && (is_triable == 1)) { 4138 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4139 res = xmlHashAddEntry2(triage, 4140 BAD_CAST "#text", NULL, 4141 (void *) cur); 4142 if (res != 0) 4143 is_triable = -1; 4144 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4145 ((*tmp)->name != NULL)) { 4146 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4147 res = xmlHashAddEntry2(triage, 4148 (*tmp)->name, NULL, 4149 (void *) cur); 4150 else 4151 res = xmlHashAddEntry2(triage, 4152 (*tmp)->name, (*tmp)->ns, 4153 (void *) cur); 4154 if (res != 0) 4155 is_triable = -1; 4156 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4157 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4158 res = xmlHashAddEntry2(triage, 4159 BAD_CAST "#any", NULL, 4160 (void *) cur); 4161 else 4162 res = xmlHashAddEntry2(triage, 4163 BAD_CAST "#any", (*tmp)->ns, 4164 (void *) cur); 4165 if (res != 0) 4166 is_triable = -1; 4167 } else { 4168 is_triable = -1; 4169 } 4170 tmp++; 4171 } 4172 } 4173 i++; 4174 cur = cur->next; 4175 } 4176 4177 for (i = 0; i < nbchild; i++) { 4178 if (list[i] == NULL) 4179 continue; 4180 for (j = 0; j < i; j++) { 4181 if (list[j] == NULL) 4182 continue; 4183 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4184 if (ret == 0) { 4185 is_indeterminist = 1; 4186 } 4187 } 4188 } 4189 for (i = 0; i < nbchild; i++) { 4190 if (list[i] != NULL) 4191 xmlFree(list[i]); 4192 } 4193 4194 xmlFree(list); 4195 if (is_indeterminist) { 4196 def->dflags |= IS_INDETERMINIST; 4197 } 4198 if (is_triable == 1) { 4199 def->dflags |= IS_TRIABLE; 4200 def->data = triage; 4201 } else if (triage != NULL) { 4202 xmlHashFree(triage, NULL); 4203 } 4204 def->dflags |= IS_PROCESSED; 4205} 4206 4207/** 4208 * xmlRelaxNGCheckGroupAttrs: 4209 * @ctxt: a Relax-NG parser context 4210 * @def: the group definition 4211 * 4212 * Detects violations of rule 7.3 4213 */ 4214static void 4215xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, 4216 xmlRelaxNGDefinePtr def) 4217{ 4218 xmlRelaxNGDefinePtr **list; 4219 xmlRelaxNGDefinePtr cur; 4220 int nbchild = 0, i, j, ret; 4221 4222 if ((def == NULL) || 4223 ((def->type != XML_RELAXNG_GROUP) && 4224 (def->type != XML_RELAXNG_ELEMENT))) 4225 return; 4226 4227 if (def->dflags & IS_PROCESSED) 4228 return; 4229 4230 /* 4231 * Don't run that check in case of error. Infinite recursion 4232 * becomes possible. 4233 */ 4234 if (ctxt->nbErrors != 0) 4235 return; 4236 4237 cur = def->attrs; 4238 while (cur != NULL) { 4239 nbchild++; 4240 cur = cur->next; 4241 } 4242 cur = def->content; 4243 while (cur != NULL) { 4244 nbchild++; 4245 cur = cur->next; 4246 } 4247 4248 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4249 sizeof(xmlRelaxNGDefinePtr 4250 *)); 4251 if (list == NULL) { 4252 xmlRngPErrMemory(ctxt, "building group\n"); 4253 return; 4254 } 4255 i = 0; 4256 cur = def->attrs; 4257 while (cur != NULL) { 4258 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4259 i++; 4260 cur = cur->next; 4261 } 4262 cur = def->content; 4263 while (cur != NULL) { 4264 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4265 i++; 4266 cur = cur->next; 4267 } 4268 4269 for (i = 0; i < nbchild; i++) { 4270 if (list[i] == NULL) 4271 continue; 4272 for (j = 0; j < i; j++) { 4273 if (list[j] == NULL) 4274 continue; 4275 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4276 if (ret == 0) { 4277 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, 4278 "Attributes conflicts in group\n", NULL, NULL); 4279 } 4280 } 4281 } 4282 for (i = 0; i < nbchild; i++) { 4283 if (list[i] != NULL) 4284 xmlFree(list[i]); 4285 } 4286 4287 xmlFree(list); 4288 def->dflags |= IS_PROCESSED; 4289} 4290 4291/** 4292 * xmlRelaxNGComputeInterleaves: 4293 * @def: the interleave definition 4294 * @ctxt: a Relax-NG parser context 4295 * @name: the definition name 4296 * 4297 * A lot of work for preprocessing interleave definitions 4298 * is potentially needed to get a decent execution speed at runtime 4299 * - trying to get a total order on the element nodes generated 4300 * by the interleaves, order the list of interleave definitions 4301 * following that order. 4302 * - if <text/> is used to handle mixed content, it is better to 4303 * flag this in the define and simplify the runtime checking 4304 * algorithm 4305 */ 4306static void 4307xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def, 4308 xmlRelaxNGParserCtxtPtr ctxt, 4309 xmlChar * name ATTRIBUTE_UNUSED) 4310{ 4311 xmlRelaxNGDefinePtr cur, *tmp; 4312 4313 xmlRelaxNGPartitionPtr partitions = NULL; 4314 xmlRelaxNGInterleaveGroupPtr *groups = NULL; 4315 xmlRelaxNGInterleaveGroupPtr group; 4316 int i, j, ret, res; 4317 int nbgroups = 0; 4318 int nbchild = 0; 4319 int is_mixed = 0; 4320 int is_determinist = 1; 4321 4322 /* 4323 * Don't run that check in case of error. Infinite recursion 4324 * becomes possible. 4325 */ 4326 if (ctxt->nbErrors != 0) 4327 return; 4328 4329#ifdef DEBUG_INTERLEAVE 4330 xmlGenericError(xmlGenericErrorContext, 4331 "xmlRelaxNGComputeInterleaves(%s)\n", name); 4332#endif 4333 cur = def->content; 4334 while (cur != NULL) { 4335 nbchild++; 4336 cur = cur->next; 4337 } 4338 4339#ifdef DEBUG_INTERLEAVE 4340 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); 4341#endif 4342 groups = (xmlRelaxNGInterleaveGroupPtr *) 4343 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); 4344 if (groups == NULL) 4345 goto error; 4346 cur = def->content; 4347 while (cur != NULL) { 4348 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) 4349 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); 4350 if (groups[nbgroups] == NULL) 4351 goto error; 4352 if (cur->type == XML_RELAXNG_TEXT) 4353 is_mixed++; 4354 groups[nbgroups]->rule = cur; 4355 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0); 4356 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); 4357 nbgroups++; 4358 cur = cur->next; 4359 } 4360#ifdef DEBUG_INTERLEAVE 4361 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); 4362#endif 4363 4364 /* 4365 * Let's check that all rules makes a partitions according to 7.4 4366 */ 4367 partitions = (xmlRelaxNGPartitionPtr) 4368 xmlMalloc(sizeof(xmlRelaxNGPartition)); 4369 if (partitions == NULL) 4370 goto error; 4371 memset(partitions, 0, sizeof(xmlRelaxNGPartition)); 4372 partitions->nbgroups = nbgroups; 4373 partitions->triage = xmlHashCreate(nbgroups); 4374 for (i = 0; i < nbgroups; i++) { 4375 group = groups[i]; 4376 for (j = i + 1; j < nbgroups; j++) { 4377 if (groups[j] == NULL) 4378 continue; 4379 4380 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, 4381 groups[j]->defs); 4382 if (ret == 0) { 4383 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, 4384 "Element or text conflicts in interleave\n", 4385 NULL, NULL); 4386 } 4387 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, 4388 groups[j]->attrs); 4389 if (ret == 0) { 4390 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, 4391 "Attributes conflicts in interleave\n", NULL, 4392 NULL); 4393 } 4394 } 4395 tmp = group->defs; 4396 if ((tmp != NULL) && (*tmp != NULL)) { 4397 while (*tmp != NULL) { 4398 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4399 res = xmlHashAddEntry2(partitions->triage, 4400 BAD_CAST "#text", NULL, 4401 (void *) (long) (i + 1)); 4402 if (res != 0) 4403 is_determinist = -1; 4404 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4405 ((*tmp)->name != NULL)) { 4406 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4407 res = xmlHashAddEntry2(partitions->triage, 4408 (*tmp)->name, NULL, 4409 (void *) (long) (i + 1)); 4410 else 4411 res = xmlHashAddEntry2(partitions->triage, 4412 (*tmp)->name, (*tmp)->ns, 4413 (void *) (long) (i + 1)); 4414 if (res != 0) 4415 is_determinist = -1; 4416 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4417 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4418 res = xmlHashAddEntry2(partitions->triage, 4419 BAD_CAST "#any", NULL, 4420 (void *) (long) (i + 1)); 4421 else 4422 res = xmlHashAddEntry2(partitions->triage, 4423 BAD_CAST "#any", (*tmp)->ns, 4424 (void *) (long) (i + 1)); 4425 if ((*tmp)->nameClass != NULL) 4426 is_determinist = 2; 4427 if (res != 0) 4428 is_determinist = -1; 4429 } else { 4430 is_determinist = -1; 4431 } 4432 tmp++; 4433 } 4434 } else { 4435 is_determinist = 0; 4436 } 4437 } 4438 partitions->groups = groups; 4439 4440 /* 4441 * and save the partition list back in the def 4442 */ 4443 def->data = partitions; 4444 if (is_mixed != 0) 4445 def->dflags |= IS_MIXED; 4446 if (is_determinist == 1) 4447 partitions->flags = IS_DETERMINIST; 4448 if (is_determinist == 2) 4449 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; 4450 return; 4451 4452 error: 4453 xmlRngPErrMemory(ctxt, "in interleave computation\n"); 4454 if (groups != NULL) { 4455 for (i = 0; i < nbgroups; i++) 4456 if (groups[i] != NULL) { 4457 if (groups[i]->defs != NULL) 4458 xmlFree(groups[i]->defs); 4459 xmlFree(groups[i]); 4460 } 4461 xmlFree(groups); 4462 } 4463 xmlRelaxNGFreePartition(partitions); 4464} 4465 4466/** 4467 * xmlRelaxNGParseInterleave: 4468 * @ctxt: a Relax-NG parser context 4469 * @node: the data node. 4470 * 4471 * parse the content of a RelaxNG interleave node. 4472 * 4473 * Returns the definition pointer or NULL in case of error 4474 */ 4475static xmlRelaxNGDefinePtr 4476xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4477{ 4478 xmlRelaxNGDefinePtr def = NULL; 4479 xmlRelaxNGDefinePtr last = NULL, cur; 4480 xmlNodePtr child; 4481 4482 def = xmlRelaxNGNewDefine(ctxt, node); 4483 if (def == NULL) { 4484 return (NULL); 4485 } 4486 def->type = XML_RELAXNG_INTERLEAVE; 4487 4488 if (ctxt->interleaves == NULL) 4489 ctxt->interleaves = xmlHashCreate(10); 4490 if (ctxt->interleaves == NULL) { 4491 xmlRngPErrMemory(ctxt, "create interleaves\n"); 4492 } else { 4493 char name[32]; 4494 4495 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); 4496 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { 4497 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, 4498 "Failed to add %s to hash table\n", 4499 (const xmlChar *) name, NULL); 4500 } 4501 } 4502 child = node->children; 4503 if (child == NULL) { 4504 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, 4505 "Element interleave is empty\n", NULL, NULL); 4506 } 4507 while (child != NULL) { 4508 if (IS_RELAXNG(child, "element")) { 4509 cur = xmlRelaxNGParseElement(ctxt, child); 4510 } else { 4511 cur = xmlRelaxNGParsePattern(ctxt, child); 4512 } 4513 if (cur != NULL) { 4514 cur->parent = def; 4515 if (last == NULL) { 4516 def->content = last = cur; 4517 } else { 4518 last->next = cur; 4519 last = cur; 4520 } 4521 } 4522 child = child->next; 4523 } 4524 4525 return (def); 4526} 4527 4528/** 4529 * xmlRelaxNGParseInclude: 4530 * @ctxt: a Relax-NG parser context 4531 * @node: the include node 4532 * 4533 * Integrate the content of an include node in the current grammar 4534 * 4535 * Returns 0 in case of success or -1 in case of error 4536 */ 4537static int 4538xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4539{ 4540 xmlRelaxNGIncludePtr incl; 4541 xmlNodePtr root; 4542 int ret = 0, tmp; 4543 4544 incl = node->psvi; 4545 if (incl == NULL) { 4546 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, 4547 "Include node has no data\n", NULL, NULL); 4548 return (-1); 4549 } 4550 root = xmlDocGetRootElement(incl->doc); 4551 if (root == NULL) { 4552 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", 4553 NULL, NULL); 4554 return (-1); 4555 } 4556 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { 4557 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 4558 "Include document root is not a grammar\n", NULL, NULL); 4559 return (-1); 4560 } 4561 4562 /* 4563 * Merge the definition from both the include and the internal list 4564 */ 4565 if (root->children != NULL) { 4566 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); 4567 if (tmp != 0) 4568 ret = -1; 4569 } 4570 if (node->children != NULL) { 4571 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); 4572 if (tmp != 0) 4573 ret = -1; 4574 } 4575 return (ret); 4576} 4577 4578/** 4579 * xmlRelaxNGParseDefine: 4580 * @ctxt: a Relax-NG parser context 4581 * @node: the define node 4582 * 4583 * parse the content of a RelaxNG define element node. 4584 * 4585 * Returns 0 in case of success or -1 in case of error 4586 */ 4587static int 4588xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4589{ 4590 xmlChar *name; 4591 int ret = 0, tmp; 4592 xmlRelaxNGDefinePtr def; 4593 const xmlChar *olddefine; 4594 4595 name = xmlGetProp(node, BAD_CAST "name"); 4596 if (name == NULL) { 4597 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, 4598 "define has no name\n", NULL, NULL); 4599 } else { 4600 xmlRelaxNGNormExtSpace(name); 4601 if (xmlValidateNCName(name, 0)) { 4602 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, 4603 "define name '%s' is not an NCName\n", name, NULL); 4604 } 4605 def = xmlRelaxNGNewDefine(ctxt, node); 4606 if (def == NULL) { 4607 xmlFree(name); 4608 return (-1); 4609 } 4610 def->type = XML_RELAXNG_DEF; 4611 def->name = name; 4612 if (node->children == NULL) { 4613 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, 4614 "define has no children\n", NULL, NULL); 4615 } else { 4616 olddefine = ctxt->define; 4617 ctxt->define = name; 4618 def->content = 4619 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4620 ctxt->define = olddefine; 4621 } 4622 if (ctxt->grammar->defs == NULL) 4623 ctxt->grammar->defs = xmlHashCreate(10); 4624 if (ctxt->grammar->defs == NULL) { 4625 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4626 "Could not create definition hash\n", NULL, NULL); 4627 ret = -1; 4628 } else { 4629 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); 4630 if (tmp < 0) { 4631 xmlRelaxNGDefinePtr prev; 4632 4633 prev = xmlHashLookup(ctxt->grammar->defs, name); 4634 if (prev == NULL) { 4635 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4636 "Internal error on define aggregation of %s\n", 4637 name, NULL); 4638 ret = -1; 4639 } else { 4640 while (prev->nextHash != NULL) 4641 prev = prev->nextHash; 4642 prev->nextHash = def; 4643 } 4644 } 4645 } 4646 } 4647 return (ret); 4648} 4649 4650/** 4651 * xmlRelaxNGParseImportRef: 4652 * @payload: the parser context 4653 * @data: the current grammar 4654 * @name: the reference name 4655 * 4656 * Import import one references into the current grammar 4657 */ 4658static void 4659xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) { 4660 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; 4661 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; 4662 int tmp; 4663 4664 def->dflags |= IS_EXTERNAL_REF; 4665 4666 tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def); 4667 if (tmp < 0) { 4668 xmlRelaxNGDefinePtr prev; 4669 4670 prev = (xmlRelaxNGDefinePtr) 4671 xmlHashLookup(ctxt->grammar->refs, def->name); 4672 if (prev == NULL) { 4673 if (def->name != NULL) { 4674 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4675 "Error refs definitions '%s'\n", 4676 def->name, NULL); 4677 } else { 4678 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4679 "Error refs definitions\n", 4680 NULL, NULL); 4681 } 4682 } else { 4683 def->nextHash = prev->nextHash; 4684 prev->nextHash = def; 4685 } 4686 } 4687} 4688 4689/** 4690 * xmlRelaxNGParseImportRefs: 4691 * @ctxt: the parser context 4692 * @grammar: the sub grammar 4693 * 4694 * Import references from the subgrammar into the current grammar 4695 * 4696 * Returns 0 in case of success, -1 in case of failure 4697 */ 4698static int 4699xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt, 4700 xmlRelaxNGGrammarPtr grammar) { 4701 if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL)) 4702 return(-1); 4703 if (grammar->refs == NULL) 4704 return(0); 4705 if (ctxt->grammar->refs == NULL) 4706 ctxt->grammar->refs = xmlHashCreate(10); 4707 if (ctxt->grammar->refs == NULL) { 4708 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, 4709 "Could not create references hash\n", NULL, NULL); 4710 return(-1); 4711 } 4712 xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt); 4713 return(0); 4714} 4715 4716/** 4717 * xmlRelaxNGProcessExternalRef: 4718 * @ctxt: the parser context 4719 * @node: the externlRef node 4720 * 4721 * Process and compile an externlRef node 4722 * 4723 * Returns the xmlRelaxNGDefinePtr or NULL in case of error 4724 */ 4725static xmlRelaxNGDefinePtr 4726xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4727{ 4728 xmlRelaxNGDocumentPtr docu; 4729 xmlNodePtr root, tmp; 4730 xmlChar *ns; 4731 int newNs = 0, oldflags; 4732 xmlRelaxNGDefinePtr def; 4733 4734 docu = node->psvi; 4735 if (docu != NULL) { 4736 def = xmlRelaxNGNewDefine(ctxt, node); 4737 if (def == NULL) 4738 return (NULL); 4739 def->type = XML_RELAXNG_EXTERNALREF; 4740 4741 if (docu->content == NULL) { 4742 /* 4743 * Then do the parsing for good 4744 */ 4745 root = xmlDocGetRootElement(docu->doc); 4746 if (root == NULL) { 4747 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY, 4748 "xmlRelaxNGParse: %s is empty\n", ctxt->URL, 4749 NULL); 4750 return (NULL); 4751 } 4752 /* 4753 * ns transmission rules 4754 */ 4755 ns = xmlGetProp(root, BAD_CAST "ns"); 4756 if (ns == NULL) { 4757 tmp = node; 4758 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) { 4759 ns = xmlGetProp(tmp, BAD_CAST "ns"); 4760 if (ns != NULL) { 4761 break; 4762 } 4763 tmp = tmp->parent; 4764 } 4765 if (ns != NULL) { 4766 xmlSetProp(root, BAD_CAST "ns", ns); 4767 newNs = 1; 4768 xmlFree(ns); 4769 } 4770 } else { 4771 xmlFree(ns); 4772 } 4773 4774 /* 4775 * Parsing to get a precompiled schemas. 4776 */ 4777 oldflags = ctxt->flags; 4778 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; 4779 docu->schema = xmlRelaxNGParseDocument(ctxt, root); 4780 ctxt->flags = oldflags; 4781 if ((docu->schema != NULL) && 4782 (docu->schema->topgrammar != NULL)) { 4783 docu->content = docu->schema->topgrammar->start; 4784 if (docu->schema->topgrammar->refs) 4785 xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar); 4786 } 4787 4788 /* 4789 * the externalRef may be reused in a different ns context 4790 */ 4791 if (newNs == 1) { 4792 xmlUnsetProp(root, BAD_CAST "ns"); 4793 } 4794 } 4795 def->content = docu->content; 4796 } else { 4797 def = NULL; 4798 } 4799 return (def); 4800} 4801 4802/** 4803 * xmlRelaxNGParsePattern: 4804 * @ctxt: a Relax-NG parser context 4805 * @node: the pattern node. 4806 * 4807 * parse the content of a RelaxNG pattern node. 4808 * 4809 * Returns the definition pointer or NULL in case of error or if no 4810 * pattern is generated. 4811 */ 4812static xmlRelaxNGDefinePtr 4813xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4814{ 4815 xmlRelaxNGDefinePtr def = NULL; 4816 4817 if (node == NULL) { 4818 return (NULL); 4819 } 4820 if (IS_RELAXNG(node, "element")) { 4821 def = xmlRelaxNGParseElement(ctxt, node); 4822 } else if (IS_RELAXNG(node, "attribute")) { 4823 def = xmlRelaxNGParseAttribute(ctxt, node); 4824 } else if (IS_RELAXNG(node, "empty")) { 4825 def = xmlRelaxNGNewDefine(ctxt, node); 4826 if (def == NULL) 4827 return (NULL); 4828 def->type = XML_RELAXNG_EMPTY; 4829 if (node->children != NULL) { 4830 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY, 4831 "empty: had a child node\n", NULL, NULL); 4832 } 4833 } else if (IS_RELAXNG(node, "text")) { 4834 def = xmlRelaxNGNewDefine(ctxt, node); 4835 if (def == NULL) 4836 return (NULL); 4837 def->type = XML_RELAXNG_TEXT; 4838 if (node->children != NULL) { 4839 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD, 4840 "text: had a child node\n", NULL, NULL); 4841 } 4842 } else if (IS_RELAXNG(node, "zeroOrMore")) { 4843 def = xmlRelaxNGNewDefine(ctxt, node); 4844 if (def == NULL) 4845 return (NULL); 4846 def->type = XML_RELAXNG_ZEROORMORE; 4847 if (node->children == NULL) { 4848 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4849 "Element %s is empty\n", node->name, NULL); 4850 } else { 4851 def->content = 4852 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4853 } 4854 } else if (IS_RELAXNG(node, "oneOrMore")) { 4855 def = xmlRelaxNGNewDefine(ctxt, node); 4856 if (def == NULL) 4857 return (NULL); 4858 def->type = XML_RELAXNG_ONEORMORE; 4859 if (node->children == NULL) { 4860 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4861 "Element %s is empty\n", node->name, NULL); 4862 } else { 4863 def->content = 4864 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4865 } 4866 } else if (IS_RELAXNG(node, "optional")) { 4867 def = xmlRelaxNGNewDefine(ctxt, node); 4868 if (def == NULL) 4869 return (NULL); 4870 def->type = XML_RELAXNG_OPTIONAL; 4871 if (node->children == NULL) { 4872 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4873 "Element %s is empty\n", node->name, NULL); 4874 } else { 4875 def->content = 4876 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4877 } 4878 } else if (IS_RELAXNG(node, "choice")) { 4879 def = xmlRelaxNGNewDefine(ctxt, node); 4880 if (def == NULL) 4881 return (NULL); 4882 def->type = XML_RELAXNG_CHOICE; 4883 if (node->children == NULL) { 4884 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4885 "Element %s is empty\n", node->name, NULL); 4886 } else { 4887 def->content = 4888 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4889 } 4890 } else if (IS_RELAXNG(node, "group")) { 4891 def = xmlRelaxNGNewDefine(ctxt, node); 4892 if (def == NULL) 4893 return (NULL); 4894 def->type = XML_RELAXNG_GROUP; 4895 if (node->children == NULL) { 4896 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4897 "Element %s is empty\n", node->name, NULL); 4898 } else { 4899 def->content = 4900 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4901 } 4902 } else if (IS_RELAXNG(node, "ref")) { 4903 def = xmlRelaxNGNewDefine(ctxt, node); 4904 if (def == NULL) 4905 return (NULL); 4906 def->type = XML_RELAXNG_REF; 4907 def->name = xmlGetProp(node, BAD_CAST "name"); 4908 if (def->name == NULL) { 4909 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n", 4910 NULL, NULL); 4911 } else { 4912 xmlRelaxNGNormExtSpace(def->name); 4913 if (xmlValidateNCName(def->name, 0)) { 4914 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID, 4915 "ref name '%s' is not an NCName\n", def->name, 4916 NULL); 4917 } 4918 } 4919 if (node->children != NULL) { 4920 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n", 4921 NULL, NULL); 4922 } 4923 if (ctxt->grammar->refs == NULL) 4924 ctxt->grammar->refs = xmlHashCreate(10); 4925 if (ctxt->grammar->refs == NULL) { 4926 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4927 "Could not create references hash\n", NULL, NULL); 4928 def = NULL; 4929 } else { 4930 int tmp; 4931 4932 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); 4933 if (tmp < 0) { 4934 xmlRelaxNGDefinePtr prev; 4935 4936 prev = (xmlRelaxNGDefinePtr) 4937 xmlHashLookup(ctxt->grammar->refs, def->name); 4938 if (prev == NULL) { 4939 if (def->name != NULL) { 4940 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4941 "Error refs definitions '%s'\n", 4942 def->name, NULL); 4943 } else { 4944 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4945 "Error refs definitions\n", 4946 NULL, NULL); 4947 } 4948 def = NULL; 4949 } else { 4950 def->nextHash = prev->nextHash; 4951 prev->nextHash = def; 4952 } 4953 } 4954 } 4955 } else if (IS_RELAXNG(node, "data")) { 4956 def = xmlRelaxNGParseData(ctxt, node); 4957 } else if (IS_RELAXNG(node, "value")) { 4958 def = xmlRelaxNGParseValue(ctxt, node); 4959 } else if (IS_RELAXNG(node, "list")) { 4960 def = xmlRelaxNGNewDefine(ctxt, node); 4961 if (def == NULL) 4962 return (NULL); 4963 def->type = XML_RELAXNG_LIST; 4964 if (node->children == NULL) { 4965 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4966 "Element %s is empty\n", node->name, NULL); 4967 } else { 4968 def->content = 4969 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4970 } 4971 } else if (IS_RELAXNG(node, "interleave")) { 4972 def = xmlRelaxNGParseInterleave(ctxt, node); 4973 } else if (IS_RELAXNG(node, "externalRef")) { 4974 def = xmlRelaxNGProcessExternalRef(ctxt, node); 4975 } else if (IS_RELAXNG(node, "notAllowed")) { 4976 def = xmlRelaxNGNewDefine(ctxt, node); 4977 if (def == NULL) 4978 return (NULL); 4979 def->type = XML_RELAXNG_NOT_ALLOWED; 4980 if (node->children != NULL) { 4981 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY, 4982 "xmlRelaxNGParse: notAllowed element is not empty\n", 4983 NULL, NULL); 4984 } 4985 } else if (IS_RELAXNG(node, "grammar")) { 4986 xmlRelaxNGGrammarPtr grammar, old; 4987 xmlRelaxNGGrammarPtr oldparent; 4988 4989#ifdef DEBUG_GRAMMAR 4990 xmlGenericError(xmlGenericErrorContext, 4991 "Found <grammar> pattern\n"); 4992#endif 4993 4994 oldparent = ctxt->parentgrammar; 4995 old = ctxt->grammar; 4996 ctxt->parentgrammar = old; 4997 grammar = xmlRelaxNGParseGrammar(ctxt, node->children); 4998 if (old != NULL) { 4999 ctxt->grammar = old; 5000 ctxt->parentgrammar = oldparent; 5001#if 0 5002 if (grammar != NULL) { 5003 grammar->next = old->next; 5004 old->next = grammar; 5005 } 5006#endif 5007 } 5008 if (grammar != NULL) 5009 def = grammar->start; 5010 else 5011 def = NULL; 5012 } else if (IS_RELAXNG(node, "parentRef")) { 5013 if (ctxt->parentgrammar == NULL) { 5014 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT, 5015 "Use of parentRef without a parent grammar\n", NULL, 5016 NULL); 5017 return (NULL); 5018 } 5019 def = xmlRelaxNGNewDefine(ctxt, node); 5020 if (def == NULL) 5021 return (NULL); 5022 def->type = XML_RELAXNG_PARENTREF; 5023 def->name = xmlGetProp(node, BAD_CAST "name"); 5024 if (def->name == NULL) { 5025 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME, 5026 "parentRef has no name\n", NULL, NULL); 5027 } else { 5028 xmlRelaxNGNormExtSpace(def->name); 5029 if (xmlValidateNCName(def->name, 0)) { 5030 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID, 5031 "parentRef name '%s' is not an NCName\n", 5032 def->name, NULL); 5033 } 5034 } 5035 if (node->children != NULL) { 5036 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY, 5037 "parentRef is not empty\n", NULL, NULL); 5038 } 5039 if (ctxt->parentgrammar->refs == NULL) 5040 ctxt->parentgrammar->refs = xmlHashCreate(10); 5041 if (ctxt->parentgrammar->refs == NULL) { 5042 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5043 "Could not create references hash\n", NULL, NULL); 5044 def = NULL; 5045 } else if (def->name != NULL) { 5046 int tmp; 5047 5048 tmp = 5049 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); 5050 if (tmp < 0) { 5051 xmlRelaxNGDefinePtr prev; 5052 5053 prev = (xmlRelaxNGDefinePtr) 5054 xmlHashLookup(ctxt->parentgrammar->refs, def->name); 5055 if (prev == NULL) { 5056 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 5057 "Internal error parentRef definitions '%s'\n", 5058 def->name, NULL); 5059 def = NULL; 5060 } else { 5061 def->nextHash = prev->nextHash; 5062 prev->nextHash = def; 5063 } 5064 } 5065 } 5066 } else if (IS_RELAXNG(node, "mixed")) { 5067 if (node->children == NULL) { 5068 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n", 5069 NULL, NULL); 5070 def = NULL; 5071 } else { 5072 def = xmlRelaxNGParseInterleave(ctxt, node); 5073 if (def != NULL) { 5074 xmlRelaxNGDefinePtr tmp; 5075 5076 if ((def->content != NULL) && (def->content->next != NULL)) { 5077 tmp = xmlRelaxNGNewDefine(ctxt, node); 5078 if (tmp != NULL) { 5079 tmp->type = XML_RELAXNG_GROUP; 5080 tmp->content = def->content; 5081 def->content = tmp; 5082 } 5083 } 5084 5085 tmp = xmlRelaxNGNewDefine(ctxt, node); 5086 if (tmp == NULL) 5087 return (def); 5088 tmp->type = XML_RELAXNG_TEXT; 5089 tmp->next = def->content; 5090 def->content = tmp; 5091 } 5092 } 5093 } else { 5094 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT, 5095 "Unexpected node %s is not a pattern\n", node->name, 5096 NULL); 5097 def = NULL; 5098 } 5099 return (def); 5100} 5101 5102/** 5103 * xmlRelaxNGParseAttribute: 5104 * @ctxt: a Relax-NG parser context 5105 * @node: the element node 5106 * 5107 * parse the content of a RelaxNG attribute node. 5108 * 5109 * Returns the definition pointer or NULL in case of error. 5110 */ 5111static xmlRelaxNGDefinePtr 5112xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5113{ 5114 xmlRelaxNGDefinePtr ret, cur; 5115 xmlNodePtr child; 5116 int old_flags; 5117 5118 ret = xmlRelaxNGNewDefine(ctxt, node); 5119 if (ret == NULL) 5120 return (NULL); 5121 ret->type = XML_RELAXNG_ATTRIBUTE; 5122 ret->parent = ctxt->def; 5123 child = node->children; 5124 if (child == NULL) { 5125 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY, 5126 "xmlRelaxNGParseattribute: attribute has no children\n", 5127 NULL, NULL); 5128 return (ret); 5129 } 5130 old_flags = ctxt->flags; 5131 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; 5132 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5133 if (cur != NULL) 5134 child = child->next; 5135 5136 if (child != NULL) { 5137 cur = xmlRelaxNGParsePattern(ctxt, child); 5138 if (cur != NULL) { 5139 switch (cur->type) { 5140 case XML_RELAXNG_EMPTY: 5141 case XML_RELAXNG_NOT_ALLOWED: 5142 case XML_RELAXNG_TEXT: 5143 case XML_RELAXNG_ELEMENT: 5144 case XML_RELAXNG_DATATYPE: 5145 case XML_RELAXNG_VALUE: 5146 case XML_RELAXNG_LIST: 5147 case XML_RELAXNG_REF: 5148 case XML_RELAXNG_PARENTREF: 5149 case XML_RELAXNG_EXTERNALREF: 5150 case XML_RELAXNG_DEF: 5151 case XML_RELAXNG_ONEORMORE: 5152 case XML_RELAXNG_ZEROORMORE: 5153 case XML_RELAXNG_OPTIONAL: 5154 case XML_RELAXNG_CHOICE: 5155 case XML_RELAXNG_GROUP: 5156 case XML_RELAXNG_INTERLEAVE: 5157 case XML_RELAXNG_ATTRIBUTE: 5158 ret->content = cur; 5159 cur->parent = ret; 5160 break; 5161 case XML_RELAXNG_START: 5162 case XML_RELAXNG_PARAM: 5163 case XML_RELAXNG_EXCEPT: 5164 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT, 5165 "attribute has invalid content\n", NULL, 5166 NULL); 5167 break; 5168 case XML_RELAXNG_NOOP: 5169 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP, 5170 "RNG Internal error, noop found in attribute\n", 5171 NULL, NULL); 5172 break; 5173 } 5174 } 5175 child = child->next; 5176 } 5177 if (child != NULL) { 5178 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN, 5179 "attribute has multiple children\n", NULL, NULL); 5180 } 5181 ctxt->flags = old_flags; 5182 return (ret); 5183} 5184 5185/** 5186 * xmlRelaxNGParseExceptNameClass: 5187 * @ctxt: a Relax-NG parser context 5188 * @node: the except node 5189 * @attr: 1 if within an attribute, 0 if within an element 5190 * 5191 * parse the content of a RelaxNG nameClass node. 5192 * 5193 * Returns the definition pointer or NULL in case of error. 5194 */ 5195static xmlRelaxNGDefinePtr 5196xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, 5197 xmlNodePtr node, int attr) 5198{ 5199 xmlRelaxNGDefinePtr ret, cur, last = NULL; 5200 xmlNodePtr child; 5201 5202 if (!IS_RELAXNG(node, "except")) { 5203 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING, 5204 "Expecting an except node\n", NULL, NULL); 5205 return (NULL); 5206 } 5207 if (node->next != NULL) { 5208 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE, 5209 "exceptNameClass allows only a single except node\n", 5210 NULL, NULL); 5211 } 5212 if (node->children == NULL) { 5213 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n", 5214 NULL, NULL); 5215 return (NULL); 5216 } 5217 5218 ret = xmlRelaxNGNewDefine(ctxt, node); 5219 if (ret == NULL) 5220 return (NULL); 5221 ret->type = XML_RELAXNG_EXCEPT; 5222 child = node->children; 5223 while (child != NULL) { 5224 cur = xmlRelaxNGNewDefine(ctxt, child); 5225 if (cur == NULL) 5226 break; 5227 if (attr) 5228 cur->type = XML_RELAXNG_ATTRIBUTE; 5229 else 5230 cur->type = XML_RELAXNG_ELEMENT; 5231 5232 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) { 5233 if (last == NULL) { 5234 ret->content = cur; 5235 } else { 5236 last->next = cur; 5237 } 5238 last = cur; 5239 } 5240 child = child->next; 5241 } 5242 5243 return (ret); 5244} 5245 5246/** 5247 * xmlRelaxNGParseNameClass: 5248 * @ctxt: a Relax-NG parser context 5249 * @node: the nameClass node 5250 * @def: the current definition 5251 * 5252 * parse the content of a RelaxNG nameClass node. 5253 * 5254 * Returns the definition pointer or NULL in case of error. 5255 */ 5256static xmlRelaxNGDefinePtr 5257xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, 5258 xmlRelaxNGDefinePtr def) 5259{ 5260 xmlRelaxNGDefinePtr ret, tmp; 5261 xmlChar *val; 5262 5263 ret = def; 5264 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) || 5265 (IS_RELAXNG(node, "nsName"))) { 5266 if ((def->type != XML_RELAXNG_ELEMENT) && 5267 (def->type != XML_RELAXNG_ATTRIBUTE)) { 5268 ret = xmlRelaxNGNewDefine(ctxt, node); 5269 if (ret == NULL) 5270 return (NULL); 5271 ret->parent = def; 5272 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) 5273 ret->type = XML_RELAXNG_ATTRIBUTE; 5274 else 5275 ret->type = XML_RELAXNG_ELEMENT; 5276 } 5277 } 5278 if (IS_RELAXNG(node, "name")) { 5279 val = xmlNodeGetContent(node); 5280 xmlRelaxNGNormExtSpace(val); 5281 if (xmlValidateNCName(val, 0)) { 5282 if (node->parent != NULL) 5283 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5284 "Element %s name '%s' is not an NCName\n", 5285 node->parent->name, val); 5286 else 5287 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, 5288 "name '%s' is not an NCName\n", 5289 val, NULL); 5290 } 5291 ret->name = val; 5292 val = xmlGetProp(node, BAD_CAST "ns"); 5293 ret->ns = val; 5294 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5295 (val != NULL) && 5296 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5297 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5298 "Attribute with namespace '%s' is not allowed\n", 5299 val, NULL); 5300 } 5301 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5302 (val != NULL) && 5303 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) { 5304 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME, 5305 "Attribute with QName 'xmlns' is not allowed\n", 5306 val, NULL); 5307 } 5308 } else if (IS_RELAXNG(node, "anyName")) { 5309 ret->name = NULL; 5310 ret->ns = NULL; 5311 if (node->children != NULL) { 5312 ret->nameClass = 5313 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5314 (def->type == 5315 XML_RELAXNG_ATTRIBUTE)); 5316 } 5317 } else if (IS_RELAXNG(node, "nsName")) { 5318 ret->name = NULL; 5319 ret->ns = xmlGetProp(node, BAD_CAST "ns"); 5320 if (ret->ns == NULL) { 5321 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS, 5322 "nsName has no ns attribute\n", NULL, NULL); 5323 } 5324 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && 5325 (ret->ns != NULL) && 5326 (xmlStrEqual 5327 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) { 5328 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, 5329 "Attribute with namespace '%s' is not allowed\n", 5330 ret->ns, NULL); 5331 } 5332 if (node->children != NULL) { 5333 ret->nameClass = 5334 xmlRelaxNGParseExceptNameClass(ctxt, node->children, 5335 (def->type == 5336 XML_RELAXNG_ATTRIBUTE)); 5337 } 5338 } else if (IS_RELAXNG(node, "choice")) { 5339 xmlNodePtr child; 5340 xmlRelaxNGDefinePtr last = NULL; 5341 5342 ret = xmlRelaxNGNewDefine(ctxt, node); 5343 if (ret == NULL) 5344 return (NULL); 5345 ret->parent = def; 5346 ret->type = XML_RELAXNG_CHOICE; 5347 5348 if (node->children == NULL) { 5349 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY, 5350 "Element choice is empty\n", NULL, NULL); 5351 } else { 5352 5353 child = node->children; 5354 while (child != NULL) { 5355 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret); 5356 if (tmp != NULL) { 5357 if (last == NULL) { 5358 last = ret->nameClass = tmp; 5359 } else { 5360 last->next = tmp; 5361 last = tmp; 5362 } 5363 } 5364 child = child->next; 5365 } 5366 } 5367 } else { 5368 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT, 5369 "expecting name, anyName, nsName or choice : got %s\n", 5370 (node == NULL ? (const xmlChar *) "nothing" : node->name), 5371 NULL); 5372 return (NULL); 5373 } 5374 if (ret != def) { 5375 if (def->nameClass == NULL) { 5376 def->nameClass = ret; 5377 } else { 5378 tmp = def->nameClass; 5379 while (tmp->next != NULL) { 5380 tmp = tmp->next; 5381 } 5382 tmp->next = ret; 5383 } 5384 } 5385 return (ret); 5386} 5387 5388/** 5389 * xmlRelaxNGParseElement: 5390 * @ctxt: a Relax-NG parser context 5391 * @node: the element node 5392 * 5393 * parse the content of a RelaxNG element node. 5394 * 5395 * Returns the definition pointer or NULL in case of error. 5396 */ 5397static xmlRelaxNGDefinePtr 5398xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 5399{ 5400 xmlRelaxNGDefinePtr ret, cur, last; 5401 xmlNodePtr child; 5402 const xmlChar *olddefine; 5403 5404 ret = xmlRelaxNGNewDefine(ctxt, node); 5405 if (ret == NULL) 5406 return (NULL); 5407 ret->type = XML_RELAXNG_ELEMENT; 5408 ret->parent = ctxt->def; 5409 child = node->children; 5410 if (child == NULL) { 5411 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY, 5412 "xmlRelaxNGParseElement: element has no children\n", 5413 NULL, NULL); 5414 return (ret); 5415 } 5416 cur = xmlRelaxNGParseNameClass(ctxt, child, ret); 5417 if (cur != NULL) 5418 child = child->next; 5419 5420 if (child == NULL) { 5421 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT, 5422 "xmlRelaxNGParseElement: element has no content\n", 5423 NULL, NULL); 5424 return (ret); 5425 } 5426 olddefine = ctxt->define; 5427 ctxt->define = NULL; 5428 last = NULL; 5429 while (child != NULL) { 5430 cur = xmlRelaxNGParsePattern(ctxt, child); 5431 if (cur != NULL) { 5432 cur->parent = ret; 5433 switch (cur->type) { 5434 case XML_RELAXNG_EMPTY: 5435 case XML_RELAXNG_NOT_ALLOWED: 5436 case XML_RELAXNG_TEXT: 5437 case XML_RELAXNG_ELEMENT: 5438 case XML_RELAXNG_DATATYPE: 5439 case XML_RELAXNG_VALUE: 5440 case XML_RELAXNG_LIST: 5441 case XML_RELAXNG_REF: 5442 case XML_RELAXNG_PARENTREF: 5443 case XML_RELAXNG_EXTERNALREF: 5444 case XML_RELAXNG_DEF: 5445 case XML_RELAXNG_ZEROORMORE: 5446 case XML_RELAXNG_ONEORMORE: 5447 case XML_RELAXNG_OPTIONAL: 5448 case XML_RELAXNG_CHOICE: 5449 case XML_RELAXNG_GROUP: 5450 case XML_RELAXNG_INTERLEAVE: 5451 if (last == NULL) { 5452 ret->content = last = cur; 5453 } else { 5454 if ((last->type == XML_RELAXNG_ELEMENT) && 5455 (ret->content == last)) { 5456 ret->content = xmlRelaxNGNewDefine(ctxt, node); 5457 if (ret->content != NULL) { 5458 ret->content->type = XML_RELAXNG_GROUP; 5459 ret->content->content = last; 5460 } else { 5461 ret->content = last; 5462 } 5463 } 5464 last->next = cur; 5465 last = cur; 5466 } 5467 break; 5468 case XML_RELAXNG_ATTRIBUTE: 5469 cur->next = ret->attrs; 5470 ret->attrs = cur; 5471 break; 5472 case XML_RELAXNG_START: 5473 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5474 "RNG Internal error, start found in element\n", 5475 NULL, NULL); 5476 break; 5477 case XML_RELAXNG_PARAM: 5478 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5479 "RNG Internal error, param found in element\n", 5480 NULL, NULL); 5481 break; 5482 case XML_RELAXNG_EXCEPT: 5483 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5484 "RNG Internal error, except found in element\n", 5485 NULL, NULL); 5486 break; 5487 case XML_RELAXNG_NOOP: 5488 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, 5489 "RNG Internal error, noop found in element\n", 5490 NULL, NULL); 5491 break; 5492 } 5493 } 5494 child = child->next; 5495 } 5496 ctxt->define = olddefine; 5497 return (ret); 5498} 5499 5500/** 5501 * xmlRelaxNGParsePatterns: 5502 * @ctxt: a Relax-NG parser context 5503 * @nodes: list of nodes 5504 * @group: use an implicit <group> for elements 5505 * 5506 * parse the content of a RelaxNG start node. 5507 * 5508 * Returns the definition pointer or NULL in case of error. 5509 */ 5510static xmlRelaxNGDefinePtr 5511xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, 5512 int group) 5513{ 5514 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent; 5515 5516 parent = ctxt->def; 5517 while (nodes != NULL) { 5518 if (IS_RELAXNG(nodes, "element")) { 5519 cur = xmlRelaxNGParseElement(ctxt, nodes); 5520 if (def == NULL) { 5521 def = last = cur; 5522 } else { 5523 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) && 5524 (def == last)) { 5525 def = xmlRelaxNGNewDefine(ctxt, nodes); 5526 def->type = XML_RELAXNG_GROUP; 5527 def->content = last; 5528 } 5529 last->next = cur; 5530 last = cur; 5531 } 5532 cur->parent = parent; 5533 } else { 5534 cur = xmlRelaxNGParsePattern(ctxt, nodes); 5535 if (cur != NULL) { 5536 if (def == NULL) { 5537 def = last = cur; 5538 } else { 5539 last->next = cur; 5540 last = cur; 5541 } 5542 } 5543 } 5544 nodes = nodes->next; 5545 } 5546 return (def); 5547} 5548 5549/** 5550 * xmlRelaxNGParseStart: 5551 * @ctxt: a Relax-NG parser context 5552 * @nodes: start children nodes 5553 * 5554 * parse the content of a RelaxNG start node. 5555 * 5556 * Returns 0 in case of success, -1 in case of error 5557 */ 5558static int 5559xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 5560{ 5561 int ret = 0; 5562 xmlRelaxNGDefinePtr def = NULL, last; 5563 5564 if (nodes == NULL) { 5565 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n", 5566 NULL, NULL); 5567 return (-1); 5568 } 5569 if (IS_RELAXNG(nodes, "empty")) { 5570 def = xmlRelaxNGNewDefine(ctxt, nodes); 5571 if (def == NULL) 5572 return (-1); 5573 def->type = XML_RELAXNG_EMPTY; 5574 if (nodes->children != NULL) { 5575 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT, 5576 "element empty is not empty\n", NULL, NULL); 5577 } 5578 } else if (IS_RELAXNG(nodes, "notAllowed")) { 5579 def = xmlRelaxNGNewDefine(ctxt, nodes); 5580 if (def == NULL) 5581 return (-1); 5582 def->type = XML_RELAXNG_NOT_ALLOWED; 5583 if (nodes->children != NULL) { 5584 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY, 5585 "element notAllowed is not empty\n", NULL, NULL); 5586 } 5587 } else { 5588 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1); 5589 } 5590 if (ctxt->grammar->start != NULL) { 5591 last = ctxt->grammar->start; 5592 while (last->next != NULL) 5593 last = last->next; 5594 last->next = def; 5595 } else { 5596 ctxt->grammar->start = def; 5597 } 5598 nodes = nodes->next; 5599 if (nodes != NULL) { 5600 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT, 5601 "start more than one children\n", NULL, NULL); 5602 return (-1); 5603 } 5604 return (ret); 5605} 5606 5607/** 5608 * xmlRelaxNGParseGrammarContent: 5609 * @ctxt: a Relax-NG parser context 5610 * @nodes: grammar children nodes 5611 * 5612 * parse the content of a RelaxNG grammar node. 5613 * 5614 * Returns 0 in case of success, -1 in case of error 5615 */ 5616static int 5617xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 5618 xmlNodePtr nodes) 5619{ 5620 int ret = 0, tmp; 5621 5622 if (nodes == NULL) { 5623 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY, 5624 "grammar has no children\n", NULL, NULL); 5625 return (-1); 5626 } 5627 while (nodes != NULL) { 5628 if (IS_RELAXNG(nodes, "start")) { 5629 if (nodes->children == NULL) { 5630 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, 5631 "start has no children\n", NULL, NULL); 5632 } else { 5633 tmp = xmlRelaxNGParseStart(ctxt, nodes->children); 5634 if (tmp != 0) 5635 ret = -1; 5636 } 5637 } else if (IS_RELAXNG(nodes, "define")) { 5638 tmp = xmlRelaxNGParseDefine(ctxt, nodes); 5639 if (tmp != 0) 5640 ret = -1; 5641 } else if (IS_RELAXNG(nodes, "include")) { 5642 tmp = xmlRelaxNGParseInclude(ctxt, nodes); 5643 if (tmp != 0) 5644 ret = -1; 5645 } else { 5646 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 5647 "grammar has unexpected child %s\n", nodes->name, 5648 NULL); 5649 ret = -1; 5650 } 5651 nodes = nodes->next; 5652 } 5653 return (ret); 5654} 5655 5656/** 5657 * xmlRelaxNGCheckReference: 5658 * @ref: the ref 5659 * @ctxt: a Relax-NG parser context 5660 * @name: the name associated to the defines 5661 * 5662 * Applies the 4.17. combine attribute rule for all the define 5663 * element of a given grammar using the same name. 5664 */ 5665static void 5666xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref, 5667 xmlRelaxNGParserCtxtPtr ctxt, 5668 const xmlChar * name) 5669{ 5670 xmlRelaxNGGrammarPtr grammar; 5671 xmlRelaxNGDefinePtr def, cur; 5672 5673 /* 5674 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef 5675 */ 5676 if (ref->dflags & IS_EXTERNAL_REF) 5677 return; 5678 5679 grammar = ctxt->grammar; 5680 if (grammar == NULL) { 5681 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5682 "Internal error: no grammar in CheckReference %s\n", 5683 name, NULL); 5684 return; 5685 } 5686 if (ref->content != NULL) { 5687 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, 5688 "Internal error: reference has content in CheckReference %s\n", 5689 name, NULL); 5690 return; 5691 } 5692 if (grammar->defs != NULL) { 5693 def = xmlHashLookup(grammar->defs, name); 5694 if (def != NULL) { 5695 cur = ref; 5696 while (cur != NULL) { 5697 cur->content = def; 5698 cur = cur->nextHash; 5699 } 5700 } else { 5701 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5702 "Reference %s has no matching definition\n", name, 5703 NULL); 5704 } 5705 } else { 5706 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, 5707 "Reference %s has no matching definition\n", name, 5708 NULL); 5709 } 5710} 5711 5712/** 5713 * xmlRelaxNGCheckCombine: 5714 * @define: the define(s) list 5715 * @ctxt: a Relax-NG parser context 5716 * @name: the name associated to the defines 5717 * 5718 * Applies the 4.17. combine attribute rule for all the define 5719 * element of a given grammar using the same name. 5720 */ 5721static void 5722xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define, 5723 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name) 5724{ 5725 xmlChar *combine; 5726 int choiceOrInterleave = -1; 5727 int missing = 0; 5728 xmlRelaxNGDefinePtr cur, last, tmp, tmp2; 5729 5730 if (define->nextHash == NULL) 5731 return; 5732 cur = define; 5733 while (cur != NULL) { 5734 combine = xmlGetProp(cur->node, BAD_CAST "combine"); 5735 if (combine != NULL) { 5736 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5737 if (choiceOrInterleave == -1) 5738 choiceOrInterleave = 1; 5739 else if (choiceOrInterleave == 0) { 5740 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5741 "Defines for %s use both 'choice' and 'interleave'\n", 5742 name, NULL); 5743 } 5744 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5745 if (choiceOrInterleave == -1) 5746 choiceOrInterleave = 0; 5747 else if (choiceOrInterleave == 1) { 5748 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, 5749 "Defines for %s use both 'choice' and 'interleave'\n", 5750 name, NULL); 5751 } 5752 } else { 5753 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE, 5754 "Defines for %s use unknown combine value '%s''\n", 5755 name, combine); 5756 } 5757 xmlFree(combine); 5758 } else { 5759 if (missing == 0) 5760 missing = 1; 5761 else { 5762 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE, 5763 "Some defines for %s needs the combine attribute\n", 5764 name, NULL); 5765 } 5766 } 5767 5768 cur = cur->nextHash; 5769 } 5770#ifdef DEBUG 5771 xmlGenericError(xmlGenericErrorContext, 5772 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", 5773 name, choiceOrInterleave); 5774#endif 5775 if (choiceOrInterleave == -1) 5776 choiceOrInterleave = 0; 5777 cur = xmlRelaxNGNewDefine(ctxt, define->node); 5778 if (cur == NULL) 5779 return; 5780 if (choiceOrInterleave == 0) 5781 cur->type = XML_RELAXNG_INTERLEAVE; 5782 else 5783 cur->type = XML_RELAXNG_CHOICE; 5784 tmp = define; 5785 last = NULL; 5786 while (tmp != NULL) { 5787 if (tmp->content != NULL) { 5788 if (tmp->content->next != NULL) { 5789 /* 5790 * we need first to create a wrapper. 5791 */ 5792 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node); 5793 if (tmp2 == NULL) 5794 break; 5795 tmp2->type = XML_RELAXNG_GROUP; 5796 tmp2->content = tmp->content; 5797 } else { 5798 tmp2 = tmp->content; 5799 } 5800 if (last == NULL) { 5801 cur->content = tmp2; 5802 } else { 5803 last->next = tmp2; 5804 } 5805 last = tmp2; 5806 } 5807 tmp->content = cur; 5808 tmp = tmp->nextHash; 5809 } 5810 define->content = cur; 5811 if (choiceOrInterleave == 0) { 5812 if (ctxt->interleaves == NULL) 5813 ctxt->interleaves = xmlHashCreate(10); 5814 if (ctxt->interleaves == NULL) { 5815 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5816 "Failed to create interleaves hash table\n", NULL, 5817 NULL); 5818 } else { 5819 char tmpname[32]; 5820 5821 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5822 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5823 0) { 5824 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5825 "Failed to add %s to hash table\n", 5826 (const xmlChar *) tmpname, NULL); 5827 } 5828 } 5829 } 5830} 5831 5832/** 5833 * xmlRelaxNGCombineStart: 5834 * @ctxt: a Relax-NG parser context 5835 * @grammar: the grammar 5836 * 5837 * Applies the 4.17. combine rule for all the start 5838 * element of a given grammar. 5839 */ 5840static void 5841xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, 5842 xmlRelaxNGGrammarPtr grammar) 5843{ 5844 xmlRelaxNGDefinePtr starts; 5845 xmlChar *combine; 5846 int choiceOrInterleave = -1; 5847 int missing = 0; 5848 xmlRelaxNGDefinePtr cur; 5849 5850 starts = grammar->start; 5851 if ((starts == NULL) || (starts->next == NULL)) 5852 return; 5853 cur = starts; 5854 while (cur != NULL) { 5855 if ((cur->node == NULL) || (cur->node->parent == NULL) || 5856 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) { 5857 combine = NULL; 5858 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING, 5859 "Internal error: start element not found\n", NULL, 5860 NULL); 5861 } else { 5862 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine"); 5863 } 5864 5865 if (combine != NULL) { 5866 if (xmlStrEqual(combine, BAD_CAST "choice")) { 5867 if (choiceOrInterleave == -1) 5868 choiceOrInterleave = 1; 5869 else if (choiceOrInterleave == 0) { 5870 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5871 "<start> use both 'choice' and 'interleave'\n", 5872 NULL, NULL); 5873 } 5874 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { 5875 if (choiceOrInterleave == -1) 5876 choiceOrInterleave = 0; 5877 else if (choiceOrInterleave == 1) { 5878 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, 5879 "<start> use both 'choice' and 'interleave'\n", 5880 NULL, NULL); 5881 } 5882 } else { 5883 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE, 5884 "<start> uses unknown combine value '%s''\n", 5885 combine, NULL); 5886 } 5887 xmlFree(combine); 5888 } else { 5889 if (missing == 0) 5890 missing = 1; 5891 else { 5892 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE, 5893 "Some <start> element miss the combine attribute\n", 5894 NULL, NULL); 5895 } 5896 } 5897 5898 cur = cur->next; 5899 } 5900#ifdef DEBUG 5901 xmlGenericError(xmlGenericErrorContext, 5902 "xmlRelaxNGCombineStart(): merging <start>: %d\n", 5903 choiceOrInterleave); 5904#endif 5905 if (choiceOrInterleave == -1) 5906 choiceOrInterleave = 0; 5907 cur = xmlRelaxNGNewDefine(ctxt, starts->node); 5908 if (cur == NULL) 5909 return; 5910 if (choiceOrInterleave == 0) 5911 cur->type = XML_RELAXNG_INTERLEAVE; 5912 else 5913 cur->type = XML_RELAXNG_CHOICE; 5914 cur->content = grammar->start; 5915 grammar->start = cur; 5916 if (choiceOrInterleave == 0) { 5917 if (ctxt->interleaves == NULL) 5918 ctxt->interleaves = xmlHashCreate(10); 5919 if (ctxt->interleaves == NULL) { 5920 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5921 "Failed to create interleaves hash table\n", NULL, 5922 NULL); 5923 } else { 5924 char tmpname[32]; 5925 5926 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); 5927 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 5928 0) { 5929 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, 5930 "Failed to add %s to hash table\n", 5931 (const xmlChar *) tmpname, NULL); 5932 } 5933 } 5934 } 5935} 5936 5937/** 5938 * xmlRelaxNGCheckCycles: 5939 * @ctxt: a Relax-NG parser context 5940 * @nodes: grammar children nodes 5941 * @depth: the counter 5942 * 5943 * Check for cycles. 5944 * 5945 * Returns 0 if check passed, and -1 in case of error 5946 */ 5947static int 5948xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 5949 xmlRelaxNGDefinePtr cur, int depth) 5950{ 5951 int ret = 0; 5952 5953 while ((ret == 0) && (cur != NULL)) { 5954 if ((cur->type == XML_RELAXNG_REF) || 5955 (cur->type == XML_RELAXNG_PARENTREF)) { 5956 if (cur->depth == -1) { 5957 cur->depth = depth; 5958 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 5959 cur->depth = -2; 5960 } else if (depth == cur->depth) { 5961 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE, 5962 "Detected a cycle in %s references\n", 5963 cur->name, NULL); 5964 return (-1); 5965 } 5966 } else if (cur->type == XML_RELAXNG_ELEMENT) { 5967 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1); 5968 } else { 5969 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); 5970 } 5971 cur = cur->next; 5972 } 5973 return (ret); 5974} 5975 5976/** 5977 * xmlRelaxNGTryUnlink: 5978 * @ctxt: a Relax-NG parser context 5979 * @cur: the definition to unlink 5980 * @parent: the parent definition 5981 * @prev: the previous sibling definition 5982 * 5983 * Try to unlink a definition. If not possble make it a NOOP 5984 * 5985 * Returns the new prev definition 5986 */ 5987static xmlRelaxNGDefinePtr 5988xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 5989 xmlRelaxNGDefinePtr cur, 5990 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev) 5991{ 5992 if (prev != NULL) { 5993 prev->next = cur->next; 5994 } else { 5995 if (parent != NULL) { 5996 if (parent->content == cur) 5997 parent->content = cur->next; 5998 else if (parent->attrs == cur) 5999 parent->attrs = cur->next; 6000 else if (parent->nameClass == cur) 6001 parent->nameClass = cur->next; 6002 } else { 6003 cur->type = XML_RELAXNG_NOOP; 6004 prev = cur; 6005 } 6006 } 6007 return (prev); 6008} 6009 6010/** 6011 * xmlRelaxNGSimplify: 6012 * @ctxt: a Relax-NG parser context 6013 * @nodes: grammar children nodes 6014 * 6015 * Check for simplification of empty and notAllowed 6016 */ 6017static void 6018xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, 6019 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent) 6020{ 6021 xmlRelaxNGDefinePtr prev = NULL; 6022 6023 while (cur != NULL) { 6024 if ((cur->type == XML_RELAXNG_REF) || 6025 (cur->type == XML_RELAXNG_PARENTREF)) { 6026 if (cur->depth != -3) { 6027 cur->depth = -3; 6028 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6029 } 6030 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6031 cur->parent = parent; 6032 if ((parent != NULL) && 6033 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6034 (parent->type == XML_RELAXNG_LIST) || 6035 (parent->type == XML_RELAXNG_GROUP) || 6036 (parent->type == XML_RELAXNG_INTERLEAVE) || 6037 (parent->type == XML_RELAXNG_ONEORMORE) || 6038 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6039 parent->type = XML_RELAXNG_NOT_ALLOWED; 6040 break; 6041 } 6042 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) { 6043 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6044 } else 6045 prev = cur; 6046 } else if (cur->type == XML_RELAXNG_EMPTY) { 6047 cur->parent = parent; 6048 if ((parent != NULL) && 6049 ((parent->type == XML_RELAXNG_ONEORMORE) || 6050 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6051 parent->type = XML_RELAXNG_EMPTY; 6052 break; 6053 } 6054 if ((parent != NULL) && 6055 ((parent->type == XML_RELAXNG_GROUP) || 6056 (parent->type == XML_RELAXNG_INTERLEAVE))) { 6057 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6058 } else 6059 prev = cur; 6060 } else { 6061 cur->parent = parent; 6062 if (cur->content != NULL) 6063 xmlRelaxNGSimplify(ctxt, cur->content, cur); 6064 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL)) 6065 xmlRelaxNGSimplify(ctxt, cur->attrs, cur); 6066 if (cur->nameClass != NULL) 6067 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur); 6068 /* 6069 * On Elements, try to move attribute only generating rules on 6070 * the attrs rules. 6071 */ 6072 if (cur->type == XML_RELAXNG_ELEMENT) { 6073 int attronly; 6074 xmlRelaxNGDefinePtr tmp, pre; 6075 6076 while (cur->content != NULL) { 6077 attronly = 6078 xmlRelaxNGGenerateAttributes(ctxt, cur->content); 6079 if (attronly == 1) { 6080 /* 6081 * migrate cur->content to attrs 6082 */ 6083 tmp = cur->content; 6084 cur->content = tmp->next; 6085 tmp->next = cur->attrs; 6086 cur->attrs = tmp; 6087 } else { 6088 /* 6089 * cur->content can generate elements or text 6090 */ 6091 break; 6092 } 6093 } 6094 pre = cur->content; 6095 while ((pre != NULL) && (pre->next != NULL)) { 6096 tmp = pre->next; 6097 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp); 6098 if (attronly == 1) { 6099 /* 6100 * migrate tmp to attrs 6101 */ 6102 pre->next = tmp->next; 6103 tmp->next = cur->attrs; 6104 cur->attrs = tmp; 6105 } else { 6106 pre = tmp; 6107 } 6108 } 6109 } 6110 /* 6111 * This may result in a simplification 6112 */ 6113 if ((cur->type == XML_RELAXNG_GROUP) || 6114 (cur->type == XML_RELAXNG_INTERLEAVE)) { 6115 if (cur->content == NULL) 6116 cur->type = XML_RELAXNG_EMPTY; 6117 else if (cur->content->next == NULL) { 6118 if ((parent == NULL) && (prev == NULL)) { 6119 cur->type = XML_RELAXNG_NOOP; 6120 } else if (prev == NULL) { 6121 parent->content = cur->content; 6122 cur->content->next = cur->next; 6123 cur = cur->content; 6124 } else { 6125 cur->content->next = cur->next; 6126 prev->next = cur->content; 6127 cur = cur->content; 6128 } 6129 } 6130 } 6131 /* 6132 * the current node may have been transformed back 6133 */ 6134 if ((cur->type == XML_RELAXNG_EXCEPT) && 6135 (cur->content != NULL) && 6136 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) { 6137 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6138 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { 6139 if ((parent != NULL) && 6140 ((parent->type == XML_RELAXNG_ATTRIBUTE) || 6141 (parent->type == XML_RELAXNG_LIST) || 6142 (parent->type == XML_RELAXNG_GROUP) || 6143 (parent->type == XML_RELAXNG_INTERLEAVE) || 6144 (parent->type == XML_RELAXNG_ONEORMORE) || 6145 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6146 parent->type = XML_RELAXNG_NOT_ALLOWED; 6147 break; 6148 } 6149 if ((parent != NULL) && 6150 (parent->type == XML_RELAXNG_CHOICE)) { 6151 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6152 } else 6153 prev = cur; 6154 } else if (cur->type == XML_RELAXNG_EMPTY) { 6155 if ((parent != NULL) && 6156 ((parent->type == XML_RELAXNG_ONEORMORE) || 6157 (parent->type == XML_RELAXNG_ZEROORMORE))) { 6158 parent->type = XML_RELAXNG_EMPTY; 6159 break; 6160 } 6161 if ((parent != NULL) && 6162 ((parent->type == XML_RELAXNG_GROUP) || 6163 (parent->type == XML_RELAXNG_INTERLEAVE) || 6164 (parent->type == XML_RELAXNG_CHOICE))) { 6165 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); 6166 } else 6167 prev = cur; 6168 } else { 6169 prev = cur; 6170 } 6171 } 6172 cur = cur->next; 6173 } 6174} 6175 6176/** 6177 * xmlRelaxNGGroupContentType: 6178 * @ct1: the first content type 6179 * @ct2: the second content type 6180 * 6181 * Try to group 2 content types 6182 * 6183 * Returns the content type 6184 */ 6185static xmlRelaxNGContentType 6186xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1, 6187 xmlRelaxNGContentType ct2) 6188{ 6189 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6190 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6191 return (XML_RELAXNG_CONTENT_ERROR); 6192 if (ct1 == XML_RELAXNG_CONTENT_EMPTY) 6193 return (ct2); 6194 if (ct2 == XML_RELAXNG_CONTENT_EMPTY) 6195 return (ct1); 6196 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) && 6197 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6198 return (XML_RELAXNG_CONTENT_COMPLEX); 6199 return (XML_RELAXNG_CONTENT_ERROR); 6200} 6201 6202/** 6203 * xmlRelaxNGMaxContentType: 6204 * @ct1: the first content type 6205 * @ct2: the second content type 6206 * 6207 * Compute the max content-type 6208 * 6209 * Returns the content type 6210 */ 6211static xmlRelaxNGContentType 6212xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1, 6213 xmlRelaxNGContentType ct2) 6214{ 6215 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || 6216 (ct2 == XML_RELAXNG_CONTENT_ERROR)) 6217 return (XML_RELAXNG_CONTENT_ERROR); 6218 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) || 6219 (ct2 == XML_RELAXNG_CONTENT_SIMPLE)) 6220 return (XML_RELAXNG_CONTENT_SIMPLE); 6221 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) || 6222 (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) 6223 return (XML_RELAXNG_CONTENT_COMPLEX); 6224 return (XML_RELAXNG_CONTENT_EMPTY); 6225} 6226 6227/** 6228 * xmlRelaxNGCheckRules: 6229 * @ctxt: a Relax-NG parser context 6230 * @cur: the current definition 6231 * @flags: some accumulated flags 6232 * @ptype: the parent type 6233 * 6234 * Check for rules in section 7.1 and 7.2 6235 * 6236 * Returns the content type of @cur 6237 */ 6238static xmlRelaxNGContentType 6239xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, 6240 xmlRelaxNGDefinePtr cur, int flags, 6241 xmlRelaxNGType ptype) 6242{ 6243 int nflags; 6244 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY; 6245 6246 while (cur != NULL) { 6247 ret = XML_RELAXNG_CONTENT_EMPTY; 6248 if ((cur->type == XML_RELAXNG_REF) || 6249 (cur->type == XML_RELAXNG_PARENTREF)) { 6250 /* 6251 * This should actually be caught by list//element(ref) at the 6252 * element boundaries, c.f. Bug #159968 local refs are dropped 6253 * in step 4.19. 6254 */ 6255#if 0 6256 if (flags & XML_RELAXNG_IN_LIST) { 6257 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF, 6258 "Found forbidden pattern list//ref\n", NULL, 6259 NULL); 6260 } 6261#endif 6262 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6263 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF, 6264 "Found forbidden pattern data/except//ref\n", 6265 NULL, NULL); 6266 } 6267 if (cur->content == NULL) { 6268 if (cur->type == XML_RELAXNG_PARENTREF) 6269 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6270 "Internal found no define for parent refs\n", 6271 NULL, NULL); 6272 else 6273 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, 6274 "Internal found no define for ref %s\n", 6275 (cur->name ? cur->name: BAD_CAST "null"), NULL); 6276 } 6277 if (cur->depth > -4) { 6278 cur->depth = -4; 6279 ret = xmlRelaxNGCheckRules(ctxt, cur->content, 6280 flags, cur->type); 6281 cur->depth = ret - 15; 6282 } else if (cur->depth == -4) { 6283 ret = XML_RELAXNG_CONTENT_COMPLEX; 6284 } else { 6285 ret = (xmlRelaxNGContentType) (cur->depth + 15); 6286 } 6287 } else if (cur->type == XML_RELAXNG_ELEMENT) { 6288 /* 6289 * The 7.3 Attribute derivation rule for groups is plugged there 6290 */ 6291 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6292 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6293 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM, 6294 "Found forbidden pattern data/except//element(ref)\n", 6295 NULL, NULL); 6296 } 6297 if (flags & XML_RELAXNG_IN_LIST) { 6298 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM, 6299 "Found forbidden pattern list//element(ref)\n", 6300 NULL, NULL); 6301 } 6302 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6303 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6304 "Found forbidden pattern attribute//element(ref)\n", 6305 NULL, NULL); 6306 } 6307 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6308 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, 6309 "Found forbidden pattern attribute//element(ref)\n", 6310 NULL, NULL); 6311 } 6312 /* 6313 * reset since in the simple form elements are only child 6314 * of grammar/define 6315 */ 6316 nflags = 0; 6317 ret = 6318 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type); 6319 if (ret != XML_RELAXNG_CONTENT_EMPTY) { 6320 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY, 6321 "Element %s attributes have a content type error\n", 6322 cur->name, NULL); 6323 } 6324 ret = 6325 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6326 cur->type); 6327 if (ret == XML_RELAXNG_CONTENT_ERROR) { 6328 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR, 6329 "Element %s has a content type error\n", 6330 cur->name, NULL); 6331 } else { 6332 ret = XML_RELAXNG_CONTENT_COMPLEX; 6333 } 6334 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) { 6335 if (flags & XML_RELAXNG_IN_ATTRIBUTE) { 6336 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR, 6337 "Found forbidden pattern attribute//attribute\n", 6338 NULL, NULL); 6339 } 6340 if (flags & XML_RELAXNG_IN_LIST) { 6341 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR, 6342 "Found forbidden pattern list//attribute\n", 6343 NULL, NULL); 6344 } 6345 if (flags & XML_RELAXNG_IN_OOMGROUP) { 6346 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR, 6347 "Found forbidden pattern oneOrMore//group//attribute\n", 6348 NULL, NULL); 6349 } 6350 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) { 6351 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, 6352 "Found forbidden pattern oneOrMore//interleave//attribute\n", 6353 NULL, NULL); 6354 } 6355 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6356 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR, 6357 "Found forbidden pattern data/except//attribute\n", 6358 NULL, NULL); 6359 } 6360 if (flags & XML_RELAXNG_IN_START) { 6361 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR, 6362 "Found forbidden pattern start//attribute\n", 6363 NULL, NULL); 6364 } 6365 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) 6366 && (cur->name == NULL)) { 6367 if (cur->ns == NULL) { 6368 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR, 6369 "Found anyName attribute without oneOrMore ancestor\n", 6370 NULL, NULL); 6371 } else { 6372 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR, 6373 "Found nsName attribute without oneOrMore ancestor\n", 6374 NULL, NULL); 6375 } 6376 } 6377 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE; 6378 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); 6379 ret = XML_RELAXNG_CONTENT_EMPTY; 6380 } else if ((cur->type == XML_RELAXNG_ONEORMORE) || 6381 (cur->type == XML_RELAXNG_ZEROORMORE)) { 6382 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6383 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, 6384 "Found forbidden pattern data/except//oneOrMore\n", 6385 NULL, NULL); 6386 } 6387 if (flags & XML_RELAXNG_IN_START) { 6388 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE, 6389 "Found forbidden pattern start//oneOrMore\n", 6390 NULL, NULL); 6391 } 6392 nflags = flags | XML_RELAXNG_IN_ONEORMORE; 6393 ret = 6394 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6395 cur->type); 6396 ret = xmlRelaxNGGroupContentType(ret, ret); 6397 } else if (cur->type == XML_RELAXNG_LIST) { 6398 if (flags & XML_RELAXNG_IN_LIST) { 6399 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST, 6400 "Found forbidden pattern list//list\n", NULL, 6401 NULL); 6402 } 6403 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6404 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST, 6405 "Found forbidden pattern data/except//list\n", 6406 NULL, NULL); 6407 } 6408 if (flags & XML_RELAXNG_IN_START) { 6409 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST, 6410 "Found forbidden pattern start//list\n", NULL, 6411 NULL); 6412 } 6413 nflags = flags | XML_RELAXNG_IN_LIST; 6414 ret = 6415 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6416 cur->type); 6417 } else if (cur->type == XML_RELAXNG_GROUP) { 6418 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6419 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP, 6420 "Found forbidden pattern data/except//group\n", 6421 NULL, NULL); 6422 } 6423 if (flags & XML_RELAXNG_IN_START) { 6424 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP, 6425 "Found forbidden pattern start//group\n", NULL, 6426 NULL); 6427 } 6428 if (flags & XML_RELAXNG_IN_ONEORMORE) 6429 nflags = flags | XML_RELAXNG_IN_OOMGROUP; 6430 else 6431 nflags = flags; 6432 ret = 6433 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6434 cur->type); 6435 /* 6436 * The 7.3 Attribute derivation rule for groups is plugged there 6437 */ 6438 xmlRelaxNGCheckGroupAttrs(ctxt, cur); 6439 } else if (cur->type == XML_RELAXNG_INTERLEAVE) { 6440 if (flags & XML_RELAXNG_IN_LIST) { 6441 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE, 6442 "Found forbidden pattern list//interleave\n", 6443 NULL, NULL); 6444 } 6445 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6446 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6447 "Found forbidden pattern data/except//interleave\n", 6448 NULL, NULL); 6449 } 6450 if (flags & XML_RELAXNG_IN_START) { 6451 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, 6452 "Found forbidden pattern start//interleave\n", 6453 NULL, NULL); 6454 } 6455 if (flags & XML_RELAXNG_IN_ONEORMORE) 6456 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE; 6457 else 6458 nflags = flags; 6459 ret = 6460 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6461 cur->type); 6462 } else if (cur->type == XML_RELAXNG_EXCEPT) { 6463 if ((cur->parent != NULL) && 6464 (cur->parent->type == XML_RELAXNG_DATATYPE)) 6465 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT; 6466 else 6467 nflags = flags; 6468 ret = 6469 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, 6470 cur->type); 6471 } else if (cur->type == XML_RELAXNG_DATATYPE) { 6472 if (flags & XML_RELAXNG_IN_START) { 6473 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA, 6474 "Found forbidden pattern start//data\n", NULL, 6475 NULL); 6476 } 6477 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6478 ret = XML_RELAXNG_CONTENT_SIMPLE; 6479 } else if (cur->type == XML_RELAXNG_VALUE) { 6480 if (flags & XML_RELAXNG_IN_START) { 6481 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE, 6482 "Found forbidden pattern start//value\n", NULL, 6483 NULL); 6484 } 6485 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6486 ret = XML_RELAXNG_CONTENT_SIMPLE; 6487 } else if (cur->type == XML_RELAXNG_TEXT) { 6488 if (flags & XML_RELAXNG_IN_LIST) { 6489 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT, 6490 "Found forbidden pattern list//text\n", NULL, 6491 NULL); 6492 } 6493 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6494 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT, 6495 "Found forbidden pattern data/except//text\n", 6496 NULL, NULL); 6497 } 6498 if (flags & XML_RELAXNG_IN_START) { 6499 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT, 6500 "Found forbidden pattern start//text\n", NULL, 6501 NULL); 6502 } 6503 ret = XML_RELAXNG_CONTENT_COMPLEX; 6504 } else if (cur->type == XML_RELAXNG_EMPTY) { 6505 if (flags & XML_RELAXNG_IN_DATAEXCEPT) { 6506 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY, 6507 "Found forbidden pattern data/except//empty\n", 6508 NULL, NULL); 6509 } 6510 if (flags & XML_RELAXNG_IN_START) { 6511 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY, 6512 "Found forbidden pattern start//empty\n", NULL, 6513 NULL); 6514 } 6515 ret = XML_RELAXNG_CONTENT_EMPTY; 6516 } else if (cur->type == XML_RELAXNG_CHOICE) { 6517 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur); 6518 ret = 6519 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6520 } else { 6521 ret = 6522 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); 6523 } 6524 cur = cur->next; 6525 if (ptype == XML_RELAXNG_GROUP) { 6526 val = xmlRelaxNGGroupContentType(val, ret); 6527 } else if (ptype == XML_RELAXNG_INTERLEAVE) { 6528 /* 6529 * TODO: scan complain that tmp is never used, seems on purpose 6530 * need double-checking 6531 */ 6532 tmp = xmlRelaxNGGroupContentType(val, ret); 6533 if (tmp != XML_RELAXNG_CONTENT_ERROR) 6534 tmp = xmlRelaxNGMaxContentType(val, ret); 6535 } else if (ptype == XML_RELAXNG_CHOICE) { 6536 val = xmlRelaxNGMaxContentType(val, ret); 6537 } else if (ptype == XML_RELAXNG_LIST) { 6538 val = XML_RELAXNG_CONTENT_SIMPLE; 6539 } else if (ptype == XML_RELAXNG_EXCEPT) { 6540 if (ret == XML_RELAXNG_CONTENT_ERROR) 6541 val = XML_RELAXNG_CONTENT_ERROR; 6542 else 6543 val = XML_RELAXNG_CONTENT_SIMPLE; 6544 } else { 6545 val = xmlRelaxNGGroupContentType(val, ret); 6546 } 6547 6548 } 6549 return (val); 6550} 6551 6552/** 6553 * xmlRelaxNGParseGrammar: 6554 * @ctxt: a Relax-NG parser context 6555 * @nodes: grammar children nodes 6556 * 6557 * parse a Relax-NG <grammar> node 6558 * 6559 * Returns the internal xmlRelaxNGGrammarPtr built or 6560 * NULL in case of error 6561 */ 6562static xmlRelaxNGGrammarPtr 6563xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) 6564{ 6565 xmlRelaxNGGrammarPtr ret, tmp, old; 6566 6567#ifdef DEBUG_GRAMMAR 6568 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n"); 6569#endif 6570 6571 ret = xmlRelaxNGNewGrammar(ctxt); 6572 if (ret == NULL) 6573 return (NULL); 6574 6575 /* 6576 * Link the new grammar in the tree 6577 */ 6578 ret->parent = ctxt->grammar; 6579 if (ctxt->grammar != NULL) { 6580 tmp = ctxt->grammar->children; 6581 if (tmp == NULL) { 6582 ctxt->grammar->children = ret; 6583 } else { 6584 while (tmp->next != NULL) 6585 tmp = tmp->next; 6586 tmp->next = ret; 6587 } 6588 } 6589 6590 old = ctxt->grammar; 6591 ctxt->grammar = ret; 6592 xmlRelaxNGParseGrammarContent(ctxt, nodes); 6593 ctxt->grammar = ret; 6594 if (ctxt->grammar == NULL) { 6595 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, 6596 "Failed to parse <grammar> content\n", NULL, NULL); 6597 } else if (ctxt->grammar->start == NULL) { 6598 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START, 6599 "Element <grammar> has no <start>\n", NULL, NULL); 6600 } 6601 6602 /* 6603 * Apply 4.17 merging rules to defines and starts 6604 */ 6605 xmlRelaxNGCombineStart(ctxt, ret); 6606 if (ret->defs != NULL) { 6607 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine, 6608 ctxt); 6609 } 6610 6611 /* 6612 * link together defines and refs in this grammar 6613 */ 6614 if (ret->refs != NULL) { 6615 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference, 6616 ctxt); 6617 } 6618 6619 6620 /* @@@@ */ 6621 6622 ctxt->grammar = old; 6623 return (ret); 6624} 6625 6626/** 6627 * xmlRelaxNGParseDocument: 6628 * @ctxt: a Relax-NG parser context 6629 * @node: the root node of the RelaxNG schema 6630 * 6631 * parse a Relax-NG definition resource and build an internal 6632 * xmlRelaxNG struture which can be used to validate instances. 6633 * 6634 * Returns the internal XML RelaxNG structure built or 6635 * NULL in case of error 6636 */ 6637static xmlRelaxNGPtr 6638xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6639{ 6640 xmlRelaxNGPtr schema = NULL; 6641 const xmlChar *olddefine; 6642 xmlRelaxNGGrammarPtr old; 6643 6644 if ((ctxt == NULL) || (node == NULL)) 6645 return (NULL); 6646 6647 schema = xmlRelaxNGNewRelaxNG(ctxt); 6648 if (schema == NULL) 6649 return (NULL); 6650 6651 olddefine = ctxt->define; 6652 ctxt->define = NULL; 6653 if (IS_RELAXNG(node, "grammar")) { 6654 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children); 6655 if (schema->topgrammar == NULL) { 6656 xmlRelaxNGFree(schema); 6657 return (NULL); 6658 } 6659 } else { 6660 xmlRelaxNGGrammarPtr tmp, ret; 6661 6662 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt); 6663 if (schema->topgrammar == NULL) { 6664 xmlRelaxNGFree(schema); 6665 return (NULL); 6666 } 6667 /* 6668 * Link the new grammar in the tree 6669 */ 6670 ret->parent = ctxt->grammar; 6671 if (ctxt->grammar != NULL) { 6672 tmp = ctxt->grammar->children; 6673 if (tmp == NULL) { 6674 ctxt->grammar->children = ret; 6675 } else { 6676 while (tmp->next != NULL) 6677 tmp = tmp->next; 6678 tmp->next = ret; 6679 } 6680 } 6681 old = ctxt->grammar; 6682 ctxt->grammar = ret; 6683 xmlRelaxNGParseStart(ctxt, node); 6684 if (old != NULL) 6685 ctxt->grammar = old; 6686 } 6687 ctxt->define = olddefine; 6688 if (schema->topgrammar->start != NULL) { 6689 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0); 6690 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) { 6691 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL); 6692 while ((schema->topgrammar->start != NULL) && 6693 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) && 6694 (schema->topgrammar->start->next != NULL)) 6695 schema->topgrammar->start = 6696 schema->topgrammar->start->content; 6697 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start, 6698 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); 6699 } 6700 } 6701#ifdef DEBUG 6702 if (schema == NULL) 6703 xmlGenericError(xmlGenericErrorContext, 6704 "xmlRelaxNGParseDocument() failed\n"); 6705#endif 6706 6707 return (schema); 6708} 6709 6710/************************************************************************ 6711 * * 6712 * Reading RelaxNGs * 6713 * * 6714 ************************************************************************/ 6715 6716/** 6717 * xmlRelaxNGNewParserCtxt: 6718 * @URL: the location of the schema 6719 * 6720 * Create an XML RelaxNGs parse context for that file/resource expected 6721 * to contain an XML RelaxNGs file. 6722 * 6723 * Returns the parser context or NULL in case of error 6724 */ 6725xmlRelaxNGParserCtxtPtr 6726xmlRelaxNGNewParserCtxt(const char *URL) 6727{ 6728 xmlRelaxNGParserCtxtPtr ret; 6729 6730 if (URL == NULL) 6731 return (NULL); 6732 6733 ret = 6734 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6735 if (ret == NULL) { 6736 xmlRngPErrMemory(NULL, "building parser\n"); 6737 return (NULL); 6738 } 6739 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6740 ret->URL = xmlStrdup((const xmlChar *) URL); 6741 ret->error = xmlGenericError; 6742 ret->userData = xmlGenericErrorContext; 6743 return (ret); 6744} 6745 6746/** 6747 * xmlRelaxNGNewMemParserCtxt: 6748 * @buffer: a pointer to a char array containing the schemas 6749 * @size: the size of the array 6750 * 6751 * Create an XML RelaxNGs parse context for that memory buffer expected 6752 * to contain an XML RelaxNGs file. 6753 * 6754 * Returns the parser context or NULL in case of error 6755 */ 6756xmlRelaxNGParserCtxtPtr 6757xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) 6758{ 6759 xmlRelaxNGParserCtxtPtr ret; 6760 6761 if ((buffer == NULL) || (size <= 0)) 6762 return (NULL); 6763 6764 ret = 6765 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6766 if (ret == NULL) { 6767 xmlRngPErrMemory(NULL, "building parser\n"); 6768 return (NULL); 6769 } 6770 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6771 ret->buffer = buffer; 6772 ret->size = size; 6773 ret->error = xmlGenericError; 6774 ret->userData = xmlGenericErrorContext; 6775 return (ret); 6776} 6777 6778/** 6779 * xmlRelaxNGNewDocParserCtxt: 6780 * @doc: a preparsed document tree 6781 * 6782 * Create an XML RelaxNGs parser context for that document. 6783 * Note: since the process of compiling a RelaxNG schemas modifies the 6784 * document, the @doc parameter is duplicated internally. 6785 * 6786 * Returns the parser context or NULL in case of error 6787 */ 6788xmlRelaxNGParserCtxtPtr 6789xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) 6790{ 6791 xmlRelaxNGParserCtxtPtr ret; 6792 xmlDocPtr copy; 6793 6794 if (doc == NULL) 6795 return (NULL); 6796 copy = xmlCopyDoc(doc, 1); 6797 if (copy == NULL) 6798 return (NULL); 6799 6800 ret = 6801 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); 6802 if (ret == NULL) { 6803 xmlRngPErrMemory(NULL, "building parser\n"); 6804 return (NULL); 6805 } 6806 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); 6807 ret->document = copy; 6808 ret->freedoc = 1; 6809 ret->userData = xmlGenericErrorContext; 6810 return (ret); 6811} 6812 6813/** 6814 * xmlRelaxNGFreeParserCtxt: 6815 * @ctxt: the schema parser context 6816 * 6817 * Free the resources associated to the schema parser context 6818 */ 6819void 6820xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) 6821{ 6822 if (ctxt == NULL) 6823 return; 6824 if (ctxt->URL != NULL) 6825 xmlFree(ctxt->URL); 6826 if (ctxt->doc != NULL) 6827 xmlRelaxNGFreeDocument(ctxt->doc); 6828 if (ctxt->interleaves != NULL) 6829 xmlHashFree(ctxt->interleaves, NULL); 6830 if (ctxt->documents != NULL) 6831 xmlRelaxNGFreeDocumentList(ctxt->documents); 6832 if (ctxt->includes != NULL) 6833 xmlRelaxNGFreeIncludeList(ctxt->includes); 6834 if (ctxt->docTab != NULL) 6835 xmlFree(ctxt->docTab); 6836 if (ctxt->incTab != NULL) 6837 xmlFree(ctxt->incTab); 6838 if (ctxt->defTab != NULL) { 6839 int i; 6840 6841 for (i = 0; i < ctxt->defNr; i++) 6842 xmlRelaxNGFreeDefine(ctxt->defTab[i]); 6843 xmlFree(ctxt->defTab); 6844 } 6845 if ((ctxt->document != NULL) && (ctxt->freedoc)) 6846 xmlFreeDoc(ctxt->document); 6847 xmlFree(ctxt); 6848} 6849 6850/** 6851 * xmlRelaxNGNormExtSpace: 6852 * @value: a value 6853 * 6854 * Removes the leading and ending spaces of the value 6855 * The string is modified "in situ" 6856 */ 6857static void 6858xmlRelaxNGNormExtSpace(xmlChar * value) 6859{ 6860 xmlChar *start = value; 6861 xmlChar *cur = value; 6862 6863 if (value == NULL) 6864 return; 6865 6866 while (IS_BLANK_CH(*cur)) 6867 cur++; 6868 if (cur == start) { 6869 do { 6870 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6871 cur++; 6872 if (*cur == 0) 6873 return; 6874 start = cur; 6875 while (IS_BLANK_CH(*cur)) 6876 cur++; 6877 if (*cur == 0) { 6878 *start = 0; 6879 return; 6880 } 6881 } while (1); 6882 } else { 6883 do { 6884 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) 6885 *start++ = *cur++; 6886 if (*cur == 0) { 6887 *start = 0; 6888 return; 6889 } 6890 /* don't try to normalize the inner spaces */ 6891 while (IS_BLANK_CH(*cur)) 6892 cur++; 6893 if (*cur == 0) { 6894 *start = 0; 6895 return; 6896 } 6897 *start++ = *cur++; 6898 } while (1); 6899 } 6900} 6901 6902/** 6903 * xmlRelaxNGCleanupAttributes: 6904 * @ctxt: a Relax-NG parser context 6905 * @node: a Relax-NG node 6906 * 6907 * Check all the attributes on the given node 6908 */ 6909static void 6910xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 6911{ 6912 xmlAttrPtr cur, next; 6913 6914 cur = node->properties; 6915 while (cur != NULL) { 6916 next = cur->next; 6917 if ((cur->ns == NULL) || 6918 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 6919 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 6920 if ((!xmlStrEqual(node->name, BAD_CAST "element")) && 6921 (!xmlStrEqual(node->name, BAD_CAST "attribute")) && 6922 (!xmlStrEqual(node->name, BAD_CAST "ref")) && 6923 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) && 6924 (!xmlStrEqual(node->name, BAD_CAST "param")) && 6925 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 6926 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6927 "Attribute %s is not allowed on %s\n", 6928 cur->name, node->name); 6929 } 6930 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) { 6931 if ((!xmlStrEqual(node->name, BAD_CAST "value")) && 6932 (!xmlStrEqual(node->name, BAD_CAST "data"))) { 6933 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6934 "Attribute %s is not allowed on %s\n", 6935 cur->name, node->name); 6936 } 6937 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) { 6938 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) && 6939 (!xmlStrEqual(node->name, BAD_CAST "include"))) { 6940 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6941 "Attribute %s is not allowed on %s\n", 6942 cur->name, node->name); 6943 } 6944 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) { 6945 if ((!xmlStrEqual(node->name, BAD_CAST "start")) && 6946 (!xmlStrEqual(node->name, BAD_CAST "define"))) { 6947 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, 6948 "Attribute %s is not allowed on %s\n", 6949 cur->name, node->name); 6950 } 6951 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) { 6952 xmlChar *val; 6953 xmlURIPtr uri; 6954 6955 val = xmlNodeListGetString(node->doc, cur->children, 1); 6956 if (val != NULL) { 6957 if (val[0] != 0) { 6958 uri = xmlParseURI((const char *) val); 6959 if (uri == NULL) { 6960 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI, 6961 "Attribute %s contains invalid URI %s\n", 6962 cur->name, val); 6963 } else { 6964 if (uri->scheme == NULL) { 6965 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE, 6966 "Attribute %s URI %s is not absolute\n", 6967 cur->name, val); 6968 } 6969 if (uri->fragment != NULL) { 6970 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT, 6971 "Attribute %s URI %s has a fragment ID\n", 6972 cur->name, val); 6973 } 6974 xmlFreeURI(uri); 6975 } 6976 } 6977 xmlFree(val); 6978 } 6979 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) { 6980 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE, 6981 "Unknown attribute %s on %s\n", cur->name, 6982 node->name); 6983 } 6984 } 6985 cur = next; 6986 } 6987} 6988 6989/** 6990 * xmlRelaxNGCleanupTree: 6991 * @ctxt: a Relax-NG parser context 6992 * @root: an xmlNodePtr subtree 6993 * 6994 * Cleanup the subtree from unwanted nodes for parsing, resolve 6995 * Include and externalRef lookups. 6996 */ 6997static void 6998xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) 6999{ 7000 xmlNodePtr cur, delete; 7001 7002 delete = NULL; 7003 cur = root; 7004 while (cur != NULL) { 7005 if (delete != NULL) { 7006 xmlUnlinkNode(delete); 7007 xmlFreeNode(delete); 7008 delete = NULL; 7009 } 7010 if (cur->type == XML_ELEMENT_NODE) { 7011 /* 7012 * Simplification 4.1. Annotations 7013 */ 7014 if ((cur->ns == NULL) || 7015 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { 7016 if ((cur->parent != NULL) && 7017 (cur->parent->type == XML_ELEMENT_NODE) && 7018 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) || 7019 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) || 7020 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) { 7021 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT, 7022 "element %s doesn't allow foreign elements\n", 7023 cur->parent->name, NULL); 7024 } 7025 delete = cur; 7026 goto skip_children; 7027 } else { 7028 xmlRelaxNGCleanupAttributes(ctxt, cur); 7029 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) { 7030 xmlChar *href, *ns, *base, *URL; 7031 xmlRelaxNGDocumentPtr docu; 7032 xmlNodePtr tmp; 7033 xmlURIPtr uri; 7034 7035 ns = xmlGetProp(cur, BAD_CAST "ns"); 7036 if (ns == NULL) { 7037 tmp = cur->parent; 7038 while ((tmp != NULL) && 7039 (tmp->type == XML_ELEMENT_NODE)) { 7040 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7041 if (ns != NULL) 7042 break; 7043 tmp = tmp->parent; 7044 } 7045 } 7046 href = xmlGetProp(cur, BAD_CAST "href"); 7047 if (href == NULL) { 7048 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7049 "xmlRelaxNGParse: externalRef has no href attribute\n", 7050 NULL, NULL); 7051 if (ns != NULL) 7052 xmlFree(ns); 7053 delete = cur; 7054 goto skip_children; 7055 } 7056 uri = xmlParseURI((const char *) href); 7057 if (uri == NULL) { 7058 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7059 "Incorrect URI for externalRef %s\n", 7060 href, NULL); 7061 if (ns != NULL) 7062 xmlFree(ns); 7063 if (href != NULL) 7064 xmlFree(href); 7065 delete = cur; 7066 goto skip_children; 7067 } 7068 if (uri->fragment != NULL) { 7069 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7070 "Fragment forbidden in URI for externalRef %s\n", 7071 href, NULL); 7072 if (ns != NULL) 7073 xmlFree(ns); 7074 xmlFreeURI(uri); 7075 if (href != NULL) 7076 xmlFree(href); 7077 delete = cur; 7078 goto skip_children; 7079 } 7080 xmlFreeURI(uri); 7081 base = xmlNodeGetBase(cur->doc, cur); 7082 URL = xmlBuildURI(href, base); 7083 if (URL == NULL) { 7084 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7085 "Failed to compute URL for externalRef %s\n", 7086 href, NULL); 7087 if (ns != NULL) 7088 xmlFree(ns); 7089 if (href != NULL) 7090 xmlFree(href); 7091 if (base != NULL) 7092 xmlFree(base); 7093 delete = cur; 7094 goto skip_children; 7095 } 7096 if (href != NULL) 7097 xmlFree(href); 7098 if (base != NULL) 7099 xmlFree(base); 7100 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns); 7101 if (docu == NULL) { 7102 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE, 7103 "Failed to load externalRef %s\n", URL, 7104 NULL); 7105 if (ns != NULL) 7106 xmlFree(ns); 7107 xmlFree(URL); 7108 delete = cur; 7109 goto skip_children; 7110 } 7111 if (ns != NULL) 7112 xmlFree(ns); 7113 xmlFree(URL); 7114 cur->psvi = docu; 7115 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { 7116 xmlChar *href, *ns, *base, *URL; 7117 xmlRelaxNGIncludePtr incl; 7118 xmlNodePtr tmp; 7119 7120 href = xmlGetProp(cur, BAD_CAST "href"); 7121 if (href == NULL) { 7122 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, 7123 "xmlRelaxNGParse: include has no href attribute\n", 7124 NULL, NULL); 7125 delete = cur; 7126 goto skip_children; 7127 } 7128 base = xmlNodeGetBase(cur->doc, cur); 7129 URL = xmlBuildURI(href, base); 7130 if (URL == NULL) { 7131 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, 7132 "Failed to compute URL for include %s\n", 7133 href, NULL); 7134 if (href != NULL) 7135 xmlFree(href); 7136 if (base != NULL) 7137 xmlFree(base); 7138 delete = cur; 7139 goto skip_children; 7140 } 7141 if (href != NULL) 7142 xmlFree(href); 7143 if (base != NULL) 7144 xmlFree(base); 7145 ns = xmlGetProp(cur, BAD_CAST "ns"); 7146 if (ns == NULL) { 7147 tmp = cur->parent; 7148 while ((tmp != NULL) && 7149 (tmp->type == XML_ELEMENT_NODE)) { 7150 ns = xmlGetProp(tmp, BAD_CAST "ns"); 7151 if (ns != NULL) 7152 break; 7153 tmp = tmp->parent; 7154 } 7155 } 7156 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns); 7157 if (ns != NULL) 7158 xmlFree(ns); 7159 if (incl == NULL) { 7160 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE, 7161 "Failed to load include %s\n", URL, 7162 NULL); 7163 xmlFree(URL); 7164 delete = cur; 7165 goto skip_children; 7166 } 7167 xmlFree(URL); 7168 cur->psvi = incl; 7169 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) || 7170 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) 7171 { 7172 xmlChar *name, *ns; 7173 xmlNodePtr text = NULL; 7174 7175 /* 7176 * Simplification 4.8. name attribute of element 7177 * and attribute elements 7178 */ 7179 name = xmlGetProp(cur, BAD_CAST "name"); 7180 if (name != NULL) { 7181 if (cur->children == NULL) { 7182 text = 7183 xmlNewChild(cur, cur->ns, BAD_CAST "name", 7184 name); 7185 } else { 7186 xmlNodePtr node; 7187 7188 node = xmlNewDocNode(cur->doc, cur->ns, 7189 BAD_CAST "name", NULL); 7190 if (node != NULL) { 7191 xmlAddPrevSibling(cur->children, node); 7192 text = xmlNewText(name); 7193 xmlAddChild(node, text); 7194 text = node; 7195 } 7196 } 7197 if (text == NULL) { 7198 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE, 7199 "Failed to create a name %s element\n", 7200 name, NULL); 7201 } 7202 xmlUnsetProp(cur, BAD_CAST "name"); 7203 xmlFree(name); 7204 ns = xmlGetProp(cur, BAD_CAST "ns"); 7205 if (ns != NULL) { 7206 if (text != NULL) { 7207 xmlSetProp(text, BAD_CAST "ns", ns); 7208 /* xmlUnsetProp(cur, BAD_CAST "ns"); */ 7209 } 7210 xmlFree(ns); 7211 } else if (xmlStrEqual(cur->name, 7212 BAD_CAST "attribute")) { 7213 xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); 7214 } 7215 } 7216 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) || 7217 (xmlStrEqual(cur->name, BAD_CAST "nsName")) || 7218 (xmlStrEqual(cur->name, BAD_CAST "value"))) { 7219 /* 7220 * Simplification 4.8. name attribute of element 7221 * and attribute elements 7222 */ 7223 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) { 7224 xmlNodePtr node; 7225 xmlChar *ns = NULL; 7226 7227 node = cur->parent; 7228 while ((node != NULL) && 7229 (node->type == XML_ELEMENT_NODE)) { 7230 ns = xmlGetProp(node, BAD_CAST "ns"); 7231 if (ns != NULL) { 7232 break; 7233 } 7234 node = node->parent; 7235 } 7236 if (ns == NULL) { 7237 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); 7238 } else { 7239 xmlSetProp(cur, BAD_CAST "ns", ns); 7240 xmlFree(ns); 7241 } 7242 } 7243 if (xmlStrEqual(cur->name, BAD_CAST "name")) { 7244 xmlChar *name, *local, *prefix; 7245 7246 /* 7247 * Simplification: 4.10. QNames 7248 */ 7249 name = xmlNodeGetContent(cur); 7250 if (name != NULL) { 7251 local = xmlSplitQName2(name, &prefix); 7252 if (local != NULL) { 7253 xmlNsPtr ns; 7254 7255 ns = xmlSearchNs(cur->doc, cur, prefix); 7256 if (ns == NULL) { 7257 xmlRngPErr(ctxt, cur, 7258 XML_RNGP_PREFIX_UNDEFINED, 7259 "xmlRelaxNGParse: no namespace for prefix %s\n", 7260 prefix, NULL); 7261 } else { 7262 xmlSetProp(cur, BAD_CAST "ns", 7263 ns->href); 7264 xmlNodeSetContent(cur, local); 7265 } 7266 xmlFree(local); 7267 xmlFree(prefix); 7268 } 7269 xmlFree(name); 7270 } 7271 } 7272 /* 7273 * 4.16 7274 */ 7275 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) { 7276 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7277 xmlRngPErr(ctxt, cur, 7278 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, 7279 "Found nsName/except//nsName forbidden construct\n", 7280 NULL, NULL); 7281 } 7282 } 7283 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) && 7284 (cur != root)) { 7285 int oldflags = ctxt->flags; 7286 7287 /* 7288 * 4.16 7289 */ 7290 if ((cur->parent != NULL) && 7291 (xmlStrEqual 7292 (cur->parent->name, BAD_CAST "anyName"))) { 7293 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT; 7294 xmlRelaxNGCleanupTree(ctxt, cur); 7295 ctxt->flags = oldflags; 7296 goto skip_children; 7297 } else if ((cur->parent != NULL) && 7298 (xmlStrEqual 7299 (cur->parent->name, BAD_CAST "nsName"))) { 7300 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT; 7301 xmlRelaxNGCleanupTree(ctxt, cur); 7302 ctxt->flags = oldflags; 7303 goto skip_children; 7304 } 7305 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) { 7306 /* 7307 * 4.16 7308 */ 7309 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) { 7310 xmlRngPErr(ctxt, cur, 7311 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, 7312 "Found anyName/except//anyName forbidden construct\n", 7313 NULL, NULL); 7314 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { 7315 xmlRngPErr(ctxt, cur, 7316 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, 7317 "Found nsName/except//anyName forbidden construct\n", 7318 NULL, NULL); 7319 } 7320 } 7321 /* 7322 * This is not an else since "include" is transformed 7323 * into a div 7324 */ 7325 if (xmlStrEqual(cur->name, BAD_CAST "div")) { 7326 xmlChar *ns; 7327 xmlNodePtr child, ins, tmp; 7328 7329 /* 7330 * implements rule 4.11 7331 */ 7332 7333 ns = xmlGetProp(cur, BAD_CAST "ns"); 7334 7335 child = cur->children; 7336 ins = cur; 7337 while (child != NULL) { 7338 if (ns != NULL) { 7339 if (!xmlHasProp(child, BAD_CAST "ns")) { 7340 xmlSetProp(child, BAD_CAST "ns", ns); 7341 } 7342 } 7343 tmp = child->next; 7344 xmlUnlinkNode(child); 7345 ins = xmlAddNextSibling(ins, child); 7346 child = tmp; 7347 } 7348 if (ns != NULL) 7349 xmlFree(ns); 7350 /* 7351 * Since we are about to delete cur, if its nsDef is non-NULL we 7352 * need to preserve it (it contains the ns definitions for the 7353 * children we just moved). We'll just stick it on to the end 7354 * of cur->parent's list, since it's never going to be re-serialized 7355 * (bug 143738). 7356 */ 7357 if ((cur->nsDef != NULL) && (cur->parent != NULL)) { 7358 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef; 7359 while (parDef->next != NULL) 7360 parDef = parDef->next; 7361 parDef->next = cur->nsDef; 7362 cur->nsDef = NULL; 7363 } 7364 delete = cur; 7365 goto skip_children; 7366 } 7367 } 7368 } 7369 /* 7370 * Simplification 4.2 whitespaces 7371 */ 7372 else if ((cur->type == XML_TEXT_NODE) || 7373 (cur->type == XML_CDATA_SECTION_NODE)) { 7374 if (IS_BLANK_NODE(cur)) { 7375 if ((cur->parent != NULL) && 7376 (cur->parent->type == XML_ELEMENT_NODE)) { 7377 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) 7378 && 7379 (!xmlStrEqual 7380 (cur->parent->name, BAD_CAST "param"))) 7381 delete = cur; 7382 } else { 7383 delete = cur; 7384 goto skip_children; 7385 } 7386 } 7387 } else { 7388 delete = cur; 7389 goto skip_children; 7390 } 7391 7392 /* 7393 * Skip to next node 7394 */ 7395 if (cur->children != NULL) { 7396 if ((cur->children->type != XML_ENTITY_DECL) && 7397 (cur->children->type != XML_ENTITY_REF_NODE) && 7398 (cur->children->type != XML_ENTITY_NODE)) { 7399 cur = cur->children; 7400 continue; 7401 } 7402 } 7403 skip_children: 7404 if (cur->next != NULL) { 7405 cur = cur->next; 7406 continue; 7407 } 7408 7409 do { 7410 cur = cur->parent; 7411 if (cur == NULL) 7412 break; 7413 if (cur == root) { 7414 cur = NULL; 7415 break; 7416 } 7417 if (cur->next != NULL) { 7418 cur = cur->next; 7419 break; 7420 } 7421 } while (cur != NULL); 7422 } 7423 if (delete != NULL) { 7424 xmlUnlinkNode(delete); 7425 xmlFreeNode(delete); 7426 delete = NULL; 7427 } 7428} 7429 7430/** 7431 * xmlRelaxNGCleanupDoc: 7432 * @ctxt: a Relax-NG parser context 7433 * @doc: an xmldocPtr document pointer 7434 * 7435 * Cleanup the document from unwanted nodes for parsing, resolve 7436 * Include and externalRef lookups. 7437 * 7438 * Returns the cleaned up document or NULL in case of error 7439 */ 7440static xmlDocPtr 7441xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) 7442{ 7443 xmlNodePtr root; 7444 7445 /* 7446 * Extract the root 7447 */ 7448 root = xmlDocGetRootElement(doc); 7449 if (root == NULL) { 7450 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7451 ctxt->URL, NULL); 7452 return (NULL); 7453 } 7454 xmlRelaxNGCleanupTree(ctxt, root); 7455 return (doc); 7456} 7457 7458/** 7459 * xmlRelaxNGParse: 7460 * @ctxt: a Relax-NG parser context 7461 * 7462 * parse a schema definition resource and build an internal 7463 * XML Shema struture which can be used to validate instances. 7464 * 7465 * Returns the internal XML RelaxNG structure built from the resource or 7466 * NULL in case of error 7467 */ 7468xmlRelaxNGPtr 7469xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) 7470{ 7471 xmlRelaxNGPtr ret = NULL; 7472 xmlDocPtr doc; 7473 xmlNodePtr root; 7474 7475 xmlRelaxNGInitTypes(); 7476 7477 if (ctxt == NULL) 7478 return (NULL); 7479 7480 /* 7481 * First step is to parse the input document into an DOM/Infoset 7482 */ 7483 if (ctxt->URL != NULL) { 7484 doc = xmlReadFile((const char *) ctxt->URL,NULL,0); 7485 if (doc == NULL) { 7486 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7487 "xmlRelaxNGParse: could not load %s\n", ctxt->URL, 7488 NULL); 7489 return (NULL); 7490 } 7491 } else if (ctxt->buffer != NULL) { 7492 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); 7493 if (doc == NULL) { 7494 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 7495 "xmlRelaxNGParse: could not parse schemas\n", NULL, 7496 NULL); 7497 return (NULL); 7498 } 7499 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7500 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); 7501 } else if (ctxt->document != NULL) { 7502 doc = ctxt->document; 7503 } else { 7504 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY, 7505 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL); 7506 return (NULL); 7507 } 7508 ctxt->document = doc; 7509 7510 /* 7511 * Some preprocessing of the document content 7512 */ 7513 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 7514 if (doc == NULL) { 7515 xmlFreeDoc(ctxt->document); 7516 ctxt->document = NULL; 7517 return (NULL); 7518 } 7519 7520 /* 7521 * Then do the parsing for good 7522 */ 7523 root = xmlDocGetRootElement(doc); 7524 if (root == NULL) { 7525 xmlRngPErr(ctxt, (xmlNodePtr) doc, 7526 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", 7527 (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL); 7528 7529 xmlFreeDoc(ctxt->document); 7530 ctxt->document = NULL; 7531 return (NULL); 7532 } 7533 ret = xmlRelaxNGParseDocument(ctxt, root); 7534 if (ret == NULL) { 7535 xmlFreeDoc(ctxt->document); 7536 ctxt->document = NULL; 7537 return (NULL); 7538 } 7539 7540 /* 7541 * Check the ref/defines links 7542 */ 7543 /* 7544 * try to preprocess interleaves 7545 */ 7546 if (ctxt->interleaves != NULL) { 7547 xmlHashScan(ctxt->interleaves, 7548 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt); 7549 } 7550 7551 /* 7552 * if there was a parsing error return NULL 7553 */ 7554 if (ctxt->nbErrors > 0) { 7555 xmlRelaxNGFree(ret); 7556 ctxt->document = NULL; 7557 xmlFreeDoc(doc); 7558 return (NULL); 7559 } 7560 7561 /* 7562 * try to compile (parts of) the schemas 7563 */ 7564 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) { 7565 if (ret->topgrammar->start->type != XML_RELAXNG_START) { 7566 xmlRelaxNGDefinePtr def; 7567 7568 def = xmlRelaxNGNewDefine(ctxt, NULL); 7569 if (def != NULL) { 7570 def->type = XML_RELAXNG_START; 7571 def->content = ret->topgrammar->start; 7572 ret->topgrammar->start = def; 7573 } 7574 } 7575 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start); 7576 } 7577 7578 /* 7579 * Transfer the pointer for cleanup at the schema level. 7580 */ 7581 ret->doc = doc; 7582 ctxt->document = NULL; 7583 ret->documents = ctxt->documents; 7584 ctxt->documents = NULL; 7585 7586 ret->includes = ctxt->includes; 7587 ctxt->includes = NULL; 7588 ret->defNr = ctxt->defNr; 7589 ret->defTab = ctxt->defTab; 7590 ctxt->defTab = NULL; 7591 if (ctxt->idref == 1) 7592 ret->idref = 1; 7593 7594 return (ret); 7595} 7596 7597/** 7598 * xmlRelaxNGSetParserErrors: 7599 * @ctxt: a Relax-NG validation context 7600 * @err: the error callback 7601 * @warn: the warning callback 7602 * @ctx: contextual data for the callbacks 7603 * 7604 * Set the callback functions used to handle errors for a validation context 7605 */ 7606void 7607xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, 7608 xmlRelaxNGValidityErrorFunc err, 7609 xmlRelaxNGValidityWarningFunc warn, void *ctx) 7610{ 7611 if (ctxt == NULL) 7612 return; 7613 ctxt->error = err; 7614 ctxt->warning = warn; 7615 ctxt->serror = NULL; 7616 ctxt->userData = ctx; 7617} 7618 7619/** 7620 * xmlRelaxNGGetParserErrors: 7621 * @ctxt: a Relax-NG validation context 7622 * @err: the error callback result 7623 * @warn: the warning callback result 7624 * @ctx: contextual data for the callbacks result 7625 * 7626 * Get the callback information used to handle errors for a validation context 7627 * 7628 * Returns -1 in case of failure, 0 otherwise. 7629 */ 7630int 7631xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, 7632 xmlRelaxNGValidityErrorFunc * err, 7633 xmlRelaxNGValidityWarningFunc * warn, void **ctx) 7634{ 7635 if (ctxt == NULL) 7636 return (-1); 7637 if (err != NULL) 7638 *err = ctxt->error; 7639 if (warn != NULL) 7640 *warn = ctxt->warning; 7641 if (ctx != NULL) 7642 *ctx = ctxt->userData; 7643 return (0); 7644} 7645 7646/** 7647 * xmlRelaxNGSetParserStructuredErrors: 7648 * @ctxt: a Relax-NG parser context 7649 * @serror: the error callback 7650 * @ctx: contextual data for the callbacks 7651 * 7652 * Set the callback functions used to handle errors for a parsing context 7653 */ 7654void 7655xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt, 7656 xmlStructuredErrorFunc serror, 7657 void *ctx) 7658{ 7659 if (ctxt == NULL) 7660 return; 7661 ctxt->serror = serror; 7662 ctxt->error = NULL; 7663 ctxt->warning = NULL; 7664 ctxt->userData = ctx; 7665} 7666 7667#ifdef LIBXML_OUTPUT_ENABLED 7668 7669/************************************************************************ 7670 * * 7671 * Dump back a compiled form * 7672 * * 7673 ************************************************************************/ 7674static void xmlRelaxNGDumpDefine(FILE * output, 7675 xmlRelaxNGDefinePtr define); 7676 7677/** 7678 * xmlRelaxNGDumpDefines: 7679 * @output: the file output 7680 * @defines: a list of define structures 7681 * 7682 * Dump a RelaxNG structure back 7683 */ 7684static void 7685xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) 7686{ 7687 while (defines != NULL) { 7688 xmlRelaxNGDumpDefine(output, defines); 7689 defines = defines->next; 7690 } 7691} 7692 7693/** 7694 * xmlRelaxNGDumpDefine: 7695 * @output: the file output 7696 * @define: a define structure 7697 * 7698 * Dump a RelaxNG structure back 7699 */ 7700static void 7701xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) 7702{ 7703 if (define == NULL) 7704 return; 7705 switch (define->type) { 7706 case XML_RELAXNG_EMPTY: 7707 fprintf(output, "<empty/>\n"); 7708 break; 7709 case XML_RELAXNG_NOT_ALLOWED: 7710 fprintf(output, "<notAllowed/>\n"); 7711 break; 7712 case XML_RELAXNG_TEXT: 7713 fprintf(output, "<text/>\n"); 7714 break; 7715 case XML_RELAXNG_ELEMENT: 7716 fprintf(output, "<element>\n"); 7717 if (define->name != NULL) { 7718 fprintf(output, "<name"); 7719 if (define->ns != NULL) 7720 fprintf(output, " ns=\"%s\"", define->ns); 7721 fprintf(output, ">%s</name>\n", define->name); 7722 } 7723 xmlRelaxNGDumpDefines(output, define->attrs); 7724 xmlRelaxNGDumpDefines(output, define->content); 7725 fprintf(output, "</element>\n"); 7726 break; 7727 case XML_RELAXNG_LIST: 7728 fprintf(output, "<list>\n"); 7729 xmlRelaxNGDumpDefines(output, define->content); 7730 fprintf(output, "</list>\n"); 7731 break; 7732 case XML_RELAXNG_ONEORMORE: 7733 fprintf(output, "<oneOrMore>\n"); 7734 xmlRelaxNGDumpDefines(output, define->content); 7735 fprintf(output, "</oneOrMore>\n"); 7736 break; 7737 case XML_RELAXNG_ZEROORMORE: 7738 fprintf(output, "<zeroOrMore>\n"); 7739 xmlRelaxNGDumpDefines(output, define->content); 7740 fprintf(output, "</zeroOrMore>\n"); 7741 break; 7742 case XML_RELAXNG_CHOICE: 7743 fprintf(output, "<choice>\n"); 7744 xmlRelaxNGDumpDefines(output, define->content); 7745 fprintf(output, "</choice>\n"); 7746 break; 7747 case XML_RELAXNG_GROUP: 7748 fprintf(output, "<group>\n"); 7749 xmlRelaxNGDumpDefines(output, define->content); 7750 fprintf(output, "</group>\n"); 7751 break; 7752 case XML_RELAXNG_INTERLEAVE: 7753 fprintf(output, "<interleave>\n"); 7754 xmlRelaxNGDumpDefines(output, define->content); 7755 fprintf(output, "</interleave>\n"); 7756 break; 7757 case XML_RELAXNG_OPTIONAL: 7758 fprintf(output, "<optional>\n"); 7759 xmlRelaxNGDumpDefines(output, define->content); 7760 fprintf(output, "</optional>\n"); 7761 break; 7762 case XML_RELAXNG_ATTRIBUTE: 7763 fprintf(output, "<attribute>\n"); 7764 xmlRelaxNGDumpDefines(output, define->content); 7765 fprintf(output, "</attribute>\n"); 7766 break; 7767 case XML_RELAXNG_DEF: 7768 fprintf(output, "<define"); 7769 if (define->name != NULL) 7770 fprintf(output, " name=\"%s\"", define->name); 7771 fprintf(output, ">\n"); 7772 xmlRelaxNGDumpDefines(output, define->content); 7773 fprintf(output, "</define>\n"); 7774 break; 7775 case XML_RELAXNG_REF: 7776 fprintf(output, "<ref"); 7777 if (define->name != NULL) 7778 fprintf(output, " name=\"%s\"", define->name); 7779 fprintf(output, ">\n"); 7780 xmlRelaxNGDumpDefines(output, define->content); 7781 fprintf(output, "</ref>\n"); 7782 break; 7783 case XML_RELAXNG_PARENTREF: 7784 fprintf(output, "<parentRef"); 7785 if (define->name != NULL) 7786 fprintf(output, " name=\"%s\"", define->name); 7787 fprintf(output, ">\n"); 7788 xmlRelaxNGDumpDefines(output, define->content); 7789 fprintf(output, "</parentRef>\n"); 7790 break; 7791 case XML_RELAXNG_EXTERNALREF: 7792 fprintf(output, "<externalRef>"); 7793 xmlRelaxNGDumpDefines(output, define->content); 7794 fprintf(output, "</externalRef>\n"); 7795 break; 7796 case XML_RELAXNG_DATATYPE: 7797 case XML_RELAXNG_VALUE: 7798 TODO break; 7799 case XML_RELAXNG_START: 7800 case XML_RELAXNG_EXCEPT: 7801 case XML_RELAXNG_PARAM: 7802 TODO break; 7803 case XML_RELAXNG_NOOP: 7804 xmlRelaxNGDumpDefines(output, define->content); 7805 break; 7806 } 7807} 7808 7809/** 7810 * xmlRelaxNGDumpGrammar: 7811 * @output: the file output 7812 * @grammar: a grammar structure 7813 * @top: is this a top grammar 7814 * 7815 * Dump a RelaxNG structure back 7816 */ 7817static void 7818xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top) 7819{ 7820 if (grammar == NULL) 7821 return; 7822 7823 fprintf(output, "<grammar"); 7824 if (top) 7825 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\""); 7826 switch (grammar->combine) { 7827 case XML_RELAXNG_COMBINE_UNDEFINED: 7828 break; 7829 case XML_RELAXNG_COMBINE_CHOICE: 7830 fprintf(output, " combine=\"choice\""); 7831 break; 7832 case XML_RELAXNG_COMBINE_INTERLEAVE: 7833 fprintf(output, " combine=\"interleave\""); 7834 break; 7835 default: 7836 fprintf(output, " <!-- invalid combine value -->"); 7837 } 7838 fprintf(output, ">\n"); 7839 if (grammar->start == NULL) { 7840 fprintf(output, " <!-- grammar had no start -->"); 7841 } else { 7842 fprintf(output, "<start>\n"); 7843 xmlRelaxNGDumpDefine(output, grammar->start); 7844 fprintf(output, "</start>\n"); 7845 } 7846 /* TODO ? Dump the defines ? */ 7847 fprintf(output, "</grammar>\n"); 7848} 7849 7850/** 7851 * xmlRelaxNGDump: 7852 * @output: the file output 7853 * @schema: a schema structure 7854 * 7855 * Dump a RelaxNG structure back 7856 */ 7857void 7858xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema) 7859{ 7860 if (output == NULL) 7861 return; 7862 if (schema == NULL) { 7863 fprintf(output, "RelaxNG empty or failed to compile\n"); 7864 return; 7865 } 7866 fprintf(output, "RelaxNG: "); 7867 if (schema->doc == NULL) { 7868 fprintf(output, "no document\n"); 7869 } else if (schema->doc->URL != NULL) { 7870 fprintf(output, "%s\n", schema->doc->URL); 7871 } else { 7872 fprintf(output, "\n"); 7873 } 7874 if (schema->topgrammar == NULL) { 7875 fprintf(output, "RelaxNG has no top grammar\n"); 7876 return; 7877 } 7878 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1); 7879} 7880 7881/** 7882 * xmlRelaxNGDumpTree: 7883 * @output: the file output 7884 * @schema: a schema structure 7885 * 7886 * Dump the transformed RelaxNG tree. 7887 */ 7888void 7889xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema) 7890{ 7891 if (output == NULL) 7892 return; 7893 if (schema == NULL) { 7894 fprintf(output, "RelaxNG empty or failed to compile\n"); 7895 return; 7896 } 7897 if (schema->doc == NULL) { 7898 fprintf(output, "no document\n"); 7899 } else { 7900 xmlDocDump(output, schema->doc); 7901 } 7902} 7903#endif /* LIBXML_OUTPUT_ENABLED */ 7904 7905/************************************************************************ 7906 * * 7907 * Validation of compiled content * 7908 * * 7909 ************************************************************************/ 7910static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 7911 xmlRelaxNGDefinePtr define); 7912 7913/** 7914 * xmlRelaxNGValidateCompiledCallback: 7915 * @exec: the regular expression instance 7916 * @token: the token which matched 7917 * @transdata: callback data, the define for the subelement if available 7918 @ @inputdata: callback data, the Relax NG validation context 7919 * 7920 * Handle the callback and if needed validate the element children. 7921 */ 7922static void 7923xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, 7924 const xmlChar * token, 7925 void *transdata, void *inputdata) 7926{ 7927 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; 7928 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; 7929 int ret; 7930 7931#ifdef DEBUG_COMPILE 7932 xmlGenericError(xmlGenericErrorContext, 7933 "Compiled callback for: '%s'\n", token); 7934#endif 7935 if (ctxt == NULL) { 7936 fprintf(stderr, "callback on %s missing context\n", token); 7937 return; 7938 } 7939 if (define == NULL) { 7940 if (token[0] == '#') 7941 return; 7942 fprintf(stderr, "callback on %s missing define\n", token); 7943 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 7944 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7945 return; 7946 } 7947 if ((ctxt == NULL) || (define == NULL)) { 7948 fprintf(stderr, "callback on %s missing info\n", token); 7949 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 7950 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7951 return; 7952 } else if (define->type != XML_RELAXNG_ELEMENT) { 7953 fprintf(stderr, "callback on %s define is not element\n", token); 7954 if (ctxt->errNo == XML_RELAXNG_OK) 7955 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 7956 return; 7957 } 7958 ret = xmlRelaxNGValidateDefinition(ctxt, define); 7959 if (ret != 0) 7960 ctxt->perr = ret; 7961} 7962 7963/** 7964 * xmlRelaxNGValidateCompiledContent: 7965 * @ctxt: the RelaxNG validation context 7966 * @regexp: the regular expression as compiled 7967 * @content: list of children to test against the regexp 7968 * 7969 * Validate the content model of an element or start using the regexp 7970 * 7971 * Returns 0 in case of success, -1 in case of error. 7972 */ 7973static int 7974xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt, 7975 xmlRegexpPtr regexp, xmlNodePtr content) 7976{ 7977 xmlRegExecCtxtPtr exec; 7978 xmlNodePtr cur; 7979 int ret = 0; 7980 int oldperr; 7981 7982 if ((ctxt == NULL) || (regexp == NULL)) 7983 return (-1); 7984 oldperr = ctxt->perr; 7985 exec = xmlRegNewExecCtxt(regexp, 7986 xmlRelaxNGValidateCompiledCallback, ctxt); 7987 ctxt->perr = 0; 7988 cur = content; 7989 while (cur != NULL) { 7990 ctxt->state->seq = cur; 7991 switch (cur->type) { 7992 case XML_TEXT_NODE: 7993 case XML_CDATA_SECTION_NODE: 7994 if (xmlIsBlankNode(cur)) 7995 break; 7996 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt); 7997 if (ret < 0) { 7998 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, 7999 cur->parent->name); 8000 } 8001 break; 8002 case XML_ELEMENT_NODE: 8003 if (cur->ns != NULL) { 8004 ret = xmlRegExecPushString2(exec, cur->name, 8005 cur->ns->href, ctxt); 8006 } else { 8007 ret = xmlRegExecPushString(exec, cur->name, ctxt); 8008 } 8009 if (ret < 0) { 8010 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name); 8011 } 8012 break; 8013 default: 8014 break; 8015 } 8016 if (ret < 0) 8017 break; 8018 /* 8019 * Switch to next element 8020 */ 8021 cur = cur->next; 8022 } 8023 ret = xmlRegExecPushString(exec, NULL, NULL); 8024 if (ret == 1) { 8025 ret = 0; 8026 ctxt->state->seq = NULL; 8027 } else if (ret == 0) { 8028 /* 8029 * TODO: get some of the names needed to exit the current state of exec 8030 */ 8031 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); 8032 ret = -1; 8033 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8034 xmlRelaxNGDumpValidError(ctxt); 8035 } else { 8036 ret = -1; 8037 } 8038 xmlRegFreeExecCtxt(exec); 8039 /* 8040 * There might be content model errors outside of the pure 8041 * regexp validation, e.g. for attribute values. 8042 */ 8043 if ((ret == 0) && (ctxt->perr != 0)) { 8044 ret = ctxt->perr; 8045 } 8046 ctxt->perr = oldperr; 8047 return (ret); 8048} 8049 8050/************************************************************************ 8051 * * 8052 * Progressive validation of when possible * 8053 * * 8054 ************************************************************************/ 8055static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 8056 xmlRelaxNGDefinePtr defines); 8057static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, 8058 int dolog); 8059static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt); 8060 8061/** 8062 * xmlRelaxNGElemPush: 8063 * @ctxt: the validation context 8064 * @exec: the regexp runtime for the new content model 8065 * 8066 * Push a new regexp for the current node content model on the stack 8067 * 8068 * Returns 0 in case of success and -1 in case of error. 8069 */ 8070static int 8071xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) 8072{ 8073 if (ctxt->elemTab == NULL) { 8074 ctxt->elemMax = 10; 8075 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax * 8076 sizeof 8077 (xmlRegExecCtxtPtr)); 8078 if (ctxt->elemTab == NULL) { 8079 xmlRngVErrMemory(ctxt, "validating\n"); 8080 return (-1); 8081 } 8082 } 8083 if (ctxt->elemNr >= ctxt->elemMax) { 8084 ctxt->elemMax *= 2; 8085 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab, 8086 ctxt->elemMax * 8087 sizeof 8088 (xmlRegExecCtxtPtr)); 8089 if (ctxt->elemTab == NULL) { 8090 xmlRngVErrMemory(ctxt, "validating\n"); 8091 return (-1); 8092 } 8093 } 8094 ctxt->elemTab[ctxt->elemNr++] = exec; 8095 ctxt->elem = exec; 8096 return (0); 8097} 8098 8099/** 8100 * xmlRelaxNGElemPop: 8101 * @ctxt: the validation context 8102 * 8103 * Pop the regexp of the current node content model from the stack 8104 * 8105 * Returns the exec or NULL if empty 8106 */ 8107static xmlRegExecCtxtPtr 8108xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) 8109{ 8110 xmlRegExecCtxtPtr ret; 8111 8112 if (ctxt->elemNr <= 0) 8113 return (NULL); 8114 ctxt->elemNr--; 8115 ret = ctxt->elemTab[ctxt->elemNr]; 8116 ctxt->elemTab[ctxt->elemNr] = NULL; 8117 if (ctxt->elemNr > 0) 8118 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1]; 8119 else 8120 ctxt->elem = NULL; 8121 return (ret); 8122} 8123 8124/** 8125 * xmlRelaxNGValidateProgressiveCallback: 8126 * @exec: the regular expression instance 8127 * @token: the token which matched 8128 * @transdata: callback data, the define for the subelement if available 8129 @ @inputdata: callback data, the Relax NG validation context 8130 * 8131 * Handle the callback and if needed validate the element children. 8132 * some of the in/out informations are passed via the context in @inputdata. 8133 */ 8134static void 8135xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec 8136 ATTRIBUTE_UNUSED, 8137 const xmlChar * token, 8138 void *transdata, void *inputdata) 8139{ 8140 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; 8141 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; 8142 xmlRelaxNGValidStatePtr state, oldstate; 8143 xmlNodePtr node; 8144 int ret = 0, oldflags; 8145 8146#ifdef DEBUG_PROGRESSIVE 8147 xmlGenericError(xmlGenericErrorContext, 8148 "Progressive callback for: '%s'\n", token); 8149#endif 8150 if (ctxt == NULL) { 8151 fprintf(stderr, "callback on %s missing context\n", token); 8152 return; 8153 } 8154 node = ctxt->pnode; 8155 ctxt->pstate = 1; 8156 if (define == NULL) { 8157 if (token[0] == '#') 8158 return; 8159 fprintf(stderr, "callback on %s missing define\n", token); 8160 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 8161 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 8162 ctxt->pstate = -1; 8163 return; 8164 } 8165 if ((ctxt == NULL) || (define == NULL)) { 8166 fprintf(stderr, "callback on %s missing info\n", token); 8167 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) 8168 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 8169 ctxt->pstate = -1; 8170 return; 8171 } else if (define->type != XML_RELAXNG_ELEMENT) { 8172 fprintf(stderr, "callback on %s define is not element\n", token); 8173 if (ctxt->errNo == XML_RELAXNG_OK) 8174 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; 8175 ctxt->pstate = -1; 8176 return; 8177 } 8178 if (node->type != XML_ELEMENT_NODE) { 8179 VALID_ERR(XML_RELAXNG_ERR_NOTELEM); 8180 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8181 xmlRelaxNGDumpValidError(ctxt); 8182 ctxt->pstate = -1; 8183 return; 8184 } 8185 if (define->contModel == NULL) { 8186 /* 8187 * this node cannot be validated in a streamable fashion 8188 */ 8189#ifdef DEBUG_PROGRESSIVE 8190 xmlGenericError(xmlGenericErrorContext, 8191 "Element '%s' validation is not streamable\n", 8192 token); 8193#endif 8194 ctxt->pstate = 0; 8195 ctxt->pdef = define; 8196 return; 8197 } 8198 exec = xmlRegNewExecCtxt(define->contModel, 8199 xmlRelaxNGValidateProgressiveCallback, ctxt); 8200 if (exec == NULL) { 8201 ctxt->pstate = -1; 8202 return; 8203 } 8204 xmlRelaxNGElemPush(ctxt, exec); 8205 8206 /* 8207 * Validate the attributes part of the content. 8208 */ 8209 state = xmlRelaxNGNewValidState(ctxt, node); 8210 if (state == NULL) { 8211 ctxt->pstate = -1; 8212 return; 8213 } 8214 oldstate = ctxt->state; 8215 ctxt->state = state; 8216 if (define->attrs != NULL) { 8217 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); 8218 if (ret != 0) { 8219 ctxt->pstate = -1; 8220 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); 8221 } 8222 } 8223 if (ctxt->state != NULL) { 8224 ctxt->state->seq = NULL; 8225 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 8226 if (ret != 0) { 8227 ctxt->pstate = -1; 8228 } 8229 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 8230 } else if (ctxt->states != NULL) { 8231 int tmp = -1, i; 8232 8233 oldflags = ctxt->flags; 8234 8235 for (i = 0; i < ctxt->states->nbState; i++) { 8236 state = ctxt->states->tabState[i]; 8237 ctxt->state = state; 8238 ctxt->state->seq = NULL; 8239 8240 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 8241 tmp = 0; 8242 break; 8243 } 8244 } 8245 if (tmp != 0) { 8246 /* 8247 * validation error, log the message for the "best" one 8248 */ 8249 ctxt->flags |= FLAGS_IGNORABLE; 8250 xmlRelaxNGLogBestError(ctxt); 8251 } 8252 for (i = 0; i < ctxt->states->nbState; i++) { 8253 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]); 8254 } 8255 xmlRelaxNGFreeStates(ctxt, ctxt->states); 8256 ctxt->states = NULL; 8257 if ((ret == 0) && (tmp == -1)) 8258 ctxt->pstate = -1; 8259 ctxt->flags = oldflags; 8260 } 8261 if (ctxt->pstate == -1) { 8262 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 8263 xmlRelaxNGDumpValidError(ctxt); 8264 } 8265 } 8266 ctxt->state = oldstate; 8267} 8268 8269/** 8270 * xmlRelaxNGValidatePushElement: 8271 * @ctxt: the validation context 8272 * @doc: a document instance 8273 * @elem: an element instance 8274 * 8275 * Push a new element start on the RelaxNG validation stack. 8276 * 8277 * returns 1 if no validation problem was found or 0 if validating the 8278 * element requires a full node, and -1 in case of error. 8279 */ 8280int 8281xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, 8282 xmlDocPtr doc ATTRIBUTE_UNUSED, 8283 xmlNodePtr elem) 8284{ 8285 int ret = 1; 8286 8287 if ((ctxt == NULL) || (elem == NULL)) 8288 return (-1); 8289 8290#ifdef DEBUG_PROGRESSIVE 8291 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name); 8292#endif 8293 if (ctxt->elem == 0) { 8294 xmlRelaxNGPtr schema; 8295 xmlRelaxNGGrammarPtr grammar; 8296 xmlRegExecCtxtPtr exec; 8297 xmlRelaxNGDefinePtr define; 8298 8299 schema = ctxt->schema; 8300 if (schema == NULL) { 8301 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 8302 return (-1); 8303 } 8304 grammar = schema->topgrammar; 8305 if ((grammar == NULL) || (grammar->start == NULL)) { 8306 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 8307 return (-1); 8308 } 8309 define = grammar->start; 8310 if (define->contModel == NULL) { 8311 ctxt->pdef = define; 8312 return (0); 8313 } 8314 exec = xmlRegNewExecCtxt(define->contModel, 8315 xmlRelaxNGValidateProgressiveCallback, 8316 ctxt); 8317 if (exec == NULL) { 8318 return (-1); 8319 } 8320 xmlRelaxNGElemPush(ctxt, exec); 8321 } 8322 ctxt->pnode = elem; 8323 ctxt->pstate = 0; 8324 if (elem->ns != NULL) { 8325 ret = 8326 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href, 8327 ctxt); 8328 } else { 8329 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt); 8330 } 8331 if (ret < 0) { 8332 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name); 8333 } else { 8334 if (ctxt->pstate == 0) 8335 ret = 0; 8336 else if (ctxt->pstate < 0) 8337 ret = -1; 8338 else 8339 ret = 1; 8340 } 8341#ifdef DEBUG_PROGRESSIVE 8342 if (ret < 0) 8343 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n", 8344 elem->name); 8345#endif 8346 return (ret); 8347} 8348 8349/** 8350 * xmlRelaxNGValidatePushCData: 8351 * @ctxt: the RelaxNG validation context 8352 * @data: some character data read 8353 * @len: the length of the data 8354 * 8355 * check the CData parsed for validation in the current stack 8356 * 8357 * returns 1 if no validation problem was found or -1 otherwise 8358 */ 8359int 8360xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, 8361 const xmlChar * data, int len ATTRIBUTE_UNUSED) 8362{ 8363 int ret = 1; 8364 8365 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL)) 8366 return (-1); 8367 8368#ifdef DEBUG_PROGRESSIVE 8369 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len); 8370#endif 8371 8372 while (*data != 0) { 8373 if (!IS_BLANK_CH(*data)) 8374 break; 8375 data++; 8376 } 8377 if (*data == 0) 8378 return (1); 8379 8380 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt); 8381 if (ret < 0) { 8382 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO "); 8383#ifdef DEBUG_PROGRESSIVE 8384 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n"); 8385#endif 8386 8387 return (-1); 8388 } 8389 return (1); 8390} 8391 8392/** 8393 * xmlRelaxNGValidatePopElement: 8394 * @ctxt: the RelaxNG validation context 8395 * @doc: a document instance 8396 * @elem: an element instance 8397 * 8398 * Pop the element end from the RelaxNG validation stack. 8399 * 8400 * returns 1 if no validation problem was found or 0 otherwise 8401 */ 8402int 8403xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, 8404 xmlDocPtr doc ATTRIBUTE_UNUSED, 8405 xmlNodePtr elem) 8406{ 8407 int ret; 8408 xmlRegExecCtxtPtr exec; 8409 8410 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) 8411 return (-1); 8412#ifdef DEBUG_PROGRESSIVE 8413 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name); 8414#endif 8415 /* 8416 * verify that we reached a terminal state of the content model. 8417 */ 8418 exec = xmlRelaxNGElemPop(ctxt); 8419 ret = xmlRegExecPushString(exec, NULL, NULL); 8420 if (ret == 0) { 8421 /* 8422 * TODO: get some of the names needed to exit the current state of exec 8423 */ 8424 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); 8425 ret = -1; 8426 } else if (ret < 0) { 8427 ret = -1; 8428 } else { 8429 ret = 1; 8430 } 8431 xmlRegFreeExecCtxt(exec); 8432#ifdef DEBUG_PROGRESSIVE 8433 if (ret < 0) 8434 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n", 8435 elem->name); 8436#endif 8437 return (ret); 8438} 8439 8440/** 8441 * xmlRelaxNGValidateFullElement: 8442 * @ctxt: the validation context 8443 * @doc: a document instance 8444 * @elem: an element instance 8445 * 8446 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned 8447 * 0 and the content of the node has been expanded. 8448 * 8449 * returns 1 if no validation problem was found or -1 in case of error. 8450 */ 8451int 8452xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, 8453 xmlDocPtr doc ATTRIBUTE_UNUSED, 8454 xmlNodePtr elem) 8455{ 8456 int ret; 8457 xmlRelaxNGValidStatePtr state; 8458 8459 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) 8460 return (-1); 8461#ifdef DEBUG_PROGRESSIVE 8462 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name); 8463#endif 8464 state = xmlRelaxNGNewValidState(ctxt, elem->parent); 8465 if (state == NULL) { 8466 return (-1); 8467 } 8468 state->seq = elem; 8469 ctxt->state = state; 8470 ctxt->errNo = XML_RELAXNG_OK; 8471 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef); 8472 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) 8473 ret = -1; 8474 else 8475 ret = 1; 8476 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 8477 ctxt->state = NULL; 8478#ifdef DEBUG_PROGRESSIVE 8479 if (ret < 0) 8480 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n", 8481 elem->name); 8482#endif 8483 return (ret); 8484} 8485 8486/************************************************************************ 8487 * * 8488 * Generic interpreted validation implementation * 8489 * * 8490 ************************************************************************/ 8491static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 8492 xmlRelaxNGDefinePtr define); 8493 8494/** 8495 * xmlRelaxNGSkipIgnored: 8496 * @ctxt: a schema validation context 8497 * @node: the top node. 8498 * 8499 * Skip ignorable nodes in that context 8500 * 8501 * Returns the new sibling or NULL in case of error. 8502 */ 8503static xmlNodePtr 8504xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 8505 xmlNodePtr node) 8506{ 8507 /* 8508 * TODO complete and handle entities 8509 */ 8510 while ((node != NULL) && 8511 ((node->type == XML_COMMENT_NODE) || 8512 (node->type == XML_PI_NODE) || 8513 (node->type == XML_XINCLUDE_START) || 8514 (node->type == XML_XINCLUDE_END) || 8515 (((node->type == XML_TEXT_NODE) || 8516 (node->type == XML_CDATA_SECTION_NODE)) && 8517 ((ctxt->flags & FLAGS_MIXED_CONTENT) || 8518 (IS_BLANK_NODE(node)))))) { 8519 node = node->next; 8520 } 8521 return (node); 8522} 8523 8524/** 8525 * xmlRelaxNGNormalize: 8526 * @ctxt: a schema validation context 8527 * @str: the string to normalize 8528 * 8529 * Implements the normalizeWhiteSpace( s ) function from 8530 * section 6.2.9 of the spec 8531 * 8532 * Returns the new string or NULL in case of error. 8533 */ 8534static xmlChar * 8535xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str) 8536{ 8537 xmlChar *ret, *p; 8538 const xmlChar *tmp; 8539 int len; 8540 8541 if (str == NULL) 8542 return (NULL); 8543 tmp = str; 8544 while (*tmp != 0) 8545 tmp++; 8546 len = tmp - str; 8547 8548 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); 8549 if (ret == NULL) { 8550 xmlRngVErrMemory(ctxt, "validating\n"); 8551 return (NULL); 8552 } 8553 p = ret; 8554 while (IS_BLANK_CH(*str)) 8555 str++; 8556 while (*str != 0) { 8557 if (IS_BLANK_CH(*str)) { 8558 while (IS_BLANK_CH(*str)) 8559 str++; 8560 if (*str == 0) 8561 break; 8562 *p++ = ' '; 8563 } else 8564 *p++ = *str++; 8565 } 8566 *p = 0; 8567 return (ret); 8568} 8569 8570/** 8571 * xmlRelaxNGValidateDatatype: 8572 * @ctxt: a Relax-NG validation context 8573 * @value: the string value 8574 * @type: the datatype definition 8575 * @node: the node 8576 * 8577 * Validate the given value against the dataype 8578 * 8579 * Returns 0 if the validation succeeded or an error code. 8580 */ 8581static int 8582xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, 8583 const xmlChar * value, 8584 xmlRelaxNGDefinePtr define, xmlNodePtr node) 8585{ 8586 int ret, tmp; 8587 xmlRelaxNGTypeLibraryPtr lib; 8588 void *result = NULL; 8589 xmlRelaxNGDefinePtr cur; 8590 8591 if ((define == NULL) || (define->data == NULL)) { 8592 return (-1); 8593 } 8594 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 8595 if (lib->check != NULL) { 8596 if ((define->attrs != NULL) && 8597 (define->attrs->type == XML_RELAXNG_PARAM)) { 8598 ret = 8599 lib->check(lib->data, define->name, value, &result, node); 8600 } else { 8601 ret = lib->check(lib->data, define->name, value, NULL, node); 8602 } 8603 } else 8604 ret = -1; 8605 if (ret < 0) { 8606 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name); 8607 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) 8608 lib->freef(lib->data, result); 8609 return (-1); 8610 } else if (ret == 1) { 8611 ret = 0; 8612 } else if (ret == 2) { 8613 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value); 8614 } else { 8615 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value); 8616 ret = -1; 8617 } 8618 cur = define->attrs; 8619 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) { 8620 if (lib->facet != NULL) { 8621 tmp = lib->facet(lib->data, define->name, cur->name, 8622 cur->value, value, result); 8623 if (tmp != 0) 8624 ret = -1; 8625 } 8626 cur = cur->next; 8627 } 8628 if ((ret == 0) && (define->content != NULL)) { 8629 const xmlChar *oldvalue, *oldendvalue; 8630 8631 oldvalue = ctxt->state->value; 8632 oldendvalue = ctxt->state->endvalue; 8633 ctxt->state->value = (xmlChar *) value; 8634 ctxt->state->endvalue = NULL; 8635 ret = xmlRelaxNGValidateValue(ctxt, define->content); 8636 ctxt->state->value = (xmlChar *) oldvalue; 8637 ctxt->state->endvalue = (xmlChar *) oldendvalue; 8638 } 8639 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) 8640 lib->freef(lib->data, result); 8641 return (ret); 8642} 8643 8644/** 8645 * xmlRelaxNGNextValue: 8646 * @ctxt: a Relax-NG validation context 8647 * 8648 * Skip to the next value when validating within a list 8649 * 8650 * Returns 0 if the operation succeeded or an error code. 8651 */ 8652static int 8653xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) 8654{ 8655 xmlChar *cur; 8656 8657 cur = ctxt->state->value; 8658 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) { 8659 ctxt->state->value = NULL; 8660 ctxt->state->endvalue = NULL; 8661 return (0); 8662 } 8663 while (*cur != 0) 8664 cur++; 8665 while ((cur != ctxt->state->endvalue) && (*cur == 0)) 8666 cur++; 8667 if (cur == ctxt->state->endvalue) 8668 ctxt->state->value = NULL; 8669 else 8670 ctxt->state->value = cur; 8671 return (0); 8672} 8673 8674/** 8675 * xmlRelaxNGValidateValueList: 8676 * @ctxt: a Relax-NG validation context 8677 * @defines: the list of definitions to verify 8678 * 8679 * Validate the given set of definitions for the current value 8680 * 8681 * Returns 0 if the validation succeeded or an error code. 8682 */ 8683static int 8684xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, 8685 xmlRelaxNGDefinePtr defines) 8686{ 8687 int ret = 0; 8688 8689 while (defines != NULL) { 8690 ret = xmlRelaxNGValidateValue(ctxt, defines); 8691 if (ret != 0) 8692 break; 8693 defines = defines->next; 8694 } 8695 return (ret); 8696} 8697 8698/** 8699 * xmlRelaxNGValidateValue: 8700 * @ctxt: a Relax-NG validation context 8701 * @define: the definition to verify 8702 * 8703 * Validate the given definition for the current value 8704 * 8705 * Returns 0 if the validation succeeded or an error code. 8706 */ 8707static int 8708xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 8709 xmlRelaxNGDefinePtr define) 8710{ 8711 int ret = 0, oldflags; 8712 xmlChar *value; 8713 8714 value = ctxt->state->value; 8715 switch (define->type) { 8716 case XML_RELAXNG_EMPTY:{ 8717 if ((value != NULL) && (value[0] != 0)) { 8718 int idx = 0; 8719 8720 while (IS_BLANK_CH(value[idx])) 8721 idx++; 8722 if (value[idx] != 0) 8723 ret = -1; 8724 } 8725 break; 8726 } 8727 case XML_RELAXNG_TEXT: 8728 break; 8729 case XML_RELAXNG_VALUE:{ 8730 if (!xmlStrEqual(value, define->value)) { 8731 if (define->name != NULL) { 8732 xmlRelaxNGTypeLibraryPtr lib; 8733 8734 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 8735 if ((lib != NULL) && (lib->comp != NULL)) { 8736 ret = lib->comp(lib->data, define->name, 8737 define->value, define->node, 8738 (void *) define->attrs, 8739 value, ctxt->state->node); 8740 } else 8741 ret = -1; 8742 if (ret < 0) { 8743 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, 8744 define->name); 8745 return (-1); 8746 } else if (ret == 1) { 8747 ret = 0; 8748 } else { 8749 ret = -1; 8750 } 8751 } else { 8752 xmlChar *nval, *nvalue; 8753 8754 /* 8755 * TODO: trivial optimizations are possible by 8756 * computing at compile-time 8757 */ 8758 nval = xmlRelaxNGNormalize(ctxt, define->value); 8759 nvalue = xmlRelaxNGNormalize(ctxt, value); 8760 8761 if ((nval == NULL) || (nvalue == NULL) || 8762 (!xmlStrEqual(nval, nvalue))) 8763 ret = -1; 8764 if (nval != NULL) 8765 xmlFree(nval); 8766 if (nvalue != NULL) 8767 xmlFree(nvalue); 8768 } 8769 } 8770 if (ret == 0) 8771 xmlRelaxNGNextValue(ctxt); 8772 break; 8773 } 8774 case XML_RELAXNG_DATATYPE:{ 8775 ret = xmlRelaxNGValidateDatatype(ctxt, value, define, 8776 ctxt->state->seq); 8777 if (ret == 0) 8778 xmlRelaxNGNextValue(ctxt); 8779 8780 break; 8781 } 8782 case XML_RELAXNG_CHOICE:{ 8783 xmlRelaxNGDefinePtr list = define->content; 8784 xmlChar *oldvalue; 8785 8786 oldflags = ctxt->flags; 8787 ctxt->flags |= FLAGS_IGNORABLE; 8788 8789 oldvalue = ctxt->state->value; 8790 while (list != NULL) { 8791 ret = xmlRelaxNGValidateValue(ctxt, list); 8792 if (ret == 0) { 8793 break; 8794 } 8795 ctxt->state->value = oldvalue; 8796 list = list->next; 8797 } 8798 ctxt->flags = oldflags; 8799 if (ret != 0) { 8800 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 8801 xmlRelaxNGDumpValidError(ctxt); 8802 } else { 8803 if (ctxt->errNr > 0) 8804 xmlRelaxNGPopErrors(ctxt, 0); 8805 } 8806 break; 8807 } 8808 case XML_RELAXNG_LIST:{ 8809 xmlRelaxNGDefinePtr list = define->content; 8810 xmlChar *oldvalue, *oldend, *val, *cur; 8811 8812#ifdef DEBUG_LIST 8813 int nb_values = 0; 8814#endif 8815 8816 oldvalue = ctxt->state->value; 8817 oldend = ctxt->state->endvalue; 8818 8819 val = xmlStrdup(oldvalue); 8820 if (val == NULL) { 8821 val = xmlStrdup(BAD_CAST ""); 8822 } 8823 if (val == NULL) { 8824 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 8825 return (-1); 8826 } 8827 cur = val; 8828 while (*cur != 0) { 8829 if (IS_BLANK_CH(*cur)) { 8830 *cur = 0; 8831 cur++; 8832#ifdef DEBUG_LIST 8833 nb_values++; 8834#endif 8835 while (IS_BLANK_CH(*cur)) 8836 *cur++ = 0; 8837 } else 8838 cur++; 8839 } 8840#ifdef DEBUG_LIST 8841 xmlGenericError(xmlGenericErrorContext, 8842 "list value: '%s' found %d items\n", 8843 oldvalue, nb_values); 8844 nb_values = 0; 8845#endif 8846 ctxt->state->endvalue = cur; 8847 cur = val; 8848 while ((*cur == 0) && (cur != ctxt->state->endvalue)) 8849 cur++; 8850 8851 ctxt->state->value = cur; 8852 8853 while (list != NULL) { 8854 if (ctxt->state->value == ctxt->state->endvalue) 8855 ctxt->state->value = NULL; 8856 ret = xmlRelaxNGValidateValue(ctxt, list); 8857 if (ret != 0) { 8858#ifdef DEBUG_LIST 8859 xmlGenericError(xmlGenericErrorContext, 8860 "Failed to validate value: '%s' with %d rule\n", 8861 ctxt->state->value, nb_values); 8862#endif 8863 break; 8864 } 8865#ifdef DEBUG_LIST 8866 nb_values++; 8867#endif 8868 list = list->next; 8869 } 8870 8871 if ((ret == 0) && (ctxt->state->value != NULL) && 8872 (ctxt->state->value != ctxt->state->endvalue)) { 8873 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, 8874 ctxt->state->value); 8875 ret = -1; 8876 } 8877 xmlFree(val); 8878 ctxt->state->value = oldvalue; 8879 ctxt->state->endvalue = oldend; 8880 break; 8881 } 8882 case XML_RELAXNG_ONEORMORE: 8883 ret = xmlRelaxNGValidateValueList(ctxt, define->content); 8884 if (ret != 0) { 8885 break; 8886 } 8887 /* no break on purpose */ 8888 case XML_RELAXNG_ZEROORMORE:{ 8889 xmlChar *cur, *temp; 8890 8891 if ((ctxt->state->value == NULL) || 8892 (*ctxt->state->value == 0)) { 8893 ret = 0; 8894 break; 8895 } 8896 oldflags = ctxt->flags; 8897 ctxt->flags |= FLAGS_IGNORABLE; 8898 cur = ctxt->state->value; 8899 temp = NULL; 8900 while ((cur != NULL) && (cur != ctxt->state->endvalue) && 8901 (temp != cur)) { 8902 temp = cur; 8903 ret = 8904 xmlRelaxNGValidateValueList(ctxt, define->content); 8905 if (ret != 0) { 8906 ctxt->state->value = temp; 8907 ret = 0; 8908 break; 8909 } 8910 cur = ctxt->state->value; 8911 } 8912 ctxt->flags = oldflags; 8913 if (ctxt->errNr > 0) 8914 xmlRelaxNGPopErrors(ctxt, 0); 8915 break; 8916 } 8917 case XML_RELAXNG_OPTIONAL:{ 8918 xmlChar *temp; 8919 8920 if ((ctxt->state->value == NULL) || 8921 (*ctxt->state->value == 0)) { 8922 ret = 0; 8923 break; 8924 } 8925 oldflags = ctxt->flags; 8926 ctxt->flags |= FLAGS_IGNORABLE; 8927 temp = ctxt->state->value; 8928 ret = xmlRelaxNGValidateValue(ctxt, define->content); 8929 ctxt->flags = oldflags; 8930 if (ret != 0) { 8931 ctxt->state->value = temp; 8932 if (ctxt->errNr > 0) 8933 xmlRelaxNGPopErrors(ctxt, 0); 8934 ret = 0; 8935 break; 8936 } 8937 if (ctxt->errNr > 0) 8938 xmlRelaxNGPopErrors(ctxt, 0); 8939 break; 8940 } 8941 case XML_RELAXNG_EXCEPT:{ 8942 xmlRelaxNGDefinePtr list; 8943 8944 list = define->content; 8945 while (list != NULL) { 8946 ret = xmlRelaxNGValidateValue(ctxt, list); 8947 if (ret == 0) { 8948 ret = -1; 8949 break; 8950 } else 8951 ret = 0; 8952 list = list->next; 8953 } 8954 break; 8955 } 8956 case XML_RELAXNG_DEF: 8957 case XML_RELAXNG_GROUP:{ 8958 xmlRelaxNGDefinePtr list; 8959 8960 list = define->content; 8961 while (list != NULL) { 8962 ret = xmlRelaxNGValidateValue(ctxt, list); 8963 if (ret != 0) { 8964 ret = -1; 8965 break; 8966 } else 8967 ret = 0; 8968 list = list->next; 8969 } 8970 break; 8971 } 8972 case XML_RELAXNG_REF: 8973 case XML_RELAXNG_PARENTREF: 8974 if (define->content == NULL) { 8975 VALID_ERR(XML_RELAXNG_ERR_NODEFINE); 8976 ret = -1; 8977 } else { 8978 ret = xmlRelaxNGValidateValue(ctxt, define->content); 8979 } 8980 break; 8981 default: 8982 TODO ret = -1; 8983 } 8984 return (ret); 8985} 8986 8987/** 8988 * xmlRelaxNGValidateValueContent: 8989 * @ctxt: a Relax-NG validation context 8990 * @defines: the list of definitions to verify 8991 * 8992 * Validate the given definitions for the current value 8993 * 8994 * Returns 0 if the validation succeeded or an error code. 8995 */ 8996static int 8997xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, 8998 xmlRelaxNGDefinePtr defines) 8999{ 9000 int ret = 0; 9001 9002 while (defines != NULL) { 9003 ret = xmlRelaxNGValidateValue(ctxt, defines); 9004 if (ret != 0) 9005 break; 9006 defines = defines->next; 9007 } 9008 return (ret); 9009} 9010 9011/** 9012 * xmlRelaxNGAttributeMatch: 9013 * @ctxt: a Relax-NG validation context 9014 * @define: the definition to check 9015 * @prop: the attribute 9016 * 9017 * Check if the attribute matches the definition nameClass 9018 * 9019 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error 9020 */ 9021static int 9022xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, 9023 xmlRelaxNGDefinePtr define, xmlAttrPtr prop) 9024{ 9025 int ret; 9026 9027 if (define->name != NULL) { 9028 if (!xmlStrEqual(define->name, prop->name)) 9029 return (0); 9030 } 9031 if (define->ns != NULL) { 9032 if (define->ns[0] == 0) { 9033 if (prop->ns != NULL) 9034 return (0); 9035 } else { 9036 if ((prop->ns == NULL) || 9037 (!xmlStrEqual(define->ns, prop->ns->href))) 9038 return (0); 9039 } 9040 } 9041 if (define->nameClass == NULL) 9042 return (1); 9043 define = define->nameClass; 9044 if (define->type == XML_RELAXNG_EXCEPT) { 9045 xmlRelaxNGDefinePtr list; 9046 9047 list = define->content; 9048 while (list != NULL) { 9049 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); 9050 if (ret == 1) 9051 return (0); 9052 if (ret < 0) 9053 return (ret); 9054 list = list->next; 9055 } 9056 } else if (define->type == XML_RELAXNG_CHOICE) { 9057 xmlRelaxNGDefinePtr list; 9058 9059 list = define->nameClass; 9060 while (list != NULL) { 9061 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); 9062 if (ret == 1) 9063 return (1); 9064 if (ret < 0) 9065 return (ret); 9066 list = list->next; 9067 } 9068 return (0); 9069 } else { 9070 TODO} 9071 return (1); 9072} 9073 9074/** 9075 * xmlRelaxNGValidateAttribute: 9076 * @ctxt: a Relax-NG validation context 9077 * @define: the definition to verify 9078 * 9079 * Validate the given attribute definition for that node 9080 * 9081 * Returns 0 if the validation succeeded or an error code. 9082 */ 9083static int 9084xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, 9085 xmlRelaxNGDefinePtr define) 9086{ 9087 int ret = 0, i; 9088 xmlChar *value, *oldvalue; 9089 xmlAttrPtr prop = NULL, tmp; 9090 xmlNodePtr oldseq; 9091 9092 if (ctxt->state->nbAttrLeft <= 0) 9093 return (-1); 9094 if (define->name != NULL) { 9095 for (i = 0; i < ctxt->state->nbAttrs; i++) { 9096 tmp = ctxt->state->attrs[i]; 9097 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) { 9098 if ((((define->ns == NULL) || (define->ns[0] == 0)) && 9099 (tmp->ns == NULL)) || 9100 ((tmp->ns != NULL) && 9101 (xmlStrEqual(define->ns, tmp->ns->href)))) { 9102 prop = tmp; 9103 break; 9104 } 9105 } 9106 } 9107 if (prop != NULL) { 9108 value = xmlNodeListGetString(prop->doc, prop->children, 1); 9109 oldvalue = ctxt->state->value; 9110 oldseq = ctxt->state->seq; 9111 ctxt->state->seq = (xmlNodePtr) prop; 9112 ctxt->state->value = value; 9113 ctxt->state->endvalue = NULL; 9114 ret = xmlRelaxNGValidateValueContent(ctxt, define->content); 9115 if (ctxt->state->value != NULL) 9116 value = ctxt->state->value; 9117 if (value != NULL) 9118 xmlFree(value); 9119 ctxt->state->value = oldvalue; 9120 ctxt->state->seq = oldseq; 9121 if (ret == 0) { 9122 /* 9123 * flag the attribute as processed 9124 */ 9125 ctxt->state->attrs[i] = NULL; 9126 ctxt->state->nbAttrLeft--; 9127 } 9128 } else { 9129 ret = -1; 9130 } 9131#ifdef DEBUG 9132 xmlGenericError(xmlGenericErrorContext, 9133 "xmlRelaxNGValidateAttribute(%s): %d\n", 9134 define->name, ret); 9135#endif 9136 } else { 9137 for (i = 0; i < ctxt->state->nbAttrs; i++) { 9138 tmp = ctxt->state->attrs[i]; 9139 if ((tmp != NULL) && 9140 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) { 9141 prop = tmp; 9142 break; 9143 } 9144 } 9145 if (prop != NULL) { 9146 value = xmlNodeListGetString(prop->doc, prop->children, 1); 9147 oldvalue = ctxt->state->value; 9148 oldseq = ctxt->state->seq; 9149 ctxt->state->seq = (xmlNodePtr) prop; 9150 ctxt->state->value = value; 9151 ret = xmlRelaxNGValidateValueContent(ctxt, define->content); 9152 if (ctxt->state->value != NULL) 9153 value = ctxt->state->value; 9154 if (value != NULL) 9155 xmlFree(value); 9156 ctxt->state->value = oldvalue; 9157 ctxt->state->seq = oldseq; 9158 if (ret == 0) { 9159 /* 9160 * flag the attribute as processed 9161 */ 9162 ctxt->state->attrs[i] = NULL; 9163 ctxt->state->nbAttrLeft--; 9164 } 9165 } else { 9166 ret = -1; 9167 } 9168#ifdef DEBUG 9169 if (define->ns != NULL) { 9170 xmlGenericError(xmlGenericErrorContext, 9171 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", 9172 define->ns, ret); 9173 } else { 9174 xmlGenericError(xmlGenericErrorContext, 9175 "xmlRelaxNGValidateAttribute(anyName): %d\n", 9176 ret); 9177 } 9178#endif 9179 } 9180 9181 return (ret); 9182} 9183 9184/** 9185 * xmlRelaxNGValidateAttributeList: 9186 * @ctxt: a Relax-NG validation context 9187 * @define: the list of definition to verify 9188 * 9189 * Validate the given node against the list of attribute definitions 9190 * 9191 * Returns 0 if the validation succeeded or an error code. 9192 */ 9193static int 9194xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 9195 xmlRelaxNGDefinePtr defines) 9196{ 9197 int ret = 0, res; 9198 int needmore = 0; 9199 xmlRelaxNGDefinePtr cur; 9200 9201 cur = defines; 9202 while (cur != NULL) { 9203 if (cur->type == XML_RELAXNG_ATTRIBUTE) { 9204 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0) 9205 ret = -1; 9206 } else 9207 needmore = 1; 9208 cur = cur->next; 9209 } 9210 if (!needmore) 9211 return (ret); 9212 cur = defines; 9213 while (cur != NULL) { 9214 if (cur->type != XML_RELAXNG_ATTRIBUTE) { 9215 if ((ctxt->state != NULL) || (ctxt->states != NULL)) { 9216 res = xmlRelaxNGValidateDefinition(ctxt, cur); 9217 if (res < 0) 9218 ret = -1; 9219 } else { 9220 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 9221 return (-1); 9222 } 9223 if (res == -1) /* continues on -2 */ 9224 break; 9225 } 9226 cur = cur->next; 9227 } 9228 9229 return (ret); 9230} 9231 9232/** 9233 * xmlRelaxNGNodeMatchesList: 9234 * @node: the node 9235 * @list: a NULL terminated array of definitions 9236 * 9237 * Check if a node can be matched by one of the definitions 9238 * 9239 * Returns 1 if matches 0 otherwise 9240 */ 9241static int 9242xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list) 9243{ 9244 xmlRelaxNGDefinePtr cur; 9245 int i = 0, tmp; 9246 9247 if ((node == NULL) || (list == NULL)) 9248 return (0); 9249 9250 cur = list[i++]; 9251 while (cur != NULL) { 9252 if ((node->type == XML_ELEMENT_NODE) && 9253 (cur->type == XML_RELAXNG_ELEMENT)) { 9254 tmp = xmlRelaxNGElementMatch(NULL, cur, node); 9255 if (tmp == 1) 9256 return (1); 9257 } else if (((node->type == XML_TEXT_NODE) || 9258 (node->type == XML_CDATA_SECTION_NODE)) && 9259 (cur->type == XML_RELAXNG_TEXT)) { 9260 return (1); 9261 } 9262 cur = list[i++]; 9263 } 9264 return (0); 9265} 9266 9267/** 9268 * xmlRelaxNGValidateInterleave: 9269 * @ctxt: a Relax-NG validation context 9270 * @define: the definition to verify 9271 * 9272 * Validate an interleave definition for a node. 9273 * 9274 * Returns 0 if the validation succeeded or an error code. 9275 */ 9276static int 9277xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, 9278 xmlRelaxNGDefinePtr define) 9279{ 9280 int ret = 0, i, nbgroups; 9281 int errNr = ctxt->errNr; 9282 int oldflags; 9283 9284 xmlRelaxNGValidStatePtr oldstate; 9285 xmlRelaxNGPartitionPtr partitions; 9286 xmlRelaxNGInterleaveGroupPtr group = NULL; 9287 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem; 9288 xmlNodePtr *list = NULL, *lasts = NULL; 9289 9290 if (define->data != NULL) { 9291 partitions = (xmlRelaxNGPartitionPtr) define->data; 9292 nbgroups = partitions->nbgroups; 9293 } else { 9294 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA); 9295 return (-1); 9296 } 9297 /* 9298 * Optimizations for MIXED 9299 */ 9300 oldflags = ctxt->flags; 9301 if (define->dflags & IS_MIXED) { 9302 ctxt->flags |= FLAGS_MIXED_CONTENT; 9303 if (nbgroups == 2) { 9304 /* 9305 * this is a pure <mixed> case 9306 */ 9307 if (ctxt->state != NULL) 9308 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, 9309 ctxt->state->seq); 9310 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT) 9311 ret = xmlRelaxNGValidateDefinition(ctxt, 9312 partitions->groups[1]-> 9313 rule); 9314 else 9315 ret = xmlRelaxNGValidateDefinition(ctxt, 9316 partitions->groups[0]-> 9317 rule); 9318 if (ret == 0) { 9319 if (ctxt->state != NULL) 9320 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, 9321 ctxt->state-> 9322 seq); 9323 } 9324 ctxt->flags = oldflags; 9325 return (ret); 9326 } 9327 } 9328 9329 /* 9330 * Build arrays to store the first and last node of the chain 9331 * pertaining to each group 9332 */ 9333 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); 9334 if (list == NULL) { 9335 xmlRngVErrMemory(ctxt, "validating\n"); 9336 return (-1); 9337 } 9338 memset(list, 0, nbgroups * sizeof(xmlNodePtr)); 9339 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); 9340 if (lasts == NULL) { 9341 xmlRngVErrMemory(ctxt, "validating\n"); 9342 return (-1); 9343 } 9344 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); 9345 9346 /* 9347 * Walk the sequence of children finding the right group and 9348 * sorting them in sequences. 9349 */ 9350 cur = ctxt->state->seq; 9351 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9352 start = cur; 9353 while (cur != NULL) { 9354 ctxt->state->seq = cur; 9355 if ((partitions->triage != NULL) && 9356 (partitions->flags & IS_DETERMINIST)) { 9357 void *tmp = NULL; 9358 9359 if ((cur->type == XML_TEXT_NODE) || 9360 (cur->type == XML_CDATA_SECTION_NODE)) { 9361 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text", 9362 NULL); 9363 } else if (cur->type == XML_ELEMENT_NODE) { 9364 if (cur->ns != NULL) { 9365 tmp = xmlHashLookup2(partitions->triage, cur->name, 9366 cur->ns->href); 9367 if (tmp == NULL) 9368 tmp = xmlHashLookup2(partitions->triage, 9369 BAD_CAST "#any", 9370 cur->ns->href); 9371 } else 9372 tmp = 9373 xmlHashLookup2(partitions->triage, cur->name, 9374 NULL); 9375 if (tmp == NULL) 9376 tmp = 9377 xmlHashLookup2(partitions->triage, BAD_CAST "#any", 9378 NULL); 9379 } 9380 9381 if (tmp == NULL) { 9382 i = nbgroups; 9383 } else { 9384 i = ((long) tmp) - 1; 9385 if (partitions->flags & IS_NEEDCHECK) { 9386 group = partitions->groups[i]; 9387 if (!xmlRelaxNGNodeMatchesList(cur, group->defs)) 9388 i = nbgroups; 9389 } 9390 } 9391 } else { 9392 for (i = 0; i < nbgroups; i++) { 9393 group = partitions->groups[i]; 9394 if (group == NULL) 9395 continue; 9396 if (xmlRelaxNGNodeMatchesList(cur, group->defs)) 9397 break; 9398 } 9399 } 9400 /* 9401 * We break as soon as an element not matched is found 9402 */ 9403 if (i >= nbgroups) { 9404 break; 9405 } 9406 if (lasts[i] != NULL) { 9407 lasts[i]->next = cur; 9408 lasts[i] = cur; 9409 } else { 9410 list[i] = cur; 9411 lasts[i] = cur; 9412 } 9413 if (cur->next != NULL) 9414 lastchg = cur->next; 9415 else 9416 lastchg = cur; 9417 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next); 9418 } 9419 if (ret != 0) { 9420 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); 9421 ret = -1; 9422 goto done; 9423 } 9424 lastelem = cur; 9425 oldstate = ctxt->state; 9426 for (i = 0; i < nbgroups; i++) { 9427 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate); 9428 if (ctxt->state == NULL) { 9429 ret = -1; 9430 break; 9431 } 9432 group = partitions->groups[i]; 9433 if (lasts[i] != NULL) { 9434 last = lasts[i]->next; 9435 lasts[i]->next = NULL; 9436 } 9437 ctxt->state->seq = list[i]; 9438 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule); 9439 if (ret != 0) 9440 break; 9441 if (ctxt->state != NULL) { 9442 cur = ctxt->state->seq; 9443 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9444 xmlRelaxNGFreeValidState(ctxt, oldstate); 9445 oldstate = ctxt->state; 9446 ctxt->state = NULL; 9447 if (cur != NULL) { 9448 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); 9449 ret = -1; 9450 ctxt->state = oldstate; 9451 goto done; 9452 } 9453 } else if (ctxt->states != NULL) { 9454 int j; 9455 int found = 0; 9456 int best = -1; 9457 int lowattr = -1; 9458 9459 /* 9460 * PBM: what happen if there is attributes checks in the interleaves 9461 */ 9462 9463 for (j = 0; j < ctxt->states->nbState; j++) { 9464 cur = ctxt->states->tabState[j]->seq; 9465 cur = xmlRelaxNGSkipIgnored(ctxt, cur); 9466 if (cur == NULL) { 9467 if (found == 0) { 9468 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9469 best = j; 9470 } 9471 found = 1; 9472 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { 9473 /* try to keep the latest one to mach old heuristic */ 9474 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9475 best = j; 9476 } 9477 if (lowattr == 0) 9478 break; 9479 } else if (found == 0) { 9480 if (lowattr == -1) { 9481 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9482 best = j; 9483 } else 9484 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { 9485 /* try to keep the latest one to mach old heuristic */ 9486 lowattr = ctxt->states->tabState[j]->nbAttrLeft; 9487 best = j; 9488 } 9489 } 9490 } 9491 /* 9492 * BIG PBM: here we pick only one restarting point :-( 9493 */ 9494 if (ctxt->states->nbState > 0) { 9495 xmlRelaxNGFreeValidState(ctxt, oldstate); 9496 if (best != -1) { 9497 oldstate = ctxt->states->tabState[best]; 9498 ctxt->states->tabState[best] = NULL; 9499 } else { 9500 oldstate = 9501 ctxt->states->tabState[ctxt->states->nbState - 1]; 9502 ctxt->states->tabState[ctxt->states->nbState - 1] = NULL; 9503 ctxt->states->nbState--; 9504 } 9505 } 9506 for (j = 0; j < ctxt->states->nbState ; j++) { 9507 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]); 9508 } 9509 xmlRelaxNGFreeStates(ctxt, ctxt->states); 9510 ctxt->states = NULL; 9511 if (found == 0) { 9512 if (cur == NULL) { 9513 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, 9514 (const xmlChar *) "noname"); 9515 } else { 9516 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); 9517 } 9518 ret = -1; 9519 ctxt->state = oldstate; 9520 goto done; 9521 } 9522 } else { 9523 ret = -1; 9524 break; 9525 } 9526 if (lasts[i] != NULL) { 9527 lasts[i]->next = last; 9528 } 9529 } 9530 if (ctxt->state != NULL) 9531 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 9532 ctxt->state = oldstate; 9533 ctxt->state->seq = lastelem; 9534 if (ret != 0) { 9535 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); 9536 ret = -1; 9537 goto done; 9538 } 9539 9540 done: 9541 ctxt->flags = oldflags; 9542 /* 9543 * builds the next links chain from the prev one 9544 */ 9545 cur = lastchg; 9546 while (cur != NULL) { 9547 if ((cur == start) || (cur->prev == NULL)) 9548 break; 9549 cur->prev->next = cur; 9550 cur = cur->prev; 9551 } 9552 if (ret == 0) { 9553 if (ctxt->errNr > errNr) 9554 xmlRelaxNGPopErrors(ctxt, errNr); 9555 } 9556 9557 xmlFree(list); 9558 xmlFree(lasts); 9559 return (ret); 9560} 9561 9562/** 9563 * xmlRelaxNGValidateDefinitionList: 9564 * @ctxt: a Relax-NG validation context 9565 * @define: the list of definition to verify 9566 * 9567 * Validate the given node content against the (list) of definitions 9568 * 9569 * Returns 0 if the validation succeeded or an error code. 9570 */ 9571static int 9572xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt, 9573 xmlRelaxNGDefinePtr defines) 9574{ 9575 int ret = 0, res; 9576 9577 9578 if (defines == NULL) { 9579 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, 9580 BAD_CAST "NULL definition list"); 9581 return (-1); 9582 } 9583 while (defines != NULL) { 9584 if ((ctxt->state != NULL) || (ctxt->states != NULL)) { 9585 res = xmlRelaxNGValidateDefinition(ctxt, defines); 9586 if (res < 0) 9587 ret = -1; 9588 } else { 9589 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); 9590 return (-1); 9591 } 9592 if (res == -1) /* continues on -2 */ 9593 break; 9594 defines = defines->next; 9595 } 9596 9597 return (ret); 9598} 9599 9600/** 9601 * xmlRelaxNGElementMatch: 9602 * @ctxt: a Relax-NG validation context 9603 * @define: the definition to check 9604 * @elem: the element 9605 * 9606 * Check if the element matches the definition nameClass 9607 * 9608 * Returns 1 if the element matches, 0 if no, or -1 in case of error 9609 */ 9610static int 9611xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 9612 xmlRelaxNGDefinePtr define, xmlNodePtr elem) 9613{ 9614 int ret = 0, oldflags = 0; 9615 9616 if (define->name != NULL) { 9617 if (!xmlStrEqual(elem->name, define->name)) { 9618 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name); 9619 return (0); 9620 } 9621 } 9622 if ((define->ns != NULL) && (define->ns[0] != 0)) { 9623 if (elem->ns == NULL) { 9624 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name); 9625 return (0); 9626 } else if (!xmlStrEqual(elem->ns->href, define->ns)) { 9627 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS, 9628 elem->name, define->ns); 9629 return (0); 9630 } 9631 } else if ((elem->ns != NULL) && (define->ns != NULL) && 9632 (define->name == NULL)) { 9633 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name); 9634 return (0); 9635 } else if ((elem->ns != NULL) && (define->name != NULL)) { 9636 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name); 9637 return (0); 9638 } 9639 9640 if (define->nameClass == NULL) 9641 return (1); 9642 9643 define = define->nameClass; 9644 if (define->type == XML_RELAXNG_EXCEPT) { 9645 xmlRelaxNGDefinePtr list; 9646 9647 if (ctxt != NULL) { 9648 oldflags = ctxt->flags; 9649 ctxt->flags |= FLAGS_IGNORABLE; 9650 } 9651 9652 list = define->content; 9653 while (list != NULL) { 9654 ret = xmlRelaxNGElementMatch(ctxt, list, elem); 9655 if (ret == 1) { 9656 if (ctxt != NULL) 9657 ctxt->flags = oldflags; 9658 return (0); 9659 } 9660 if (ret < 0) { 9661 if (ctxt != NULL) 9662 ctxt->flags = oldflags; 9663 return (ret); 9664 } 9665 list = list->next; 9666 } 9667 ret = 1; 9668 if (ctxt != NULL) { 9669 ctxt->flags = oldflags; 9670 } 9671 } else if (define->type == XML_RELAXNG_CHOICE) { 9672 xmlRelaxNGDefinePtr list; 9673 9674 if (ctxt != NULL) { 9675 oldflags = ctxt->flags; 9676 ctxt->flags |= FLAGS_IGNORABLE; 9677 } 9678 9679 list = define->nameClass; 9680 while (list != NULL) { 9681 ret = xmlRelaxNGElementMatch(ctxt, list, elem); 9682 if (ret == 1) { 9683 if (ctxt != NULL) 9684 ctxt->flags = oldflags; 9685 return (1); 9686 } 9687 if (ret < 0) { 9688 if (ctxt != NULL) 9689 ctxt->flags = oldflags; 9690 return (ret); 9691 } 9692 list = list->next; 9693 } 9694 if (ctxt != NULL) { 9695 if (ret != 0) { 9696 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9697 xmlRelaxNGDumpValidError(ctxt); 9698 } else { 9699 if (ctxt->errNr > 0) 9700 xmlRelaxNGPopErrors(ctxt, 0); 9701 } 9702 } 9703 ret = 0; 9704 if (ctxt != NULL) { 9705 ctxt->flags = oldflags; 9706 } 9707 } else { 9708 TODO ret = -1; 9709 } 9710 return (ret); 9711} 9712 9713/** 9714 * xmlRelaxNGBestState: 9715 * @ctxt: a Relax-NG validation context 9716 * 9717 * Find the "best" state in the ctxt->states list of states to report 9718 * errors about. I.e. a state with no element left in the child list 9719 * or the one with the less attributes left. 9720 * This is called only if a falidation error was detected 9721 * 9722 * Returns the index of the "best" state or -1 in case of error 9723 */ 9724static int 9725xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt) 9726{ 9727 xmlRelaxNGValidStatePtr state; 9728 int i, tmp; 9729 int best = -1; 9730 int value = 1000000; 9731 9732 if ((ctxt == NULL) || (ctxt->states == NULL) || 9733 (ctxt->states->nbState <= 0)) 9734 return (-1); 9735 9736 for (i = 0; i < ctxt->states->nbState; i++) { 9737 state = ctxt->states->tabState[i]; 9738 if (state == NULL) 9739 continue; 9740 if (state->seq != NULL) { 9741 if ((best == -1) || (value > 100000)) { 9742 value = 100000; 9743 best = i; 9744 } 9745 } else { 9746 tmp = state->nbAttrLeft; 9747 if ((best == -1) || (value > tmp)) { 9748 value = tmp; 9749 best = i; 9750 } 9751 } 9752 } 9753 return (best); 9754} 9755 9756/** 9757 * xmlRelaxNGLogBestError: 9758 * @ctxt: a Relax-NG validation context 9759 * 9760 * Find the "best" state in the ctxt->states list of states to report 9761 * errors about and log it. 9762 */ 9763static void 9764xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt) 9765{ 9766 int best; 9767 9768 if ((ctxt == NULL) || (ctxt->states == NULL) || 9769 (ctxt->states->nbState <= 0)) 9770 return; 9771 9772 best = xmlRelaxNGBestState(ctxt); 9773 if ((best >= 0) && (best < ctxt->states->nbState)) { 9774 ctxt->state = ctxt->states->tabState[best]; 9775 9776 xmlRelaxNGValidateElementEnd(ctxt, 1); 9777 } 9778} 9779 9780/** 9781 * xmlRelaxNGValidateElementEnd: 9782 * @ctxt: a Relax-NG validation context 9783 * @dolog: indicate that error logging should be done 9784 * 9785 * Validate the end of the element, implements check that 9786 * there is nothing left not consumed in the element content 9787 * or in the attribute list. 9788 * 9789 * Returns 0 if the validation succeeded or an error code. 9790 */ 9791static int 9792xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog) 9793{ 9794 int i; 9795 xmlRelaxNGValidStatePtr state; 9796 9797 state = ctxt->state; 9798 if (state->seq != NULL) { 9799 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq); 9800 if (state->seq != NULL) { 9801 if (dolog) { 9802 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT, 9803 state->node->name, state->seq->name); 9804 } 9805 return (-1); 9806 } 9807 } 9808 for (i = 0; i < state->nbAttrs; i++) { 9809 if (state->attrs[i] != NULL) { 9810 if (dolog) { 9811 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR, 9812 state->attrs[i]->name, state->node->name); 9813 } 9814 return (-1 - i); 9815 } 9816 } 9817 return (0); 9818} 9819 9820/** 9821 * xmlRelaxNGValidateState: 9822 * @ctxt: a Relax-NG validation context 9823 * @define: the definition to verify 9824 * 9825 * Validate the current state against the definition 9826 * 9827 * Returns 0 if the validation succeeded or an error code. 9828 */ 9829static int 9830xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, 9831 xmlRelaxNGDefinePtr define) 9832{ 9833 xmlNodePtr node; 9834 int ret = 0, i, tmp, oldflags, errNr; 9835 xmlRelaxNGValidStatePtr oldstate = NULL, state; 9836 9837 if (define == NULL) { 9838 VALID_ERR(XML_RELAXNG_ERR_NODEFINE); 9839 return (-1); 9840 } 9841 9842 if (ctxt->state != NULL) { 9843 node = ctxt->state->seq; 9844 } else { 9845 node = NULL; 9846 } 9847#ifdef DEBUG 9848 for (i = 0; i < ctxt->depth; i++) 9849 xmlGenericError(xmlGenericErrorContext, " "); 9850 xmlGenericError(xmlGenericErrorContext, 9851 "Start validating %s ", xmlRelaxNGDefName(define)); 9852 if (define->name != NULL) 9853 xmlGenericError(xmlGenericErrorContext, "%s ", define->name); 9854 if ((node != NULL) && (node->name != NULL)) 9855 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name); 9856 else 9857 xmlGenericError(xmlGenericErrorContext, "\n"); 9858#endif 9859 ctxt->depth++; 9860 switch (define->type) { 9861 case XML_RELAXNG_EMPTY: 9862 xmlRelaxNGSkipIgnored(ctxt, node); 9863 ret = 0; 9864 break; 9865 case XML_RELAXNG_NOT_ALLOWED: 9866 ret = -1; 9867 break; 9868 case XML_RELAXNG_TEXT: 9869 while ((node != NULL) && 9870 ((node->type == XML_TEXT_NODE) || 9871 (node->type == XML_COMMENT_NODE) || 9872 (node->type == XML_PI_NODE) || 9873 (node->type == XML_CDATA_SECTION_NODE))) 9874 node = node->next; 9875 ctxt->state->seq = node; 9876 break; 9877 case XML_RELAXNG_ELEMENT: 9878 errNr = ctxt->errNr; 9879 node = xmlRelaxNGSkipIgnored(ctxt, node); 9880 if (node == NULL) { 9881 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name); 9882 ret = -1; 9883 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9884 xmlRelaxNGDumpValidError(ctxt); 9885 break; 9886 } 9887 if (node->type != XML_ELEMENT_NODE) { 9888 VALID_ERR(XML_RELAXNG_ERR_NOTELEM); 9889 ret = -1; 9890 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9891 xmlRelaxNGDumpValidError(ctxt); 9892 break; 9893 } 9894 /* 9895 * This node was already validated successfully against 9896 * this definition. 9897 */ 9898 if (node->psvi == define) { 9899 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); 9900 if (ctxt->errNr > errNr) 9901 xmlRelaxNGPopErrors(ctxt, errNr); 9902 if (ctxt->errNr != 0) { 9903 while ((ctxt->err != NULL) && 9904 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) 9905 && (xmlStrEqual(ctxt->err->arg2, node->name))) 9906 || 9907 ((ctxt->err->err == 9908 XML_RELAXNG_ERR_ELEMEXTRANS) 9909 && (xmlStrEqual(ctxt->err->arg1, node->name))) 9910 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) 9911 || (ctxt->err->err == 9912 XML_RELAXNG_ERR_NOTELEM))) 9913 xmlRelaxNGValidErrorPop(ctxt); 9914 } 9915 break; 9916 } 9917 9918 ret = xmlRelaxNGElementMatch(ctxt, define, node); 9919 if (ret <= 0) { 9920 ret = -1; 9921 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9922 xmlRelaxNGDumpValidError(ctxt); 9923 break; 9924 } 9925 ret = 0; 9926 if (ctxt->errNr != 0) { 9927 if (ctxt->errNr > errNr) 9928 xmlRelaxNGPopErrors(ctxt, errNr); 9929 while ((ctxt->err != NULL) && 9930 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) && 9931 (xmlStrEqual(ctxt->err->arg2, node->name))) || 9932 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) && 9933 (xmlStrEqual(ctxt->err->arg1, node->name))) || 9934 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) || 9935 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM))) 9936 xmlRelaxNGValidErrorPop(ctxt); 9937 } 9938 errNr = ctxt->errNr; 9939 9940 oldflags = ctxt->flags; 9941 if (ctxt->flags & FLAGS_MIXED_CONTENT) { 9942 ctxt->flags -= FLAGS_MIXED_CONTENT; 9943 } 9944 state = xmlRelaxNGNewValidState(ctxt, node); 9945 if (state == NULL) { 9946 ret = -1; 9947 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) 9948 xmlRelaxNGDumpValidError(ctxt); 9949 break; 9950 } 9951 9952 oldstate = ctxt->state; 9953 ctxt->state = state; 9954 if (define->attrs != NULL) { 9955 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); 9956 if (tmp != 0) { 9957 ret = -1; 9958 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); 9959 } 9960 } 9961 if (define->contModel != NULL) { 9962 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state; 9963 xmlRelaxNGStatesPtr tmpstates = ctxt->states; 9964 xmlNodePtr nseq; 9965 9966 nstate = xmlRelaxNGNewValidState(ctxt, node); 9967 ctxt->state = nstate; 9968 ctxt->states = NULL; 9969 9970 tmp = xmlRelaxNGValidateCompiledContent(ctxt, 9971 define->contModel, 9972 ctxt->state->seq); 9973 nseq = ctxt->state->seq; 9974 ctxt->state = tmpstate; 9975 ctxt->states = tmpstates; 9976 xmlRelaxNGFreeValidState(ctxt, nstate); 9977 9978#ifdef DEBUG_COMPILE 9979 xmlGenericError(xmlGenericErrorContext, 9980 "Validating content of '%s' : %d\n", 9981 define->name, tmp); 9982#endif 9983 if (tmp != 0) 9984 ret = -1; 9985 9986 if (ctxt->states != NULL) { 9987 tmp = -1; 9988 9989 for (i = 0; i < ctxt->states->nbState; i++) { 9990 state = ctxt->states->tabState[i]; 9991 ctxt->state = state; 9992 ctxt->state->seq = nseq; 9993 9994 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 9995 tmp = 0; 9996 break; 9997 } 9998 } 9999 if (tmp != 0) { 10000 /* 10001 * validation error, log the message for the "best" one 10002 */ 10003 ctxt->flags |= FLAGS_IGNORABLE; 10004 xmlRelaxNGLogBestError(ctxt); 10005 } 10006 for (i = 0; i < ctxt->states->nbState; i++) { 10007 xmlRelaxNGFreeValidState(ctxt, 10008 ctxt->states-> 10009 tabState[i]); 10010 } 10011 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10012 ctxt->flags = oldflags; 10013 ctxt->states = NULL; 10014 if ((ret == 0) && (tmp == -1)) 10015 ret = -1; 10016 } else { 10017 state = ctxt->state; 10018 if (ctxt->state != NULL) 10019 ctxt->state->seq = nseq; 10020 if (ret == 0) 10021 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 10022 xmlRelaxNGFreeValidState(ctxt, state); 10023 } 10024 } else { 10025 if (define->content != NULL) { 10026 tmp = xmlRelaxNGValidateDefinitionList(ctxt, 10027 define-> 10028 content); 10029 if (tmp != 0) { 10030 ret = -1; 10031 if (ctxt->state == NULL) { 10032 ctxt->state = oldstate; 10033 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, 10034 node->name); 10035 ctxt->state = NULL; 10036 } else { 10037 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, 10038 node->name); 10039 } 10040 10041 } 10042 } 10043 if (ctxt->states != NULL) { 10044 tmp = -1; 10045 10046 for (i = 0; i < ctxt->states->nbState; i++) { 10047 state = ctxt->states->tabState[i]; 10048 ctxt->state = state; 10049 10050 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { 10051 tmp = 0; 10052 break; 10053 } 10054 } 10055 if (tmp != 0) { 10056 /* 10057 * validation error, log the message for the "best" one 10058 */ 10059 ctxt->flags |= FLAGS_IGNORABLE; 10060 xmlRelaxNGLogBestError(ctxt); 10061 } 10062 for (i = 0; i < ctxt->states->nbState; i++) { 10063 xmlRelaxNGFreeValidState(ctxt, 10064 ctxt->states->tabState[i]); 10065 ctxt->states->tabState[i] = NULL; 10066 } 10067 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10068 ctxt->flags = oldflags; 10069 ctxt->states = NULL; 10070 if ((ret == 0) && (tmp == -1)) 10071 ret = -1; 10072 } else { 10073 state = ctxt->state; 10074 if (ret == 0) 10075 ret = xmlRelaxNGValidateElementEnd(ctxt, 1); 10076 xmlRelaxNGFreeValidState(ctxt, state); 10077 } 10078 } 10079 if (ret == 0) { 10080 node->psvi = define; 10081 } 10082 ctxt->flags = oldflags; 10083 ctxt->state = oldstate; 10084 if (oldstate != NULL) 10085 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); 10086 if (ret != 0) { 10087 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 10088 xmlRelaxNGDumpValidError(ctxt); 10089 ret = 0; 10090#if 0 10091 } else { 10092 ret = -2; 10093#endif 10094 } 10095 } else { 10096 if (ctxt->errNr > errNr) 10097 xmlRelaxNGPopErrors(ctxt, errNr); 10098 } 10099 10100#ifdef DEBUG 10101 xmlGenericError(xmlGenericErrorContext, 10102 "xmlRelaxNGValidateDefinition(): validated %s : %d", 10103 node->name, ret); 10104 if (oldstate == NULL) 10105 xmlGenericError(xmlGenericErrorContext, ": no state\n"); 10106 else if (oldstate->seq == NULL) 10107 xmlGenericError(xmlGenericErrorContext, ": done\n"); 10108 else if (oldstate->seq->type == XML_ELEMENT_NODE) 10109 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n", 10110 oldstate->seq->name); 10111 else 10112 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n", 10113 oldstate->seq->name, oldstate->seq->type); 10114#endif 10115 break; 10116 case XML_RELAXNG_OPTIONAL:{ 10117 errNr = ctxt->errNr; 10118 oldflags = ctxt->flags; 10119 ctxt->flags |= FLAGS_IGNORABLE; 10120 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); 10121 ret = 10122 xmlRelaxNGValidateDefinitionList(ctxt, 10123 define->content); 10124 if (ret != 0) { 10125 if (ctxt->state != NULL) 10126 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10127 ctxt->state = oldstate; 10128 ctxt->flags = oldflags; 10129 ret = 0; 10130 if (ctxt->errNr > errNr) 10131 xmlRelaxNGPopErrors(ctxt, errNr); 10132 break; 10133 } 10134 if (ctxt->states != NULL) { 10135 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); 10136 } else { 10137 ctxt->states = xmlRelaxNGNewStates(ctxt, 1); 10138 if (ctxt->states == NULL) { 10139 xmlRelaxNGFreeValidState(ctxt, oldstate); 10140 ctxt->flags = oldflags; 10141 ret = -1; 10142 if (ctxt->errNr > errNr) 10143 xmlRelaxNGPopErrors(ctxt, errNr); 10144 break; 10145 } 10146 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); 10147 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state); 10148 ctxt->state = NULL; 10149 } 10150 ctxt->flags = oldflags; 10151 ret = 0; 10152 if (ctxt->errNr > errNr) 10153 xmlRelaxNGPopErrors(ctxt, errNr); 10154 break; 10155 } 10156 case XML_RELAXNG_ONEORMORE: 10157 errNr = ctxt->errNr; 10158 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); 10159 if (ret != 0) { 10160 break; 10161 } 10162 if (ctxt->errNr > errNr) 10163 xmlRelaxNGPopErrors(ctxt, errNr); 10164 /* no break on purpose */ 10165 case XML_RELAXNG_ZEROORMORE:{ 10166 int progress; 10167 xmlRelaxNGStatesPtr states = NULL, res = NULL; 10168 int base, j; 10169 10170 errNr = ctxt->errNr; 10171 res = xmlRelaxNGNewStates(ctxt, 1); 10172 if (res == NULL) { 10173 ret = -1; 10174 break; 10175 } 10176 /* 10177 * All the input states are also exit states 10178 */ 10179 if (ctxt->state != NULL) { 10180 xmlRelaxNGAddStates(ctxt, res, 10181 xmlRelaxNGCopyValidState(ctxt, 10182 ctxt-> 10183 state)); 10184 } else { 10185 for (j = 0; j < ctxt->states->nbState; j++) { 10186 xmlRelaxNGAddStates(ctxt, res, 10187 xmlRelaxNGCopyValidState(ctxt, 10188 ctxt->states->tabState[j])); 10189 } 10190 } 10191 oldflags = ctxt->flags; 10192 ctxt->flags |= FLAGS_IGNORABLE; 10193 do { 10194 progress = 0; 10195 base = res->nbState; 10196 10197 if (ctxt->states != NULL) { 10198 states = ctxt->states; 10199 for (i = 0; i < states->nbState; i++) { 10200 ctxt->state = states->tabState[i]; 10201 ctxt->states = NULL; 10202 ret = xmlRelaxNGValidateDefinitionList(ctxt, 10203 define-> 10204 content); 10205 if (ret == 0) { 10206 if (ctxt->state != NULL) { 10207 tmp = xmlRelaxNGAddStates(ctxt, res, 10208 ctxt->state); 10209 ctxt->state = NULL; 10210 if (tmp == 1) 10211 progress = 1; 10212 } else if (ctxt->states != NULL) { 10213 for (j = 0; j < ctxt->states->nbState; 10214 j++) { 10215 tmp = 10216 xmlRelaxNGAddStates(ctxt, res, 10217 ctxt->states->tabState[j]); 10218 if (tmp == 1) 10219 progress = 1; 10220 } 10221 xmlRelaxNGFreeStates(ctxt, 10222 ctxt->states); 10223 ctxt->states = NULL; 10224 } 10225 } else { 10226 if (ctxt->state != NULL) { 10227 xmlRelaxNGFreeValidState(ctxt, 10228 ctxt->state); 10229 ctxt->state = NULL; 10230 } 10231 } 10232 } 10233 } else { 10234 ret = xmlRelaxNGValidateDefinitionList(ctxt, 10235 define-> 10236 content); 10237 if (ret != 0) { 10238 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10239 ctxt->state = NULL; 10240 } else { 10241 base = res->nbState; 10242 if (ctxt->state != NULL) { 10243 tmp = xmlRelaxNGAddStates(ctxt, res, 10244 ctxt->state); 10245 ctxt->state = NULL; 10246 if (tmp == 1) 10247 progress = 1; 10248 } else if (ctxt->states != NULL) { 10249 for (j = 0; j < ctxt->states->nbState; j++) { 10250 tmp = xmlRelaxNGAddStates(ctxt, res, 10251 ctxt->states->tabState[j]); 10252 if (tmp == 1) 10253 progress = 1; 10254 } 10255 if (states == NULL) { 10256 states = ctxt->states; 10257 } else { 10258 xmlRelaxNGFreeStates(ctxt, 10259 ctxt->states); 10260 } 10261 ctxt->states = NULL; 10262 } 10263 } 10264 } 10265 if (progress) { 10266 /* 10267 * Collect all the new nodes added at that step 10268 * and make them the new node set 10269 */ 10270 if (res->nbState - base == 1) { 10271 ctxt->state = xmlRelaxNGCopyValidState(ctxt, 10272 res-> 10273 tabState 10274 [base]); 10275 } else { 10276 if (states == NULL) { 10277 xmlRelaxNGNewStates(ctxt, 10278 res->nbState - base); 10279 states = ctxt->states; 10280 if (states == NULL) { 10281 progress = 0; 10282 break; 10283 } 10284 } 10285 states->nbState = 0; 10286 for (i = base; i < res->nbState; i++) 10287 xmlRelaxNGAddStates(ctxt, states, 10288 xmlRelaxNGCopyValidState 10289 (ctxt, res->tabState[i])); 10290 ctxt->states = states; 10291 } 10292 } 10293 } while (progress == 1); 10294 if (states != NULL) { 10295 xmlRelaxNGFreeStates(ctxt, states); 10296 } 10297 ctxt->states = res; 10298 ctxt->flags = oldflags; 10299#if 0 10300 /* 10301 * errors may have to be propagated back... 10302 */ 10303 if (ctxt->errNr > errNr) 10304 xmlRelaxNGPopErrors(ctxt, errNr); 10305#endif 10306 ret = 0; 10307 break; 10308 } 10309 case XML_RELAXNG_CHOICE:{ 10310 xmlRelaxNGDefinePtr list = NULL; 10311 xmlRelaxNGStatesPtr states = NULL; 10312 10313 node = xmlRelaxNGSkipIgnored(ctxt, node); 10314 10315 errNr = ctxt->errNr; 10316 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) && 10317 (node != NULL)) { 10318 /* 10319 * node == NULL can't be optimized since IS_TRIABLE 10320 * doesn't account for choice which may lead to 10321 * only attributes. 10322 */ 10323 xmlHashTablePtr triage = 10324 (xmlHashTablePtr) define->data; 10325 10326 /* 10327 * Something we can optimize cleanly there is only one 10328 * possble branch out ! 10329 */ 10330 if ((node->type == XML_TEXT_NODE) || 10331 (node->type == XML_CDATA_SECTION_NODE)) { 10332 list = 10333 xmlHashLookup2(triage, BAD_CAST "#text", NULL); 10334 } else if (node->type == XML_ELEMENT_NODE) { 10335 if (node->ns != NULL) { 10336 list = xmlHashLookup2(triage, node->name, 10337 node->ns->href); 10338 if (list == NULL) 10339 list = 10340 xmlHashLookup2(triage, BAD_CAST "#any", 10341 node->ns->href); 10342 } else 10343 list = 10344 xmlHashLookup2(triage, node->name, NULL); 10345 if (list == NULL) 10346 list = 10347 xmlHashLookup2(triage, BAD_CAST "#any", 10348 NULL); 10349 } 10350 if (list == NULL) { 10351 ret = -1; 10352 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name); 10353 break; 10354 } 10355 ret = xmlRelaxNGValidateDefinition(ctxt, list); 10356 if (ret == 0) { 10357 } 10358 break; 10359 } 10360 10361 list = define->content; 10362 oldflags = ctxt->flags; 10363 ctxt->flags |= FLAGS_IGNORABLE; 10364 10365 while (list != NULL) { 10366 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); 10367 ret = xmlRelaxNGValidateDefinition(ctxt, list); 10368 if (ret == 0) { 10369 if (states == NULL) { 10370 states = xmlRelaxNGNewStates(ctxt, 1); 10371 } 10372 if (ctxt->state != NULL) { 10373 xmlRelaxNGAddStates(ctxt, states, ctxt->state); 10374 } else if (ctxt->states != NULL) { 10375 for (i = 0; i < ctxt->states->nbState; i++) { 10376 xmlRelaxNGAddStates(ctxt, states, 10377 ctxt->states-> 10378 tabState[i]); 10379 } 10380 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10381 ctxt->states = NULL; 10382 } 10383 } else { 10384 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10385 } 10386 ctxt->state = oldstate; 10387 list = list->next; 10388 } 10389 if (states != NULL) { 10390 xmlRelaxNGFreeValidState(ctxt, oldstate); 10391 ctxt->states = states; 10392 ctxt->state = NULL; 10393 ret = 0; 10394 } else { 10395 ctxt->states = NULL; 10396 } 10397 ctxt->flags = oldflags; 10398 if (ret != 0) { 10399 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { 10400 xmlRelaxNGDumpValidError(ctxt); 10401 } 10402 } else { 10403 if (ctxt->errNr > errNr) 10404 xmlRelaxNGPopErrors(ctxt, errNr); 10405 } 10406 break; 10407 } 10408 case XML_RELAXNG_DEF: 10409 case XML_RELAXNG_GROUP: 10410 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); 10411 break; 10412 case XML_RELAXNG_INTERLEAVE: 10413 ret = xmlRelaxNGValidateInterleave(ctxt, define); 10414 break; 10415 case XML_RELAXNG_ATTRIBUTE: 10416 ret = xmlRelaxNGValidateAttribute(ctxt, define); 10417 break; 10418 case XML_RELAXNG_START: 10419 case XML_RELAXNG_NOOP: 10420 case XML_RELAXNG_REF: 10421 case XML_RELAXNG_EXTERNALREF: 10422 case XML_RELAXNG_PARENTREF: 10423 ret = xmlRelaxNGValidateDefinition(ctxt, define->content); 10424 break; 10425 case XML_RELAXNG_DATATYPE:{ 10426 xmlNodePtr child; 10427 xmlChar *content = NULL; 10428 10429 child = node; 10430 while (child != NULL) { 10431 if (child->type == XML_ELEMENT_NODE) { 10432 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM, 10433 node->parent->name); 10434 ret = -1; 10435 break; 10436 } else if ((child->type == XML_TEXT_NODE) || 10437 (child->type == XML_CDATA_SECTION_NODE)) { 10438 content = xmlStrcat(content, child->content); 10439 } 10440 /* TODO: handle entities ... */ 10441 child = child->next; 10442 } 10443 if (ret == -1) { 10444 if (content != NULL) 10445 xmlFree(content); 10446 break; 10447 } 10448 if (content == NULL) { 10449 content = xmlStrdup(BAD_CAST ""); 10450 if (content == NULL) { 10451 xmlRngVErrMemory(ctxt, "validating\n"); 10452 ret = -1; 10453 break; 10454 } 10455 } 10456 ret = xmlRelaxNGValidateDatatype(ctxt, content, define, 10457 ctxt->state->seq); 10458 if (ret == -1) { 10459 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name); 10460 } else if (ret == 0) { 10461 ctxt->state->seq = NULL; 10462 } 10463 if (content != NULL) 10464 xmlFree(content); 10465 break; 10466 } 10467 case XML_RELAXNG_VALUE:{ 10468 xmlChar *content = NULL; 10469 xmlChar *oldvalue; 10470 xmlNodePtr child; 10471 10472 child = node; 10473 while (child != NULL) { 10474 if (child->type == XML_ELEMENT_NODE) { 10475 VALID_ERR2(XML_RELAXNG_ERR_VALELEM, 10476 node->parent->name); 10477 ret = -1; 10478 break; 10479 } else if ((child->type == XML_TEXT_NODE) || 10480 (child->type == XML_CDATA_SECTION_NODE)) { 10481 content = xmlStrcat(content, child->content); 10482 } 10483 /* TODO: handle entities ... */ 10484 child = child->next; 10485 } 10486 if (ret == -1) { 10487 if (content != NULL) 10488 xmlFree(content); 10489 break; 10490 } 10491 if (content == NULL) { 10492 content = xmlStrdup(BAD_CAST ""); 10493 if (content == NULL) { 10494 xmlRngVErrMemory(ctxt, "validating\n"); 10495 ret = -1; 10496 break; 10497 } 10498 } 10499 oldvalue = ctxt->state->value; 10500 ctxt->state->value = content; 10501 ret = xmlRelaxNGValidateValue(ctxt, define); 10502 ctxt->state->value = oldvalue; 10503 if (ret == -1) { 10504 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name); 10505 } else if (ret == 0) { 10506 ctxt->state->seq = NULL; 10507 } 10508 if (content != NULL) 10509 xmlFree(content); 10510 break; 10511 } 10512 case XML_RELAXNG_LIST:{ 10513 xmlChar *content; 10514 xmlNodePtr child; 10515 xmlChar *oldvalue, *oldendvalue; 10516 int len; 10517 10518 /* 10519 * Make sure it's only text nodes 10520 */ 10521 10522 content = NULL; 10523 child = node; 10524 while (child != NULL) { 10525 if (child->type == XML_ELEMENT_NODE) { 10526 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM, 10527 node->parent->name); 10528 ret = -1; 10529 break; 10530 } else if ((child->type == XML_TEXT_NODE) || 10531 (child->type == XML_CDATA_SECTION_NODE)) { 10532 content = xmlStrcat(content, child->content); 10533 } 10534 /* TODO: handle entities ... */ 10535 child = child->next; 10536 } 10537 if (ret == -1) { 10538 if (content != NULL) 10539 xmlFree(content); 10540 break; 10541 } 10542 if (content == NULL) { 10543 content = xmlStrdup(BAD_CAST ""); 10544 if (content == NULL) { 10545 xmlRngVErrMemory(ctxt, "validating\n"); 10546 ret = -1; 10547 break; 10548 } 10549 } 10550 len = xmlStrlen(content); 10551 oldvalue = ctxt->state->value; 10552 oldendvalue = ctxt->state->endvalue; 10553 ctxt->state->value = content; 10554 ctxt->state->endvalue = content + len; 10555 ret = xmlRelaxNGValidateValue(ctxt, define); 10556 ctxt->state->value = oldvalue; 10557 ctxt->state->endvalue = oldendvalue; 10558 if (ret == -1) { 10559 VALID_ERR(XML_RELAXNG_ERR_LIST); 10560 } else if ((ret == 0) && (node != NULL)) { 10561 ctxt->state->seq = node->next; 10562 } 10563 if (content != NULL) 10564 xmlFree(content); 10565 break; 10566 } 10567 case XML_RELAXNG_EXCEPT: 10568 case XML_RELAXNG_PARAM: 10569 TODO ret = -1; 10570 break; 10571 } 10572 ctxt->depth--; 10573#ifdef DEBUG 10574 for (i = 0; i < ctxt->depth; i++) 10575 xmlGenericError(xmlGenericErrorContext, " "); 10576 xmlGenericError(xmlGenericErrorContext, 10577 "Validating %s ", xmlRelaxNGDefName(define)); 10578 if (define->name != NULL) 10579 xmlGenericError(xmlGenericErrorContext, "%s ", define->name); 10580 if (ret == 0) 10581 xmlGenericError(xmlGenericErrorContext, "suceeded\n"); 10582 else 10583 xmlGenericError(xmlGenericErrorContext, "failed\n"); 10584#endif 10585 return (ret); 10586} 10587 10588/** 10589 * xmlRelaxNGValidateDefinition: 10590 * @ctxt: a Relax-NG validation context 10591 * @define: the definition to verify 10592 * 10593 * Validate the current node lists against the definition 10594 * 10595 * Returns 0 if the validation succeeded or an error code. 10596 */ 10597static int 10598xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 10599 xmlRelaxNGDefinePtr define) 10600{ 10601 xmlRelaxNGStatesPtr states, res; 10602 int i, j, k, ret, oldflags; 10603 10604 /* 10605 * We should NOT have both ctxt->state and ctxt->states 10606 */ 10607 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10608 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10609 ctxt->state = NULL; 10610 } 10611 10612 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) { 10613 if (ctxt->states != NULL) { 10614 ctxt->state = ctxt->states->tabState[0]; 10615 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10616 ctxt->states = NULL; 10617 } 10618 ret = xmlRelaxNGValidateState(ctxt, define); 10619 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10620 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10621 ctxt->state = NULL; 10622 } 10623 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { 10624 ctxt->state = ctxt->states->tabState[0]; 10625 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10626 ctxt->states = NULL; 10627 } 10628 return (ret); 10629 } 10630 10631 states = ctxt->states; 10632 ctxt->states = NULL; 10633 res = NULL; 10634 j = 0; 10635 oldflags = ctxt->flags; 10636 ctxt->flags |= FLAGS_IGNORABLE; 10637 for (i = 0; i < states->nbState; i++) { 10638 ctxt->state = states->tabState[i]; 10639 ctxt->states = NULL; 10640 ret = xmlRelaxNGValidateState(ctxt, define); 10641 /* 10642 * We should NOT have both ctxt->state and ctxt->states 10643 */ 10644 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10645 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10646 ctxt->state = NULL; 10647 } 10648 if (ret == 0) { 10649 if (ctxt->states == NULL) { 10650 if (res != NULL) { 10651 /* add the state to the container */ 10652 xmlRelaxNGAddStates(ctxt, res, ctxt->state); 10653 ctxt->state = NULL; 10654 } else { 10655 /* add the state directly in states */ 10656 states->tabState[j++] = ctxt->state; 10657 ctxt->state = NULL; 10658 } 10659 } else { 10660 if (res == NULL) { 10661 /* make it the new container and copy other results */ 10662 res = ctxt->states; 10663 ctxt->states = NULL; 10664 for (k = 0; k < j; k++) 10665 xmlRelaxNGAddStates(ctxt, res, 10666 states->tabState[k]); 10667 } else { 10668 /* add all the new results to res and reff the container */ 10669 for (k = 0; k < ctxt->states->nbState; k++) 10670 xmlRelaxNGAddStates(ctxt, res, 10671 ctxt->states->tabState[k]); 10672 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10673 ctxt->states = NULL; 10674 } 10675 } 10676 } else { 10677 if (ctxt->state != NULL) { 10678 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10679 ctxt->state = NULL; 10680 } else if (ctxt->states != NULL) { 10681 for (k = 0; k < ctxt->states->nbState; k++) 10682 xmlRelaxNGFreeValidState(ctxt, 10683 ctxt->states->tabState[k]); 10684 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10685 ctxt->states = NULL; 10686 } 10687 } 10688 } 10689 ctxt->flags = oldflags; 10690 if (res != NULL) { 10691 xmlRelaxNGFreeStates(ctxt, states); 10692 ctxt->states = res; 10693 ret = 0; 10694 } else if (j > 1) { 10695 states->nbState = j; 10696 ctxt->states = states; 10697 ret = 0; 10698 } else if (j == 1) { 10699 ctxt->state = states->tabState[0]; 10700 xmlRelaxNGFreeStates(ctxt, states); 10701 ret = 0; 10702 } else { 10703 ret = -1; 10704 xmlRelaxNGFreeStates(ctxt, states); 10705 if (ctxt->states != NULL) { 10706 xmlRelaxNGFreeStates(ctxt, ctxt->states); 10707 ctxt->states = NULL; 10708 } 10709 } 10710 if ((ctxt->state != NULL) && (ctxt->states != NULL)) { 10711 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10712 ctxt->state = NULL; 10713 } 10714 return (ret); 10715} 10716 10717/** 10718 * xmlRelaxNGValidateDocument: 10719 * @ctxt: a Relax-NG validation context 10720 * @doc: the document 10721 * 10722 * Validate the given document 10723 * 10724 * Returns 0 if the validation succeeded or an error code. 10725 */ 10726static int 10727xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) 10728{ 10729 int ret; 10730 xmlRelaxNGPtr schema; 10731 xmlRelaxNGGrammarPtr grammar; 10732 xmlRelaxNGValidStatePtr state; 10733 xmlNodePtr node; 10734 10735 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL)) 10736 return (-1); 10737 10738 ctxt->errNo = XML_RELAXNG_OK; 10739 schema = ctxt->schema; 10740 grammar = schema->topgrammar; 10741 if (grammar == NULL) { 10742 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); 10743 return (-1); 10744 } 10745 state = xmlRelaxNGNewValidState(ctxt, NULL); 10746 ctxt->state = state; 10747 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start); 10748 if ((ctxt->state != NULL) && (state->seq != NULL)) { 10749 state = ctxt->state; 10750 node = state->seq; 10751 node = xmlRelaxNGSkipIgnored(ctxt, node); 10752 if (node != NULL) { 10753 if (ret != -1) { 10754 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); 10755 ret = -1; 10756 } 10757 } 10758 } else if (ctxt->states != NULL) { 10759 int i; 10760 int tmp = -1; 10761 10762 for (i = 0; i < ctxt->states->nbState; i++) { 10763 state = ctxt->states->tabState[i]; 10764 node = state->seq; 10765 node = xmlRelaxNGSkipIgnored(ctxt, node); 10766 if (node == NULL) 10767 tmp = 0; 10768 xmlRelaxNGFreeValidState(ctxt, state); 10769 } 10770 if (tmp == -1) { 10771 if (ret != -1) { 10772 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); 10773 ret = -1; 10774 } 10775 } 10776 } 10777 if (ctxt->state != NULL) { 10778 xmlRelaxNGFreeValidState(ctxt, ctxt->state); 10779 ctxt->state = NULL; 10780 } 10781 if (ret != 0) 10782 xmlRelaxNGDumpValidError(ctxt); 10783#ifdef DEBUG 10784 else if (ctxt->errNr != 0) { 10785 ctxt->error(ctxt->userData, 10786 "%d Extra error messages left on stack !\n", 10787 ctxt->errNr); 10788 xmlRelaxNGDumpValidError(ctxt); 10789 } 10790#endif 10791#ifdef LIBXML_VALID_ENABLED 10792 if (ctxt->idref == 1) { 10793 xmlValidCtxt vctxt; 10794 10795 memset(&vctxt, 0, sizeof(xmlValidCtxt)); 10796 vctxt.valid = 1; 10797 vctxt.error = ctxt->error; 10798 vctxt.warning = ctxt->warning; 10799 vctxt.userData = ctxt->userData; 10800 10801 if (xmlValidateDocumentFinal(&vctxt, doc) != 1) 10802 ret = -1; 10803 } 10804#endif /* LIBXML_VALID_ENABLED */ 10805 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK)) 10806 ret = -1; 10807 10808 return (ret); 10809} 10810 10811/** 10812 * xmlRelaxNGCleanPSVI: 10813 * @node: an input element or document 10814 * 10815 * Call this routine to speed up XPath computation on static documents. 10816 * This stamps all the element nodes with the document order 10817 * Like for line information, the order is kept in the element->content 10818 * field, the value stored is actually - the node number (starting at -1) 10819 * to be able to differentiate from line numbers. 10820 * 10821 * Returns the number of elements found in the document or -1 in case 10822 * of error. 10823 */ 10824static void 10825xmlRelaxNGCleanPSVI(xmlNodePtr node) { 10826 xmlNodePtr cur; 10827 10828 if ((node == NULL) || 10829 ((node->type != XML_ELEMENT_NODE) && 10830 (node->type != XML_DOCUMENT_NODE) && 10831 (node->type != XML_HTML_DOCUMENT_NODE))) 10832 return; 10833 if (node->type == XML_ELEMENT_NODE) 10834 node->psvi = NULL; 10835 10836 cur = node->children; 10837 while (cur != NULL) { 10838 if (cur->type == XML_ELEMENT_NODE) { 10839 cur->psvi = NULL; 10840 if (cur->children != NULL) { 10841 cur = cur->children; 10842 continue; 10843 } 10844 } 10845 if (cur->next != NULL) { 10846 cur = cur->next; 10847 continue; 10848 } 10849 do { 10850 cur = cur->parent; 10851 if (cur == NULL) 10852 break; 10853 if (cur == node) { 10854 cur = NULL; 10855 break; 10856 } 10857 if (cur->next != NULL) { 10858 cur = cur->next; 10859 break; 10860 } 10861 } while (cur != NULL); 10862 } 10863 return; 10864} 10865/************************************************************************ 10866 * * 10867 * Validation interfaces * 10868 * * 10869 ************************************************************************/ 10870 10871/** 10872 * xmlRelaxNGNewValidCtxt: 10873 * @schema: a precompiled XML RelaxNGs 10874 * 10875 * Create an XML RelaxNGs validation context based on the given schema 10876 * 10877 * Returns the validation context or NULL in case of error 10878 */ 10879xmlRelaxNGValidCtxtPtr 10880xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) 10881{ 10882 xmlRelaxNGValidCtxtPtr ret; 10883 10884 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); 10885 if (ret == NULL) { 10886 xmlRngVErrMemory(NULL, "building context\n"); 10887 return (NULL); 10888 } 10889 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); 10890 ret->schema = schema; 10891 ret->error = xmlGenericError; 10892 ret->userData = xmlGenericErrorContext; 10893 ret->errNr = 0; 10894 ret->errMax = 0; 10895 ret->err = NULL; 10896 ret->errTab = NULL; 10897 if (schema != NULL) 10898 ret->idref = schema->idref; 10899 ret->states = NULL; 10900 ret->freeState = NULL; 10901 ret->freeStates = NULL; 10902 ret->errNo = XML_RELAXNG_OK; 10903 return (ret); 10904} 10905 10906/** 10907 * xmlRelaxNGFreeValidCtxt: 10908 * @ctxt: the schema validation context 10909 * 10910 * Free the resources associated to the schema validation context 10911 */ 10912void 10913xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) 10914{ 10915 int k; 10916 10917 if (ctxt == NULL) 10918 return; 10919 if (ctxt->states != NULL) 10920 xmlRelaxNGFreeStates(NULL, ctxt->states); 10921 if (ctxt->freeState != NULL) { 10922 for (k = 0; k < ctxt->freeState->nbState; k++) { 10923 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]); 10924 } 10925 xmlRelaxNGFreeStates(NULL, ctxt->freeState); 10926 } 10927 if (ctxt->freeStates != NULL) { 10928 for (k = 0; k < ctxt->freeStatesNr; k++) { 10929 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]); 10930 } 10931 xmlFree(ctxt->freeStates); 10932 } 10933 if (ctxt->errTab != NULL) 10934 xmlFree(ctxt->errTab); 10935 if (ctxt->elemTab != NULL) { 10936 xmlRegExecCtxtPtr exec; 10937 10938 exec = xmlRelaxNGElemPop(ctxt); 10939 while (exec != NULL) { 10940 xmlRegFreeExecCtxt(exec); 10941 exec = xmlRelaxNGElemPop(ctxt); 10942 } 10943 xmlFree(ctxt->elemTab); 10944 } 10945 xmlFree(ctxt); 10946} 10947 10948/** 10949 * xmlRelaxNGSetValidErrors: 10950 * @ctxt: a Relax-NG validation context 10951 * @err: the error function 10952 * @warn: the warning function 10953 * @ctx: the functions context 10954 * 10955 * Set the error and warning callback informations 10956 */ 10957void 10958xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, 10959 xmlRelaxNGValidityErrorFunc err, 10960 xmlRelaxNGValidityWarningFunc warn, void *ctx) 10961{ 10962 if (ctxt == NULL) 10963 return; 10964 ctxt->error = err; 10965 ctxt->warning = warn; 10966 ctxt->userData = ctx; 10967 ctxt->serror = NULL; 10968} 10969 10970/** 10971 * xmlRelaxNGSetValidStructuredErrors: 10972 * @ctxt: a Relax-NG validation context 10973 * @serror: the structured error function 10974 * @ctx: the functions context 10975 * 10976 * Set the structured error callback 10977 */ 10978void 10979xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, 10980 xmlStructuredErrorFunc serror, void *ctx) 10981{ 10982 if (ctxt == NULL) 10983 return; 10984 ctxt->serror = serror; 10985 ctxt->error = NULL; 10986 ctxt->warning = NULL; 10987 ctxt->userData = ctx; 10988} 10989 10990/** 10991 * xmlRelaxNGGetValidErrors: 10992 * @ctxt: a Relax-NG validation context 10993 * @err: the error function result 10994 * @warn: the warning function result 10995 * @ctx: the functions context result 10996 * 10997 * Get the error and warning callback informations 10998 * 10999 * Returns -1 in case of error and 0 otherwise 11000 */ 11001int 11002xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, 11003 xmlRelaxNGValidityErrorFunc * err, 11004 xmlRelaxNGValidityWarningFunc * warn, void **ctx) 11005{ 11006 if (ctxt == NULL) 11007 return (-1); 11008 if (err != NULL) 11009 *err = ctxt->error; 11010 if (warn != NULL) 11011 *warn = ctxt->warning; 11012 if (ctx != NULL) 11013 *ctx = ctxt->userData; 11014 return (0); 11015} 11016 11017/** 11018 * xmlRelaxNGValidateDoc: 11019 * @ctxt: a Relax-NG validation context 11020 * @doc: a parsed document tree 11021 * 11022 * Validate a document tree in memory. 11023 * 11024 * Returns 0 if the document is valid, a positive error code 11025 * number otherwise and -1 in case of internal or API error. 11026 */ 11027int 11028xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) 11029{ 11030 int ret; 11031 11032 if ((ctxt == NULL) || (doc == NULL)) 11033 return (-1); 11034 11035 ctxt->doc = doc; 11036 11037 ret = xmlRelaxNGValidateDocument(ctxt, doc); 11038 /* 11039 * Remove all left PSVI 11040 */ 11041 xmlRelaxNGCleanPSVI((xmlNodePtr) doc); 11042 11043 /* 11044 * TODO: build error codes 11045 */ 11046 if (ret == -1) 11047 return (1); 11048 return (ret); 11049} 11050 11051#define bottom_relaxng 11052#include "elfgcchack.h" 11053#endif /* LIBXML_SCHEMAS_ENABLED */ 11054