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