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