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 (at) 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 */ 39 static 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 79 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; 80 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; 81 82 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine; 83 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr; 84 85 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument; 86 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr; 87 88 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude; 89 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr; 90 91 typedef enum { 92 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */ 93 XML_RELAXNG_COMBINE_CHOICE, /* choice */ 94 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */ 95 } xmlRelaxNGCombine; 96 97 typedef 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 104 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar; 105 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr; 106 107 struct _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 119 typedef 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 153 struct _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 */ 176 struct _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 203 struct _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 */ 266 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup; 267 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr; 268 struct _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 */ 282 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition; 283 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr; 284 struct _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 298 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState; 299 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr; 300 struct _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 */ 316 typedef struct _xmlRelaxNGStates xmlRelaxNGStates; 317 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr; 318 struct _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 */ 331 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError; 332 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr; 333 struct _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 348 struct _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 */ 398 struct _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 */ 411 struct _xmlRelaxNGDocument { 412 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */ 413 xmlChar *href; /* the normalized href value */ 414 xmlDocPtr doc; /* the associated XML document */ 415 xmlRelaxNGDefinePtr content; /* the definitions */ 416 xmlRelaxNGPtr schema; /* the schema */ 417 }; 418 419 420 /************************************************************************ 421 * * 422 * Some factorized error routines * 423 * * 424 ************************************************************************/ 425 426 /** 427 * xmlRngPErrMemory: 428 * @ctxt: an Relax-NG parser context 429 * @extra: extra informations 430 * 431 * Handle a redefinition of attribute error 432 */ 433 static void 434 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) 435 { 436 xmlStructuredErrorFunc schannel = NULL; 437 xmlGenericErrorFunc channel = NULL; 438 void *data = NULL; 439 440 if (ctxt != NULL) { 441 if (ctxt->serror != NULL) 442 schannel = ctxt->serror; 443 else 444 channel = ctxt->error; 445 data = ctxt->userData; 446 ctxt->nbErrors++; 447 } 448 if (extra) 449 __xmlRaiseError(schannel, channel, data, 450 NULL, NULL, XML_FROM_RELAXNGP, 451 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 452 NULL, NULL, 0, 0, 453 "Memory allocation failed : %s\n", extra); 454 else 455 __xmlRaiseError(schannel, channel, data, 456 NULL, NULL, XML_FROM_RELAXNGP, 457 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 458 NULL, NULL, 0, 0, "Memory allocation failed\n"); 459 } 460 461 /** 462 * xmlRngVErrMemory: 463 * @ctxt: a Relax-NG validation context 464 * @extra: extra informations 465 * 466 * Handle a redefinition of attribute error 467 */ 468 static void 469 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) 470 { 471 xmlStructuredErrorFunc schannel = NULL; 472 xmlGenericErrorFunc channel = NULL; 473 void *data = NULL; 474 475 if (ctxt != NULL) { 476 if (ctxt->serror != NULL) 477 schannel = ctxt->serror; 478 else 479 channel = ctxt->error; 480 data = ctxt->userData; 481 ctxt->nbErrors++; 482 } 483 if (extra) 484 __xmlRaiseError(schannel, channel, data, 485 NULL, NULL, XML_FROM_RELAXNGV, 486 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, 487 NULL, NULL, 0, 0, 488 "Memory allocation failed : %s\n", extra); 489 else 490 __xmlRaiseError(schannel, channel, data, 491 NULL, NULL, XML_FROM_RELAXNGV, 492 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, 493 NULL, NULL, 0, 0, "Memory allocation failed\n"); 494 } 495 496 /** 497 * xmlRngPErr: 498 * @ctxt: a Relax-NG parser context 499 * @node: the node raising the error 500 * @error: the error code 501 * @msg: message 502 * @str1: extra info 503 * @str2: extra info 504 * 505 * Handle a Relax NG Parsing error 506 */ 507 static void 508 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, 509 const char *msg, const xmlChar * str1, const xmlChar * str2) 510 { 511 xmlStructuredErrorFunc schannel = NULL; 512 xmlGenericErrorFunc channel = NULL; 513 void *data = NULL; 514 515 if (ctxt != NULL) { 516 if (ctxt->serror != NULL) 517 schannel = ctxt->serror; 518 else 519 channel = ctxt->error; 520 data = ctxt->userData; 521 ctxt->nbErrors++; 522 } 523 __xmlRaiseError(schannel, channel, data, 524 NULL, node, XML_FROM_RELAXNGP, 525 error, XML_ERR_ERROR, NULL, 0, 526 (const char *) str1, (const char *) str2, NULL, 0, 0, 527 msg, str1, str2); 528 } 529 530 /** 531 * xmlRngVErr: 532 * @ctxt: a Relax-NG validation context 533 * @node: the node raising the error 534 * @error: the error code 535 * @msg: message 536 * @str1: extra info 537 * @str2: extra info 538 * 539 * Handle a Relax NG Validation error 540 */ 541 static void 542 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, 543 const char *msg, const xmlChar * str1, const xmlChar * str2) 544 { 545 xmlStructuredErrorFunc schannel = NULL; 546 xmlGenericErrorFunc channel = NULL; 547 void *data = NULL; 548 549 if (ctxt != NULL) { 550 if (ctxt->serror != NULL) 551 schannel = ctxt->serror; 552 else 553 channel = ctxt->error; 554 data = ctxt->userData; 555 ctxt->nbErrors++; 556 } 557 __xmlRaiseError(schannel, channel, data, 558 NULL, node, XML_FROM_RELAXNGV, 559 error, XML_ERR_ERROR, NULL, 0, 560 (const char *) str1, (const char *) str2, NULL, 0, 0, 561 msg, str1, str2); 562 } 563 564 /************************************************************************ 565 * * 566 * Preliminary type checking interfaces * 567 * * 568 ************************************************************************/ 569 570 /** 571 * xmlRelaxNGTypeHave: 572 * @data: data needed for the library 573 * @type: the type name 574 * @value: the value to check 575 * 576 * Function provided by a type library to check if a type is exported 577 * 578 * Returns 1 if yes, 0 if no and -1 in case of error. 579 */ 580 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type); 581 582 /** 583 * xmlRelaxNGTypeCheck: 584 * @data: data needed for the library 585 * @type: the type name 586 * @value: the value to check 587 * @result: place to store the result if needed 588 * 589 * Function provided by a type library to check if a value match a type 590 * 591 * Returns 1 if yes, 0 if no and -1 in case of error. 592 */ 593 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type, 594 const xmlChar * value, void **result, 595 xmlNodePtr node); 596 597 /** 598 * xmlRelaxNGFacetCheck: 599 * @data: data needed for the library 600 * @type: the type name 601 * @facet: the facet name 602 * @val: the facet value 603 * @strval: the string value 604 * @value: the value to check 605 * 606 * Function provided by a type library to check a value facet 607 * 608 * Returns 1 if yes, 0 if no and -1 in case of error. 609 */ 610 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type, 611 const xmlChar * facet, 612 const xmlChar * val, 613 const xmlChar * strval, void *value); 614 615 /** 616 * xmlRelaxNGTypeFree: 617 * @data: data needed for the library 618 * @result: the value to free 619 * 620 * Function provided by a type library to free a returned result 621 */ 622 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result); 623 624 /** 625 * xmlRelaxNGTypeCompare: 626 * @data: data needed for the library 627 * @type: the type name 628 * @value1: the first value 629 * @value2: the second value 630 * 631 * Function provided by a type library to compare two values accordingly 632 * to a type. 633 * 634 * Returns 1 if yes, 0 if no and -1 in case of error. 635 */ 636 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type, 637 const xmlChar * value1, 638 xmlNodePtr ctxt1, 639 void *comp1, 640 const xmlChar * value2, 641 xmlNodePtr ctxt2); 642 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary; 643 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr; 644 struct _xmlRelaxNGTypeLibrary { 645 const xmlChar *namespace; /* the datatypeLibrary value */ 646 void *data; /* data needed for the library */ 647 xmlRelaxNGTypeHave have; /* the export function */ 648 xmlRelaxNGTypeCheck check; /* the checking function */ 649 xmlRelaxNGTypeCompare comp; /* the compare function */ 650 xmlRelaxNGFacetCheck facet; /* the facet check function */ 651 xmlRelaxNGTypeFree freef; /* the freeing function */ 652 }; 653 654 /************************************************************************ 655 * * 656 * Allocation functions * 657 * * 658 ************************************************************************/ 659 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar); 660 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define); 661 static void xmlRelaxNGNormExtSpace(xmlChar * value); 662 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema); 663 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt 664 ATTRIBUTE_UNUSED, 665 xmlRelaxNGValidStatePtr state1, 666 xmlRelaxNGValidStatePtr state2); 667 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, 668 xmlRelaxNGValidStatePtr state); 669 670 /** 671 * xmlRelaxNGFreeDocument: 672 * @docu: a document structure 673 * 674 * Deallocate a RelaxNG document structure. 675 */ 676 static void 677 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu) 678 { 679 if (docu == NULL) 680 return; 681 682 if (docu->href != NULL) 683 xmlFree(docu->href); 684 if (docu->doc != NULL) 685 xmlFreeDoc(docu->doc); 686 if (docu->schema != NULL) 687 xmlRelaxNGFreeInnerSchema(docu->schema); 688 xmlFree(docu); 689 } 690 691 /** 692 * xmlRelaxNGFreeDocumentList: 693 * @docu: a list of document structure 694 * 695 * Deallocate a RelaxNG document structures. 696 */ 697 static void 698 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu) 699 { 700 xmlRelaxNGDocumentPtr next; 701 702 while (docu != NULL) { 703 next = docu->next; 704 xmlRelaxNGFreeDocument(docu); 705 docu = next; 706 } 707 } 708 709 /** 710 * xmlRelaxNGFreeInclude: 711 * @incl: a include structure 712 * 713 * Deallocate a RelaxNG include structure. 714 */ 715 static void 716 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl) 717 { 718 if (incl == NULL) 719 return; 720 721 if (incl->href != NULL) 722 xmlFree(incl->href); 723 if (incl->doc != NULL) 724 xmlFreeDoc(incl->doc); 725 if (incl->schema != NULL) 726 xmlRelaxNGFree(incl->schema); 727 xmlFree(incl); 728 } 729 730 /** 731 * xmlRelaxNGFreeIncludeList: 732 * @incl: a include structure list 733 * 734 * Deallocate a RelaxNG include structure. 735 */ 736 static void 737 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl) 738 { 739 xmlRelaxNGIncludePtr next; 740 741 while (incl != NULL) { 742 next = incl->next; 743 xmlRelaxNGFreeInclude(incl); 744 incl = next; 745 } 746 } 747 748 /** 749 * xmlRelaxNGNewRelaxNG: 750 * @ctxt: a Relax-NG validation context (optional) 751 * 752 * Allocate a new RelaxNG structure. 753 * 754 * Returns the newly allocated structure or NULL in case or error 755 */ 756 static xmlRelaxNGPtr 757 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) 758 { 759 xmlRelaxNGPtr ret; 760 761 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); 762 if (ret == NULL) { 763 xmlRngPErrMemory(ctxt, NULL); 764 return (NULL); 765 } 766 memset(ret, 0, sizeof(xmlRelaxNG)); 767 768 return (ret); 769 } 770 771 /** 772 * xmlRelaxNGFreeInnerSchema: 773 * @schema: a schema structure 774 * 775 * Deallocate a RelaxNG schema structure. 776 */ 777 static void 778 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema) 779 { 780 if (schema == NULL) 781 return; 782 783 if (schema->doc != NULL) 784 xmlFreeDoc(schema->doc); 785 if (schema->defTab != NULL) { 786 int i; 787 788 for (i = 0; i < schema->defNr; i++) 789 xmlRelaxNGFreeDefine(schema->defTab[i]); 790 xmlFree(schema->defTab); 791 } 792 793 xmlFree(schema); 794 } 795 796 /** 797 * xmlRelaxNGFree: 798 * @schema: a schema structure 799 * 800 * Deallocate a RelaxNG structure. 801 */ 802 void 803 xmlRelaxNGFree(xmlRelaxNGPtr schema) 804 { 805 if (schema == NULL) 806 return; 807 808 if (schema->topgrammar != NULL) 809 xmlRelaxNGFreeGrammar(schema->topgrammar); 810 if (schema->doc != NULL) 811 xmlFreeDoc(schema->doc); 812 if (schema->documents != NULL) 813 xmlRelaxNGFreeDocumentList(schema->documents); 814 if (schema->includes != NULL) 815 xmlRelaxNGFreeIncludeList(schema->includes); 816 if (schema->defTab != NULL) { 817 int i; 818 819 for (i = 0; i < schema->defNr; i++) 820 xmlRelaxNGFreeDefine(schema->defTab[i]); 821 xmlFree(schema->defTab); 822 } 823 824 xmlFree(schema); 825 } 826 827 /** 828 * xmlRelaxNGNewGrammar: 829 * @ctxt: a Relax-NG validation context (optional) 830 * 831 * Allocate a new RelaxNG grammar. 832 * 833 * Returns the newly allocated structure or NULL in case or error 834 */ 835 static xmlRelaxNGGrammarPtr 836 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) 837 { 838 xmlRelaxNGGrammarPtr ret; 839 840 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); 841 if (ret == NULL) { 842 xmlRngPErrMemory(ctxt, NULL); 843 return (NULL); 844 } 845 memset(ret, 0, sizeof(xmlRelaxNGGrammar)); 846 847 return (ret); 848 } 849 850 /** 851 * xmlRelaxNGFreeGrammar: 852 * @grammar: a grammar structure 853 * 854 * Deallocate a RelaxNG grammar structure. 855 */ 856 static void 857 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar) 858 { 859 if (grammar == NULL) 860 return; 861 862 if (grammar->children != NULL) { 863 xmlRelaxNGFreeGrammar(grammar->children); 864 } 865 if (grammar->next != NULL) { 866 xmlRelaxNGFreeGrammar(grammar->next); 867 } 868 if (grammar->refs != NULL) { 869 xmlHashFree(grammar->refs, NULL); 870 } 871 if (grammar->defs != NULL) { 872 xmlHashFree(grammar->defs, NULL); 873 } 874 875 xmlFree(grammar); 876 } 877 878 /** 879 * xmlRelaxNGNewDefine: 880 * @ctxt: a Relax-NG validation context 881 * @node: the node in the input document. 882 * 883 * Allocate a new RelaxNG define. 884 * 885 * Returns the newly allocated structure or NULL in case or error 886 */ 887 static xmlRelaxNGDefinePtr 888 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 889 { 890 xmlRelaxNGDefinePtr ret; 891 892 if (ctxt->defMax == 0) { 893 ctxt->defMax = 16; 894 ctxt->defNr = 0; 895 ctxt->defTab = (xmlRelaxNGDefinePtr *) 896 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); 897 if (ctxt->defTab == NULL) { 898 xmlRngPErrMemory(ctxt, "allocating define\n"); 899 return (NULL); 900 } 901 } else if (ctxt->defMax <= ctxt->defNr) { 902 xmlRelaxNGDefinePtr *tmp; 903 904 ctxt->defMax *= 2; 905 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab, 906 ctxt->defMax * 907 sizeof 908 (xmlRelaxNGDefinePtr)); 909 if (tmp == NULL) { 910 xmlRngPErrMemory(ctxt, "allocating define\n"); 911 return (NULL); 912 } 913 ctxt->defTab = tmp; 914 } 915 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); 916 if (ret == NULL) { 917 xmlRngPErrMemory(ctxt, "allocating define\n"); 918 return (NULL); 919 } 920 memset(ret, 0, sizeof(xmlRelaxNGDefine)); 921 ctxt->defTab[ctxt->defNr++] = ret; 922 ret->node = node; 923 ret->depth = -1; 924 return (ret); 925 } 926 927 /** 928 * xmlRelaxNGFreePartition: 929 * @partitions: a partition set structure 930 * 931 * Deallocate RelaxNG partition set structures. 932 */ 933 static void 934 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) 935 { 936 xmlRelaxNGInterleaveGroupPtr group; 937 int j; 938 939 if (partitions != NULL) { 940 if (partitions->groups != NULL) { 941 for (j = 0; j < partitions->nbgroups; j++) { 942 group = partitions->groups[j]; 943 if (group != NULL) { 944 if (group->defs != NULL) 945 xmlFree(group->defs); 946 if (group->attrs != NULL) 947 xmlFree(group->attrs); 948 xmlFree(group); 949 } 950 } 951 xmlFree(partitions->groups); 952 } 953 if (partitions->triage != NULL) { 954 xmlHashFree(partitions->triage, NULL); 955 } 956 xmlFree(partitions); 957 } 958 } 959 960 /** 961 * xmlRelaxNGFreeDefine: 962 * @define: a define structure 963 * 964 * Deallocate a RelaxNG define structure. 965 */ 966 static void 967 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define) 968 { 969 if (define == NULL) 970 return; 971 972 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) { 973 xmlRelaxNGTypeLibraryPtr lib; 974 975 lib = (xmlRelaxNGTypeLibraryPtr) define->data; 976 if ((lib != NULL) && (lib->freef != NULL)) 977 lib->freef(lib->data, (void *) define->attrs); 978 } 979 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE)) 980 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data); 981 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE)) 982 xmlHashFree((xmlHashTablePtr) define->data, NULL); 983 if (define->name != NULL) 984 xmlFree(define->name); 985 if (define->ns != NULL) 986 xmlFree(define->ns); 987 if (define->value != NULL) 988 xmlFree(define->value); 989 if (define->contModel != NULL) 990 xmlRegFreeRegexp(define->contModel); 991 xmlFree(define); 992 } 993 994 /** 995 * xmlRelaxNGNewStates: 996 * @ctxt: a Relax-NG validation context 997 * @size: the default size for the container 998 * 999 * Allocate a new RelaxNG validation state container 1000 * 1001 * Returns the newly allocated structure or NULL in case or error 1002 */ 1003 static xmlRelaxNGStatesPtr 1004 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) 1005 { 1006 xmlRelaxNGStatesPtr ret; 1007 1008 if ((ctxt != NULL) && 1009 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) { 1010 ctxt->freeStatesNr--; 1011 ret = ctxt->freeStates[ctxt->freeStatesNr]; 1012 ret->nbState = 0; 1013 return (ret); 1014 } 1015 if (size < 16) 1016 size = 16; 1017 1018 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) + 1019 (size - 1020 1) * 1021 sizeof(xmlRelaxNGValidStatePtr)); 1022 if (ret == NULL) { 1023 xmlRngVErrMemory(ctxt, "allocating states\n"); 1024 return (NULL); 1025 } 1026 ret->nbState = 0; 1027 ret->maxState = size; 1028 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) * 1029 sizeof 1030 (xmlRelaxNGValidStatePtr)); 1031 if (ret->tabState == NULL) { 1032 xmlRngVErrMemory(ctxt, "allocating states\n"); 1033 xmlFree(ret); 1034 return (NULL); 1035 } 1036 return (ret); 1037 } 1038 1039 /** 1040 * xmlRelaxNGAddStateUniq: 1041 * @ctxt: a Relax-NG validation context 1042 * @states: the states container 1043 * @state: the validation state 1044 * 1045 * Add a RelaxNG validation state to the container without checking 1046 * for unicity. 1047 * 1048 * Return 1 in case of success and 0 if this is a duplicate and -1 on error 1049 */ 1050 static int 1051 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, 1052 xmlRelaxNGStatesPtr states, 1053 xmlRelaxNGValidStatePtr state) 1054 { 1055 if (state == NULL) { 1056 return (-1); 1057 } 1058 if (states->nbState >= states->maxState) { 1059 xmlRelaxNGValidStatePtr *tmp; 1060 int size; 1061 1062 size = states->maxState * 2; 1063 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, 1064 (size) * 1065 sizeof 1066 (xmlRelaxNGValidStatePtr)); 1067 if (tmp == NULL) { 1068 xmlRngVErrMemory(ctxt, "adding states\n"); 1069 return (-1); 1070 } 1071 states->tabState = tmp; 1072 states->maxState = size; 1073 } 1074 states->tabState[states->nbState++] = state; 1075 return (1); 1076 } 1077 1078 /** 1079 * xmlRelaxNGAddState: 1080 * @ctxt: a Relax-NG validation context 1081 * @states: the states container 1082 * @state: the validation state 1083 * 1084 * Add a RelaxNG validation state to the container 1085 * 1086 * Return 1 in case of success and 0 if this is a duplicate and -1 on error 1087 */ 1088 static int 1089 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, 1090 xmlRelaxNGStatesPtr states, 1091 xmlRelaxNGValidStatePtr state) 1092 { 1093 int i; 1094 1095 if (state == NULL) { 1096 return (-1); 1097 } 1098 if (states->nbState >= states->maxState) { 1099 xmlRelaxNGValidStatePtr *tmp; 1100 int size; 1101 1102 size = states->maxState * 2; 1103 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, 1104 (size) * 1105 sizeof 1106 (xmlRelaxNGValidStatePtr)); 1107 if (tmp == NULL) { 1108 xmlRngVErrMemory(ctxt, "adding states\n"); 1109 return (-1); 1110 } 1111 states->tabState = tmp; 1112 states->maxState = size; 1113 } 1114 for (i = 0; i < states->nbState; i++) { 1115 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) { 1116 xmlRelaxNGFreeValidState(ctxt, state); 1117 return (0); 1118 } 1119 } 1120 states->tabState[states->nbState++] = state; 1121 return (1); 1122 } 1123 1124 /** 1125 * xmlRelaxNGFreeStates: 1126 * @ctxt: a Relax-NG validation context 1127 * @states: teh container 1128 * 1129 * Free a RelaxNG validation state container 1130 */ 1131 static void 1132 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, 1133 xmlRelaxNGStatesPtr states) 1134 { 1135 if (states == NULL) 1136 return; 1137 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) { 1138 ctxt->freeStatesMax = 40; 1139 ctxt->freeStatesNr = 0; 1140 ctxt->freeStates = (xmlRelaxNGStatesPtr *) 1141 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); 1142 if (ctxt->freeStates == NULL) { 1143 xmlRngVErrMemory(ctxt, "storing states\n"); 1144 } 1145 } else if ((ctxt != NULL) 1146 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { 1147 xmlRelaxNGStatesPtr *tmp; 1148 1149 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates, 1150 2 * ctxt->freeStatesMax * 1151 sizeof 1152 (xmlRelaxNGStatesPtr)); 1153 if (tmp == NULL) { 1154 xmlRngVErrMemory(ctxt, "storing states\n"); 1155 xmlFree(states->tabState); 1156 xmlFree(states); 1157 return; 1158 } 1159 ctxt->freeStates = tmp; 1160 ctxt->freeStatesMax *= 2; 1161 } 1162 if ((ctxt == NULL) || (ctxt->freeStates == NULL)) { 1163 xmlFree(states->tabState); 1164 xmlFree(states); 1165 } else { 1166 ctxt->freeStates[ctxt->freeStatesNr++] = states; 1167 } 1168 } 1169 1170 /** 1171 * xmlRelaxNGNewValidState: 1172 * @ctxt: a Relax-NG validation context 1173 * @node: the current node or NULL for the document 1174 * 1175 * Allocate a new RelaxNG validation state 1176 * 1177 * Returns the newly allocated structure or NULL in case or error 1178 */ 1179 static xmlRelaxNGValidStatePtr 1180 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) 1181 { 1182 xmlRelaxNGValidStatePtr ret; 1183 xmlAttrPtr attr; 1184 xmlAttrPtr attrs[MAX_ATTR]; 1185 int nbAttrs = 0; 1186 xmlNodePtr root = NULL; 1187 1188 if (node == NULL) { 1189 root = xmlDocGetRootElement(ctxt->doc); 1190 if (root == NULL) 1191 return (NULL); 1192 } else { 1193 attr = node->properties; 1194 while (attr != NULL) { 1195 if (nbAttrs < MAX_ATTR) 1196 attrs[nbAttrs++] = attr; 1197 else 1198 nbAttrs++; 1199 attr = attr->next; 1200 } 1201 } 1202 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { 1203 ctxt->freeState->nbState--; 1204 ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; 1205 } else { 1206 ret = 1207 (xmlRelaxNGValidStatePtr) 1208 xmlMalloc(sizeof(xmlRelaxNGValidState)); 1209 if (ret == NULL) { 1210 xmlRngVErrMemory(ctxt, "allocating states\n"); 1211 return (NULL); 1212 } 1213 memset(ret, 0, sizeof(xmlRelaxNGValidState)); 1214 } 1215 ret->value = NULL; 1216 ret->endvalue = NULL; 1217 if (node == NULL) { 1218 ret->node = (xmlNodePtr) ctxt->doc; 1219 ret->seq = root; 1220 } else { 1221 ret->node = node; 1222 ret->seq = node->children; 1223 } 1224 ret->nbAttrs = 0; 1225 if (nbAttrs > 0) { 1226 if (ret->attrs == NULL) { 1227 if (nbAttrs < 4) 1228 ret->maxAttrs = 4; 1229 else 1230 ret->maxAttrs = nbAttrs; 1231 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * 1232 sizeof(xmlAttrPtr)); 1233 if (ret->attrs == NULL) { 1234 xmlRngVErrMemory(ctxt, "allocating states\n"); 1235 return (ret); 1236 } 1237 } else if (ret->maxAttrs < nbAttrs) { 1238 xmlAttrPtr *tmp; 1239 1240 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * 1241 sizeof(xmlAttrPtr)); 1242 if (tmp == NULL) { 1243 xmlRngVErrMemory(ctxt, "allocating states\n"); 1244 return (ret); 1245 } 1246 ret->attrs = tmp; 1247 ret->maxAttrs = nbAttrs; 1248 } 1249 ret->nbAttrs = nbAttrs; 1250 if (nbAttrs < MAX_ATTR) { 1251 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs); 1252 } else { 1253 attr = node->properties; 1254 nbAttrs = 0; 1255 while (attr != NULL) { 1256 ret->attrs[nbAttrs++] = attr; 1257 attr = attr->next; 1258 } 1259 } 1260 } 1261 ret->nbAttrLeft = ret->nbAttrs; 1262 return (ret); 1263 } 1264 1265 /** 1266 * xmlRelaxNGCopyValidState: 1267 * @ctxt: a Relax-NG validation context 1268 * @state: a validation state 1269 * 1270 * Copy the validation state 1271 * 1272 * Returns the newly allocated structure or NULL in case or error 1273 */ 1274 static xmlRelaxNGValidStatePtr 1275 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, 1276 xmlRelaxNGValidStatePtr state) 1277 { 1278 xmlRelaxNGValidStatePtr ret; 1279 unsigned int maxAttrs; 1280 xmlAttrPtr *attrs; 1281 1282 if (state == NULL) 1283 return (NULL); 1284 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { 1285 ctxt->freeState->nbState--; 1286 ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; 1287 } else { 1288 ret = 1289 (xmlRelaxNGValidStatePtr) 1290 xmlMalloc(sizeof(xmlRelaxNGValidState)); 1291 if (ret == NULL) { 1292 xmlRngVErrMemory(ctxt, "allocating states\n"); 1293 return (NULL); 1294 } 1295 memset(ret, 0, sizeof(xmlRelaxNGValidState)); 1296 } 1297 attrs = ret->attrs; 1298 maxAttrs = ret->maxAttrs; 1299 memcpy(ret, state, sizeof(xmlRelaxNGValidState)); 1300 ret->attrs = attrs; 1301 ret->maxAttrs = maxAttrs; 1302 if (state->nbAttrs > 0) { 1303 if (ret->attrs == NULL) { 1304 ret->maxAttrs = state->maxAttrs; 1305 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * 1306 sizeof(xmlAttrPtr)); 1307 if (ret->attrs == NULL) { 1308 xmlRngVErrMemory(ctxt, "allocating states\n"); 1309 ret->nbAttrs = 0; 1310 return (ret); 1311 } 1312 } else if (ret->maxAttrs < state->nbAttrs) { 1313 xmlAttrPtr *tmp; 1314 1315 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * 1316 sizeof(xmlAttrPtr)); 1317 if (tmp == NULL) { 1318 xmlRngVErrMemory(ctxt, "allocating states\n"); 1319 ret->nbAttrs = 0; 1320 return (ret); 1321 } 1322 ret->maxAttrs = state->maxAttrs; 1323 ret->attrs = tmp; 1324 } 1325 memcpy(ret->attrs, state->attrs, 1326 state->nbAttrs * sizeof(xmlAttrPtr)); 1327 } 1328 return (ret); 1329 } 1330 1331 /** 1332 * xmlRelaxNGEqualValidState: 1333 * @ctxt: a Relax-NG validation context 1334 * @state1: a validation state 1335 * @state2: a validation state 1336 * 1337 * Compare the validation states for equality 1338 * 1339 * Returns 1 if equald, 0 otherwise 1340 */ 1341 static int 1342 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 1343 xmlRelaxNGValidStatePtr state1, 1344 xmlRelaxNGValidStatePtr state2) 1345 { 1346 int i; 1347 1348 if ((state1 == NULL) || (state2 == NULL)) 1349 return (0); 1350 if (state1 == state2) 1351 return (1); 1352 if (state1->node != state2->node) 1353 return (0); 1354 if (state1->seq != state2->seq) 1355 return (0); 1356 if (state1->nbAttrLeft != state2->nbAttrLeft) 1357 return (0); 1358 if (state1->nbAttrs != state2->nbAttrs) 1359 return (0); 1360 if (state1->endvalue != state2->endvalue) 1361 return (0); 1362 if ((state1->value != state2->value) && 1363 (!xmlStrEqual(state1->value, state2->value))) 1364 return (0); 1365 for (i = 0; i < state1->nbAttrs; i++) { 1366 if (state1->attrs[i] != state2->attrs[i]) 1367 return (0); 1368 } 1369 return (1); 1370 } 1371 1372 /** 1373 * xmlRelaxNGFreeValidState: 1374 * @state: a validation state structure 1375 * 1376 * Deallocate a RelaxNG validation state structure. 1377 */ 1378 static void 1379 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, 1380 xmlRelaxNGValidStatePtr state) 1381 { 1382 if (state == NULL) 1383 return; 1384 1385 if ((ctxt != NULL) && (ctxt->freeState == NULL)) { 1386 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40); 1387 } 1388 if ((ctxt == NULL) || (ctxt->freeState == NULL)) { 1389 if (state->attrs != NULL) 1390 xmlFree(state->attrs); 1391 xmlFree(state); 1392 } else { 1393 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state); 1394 } 1395 } 1396 1397 /************************************************************************ 1398 * * 1399 * Semi internal functions * 1400 * * 1401 ************************************************************************/ 1402 1403 /** 1404 * xmlRelaxParserSetFlag: 1405 * @ctxt: a RelaxNG parser context 1406 * @flags: a set of flags values 1407 * 1408 * Semi private function used to pass informations to a parser context 1409 * which are a combination of xmlRelaxNGParserFlag . 1410 * 1411 * Returns 0 if success and -1 in case of error 1412 */ 1413 int 1414 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) 1415 { 1416 if (ctxt == NULL) return(-1); 1417 if (flags & XML_RELAXNGP_FREE_DOC) { 1418 ctxt->crng |= XML_RELAXNGP_FREE_DOC; 1419 flags -= XML_RELAXNGP_FREE_DOC; 1420 } 1421 if (flags & XML_RELAXNGP_CRNG) { 1422 ctxt->crng |= XML_RELAXNGP_CRNG; 1423 flags -= XML_RELAXNGP_CRNG; 1424 } 1425 if (flags != 0) return(-1); 1426 return(0); 1427 } 1428 1429 /************************************************************************ 1430 * * 1431 * Document functions * 1432 * * 1433 ************************************************************************/ 1434 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, 1435 xmlDocPtr doc); 1436 1437 /** 1438 * xmlRelaxNGIncludePush: 1439 * @ctxt: the parser context 1440 * @value: the element doc 1441 * 1442 * Pushes a new include on top of the include stack 1443 * 1444 * Returns 0 in case of error, the index in the stack otherwise 1445 */ 1446 static int 1447 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, 1448 xmlRelaxNGIncludePtr value) 1449 { 1450 if (ctxt->incTab == NULL) { 1451 ctxt->incMax = 4; 1452 ctxt->incNr = 0; 1453 ctxt->incTab = 1454 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * 1455 sizeof(ctxt->incTab[0])); 1456 if (ctxt->incTab == NULL) { 1457 xmlRngPErrMemory(ctxt, "allocating include\n"); 1458 return (0); 1459 } 1460 } 1461 if (ctxt->incNr >= ctxt->incMax) { 1462 ctxt->incMax *= 2; 1463 ctxt->incTab = 1464 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab, 1465 ctxt->incMax * 1466 sizeof(ctxt->incTab[0])); 1467 if (ctxt->incTab == NULL) { 1468 xmlRngPErrMemory(ctxt, "allocating include\n"); 1469 return (0); 1470 } 1471 } 1472 ctxt->incTab[ctxt->incNr] = value; 1473 ctxt->inc = value; 1474 return (ctxt->incNr++); 1475 } 1476 1477 /** 1478 * xmlRelaxNGIncludePop: 1479 * @ctxt: the parser context 1480 * 1481 * Pops the top include from the include stack 1482 * 1483 * Returns the include just removed 1484 */ 1485 static xmlRelaxNGIncludePtr 1486 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt) 1487 { 1488 xmlRelaxNGIncludePtr ret; 1489 1490 if (ctxt->incNr <= 0) 1491 return (NULL); 1492 ctxt->incNr--; 1493 if (ctxt->incNr > 0) 1494 ctxt->inc = ctxt->incTab[ctxt->incNr - 1]; 1495 else 1496 ctxt->inc = NULL; 1497 ret = ctxt->incTab[ctxt->incNr]; 1498 ctxt->incTab[ctxt->incNr] = NULL; 1499 return (ret); 1500 } 1501 1502 /** 1503 * xmlRelaxNGRemoveRedefine: 1504 * @ctxt: the parser context 1505 * @URL: the normalized URL 1506 * @target: the included target 1507 * @name: the define name to eliminate 1508 * 1509 * Applies the elimination algorithm of 4.7 1510 * 1511 * Returns 0 in case of error, 1 in case of success. 1512 */ 1513 static int 1514 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, 1515 const xmlChar * URL ATTRIBUTE_UNUSED, 1516 xmlNodePtr target, const xmlChar * name) 1517 { 1518 int found = 0; 1519 xmlNodePtr tmp, tmp2; 1520 xmlChar *name2; 1521 1522 #ifdef DEBUG_INCLUDE 1523 if (name == NULL) 1524 xmlGenericError(xmlGenericErrorContext, 1525 "Elimination of <include> start from %s\n", URL); 1526 else 1527 xmlGenericError(xmlGenericErrorContext, 1528 "Elimination of <include> define %s from %s\n", 1529 name, URL); 1530 #endif 1531 tmp = target; 1532 while (tmp != NULL) { 1533 tmp2 = tmp->next; 1534 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) { 1535 found = 1; 1536 xmlUnlinkNode(tmp); 1537 xmlFreeNode(tmp); 1538 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) { 1539 name2 = xmlGetProp(tmp, BAD_CAST "name"); 1540 xmlRelaxNGNormExtSpace(name2); 1541 if (name2 != NULL) { 1542 if (xmlStrEqual(name, name2)) { 1543 found = 1; 1544 xmlUnlinkNode(tmp); 1545 xmlFreeNode(tmp); 1546 } 1547 xmlFree(name2); 1548 } 1549 } else if (IS_RELAXNG(tmp, "include")) { 1550 xmlChar *href = NULL; 1551 xmlRelaxNGDocumentPtr inc = tmp->psvi; 1552 1553 if ((inc != NULL) && (inc->doc != NULL) && 1554 (inc->doc->children != NULL)) { 1555 1556 if (xmlStrEqual 1557 (inc->doc->children->name, BAD_CAST "grammar")) { 1558 #ifdef DEBUG_INCLUDE 1559 href = xmlGetProp(tmp, BAD_CAST "href"); 1560 #endif 1561 if (xmlRelaxNGRemoveRedefine(ctxt, href, 1562 inc->doc->children-> 1563 children, name) == 1) { 1564 found = 1; 1565 } 1566 #ifdef DEBUG_INCLUDE 1567 if (href != NULL) 1568 xmlFree(href); 1569 #endif 1570 } 1571 } 1572 } 1573 tmp = tmp2; 1574 } 1575 return (found); 1576 } 1577 1578 /** 1579 * xmlRelaxNGLoadInclude: 1580 * @ctxt: the parser context 1581 * @URL: the normalized URL 1582 * @node: the include node. 1583 * @ns: the namespace passed from the context. 1584 * 1585 * First lookup if the document is already loaded into the parser context, 1586 * check against recursion. If not found the resource is loaded and 1587 * the content is preprocessed before being returned back to the caller. 1588 * 1589 * Returns the xmlRelaxNGIncludePtr or NULL in case of error 1590 */ 1591 static xmlRelaxNGIncludePtr 1592 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, 1593 xmlNodePtr node, const xmlChar * ns) 1594 { 1595 xmlRelaxNGIncludePtr ret = NULL; 1596 xmlDocPtr doc; 1597 int i; 1598 xmlNodePtr root, cur; 1599 1600 #ifdef DEBUG_INCLUDE 1601 xmlGenericError(xmlGenericErrorContext, 1602 "xmlRelaxNGLoadInclude(%s)\n", URL); 1603 #endif 1604 1605 /* 1606 * check against recursion in the stack 1607 */ 1608 for (i = 0; i < ctxt->incNr; i++) { 1609 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) { 1610 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE, 1611 "Detected an Include recursion for %s\n", URL, 1612 NULL); 1613 return (NULL); 1614 } 1615 } 1616 1617 /* 1618 * load the document 1619 */ 1620 doc = xmlReadFile((const char *) URL,NULL,0); 1621 if (doc == NULL) { 1622 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, 1623 "xmlRelaxNG: could not load %s\n", URL, NULL); 1624 return (NULL); 1625 } 1626 #ifdef DEBUG_INCLUDE 1627 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL); 1628 #endif 1629 1630 /* 1631 * Allocate the document structures and register it first. 1632 */ 1633 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); 1634 if (ret == NULL) { 1635 xmlRngPErrMemory(ctxt, "allocating include\n"); 1636 xmlFreeDoc(doc); 1637 return (NULL); 1638 } 1639 memset(ret, 0, sizeof(xmlRelaxNGInclude)); 1640 ret->doc = doc; 1641 ret->href = xmlStrdup(URL); 1642 ret->next = ctxt->includes; 1643 ctxt->includes = ret; 1644 1645 /* 1646 * transmit the ns if needed 1647 */ 1648 if (ns != NULL) { 1649 root = xmlDocGetRootElement(doc); 1650 if (root != NULL) { 1651 if (xmlHasProp(root, BAD_CAST "ns") == NULL) { 1652 xmlSetProp(root, BAD_CAST "ns", ns); 1653 } 1654 } 1655 } 1656 1657 /* 1658 * push it on the stack 1659 */ 1660 xmlRelaxNGIncludePush(ctxt, ret); 1661 1662 /* 1663 * Some preprocessing of the document content, this include recursing 1664 * in the include stack. 1665 */ 1666 #ifdef DEBUG_INCLUDE 1667 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL); 1668 #endif 1669 1670 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 1671 if (doc == NULL) { 1672 ctxt->inc = NULL; 1673 return (NULL); 1674 } 1675 1676 /* 1677 * Pop up the include from the stack 1678 */ 1679 xmlRelaxNGIncludePop(ctxt); 1680 1681 #ifdef DEBUG_INCLUDE 1682 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL); 1683 #endif 1684 /* 1685 * Check that the top element is a grammar 1686 */ 1687 root = xmlDocGetRootElement(doc); 1688 if (root == NULL) { 1689 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, 1690 "xmlRelaxNG: included document is empty %s\n", URL, 1691 NULL); 1692 return (NULL); 1693 } 1694 if (!IS_RELAXNG(root, "grammar")) { 1695 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 1696 "xmlRelaxNG: included document %s root is not a grammar\n", 1697 URL, NULL); 1698 return (NULL); 1699 } 1700 1701 /* 1702 * Elimination of redefined rules in the include. 1703 */ 1704 cur = node->children; 1705 while (cur != NULL) { 1706 if (IS_RELAXNG(cur, "start")) { 1707 int found = 0; 1708 1709 found = 1710 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL); 1711 if (!found) { 1712 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING, 1713 "xmlRelaxNG: include %s has a start but not the included grammar\n", 1714 URL, NULL); 1715 } 1716 } else if (IS_RELAXNG(cur, "define")) { 1717 xmlChar *name; 1718 1719 name = xmlGetProp(cur, BAD_CAST "name"); 1720 if (name == NULL) { 1721 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING, 1722 "xmlRelaxNG: include %s has define without name\n", 1723 URL, NULL); 1724 } else { 1725 int found; 1726 1727 xmlRelaxNGNormExtSpace(name); 1728 found = xmlRelaxNGRemoveRedefine(ctxt, URL, 1729 root->children, name); 1730 if (!found) { 1731 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING, 1732 "xmlRelaxNG: include %s has a define %s but not the included grammar\n", 1733 URL, name); 1734 } 1735 xmlFree(name); 1736 } 1737 } 1738 cur = cur->next; 1739 } 1740 1741 1742 return (ret); 1743 } 1744 1745 /** 1746 * xmlRelaxNGValidErrorPush: 1747 * @ctxt: the validation context 1748 * @err: the error code 1749 * @arg1: the first string argument 1750 * @arg2: the second string argument 1751 * @dup: arg need to be duplicated 1752 * 1753 * Pushes a new error on top of the error stack 1754 * 1755 * Returns 0 in case of error, the index in the stack otherwise 1756 */ 1757 static int 1758 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, 1759 xmlRelaxNGValidErr err, const xmlChar * arg1, 1760 const xmlChar * arg2, int dup) 1761 { 1762 xmlRelaxNGValidErrorPtr cur; 1763 1764 #ifdef DEBUG_ERROR 1765 xmlGenericError(xmlGenericErrorContext, 1766 "Pushing error %d at %d on stack\n", err, ctxt->errNr); 1767 #endif 1768 if (ctxt->errTab == NULL) { 1769 ctxt->errMax = 8; 1770 ctxt->errNr = 0; 1771 ctxt->errTab = 1772 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax * 1773 sizeof 1774 (xmlRelaxNGValidError)); 1775 if (ctxt->errTab == NULL) { 1776 xmlRngVErrMemory(ctxt, "pushing error\n"); 1777 return (0); 1778 } 1779 ctxt->err = NULL; 1780 } 1781 if (ctxt->errNr >= ctxt->errMax) { 1782 ctxt->errMax *= 2; 1783 ctxt->errTab = 1784 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab, 1785 ctxt->errMax * 1786 sizeof 1787 (xmlRelaxNGValidError)); 1788 if (ctxt->errTab == NULL) { 1789 xmlRngVErrMemory(ctxt, "pushing error\n"); 1790 return (0); 1791 } 1792 ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; 1793 } 1794 if ((ctxt->err != NULL) && (ctxt->state != NULL) && 1795 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err)) 1796 return (ctxt->errNr); 1797 cur = &ctxt->errTab[ctxt->errNr]; 1798 cur->err = err; 1799 if (dup) { 1800 cur->arg1 = xmlStrdup(arg1); 1801 cur->arg2 = xmlStrdup(arg2); 1802 cur->flags = ERROR_IS_DUP; 1803 } else { 1804 cur->arg1 = arg1; 1805 cur->arg2 = arg2; 1806 cur->flags = 0; 1807 } 1808 if (ctxt->state != NULL) { 1809 cur->node = ctxt->state->node; 1810 cur->seq = ctxt->state->seq; 1811 } else { 1812 cur->node = NULL; 1813 cur->seq = NULL; 1814 } 1815 ctxt->err = cur; 1816 return (ctxt->errNr++); 1817 } 1818 1819 /** 1820 * xmlRelaxNGValidErrorPop: 1821 * @ctxt: the validation context 1822 * 1823 * Pops the top error from the error stack 1824 */ 1825 static void 1826 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt) 1827 { 1828 xmlRelaxNGValidErrorPtr cur; 1829 1830 if (ctxt->errNr <= 0) { 1831 ctxt->err = NULL; 1832 return; 1833 } 1834 ctxt->errNr--; 1835 if (ctxt->errNr > 0) 1836 ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; 1837 else 1838 ctxt->err = NULL; 1839 cur = &ctxt->errTab[ctxt->errNr]; 1840 if (cur->flags & ERROR_IS_DUP) { 1841 if (cur->arg1 != NULL) 1842 xmlFree((xmlChar *) cur->arg1); 1843 cur->arg1 = NULL; 1844 if (cur->arg2 != NULL) 1845 xmlFree((xmlChar *) cur->arg2); 1846 cur->arg2 = NULL; 1847 cur->flags = 0; 1848 } 1849 } 1850 1851 /** 1852 * xmlRelaxNGDocumentPush: 1853 * @ctxt: the parser context 1854 * @value: the element doc 1855 * 1856 * Pushes a new doc on top of the doc stack 1857 * 1858 * Returns 0 in case of error, the index in the stack otherwise 1859 */ 1860 static int 1861 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, 1862 xmlRelaxNGDocumentPtr value) 1863 { 1864 if (ctxt->docTab == NULL) { 1865 ctxt->docMax = 4; 1866 ctxt->docNr = 0; 1867 ctxt->docTab = 1868 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * 1869 sizeof(ctxt->docTab[0])); 1870 if (ctxt->docTab == NULL) { 1871 xmlRngPErrMemory(ctxt, "adding document\n"); 1872 return (0); 1873 } 1874 } 1875 if (ctxt->docNr >= ctxt->docMax) { 1876 ctxt->docMax *= 2; 1877 ctxt->docTab = 1878 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab, 1879 ctxt->docMax * 1880 sizeof(ctxt->docTab[0])); 1881 if (ctxt->docTab == NULL) { 1882 xmlRngPErrMemory(ctxt, "adding document\n"); 1883 return (0); 1884 } 1885 } 1886 ctxt->docTab[ctxt->docNr] = value; 1887 ctxt->doc = value; 1888 return (ctxt->docNr++); 1889 } 1890 1891 /** 1892 * xmlRelaxNGDocumentPop: 1893 * @ctxt: the parser context 1894 * 1895 * Pops the top doc from the doc stack 1896 * 1897 * Returns the doc just removed 1898 */ 1899 static xmlRelaxNGDocumentPtr 1900 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt) 1901 { 1902 xmlRelaxNGDocumentPtr ret; 1903 1904 if (ctxt->docNr <= 0) 1905 return (NULL); 1906 ctxt->docNr--; 1907 if (ctxt->docNr > 0) 1908 ctxt->doc = ctxt->docTab[ctxt->docNr - 1]; 1909 else 1910 ctxt->doc = NULL; 1911 ret = ctxt->docTab[ctxt->docNr]; 1912 ctxt->docTab[ctxt->docNr] = NULL; 1913 return (ret); 1914 } 1915 1916 /** 1917 * xmlRelaxNGLoadExternalRef: 1918 * @ctxt: the parser context 1919 * @URL: the normalized URL 1920 * @ns: the inherited ns if any 1921 * 1922 * First lookup if the document is already loaded into the parser context, 1923 * check against recursion. If not found the resource is loaded and 1924 * the content is preprocessed before being returned back to the caller. 1925 * 1926 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error 1927 */ 1928 static xmlRelaxNGDocumentPtr 1929 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, 1930 const xmlChar * URL, const xmlChar * ns) 1931 { 1932 xmlRelaxNGDocumentPtr ret = NULL; 1933 xmlDocPtr doc; 1934 xmlNodePtr root; 1935 int i; 1936 1937 /* 1938 * check against recursion in the stack 1939 */ 1940 for (i = 0; i < ctxt->docNr; i++) { 1941 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) { 1942 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE, 1943 "Detected an externalRef recursion for %s\n", URL, 1944 NULL); 1945 return (NULL); 1946 } 1947 } 1948 1949 /* 1950 * load the document 1951 */ 1952 doc = xmlReadFile((const char *) URL,NULL,0); 1953 if (doc == NULL) { 1954 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, 1955 "xmlRelaxNG: could not load %s\n", URL, NULL); 1956 return (NULL); 1957 } 1958 1959 /* 1960 * Allocate the document structures and register it first. 1961 */ 1962 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); 1963 if (ret == NULL) { 1964 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, 1965 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); 1966 xmlFreeDoc(doc); 1967 return (NULL); 1968 } 1969 memset(ret, 0, sizeof(xmlRelaxNGDocument)); 1970 ret->doc = doc; 1971 ret->href = xmlStrdup(URL); 1972 ret->next = ctxt->documents; 1973 ctxt->documents = ret; 1974 1975 /* 1976 * transmit the ns if needed 1977 */ 1978 if (ns != NULL) { 1979 root = xmlDocGetRootElement(doc); 1980 if (root != NULL) { 1981 if (xmlHasProp(root, BAD_CAST "ns") == NULL) { 1982 xmlSetProp(root, BAD_CAST "ns", ns); 1983 } 1984 } 1985 } 1986 1987 /* 1988 * push it on the stack and register it in the hash table 1989 */ 1990 xmlRelaxNGDocumentPush(ctxt, ret); 1991 1992 /* 1993 * Some preprocessing of the document content 1994 */ 1995 doc = xmlRelaxNGCleanupDoc(ctxt, doc); 1996 if (doc == NULL) { 1997 ctxt->doc = NULL; 1998 return (NULL); 1999 } 2000 2001 xmlRelaxNGDocumentPop(ctxt); 2002 2003 return (ret); 2004 } 2005 2006 /************************************************************************ 2007 * * 2008 * Error functions * 2009 * * 2010 ************************************************************************/ 2011 2012 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0); 2013 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0); 2014 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0); 2015 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1); 2016 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1); 2017 2018 static const char * 2019 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) 2020 { 2021 if (def == NULL) 2022 return ("none"); 2023 switch (def->type) { 2024 case XML_RELAXNG_EMPTY: 2025 return ("empty"); 2026 case XML_RELAXNG_NOT_ALLOWED: 2027 return ("notAllowed"); 2028 case XML_RELAXNG_EXCEPT: 2029 return ("except"); 2030 case XML_RELAXNG_TEXT: 2031 return ("text"); 2032 case XML_RELAXNG_ELEMENT: 2033 return ("element"); 2034 case XML_RELAXNG_DATATYPE: 2035 return ("datatype"); 2036 case XML_RELAXNG_VALUE: 2037 return ("value"); 2038 case XML_RELAXNG_LIST: 2039 return ("list"); 2040 case XML_RELAXNG_ATTRIBUTE: 2041 return ("attribute"); 2042 case XML_RELAXNG_DEF: 2043 return ("def"); 2044 case XML_RELAXNG_REF: 2045 return ("ref"); 2046 case XML_RELAXNG_EXTERNALREF: 2047 return ("externalRef"); 2048 case XML_RELAXNG_PARENTREF: 2049 return ("parentRef"); 2050 case XML_RELAXNG_OPTIONAL: 2051 return ("optional"); 2052 case XML_RELAXNG_ZEROORMORE: 2053 return ("zeroOrMore"); 2054 case XML_RELAXNG_ONEORMORE: 2055 return ("oneOrMore"); 2056 case XML_RELAXNG_CHOICE: 2057 return ("choice"); 2058 case XML_RELAXNG_GROUP: 2059 return ("group"); 2060 case XML_RELAXNG_INTERLEAVE: 2061 return ("interleave"); 2062 case XML_RELAXNG_START: 2063 return ("start"); 2064 case XML_RELAXNG_NOOP: 2065 return ("noop"); 2066 case XML_RELAXNG_PARAM: 2067 return ("param"); 2068 } 2069 return ("unknown"); 2070 } 2071 2072 /** 2073 * xmlRelaxNGGetErrorString: 2074 * @err: the error code 2075 * @arg1: the first string argument 2076 * @arg2: the second string argument 2077 * 2078 * computes a formatted error string for the given error code and args 2079 * 2080 * Returns the error string, it must be deallocated by the caller 2081 */ 2082 static xmlChar * 2083 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1, 2084 const xmlChar * arg2) 2085 { 2086 char msg[1000]; 2087 2088 if (arg1 == NULL) 2089 arg1 = BAD_CAST ""; 2090 if (arg2 == NULL) 2091 arg2 = BAD_CAST ""; 2092 2093 msg[0] = 0; 2094 switch (err) { 2095 case XML_RELAXNG_OK: 2096 return (NULL); 2097 case XML_RELAXNG_ERR_MEMORY: 2098 return (xmlCharStrdup("out of memory\n")); 2099 case XML_RELAXNG_ERR_TYPE: 2100 snprintf(msg, 1000, "failed to validate type %s\n", arg1); 2101 break; 2102 case XML_RELAXNG_ERR_TYPEVAL: 2103 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1, 2104 arg2); 2105 break; 2106 case XML_RELAXNG_ERR_DUPID: 2107 snprintf(msg, 1000, "ID %s redefined\n", arg1); 2108 break; 2109 case XML_RELAXNG_ERR_TYPECMP: 2110 snprintf(msg, 1000, "failed to compare type %s\n", arg1); 2111 break; 2112 case XML_RELAXNG_ERR_NOSTATE: 2113 return (xmlCharStrdup("Internal error: no state\n")); 2114 case XML_RELAXNG_ERR_NODEFINE: 2115 return (xmlCharStrdup("Internal error: no define\n")); 2116 case XML_RELAXNG_ERR_INTERNAL: 2117 snprintf(msg, 1000, "Internal error: %s\n", arg1); 2118 break; 2119 case XML_RELAXNG_ERR_LISTEXTRA: 2120 snprintf(msg, 1000, "Extra data in list: %s\n", arg1); 2121 break; 2122 case XML_RELAXNG_ERR_INTERNODATA: 2123 return (xmlCharStrdup 2124 ("Internal: interleave block has no data\n")); 2125 case XML_RELAXNG_ERR_INTERSEQ: 2126 return (xmlCharStrdup("Invalid sequence in interleave\n")); 2127 case XML_RELAXNG_ERR_INTEREXTRA: 2128 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1); 2129 break; 2130 case XML_RELAXNG_ERR_ELEMNAME: 2131 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1, 2132 arg2); 2133 break; 2134 case XML_RELAXNG_ERR_ELEMNONS: 2135 snprintf(msg, 1000, "Expecting a namespace for element %s\n", 2136 arg1); 2137 break; 2138 case XML_RELAXNG_ERR_ELEMWRONGNS: 2139 snprintf(msg, 1000, 2140 "Element %s has wrong namespace: expecting %s\n", arg1, 2141 arg2); 2142 break; 2143 case XML_RELAXNG_ERR_ELEMWRONG: 2144 snprintf(msg, 1000, "Did not expect element %s there\n", arg1); 2145 break; 2146 case XML_RELAXNG_ERR_TEXTWRONG: 2147 snprintf(msg, 1000, 2148 "Did not expect text in element %s content\n", arg1); 2149 break; 2150 case XML_RELAXNG_ERR_ELEMEXTRANS: 2151 snprintf(msg, 1000, "Expecting no namespace for element %s\n", 2152 arg1); 2153 break; 2154 case XML_RELAXNG_ERR_ELEMNOTEMPTY: 2155 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1); 2156 break; 2157 case XML_RELAXNG_ERR_NOELEM: 2158 snprintf(msg, 1000, "Expecting an element %s, got nothing\n", 2159 arg1); 2160 break; 2161 case XML_RELAXNG_ERR_NOTELEM: 2162 return (xmlCharStrdup("Expecting an element got text\n")); 2163 case XML_RELAXNG_ERR_ATTRVALID: 2164 snprintf(msg, 1000, "Element %s failed to validate attributes\n", 2165 arg1); 2166 break; 2167 case XML_RELAXNG_ERR_CONTENTVALID: 2168 snprintf(msg, 1000, "Element %s failed to validate content\n", 2169 arg1); 2170 break; 2171 case XML_RELAXNG_ERR_EXTRACONTENT: 2172 snprintf(msg, 1000, "Element %s has extra content: %s\n", 2173 arg1, arg2); 2174 break; 2175 case XML_RELAXNG_ERR_INVALIDATTR: 2176 snprintf(msg, 1000, "Invalid attribute %s for element %s\n", 2177 arg1, arg2); 2178 break; 2179 case XML_RELAXNG_ERR_LACKDATA: 2180 snprintf(msg, 1000, "Datatype element %s contains no data\n", 2181 arg1); 2182 break; 2183 case XML_RELAXNG_ERR_DATAELEM: 2184 snprintf(msg, 1000, "Datatype element %s has child elements\n", 2185 arg1); 2186 break; 2187 case XML_RELAXNG_ERR_VALELEM: 2188 snprintf(msg, 1000, "Value element %s has child elements\n", 2189 arg1); 2190 break; 2191 case XML_RELAXNG_ERR_LISTELEM: 2192 snprintf(msg, 1000, "List element %s has child elements\n", 2193 arg1); 2194 break; 2195 case XML_RELAXNG_ERR_DATATYPE: 2196 snprintf(msg, 1000, "Error validating datatype %s\n", arg1); 2197 break; 2198 case XML_RELAXNG_ERR_VALUE: 2199 snprintf(msg, 1000, "Error validating value %s\n", arg1); 2200 break; 2201 case XML_RELAXNG_ERR_LIST: 2202 return (xmlCharStrdup("Error validating list\n")); 2203 case XML_RELAXNG_ERR_NOGRAMMAR: 2204 return (xmlCharStrdup("No top grammar defined\n")); 2205 case XML_RELAXNG_ERR_EXTRADATA: 2206 return (xmlCharStrdup("Extra data in the document\n")); 2207 default: 2208 return (xmlCharStrdup("Unknown error !\n")); 2209 } 2210 if (msg[0] == 0) { 2211 snprintf(msg, 1000, "Unknown error code %d\n", err); 2212 } 2213 msg[1000 - 1] = 0; 2214 return (xmlStrdup((xmlChar *) msg)); 2215 } 2216 2217 /** 2218 * xmlRelaxNGShowValidError: 2219 * @ctxt: the validation context 2220 * @err: the error number 2221 * @node: the node 2222 * @child: the node child generating the problem. 2223 * @arg1: the first argument 2224 * @arg2: the second argument 2225 * 2226 * Show a validation error. 2227 */ 2228 static void 2229 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, 2230 xmlRelaxNGValidErr err, xmlNodePtr node, 2231 xmlNodePtr child, const xmlChar * arg1, 2232 const xmlChar * arg2) 2233 { 2234 xmlChar *msg; 2235 2236 if (ctxt->flags & FLAGS_NOERROR) 2237 return; 2238 2239 #ifdef DEBUG_ERROR 2240 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err); 2241 #endif 2242 msg = xmlRelaxNGGetErrorString(err, arg1, arg2); 2243 if (msg == NULL) 2244 return; 2245 2246 if (ctxt->errNo == XML_RELAXNG_OK) 2247 ctxt->errNo = err; 2248 xmlRngVErr(ctxt, (child == NULL ? node : child), err, 2249 (const char *) msg, arg1, arg2); 2250 xmlFree(msg); 2251 } 2252 2253 /** 2254 * xmlRelaxNGPopErrors: 2255 * @ctxt: the validation context 2256 * @level: the error level in the stack 2257 * 2258 * pop and discard all errors until the given level is reached 2259 */ 2260 static void 2261 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) 2262 { 2263 int i; 2264 xmlRelaxNGValidErrorPtr err; 2265 2266 #ifdef DEBUG_ERROR 2267 xmlGenericError(xmlGenericErrorContext, 2268 "Pop errors till level %d\n", level); 2269 #endif 2270 for (i = level; i < ctxt->errNr; i++) { 2271 err = &ctxt->errTab[i]; 2272 if (err->flags & ERROR_IS_DUP) { 2273 if (err->arg1 != NULL) 2274 xmlFree((xmlChar *) err->arg1); 2275 err->arg1 = NULL; 2276 if (err->arg2 != NULL) 2277 xmlFree((xmlChar *) err->arg2); 2278 err->arg2 = NULL; 2279 err->flags = 0; 2280 } 2281 } 2282 ctxt->errNr = level; 2283 if (ctxt->errNr <= 0) 2284 ctxt->err = NULL; 2285 } 2286 2287 /** 2288 * xmlRelaxNGDumpValidError: 2289 * @ctxt: the validation context 2290 * 2291 * Show all validation error over a given index. 2292 */ 2293 static void 2294 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) 2295 { 2296 int i, j, k; 2297 xmlRelaxNGValidErrorPtr err, dup; 2298 2299 #ifdef DEBUG_ERROR 2300 xmlGenericError(xmlGenericErrorContext, 2301 "Dumping error stack %d errors\n", ctxt->errNr); 2302 #endif 2303 for (i = 0, k = 0; i < ctxt->errNr; i++) { 2304 err = &ctxt->errTab[i]; 2305 if (k < MAX_ERROR) { 2306 for (j = 0; j < i; j++) { 2307 dup = &ctxt->errTab[j]; 2308 if ((err->err == dup->err) && (err->node == dup->node) && 2309 (xmlStrEqual(err->arg1, dup->arg1)) && 2310 (xmlStrEqual(err->arg2, dup->arg2))) { 2311 goto skip; 2312 } 2313 } 2314 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq, 2315 err->arg1, err->arg2); 2316 k++; 2317 } 2318 skip: 2319 if (err->flags & ERROR_IS_DUP) { 2320 if (err->arg1 != NULL) 2321 xmlFree((xmlChar *) err->arg1); 2322 err->arg1 = NULL; 2323 if (err->arg2 != NULL) 2324 xmlFree((xmlChar *) err->arg2); 2325 err->arg2 = NULL; 2326 err->flags = 0; 2327 } 2328 } 2329 ctxt->errNr = 0; 2330 } 2331 2332 /** 2333 * xmlRelaxNGAddValidError: 2334 * @ctxt: the validation context 2335 * @err: the error number 2336 * @arg1: the first argument 2337 * @arg2: the second argument 2338 * @dup: need to dup the args 2339 * 2340 * Register a validation error, either generating it if it's sure 2341 * or stacking it for later handling if unsure. 2342 */ 2343 static void 2344 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, 2345 xmlRelaxNGValidErr err, const xmlChar * arg1, 2346 const xmlChar * arg2, int dup) 2347 { 2348 if (ctxt == NULL) 2349 return; 2350 if (ctxt->flags & FLAGS_NOERROR) 2351 return; 2352 2353 #ifdef DEBUG_ERROR 2354 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err); 2355 #endif 2356 /* 2357 * generate the error directly 2358 */ 2359 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) || 2360 (ctxt->flags & FLAGS_NEGATIVE)) { 2361 xmlNodePtr node, seq; 2362 2363 /* 2364 * Flush first any stacked error which might be the 2365 * real cause of the problem. 2366 */ 2367 if (ctxt->errNr != 0) 2368 xmlRelaxNGDumpValidError(ctxt); 2369 if (ctxt->state != NULL) { 2370 node = ctxt->state->node; 2371 seq = ctxt->state->seq; 2372 } else { 2373 node = seq = NULL; 2374 } 2375 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2); 2376 } 2377 /* 2378 * Stack the error for later processing if needed 2379 */ 2380 else { 2381 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup); 2382 } 2383 } 2384 2385 2386 /************************************************************************ 2387 * * 2388 * Type library hooks * 2389 * * 2390 ************************************************************************/ 2391 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, 2392 const xmlChar * str); 2393 2394 /** 2395 * xmlRelaxNGSchemaTypeHave: 2396 * @data: data needed for the library 2397 * @type: the type name 2398 * 2399 * Check if the given type is provided by 2400 * the W3C XMLSchema Datatype library. 2401 * 2402 * Returns 1 if yes, 0 if no and -1 in case of error. 2403 */ 2404 static int 2405 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type) 2406 { 2407 xmlSchemaTypePtr typ; 2408 2409 if (type == NULL) 2410 return (-1); 2411 typ = xmlSchemaGetPredefinedType(type, 2412 BAD_CAST 2413 "http://www.w3.org/2001/XMLSchema"); 2414 if (typ == NULL) 2415 return (0); 2416 return (1); 2417 } 2418 2419 /** 2420 * xmlRelaxNGSchemaTypeCheck: 2421 * @data: data needed for the library 2422 * @type: the type name 2423 * @value: the value to check 2424 * @node: the node 2425 * 2426 * Check if the given type and value are validated by 2427 * the W3C XMLSchema Datatype library. 2428 * 2429 * Returns 1 if yes, 0 if no and -1 in case of error. 2430 */ 2431 static int 2432 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED, 2433 const xmlChar * type, 2434 const xmlChar * value, 2435 void **result, xmlNodePtr node) 2436 { 2437 xmlSchemaTypePtr typ; 2438 int ret; 2439 2440 if ((type == NULL) || (value == NULL)) 2441 return (-1); 2442 typ = xmlSchemaGetPredefinedType(type, 2443 BAD_CAST 2444 "http://www.w3.org/2001/XMLSchema"); 2445 if (typ == NULL) 2446 return (-1); 2447 ret = xmlSchemaValPredefTypeNode(typ, value, 2448 (xmlSchemaValPtr *) result, node); 2449 if (ret == 2) /* special ID error code */ 2450 return (2); 2451 if (ret == 0) 2452 return (1); 2453 if (ret > 0) 2454 return (0); 2455 return (-1); 2456 } 2457 2458 /** 2459 * xmlRelaxNGSchemaFacetCheck: 2460 * @data: data needed for the library 2461 * @type: the type name 2462 * @facet: the facet name 2463 * @val: the facet value 2464 * @strval: the string value 2465 * @value: the value to check 2466 * 2467 * Function provided by a type library to check a value facet 2468 * 2469 * Returns 1 if yes, 0 if no and -1 in case of error. 2470 */ 2471 static int 2472 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED, 2473 const xmlChar * type, const xmlChar * facetname, 2474 const xmlChar * val, const xmlChar * strval, 2475 void *value) 2476 { 2477 xmlSchemaFacetPtr facet; 2478 xmlSchemaTypePtr typ; 2479 int ret; 2480 2481 if ((type == NULL) || (strval == NULL)) 2482 return (-1); 2483 typ = xmlSchemaGetPredefinedType(type, 2484 BAD_CAST 2485 "http://www.w3.org/2001/XMLSchema"); 2486 if (typ == NULL) 2487 return (-1); 2488 2489 facet = xmlSchemaNewFacet(); 2490 if (facet == NULL) 2491 return (-1); 2492 2493 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) { 2494 facet->type = XML_SCHEMA_FACET_MININCLUSIVE; 2495 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) { 2496 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; 2497 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) { 2498 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; 2499 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) { 2500 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; 2501 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) { 2502 facet->type = XML_SCHEMA_FACET_TOTALDIGITS; 2503 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) { 2504 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; 2505 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) { 2506 facet->type = XML_SCHEMA_FACET_PATTERN; 2507 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) { 2508 facet->type = XML_SCHEMA_FACET_ENUMERATION; 2509 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) { 2510 facet->type = XML_SCHEMA_FACET_WHITESPACE; 2511 } else if (xmlStrEqual(facetname, BAD_CAST "length")) { 2512 facet->type = XML_SCHEMA_FACET_LENGTH; 2513 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) { 2514 facet->type = XML_SCHEMA_FACET_MAXLENGTH; 2515 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) { 2516 facet->type = XML_SCHEMA_FACET_MINLENGTH; 2517 } else { 2518 xmlSchemaFreeFacet(facet); 2519 return (-1); 2520 } 2521 facet->value = val; 2522 ret = xmlSchemaCheckFacet(facet, typ, NULL, type); 2523 if (ret != 0) { 2524 xmlSchemaFreeFacet(facet); 2525 return (-1); 2526 } 2527 ret = xmlSchemaValidateFacet(typ, facet, strval, value); 2528 xmlSchemaFreeFacet(facet); 2529 if (ret != 0) 2530 return (-1); 2531 return (0); 2532 } 2533 2534 /** 2535 * xmlRelaxNGSchemaFreeValue: 2536 * @data: data needed for the library 2537 * @value: the value to free 2538 * 2539 * Function provided by a type library to free a Schemas value 2540 * 2541 * Returns 1 if yes, 0 if no and -1 in case of error. 2542 */ 2543 static void 2544 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value) 2545 { 2546 xmlSchemaFreeValue(value); 2547 } 2548 2549 /** 2550 * xmlRelaxNGSchemaTypeCompare: 2551 * @data: data needed for the library 2552 * @type: the type name 2553 * @value1: the first value 2554 * @value2: the second value 2555 * 2556 * Compare two values for equality accordingly a type from the W3C XMLSchema 2557 * Datatype library. 2558 * 2559 * Returns 1 if equal, 0 if no and -1 in case of error. 2560 */ 2561 static int 2562 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED, 2563 const xmlChar * type, 2564 const xmlChar * value1, 2565 xmlNodePtr ctxt1, 2566 void *comp1, 2567 const xmlChar * value2, xmlNodePtr ctxt2) 2568 { 2569 int ret; 2570 xmlSchemaTypePtr typ; 2571 xmlSchemaValPtr res1 = NULL, res2 = NULL; 2572 2573 if ((type == NULL) || (value1 == NULL) || (value2 == NULL)) 2574 return (-1); 2575 typ = xmlSchemaGetPredefinedType(type, 2576 BAD_CAST 2577 "http://www.w3.org/2001/XMLSchema"); 2578 if (typ == NULL) 2579 return (-1); 2580 if (comp1 == NULL) { 2581 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1); 2582 if (ret != 0) 2583 return (-1); 2584 if (res1 == NULL) 2585 return (-1); 2586 } else { 2587 res1 = (xmlSchemaValPtr) comp1; 2588 } 2589 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2); 2590 if (ret != 0) { 2591 if ((comp1 == NULL) && (res1 != NULL)) 2592 xmlSchemaFreeValue(res1); 2593 return (-1); 2594 } 2595 if (res1 == NULL) { 2596 return (-1); 2597 } 2598 ret = xmlSchemaCompareValues(res1, res2); 2599 if (res1 != (xmlSchemaValPtr) comp1) 2600 xmlSchemaFreeValue(res1); 2601 xmlSchemaFreeValue(res2); 2602 if (ret == -2) 2603 return (-1); 2604 if (ret == 0) 2605 return (1); 2606 return (0); 2607 } 2608 2609 /** 2610 * xmlRelaxNGDefaultTypeHave: 2611 * @data: data needed for the library 2612 * @type: the type name 2613 * 2614 * Check if the given type is provided by 2615 * the default datatype library. 2616 * 2617 * Returns 1 if yes, 0 if no and -1 in case of error. 2618 */ 2619 static int 2620 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, 2621 const xmlChar * type) 2622 { 2623 if (type == NULL) 2624 return (-1); 2625 if (xmlStrEqual(type, BAD_CAST "string")) 2626 return (1); 2627 if (xmlStrEqual(type, BAD_CAST "token")) 2628 return (1); 2629 return (0); 2630 } 2631 2632 /** 2633 * xmlRelaxNGDefaultTypeCheck: 2634 * @data: data needed for the library 2635 * @type: the type name 2636 * @value: the value to check 2637 * @node: the node 2638 * 2639 * Check if the given type and value are validated by 2640 * the default datatype library. 2641 * 2642 * Returns 1 if yes, 0 if no and -1 in case of error. 2643 */ 2644 static int 2645 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, 2646 const xmlChar * type ATTRIBUTE_UNUSED, 2647 const xmlChar * value ATTRIBUTE_UNUSED, 2648 void **result ATTRIBUTE_UNUSED, 2649 xmlNodePtr node ATTRIBUTE_UNUSED) 2650 { 2651 if (value == NULL) 2652 return (-1); 2653 if (xmlStrEqual(type, BAD_CAST "string")) 2654 return (1); 2655 if (xmlStrEqual(type, BAD_CAST "token")) { 2656 return (1); 2657 } 2658 2659 return (0); 2660 } 2661 2662 /** 2663 * xmlRelaxNGDefaultTypeCompare: 2664 * @data: data needed for the library 2665 * @type: the type name 2666 * @value1: the first value 2667 * @value2: the second value 2668 * 2669 * Compare two values accordingly a type from the default 2670 * datatype library. 2671 * 2672 * Returns 1 if yes, 0 if no and -1 in case of error. 2673 */ 2674 static int 2675 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, 2676 const xmlChar * type, 2677 const xmlChar * value1, 2678 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED, 2679 void *comp1 ATTRIBUTE_UNUSED, 2680 const xmlChar * value2, 2681 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) 2682 { 2683 int ret = -1; 2684 2685 if (xmlStrEqual(type, BAD_CAST "string")) { 2686 ret = xmlStrEqual(value1, value2); 2687 } else if (xmlStrEqual(type, BAD_CAST "token")) { 2688 if (!xmlStrEqual(value1, value2)) { 2689 xmlChar *nval, *nvalue; 2690 2691 /* 2692 * TODO: trivial optimizations are possible by 2693 * computing at compile-time 2694 */ 2695 nval = xmlRelaxNGNormalize(NULL, value1); 2696 nvalue = xmlRelaxNGNormalize(NULL, value2); 2697 2698 if ((nval == NULL) || (nvalue == NULL)) 2699 ret = -1; 2700 else if (xmlStrEqual(nval, nvalue)) 2701 ret = 1; 2702 else 2703 ret = 0; 2704 if (nval != NULL) 2705 xmlFree(nval); 2706 if (nvalue != NULL) 2707 xmlFree(nvalue); 2708 } else 2709 ret = 1; 2710 } 2711 return (ret); 2712 } 2713 2714 static int xmlRelaxNGTypeInitialized = 0; 2715 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; 2716 2717 /** 2718 * xmlRelaxNGFreeTypeLibrary: 2719 * @lib: the type library structure 2720 * @namespace: the URI bound to the library 2721 * 2722 * Free the structure associated to the type library 2723 */ 2724 static void 2725 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib, 2726 const xmlChar * namespace ATTRIBUTE_UNUSED) 2727 { 2728 if (lib == NULL) 2729 return; 2730 if (lib->namespace != NULL) 2731 xmlFree((xmlChar *) lib->namespace); 2732 xmlFree(lib); 2733 } 2734 2735 /** 2736 * xmlRelaxNGRegisterTypeLibrary: 2737 * @namespace: the URI bound to the library 2738 * @data: data associated to the library 2739 * @have: the provide function 2740 * @check: the checking function 2741 * @comp: the comparison function 2742 * 2743 * Register a new type library 2744 * 2745 * Returns 0 in case of success and -1 in case of error. 2746 */ 2747 static int 2748 xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, 2749 xmlRelaxNGTypeHave have, 2750 xmlRelaxNGTypeCheck check, 2751 xmlRelaxNGTypeCompare comp, 2752 xmlRelaxNGFacetCheck facet, 2753 xmlRelaxNGTypeFree freef) 2754 { 2755 xmlRelaxNGTypeLibraryPtr lib; 2756 int ret; 2757 2758 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || 2759 (check == NULL) || (comp == NULL)) 2760 return (-1); 2761 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { 2762 xmlGenericError(xmlGenericErrorContext, 2763 "Relax-NG types library '%s' already registered\n", 2764 namespace); 2765 return (-1); 2766 } 2767 lib = 2768 (xmlRelaxNGTypeLibraryPtr) 2769 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); 2770 if (lib == NULL) { 2771 xmlRngVErrMemory(NULL, "adding types library\n"); 2772 return (-1); 2773 } 2774 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); 2775 lib->namespace = xmlStrdup(namespace); 2776 lib->data = data; 2777 lib->have = have; 2778 lib->comp = comp; 2779 lib->check = check; 2780 lib->facet = facet; 2781 lib->freef = freef; 2782 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); 2783 if (ret < 0) { 2784 xmlGenericError(xmlGenericErrorContext, 2785 "Relax-NG types library failed to register '%s'\n", 2786 namespace); 2787 xmlRelaxNGFreeTypeLibrary(lib, namespace); 2788 return (-1); 2789 } 2790 return (0); 2791 } 2792 2793 /** 2794 * xmlRelaxNGInitTypes: 2795 * 2796 * Initilize the default type libraries. 2797 * 2798 * Returns 0 in case of success and -1 in case of error. 2799 */ 2800 int 2801 xmlRelaxNGInitTypes(void) 2802 { 2803 if (xmlRelaxNGTypeInitialized != 0) 2804 return (0); 2805 xmlRelaxNGRegisteredTypes = xmlHashCreate(10); 2806 if (xmlRelaxNGRegisteredTypes == NULL) { 2807 xmlGenericError(xmlGenericErrorContext, 2808 "Failed to allocate sh table for Relax-NG types\n"); 2809 return (-1); 2810 } 2811 xmlRelaxNGRegisterTypeLibrary(BAD_CAST 2812 "http://www.w3.org/2001/XMLSchema-datatypes", 2813 NULL, xmlRelaxNGSchemaTypeHave, 2814 xmlRelaxNGSchemaTypeCheck, 2815 xmlRelaxNGSchemaTypeCompare, 2816 xmlRelaxNGSchemaFacetCheck, 2817 xmlRelaxNGSchemaFreeValue); 2818 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL, 2819 xmlRelaxNGDefaultTypeHave, 2820 xmlRelaxNGDefaultTypeCheck, 2821 xmlRelaxNGDefaultTypeCompare, NULL, 2822 NULL); 2823 xmlRelaxNGTypeInitialized = 1; 2824 return (0); 2825 } 2826 2827 /** 2828 * xmlRelaxNGCleanupTypes: 2829 * 2830 * Cleanup the default Schemas type library associated to RelaxNG 2831 */ 2832 void 2833 xmlRelaxNGCleanupTypes(void) 2834 { 2835 xmlSchemaCleanupTypes(); 2836 if (xmlRelaxNGTypeInitialized == 0) 2837 return; 2838 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator) 2839 xmlRelaxNGFreeTypeLibrary); 2840 xmlRelaxNGTypeInitialized = 0; 2841 } 2842 2843 /************************************************************************ 2844 * * 2845 * Compiling element content into regexp * 2846 * * 2847 * Sometime the element content can be compiled into a pure regexp, * 2848 * This allows a faster execution and streamability at that level * 2849 * * 2850 ************************************************************************/ 2851 2852 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, 2853 xmlRelaxNGDefinePtr def); 2854 2855 /** 2856 * xmlRelaxNGIsCompileable: 2857 * @define: the definition to check 2858 * 2859 * Check if a definition is nullable. 2860 * 2861 * Returns 1 if yes, 0 if no and -1 in case of error 2862 */ 2863 static int 2864 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) 2865 { 2866 int ret = -1; 2867 2868 if (def == NULL) { 2869 return (-1); 2870 } 2871 if ((def->type != XML_RELAXNG_ELEMENT) && 2872 (def->dflags & IS_COMPILABLE)) 2873 return (1); 2874 if ((def->type != XML_RELAXNG_ELEMENT) && 2875 (def->dflags & IS_NOT_COMPILABLE)) 2876 return (0); 2877 switch (def->type) { 2878 case XML_RELAXNG_NOOP: 2879 ret = xmlRelaxNGIsCompileable(def->content); 2880 break; 2881 case XML_RELAXNG_TEXT: 2882 case XML_RELAXNG_EMPTY: 2883 ret = 1; 2884 break; 2885 case XML_RELAXNG_ELEMENT: 2886 /* 2887 * Check if the element content is compileable 2888 */ 2889 if (((def->dflags & IS_NOT_COMPILABLE) == 0) && 2890 ((def->dflags & IS_COMPILABLE) == 0)) { 2891 xmlRelaxNGDefinePtr list; 2892 2893 list = def->content; 2894 while (list != NULL) { 2895 ret = xmlRelaxNGIsCompileable(list); 2896 if (ret != 1) 2897 break; 2898 list = list->next; 2899 } 2900 /* 2901 * Because the routine is recursive, we must guard against 2902 * discovering both COMPILABLE and NOT_COMPILABLE 2903 */ 2904 if (ret == 0) { 2905 def->dflags &= ~IS_COMPILABLE; 2906 def->dflags |= IS_NOT_COMPILABLE; 2907 } 2908 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) 2909 def->dflags |= IS_COMPILABLE; 2910 #ifdef DEBUG_COMPILE 2911 if (ret == 1) { 2912 xmlGenericError(xmlGenericErrorContext, 2913 "element content for %s is compilable\n", 2914 def->name); 2915 } else if (ret == 0) { 2916 xmlGenericError(xmlGenericErrorContext, 2917 "element content for %s is not compilable\n", 2918 def->name); 2919 } else { 2920 xmlGenericError(xmlGenericErrorContext, 2921 "Problem in RelaxNGIsCompileable for element %s\n", 2922 def->name); 2923 } 2924 #endif 2925 } 2926 /* 2927 * All elements return a compileable status unless they 2928 * are generic like anyName 2929 */ 2930 if ((def->nameClass != NULL) || (def->name == NULL)) 2931 ret = 0; 2932 else 2933 ret = 1; 2934 return (ret); 2935 case XML_RELAXNG_REF: 2936 case XML_RELAXNG_EXTERNALREF: 2937 case XML_RELAXNG_PARENTREF: 2938 if (def->depth == -20) { 2939 return (1); 2940 } else { 2941 xmlRelaxNGDefinePtr list; 2942 2943 def->depth = -20; 2944 list = def->content; 2945 while (list != NULL) { 2946 ret = xmlRelaxNGIsCompileable(list); 2947 if (ret != 1) 2948 break; 2949 list = list->next; 2950 } 2951 } 2952 break; 2953 case XML_RELAXNG_START: 2954 case XML_RELAXNG_OPTIONAL: 2955 case XML_RELAXNG_ZEROORMORE: 2956 case XML_RELAXNG_ONEORMORE: 2957 case XML_RELAXNG_CHOICE: 2958 case XML_RELAXNG_GROUP: 2959 case XML_RELAXNG_DEF:{ 2960 xmlRelaxNGDefinePtr list; 2961 2962 list = def->content; 2963 while (list != NULL) { 2964 ret = xmlRelaxNGIsCompileable(list); 2965 if (ret != 1) 2966 break; 2967 list = list->next; 2968 } 2969 break; 2970 } 2971 case XML_RELAXNG_EXCEPT: 2972 case XML_RELAXNG_ATTRIBUTE: 2973 case XML_RELAXNG_INTERLEAVE: 2974 case XML_RELAXNG_DATATYPE: 2975 case XML_RELAXNG_LIST: 2976 case XML_RELAXNG_PARAM: 2977 case XML_RELAXNG_VALUE: 2978 case XML_RELAXNG_NOT_ALLOWED: 2979 ret = 0; 2980 break; 2981 } 2982 if (ret == 0) 2983 def->dflags |= IS_NOT_COMPILABLE; 2984 if (ret == 1) 2985 def->dflags |= IS_COMPILABLE; 2986 #ifdef DEBUG_COMPILE 2987 if (ret == 1) { 2988 xmlGenericError(xmlGenericErrorContext, 2989 "RelaxNGIsCompileable %s : true\n", 2990 xmlRelaxNGDefName(def)); 2991 } else if (ret == 0) { 2992 xmlGenericError(xmlGenericErrorContext, 2993 "RelaxNGIsCompileable %s : false\n", 2994 xmlRelaxNGDefName(def)); 2995 } else { 2996 xmlGenericError(xmlGenericErrorContext, 2997 "Problem in RelaxNGIsCompileable %s\n", 2998 xmlRelaxNGDefName(def)); 2999 } 3000 #endif 3001 return (ret); 3002 } 3003 3004 /** 3005 * xmlRelaxNGCompile: 3006 * ctxt: the RelaxNG parser context 3007 * @define: the definition tree to compile 3008 * 3009 * Compile the set of definitions, it works recursively, till the 3010 * element boundaries, where it tries to compile the content if possible 3011 * 3012 * Returns 0 if success and -1 in case of error 3013 */ 3014 static int 3015 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3016 { 3017 int ret = 0; 3018 xmlRelaxNGDefinePtr list; 3019 3020 if ((ctxt == NULL) || (def == NULL)) 3021 return (-1); 3022 3023 switch (def->type) { 3024 case XML_RELAXNG_START: 3025 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) { 3026 xmlAutomataPtr oldam = ctxt->am; 3027 xmlAutomataStatePtr oldstate = ctxt->state; 3028 3029 def->depth = -25; 3030 3031 list = def->content; 3032 ctxt->am = xmlNewAutomata(); 3033 if (ctxt->am == NULL) 3034 return (-1); 3035 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3036 while (list != NULL) { 3037 xmlRelaxNGCompile(ctxt, list); 3038 list = list->next; 3039 } 3040 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3041 def->contModel = xmlAutomataCompile(ctxt->am); 3042 xmlRegexpIsDeterminist(def->contModel); 3043 3044 xmlFreeAutomata(ctxt->am); 3045 ctxt->state = oldstate; 3046 ctxt->am = oldam; 3047 } 3048 break; 3049 case XML_RELAXNG_ELEMENT: 3050 if ((ctxt->am != NULL) && (def->name != NULL)) { 3051 ctxt->state = xmlAutomataNewTransition2(ctxt->am, 3052 ctxt->state, NULL, 3053 def->name, def->ns, 3054 def); 3055 } 3056 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3057 xmlAutomataPtr oldam = ctxt->am; 3058 xmlAutomataStatePtr oldstate = ctxt->state; 3059 3060 def->depth = -25; 3061 3062 list = def->content; 3063 ctxt->am = xmlNewAutomata(); 3064 if (ctxt->am == NULL) 3065 return (-1); 3066 ctxt->state = xmlAutomataGetInitState(ctxt->am); 3067 while (list != NULL) { 3068 xmlRelaxNGCompile(ctxt, list); 3069 list = list->next; 3070 } 3071 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 3072 def->contModel = xmlAutomataCompile(ctxt->am); 3073 if (!xmlRegexpIsDeterminist(def->contModel)) { 3074 /* 3075 * we can only use the automata if it is determinist 3076 */ 3077 xmlRegFreeRegexp(def->contModel); 3078 def->contModel = NULL; 3079 } 3080 xmlFreeAutomata(ctxt->am); 3081 ctxt->state = oldstate; 3082 ctxt->am = oldam; 3083 } else { 3084 xmlAutomataPtr oldam = ctxt->am; 3085 3086 /* 3087 * we can't build the content model for this element content 3088 * but it still might be possible to build it for some of its 3089 * children, recurse. 3090 */ 3091 ret = xmlRelaxNGTryCompile(ctxt, def); 3092 ctxt->am = oldam; 3093 } 3094 break; 3095 case XML_RELAXNG_NOOP: 3096 ret = xmlRelaxNGCompile(ctxt, def->content); 3097 break; 3098 case XML_RELAXNG_OPTIONAL:{ 3099 xmlAutomataStatePtr oldstate = ctxt->state; 3100 3101 xmlRelaxNGCompile(ctxt, def->content); 3102 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 3103 break; 3104 } 3105 case XML_RELAXNG_ZEROORMORE:{ 3106 xmlAutomataStatePtr oldstate; 3107 3108 ctxt->state = 3109 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3110 oldstate = ctxt->state; 3111 list = def->content; 3112 while (list != NULL) { 3113 xmlRelaxNGCompile(ctxt, list); 3114 list = list->next; 3115 } 3116 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3117 ctxt->state = 3118 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3119 break; 3120 } 3121 case XML_RELAXNG_ONEORMORE:{ 3122 xmlAutomataStatePtr oldstate; 3123 3124 list = def->content; 3125 while (list != NULL) { 3126 xmlRelaxNGCompile(ctxt, list); 3127 list = list->next; 3128 } 3129 oldstate = ctxt->state; 3130 list = def->content; 3131 while (list != NULL) { 3132 xmlRelaxNGCompile(ctxt, list); 3133 list = list->next; 3134 } 3135 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); 3136 ctxt->state = 3137 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3138 break; 3139 } 3140 case XML_RELAXNG_CHOICE:{ 3141 xmlAutomataStatePtr target = NULL; 3142 xmlAutomataStatePtr oldstate = ctxt->state; 3143 3144 list = def->content; 3145 while (list != NULL) { 3146 ctxt->state = oldstate; 3147 ret = xmlRelaxNGCompile(ctxt, list); 3148 if (ret != 0) 3149 break; 3150 if (target == NULL) 3151 target = ctxt->state; 3152 else { 3153 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, 3154 target); 3155 } 3156 list = list->next; 3157 } 3158 ctxt->state = target; 3159 3160 break; 3161 } 3162 case XML_RELAXNG_REF: 3163 case XML_RELAXNG_EXTERNALREF: 3164 case XML_RELAXNG_PARENTREF: 3165 case XML_RELAXNG_GROUP: 3166 case XML_RELAXNG_DEF: 3167 list = def->content; 3168 while (list != NULL) { 3169 ret = xmlRelaxNGCompile(ctxt, list); 3170 if (ret != 0) 3171 break; 3172 list = list->next; 3173 } 3174 break; 3175 case XML_RELAXNG_TEXT:{ 3176 xmlAutomataStatePtr oldstate; 3177 3178 ctxt->state = 3179 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3180 oldstate = ctxt->state; 3181 xmlRelaxNGCompile(ctxt, def->content); 3182 xmlAutomataNewTransition(ctxt->am, ctxt->state, 3183 ctxt->state, BAD_CAST "#text", 3184 NULL); 3185 ctxt->state = 3186 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 3187 break; 3188 } 3189 case XML_RELAXNG_EMPTY: 3190 ctxt->state = 3191 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); 3192 break; 3193 case XML_RELAXNG_EXCEPT: 3194 case XML_RELAXNG_ATTRIBUTE: 3195 case XML_RELAXNG_INTERLEAVE: 3196 case XML_RELAXNG_NOT_ALLOWED: 3197 case XML_RELAXNG_DATATYPE: 3198 case XML_RELAXNG_LIST: 3199 case XML_RELAXNG_PARAM: 3200 case XML_RELAXNG_VALUE: 3201 /* This should not happen and generate an internal error */ 3202 fprintf(stderr, "RNG internal error trying to compile %s\n", 3203 xmlRelaxNGDefName(def)); 3204 break; 3205 } 3206 return (ret); 3207 } 3208 3209 /** 3210 * xmlRelaxNGTryCompile: 3211 * ctxt: the RelaxNG parser context 3212 * @define: the definition tree to compile 3213 * 3214 * Try to compile the set of definitions, it works recursively, 3215 * possibly ignoring parts which cannot be compiled. 3216 * 3217 * Returns 0 if success and -1 in case of error 3218 */ 3219 static int 3220 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) 3221 { 3222 int ret = 0; 3223 xmlRelaxNGDefinePtr list; 3224 3225 if ((ctxt == NULL) || (def == NULL)) 3226 return (-1); 3227 3228 if ((def->type == XML_RELAXNG_START) || 3229 (def->type == XML_RELAXNG_ELEMENT)) { 3230 ret = xmlRelaxNGIsCompileable(def); 3231 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { 3232 ctxt->am = NULL; 3233 ret = xmlRelaxNGCompile(ctxt, def); 3234 #ifdef DEBUG_PROGRESSIVE 3235 if (ret == 0) { 3236 if (def->type == XML_RELAXNG_START) 3237 xmlGenericError(xmlGenericErrorContext, 3238 "compiled the start\n"); 3239 else 3240 xmlGenericError(xmlGenericErrorContext, 3241 "compiled element %s\n", def->name); 3242 } else { 3243 if (def->type == XML_RELAXNG_START) 3244 xmlGenericError(xmlGenericErrorContext, 3245 "failed to compile the start\n"); 3246 else 3247 xmlGenericError(xmlGenericErrorContext, 3248 "failed to compile element %s\n", 3249 def->name); 3250 } 3251 #endif 3252 return (ret); 3253 } 3254 } 3255 switch (def->type) { 3256 case XML_RELAXNG_NOOP: 3257 ret = xmlRelaxNGTryCompile(ctxt, def->content); 3258 break; 3259 case XML_RELAXNG_TEXT: 3260 case XML_RELAXNG_DATATYPE: 3261 case XML_RELAXNG_LIST: 3262 case XML_RELAXNG_PARAM: 3263 case XML_RELAXNG_VALUE: 3264 case XML_RELAXNG_EMPTY: 3265 case XML_RELAXNG_ELEMENT: 3266 ret = 0; 3267 break; 3268 case XML_RELAXNG_OPTIONAL: 3269 case XML_RELAXNG_ZEROORMORE: 3270 case XML_RELAXNG_ONEORMORE: 3271 case XML_RELAXNG_CHOICE: 3272 case XML_RELAXNG_GROUP: 3273 case XML_RELAXNG_DEF: 3274 case XML_RELAXNG_START: 3275 case XML_RELAXNG_REF: 3276 case XML_RELAXNG_EXTERNALREF: 3277 case XML_RELAXNG_PARENTREF: 3278 list = def->content; 3279 while (list != NULL) { 3280 ret = xmlRelaxNGTryCompile(ctxt, list); 3281 if (ret != 0) 3282 break; 3283 list = list->next; 3284 } 3285 break; 3286 case XML_RELAXNG_EXCEPT: 3287 case XML_RELAXNG_ATTRIBUTE: 3288 case XML_RELAXNG_INTERLEAVE: 3289 case XML_RELAXNG_NOT_ALLOWED: 3290 ret = 0; 3291 break; 3292 } 3293 return (ret); 3294 } 3295 3296 /************************************************************************ 3297 * * 3298 * Parsing functions * 3299 * * 3300 ************************************************************************/ 3301 3302 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr 3303 ctxt, xmlNodePtr node); 3304 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr 3305 ctxt, xmlNodePtr node); 3306 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr 3307 ctxt, xmlNodePtr nodes, 3308 int group); 3309 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr 3310 ctxt, xmlNodePtr node); 3311 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, 3312 xmlNodePtr node); 3313 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, 3314 xmlNodePtr nodes); 3315 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr 3316 ctxt, xmlNodePtr node, 3317 xmlRelaxNGDefinePtr 3318 def); 3319 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr 3320 ctxt, xmlNodePtr nodes); 3321 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 3322 xmlRelaxNGDefinePtr define, 3323 xmlNodePtr elem); 3324 3325 3326 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) 3327 3328 /** 3329 * xmlRelaxNGIsNullable: 3330 * @define: the definition to verify 3331 * 3332 * Check if a definition is nullable. 3333 * 3334 * Returns 1 if yes, 0 if no and -1 in case of error 3335 */ 3336 static int 3337 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) 3338 { 3339 int ret; 3340 3341 if (define == NULL) 3342 return (-1); 3343 3344 if (define->dflags & IS_NULLABLE) 3345 return (1); 3346 if (define->dflags & IS_NOT_NULLABLE) 3347 return (0); 3348 switch (define->type) { 3349 case XML_RELAXNG_EMPTY: 3350 case XML_RELAXNG_TEXT: 3351 ret = 1; 3352 break; 3353 case XML_RELAXNG_NOOP: 3354 case XML_RELAXNG_DEF: 3355 case XML_RELAXNG_REF: 3356 case XML_RELAXNG_EXTERNALREF: 3357 case XML_RELAXNG_PARENTREF: 3358 case XML_RELAXNG_ONEORMORE: 3359 ret = xmlRelaxNGIsNullable(define->content); 3360 break; 3361 case XML_RELAXNG_EXCEPT: 3362 case XML_RELAXNG_NOT_ALLOWED: 3363 case XML_RELAXNG_ELEMENT: 3364 case XML_RELAXNG_DATATYPE: 3365 case XML_RELAXNG_PARAM: 3366 case XML_RELAXNG_VALUE: 3367 case XML_RELAXNG_LIST: 3368 case XML_RELAXNG_ATTRIBUTE: 3369 ret = 0; 3370 break; 3371 case XML_RELAXNG_CHOICE:{ 3372 xmlRelaxNGDefinePtr list = define->content; 3373 3374 while (list != NULL) { 3375 ret = xmlRelaxNGIsNullable(list); 3376 if (ret != 0) 3377 goto done; 3378 list = list->next; 3379 } 3380 ret = 0; 3381 break; 3382 } 3383 case XML_RELAXNG_START: 3384 case XML_RELAXNG_INTERLEAVE: 3385 case XML_RELAXNG_GROUP:{ 3386 xmlRelaxNGDefinePtr list = define->content; 3387 3388 while (list != NULL) { 3389 ret = xmlRelaxNGIsNullable(list); 3390 if (ret != 1) 3391 goto done; 3392 list = list->next; 3393 } 3394 return (1); 3395 } 3396 default: 3397 return (-1); 3398 } 3399 done: 3400 if (ret == 0) 3401 define->dflags |= IS_NOT_NULLABLE; 3402 if (ret == 1) 3403 define->dflags |= IS_NULLABLE; 3404 return (ret); 3405 } 3406 3407 /** 3408 * xmlRelaxNGIsBlank: 3409 * @str: a string 3410 * 3411 * Check if a string is ignorable c.f. 4.2. Whitespace 3412 * 3413 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise 3414 */ 3415 static int 3416 xmlRelaxNGIsBlank(xmlChar * str) 3417 { 3418 if (str == NULL) 3419 return (1); 3420 while (*str != 0) { 3421 if (!(IS_BLANK_CH(*str))) 3422 return (0); 3423 str++; 3424 } 3425 return (1); 3426 } 3427 3428 /** 3429 * xmlRelaxNGGetDataTypeLibrary: 3430 * @ctxt: a Relax-NG parser context 3431 * @node: the current data or value element 3432 * 3433 * Applies algorithm from 4.3. datatypeLibrary attribute 3434 * 3435 * Returns the datatypeLibary value or NULL if not found 3436 */ 3437 static xmlChar * 3438 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 3439 xmlNodePtr node) 3440 { 3441 xmlChar *ret, *escape; 3442 3443 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { 3444 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3445 if (ret != NULL) { 3446 if (ret[0] == 0) { 3447 xmlFree(ret); 3448 return (NULL); 3449 } 3450 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3451 if (escape == NULL) { 3452 return (ret); 3453 } 3454 xmlFree(ret); 3455 return (escape); 3456 } 3457 } 3458 node = node->parent; 3459 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { 3460 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); 3461 if (ret != NULL) { 3462 if (ret[0] == 0) { 3463 xmlFree(ret); 3464 return (NULL); 3465 } 3466 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); 3467 if (escape == NULL) { 3468 return (ret); 3469 } 3470 xmlFree(ret); 3471 return (escape); 3472 } 3473 node = node->parent; 3474 } 3475 return (NULL); 3476 } 3477 3478 /** 3479 * xmlRelaxNGParseValue: 3480 * @ctxt: a Relax-NG parser context 3481 * @node: the data node. 3482 * 3483 * parse the content of a RelaxNG value node. 3484 * 3485 * Returns the definition pointer or NULL in case of error 3486 */ 3487 static xmlRelaxNGDefinePtr 3488 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3489 { 3490 xmlRelaxNGDefinePtr def = NULL; 3491 xmlRelaxNGTypeLibraryPtr lib = NULL; 3492 xmlChar *type; 3493 xmlChar *library; 3494 int success = 0; 3495 3496 def = xmlRelaxNGNewDefine(ctxt, node); 3497 if (def == NULL) 3498 return (NULL); 3499 def->type = XML_RELAXNG_VALUE; 3500 3501 type = xmlGetProp(node, BAD_CAST "type"); 3502 if (type != NULL) { 3503 xmlRelaxNGNormExtSpace(type); 3504 if (xmlValidateNCName(type, 0)) { 3505 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3506 "value type '%s' is not an NCName\n", type, NULL); 3507 } 3508 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3509 if (library == NULL) 3510 library = 3511 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3512 3513 def->name = type; 3514 def->ns = library; 3515 3516 lib = (xmlRelaxNGTypeLibraryPtr) 3517 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3518 if (lib == NULL) { 3519 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3520 "Use of unregistered type library '%s'\n", library, 3521 NULL); 3522 def->data = NULL; 3523 } else { 3524 def->data = lib; 3525 if (lib->have == NULL) { 3526 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3527 "Internal error with type library '%s': no 'have'\n", 3528 library, NULL); 3529 } else { 3530 success = lib->have(lib->data, def->name); 3531 if (success != 1) { 3532 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3533 "Error type '%s' is not exported by type library '%s'\n", 3534 def->name, library); 3535 } 3536 } 3537 } 3538 } 3539 if (node->children == NULL) { 3540 def->value = xmlStrdup(BAD_CAST ""); 3541 } else if (((node->children->type != XML_TEXT_NODE) && 3542 (node->children->type != XML_CDATA_SECTION_NODE)) || 3543 (node->children->next != NULL)) { 3544 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, 3545 "Expecting a single text value for <value>content\n", 3546 NULL, NULL); 3547 } else if (def != NULL) { 3548 def->value = xmlNodeGetContent(node); 3549 if (def->value == NULL) { 3550 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, 3551 "Element <value> has no content\n", NULL, NULL); 3552 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { 3553 void *val = NULL; 3554 3555 success = 3556 lib->check(lib->data, def->name, def->value, &val, node); 3557 if (success != 1) { 3558 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, 3559 "Value '%s' is not acceptable for type '%s'\n", 3560 def->value, def->name); 3561 } else { 3562 if (val != NULL) 3563 def->attrs = val; 3564 } 3565 } 3566 } 3567 return (def); 3568 } 3569 3570 /** 3571 * xmlRelaxNGParseData: 3572 * @ctxt: a Relax-NG parser context 3573 * @node: the data node. 3574 * 3575 * parse the content of a RelaxNG data node. 3576 * 3577 * Returns the definition pointer or NULL in case of error 3578 */ 3579 static xmlRelaxNGDefinePtr 3580 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 3581 { 3582 xmlRelaxNGDefinePtr def = NULL, except; 3583 xmlRelaxNGDefinePtr param, lastparam = NULL; 3584 xmlRelaxNGTypeLibraryPtr lib; 3585 xmlChar *type; 3586 xmlChar *library; 3587 xmlNodePtr content; 3588 int tmp; 3589 3590 type = xmlGetProp(node, BAD_CAST "type"); 3591 if (type == NULL) { 3592 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, 3593 NULL); 3594 return (NULL); 3595 } 3596 xmlRelaxNGNormExtSpace(type); 3597 if (xmlValidateNCName(type, 0)) { 3598 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, 3599 "data type '%s' is not an NCName\n", type, NULL); 3600 } 3601 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); 3602 if (library == NULL) 3603 library = 3604 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); 3605 3606 def = xmlRelaxNGNewDefine(ctxt, node); 3607 if (def == NULL) { 3608 xmlFree(type); 3609 return (NULL); 3610 } 3611 def->type = XML_RELAXNG_DATATYPE; 3612 def->name = type; 3613 def->ns = library; 3614 3615 lib = (xmlRelaxNGTypeLibraryPtr) 3616 xmlHashLookup(xmlRelaxNGRegisteredTypes, library); 3617 if (lib == NULL) { 3618 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, 3619 "Use of unregistered type library '%s'\n", library, 3620 NULL); 3621 def->data = NULL; 3622 } else { 3623 def->data = lib; 3624 if (lib->have == NULL) { 3625 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, 3626 "Internal error with type library '%s': no 'have'\n", 3627 library, NULL); 3628 } else { 3629 tmp = lib->have(lib->data, def->name); 3630 if (tmp != 1) { 3631 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, 3632 "Error type '%s' is not exported by type library '%s'\n", 3633 def->name, library); 3634 } else 3635 if ((xmlStrEqual 3636 (library, 3637 BAD_CAST 3638 "http://www.w3.org/2001/XMLSchema-datatypes")) 3639 && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) 3640 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { 3641 ctxt->idref = 1; 3642 } 3643 } 3644 } 3645 content = node->children; 3646 3647 /* 3648 * Handle optional params 3649 */ 3650 while (content != NULL) { 3651 if (!xmlStrEqual(content->name, BAD_CAST "param")) 3652 break; 3653 if (xmlStrEqual(library, 3654 BAD_CAST "http://relaxng.org/ns/structure/1.0")) { 3655 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, 3656 "Type library '%s' does not allow type parameters\n", 3657 library, NULL); 3658 content = content->next; 3659 while ((content != NULL) && 3660 (xmlStrEqual(content->name, BAD_CAST "param"))) 3661 content = content->next; 3662 } else { 3663 param = xmlRelaxNGNewDefine(ctxt, node); 3664 if (param != NULL) { 3665 param->type = XML_RELAXNG_PARAM; 3666 param->name = xmlGetProp(content, BAD_CAST "name"); 3667 if (param->name == NULL) { 3668 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, 3669 "param has no name\n", NULL, NULL); 3670 } 3671 param->value = xmlNodeGetContent(content); 3672 if (lastparam == NULL) { 3673 def->attrs = lastparam = param; 3674 } else { 3675 lastparam->next = param; 3676 lastparam = param; 3677 } 3678 if (lib != NULL) { 3679 } 3680 } 3681 content = content->next; 3682 } 3683 } 3684 /* 3685 * Handle optional except 3686 */ 3687 if ((content != NULL) 3688 && (xmlStrEqual(content->name, BAD_CAST "except"))) { 3689 xmlNodePtr child; 3690 xmlRelaxNGDefinePtr tmp2, last = NULL; 3691 3692 except = xmlRelaxNGNewDefine(ctxt, node); 3693 if (except == NULL) { 3694 return (def); 3695 } 3696 except->type = XML_RELAXNG_EXCEPT; 3697 child = content->children; 3698 def->content = except; 3699 if (child == NULL) { 3700 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, 3701 "except has no content\n", NULL, NULL); 3702 } 3703 while (child != NULL) { 3704 tmp2 = xmlRelaxNGParsePattern(ctxt, child); 3705 if (tmp2 != NULL) { 3706 if (last == NULL) { 3707 except->content = last = tmp2; 3708 } else { 3709 last->next = tmp2; 3710 last = tmp2; 3711 } 3712 } 3713 child = child->next; 3714 } 3715 content = content->next; 3716 } 3717 /* 3718 * Check there is no unhandled data 3719 */ 3720 if (content != NULL) { 3721 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, 3722 "Element data has unexpected content %s\n", 3723 content->name, NULL); 3724 } 3725 3726 return (def); 3727 } 3728 3729 static const xmlChar *invalidName = BAD_CAST "\1"; 3730 3731 /** 3732 * xmlRelaxNGCompareNameClasses: 3733 * @defs1: the first element/attribute defs 3734 * @defs2: the second element/attribute defs 3735 * @name: the restriction on the name 3736 * @ns: the restriction on the namespace 3737 * 3738 * Compare the 2 lists of element definitions. The comparison is 3739 * that if both lists do not accept the same QNames, it returns 1 3740 * If the 2 lists can accept the same QName the comparison returns 0 3741 * 3742 * Returns 1 disttinct, 0 if equal 3743 */ 3744 static int 3745 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, 3746 xmlRelaxNGDefinePtr def2) 3747 { 3748 int ret = 1; 3749 xmlNode node; 3750 xmlNs ns; 3751 xmlRelaxNGValidCtxt ctxt; 3752 3753 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); 3754 3755 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; 3756 3757 if ((def1->type == XML_RELAXNG_ELEMENT) || 3758 (def1->type == XML_RELAXNG_ATTRIBUTE)) { 3759 if (def2->type == XML_RELAXNG_TEXT) 3760 return (1); 3761 if (def1->name != NULL) { 3762 node.name = def1->name; 3763 } else { 3764 node.name = invalidName; 3765 } 3766 if (def1->ns != NULL) { 3767 if (def1->ns[0] == 0) { 3768 node.ns = NULL; 3769 } else { 3770 node.ns = &ns; 3771 ns.href = def1->ns; 3772 } 3773 } else { 3774 node.ns = NULL; 3775 } 3776 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { 3777 if (def1->nameClass != NULL) { 3778 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); 3779 } else { 3780 ret = 0; 3781 } 3782 } else { 3783 ret = 1; 3784 } 3785 } else if (def1->type == XML_RELAXNG_TEXT) { 3786 if (def2->type == XML_RELAXNG_TEXT) 3787 return (0); 3788 return (1); 3789 } else if (def1->type == XML_RELAXNG_EXCEPT) { 3790 TODO ret = 0; 3791 } else { 3792 TODO ret = 0; 3793 } 3794 if (ret == 0) 3795 return (ret); 3796 if ((def2->type == XML_RELAXNG_ELEMENT) || 3797 (def2->type == XML_RELAXNG_ATTRIBUTE)) { 3798 if (def2->name != NULL) { 3799 node.name = def2->name; 3800 } else { 3801 node.name = invalidName; 3802 } 3803 node.ns = &ns; 3804 if (def2->ns != NULL) { 3805 if (def2->ns[0] == 0) { 3806 node.ns = NULL; 3807 } else { 3808 ns.href = def2->ns; 3809 } 3810 } else { 3811 ns.href = invalidName; 3812 } 3813 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { 3814 if (def2->nameClass != NULL) { 3815 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); 3816 } else { 3817 ret = 0; 3818 } 3819 } else { 3820 ret = 1; 3821 } 3822 } else { 3823 TODO ret = 0; 3824 } 3825 3826 return (ret); 3827 } 3828 3829 /** 3830 * xmlRelaxNGCompareElemDefLists: 3831 * @ctxt: a Relax-NG parser context 3832 * @defs1: the first list of element/attribute defs 3833 * @defs2: the second list of element/attribute defs 3834 * 3835 * Compare the 2 lists of element or attribute definitions. The comparison 3836 * is that if both lists do not accept the same QNames, it returns 1 3837 * If the 2 lists can accept the same QName the comparison returns 0 3838 * 3839 * Returns 1 disttinct, 0 if equal 3840 */ 3841 static int 3842 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt 3843 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, 3844 xmlRelaxNGDefinePtr * def2) 3845 { 3846 xmlRelaxNGDefinePtr *basedef2 = def2; 3847 3848 if ((def1 == NULL) || (def2 == NULL)) 3849 return (1); 3850 if ((*def1 == NULL) || (*def2 == NULL)) 3851 return (1); 3852 while (*def1 != NULL) { 3853 while ((*def2) != NULL) { 3854 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) 3855 return (0); 3856 def2++; 3857 } 3858 def2 = basedef2; 3859 def1++; 3860 } 3861 return (1); 3862 } 3863 3864 /** 3865 * xmlRelaxNGGenerateAttributes: 3866 * @ctxt: a Relax-NG parser context 3867 * @def: the definition definition 3868 * 3869 * Check if the definition can only generate attributes 3870 * 3871 * Returns 1 if yes, 0 if no and -1 in case of error. 3872 */ 3873 static int 3874 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, 3875 xmlRelaxNGDefinePtr def) 3876 { 3877 xmlRelaxNGDefinePtr parent, cur, tmp; 3878 3879 /* 3880 * Don't run that check in case of error. Infinite recursion 3881 * becomes possible. 3882 */ 3883 if (ctxt->nbErrors != 0) 3884 return (-1); 3885 3886 parent = NULL; 3887 cur = def; 3888 while (cur != NULL) { 3889 if ((cur->type == XML_RELAXNG_ELEMENT) || 3890 (cur->type == XML_RELAXNG_TEXT) || 3891 (cur->type == XML_RELAXNG_DATATYPE) || 3892 (cur->type == XML_RELAXNG_PARAM) || 3893 (cur->type == XML_RELAXNG_LIST) || 3894 (cur->type == XML_RELAXNG_VALUE) || 3895 (cur->type == XML_RELAXNG_EMPTY)) 3896 return (0); 3897 if ((cur->type == XML_RELAXNG_CHOICE) || 3898 (cur->type == XML_RELAXNG_INTERLEAVE) || 3899 (cur->type == XML_RELAXNG_GROUP) || 3900 (cur->type == XML_RELAXNG_ONEORMORE) || 3901 (cur->type == XML_RELAXNG_ZEROORMORE) || 3902 (cur->type == XML_RELAXNG_OPTIONAL) || 3903 (cur->type == XML_RELAXNG_PARENTREF) || 3904 (cur->type == XML_RELAXNG_EXTERNALREF) || 3905 (cur->type == XML_RELAXNG_REF) || 3906 (cur->type == XML_RELAXNG_DEF)) { 3907 if (cur->content != NULL) { 3908 parent = cur; 3909 cur = cur->content; 3910 tmp = cur; 3911 while (tmp != NULL) { 3912 tmp->parent = parent; 3913 tmp = tmp->next; 3914 } 3915 continue; 3916 } 3917 } 3918 if (cur == def) 3919 break; 3920 if (cur->next != NULL) { 3921 cur = cur->next; 3922 continue; 3923 } 3924 do { 3925 cur = cur->parent; 3926 if (cur == NULL) 3927 break; 3928 if (cur == def) 3929 return (1); 3930 if (cur->next != NULL) { 3931 cur = cur->next; 3932 break; 3933 } 3934 } while (cur != NULL); 3935 } 3936 return (1); 3937 } 3938 3939 /** 3940 * xmlRelaxNGGetElements: 3941 * @ctxt: a Relax-NG parser context 3942 * @def: the definition definition 3943 * @eora: gather elements (0) or attributes (1) 3944 * 3945 * Compute the list of top elements a definition can generate 3946 * 3947 * Returns a list of elements or NULL if none was found. 3948 */ 3949 static xmlRelaxNGDefinePtr * 3950 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, 3951 xmlRelaxNGDefinePtr def, int eora) 3952 { 3953 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; 3954 int len = 0; 3955 int max = 0; 3956 3957 /* 3958 * Don't run that check in case of error. Infinite recursion 3959 * becomes possible. 3960 */ 3961 if (ctxt->nbErrors != 0) 3962 return (NULL); 3963 3964 parent = NULL; 3965 cur = def; 3966 while (cur != NULL) { 3967 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || 3968 (cur->type == XML_RELAXNG_TEXT))) || 3969 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) { 3970 if (ret == NULL) { 3971 max = 10; 3972 ret = (xmlRelaxNGDefinePtr *) 3973 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); 3974 if (ret == NULL) { 3975 xmlRngPErrMemory(ctxt, "getting element list\n"); 3976 return (NULL); 3977 } 3978 } else if (max <= len) { 3979 xmlRelaxNGDefinePtr *temp; 3980 3981 max *= 2; 3982 temp = xmlRealloc(ret, 3983 (max + 1) * sizeof(xmlRelaxNGDefinePtr)); 3984 if (temp == NULL) { 3985 xmlRngPErrMemory(ctxt, "getting element list\n"); 3986 xmlFree(ret); 3987 return (NULL); 3988 } 3989 ret = temp; 3990 } 3991 ret[len++] = cur; 3992 ret[len] = NULL; 3993 } else if ((cur->type == XML_RELAXNG_CHOICE) || 3994 (cur->type == XML_RELAXNG_INTERLEAVE) || 3995 (cur->type == XML_RELAXNG_GROUP) || 3996 (cur->type == XML_RELAXNG_ONEORMORE) || 3997 (cur->type == XML_RELAXNG_ZEROORMORE) || 3998 (cur->type == XML_RELAXNG_OPTIONAL) || 3999 (cur->type == XML_RELAXNG_PARENTREF) || 4000 (cur->type == XML_RELAXNG_REF) || 4001 (cur->type == XML_RELAXNG_DEF) || 4002 (cur->type == XML_RELAXNG_EXTERNALREF)) { 4003 /* 4004 * Don't go within elements or attributes or string values. 4005 * Just gather the element top list 4006 */ 4007 if (cur->content != NULL) { 4008 parent = cur; 4009 cur = cur->content; 4010 tmp = cur; 4011 while (tmp != NULL) { 4012 tmp->parent = parent; 4013 tmp = tmp->next; 4014 } 4015 continue; 4016 } 4017 } 4018 if (cur == def) 4019 break; 4020 if (cur->next != NULL) { 4021 cur = cur->next; 4022 continue; 4023 } 4024 do { 4025 cur = cur->parent; 4026 if (cur == NULL) 4027 break; 4028 if (cur == def) 4029 return (ret); 4030 if (cur->next != NULL) { 4031 cur = cur->next; 4032 break; 4033 } 4034 } while (cur != NULL); 4035 } 4036 return (ret); 4037 } 4038 4039 /** 4040 * xmlRelaxNGCheckChoiceDeterminism: 4041 * @ctxt: a Relax-NG parser context 4042 * @def: the choice definition 4043 * 4044 * Also used to find indeterministic pattern in choice 4045 */ 4046 static void 4047 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, 4048 xmlRelaxNGDefinePtr def) 4049 { 4050 xmlRelaxNGDefinePtr **list; 4051 xmlRelaxNGDefinePtr cur; 4052 int nbchild = 0, i, j, ret; 4053 int is_nullable = 0; 4054 int is_indeterminist = 0; 4055 xmlHashTablePtr triage = NULL; 4056 int is_triable = 1; 4057 4058 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) 4059 return; 4060 4061 if (def->dflags & IS_PROCESSED) 4062 return; 4063 4064 /* 4065 * Don't run that check in case of error. Infinite recursion 4066 * becomes possible. 4067 */ 4068 if (ctxt->nbErrors != 0) 4069 return; 4070 4071 is_nullable = xmlRelaxNGIsNullable(def); 4072 4073 cur = def->content; 4074 while (cur != NULL) { 4075 nbchild++; 4076 cur = cur->next; 4077 } 4078 4079 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4080 sizeof(xmlRelaxNGDefinePtr 4081 *)); 4082 if (list == NULL) { 4083 xmlRngPErrMemory(ctxt, "building choice\n"); 4084 return; 4085 } 4086 i = 0; 4087 /* 4088 * a bit strong but safe 4089 */ 4090 if (is_nullable == 0) { 4091 triage = xmlHashCreate(10); 4092 } else { 4093 is_triable = 0; 4094 } 4095 cur = def->content; 4096 while (cur != NULL) { 4097 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); 4098 if ((list[i] == NULL) || (list[i][0] == NULL)) { 4099 is_triable = 0; 4100 } else if (is_triable == 1) { 4101 xmlRelaxNGDefinePtr *tmp; 4102 int res; 4103 4104 tmp = list[i]; 4105 while ((*tmp != NULL) && (is_triable == 1)) { 4106 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4107 res = xmlHashAddEntry2(triage, 4108 BAD_CAST "#text", NULL, 4109 (void *) cur); 4110 if (res != 0) 4111 is_triable = -1; 4112 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4113 ((*tmp)->name != NULL)) { 4114 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4115 res = xmlHashAddEntry2(triage, 4116 (*tmp)->name, NULL, 4117 (void *) cur); 4118 else 4119 res = xmlHashAddEntry2(triage, 4120 (*tmp)->name, (*tmp)->ns, 4121 (void *) cur); 4122 if (res != 0) 4123 is_triable = -1; 4124 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4125 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4126 res = xmlHashAddEntry2(triage, 4127 BAD_CAST "#any", NULL, 4128 (void *) cur); 4129 else 4130 res = xmlHashAddEntry2(triage, 4131 BAD_CAST "#any", (*tmp)->ns, 4132 (void *) cur); 4133 if (res != 0) 4134 is_triable = -1; 4135 } else { 4136 is_triable = -1; 4137 } 4138 tmp++; 4139 } 4140 } 4141 i++; 4142 cur = cur->next; 4143 } 4144 4145 for (i = 0; i < nbchild; i++) { 4146 if (list[i] == NULL) 4147 continue; 4148 for (j = 0; j < i; j++) { 4149 if (list[j] == NULL) 4150 continue; 4151 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4152 if (ret == 0) { 4153 is_indeterminist = 1; 4154 } 4155 } 4156 } 4157 for (i = 0; i < nbchild; i++) { 4158 if (list[i] != NULL) 4159 xmlFree(list[i]); 4160 } 4161 4162 xmlFree(list); 4163 if (is_indeterminist) { 4164 def->dflags |= IS_INDETERMINIST; 4165 } 4166 if (is_triable == 1) { 4167 def->dflags |= IS_TRIABLE; 4168 def->data = triage; 4169 } else if (triage != NULL) { 4170 xmlHashFree(triage, NULL); 4171 } 4172 def->dflags |= IS_PROCESSED; 4173 } 4174 4175 /** 4176 * xmlRelaxNGCheckGroupAttrs: 4177 * @ctxt: a Relax-NG parser context 4178 * @def: the group definition 4179 * 4180 * Detects violations of rule 7.3 4181 */ 4182 static void 4183 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, 4184 xmlRelaxNGDefinePtr def) 4185 { 4186 xmlRelaxNGDefinePtr **list; 4187 xmlRelaxNGDefinePtr cur; 4188 int nbchild = 0, i, j, ret; 4189 4190 if ((def == NULL) || 4191 ((def->type != XML_RELAXNG_GROUP) && 4192 (def->type != XML_RELAXNG_ELEMENT))) 4193 return; 4194 4195 if (def->dflags & IS_PROCESSED) 4196 return; 4197 4198 /* 4199 * Don't run that check in case of error. Infinite recursion 4200 * becomes possible. 4201 */ 4202 if (ctxt->nbErrors != 0) 4203 return; 4204 4205 cur = def->attrs; 4206 while (cur != NULL) { 4207 nbchild++; 4208 cur = cur->next; 4209 } 4210 cur = def->content; 4211 while (cur != NULL) { 4212 nbchild++; 4213 cur = cur->next; 4214 } 4215 4216 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * 4217 sizeof(xmlRelaxNGDefinePtr 4218 *)); 4219 if (list == NULL) { 4220 xmlRngPErrMemory(ctxt, "building group\n"); 4221 return; 4222 } 4223 i = 0; 4224 cur = def->attrs; 4225 while (cur != NULL) { 4226 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4227 i++; 4228 cur = cur->next; 4229 } 4230 cur = def->content; 4231 while (cur != NULL) { 4232 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); 4233 i++; 4234 cur = cur->next; 4235 } 4236 4237 for (i = 0; i < nbchild; i++) { 4238 if (list[i] == NULL) 4239 continue; 4240 for (j = 0; j < i; j++) { 4241 if (list[j] == NULL) 4242 continue; 4243 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); 4244 if (ret == 0) { 4245 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, 4246 "Attributes conflicts in group\n", NULL, NULL); 4247 } 4248 } 4249 } 4250 for (i = 0; i < nbchild; i++) { 4251 if (list[i] != NULL) 4252 xmlFree(list[i]); 4253 } 4254 4255 xmlFree(list); 4256 def->dflags |= IS_PROCESSED; 4257 } 4258 4259 /** 4260 * xmlRelaxNGComputeInterleaves: 4261 * @def: the interleave definition 4262 * @ctxt: a Relax-NG parser context 4263 * @name: the definition name 4264 * 4265 * A lot of work for preprocessing interleave definitions 4266 * is potentially needed to get a decent execution speed at runtime 4267 * - trying to get a total order on the element nodes generated 4268 * by the interleaves, order the list of interleave definitions 4269 * following that order. 4270 * - if <text/> is used to handle mixed content, it is better to 4271 * flag this in the define and simplify the runtime checking 4272 * algorithm 4273 */ 4274 static void 4275 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def, 4276 xmlRelaxNGParserCtxtPtr ctxt, 4277 xmlChar * name ATTRIBUTE_UNUSED) 4278 { 4279 xmlRelaxNGDefinePtr cur, *tmp; 4280 4281 xmlRelaxNGPartitionPtr partitions = NULL; 4282 xmlRelaxNGInterleaveGroupPtr *groups = NULL; 4283 xmlRelaxNGInterleaveGroupPtr group; 4284 int i, j, ret, res; 4285 int nbgroups = 0; 4286 int nbchild = 0; 4287 int is_mixed = 0; 4288 int is_determinist = 1; 4289 4290 /* 4291 * Don't run that check in case of error. Infinite recursion 4292 * becomes possible. 4293 */ 4294 if (ctxt->nbErrors != 0) 4295 return; 4296 4297 #ifdef DEBUG_INTERLEAVE 4298 xmlGenericError(xmlGenericErrorContext, 4299 "xmlRelaxNGComputeInterleaves(%s)\n", name); 4300 #endif 4301 cur = def->content; 4302 while (cur != NULL) { 4303 nbchild++; 4304 cur = cur->next; 4305 } 4306 4307 #ifdef DEBUG_INTERLEAVE 4308 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); 4309 #endif 4310 groups = (xmlRelaxNGInterleaveGroupPtr *) 4311 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); 4312 if (groups == NULL) 4313 goto error; 4314 cur = def->content; 4315 while (cur != NULL) { 4316 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) 4317 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); 4318 if (groups[nbgroups] == NULL) 4319 goto error; 4320 if (cur->type == XML_RELAXNG_TEXT) 4321 is_mixed++; 4322 groups[nbgroups]->rule = cur; 4323 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0); 4324 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); 4325 nbgroups++; 4326 cur = cur->next; 4327 } 4328 #ifdef DEBUG_INTERLEAVE 4329 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); 4330 #endif 4331 4332 /* 4333 * Let's check that all rules makes a partitions according to 7.4 4334 */ 4335 partitions = (xmlRelaxNGPartitionPtr) 4336 xmlMalloc(sizeof(xmlRelaxNGPartition)); 4337 if (partitions == NULL) 4338 goto error; 4339 memset(partitions, 0, sizeof(xmlRelaxNGPartition)); 4340 partitions->nbgroups = nbgroups; 4341 partitions->triage = xmlHashCreate(nbgroups); 4342 for (i = 0; i < nbgroups; i++) { 4343 group = groups[i]; 4344 for (j = i + 1; j < nbgroups; j++) { 4345 if (groups[j] == NULL) 4346 continue; 4347 4348 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, 4349 groups[j]->defs); 4350 if (ret == 0) { 4351 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, 4352 "Element or text conflicts in interleave\n", 4353 NULL, NULL); 4354 } 4355 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, 4356 groups[j]->attrs); 4357 if (ret == 0) { 4358 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, 4359 "Attributes conflicts in interleave\n", NULL, 4360 NULL); 4361 } 4362 } 4363 tmp = group->defs; 4364 if ((tmp != NULL) && (*tmp != NULL)) { 4365 while (*tmp != NULL) { 4366 if ((*tmp)->type == XML_RELAXNG_TEXT) { 4367 res = xmlHashAddEntry2(partitions->triage, 4368 BAD_CAST "#text", NULL, 4369 (void *) (long) (i + 1)); 4370 if (res != 0) 4371 is_determinist = -1; 4372 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && 4373 ((*tmp)->name != NULL)) { 4374 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4375 res = xmlHashAddEntry2(partitions->triage, 4376 (*tmp)->name, NULL, 4377 (void *) (long) (i + 1)); 4378 else 4379 res = xmlHashAddEntry2(partitions->triage, 4380 (*tmp)->name, (*tmp)->ns, 4381 (void *) (long) (i + 1)); 4382 if (res != 0) 4383 is_determinist = -1; 4384 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { 4385 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) 4386 res = xmlHashAddEntry2(partitions->triage, 4387 BAD_CAST "#any", NULL, 4388 (void *) (long) (i + 1)); 4389 else 4390 res = xmlHashAddEntry2(partitions->triage, 4391 BAD_CAST "#any", (*tmp)->ns, 4392 (void *) (long) (i + 1)); 4393 if ((*tmp)->nameClass != NULL) 4394 is_determinist = 2; 4395 if (res != 0) 4396 is_determinist = -1; 4397 } else { 4398 is_determinist = -1; 4399 } 4400 tmp++; 4401 } 4402 } else { 4403 is_determinist = 0; 4404 } 4405 } 4406 partitions->groups = groups; 4407 4408 /* 4409 * and save the partition list back in the def 4410 */ 4411 def->data = partitions; 4412 if (is_mixed != 0) 4413 def->dflags |= IS_MIXED; 4414 if (is_determinist == 1) 4415 partitions->flags = IS_DETERMINIST; 4416 if (is_determinist == 2) 4417 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; 4418 return; 4419 4420 error: 4421 xmlRngPErrMemory(ctxt, "in interleave computation\n"); 4422 if (groups != NULL) { 4423 for (i = 0; i < nbgroups; i++) 4424 if (groups[i] != NULL) { 4425 if (groups[i]->defs != NULL) 4426 xmlFree(groups[i]->defs); 4427 xmlFree(groups[i]); 4428 } 4429 xmlFree(groups); 4430 } 4431 xmlRelaxNGFreePartition(partitions); 4432 } 4433 4434 /** 4435 * xmlRelaxNGParseInterleave: 4436 * @ctxt: a Relax-NG parser context 4437 * @node: the data node. 4438 * 4439 * parse the content of a RelaxNG interleave node. 4440 * 4441 * Returns the definition pointer or NULL in case of error 4442 */ 4443 static xmlRelaxNGDefinePtr 4444 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4445 { 4446 xmlRelaxNGDefinePtr def = NULL; 4447 xmlRelaxNGDefinePtr last = NULL, cur; 4448 xmlNodePtr child; 4449 4450 def = xmlRelaxNGNewDefine(ctxt, node); 4451 if (def == NULL) { 4452 return (NULL); 4453 } 4454 def->type = XML_RELAXNG_INTERLEAVE; 4455 4456 if (ctxt->interleaves == NULL) 4457 ctxt->interleaves = xmlHashCreate(10); 4458 if (ctxt->interleaves == NULL) { 4459 xmlRngPErrMemory(ctxt, "create interleaves\n"); 4460 } else { 4461 char name[32]; 4462 4463 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); 4464 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { 4465 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, 4466 "Failed to add %s to hash table\n", 4467 (const xmlChar *) name, NULL); 4468 } 4469 } 4470 child = node->children; 4471 if (child == NULL) { 4472 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, 4473 "Element interleave is empty\n", NULL, NULL); 4474 } 4475 while (child != NULL) { 4476 if (IS_RELAXNG(child, "element")) { 4477 cur = xmlRelaxNGParseElement(ctxt, child); 4478 } else { 4479 cur = xmlRelaxNGParsePattern(ctxt, child); 4480 } 4481 if (cur != NULL) { 4482 cur->parent = def; 4483 if (last == NULL) { 4484 def->content = last = cur; 4485 } else { 4486 last->next = cur; 4487 last = cur; 4488 } 4489 } 4490 child = child->next; 4491 } 4492 4493 return (def); 4494 } 4495 4496 /** 4497 * xmlRelaxNGParseInclude: 4498 * @ctxt: a Relax-NG parser context 4499 * @node: the include node 4500 * 4501 * Integrate the content of an include node in the current grammar 4502 * 4503 * Returns 0 in case of success or -1 in case of error 4504 */ 4505 static int 4506 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4507 { 4508 xmlRelaxNGIncludePtr incl; 4509 xmlNodePtr root; 4510 int ret = 0, tmp; 4511 4512 incl = node->psvi; 4513 if (incl == NULL) { 4514 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, 4515 "Include node has no data\n", NULL, NULL); 4516 return (-1); 4517 } 4518 root = xmlDocGetRootElement(incl->doc); 4519 if (root == NULL) { 4520 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", 4521 NULL, NULL); 4522 return (-1); 4523 } 4524 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { 4525 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, 4526 "Include document root is not a grammar\n", NULL, NULL); 4527 return (-1); 4528 } 4529 4530 /* 4531 * Merge the definition from both the include and the internal list 4532 */ 4533 if (root->children != NULL) { 4534 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); 4535 if (tmp != 0) 4536 ret = -1; 4537 } 4538 if (node->children != NULL) { 4539 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); 4540 if (tmp != 0) 4541 ret = -1; 4542 } 4543 return (ret); 4544 } 4545 4546 /** 4547 * xmlRelaxNGParseDefine: 4548 * @ctxt: a Relax-NG parser context 4549 * @node: the define node 4550 * 4551 * parse the content of a RelaxNG define element node. 4552 * 4553 * Returns 0 in case of success or -1 in case of error 4554 */ 4555 static int 4556 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4557 { 4558 xmlChar *name; 4559 int ret = 0, tmp; 4560 xmlRelaxNGDefinePtr def; 4561 const xmlChar *olddefine; 4562 4563 name = xmlGetProp(node, BAD_CAST "name"); 4564 if (name == NULL) { 4565 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, 4566 "define has no name\n", NULL, NULL); 4567 } else { 4568 xmlRelaxNGNormExtSpace(name); 4569 if (xmlValidateNCName(name, 0)) { 4570 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, 4571 "define name '%s' is not an NCName\n", name, NULL); 4572 } 4573 def = xmlRelaxNGNewDefine(ctxt, node); 4574 if (def == NULL) { 4575 xmlFree(name); 4576 return (-1); 4577 } 4578 def->type = XML_RELAXNG_DEF; 4579 def->name = name; 4580 if (node->children == NULL) { 4581 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, 4582 "define has no children\n", NULL, NULL); 4583 } else { 4584 olddefine = ctxt->define; 4585 ctxt->define = name; 4586 def->content = 4587 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4588 ctxt->define = olddefine; 4589 } 4590 if (ctxt->grammar->defs == NULL) 4591 ctxt->grammar->defs = xmlHashCreate(10); 4592 if (ctxt->grammar->defs == NULL) { 4593 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4594 "Could not create definition hash\n", NULL, NULL); 4595 ret = -1; 4596 } else { 4597 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); 4598 if (tmp < 0) { 4599 xmlRelaxNGDefinePtr prev; 4600 4601 prev = xmlHashLookup(ctxt->grammar->defs, name); 4602 if (prev == NULL) { 4603 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, 4604 "Internal error on define aggregation of %s\n", 4605 name, NULL); 4606 ret = -1; 4607 } else { 4608 while (prev->nextHash != NULL) 4609 prev = prev->nextHash; 4610 prev->nextHash = def; 4611 } 4612 } 4613 } 4614 } 4615 return (ret); 4616 } 4617 4618 /** 4619 * xmlRelaxNGProcessExternalRef: 4620 * @ctxt: the parser context 4621 * @node: the externlRef node 4622 * 4623 * Process and compile an externlRef node 4624 * 4625 * Returns the xmlRelaxNGDefinePtr or NULL in case of error 4626 */ 4627 static xmlRelaxNGDefinePtr 4628 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4629 { 4630 xmlRelaxNGDocumentPtr docu; 4631 xmlNodePtr root, tmp; 4632 xmlChar *ns; 4633 int newNs = 0, oldflags; 4634 xmlRelaxNGDefinePtr def; 4635 4636 docu = node->psvi; 4637 if (docu != NULL) { 4638 def = xmlRelaxNGNewDefine(ctxt, node); 4639 if (def == NULL) 4640 return (NULL); 4641 def->type = XML_RELAXNG_EXTERNALREF; 4642 4643 if (docu->content == NULL) { 4644 /* 4645 * Then do the parsing for good 4646 */ 4647 root = xmlDocGetRootElement(docu->doc); 4648 if (root == NULL) { 4649 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY, 4650 "xmlRelaxNGParse: %s is empty\n", ctxt->URL, 4651 NULL); 4652 return (NULL); 4653 } 4654 /* 4655 * ns transmission rules 4656 */ 4657 ns = xmlGetProp(root, BAD_CAST "ns"); 4658 if (ns == NULL) { 4659 tmp = node; 4660 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) { 4661 ns = xmlGetProp(tmp, BAD_CAST "ns"); 4662 if (ns != NULL) { 4663 break; 4664 } 4665 tmp = tmp->parent; 4666 } 4667 if (ns != NULL) { 4668 xmlSetProp(root, BAD_CAST "ns", ns); 4669 newNs = 1; 4670 xmlFree(ns); 4671 } 4672 } else { 4673 xmlFree(ns); 4674 } 4675 4676 /* 4677 * Parsing to get a precompiled schemas. 4678 */ 4679 oldflags = ctxt->flags; 4680 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; 4681 docu->schema = xmlRelaxNGParseDocument(ctxt, root); 4682 ctxt->flags = oldflags; 4683 if ((docu->schema != NULL) && 4684 (docu->schema->topgrammar != NULL)) { 4685 docu->content = docu->schema->topgrammar->start; 4686 } 4687 4688 /* 4689 * the externalRef may be reused in a different ns context 4690 */ 4691 if (newNs == 1) { 4692 xmlUnsetProp(root, BAD_CAST "ns"); 4693 } 4694 } 4695 def->content = docu->content; 4696 } else { 4697 def = NULL; 4698 } 4699 return (def); 4700 } 4701 4702 /** 4703 * xmlRelaxNGParsePattern: 4704 * @ctxt: a Relax-NG parser context 4705 * @node: the pattern node. 4706 * 4707 * parse the content of a RelaxNG pattern node. 4708 * 4709 * Returns the definition pointer or NULL in case of error or if no 4710 * pattern is generated. 4711 */ 4712 static xmlRelaxNGDefinePtr 4713 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) 4714 { 4715 xmlRelaxNGDefinePtr def = NULL; 4716 4717 if (node == NULL) { 4718 return (NULL); 4719 } 4720 if (IS_RELAXNG(node, "element")) { 4721 def = xmlRelaxNGParseElement(ctxt, node); 4722 } else if (IS_RELAXNG(node, "attribute")) { 4723 def = xmlRelaxNGParseAttribute(ctxt, node); 4724 } else if (IS_RELAXNG(node, "empty")) { 4725 def = xmlRelaxNGNewDefine(ctxt, node); 4726 if (def == NULL) 4727 return (NULL); 4728 def->type = XML_RELAXNG_EMPTY; 4729 if (node->children != NULL) { 4730 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY, 4731 "empty: had a child node\n", NULL, NULL); 4732 } 4733 } else if (IS_RELAXNG(node, "text")) { 4734 def = xmlRelaxNGNewDefine(ctxt, node); 4735 if (def == NULL) 4736 return (NULL); 4737 def->type = XML_RELAXNG_TEXT; 4738 if (node->children != NULL) { 4739 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD, 4740 "text: had a child node\n", NULL, NULL); 4741 } 4742 } else if (IS_RELAXNG(node, "zeroOrMore")) { 4743 def = xmlRelaxNGNewDefine(ctxt, node); 4744 if (def == NULL) 4745 return (NULL); 4746 def->type = XML_RELAXNG_ZEROORMORE; 4747 if (node->children == NULL) { 4748 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4749 "Element %s is empty\n", node->name, NULL); 4750 } else { 4751 def->content = 4752 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4753 } 4754 } else if (IS_RELAXNG(node, "oneOrMore")) { 4755 def = xmlRelaxNGNewDefine(ctxt, node); 4756 if (def == NULL) 4757 return (NULL); 4758 def->type = XML_RELAXNG_ONEORMORE; 4759 if (node->children == NULL) { 4760 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4761 "Element %s is empty\n", node->name, NULL); 4762 } else { 4763 def->content = 4764 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4765 } 4766 } else if (IS_RELAXNG(node, "optional")) { 4767 def = xmlRelaxNGNewDefine(ctxt, node); 4768 if (def == NULL) 4769 return (NULL); 4770 def->type = XML_RELAXNG_OPTIONAL; 4771 if (node->children == NULL) { 4772 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4773 "Element %s is empty\n", node->name, NULL); 4774 } else { 4775 def->content = 4776 xmlRelaxNGParsePatterns(ctxt, node->children, 1); 4777 } 4778 } else if (IS_RELAXNG(node, "choice")) { 4779 def = xmlRelaxNGNewDefine(ctxt, node); 4780 if (def == NULL) 4781 return (NULL); 4782 def->type = XML_RELAXNG_CHOICE; 4783 if (node->children == NULL) { 4784 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4785 "Element %s is empty\n", node->name, NULL); 4786 } else { 4787 def->content = 4788 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4789 } 4790 } else if (IS_RELAXNG(node, "group")) { 4791 def = xmlRelaxNGNewDefine(ctxt, node); 4792 if (def == NULL) 4793 return (NULL); 4794 def->type = XML_RELAXNG_GROUP; 4795 if (node->children == NULL) { 4796 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4797 "Element %s is empty\n", node->name, NULL); 4798 } else { 4799 def->content = 4800 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4801 } 4802 } else if (IS_RELAXNG(node, "ref")) { 4803 def = xmlRelaxNGNewDefine(ctxt, node); 4804 if (def == NULL) 4805 return (NULL); 4806 def->type = XML_RELAXNG_REF; 4807 def->name = xmlGetProp(node, BAD_CAST "name"); 4808 if (def->name == NULL) { 4809 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n", 4810 NULL, NULL); 4811 } else { 4812 xmlRelaxNGNormExtSpace(def->name); 4813 if (xmlValidateNCName(def->name, 0)) { 4814 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID, 4815 "ref name '%s' is not an NCName\n", def->name, 4816 NULL); 4817 } 4818 } 4819 if (node->children != NULL) { 4820 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n", 4821 NULL, NULL); 4822 } 4823 if (ctxt->grammar->refs == NULL) 4824 ctxt->grammar->refs = xmlHashCreate(10); 4825 if (ctxt->grammar->refs == NULL) { 4826 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4827 "Could not create references hash\n", NULL, NULL); 4828 def = NULL; 4829 } else { 4830 int tmp; 4831 4832 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); 4833 if (tmp < 0) { 4834 xmlRelaxNGDefinePtr prev; 4835 4836 prev = (xmlRelaxNGDefinePtr) 4837 xmlHashLookup(ctxt->grammar->refs, def->name); 4838 if (prev == NULL) { 4839 if (def->name != NULL) { 4840 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4841 "Error refs definitions '%s'\n", 4842 def->name, NULL); 4843 } else { 4844 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, 4845 "Error refs definitions\n", 4846 NULL, NULL); 4847 } 4848 def = NULL; 4849 } else { 4850 def->nextHash = prev->nextHash; 4851 prev->nextHash = def; 4852 } 4853 } 4854 } 4855 } else if (IS_RELAXNG(node, "data")) { 4856 def = xmlRelaxNGParseData(ctxt, node); 4857 } else if (IS_RELAXNG(node, "value")) { 4858 def = xmlRelaxNGParseValue(ctxt, node); 4859 } else if (IS_RELAXNG(node, "list")) { 4860 def = xmlRelaxNGNewDefine(ctxt, node); 4861 if (def == NULL) 4862 return (NULL); 4863 def->type = XML_RELAXNG_LIST; 4864 if (node->children == NULL) { 4865 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, 4866 "Element %s is empty\n", node->name, NULL); 4867 } else { 4868 def->content = 4869 xmlRelaxNGParsePatterns(ctxt, node->children, 0); 4870 } 4871 } else if (IS_RELAXNG(node, "interleave")) { 4872 def = xmlRelaxNGParseInterleave(ctxt, node); 4873 } else if (IS_RELAXNG(node, "externalRef")) { 4874 def = xmlRelaxNGProcessExternalRef(ctxt, node); 4875 } else if (IS_RELAXNG(node, "notAllowed")) { 4876 def = xmlRelaxNGNewDefine(ctxt, node); 4877 if (def == NULL) 4878 return (NULL); 4879 def->type = XML_RELAXNG_NOT_ALLOWED; 4880 if (node->children != NULL) { 4881 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY, 4882 "xmlRelaxNGParse: notAllowed element is not empty\n", 4883 NULL, NULL); 4884 } 4885 } else if (IS_RELAXNG(node, "grammar")) { 4886 xmlRelaxNGGrammarPtr grammar, old; 4887 xmlRelaxNGGrammarPtr oldparent; 4888 4889 #ifdef DEBUG_GRAMMAR 4890 xmlGenericError(xmlGenericErrorContext, 4891 "Found <grammar> pattern\n"); 4892 #endif 4893 4894 oldparent = ctxt->parentgrammar; 4895 old = ctxt->grammar; 4896 ctxt->parentgrammar = old; 4897 grammar = xmlRelaxNGParseGrammar(ctxt, node->children); 4898 if (old != NULL) { 4899 ctxt->grammar = old; 4900 ctxt->parentgrammar = oldparent; 4901 #if 0 4902 if (grammar != NULL) { 4903 grammar->next = old->next; 4904 old->next = grammar; 4905 } 4906 #endif 4907 } 4908 if (grammar != NULL) 4909 def = grammar->start; 4910 else 4911 def = NULL; 4912 } else if (IS_RELAXNG(node, "parentRef")) { 4913 if (ctxt->parentgrammar == NULL) { 4914 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT, 4915 "Use of parentRef without a parent grammar\n", NULL, 4916 NULL); 4917 return (NULL); 4918 } 4919 def = xmlRelaxNGNewDefine(ctxt, node); 4920 if (def == NULL) 4921 return (NULL); 4922 def->type = XML_RELAXNG_PARENTREF; 4923 def->name = xmlGetProp(node, BAD_CAST "name"); 4924 if (def->name == NULL) { 4925 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME, 4926 "parentRef has no name\n", NULL, NULL); 4927 } else { 4928 xmlRelaxNGNormExtSpace(def->name); 4929 if (xmlValidateNCName(def->name, 0)) { 4930 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID, 4931 "parentRef name '%s' is not an NCName\n", 4932 def->name, NULL); 4933 } 4934 } 4935 if (node->children != NULL) { 4936 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY, 4937 "parentRef is not empty\n", NULL, NULL); 4938 } 4939 if (ctxt->parentgrammar->refs == NULL) 4940 ctxt->parentgrammar->refs = xmlHashCreate(10); 4941 if (ctxt->parentgrammar->refs == NULL) { 4942 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 4943 "Could not create references hash\n", NULL, NULL); 4944 def = NULL; 4945 } else if (def->name != NULL) { 4946 int tmp; 4947 4948 tmp = 4949 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); 4950 if (tmp < 0) { 4951 xmlRelaxNGDefinePtr prev; 4952 4953 prev = (xmlRelaxNGDefinePtr) 4954 xmlHashLookup(ctxt->parentgrammar->refs, def->name); 4955 if (prev == NULL) { 4956 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, 4957 "Internal error parentRef definitions '%s'\n", 4958 def->name, NULL); 4959 def = NULL; 4960 } else { 4961 def->nextHash = prev->nextHash; 4962 prev->nextHash = def; 4963 } 4964 } 4965 } 4966 } else if (IS_RELAXNG(node, "mixed")) { 4967 if (node->children == NULL) { 4968 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n", 4969 NULL, NULL); 4970 def = NULL; 4971 } else { 4972 def = xmlRelaxNGParseInterleave(ctxt, node); 4973 if (def != NULL) { 4974 xmlRelaxNGDefinePtr tmp; 4975 4976 if ((def->content != NULL) && (def->content->next != NULL)) { 4977 tmp = xmlRelaxNGNewDefine(ctxt, node); 4978 if (tmp !=