Reactos
at master 6959 lines 190 kB view raw
1/* 2 * valid.c : part of the code use to do the DTD handling and the validity 3 * checking 4 * 5 * See Copyright for the status of this software. 6 * 7 * daniel@veillard.com 8 */ 9 10#define IN_LIBXML 11#include "libxml.h" 12 13#include <string.h> 14#include <stdlib.h> 15 16#include <libxml/xmlmemory.h> 17#include <libxml/hash.h> 18#include <libxml/uri.h> 19#include <libxml/valid.h> 20#include <libxml/parser.h> 21#include <libxml/parserInternals.h> 22#include <libxml/xmlerror.h> 23#include <libxml/list.h> 24 25#include "private/error.h" 26#include "private/parser.h" 27 28static xmlElementPtr 29xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, 30 int create); 31 32#define TODO \ 33 xmlGenericError(xmlGenericErrorContext, \ 34 "Unimplemented block at %s:%d\n", \ 35 __FILE__, __LINE__); 36 37#ifdef LIBXML_VALID_ENABLED 38static int 39xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, 40 const xmlChar *value); 41#endif 42/************************************************************************ 43 * * 44 * Error handling routines * 45 * * 46 ************************************************************************/ 47 48/** 49 * xmlVErrMemory: 50 * @ctxt: an XML validation parser context 51 * @extra: extra information 52 * 53 * Handle an out of memory error 54 */ 55static void 56xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra) 57{ 58 xmlGenericErrorFunc channel = NULL; 59 xmlParserCtxtPtr pctxt = NULL; 60 void *data = NULL; 61 62 if (ctxt != NULL) { 63 channel = ctxt->error; 64 data = ctxt->userData; 65 /* Look up flag to detect if it is part of a parsing 66 context */ 67 if (ctxt->flags & XML_VCTXT_USE_PCTXT) { 68 pctxt = ctxt->userData; 69 } 70 } 71 if (extra) 72 __xmlRaiseError(NULL, channel, data, 73 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, 74 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, 75 "Memory allocation failed : %s\n", extra); 76 else 77 __xmlRaiseError(NULL, channel, data, 78 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, 79 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, 80 "Memory allocation failed\n"); 81} 82 83/** 84 * xmlErrValid: 85 * @ctxt: an XML validation parser context 86 * @error: the error number 87 * @extra: extra information 88 * 89 * Handle a validation error 90 */ 91static void LIBXML_ATTR_FORMAT(3,0) 92xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, 93 const char *msg, const char *extra) 94{ 95 xmlGenericErrorFunc channel = NULL; 96 xmlParserCtxtPtr pctxt = NULL; 97 void *data = NULL; 98 99 if (ctxt != NULL) { 100 channel = ctxt->error; 101 data = ctxt->userData; 102 /* Look up flag to detect if it is part of a parsing 103 context */ 104 if (ctxt->flags & XML_VCTXT_USE_PCTXT) { 105 pctxt = ctxt->userData; 106 } 107 } 108 if (extra) 109 __xmlRaiseError(NULL, channel, data, 110 pctxt, NULL, XML_FROM_VALID, error, 111 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, 112 msg, extra); 113 else 114 __xmlRaiseError(NULL, channel, data, 115 pctxt, NULL, XML_FROM_VALID, error, 116 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, 117 "%s", msg); 118} 119 120#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 121/** 122 * xmlErrValidNode: 123 * @ctxt: an XML validation parser context 124 * @node: the node raising the error 125 * @error: the error number 126 * @str1: extra information 127 * @str2: extra information 128 * @str3: extra information 129 * 130 * Handle a validation error, provide contextual information 131 */ 132static void LIBXML_ATTR_FORMAT(4,0) 133xmlErrValidNode(xmlValidCtxtPtr ctxt, 134 xmlNodePtr node, xmlParserErrors error, 135 const char *msg, const xmlChar * str1, 136 const xmlChar * str2, const xmlChar * str3) 137{ 138 xmlStructuredErrorFunc schannel = NULL; 139 xmlGenericErrorFunc channel = NULL; 140 xmlParserCtxtPtr pctxt = NULL; 141 void *data = NULL; 142 143 if (ctxt != NULL) { 144 channel = ctxt->error; 145 data = ctxt->userData; 146 /* Look up flag to detect if it is part of a parsing 147 context */ 148 if (ctxt->flags & XML_VCTXT_USE_PCTXT) { 149 pctxt = ctxt->userData; 150 } 151 } 152 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 153 XML_ERR_ERROR, NULL, 0, 154 (const char *) str1, 155 (const char *) str2, 156 (const char *) str3, 0, 0, msg, str1, str2, str3); 157} 158#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ 159 160#ifdef LIBXML_VALID_ENABLED 161/** 162 * xmlErrValidNodeNr: 163 * @ctxt: an XML validation parser context 164 * @node: the node raising the error 165 * @error: the error number 166 * @str1: extra information 167 * @int2: extra information 168 * @str3: extra information 169 * 170 * Handle a validation error, provide contextual information 171 */ 172static void LIBXML_ATTR_FORMAT(4,0) 173xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, 174 xmlNodePtr node, xmlParserErrors error, 175 const char *msg, const xmlChar * str1, 176 int int2, const xmlChar * str3) 177{ 178 xmlStructuredErrorFunc schannel = NULL; 179 xmlGenericErrorFunc channel = NULL; 180 xmlParserCtxtPtr pctxt = NULL; 181 void *data = NULL; 182 183 if (ctxt != NULL) { 184 channel = ctxt->error; 185 data = ctxt->userData; 186 /* Look up flag to detect if it is part of a parsing 187 context */ 188 if (ctxt->flags & XML_VCTXT_USE_PCTXT) { 189 pctxt = ctxt->userData; 190 } 191 } 192 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 193 XML_ERR_ERROR, NULL, 0, 194 (const char *) str1, 195 (const char *) str3, 196 NULL, int2, 0, msg, str1, int2, str3); 197} 198 199/** 200 * xmlErrValidWarning: 201 * @ctxt: an XML validation parser context 202 * @node: the node raising the error 203 * @error: the error number 204 * @str1: extra information 205 * @str2: extra information 206 * @str3: extra information 207 * 208 * Handle a validation error, provide contextual information 209 */ 210static void LIBXML_ATTR_FORMAT(4,0) 211xmlErrValidWarning(xmlValidCtxtPtr ctxt, 212 xmlNodePtr node, xmlParserErrors error, 213 const char *msg, const xmlChar * str1, 214 const xmlChar * str2, const xmlChar * str3) 215{ 216 xmlStructuredErrorFunc schannel = NULL; 217 xmlGenericErrorFunc channel = NULL; 218 xmlParserCtxtPtr pctxt = NULL; 219 void *data = NULL; 220 221 if (ctxt != NULL) { 222 channel = ctxt->warning; 223 data = ctxt->userData; 224 /* Look up flag to detect if it is part of a parsing 225 context */ 226 if (ctxt->flags & XML_VCTXT_USE_PCTXT) { 227 pctxt = ctxt->userData; 228 } 229 } 230 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 231 XML_ERR_WARNING, NULL, 0, 232 (const char *) str1, 233 (const char *) str2, 234 (const char *) str3, 0, 0, msg, str1, str2, str3); 235} 236 237 238 239#ifdef LIBXML_REGEXP_ENABLED 240/* 241 * If regexp are enabled we can do continuous validation without the 242 * need of a tree to validate the content model. this is done in each 243 * callbacks. 244 * Each xmlValidState represent the validation state associated to the 245 * set of nodes currently open from the document root to the current element. 246 */ 247 248 249typedef struct _xmlValidState { 250 xmlElementPtr elemDecl; /* pointer to the content model */ 251 xmlNodePtr node; /* pointer to the current node */ 252 xmlRegExecCtxtPtr exec; /* regexp runtime */ 253} _xmlValidState; 254 255 256static int 257vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { 258 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) { 259 ctxt->vstateMax = 10; 260 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * 261 sizeof(ctxt->vstateTab[0])); 262 if (ctxt->vstateTab == NULL) { 263 xmlVErrMemory(ctxt, "malloc failed"); 264 return(-1); 265 } 266 } 267 268 if (ctxt->vstateNr >= ctxt->vstateMax) { 269 xmlValidState *tmp; 270 271 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 272 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 273 if (tmp == NULL) { 274 xmlVErrMemory(ctxt, "realloc failed"); 275 return(-1); 276 } 277 ctxt->vstateMax *= 2; 278 ctxt->vstateTab = tmp; 279 } 280 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr]; 281 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl; 282 ctxt->vstateTab[ctxt->vstateNr].node = node; 283 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { 284 if (elemDecl->contModel == NULL) 285 xmlValidBuildContentModel(ctxt, elemDecl); 286 if (elemDecl->contModel != NULL) { 287 ctxt->vstateTab[ctxt->vstateNr].exec = 288 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); 289 } else { 290 ctxt->vstateTab[ctxt->vstateNr].exec = NULL; 291 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, 292 XML_ERR_INTERNAL_ERROR, 293 "Failed to build content model regexp for %s\n", 294 node->name, NULL, NULL); 295 } 296 } 297 return(ctxt->vstateNr++); 298} 299 300static int 301vstateVPop(xmlValidCtxtPtr ctxt) { 302 xmlElementPtr elemDecl; 303 304 if (ctxt->vstateNr < 1) return(-1); 305 ctxt->vstateNr--; 306 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl; 307 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL; 308 ctxt->vstateTab[ctxt->vstateNr].node = NULL; 309 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { 310 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec); 311 } 312 ctxt->vstateTab[ctxt->vstateNr].exec = NULL; 313 if (ctxt->vstateNr >= 1) 314 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1]; 315 else 316 ctxt->vstate = NULL; 317 return(ctxt->vstateNr); 318} 319 320#else /* not LIBXML_REGEXP_ENABLED */ 321/* 322 * If regexp are not enabled, it uses a home made algorithm less 323 * complex and easier to 324 * debug/maintain than a generic NFA -> DFA state based algo. The 325 * only restriction is on the deepness of the tree limited by the 326 * size of the occurs bitfield 327 * 328 * this is the content of a saved state for rollbacks 329 */ 330 331#define ROLLBACK_OR 0 332#define ROLLBACK_PARENT 1 333 334typedef struct _xmlValidState { 335 xmlElementContentPtr cont; /* pointer to the content model subtree */ 336 xmlNodePtr node; /* pointer to the current node in the list */ 337 long occurs;/* bitfield for multiple occurrences */ 338 unsigned char depth; /* current depth in the overall tree */ 339 unsigned char state; /* ROLLBACK_XXX */ 340} _xmlValidState; 341 342#define MAX_RECURSE 25000 343#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8) 344#define CONT ctxt->vstate->cont 345#define NODE ctxt->vstate->node 346#define DEPTH ctxt->vstate->depth 347#define OCCURS ctxt->vstate->occurs 348#define STATE ctxt->vstate->state 349 350#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH)) 351#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1)) 352 353#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH) 354#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1) 355 356static int 357vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, 358 xmlNodePtr node, unsigned char depth, long occurs, 359 unsigned char state) { 360 int i = ctxt->vstateNr - 1; 361 362 if (ctxt->vstateNr > MAX_RECURSE) { 363 return(-1); 364 } 365 if (ctxt->vstateTab == NULL) { 366 ctxt->vstateMax = 8; 367 ctxt->vstateTab = (xmlValidState *) xmlMalloc( 368 ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 369 if (ctxt->vstateTab == NULL) { 370 xmlVErrMemory(ctxt, "malloc failed"); 371 return(-1); 372 } 373 } 374 if (ctxt->vstateNr >= ctxt->vstateMax) { 375 xmlValidState *tmp; 376 377 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 378 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 379 if (tmp == NULL) { 380 xmlVErrMemory(ctxt, "malloc failed"); 381 return(-1); 382 } 383 ctxt->vstateMax *= 2; 384 ctxt->vstateTab = tmp; 385 ctxt->vstate = &ctxt->vstateTab[0]; 386 } 387 /* 388 * Don't push on the stack a state already here 389 */ 390 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) && 391 (ctxt->vstateTab[i].node == node) && 392 (ctxt->vstateTab[i].depth == depth) && 393 (ctxt->vstateTab[i].occurs == occurs) && 394 (ctxt->vstateTab[i].state == state)) 395 return(ctxt->vstateNr); 396 ctxt->vstateTab[ctxt->vstateNr].cont = cont; 397 ctxt->vstateTab[ctxt->vstateNr].node = node; 398 ctxt->vstateTab[ctxt->vstateNr].depth = depth; 399 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs; 400 ctxt->vstateTab[ctxt->vstateNr].state = state; 401 return(ctxt->vstateNr++); 402} 403 404static int 405vstateVPop(xmlValidCtxtPtr ctxt) { 406 if (ctxt->vstateNr <= 1) return(-1); 407 ctxt->vstateNr--; 408 ctxt->vstate = &ctxt->vstateTab[0]; 409 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont; 410 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node; 411 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth; 412 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs; 413 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state; 414 return(ctxt->vstateNr); 415} 416 417#endif /* LIBXML_REGEXP_ENABLED */ 418 419static int 420nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) 421{ 422 if (ctxt->nodeMax <= 0) { 423 ctxt->nodeMax = 4; 424 ctxt->nodeTab = 425 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * 426 sizeof(ctxt->nodeTab[0])); 427 if (ctxt->nodeTab == NULL) { 428 xmlVErrMemory(ctxt, "malloc failed"); 429 ctxt->nodeMax = 0; 430 return (0); 431 } 432 } 433 if (ctxt->nodeNr >= ctxt->nodeMax) { 434 xmlNodePtr *tmp; 435 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, 436 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); 437 if (tmp == NULL) { 438 xmlVErrMemory(ctxt, "realloc failed"); 439 return (0); 440 } 441 ctxt->nodeMax *= 2; 442 ctxt->nodeTab = tmp; 443 } 444 ctxt->nodeTab[ctxt->nodeNr] = value; 445 ctxt->node = value; 446 return (ctxt->nodeNr++); 447} 448static xmlNodePtr 449nodeVPop(xmlValidCtxtPtr ctxt) 450{ 451 xmlNodePtr ret; 452 453 if (ctxt->nodeNr <= 0) 454 return (NULL); 455 ctxt->nodeNr--; 456 if (ctxt->nodeNr > 0) 457 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; 458 else 459 ctxt->node = NULL; 460 ret = ctxt->nodeTab[ctxt->nodeNr]; 461 ctxt->nodeTab[ctxt->nodeNr] = NULL; 462 return (ret); 463} 464 465/* TODO: use hash table for accesses to elem and attribute definitions */ 466 467 468#define CHECK_DTD \ 469 if (doc == NULL) return(0); \ 470 else if ((doc->intSubset == NULL) && \ 471 (doc->extSubset == NULL)) return(0) 472 473#ifdef LIBXML_REGEXP_ENABLED 474 475/************************************************************************ 476 * * 477 * Content model validation based on the regexps * 478 * * 479 ************************************************************************/ 480 481/** 482 * xmlValidBuildAContentModel: 483 * @content: the content model 484 * @ctxt: the schema parser context 485 * @name: the element name whose content is being built 486 * 487 * Generate the automata sequence needed for that type 488 * 489 * Returns 1 if successful or 0 in case of error. 490 */ 491static int 492xmlValidBuildAContentModel(xmlElementContentPtr content, 493 xmlValidCtxtPtr ctxt, 494 const xmlChar *name) { 495 if (content == NULL) { 496 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, 497 "Found NULL content in content model of %s\n", 498 name, NULL, NULL); 499 return(0); 500 } 501 switch (content->type) { 502 case XML_ELEMENT_CONTENT_PCDATA: 503 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, 504 "Found PCDATA in content model of %s\n", 505 name, NULL, NULL); 506 return(0); 507 break; 508 case XML_ELEMENT_CONTENT_ELEMENT: { 509 xmlAutomataStatePtr oldstate = ctxt->state; 510 xmlChar fn[50]; 511 xmlChar *fullname; 512 513 fullname = xmlBuildQName(content->name, content->prefix, fn, 50); 514 if (fullname == NULL) { 515 xmlVErrMemory(ctxt, "Building content model"); 516 return(0); 517 } 518 519 switch (content->ocur) { 520 case XML_ELEMENT_CONTENT_ONCE: 521 ctxt->state = xmlAutomataNewTransition(ctxt->am, 522 ctxt->state, NULL, fullname, NULL); 523 break; 524 case XML_ELEMENT_CONTENT_OPT: 525 ctxt->state = xmlAutomataNewTransition(ctxt->am, 526 ctxt->state, NULL, fullname, NULL); 527 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 528 break; 529 case XML_ELEMENT_CONTENT_PLUS: 530 ctxt->state = xmlAutomataNewTransition(ctxt->am, 531 ctxt->state, NULL, fullname, NULL); 532 xmlAutomataNewTransition(ctxt->am, ctxt->state, 533 ctxt->state, fullname, NULL); 534 break; 535 case XML_ELEMENT_CONTENT_MULT: 536 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, 537 ctxt->state, NULL); 538 xmlAutomataNewTransition(ctxt->am, 539 ctxt->state, ctxt->state, fullname, NULL); 540 break; 541 } 542 if ((fullname != fn) && (fullname != content->name)) 543 xmlFree(fullname); 544 break; 545 } 546 case XML_ELEMENT_CONTENT_SEQ: { 547 xmlAutomataStatePtr oldstate, oldend; 548 xmlElementContentOccur ocur; 549 550 /* 551 * Simply iterate over the content 552 */ 553 oldstate = ctxt->state; 554 ocur = content->ocur; 555 if (ocur != XML_ELEMENT_CONTENT_ONCE) { 556 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 557 oldstate = ctxt->state; 558 } 559 do { 560 xmlValidBuildAContentModel(content->c1, ctxt, name); 561 content = content->c2; 562 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && 563 (content->ocur == XML_ELEMENT_CONTENT_ONCE)); 564 xmlValidBuildAContentModel(content, ctxt, name); 565 oldend = ctxt->state; 566 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); 567 switch (ocur) { 568 case XML_ELEMENT_CONTENT_ONCE: 569 break; 570 case XML_ELEMENT_CONTENT_OPT: 571 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 572 break; 573 case XML_ELEMENT_CONTENT_MULT: 574 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 575 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 576 break; 577 case XML_ELEMENT_CONTENT_PLUS: 578 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 579 break; 580 } 581 break; 582 } 583 case XML_ELEMENT_CONTENT_OR: { 584 xmlAutomataStatePtr oldstate, oldend; 585 xmlElementContentOccur ocur; 586 587 ocur = content->ocur; 588 if ((ocur == XML_ELEMENT_CONTENT_PLUS) || 589 (ocur == XML_ELEMENT_CONTENT_MULT)) { 590 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, 591 ctxt->state, NULL); 592 } 593 oldstate = ctxt->state; 594 oldend = xmlAutomataNewState(ctxt->am); 595 596 /* 597 * iterate over the subtypes and remerge the end with an 598 * epsilon transition 599 */ 600 do { 601 ctxt->state = oldstate; 602 xmlValidBuildAContentModel(content->c1, ctxt, name); 603 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); 604 content = content->c2; 605 } while ((content->type == XML_ELEMENT_CONTENT_OR) && 606 (content->ocur == XML_ELEMENT_CONTENT_ONCE)); 607 ctxt->state = oldstate; 608 xmlValidBuildAContentModel(content, ctxt, name); 609 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); 610 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); 611 switch (ocur) { 612 case XML_ELEMENT_CONTENT_ONCE: 613 break; 614 case XML_ELEMENT_CONTENT_OPT: 615 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 616 break; 617 case XML_ELEMENT_CONTENT_MULT: 618 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 619 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 620 break; 621 case XML_ELEMENT_CONTENT_PLUS: 622 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 623 break; 624 } 625 break; 626 } 627 default: 628 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 629 "ContentModel broken for element %s\n", 630 (const char *) name); 631 return(0); 632 } 633 return(1); 634} 635/** 636 * xmlValidBuildContentModel: 637 * @ctxt: a validation context 638 * @elem: an element declaration node 639 * 640 * (Re)Build the automata associated to the content model of this 641 * element 642 * 643 * Returns 1 in case of success, 0 in case of error 644 */ 645int 646xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { 647 648 if ((ctxt == NULL) || (elem == NULL)) 649 return(0); 650 if (elem->type != XML_ELEMENT_DECL) 651 return(0); 652 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT) 653 return(1); 654 /* TODO: should we rebuild in this case ? */ 655 if (elem->contModel != NULL) { 656 if (!xmlRegexpIsDeterminist(elem->contModel)) { 657 ctxt->valid = 0; 658 return(0); 659 } 660 return(1); 661 } 662 663 ctxt->am = xmlNewAutomata(); 664 if (ctxt->am == NULL) { 665 xmlErrValidNode(ctxt, (xmlNodePtr) elem, 666 XML_ERR_INTERNAL_ERROR, 667 "Cannot create automata for element %s\n", 668 elem->name, NULL, NULL); 669 return(0); 670 } 671 ctxt->state = xmlAutomataGetInitState(ctxt->am); 672 xmlValidBuildAContentModel(elem->content, ctxt, elem->name); 673 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 674 elem->contModel = xmlAutomataCompile(ctxt->am); 675 if (xmlRegexpIsDeterminist(elem->contModel) != 1) { 676 char expr[5000]; 677 expr[0] = 0; 678 xmlSnprintfElementContent(expr, 5000, elem->content, 1); 679 xmlErrValidNode(ctxt, (xmlNodePtr) elem, 680 XML_DTD_CONTENT_NOT_DETERMINIST, 681 "Content model of %s is not deterministic: %s\n", 682 elem->name, BAD_CAST expr, NULL); 683 ctxt->valid = 0; 684 ctxt->state = NULL; 685 xmlFreeAutomata(ctxt->am); 686 ctxt->am = NULL; 687 return(0); 688 } 689 ctxt->state = NULL; 690 xmlFreeAutomata(ctxt->am); 691 ctxt->am = NULL; 692 return(1); 693} 694 695#endif /* LIBXML_REGEXP_ENABLED */ 696 697/**************************************************************** 698 * * 699 * Util functions for data allocation/deallocation * 700 * * 701 ****************************************************************/ 702 703/** 704 * xmlNewValidCtxt: 705 * 706 * Allocate a validation context structure. 707 * 708 * Returns NULL if not, otherwise the new validation context structure 709 */ 710xmlValidCtxtPtr xmlNewValidCtxt(void) { 711 xmlValidCtxtPtr ret; 712 713 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { 714 xmlVErrMemory(NULL, "malloc failed"); 715 return (NULL); 716 } 717 718 (void) memset(ret, 0, sizeof (xmlValidCtxt)); 719 720 return (ret); 721} 722 723/** 724 * xmlFreeValidCtxt: 725 * @cur: the validation context to free 726 * 727 * Free a validation context structure. 728 */ 729void 730xmlFreeValidCtxt(xmlValidCtxtPtr cur) { 731 if (cur == NULL) 732 return; 733 if (cur->vstateTab != NULL) 734 xmlFree(cur->vstateTab); 735 if (cur->nodeTab != NULL) 736 xmlFree(cur->nodeTab); 737 xmlFree(cur); 738} 739 740#endif /* LIBXML_VALID_ENABLED */ 741 742/** 743 * xmlNewDocElementContent: 744 * @doc: the document 745 * @name: the subelement name or NULL 746 * @type: the type of element content decl 747 * 748 * Allocate an element content structure for the document. 749 * 750 * Returns NULL if not, otherwise the new element content structure 751 */ 752xmlElementContentPtr 753xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, 754 xmlElementContentType type) { 755 xmlElementContentPtr ret; 756 xmlDictPtr dict = NULL; 757 758 if (doc != NULL) 759 dict = doc->dict; 760 761 switch(type) { 762 case XML_ELEMENT_CONTENT_ELEMENT: 763 if (name == NULL) { 764 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 765 "xmlNewElementContent : name == NULL !\n", 766 NULL); 767 } 768 break; 769 case XML_ELEMENT_CONTENT_PCDATA: 770 case XML_ELEMENT_CONTENT_SEQ: 771 case XML_ELEMENT_CONTENT_OR: 772 if (name != NULL) { 773 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 774 "xmlNewElementContent : name != NULL !\n", 775 NULL); 776 } 777 break; 778 default: 779 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 780 "Internal: ELEMENT content corrupted invalid type\n", 781 NULL); 782 return(NULL); 783 } 784 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 785 if (ret == NULL) { 786 xmlVErrMemory(NULL, "malloc failed"); 787 return(NULL); 788 } 789 memset(ret, 0, sizeof(xmlElementContent)); 790 ret->type = type; 791 ret->ocur = XML_ELEMENT_CONTENT_ONCE; 792 if (name != NULL) { 793 int l; 794 const xmlChar *tmp; 795 796 tmp = xmlSplitQName3(name, &l); 797 if (tmp == NULL) { 798 if (dict == NULL) 799 ret->name = xmlStrdup(name); 800 else 801 ret->name = xmlDictLookup(dict, name, -1); 802 } else { 803 if (dict == NULL) { 804 ret->prefix = xmlStrndup(name, l); 805 ret->name = xmlStrdup(tmp); 806 } else { 807 ret->prefix = xmlDictLookup(dict, name, l); 808 ret->name = xmlDictLookup(dict, tmp, -1); 809 } 810 } 811 } 812 return(ret); 813} 814 815/** 816 * xmlNewElementContent: 817 * @name: the subelement name or NULL 818 * @type: the type of element content decl 819 * 820 * Allocate an element content structure. 821 * Deprecated in favor of xmlNewDocElementContent 822 * 823 * Returns NULL if not, otherwise the new element content structure 824 */ 825xmlElementContentPtr 826xmlNewElementContent(const xmlChar *name, xmlElementContentType type) { 827 return(xmlNewDocElementContent(NULL, name, type)); 828} 829 830/** 831 * xmlCopyDocElementContent: 832 * @doc: the document owning the element declaration 833 * @cur: An element content pointer. 834 * 835 * Build a copy of an element content description. 836 * 837 * Returns the new xmlElementContentPtr or NULL in case of error. 838 */ 839xmlElementContentPtr 840xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { 841 xmlElementContentPtr ret = NULL, prev = NULL, tmp; 842 xmlDictPtr dict = NULL; 843 844 if (cur == NULL) return(NULL); 845 846 if (doc != NULL) 847 dict = doc->dict; 848 849 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 850 if (ret == NULL) { 851 xmlVErrMemory(NULL, "malloc failed"); 852 return(NULL); 853 } 854 memset(ret, 0, sizeof(xmlElementContent)); 855 ret->type = cur->type; 856 ret->ocur = cur->ocur; 857 if (cur->name != NULL) { 858 if (dict) 859 ret->name = xmlDictLookup(dict, cur->name, -1); 860 else 861 ret->name = xmlStrdup(cur->name); 862 } 863 864 if (cur->prefix != NULL) { 865 if (dict) 866 ret->prefix = xmlDictLookup(dict, cur->prefix, -1); 867 else 868 ret->prefix = xmlStrdup(cur->prefix); 869 } 870 if (cur->c1 != NULL) 871 ret->c1 = xmlCopyDocElementContent(doc, cur->c1); 872 if (ret->c1 != NULL) 873 ret->c1->parent = ret; 874 if (cur->c2 != NULL) { 875 prev = ret; 876 cur = cur->c2; 877 while (cur != NULL) { 878 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 879 if (tmp == NULL) { 880 xmlVErrMemory(NULL, "malloc failed"); 881 return(ret); 882 } 883 memset(tmp, 0, sizeof(xmlElementContent)); 884 tmp->type = cur->type; 885 tmp->ocur = cur->ocur; 886 prev->c2 = tmp; 887 tmp->parent = prev; 888 if (cur->name != NULL) { 889 if (dict) 890 tmp->name = xmlDictLookup(dict, cur->name, -1); 891 else 892 tmp->name = xmlStrdup(cur->name); 893 } 894 895 if (cur->prefix != NULL) { 896 if (dict) 897 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); 898 else 899 tmp->prefix = xmlStrdup(cur->prefix); 900 } 901 if (cur->c1 != NULL) 902 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); 903 if (tmp->c1 != NULL) 904 tmp->c1->parent = tmp; 905 prev = tmp; 906 cur = cur->c2; 907 } 908 } 909 return(ret); 910} 911 912/** 913 * xmlCopyElementContent: 914 * @cur: An element content pointer. 915 * 916 * Build a copy of an element content description. 917 * Deprecated, use xmlCopyDocElementContent instead 918 * 919 * Returns the new xmlElementContentPtr or NULL in case of error. 920 */ 921xmlElementContentPtr 922xmlCopyElementContent(xmlElementContentPtr cur) { 923 return(xmlCopyDocElementContent(NULL, cur)); 924} 925 926/** 927 * xmlFreeDocElementContent: 928 * @doc: the document owning the element declaration 929 * @cur: the element content tree to free 930 * 931 * Free an element content structure. The whole subtree is removed. 932 */ 933void 934xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { 935 xmlDictPtr dict = NULL; 936 size_t depth = 0; 937 938 if (cur == NULL) 939 return; 940 if (doc != NULL) 941 dict = doc->dict; 942 943 while (1) { 944 xmlElementContentPtr parent; 945 946 while ((cur->c1 != NULL) || (cur->c2 != NULL)) { 947 cur = (cur->c1 != NULL) ? cur->c1 : cur->c2; 948 depth += 1; 949 } 950 951 switch (cur->type) { 952 case XML_ELEMENT_CONTENT_PCDATA: 953 case XML_ELEMENT_CONTENT_ELEMENT: 954 case XML_ELEMENT_CONTENT_SEQ: 955 case XML_ELEMENT_CONTENT_OR: 956 break; 957 default: 958 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 959 "Internal: ELEMENT content corrupted invalid type\n", 960 NULL); 961 return; 962 } 963 if (dict) { 964 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) 965 xmlFree((xmlChar *) cur->name); 966 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix))) 967 xmlFree((xmlChar *) cur->prefix); 968 } else { 969 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 970 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix); 971 } 972 parent = cur->parent; 973 if ((depth == 0) || (parent == NULL)) { 974 xmlFree(cur); 975 break; 976 } 977 if (cur == parent->c1) 978 parent->c1 = NULL; 979 else 980 parent->c2 = NULL; 981 xmlFree(cur); 982 983 if (parent->c2 != NULL) { 984 cur = parent->c2; 985 } else { 986 depth -= 1; 987 cur = parent; 988 } 989 } 990} 991 992/** 993 * xmlFreeElementContent: 994 * @cur: the element content tree to free 995 * 996 * Free an element content structure. The whole subtree is removed. 997 * Deprecated, use xmlFreeDocElementContent instead 998 */ 999void 1000xmlFreeElementContent(xmlElementContentPtr cur) { 1001 xmlFreeDocElementContent(NULL, cur); 1002} 1003 1004#ifdef LIBXML_OUTPUT_ENABLED 1005/** 1006 * xmlDumpElementOccur: 1007 * @buf: An XML buffer 1008 * @cur: An element table 1009 * 1010 * Dump the occurrence operator of an element. 1011 */ 1012static void 1013xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) { 1014 switch (cur->ocur) { 1015 case XML_ELEMENT_CONTENT_ONCE: 1016 break; 1017 case XML_ELEMENT_CONTENT_OPT: 1018 xmlBufferWriteChar(buf, "?"); 1019 break; 1020 case XML_ELEMENT_CONTENT_MULT: 1021 xmlBufferWriteChar(buf, "*"); 1022 break; 1023 case XML_ELEMENT_CONTENT_PLUS: 1024 xmlBufferWriteChar(buf, "+"); 1025 break; 1026 } 1027} 1028 1029/** 1030 * xmlDumpElementContent: 1031 * @buf: An XML buffer 1032 * @content: An element table 1033 * 1034 * This will dump the content of the element table as an XML DTD definition 1035 */ 1036static void 1037xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) { 1038 xmlElementContentPtr cur; 1039 1040 if (content == NULL) return; 1041 1042 xmlBufferWriteChar(buf, "("); 1043 cur = content; 1044 1045 do { 1046 if (cur == NULL) return; 1047 1048 switch (cur->type) { 1049 case XML_ELEMENT_CONTENT_PCDATA: 1050 xmlBufferWriteChar(buf, "#PCDATA"); 1051 break; 1052 case XML_ELEMENT_CONTENT_ELEMENT: 1053 if (cur->prefix != NULL) { 1054 xmlBufferWriteCHAR(buf, cur->prefix); 1055 xmlBufferWriteChar(buf, ":"); 1056 } 1057 xmlBufferWriteCHAR(buf, cur->name); 1058 break; 1059 case XML_ELEMENT_CONTENT_SEQ: 1060 case XML_ELEMENT_CONTENT_OR: 1061 if ((cur != content) && 1062 (cur->parent != NULL) && 1063 ((cur->type != cur->parent->type) || 1064 (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) 1065 xmlBufferWriteChar(buf, "("); 1066 cur = cur->c1; 1067 continue; 1068 default: 1069 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 1070 "Internal: ELEMENT cur corrupted invalid type\n", 1071 NULL); 1072 } 1073 1074 while (cur != content) { 1075 xmlElementContentPtr parent = cur->parent; 1076 1077 if (parent == NULL) return; 1078 1079 if (((cur->type == XML_ELEMENT_CONTENT_OR) || 1080 (cur->type == XML_ELEMENT_CONTENT_SEQ)) && 1081 ((cur->type != parent->type) || 1082 (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) 1083 xmlBufferWriteChar(buf, ")"); 1084 xmlDumpElementOccur(buf, cur); 1085 1086 if (cur == parent->c1) { 1087 if (parent->type == XML_ELEMENT_CONTENT_SEQ) 1088 xmlBufferWriteChar(buf, " , "); 1089 else if (parent->type == XML_ELEMENT_CONTENT_OR) 1090 xmlBufferWriteChar(buf, " | "); 1091 1092 cur = parent->c2; 1093 break; 1094 } 1095 1096 cur = parent; 1097 } 1098 } while (cur != content); 1099 1100 xmlBufferWriteChar(buf, ")"); 1101 xmlDumpElementOccur(buf, content); 1102} 1103 1104/** 1105 * xmlSprintfElementContent: 1106 * @buf: an output buffer 1107 * @content: An element table 1108 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise 1109 * 1110 * Deprecated, unsafe, use xmlSnprintfElementContent 1111 */ 1112void 1113xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED, 1114 xmlElementContentPtr content ATTRIBUTE_UNUSED, 1115 int englob ATTRIBUTE_UNUSED) { 1116} 1117#endif /* LIBXML_OUTPUT_ENABLED */ 1118 1119/** 1120 * xmlSnprintfElementContent: 1121 * @buf: an output buffer 1122 * @size: the buffer size 1123 * @content: An element table 1124 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise 1125 * 1126 * This will dump the content of the element content definition 1127 * Intended just for the debug routine 1128 */ 1129void 1130xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) { 1131 int len; 1132 1133 if (content == NULL) return; 1134 len = strlen(buf); 1135 if (size - len < 50) { 1136 if ((size - len > 4) && (buf[len - 1] != '.')) 1137 strcat(buf, " ..."); 1138 return; 1139 } 1140 if (englob) strcat(buf, "("); 1141 switch (content->type) { 1142 case XML_ELEMENT_CONTENT_PCDATA: 1143 strcat(buf, "#PCDATA"); 1144 break; 1145 case XML_ELEMENT_CONTENT_ELEMENT: { 1146 int qnameLen = xmlStrlen(content->name); 1147 1148 if (content->prefix != NULL) 1149 qnameLen += xmlStrlen(content->prefix) + 1; 1150 if (size - len < qnameLen + 10) { 1151 strcat(buf, " ..."); 1152 return; 1153 } 1154 if (content->prefix != NULL) { 1155 strcat(buf, (char *) content->prefix); 1156 strcat(buf, ":"); 1157 } 1158 if (content->name != NULL) 1159 strcat(buf, (char *) content->name); 1160 break; 1161 } 1162 case XML_ELEMENT_CONTENT_SEQ: 1163 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 1164 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 1165 xmlSnprintfElementContent(buf, size, content->c1, 1); 1166 else 1167 xmlSnprintfElementContent(buf, size, content->c1, 0); 1168 len = strlen(buf); 1169 if (size - len < 50) { 1170 if ((size - len > 4) && (buf[len - 1] != '.')) 1171 strcat(buf, " ..."); 1172 return; 1173 } 1174 strcat(buf, " , "); 1175 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) || 1176 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && 1177 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) 1178 xmlSnprintfElementContent(buf, size, content->c2, 1); 1179 else 1180 xmlSnprintfElementContent(buf, size, content->c2, 0); 1181 break; 1182 case XML_ELEMENT_CONTENT_OR: 1183 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 1184 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 1185 xmlSnprintfElementContent(buf, size, content->c1, 1); 1186 else 1187 xmlSnprintfElementContent(buf, size, content->c1, 0); 1188 len = strlen(buf); 1189 if (size - len < 50) { 1190 if ((size - len > 4) && (buf[len - 1] != '.')) 1191 strcat(buf, " ..."); 1192 return; 1193 } 1194 strcat(buf, " | "); 1195 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || 1196 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && 1197 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) 1198 xmlSnprintfElementContent(buf, size, content->c2, 1); 1199 else 1200 xmlSnprintfElementContent(buf, size, content->c2, 0); 1201 break; 1202 } 1203 if (size - strlen(buf) <= 2) return; 1204 if (englob) 1205 strcat(buf, ")"); 1206 switch (content->ocur) { 1207 case XML_ELEMENT_CONTENT_ONCE: 1208 break; 1209 case XML_ELEMENT_CONTENT_OPT: 1210 strcat(buf, "?"); 1211 break; 1212 case XML_ELEMENT_CONTENT_MULT: 1213 strcat(buf, "*"); 1214 break; 1215 case XML_ELEMENT_CONTENT_PLUS: 1216 strcat(buf, "+"); 1217 break; 1218 } 1219} 1220 1221/**************************************************************** 1222 * * 1223 * Registration of DTD declarations * 1224 * * 1225 ****************************************************************/ 1226 1227/** 1228 * xmlFreeElement: 1229 * @elem: An element 1230 * 1231 * Deallocate the memory used by an element definition 1232 */ 1233static void 1234xmlFreeElement(xmlElementPtr elem) { 1235 if (elem == NULL) return; 1236 xmlUnlinkNode((xmlNodePtr) elem); 1237 xmlFreeDocElementContent(elem->doc, elem->content); 1238 if (elem->name != NULL) 1239 xmlFree((xmlChar *) elem->name); 1240 if (elem->prefix != NULL) 1241 xmlFree((xmlChar *) elem->prefix); 1242#ifdef LIBXML_REGEXP_ENABLED 1243 if (elem->contModel != NULL) 1244 xmlRegFreeRegexp(elem->contModel); 1245#endif 1246 xmlFree(elem); 1247} 1248 1249 1250/** 1251 * xmlAddElementDecl: 1252 * @ctxt: the validation context 1253 * @dtd: pointer to the DTD 1254 * @name: the entity name 1255 * @type: the element type 1256 * @content: the element content tree or NULL 1257 * 1258 * Register a new element declaration 1259 * 1260 * Returns NULL if not, otherwise the entity 1261 */ 1262xmlElementPtr 1263xmlAddElementDecl(xmlValidCtxtPtr ctxt, 1264 xmlDtdPtr dtd, const xmlChar *name, 1265 xmlElementTypeVal type, 1266 xmlElementContentPtr content) { 1267 xmlElementPtr ret; 1268 xmlElementTablePtr table; 1269 xmlAttributePtr oldAttributes = NULL; 1270 xmlChar *ns, *uqname; 1271 1272 if (dtd == NULL) { 1273 return(NULL); 1274 } 1275 if (name == NULL) { 1276 return(NULL); 1277 } 1278 1279 switch (type) { 1280 case XML_ELEMENT_TYPE_EMPTY: 1281 if (content != NULL) { 1282 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1283 "xmlAddElementDecl: content != NULL for EMPTY\n", 1284 NULL); 1285 return(NULL); 1286 } 1287 break; 1288 case XML_ELEMENT_TYPE_ANY: 1289 if (content != NULL) { 1290 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1291 "xmlAddElementDecl: content != NULL for ANY\n", 1292 NULL); 1293 return(NULL); 1294 } 1295 break; 1296 case XML_ELEMENT_TYPE_MIXED: 1297 if (content == NULL) { 1298 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1299 "xmlAddElementDecl: content == NULL for MIXED\n", 1300 NULL); 1301 return(NULL); 1302 } 1303 break; 1304 case XML_ELEMENT_TYPE_ELEMENT: 1305 if (content == NULL) { 1306 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1307 "xmlAddElementDecl: content == NULL for ELEMENT\n", 1308 NULL); 1309 return(NULL); 1310 } 1311 break; 1312 default: 1313 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1314 "Internal: ELEMENT decl corrupted invalid type\n", 1315 NULL); 1316 return(NULL); 1317 } 1318 1319 /* 1320 * check if name is a QName 1321 */ 1322 uqname = xmlSplitQName2(name, &ns); 1323 if (uqname != NULL) 1324 name = uqname; 1325 1326 /* 1327 * Create the Element table if needed. 1328 */ 1329 table = (xmlElementTablePtr) dtd->elements; 1330 if (table == NULL) { 1331 xmlDictPtr dict = NULL; 1332 1333 if (dtd->doc != NULL) 1334 dict = dtd->doc->dict; 1335 table = xmlHashCreateDict(0, dict); 1336 dtd->elements = (void *) table; 1337 } 1338 if (table == NULL) { 1339 xmlVErrMemory(ctxt, 1340 "xmlAddElementDecl: Table creation failed!\n"); 1341 if (uqname != NULL) 1342 xmlFree(uqname); 1343 if (ns != NULL) 1344 xmlFree(ns); 1345 return(NULL); 1346 } 1347 1348 /* 1349 * lookup old attributes inserted on an undefined element in the 1350 * internal subset. 1351 */ 1352 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) { 1353 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns); 1354 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { 1355 oldAttributes = ret->attributes; 1356 ret->attributes = NULL; 1357 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); 1358 xmlFreeElement(ret); 1359 } 1360 } 1361 1362 /* 1363 * The element may already be present if one of its attribute 1364 * was registered first 1365 */ 1366 ret = xmlHashLookup2(table, name, ns); 1367 if (ret != NULL) { 1368 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) { 1369#ifdef LIBXML_VALID_ENABLED 1370 /* 1371 * The element is already defined in this DTD. 1372 */ 1373 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, 1374 "Redefinition of element %s\n", 1375 name, NULL, NULL); 1376#endif /* LIBXML_VALID_ENABLED */ 1377 if (uqname != NULL) 1378 xmlFree(uqname); 1379 if (ns != NULL) 1380 xmlFree(ns); 1381 return(NULL); 1382 } 1383 if (ns != NULL) { 1384 xmlFree(ns); 1385 ns = NULL; 1386 } 1387 } else { 1388 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 1389 if (ret == NULL) { 1390 xmlVErrMemory(ctxt, "malloc failed"); 1391 if (uqname != NULL) 1392 xmlFree(uqname); 1393 if (ns != NULL) 1394 xmlFree(ns); 1395 return(NULL); 1396 } 1397 memset(ret, 0, sizeof(xmlElement)); 1398 ret->type = XML_ELEMENT_DECL; 1399 1400 /* 1401 * fill the structure. 1402 */ 1403 ret->name = xmlStrdup(name); 1404 if (ret->name == NULL) { 1405 xmlVErrMemory(ctxt, "malloc failed"); 1406 if (uqname != NULL) 1407 xmlFree(uqname); 1408 if (ns != NULL) 1409 xmlFree(ns); 1410 xmlFree(ret); 1411 return(NULL); 1412 } 1413 ret->prefix = ns; 1414 1415 /* 1416 * Validity Check: 1417 * Insertion must not fail 1418 */ 1419 if (xmlHashAddEntry2(table, name, ns, ret)) { 1420#ifdef LIBXML_VALID_ENABLED 1421 /* 1422 * The element is already defined in this DTD. 1423 */ 1424 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, 1425 "Redefinition of element %s\n", 1426 name, NULL, NULL); 1427#endif /* LIBXML_VALID_ENABLED */ 1428 xmlFreeElement(ret); 1429 if (uqname != NULL) 1430 xmlFree(uqname); 1431 return(NULL); 1432 } 1433 /* 1434 * For new element, may have attributes from earlier 1435 * definition in internal subset 1436 */ 1437 ret->attributes = oldAttributes; 1438 } 1439 1440 /* 1441 * Finish to fill the structure. 1442 */ 1443 ret->etype = type; 1444 /* 1445 * Avoid a stupid copy when called by the parser 1446 * and flag it by setting a special parent value 1447 * so the parser doesn't unallocate it. 1448 */ 1449 if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { 1450 ret->content = content; 1451 if (content != NULL) 1452 content->parent = (xmlElementContentPtr) 1; 1453 } else { 1454 ret->content = xmlCopyDocElementContent(dtd->doc, content); 1455 } 1456 1457 /* 1458 * Link it to the DTD 1459 */ 1460 ret->parent = dtd; 1461 ret->doc = dtd->doc; 1462 if (dtd->last == NULL) { 1463 dtd->children = dtd->last = (xmlNodePtr) ret; 1464 } else { 1465 dtd->last->next = (xmlNodePtr) ret; 1466 ret->prev = dtd->last; 1467 dtd->last = (xmlNodePtr) ret; 1468 } 1469 if (uqname != NULL) 1470 xmlFree(uqname); 1471 return(ret); 1472} 1473 1474static void 1475xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) { 1476 xmlFreeElement((xmlElementPtr) elem); 1477} 1478 1479/** 1480 * xmlFreeElementTable: 1481 * @table: An element table 1482 * 1483 * Deallocate the memory used by an element hash table. 1484 */ 1485void 1486xmlFreeElementTable(xmlElementTablePtr table) { 1487 xmlHashFree(table, xmlFreeElementTableEntry); 1488} 1489 1490#ifdef LIBXML_TREE_ENABLED 1491/** 1492 * xmlCopyElement: 1493 * @elem: An element 1494 * 1495 * Build a copy of an element. 1496 * 1497 * Returns the new xmlElementPtr or NULL in case of error. 1498 */ 1499static void * 1500xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { 1501 xmlElementPtr elem = (xmlElementPtr) payload; 1502 xmlElementPtr cur; 1503 1504 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 1505 if (cur == NULL) { 1506 xmlVErrMemory(NULL, "malloc failed"); 1507 return(NULL); 1508 } 1509 memset(cur, 0, sizeof(xmlElement)); 1510 cur->type = XML_ELEMENT_DECL; 1511 cur->etype = elem->etype; 1512 if (elem->name != NULL) 1513 cur->name = xmlStrdup(elem->name); 1514 else 1515 cur->name = NULL; 1516 if (elem->prefix != NULL) 1517 cur->prefix = xmlStrdup(elem->prefix); 1518 else 1519 cur->prefix = NULL; 1520 cur->content = xmlCopyElementContent(elem->content); 1521 /* TODO : rebuild the attribute list on the copy */ 1522 cur->attributes = NULL; 1523 return(cur); 1524} 1525 1526/** 1527 * xmlCopyElementTable: 1528 * @table: An element table 1529 * 1530 * Build a copy of an element table. 1531 * 1532 * Returns the new xmlElementTablePtr or NULL in case of error. 1533 */ 1534xmlElementTablePtr 1535xmlCopyElementTable(xmlElementTablePtr table) { 1536 return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement)); 1537} 1538#endif /* LIBXML_TREE_ENABLED */ 1539 1540#ifdef LIBXML_OUTPUT_ENABLED 1541/** 1542 * xmlDumpElementDecl: 1543 * @buf: the XML buffer output 1544 * @elem: An element table 1545 * 1546 * This will dump the content of the element declaration as an XML 1547 * DTD definition 1548 */ 1549void 1550xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { 1551 if ((buf == NULL) || (elem == NULL)) 1552 return; 1553 switch (elem->etype) { 1554 case XML_ELEMENT_TYPE_EMPTY: 1555 xmlBufferWriteChar(buf, "<!ELEMENT "); 1556 if (elem->prefix != NULL) { 1557 xmlBufferWriteCHAR(buf, elem->prefix); 1558 xmlBufferWriteChar(buf, ":"); 1559 } 1560 xmlBufferWriteCHAR(buf, elem->name); 1561 xmlBufferWriteChar(buf, " EMPTY>\n"); 1562 break; 1563 case XML_ELEMENT_TYPE_ANY: 1564 xmlBufferWriteChar(buf, "<!ELEMENT "); 1565 if (elem->prefix != NULL) { 1566 xmlBufferWriteCHAR(buf, elem->prefix); 1567 xmlBufferWriteChar(buf, ":"); 1568 } 1569 xmlBufferWriteCHAR(buf, elem->name); 1570 xmlBufferWriteChar(buf, " ANY>\n"); 1571 break; 1572 case XML_ELEMENT_TYPE_MIXED: 1573 xmlBufferWriteChar(buf, "<!ELEMENT "); 1574 if (elem->prefix != NULL) { 1575 xmlBufferWriteCHAR(buf, elem->prefix); 1576 xmlBufferWriteChar(buf, ":"); 1577 } 1578 xmlBufferWriteCHAR(buf, elem->name); 1579 xmlBufferWriteChar(buf, " "); 1580 xmlDumpElementContent(buf, elem->content); 1581 xmlBufferWriteChar(buf, ">\n"); 1582 break; 1583 case XML_ELEMENT_TYPE_ELEMENT: 1584 xmlBufferWriteChar(buf, "<!ELEMENT "); 1585 if (elem->prefix != NULL) { 1586 xmlBufferWriteCHAR(buf, elem->prefix); 1587 xmlBufferWriteChar(buf, ":"); 1588 } 1589 xmlBufferWriteCHAR(buf, elem->name); 1590 xmlBufferWriteChar(buf, " "); 1591 xmlDumpElementContent(buf, elem->content); 1592 xmlBufferWriteChar(buf, ">\n"); 1593 break; 1594 default: 1595 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 1596 "Internal: ELEMENT struct corrupted invalid type\n", 1597 NULL); 1598 } 1599} 1600 1601/** 1602 * xmlDumpElementDeclScan: 1603 * @elem: An element table 1604 * @buf: the XML buffer output 1605 * 1606 * This routine is used by the hash scan function. It just reverses 1607 * the arguments. 1608 */ 1609static void 1610xmlDumpElementDeclScan(void *elem, void *buf, 1611 const xmlChar *name ATTRIBUTE_UNUSED) { 1612 xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem); 1613} 1614 1615/** 1616 * xmlDumpElementTable: 1617 * @buf: the XML buffer output 1618 * @table: An element table 1619 * 1620 * This will dump the content of the element table as an XML DTD definition 1621 */ 1622void 1623xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { 1624 if ((buf == NULL) || (table == NULL)) 1625 return; 1626 xmlHashScan(table, xmlDumpElementDeclScan, buf); 1627} 1628#endif /* LIBXML_OUTPUT_ENABLED */ 1629 1630/** 1631 * xmlCreateEnumeration: 1632 * @name: the enumeration name or NULL 1633 * 1634 * create and initialize an enumeration attribute node. 1635 * 1636 * Returns the xmlEnumerationPtr just created or NULL in case 1637 * of error. 1638 */ 1639xmlEnumerationPtr 1640xmlCreateEnumeration(const xmlChar *name) { 1641 xmlEnumerationPtr ret; 1642 1643 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); 1644 if (ret == NULL) { 1645 xmlVErrMemory(NULL, "malloc failed"); 1646 return(NULL); 1647 } 1648 memset(ret, 0, sizeof(xmlEnumeration)); 1649 1650 if (name != NULL) 1651 ret->name = xmlStrdup(name); 1652 return(ret); 1653} 1654 1655/** 1656 * xmlFreeEnumeration: 1657 * @cur: the tree to free. 1658 * 1659 * free an enumeration attribute node (recursive). 1660 */ 1661void 1662xmlFreeEnumeration(xmlEnumerationPtr cur) { 1663 if (cur == NULL) return; 1664 1665 if (cur->next != NULL) xmlFreeEnumeration(cur->next); 1666 1667 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 1668 xmlFree(cur); 1669} 1670 1671#ifdef LIBXML_TREE_ENABLED 1672/** 1673 * xmlCopyEnumeration: 1674 * @cur: the tree to copy. 1675 * 1676 * Copy an enumeration attribute node (recursive). 1677 * 1678 * Returns the xmlEnumerationPtr just created or NULL in case 1679 * of error. 1680 */ 1681xmlEnumerationPtr 1682xmlCopyEnumeration(xmlEnumerationPtr cur) { 1683 xmlEnumerationPtr ret; 1684 1685 if (cur == NULL) return(NULL); 1686 ret = xmlCreateEnumeration((xmlChar *) cur->name); 1687 if (ret == NULL) return(NULL); 1688 1689 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); 1690 else ret->next = NULL; 1691 1692 return(ret); 1693} 1694#endif /* LIBXML_TREE_ENABLED */ 1695 1696#ifdef LIBXML_OUTPUT_ENABLED 1697/** 1698 * xmlDumpEnumeration: 1699 * @buf: the XML buffer output 1700 * @enum: An enumeration 1701 * 1702 * This will dump the content of the enumeration 1703 */ 1704static void 1705xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) { 1706 if ((buf == NULL) || (cur == NULL)) 1707 return; 1708 1709 xmlBufferWriteCHAR(buf, cur->name); 1710 if (cur->next == NULL) 1711 xmlBufferWriteChar(buf, ")"); 1712 else { 1713 xmlBufferWriteChar(buf, " | "); 1714 xmlDumpEnumeration(buf, cur->next); 1715 } 1716} 1717#endif /* LIBXML_OUTPUT_ENABLED */ 1718 1719#ifdef LIBXML_VALID_ENABLED 1720/** 1721 * xmlScanIDAttributeDecl: 1722 * @ctxt: the validation context 1723 * @elem: the element name 1724 * @err: whether to raise errors here 1725 * 1726 * Verify that the element don't have too many ID attributes 1727 * declared. 1728 * 1729 * Returns the number of ID attributes found. 1730 */ 1731static int 1732xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) { 1733 xmlAttributePtr cur; 1734 int ret = 0; 1735 1736 if (elem == NULL) return(0); 1737 cur = elem->attributes; 1738 while (cur != NULL) { 1739 if (cur->atype == XML_ATTRIBUTE_ID) { 1740 ret ++; 1741 if ((ret > 1) && (err)) 1742 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID, 1743 "Element %s has too many ID attributes defined : %s\n", 1744 elem->name, cur->name, NULL); 1745 } 1746 cur = cur->nexth; 1747 } 1748 return(ret); 1749} 1750#endif /* LIBXML_VALID_ENABLED */ 1751 1752/** 1753 * xmlFreeAttribute: 1754 * @elem: An attribute 1755 * 1756 * Deallocate the memory used by an attribute definition 1757 */ 1758static void 1759xmlFreeAttribute(xmlAttributePtr attr) { 1760 xmlDictPtr dict; 1761 1762 if (attr == NULL) return; 1763 if (attr->doc != NULL) 1764 dict = attr->doc->dict; 1765 else 1766 dict = NULL; 1767 xmlUnlinkNode((xmlNodePtr) attr); 1768 if (attr->tree != NULL) 1769 xmlFreeEnumeration(attr->tree); 1770 if (dict) { 1771 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem))) 1772 xmlFree((xmlChar *) attr->elem); 1773 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name))) 1774 xmlFree((xmlChar *) attr->name); 1775 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix))) 1776 xmlFree((xmlChar *) attr->prefix); 1777 if ((attr->defaultValue != NULL) && 1778 (!xmlDictOwns(dict, attr->defaultValue))) 1779 xmlFree((xmlChar *) attr->defaultValue); 1780 } else { 1781 if (attr->elem != NULL) 1782 xmlFree((xmlChar *) attr->elem); 1783 if (attr->name != NULL) 1784 xmlFree((xmlChar *) attr->name); 1785 if (attr->defaultValue != NULL) 1786 xmlFree((xmlChar *) attr->defaultValue); 1787 if (attr->prefix != NULL) 1788 xmlFree((xmlChar *) attr->prefix); 1789 } 1790 xmlFree(attr); 1791} 1792 1793 1794/** 1795 * xmlAddAttributeDecl: 1796 * @ctxt: the validation context 1797 * @dtd: pointer to the DTD 1798 * @elem: the element name 1799 * @name: the attribute name 1800 * @ns: the attribute namespace prefix 1801 * @type: the attribute type 1802 * @def: the attribute default type 1803 * @defaultValue: the attribute default value 1804 * @tree: if it's an enumeration, the associated list 1805 * 1806 * Register a new attribute declaration 1807 * Note that @tree becomes the ownership of the DTD 1808 * 1809 * Returns NULL if not new, otherwise the attribute decl 1810 */ 1811xmlAttributePtr 1812xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, 1813 xmlDtdPtr dtd, const xmlChar *elem, 1814 const xmlChar *name, const xmlChar *ns, 1815 xmlAttributeType type, xmlAttributeDefault def, 1816 const xmlChar *defaultValue, xmlEnumerationPtr tree) { 1817 xmlAttributePtr ret; 1818 xmlAttributeTablePtr table; 1819 xmlElementPtr elemDef; 1820 xmlDictPtr dict = NULL; 1821 1822 if (dtd == NULL) { 1823 xmlFreeEnumeration(tree); 1824 return(NULL); 1825 } 1826 if (name == NULL) { 1827 xmlFreeEnumeration(tree); 1828 return(NULL); 1829 } 1830 if (elem == NULL) { 1831 xmlFreeEnumeration(tree); 1832 return(NULL); 1833 } 1834 if (dtd->doc != NULL) 1835 dict = dtd->doc->dict; 1836 1837#ifdef LIBXML_VALID_ENABLED 1838 /* 1839 * Check the type and possibly the default value. 1840 */ 1841 switch (type) { 1842 case XML_ATTRIBUTE_CDATA: 1843 break; 1844 case XML_ATTRIBUTE_ID: 1845 break; 1846 case XML_ATTRIBUTE_IDREF: 1847 break; 1848 case XML_ATTRIBUTE_IDREFS: 1849 break; 1850 case XML_ATTRIBUTE_ENTITY: 1851 break; 1852 case XML_ATTRIBUTE_ENTITIES: 1853 break; 1854 case XML_ATTRIBUTE_NMTOKEN: 1855 break; 1856 case XML_ATTRIBUTE_NMTOKENS: 1857 break; 1858 case XML_ATTRIBUTE_ENUMERATION: 1859 break; 1860 case XML_ATTRIBUTE_NOTATION: 1861 break; 1862 default: 1863 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 1864 "Internal: ATTRIBUTE struct corrupted invalid type\n", 1865 NULL); 1866 xmlFreeEnumeration(tree); 1867 return(NULL); 1868 } 1869 if ((defaultValue != NULL) && 1870 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) { 1871 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT, 1872 "Attribute %s of %s: invalid default value\n", 1873 elem, name, defaultValue); 1874 defaultValue = NULL; 1875 if (ctxt != NULL) 1876 ctxt->valid = 0; 1877 } 1878#endif /* LIBXML_VALID_ENABLED */ 1879 1880 /* 1881 * Check first that an attribute defined in the external subset wasn't 1882 * already defined in the internal subset 1883 */ 1884 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) && 1885 (dtd->doc->intSubset != NULL) && 1886 (dtd->doc->intSubset->attributes != NULL)) { 1887 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem); 1888 if (ret != NULL) { 1889 xmlFreeEnumeration(tree); 1890 return(NULL); 1891 } 1892 } 1893 1894 /* 1895 * Create the Attribute table if needed. 1896 */ 1897 table = (xmlAttributeTablePtr) dtd->attributes; 1898 if (table == NULL) { 1899 table = xmlHashCreateDict(0, dict); 1900 dtd->attributes = (void *) table; 1901 } 1902 if (table == NULL) { 1903 xmlVErrMemory(ctxt, 1904 "xmlAddAttributeDecl: Table creation failed!\n"); 1905 xmlFreeEnumeration(tree); 1906 return(NULL); 1907 } 1908 1909 1910 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); 1911 if (ret == NULL) { 1912 xmlVErrMemory(ctxt, "malloc failed"); 1913 xmlFreeEnumeration(tree); 1914 return(NULL); 1915 } 1916 memset(ret, 0, sizeof(xmlAttribute)); 1917 ret->type = XML_ATTRIBUTE_DECL; 1918 1919 /* 1920 * fill the structure. 1921 */ 1922 ret->atype = type; 1923 /* 1924 * doc must be set before possible error causes call 1925 * to xmlFreeAttribute (because it's used to check on 1926 * dict use) 1927 */ 1928 ret->doc = dtd->doc; 1929 if (dict) { 1930 ret->name = xmlDictLookup(dict, name, -1); 1931 ret->prefix = xmlDictLookup(dict, ns, -1); 1932 ret->elem = xmlDictLookup(dict, elem, -1); 1933 } else { 1934 ret->name = xmlStrdup(name); 1935 ret->prefix = xmlStrdup(ns); 1936 ret->elem = xmlStrdup(elem); 1937 } 1938 ret->def = def; 1939 ret->tree = tree; 1940 if (defaultValue != NULL) { 1941 if (dict) 1942 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); 1943 else 1944 ret->defaultValue = xmlStrdup(defaultValue); 1945 } 1946 1947 /* 1948 * Validity Check: 1949 * Search the DTD for previous declarations of the ATTLIST 1950 */ 1951 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) { 1952#ifdef LIBXML_VALID_ENABLED 1953 /* 1954 * The attribute is already defined in this DTD. 1955 */ 1956 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED, 1957 "Attribute %s of element %s: already defined\n", 1958 name, elem, NULL); 1959#endif /* LIBXML_VALID_ENABLED */ 1960 xmlFreeAttribute(ret); 1961 return(NULL); 1962 } 1963 1964 /* 1965 * Validity Check: 1966 * Multiple ID per element 1967 */ 1968 elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1); 1969 if (elemDef != NULL) { 1970 1971#ifdef LIBXML_VALID_ENABLED 1972 if ((type == XML_ATTRIBUTE_ID) && 1973 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) { 1974 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, 1975 "Element %s has too may ID attributes defined : %s\n", 1976 elem, name, NULL); 1977 if (ctxt != NULL) 1978 ctxt->valid = 0; 1979 } 1980#endif /* LIBXML_VALID_ENABLED */ 1981 1982 /* 1983 * Insert namespace default def first they need to be 1984 * processed first. 1985 */ 1986 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || 1987 ((ret->prefix != NULL && 1988 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { 1989 ret->nexth = elemDef->attributes; 1990 elemDef->attributes = ret; 1991 } else { 1992 xmlAttributePtr tmp = elemDef->attributes; 1993 1994 while ((tmp != NULL) && 1995 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || 1996 ((ret->prefix != NULL && 1997 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { 1998 if (tmp->nexth == NULL) 1999 break; 2000 tmp = tmp->nexth; 2001 } 2002 if (tmp != NULL) { 2003 ret->nexth = tmp->nexth; 2004 tmp->nexth = ret; 2005 } else { 2006 ret->nexth = elemDef->attributes; 2007 elemDef->attributes = ret; 2008 } 2009 } 2010 } 2011 2012 /* 2013 * Link it to the DTD 2014 */ 2015 ret->parent = dtd; 2016 if (dtd->last == NULL) { 2017 dtd->children = dtd->last = (xmlNodePtr) ret; 2018 } else { 2019 dtd->last->next = (xmlNodePtr) ret; 2020 ret->prev = dtd->last; 2021 dtd->last = (xmlNodePtr) ret; 2022 } 2023 return(ret); 2024} 2025 2026static void 2027xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) { 2028 xmlFreeAttribute((xmlAttributePtr) attr); 2029} 2030 2031/** 2032 * xmlFreeAttributeTable: 2033 * @table: An attribute table 2034 * 2035 * Deallocate the memory used by an entities hash table. 2036 */ 2037void 2038xmlFreeAttributeTable(xmlAttributeTablePtr table) { 2039 xmlHashFree(table, xmlFreeAttributeTableEntry); 2040} 2041 2042#ifdef LIBXML_TREE_ENABLED 2043/** 2044 * xmlCopyAttribute: 2045 * @attr: An attribute 2046 * 2047 * Build a copy of an attribute. 2048 * 2049 * Returns the new xmlAttributePtr or NULL in case of error. 2050 */ 2051static void * 2052xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { 2053 xmlAttributePtr attr = (xmlAttributePtr) payload; 2054 xmlAttributePtr cur; 2055 2056 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); 2057 if (cur == NULL) { 2058 xmlVErrMemory(NULL, "malloc failed"); 2059 return(NULL); 2060 } 2061 memset(cur, 0, sizeof(xmlAttribute)); 2062 cur->type = XML_ATTRIBUTE_DECL; 2063 cur->atype = attr->atype; 2064 cur->def = attr->def; 2065 cur->tree = xmlCopyEnumeration(attr->tree); 2066 if (attr->elem != NULL) 2067 cur->elem = xmlStrdup(attr->elem); 2068 if (attr->name != NULL) 2069 cur->name = xmlStrdup(attr->name); 2070 if (attr->prefix != NULL) 2071 cur->prefix = xmlStrdup(attr->prefix); 2072 if (attr->defaultValue != NULL) 2073 cur->defaultValue = xmlStrdup(attr->defaultValue); 2074 return(cur); 2075} 2076 2077/** 2078 * xmlCopyAttributeTable: 2079 * @table: An attribute table 2080 * 2081 * Build a copy of an attribute table. 2082 * 2083 * Returns the new xmlAttributeTablePtr or NULL in case of error. 2084 */ 2085xmlAttributeTablePtr 2086xmlCopyAttributeTable(xmlAttributeTablePtr table) { 2087 return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute)); 2088} 2089#endif /* LIBXML_TREE_ENABLED */ 2090 2091#ifdef LIBXML_OUTPUT_ENABLED 2092/** 2093 * xmlDumpAttributeDecl: 2094 * @buf: the XML buffer output 2095 * @attr: An attribute declaration 2096 * 2097 * This will dump the content of the attribute declaration as an XML 2098 * DTD definition 2099 */ 2100void 2101xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { 2102 if ((buf == NULL) || (attr == NULL)) 2103 return; 2104 xmlBufferWriteChar(buf, "<!ATTLIST "); 2105 xmlBufferWriteCHAR(buf, attr->elem); 2106 xmlBufferWriteChar(buf, " "); 2107 if (attr->prefix != NULL) { 2108 xmlBufferWriteCHAR(buf, attr->prefix); 2109 xmlBufferWriteChar(buf, ":"); 2110 } 2111 xmlBufferWriteCHAR(buf, attr->name); 2112 switch (attr->atype) { 2113 case XML_ATTRIBUTE_CDATA: 2114 xmlBufferWriteChar(buf, " CDATA"); 2115 break; 2116 case XML_ATTRIBUTE_ID: 2117 xmlBufferWriteChar(buf, " ID"); 2118 break; 2119 case XML_ATTRIBUTE_IDREF: 2120 xmlBufferWriteChar(buf, " IDREF"); 2121 break; 2122 case XML_ATTRIBUTE_IDREFS: 2123 xmlBufferWriteChar(buf, " IDREFS"); 2124 break; 2125 case XML_ATTRIBUTE_ENTITY: 2126 xmlBufferWriteChar(buf, " ENTITY"); 2127 break; 2128 case XML_ATTRIBUTE_ENTITIES: 2129 xmlBufferWriteChar(buf, " ENTITIES"); 2130 break; 2131 case XML_ATTRIBUTE_NMTOKEN: 2132 xmlBufferWriteChar(buf, " NMTOKEN"); 2133 break; 2134 case XML_ATTRIBUTE_NMTOKENS: 2135 xmlBufferWriteChar(buf, " NMTOKENS"); 2136 break; 2137 case XML_ATTRIBUTE_ENUMERATION: 2138 xmlBufferWriteChar(buf, " ("); 2139 xmlDumpEnumeration(buf, attr->tree); 2140 break; 2141 case XML_ATTRIBUTE_NOTATION: 2142 xmlBufferWriteChar(buf, " NOTATION ("); 2143 xmlDumpEnumeration(buf, attr->tree); 2144 break; 2145 default: 2146 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 2147 "Internal: ATTRIBUTE struct corrupted invalid type\n", 2148 NULL); 2149 } 2150 switch (attr->def) { 2151 case XML_ATTRIBUTE_NONE: 2152 break; 2153 case XML_ATTRIBUTE_REQUIRED: 2154 xmlBufferWriteChar(buf, " #REQUIRED"); 2155 break; 2156 case XML_ATTRIBUTE_IMPLIED: 2157 xmlBufferWriteChar(buf, " #IMPLIED"); 2158 break; 2159 case XML_ATTRIBUTE_FIXED: 2160 xmlBufferWriteChar(buf, " #FIXED"); 2161 break; 2162 default: 2163 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 2164 "Internal: ATTRIBUTE struct corrupted invalid def\n", 2165 NULL); 2166 } 2167 if (attr->defaultValue != NULL) { 2168 xmlBufferWriteChar(buf, " "); 2169 xmlBufferWriteQuotedString(buf, attr->defaultValue); 2170 } 2171 xmlBufferWriteChar(buf, ">\n"); 2172} 2173 2174/** 2175 * xmlDumpAttributeDeclScan: 2176 * @attr: An attribute declaration 2177 * @buf: the XML buffer output 2178 * 2179 * This is used with the hash scan function - just reverses arguments 2180 */ 2181static void 2182xmlDumpAttributeDeclScan(void *attr, void *buf, 2183 const xmlChar *name ATTRIBUTE_UNUSED) { 2184 xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr); 2185} 2186 2187/** 2188 * xmlDumpAttributeTable: 2189 * @buf: the XML buffer output 2190 * @table: An attribute table 2191 * 2192 * This will dump the content of the attribute table as an XML DTD definition 2193 */ 2194void 2195xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { 2196 if ((buf == NULL) || (table == NULL)) 2197 return; 2198 xmlHashScan(table, xmlDumpAttributeDeclScan, buf); 2199} 2200#endif /* LIBXML_OUTPUT_ENABLED */ 2201 2202/************************************************************************ 2203 * * 2204 * NOTATIONs * 2205 * * 2206 ************************************************************************/ 2207/** 2208 * xmlFreeNotation: 2209 * @not: A notation 2210 * 2211 * Deallocate the memory used by an notation definition 2212 */ 2213static void 2214xmlFreeNotation(xmlNotationPtr nota) { 2215 if (nota == NULL) return; 2216 if (nota->name != NULL) 2217 xmlFree((xmlChar *) nota->name); 2218 if (nota->PublicID != NULL) 2219 xmlFree((xmlChar *) nota->PublicID); 2220 if (nota->SystemID != NULL) 2221 xmlFree((xmlChar *) nota->SystemID); 2222 xmlFree(nota); 2223} 2224 2225 2226/** 2227 * xmlAddNotationDecl: 2228 * @dtd: pointer to the DTD 2229 * @ctxt: the validation context 2230 * @name: the entity name 2231 * @PublicID: the public identifier or NULL 2232 * @SystemID: the system identifier or NULL 2233 * 2234 * Register a new notation declaration 2235 * 2236 * Returns NULL if not, otherwise the entity 2237 */ 2238xmlNotationPtr 2239xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, 2240 const xmlChar *name, 2241 const xmlChar *PublicID, const xmlChar *SystemID) { 2242 xmlNotationPtr ret; 2243 xmlNotationTablePtr table; 2244 2245 if (dtd == NULL) { 2246 return(NULL); 2247 } 2248 if (name == NULL) { 2249 return(NULL); 2250 } 2251 if ((PublicID == NULL) && (SystemID == NULL)) { 2252 return(NULL); 2253 } 2254 2255 /* 2256 * Create the Notation table if needed. 2257 */ 2258 table = (xmlNotationTablePtr) dtd->notations; 2259 if (table == NULL) { 2260 xmlDictPtr dict = NULL; 2261 if (dtd->doc != NULL) 2262 dict = dtd->doc->dict; 2263 2264 dtd->notations = table = xmlHashCreateDict(0, dict); 2265 } 2266 if (table == NULL) { 2267 xmlVErrMemory(ctxt, 2268 "xmlAddNotationDecl: Table creation failed!\n"); 2269 return(NULL); 2270 } 2271 2272 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); 2273 if (ret == NULL) { 2274 xmlVErrMemory(ctxt, "malloc failed"); 2275 return(NULL); 2276 } 2277 memset(ret, 0, sizeof(xmlNotation)); 2278 2279 /* 2280 * fill the structure. 2281 */ 2282 ret->name = xmlStrdup(name); 2283 if (SystemID != NULL) 2284 ret->SystemID = xmlStrdup(SystemID); 2285 if (PublicID != NULL) 2286 ret->PublicID = xmlStrdup(PublicID); 2287 2288 /* 2289 * Validity Check: 2290 * Check the DTD for previous declarations of the ATTLIST 2291 */ 2292 if (xmlHashAddEntry(table, name, ret)) { 2293#ifdef LIBXML_VALID_ENABLED 2294 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, 2295 "xmlAddNotationDecl: %s already defined\n", 2296 (const char *) name); 2297#endif /* LIBXML_VALID_ENABLED */ 2298 xmlFreeNotation(ret); 2299 return(NULL); 2300 } 2301 return(ret); 2302} 2303 2304static void 2305xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) { 2306 xmlFreeNotation((xmlNotationPtr) nota); 2307} 2308 2309/** 2310 * xmlFreeNotationTable: 2311 * @table: An notation table 2312 * 2313 * Deallocate the memory used by an entities hash table. 2314 */ 2315void 2316xmlFreeNotationTable(xmlNotationTablePtr table) { 2317 xmlHashFree(table, xmlFreeNotationTableEntry); 2318} 2319 2320#ifdef LIBXML_TREE_ENABLED 2321/** 2322 * xmlCopyNotation: 2323 * @nota: A notation 2324 * 2325 * Build a copy of a notation. 2326 * 2327 * Returns the new xmlNotationPtr or NULL in case of error. 2328 */ 2329static void * 2330xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { 2331 xmlNotationPtr nota = (xmlNotationPtr) payload; 2332 xmlNotationPtr cur; 2333 2334 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); 2335 if (cur == NULL) { 2336 xmlVErrMemory(NULL, "malloc failed"); 2337 return(NULL); 2338 } 2339 if (nota->name != NULL) 2340 cur->name = xmlStrdup(nota->name); 2341 else 2342 cur->name = NULL; 2343 if (nota->PublicID != NULL) 2344 cur->PublicID = xmlStrdup(nota->PublicID); 2345 else 2346 cur->PublicID = NULL; 2347 if (nota->SystemID != NULL) 2348 cur->SystemID = xmlStrdup(nota->SystemID); 2349 else 2350 cur->SystemID = NULL; 2351 return(cur); 2352} 2353 2354/** 2355 * xmlCopyNotationTable: 2356 * @table: A notation table 2357 * 2358 * Build a copy of a notation table. 2359 * 2360 * Returns the new xmlNotationTablePtr or NULL in case of error. 2361 */ 2362xmlNotationTablePtr 2363xmlCopyNotationTable(xmlNotationTablePtr table) { 2364 return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation)); 2365} 2366#endif /* LIBXML_TREE_ENABLED */ 2367 2368#ifdef LIBXML_OUTPUT_ENABLED 2369/** 2370 * xmlDumpNotationDecl: 2371 * @buf: the XML buffer output 2372 * @nota: A notation declaration 2373 * 2374 * This will dump the content the notation declaration as an XML DTD definition 2375 */ 2376void 2377xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { 2378 if ((buf == NULL) || (nota == NULL)) 2379 return; 2380 xmlBufferWriteChar(buf, "<!NOTATION "); 2381 xmlBufferWriteCHAR(buf, nota->name); 2382 if (nota->PublicID != NULL) { 2383 xmlBufferWriteChar(buf, " PUBLIC "); 2384 xmlBufferWriteQuotedString(buf, nota->PublicID); 2385 if (nota->SystemID != NULL) { 2386 xmlBufferWriteChar(buf, " "); 2387 xmlBufferWriteQuotedString(buf, nota->SystemID); 2388 } 2389 } else { 2390 xmlBufferWriteChar(buf, " SYSTEM "); 2391 xmlBufferWriteQuotedString(buf, nota->SystemID); 2392 } 2393 xmlBufferWriteChar(buf, " >\n"); 2394} 2395 2396/** 2397 * xmlDumpNotationDeclScan: 2398 * @nota: A notation declaration 2399 * @buf: the XML buffer output 2400 * 2401 * This is called with the hash scan function, and just reverses args 2402 */ 2403static void 2404xmlDumpNotationDeclScan(void *nota, void *buf, 2405 const xmlChar *name ATTRIBUTE_UNUSED) { 2406 xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota); 2407} 2408 2409/** 2410 * xmlDumpNotationTable: 2411 * @buf: the XML buffer output 2412 * @table: A notation table 2413 * 2414 * This will dump the content of the notation table as an XML DTD definition 2415 */ 2416void 2417xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { 2418 if ((buf == NULL) || (table == NULL)) 2419 return; 2420 xmlHashScan(table, xmlDumpNotationDeclScan, buf); 2421} 2422#endif /* LIBXML_OUTPUT_ENABLED */ 2423 2424/************************************************************************ 2425 * * 2426 * IDs * 2427 * * 2428 ************************************************************************/ 2429/** 2430 * DICT_FREE: 2431 * @str: a string 2432 * 2433 * Free a string if it is not owned by the "dict" dictionary in the 2434 * current scope 2435 */ 2436#define DICT_FREE(str) \ 2437 if ((str) && ((!dict) || \ 2438 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ 2439 xmlFree((char *)(str)); 2440 2441/** 2442 * xmlValidNormalizeString: 2443 * @str: a string 2444 * 2445 * Normalize a string in-place. 2446 */ 2447static void 2448xmlValidNormalizeString(xmlChar *str) { 2449 xmlChar *dst; 2450 const xmlChar *src; 2451 2452 if (str == NULL) 2453 return; 2454 src = str; 2455 dst = str; 2456 2457 while (*src == 0x20) src++; 2458 while (*src != 0) { 2459 if (*src == 0x20) { 2460 while (*src == 0x20) src++; 2461 if (*src != 0) 2462 *dst++ = 0x20; 2463 } else { 2464 *dst++ = *src++; 2465 } 2466 } 2467 *dst = 0; 2468} 2469 2470static int 2471xmlIsStreaming(xmlValidCtxtPtr ctxt) { 2472 xmlParserCtxtPtr pctxt; 2473 2474 if (ctxt == NULL) 2475 return(0); 2476 if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0) 2477 return(0); 2478 pctxt = ctxt->userData; 2479 return(pctxt->parseMode == XML_PARSE_READER); 2480} 2481 2482/** 2483 * xmlFreeID: 2484 * @not: A id 2485 * 2486 * Deallocate the memory used by an id definition 2487 */ 2488static void 2489xmlFreeID(xmlIDPtr id) { 2490 xmlDictPtr dict = NULL; 2491 2492 if (id == NULL) return; 2493 2494 if (id->doc != NULL) 2495 dict = id->doc->dict; 2496 2497 if (id->value != NULL) 2498 DICT_FREE(id->value) 2499 if (id->name != NULL) 2500 DICT_FREE(id->name) 2501 xmlFree(id); 2502} 2503 2504 2505/** 2506 * xmlAddID: 2507 * @ctxt: the validation context 2508 * @doc: pointer to the document 2509 * @value: the value name 2510 * @attr: the attribute holding the ID 2511 * 2512 * Register a new id declaration 2513 * 2514 * Returns NULL if not, otherwise the new xmlIDPtr 2515 */ 2516xmlIDPtr 2517xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, 2518 xmlAttrPtr attr) { 2519 xmlIDPtr ret; 2520 xmlIDTablePtr table; 2521 2522 if (doc == NULL) { 2523 return(NULL); 2524 } 2525 if ((value == NULL) || (value[0] == 0)) { 2526 return(NULL); 2527 } 2528 if (attr == NULL) { 2529 return(NULL); 2530 } 2531 2532 /* 2533 * Create the ID table if needed. 2534 */ 2535 table = (xmlIDTablePtr) doc->ids; 2536 if (table == NULL) { 2537 doc->ids = table = xmlHashCreateDict(0, doc->dict); 2538 } 2539 if (table == NULL) { 2540 xmlVErrMemory(ctxt, 2541 "xmlAddID: Table creation failed!\n"); 2542 return(NULL); 2543 } 2544 2545 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); 2546 if (ret == NULL) { 2547 xmlVErrMemory(ctxt, "malloc failed"); 2548 return(NULL); 2549 } 2550 2551 /* 2552 * fill the structure. 2553 */ 2554 ret->value = xmlStrdup(value); 2555 ret->doc = doc; 2556 if (xmlIsStreaming(ctxt)) { 2557 /* 2558 * Operating in streaming mode, attr is gonna disappear 2559 */ 2560 if (doc->dict != NULL) 2561 ret->name = xmlDictLookup(doc->dict, attr->name, -1); 2562 else 2563 ret->name = xmlStrdup(attr->name); 2564 ret->attr = NULL; 2565 } else { 2566 ret->attr = attr; 2567 ret->name = NULL; 2568 } 2569 ret->lineno = xmlGetLineNo(attr->parent); 2570 2571 if (xmlHashAddEntry(table, value, ret) < 0) { 2572#ifdef LIBXML_VALID_ENABLED 2573 /* 2574 * The id is already defined in this DTD. 2575 */ 2576 if (ctxt != NULL) { 2577 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, 2578 "ID %s already defined\n", value, NULL, NULL); 2579 } 2580#endif /* LIBXML_VALID_ENABLED */ 2581 xmlFreeID(ret); 2582 return(NULL); 2583 } 2584 if (attr != NULL) 2585 attr->atype = XML_ATTRIBUTE_ID; 2586 return(ret); 2587} 2588 2589static void 2590xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) { 2591 xmlFreeID((xmlIDPtr) id); 2592} 2593 2594/** 2595 * xmlFreeIDTable: 2596 * @table: An id table 2597 * 2598 * Deallocate the memory used by an ID hash table. 2599 */ 2600void 2601xmlFreeIDTable(xmlIDTablePtr table) { 2602 xmlHashFree(table, xmlFreeIDTableEntry); 2603} 2604 2605/** 2606 * xmlIsID: 2607 * @doc: the document 2608 * @elem: the element carrying the attribute 2609 * @attr: the attribute 2610 * 2611 * Determine whether an attribute is of type ID. In case we have DTD(s) 2612 * then this is done if DTD loading has been requested. In the case 2613 * of HTML documents parsed with the HTML parser, then ID detection is 2614 * done systematically. 2615 * 2616 * Returns 0 or 1 depending on the lookup result 2617 */ 2618int 2619xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { 2620 if ((attr == NULL) || (attr->name == NULL)) return(0); 2621 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && 2622 (!strcmp((char *) attr->name, "id")) && 2623 (!strcmp((char *) attr->ns->prefix, "xml"))) 2624 return(1); 2625 if (doc == NULL) return(0); 2626 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) && 2627 (doc->type != XML_HTML_DOCUMENT_NODE)) { 2628 return(0); 2629 } else if (doc->type == XML_HTML_DOCUMENT_NODE) { 2630 if ((xmlStrEqual(BAD_CAST "id", attr->name)) || 2631 ((xmlStrEqual(BAD_CAST "name", attr->name)) && 2632 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a"))))) 2633 return(1); 2634 return(0); 2635 } else if (elem == NULL) { 2636 return(0); 2637 } else { 2638 xmlAttributePtr attrDecl = NULL; 2639 2640 xmlChar felem[50], fattr[50]; 2641 xmlChar *fullelemname, *fullattrname; 2642 2643 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? 2644 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : 2645 (xmlChar *)elem->name; 2646 2647 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? 2648 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : 2649 (xmlChar *)attr->name; 2650 2651 if (fullelemname != NULL && fullattrname != NULL) { 2652 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, 2653 fullattrname); 2654 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 2655 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, 2656 fullattrname); 2657 } 2658 2659 if ((fullattrname != fattr) && (fullattrname != attr->name)) 2660 xmlFree(fullattrname); 2661 if ((fullelemname != felem) && (fullelemname != elem->name)) 2662 xmlFree(fullelemname); 2663 2664 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) 2665 return(1); 2666 } 2667 return(0); 2668} 2669 2670/** 2671 * xmlRemoveID: 2672 * @doc: the document 2673 * @attr: the attribute 2674 * 2675 * Remove the given attribute from the ID table maintained internally. 2676 * 2677 * Returns -1 if the lookup failed and 0 otherwise 2678 */ 2679int 2680xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { 2681 xmlIDTablePtr table; 2682 xmlIDPtr id; 2683 xmlChar *ID; 2684 2685 if (doc == NULL) return(-1); 2686 if (attr == NULL) return(-1); 2687 2688 table = (xmlIDTablePtr) doc->ids; 2689 if (table == NULL) 2690 return(-1); 2691 2692 ID = xmlNodeListGetString(doc, attr->children, 1); 2693 if (ID == NULL) 2694 return(-1); 2695 xmlValidNormalizeString(ID); 2696 2697 id = xmlHashLookup(table, ID); 2698 if (id == NULL || id->attr != attr) { 2699 xmlFree(ID); 2700 return(-1); 2701 } 2702 2703 xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry); 2704 xmlFree(ID); 2705 attr->atype = 0; 2706 return(0); 2707} 2708 2709/** 2710 * xmlGetID: 2711 * @doc: pointer to the document 2712 * @ID: the ID value 2713 * 2714 * Search the attribute declaring the given ID 2715 * 2716 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID 2717 */ 2718xmlAttrPtr 2719xmlGetID(xmlDocPtr doc, const xmlChar *ID) { 2720 xmlIDTablePtr table; 2721 xmlIDPtr id; 2722 2723 if (doc == NULL) { 2724 return(NULL); 2725 } 2726 2727 if (ID == NULL) { 2728 return(NULL); 2729 } 2730 2731 table = (xmlIDTablePtr) doc->ids; 2732 if (table == NULL) 2733 return(NULL); 2734 2735 id = xmlHashLookup(table, ID); 2736 if (id == NULL) 2737 return(NULL); 2738 if (id->attr == NULL) { 2739 /* 2740 * We are operating on a stream, return a well known reference 2741 * since the attribute node doesn't exist anymore 2742 */ 2743 return((xmlAttrPtr) doc); 2744 } 2745 return(id->attr); 2746} 2747 2748/************************************************************************ 2749 * * 2750 * Refs * 2751 * * 2752 ************************************************************************/ 2753typedef struct xmlRemoveMemo_t 2754{ 2755 xmlListPtr l; 2756 xmlAttrPtr ap; 2757} xmlRemoveMemo; 2758 2759typedef xmlRemoveMemo *xmlRemoveMemoPtr; 2760 2761typedef struct xmlValidateMemo_t 2762{ 2763 xmlValidCtxtPtr ctxt; 2764 const xmlChar *name; 2765} xmlValidateMemo; 2766 2767typedef xmlValidateMemo *xmlValidateMemoPtr; 2768 2769/** 2770 * xmlFreeRef: 2771 * @lk: A list link 2772 * 2773 * Deallocate the memory used by a ref definition 2774 */ 2775static void 2776xmlFreeRef(xmlLinkPtr lk) { 2777 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk); 2778 if (ref == NULL) return; 2779 if (ref->value != NULL) 2780 xmlFree((xmlChar *)ref->value); 2781 if (ref->name != NULL) 2782 xmlFree((xmlChar *)ref->name); 2783 xmlFree(ref); 2784} 2785 2786/** 2787 * xmlFreeRefTableEntry: 2788 * @list_ref: A list of references. 2789 * 2790 * Deallocate the memory used by a list of references 2791 */ 2792static void 2793xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { 2794 xmlListPtr list_ref = (xmlListPtr) payload; 2795 if (list_ref == NULL) return; 2796 xmlListDelete(list_ref); 2797} 2798 2799/** 2800 * xmlWalkRemoveRef: 2801 * @data: Contents of current link 2802 * @user: Value supplied by the user 2803 * 2804 * Returns 0 to abort the walk or 1 to continue 2805 */ 2806static int 2807xmlWalkRemoveRef(const void *data, void *user) 2808{ 2809 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr; 2810 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap; 2811 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l; 2812 2813 if (attr0 == attr1) { /* Matched: remove and terminate walk */ 2814 xmlListRemoveFirst(ref_list, (void *)data); 2815 return 0; 2816 } 2817 return 1; 2818} 2819 2820/** 2821 * xmlDummyCompare 2822 * @data0: Value supplied by the user 2823 * @data1: Value supplied by the user 2824 * 2825 * Do nothing, return 0. Used to create unordered lists. 2826 */ 2827static int 2828xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, 2829 const void *data1 ATTRIBUTE_UNUSED) 2830{ 2831 return (0); 2832} 2833 2834/** 2835 * xmlAddRef: 2836 * @ctxt: the validation context 2837 * @doc: pointer to the document 2838 * @value: the value name 2839 * @attr: the attribute holding the Ref 2840 * 2841 * DEPRECATED, do not use. This function will be removed from the public API. 2842 * 2843 * Register a new ref declaration 2844 * 2845 * Returns NULL if not, otherwise the new xmlRefPtr 2846 */ 2847xmlRefPtr 2848xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, 2849 xmlAttrPtr attr) { 2850 xmlRefPtr ret; 2851 xmlRefTablePtr table; 2852 xmlListPtr ref_list; 2853 2854 if (doc == NULL) { 2855 return(NULL); 2856 } 2857 if (value == NULL) { 2858 return(NULL); 2859 } 2860 if (attr == NULL) { 2861 return(NULL); 2862 } 2863 2864 /* 2865 * Create the Ref table if needed. 2866 */ 2867 table = (xmlRefTablePtr) doc->refs; 2868 if (table == NULL) { 2869 doc->refs = table = xmlHashCreateDict(0, doc->dict); 2870 } 2871 if (table == NULL) { 2872 xmlVErrMemory(ctxt, 2873 "xmlAddRef: Table creation failed!\n"); 2874 return(NULL); 2875 } 2876 2877 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); 2878 if (ret == NULL) { 2879 xmlVErrMemory(ctxt, "malloc failed"); 2880 return(NULL); 2881 } 2882 2883 /* 2884 * fill the structure. 2885 */ 2886 ret->value = xmlStrdup(value); 2887 if (xmlIsStreaming(ctxt)) { 2888 /* 2889 * Operating in streaming mode, attr is gonna disappear 2890 */ 2891 ret->name = xmlStrdup(attr->name); 2892 ret->attr = NULL; 2893 } else { 2894 ret->name = NULL; 2895 ret->attr = attr; 2896 } 2897 ret->lineno = xmlGetLineNo(attr->parent); 2898 2899 /* To add a reference :- 2900 * References are maintained as a list of references, 2901 * Lookup the entry, if no entry create new nodelist 2902 * Add the owning node to the NodeList 2903 * Return the ref 2904 */ 2905 2906 if (NULL == (ref_list = xmlHashLookup(table, value))) { 2907 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) { 2908 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 2909 "xmlAddRef: Reference list creation failed!\n", 2910 NULL); 2911 goto failed; 2912 } 2913 if (xmlHashAddEntry(table, value, ref_list) < 0) { 2914 xmlListDelete(ref_list); 2915 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 2916 "xmlAddRef: Reference list insertion failed!\n", 2917 NULL); 2918 goto failed; 2919 } 2920 } 2921 if (xmlListAppend(ref_list, ret) != 0) { 2922 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 2923 "xmlAddRef: Reference list insertion failed!\n", 2924 NULL); 2925 goto failed; 2926 } 2927 return(ret); 2928failed: 2929 if (ret != NULL) { 2930 if (ret->value != NULL) 2931 xmlFree((char *)ret->value); 2932 if (ret->name != NULL) 2933 xmlFree((char *)ret->name); 2934 xmlFree(ret); 2935 } 2936 return(NULL); 2937} 2938 2939/** 2940 * xmlFreeRefTable: 2941 * @table: An ref table 2942 * 2943 * DEPRECATED, do not use. This function will be removed from the public API. 2944 * 2945 * Deallocate the memory used by an Ref hash table. 2946 */ 2947void 2948xmlFreeRefTable(xmlRefTablePtr table) { 2949 xmlHashFree(table, xmlFreeRefTableEntry); 2950} 2951 2952/** 2953 * xmlIsRef: 2954 * @doc: the document 2955 * @elem: the element carrying the attribute 2956 * @attr: the attribute 2957 * 2958 * DEPRECATED, do not use. This function will be removed from the public API. 2959 * 2960 * Determine whether an attribute is of type Ref. In case we have DTD(s) 2961 * then this is simple, otherwise we use an heuristic: name Ref (upper 2962 * or lowercase). 2963 * 2964 * Returns 0 or 1 depending on the lookup result 2965 */ 2966int 2967xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { 2968 if (attr == NULL) 2969 return(0); 2970 if (doc == NULL) { 2971 doc = attr->doc; 2972 if (doc == NULL) return(0); 2973 } 2974 2975 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { 2976 return(0); 2977 } else if (doc->type == XML_HTML_DOCUMENT_NODE) { 2978 /* TODO @@@ */ 2979 return(0); 2980 } else { 2981 xmlAttributePtr attrDecl; 2982 2983 if (elem == NULL) return(0); 2984 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); 2985 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 2986 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 2987 elem->name, attr->name); 2988 2989 if ((attrDecl != NULL) && 2990 (attrDecl->atype == XML_ATTRIBUTE_IDREF || 2991 attrDecl->atype == XML_ATTRIBUTE_IDREFS)) 2992 return(1); 2993 } 2994 return(0); 2995} 2996 2997/** 2998 * xmlRemoveRef: 2999 * @doc: the document 3000 * @attr: the attribute 3001 * 3002 * DEPRECATED, do not use. This function will be removed from the public API. 3003 * 3004 * Remove the given attribute from the Ref table maintained internally. 3005 * 3006 * Returns -1 if the lookup failed and 0 otherwise 3007 */ 3008int 3009xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) { 3010 xmlListPtr ref_list; 3011 xmlRefTablePtr table; 3012 xmlChar *ID; 3013 xmlRemoveMemo target; 3014 3015 if (doc == NULL) return(-1); 3016 if (attr == NULL) return(-1); 3017 3018 table = (xmlRefTablePtr) doc->refs; 3019 if (table == NULL) 3020 return(-1); 3021 3022 ID = xmlNodeListGetString(doc, attr->children, 1); 3023 if (ID == NULL) 3024 return(-1); 3025 3026 ref_list = xmlHashLookup(table, ID); 3027 if(ref_list == NULL) { 3028 xmlFree(ID); 3029 return (-1); 3030 } 3031 3032 /* At this point, ref_list refers to a list of references which 3033 * have the same key as the supplied attr. Our list of references 3034 * is ordered by reference address and we don't have that information 3035 * here to use when removing. We'll have to walk the list and 3036 * check for a matching attribute, when we find one stop the walk 3037 * and remove the entry. 3038 * The list is ordered by reference, so that means we don't have the 3039 * key. Passing the list and the reference to the walker means we 3040 * will have enough data to be able to remove the entry. 3041 */ 3042 target.l = ref_list; 3043 target.ap = attr; 3044 3045 /* Remove the supplied attr from our list */ 3046 xmlListWalk(ref_list, xmlWalkRemoveRef, &target); 3047 3048 /*If the list is empty then remove the list entry in the hash */ 3049 if (xmlListEmpty(ref_list)) 3050 xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry); 3051 xmlFree(ID); 3052 return(0); 3053} 3054 3055/** 3056 * xmlGetRefs: 3057 * @doc: pointer to the document 3058 * @ID: the ID value 3059 * 3060 * DEPRECATED, do not use. This function will be removed from the public API. 3061 * 3062 * Find the set of references for the supplied ID. 3063 * 3064 * Returns NULL if not found, otherwise node set for the ID. 3065 */ 3066xmlListPtr 3067xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { 3068 xmlRefTablePtr table; 3069 3070 if (doc == NULL) { 3071 return(NULL); 3072 } 3073 3074 if (ID == NULL) { 3075 return(NULL); 3076 } 3077 3078 table = (xmlRefTablePtr) doc->refs; 3079 if (table == NULL) 3080 return(NULL); 3081 3082 return (xmlHashLookup(table, ID)); 3083} 3084 3085/************************************************************************ 3086 * * 3087 * Routines for validity checking * 3088 * * 3089 ************************************************************************/ 3090 3091/** 3092 * xmlGetDtdElementDesc: 3093 * @dtd: a pointer to the DtD to search 3094 * @name: the element name 3095 * 3096 * Search the DTD for the description of this element 3097 * 3098 * returns the xmlElementPtr if found or NULL 3099 */ 3100 3101xmlElementPtr 3102xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { 3103 xmlElementTablePtr table; 3104 xmlElementPtr cur; 3105 xmlChar *uqname = NULL, *prefix = NULL; 3106 3107 if ((dtd == NULL) || (name == NULL)) return(NULL); 3108 if (dtd->elements == NULL) 3109 return(NULL); 3110 table = (xmlElementTablePtr) dtd->elements; 3111 3112 uqname = xmlSplitQName2(name, &prefix); 3113 if (uqname != NULL) 3114 name = uqname; 3115 cur = xmlHashLookup2(table, name, prefix); 3116 if (prefix != NULL) xmlFree(prefix); 3117 if (uqname != NULL) xmlFree(uqname); 3118 return(cur); 3119} 3120/** 3121 * xmlGetDtdElementDesc2: 3122 * @dtd: a pointer to the DtD to search 3123 * @name: the element name 3124 * @create: create an empty description if not found 3125 * 3126 * Search the DTD for the description of this element 3127 * 3128 * returns the xmlElementPtr if found or NULL 3129 */ 3130 3131static xmlElementPtr 3132xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, 3133 int create) { 3134 xmlElementTablePtr table; 3135 xmlElementPtr cur; 3136 xmlChar *uqname = NULL, *prefix = NULL; 3137 3138 if (dtd == NULL) return(NULL); 3139 if (dtd->elements == NULL) { 3140 xmlDictPtr dict = NULL; 3141 3142 if (dtd->doc != NULL) 3143 dict = dtd->doc->dict; 3144 3145 if (!create) 3146 return(NULL); 3147 /* 3148 * Create the Element table if needed. 3149 */ 3150 table = (xmlElementTablePtr) dtd->elements; 3151 if (table == NULL) { 3152 table = xmlHashCreateDict(0, dict); 3153 dtd->elements = (void *) table; 3154 } 3155 if (table == NULL) { 3156 xmlVErrMemory(ctxt, "element table allocation failed"); 3157 return(NULL); 3158 } 3159 } 3160 table = (xmlElementTablePtr) dtd->elements; 3161 3162 uqname = xmlSplitQName2(name, &prefix); 3163 if (uqname != NULL) 3164 name = uqname; 3165 cur = xmlHashLookup2(table, name, prefix); 3166 if ((cur == NULL) && (create)) { 3167 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 3168 if (cur == NULL) { 3169 xmlVErrMemory(ctxt, "malloc failed"); 3170 goto error; 3171 } 3172 memset(cur, 0, sizeof(xmlElement)); 3173 cur->type = XML_ELEMENT_DECL; 3174 3175 /* 3176 * fill the structure. 3177 */ 3178 cur->name = xmlStrdup(name); 3179 cur->prefix = xmlStrdup(prefix); 3180 cur->etype = XML_ELEMENT_TYPE_UNDEFINED; 3181 3182 if (xmlHashAddEntry2(table, name, prefix, cur) < 0) { 3183 xmlVErrMemory(ctxt, "adding entry failed"); 3184 xmlFreeElement(cur); 3185 cur = NULL; 3186 } 3187 } 3188error: 3189 if (prefix != NULL) xmlFree(prefix); 3190 if (uqname != NULL) xmlFree(uqname); 3191 return(cur); 3192} 3193 3194/** 3195 * xmlGetDtdQElementDesc: 3196 * @dtd: a pointer to the DtD to search 3197 * @name: the element name 3198 * @prefix: the element namespace prefix 3199 * 3200 * Search the DTD for the description of this element 3201 * 3202 * returns the xmlElementPtr if found or NULL 3203 */ 3204 3205xmlElementPtr 3206xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name, 3207 const xmlChar *prefix) { 3208 xmlElementTablePtr table; 3209 3210 if (dtd == NULL) return(NULL); 3211 if (dtd->elements == NULL) return(NULL); 3212 table = (xmlElementTablePtr) dtd->elements; 3213 3214 return(xmlHashLookup2(table, name, prefix)); 3215} 3216 3217/** 3218 * xmlGetDtdAttrDesc: 3219 * @dtd: a pointer to the DtD to search 3220 * @elem: the element name 3221 * @name: the attribute name 3222 * 3223 * Search the DTD for the description of this attribute on 3224 * this element. 3225 * 3226 * returns the xmlAttributePtr if found or NULL 3227 */ 3228 3229xmlAttributePtr 3230xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { 3231 xmlAttributeTablePtr table; 3232 xmlAttributePtr cur; 3233 xmlChar *uqname = NULL, *prefix = NULL; 3234 3235 if (dtd == NULL) return(NULL); 3236 if (dtd->attributes == NULL) return(NULL); 3237 3238 table = (xmlAttributeTablePtr) dtd->attributes; 3239 if (table == NULL) 3240 return(NULL); 3241 3242 uqname = xmlSplitQName2(name, &prefix); 3243 3244 if (uqname != NULL) { 3245 cur = xmlHashLookup3(table, uqname, prefix, elem); 3246 if (prefix != NULL) xmlFree(prefix); 3247 if (uqname != NULL) xmlFree(uqname); 3248 } else 3249 cur = xmlHashLookup3(table, name, NULL, elem); 3250 return(cur); 3251} 3252 3253/** 3254 * xmlGetDtdQAttrDesc: 3255 * @dtd: a pointer to the DtD to search 3256 * @elem: the element name 3257 * @name: the attribute name 3258 * @prefix: the attribute namespace prefix 3259 * 3260 * Search the DTD for the description of this qualified attribute on 3261 * this element. 3262 * 3263 * returns the xmlAttributePtr if found or NULL 3264 */ 3265 3266xmlAttributePtr 3267xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, 3268 const xmlChar *prefix) { 3269 xmlAttributeTablePtr table; 3270 3271 if (dtd == NULL) return(NULL); 3272 if (dtd->attributes == NULL) return(NULL); 3273 table = (xmlAttributeTablePtr) dtd->attributes; 3274 3275 return(xmlHashLookup3(table, name, prefix, elem)); 3276} 3277 3278/** 3279 * xmlGetDtdNotationDesc: 3280 * @dtd: a pointer to the DtD to search 3281 * @name: the notation name 3282 * 3283 * Search the DTD for the description of this notation 3284 * 3285 * returns the xmlNotationPtr if found or NULL 3286 */ 3287 3288xmlNotationPtr 3289xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { 3290 xmlNotationTablePtr table; 3291 3292 if (dtd == NULL) return(NULL); 3293 if (dtd->notations == NULL) return(NULL); 3294 table = (xmlNotationTablePtr) dtd->notations; 3295 3296 return(xmlHashLookup(table, name)); 3297} 3298 3299#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 3300/** 3301 * xmlValidateNotationUse: 3302 * @ctxt: the validation context 3303 * @doc: the document 3304 * @notationName: the notation name to check 3305 * 3306 * Validate that the given name match a notation declaration. 3307 * - [ VC: Notation Declared ] 3308 * 3309 * returns 1 if valid or 0 otherwise 3310 */ 3311 3312int 3313xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 3314 const xmlChar *notationName) { 3315 xmlNotationPtr notaDecl; 3316 if ((doc == NULL) || (doc->intSubset == NULL) || 3317 (notationName == NULL)) return(-1); 3318 3319 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName); 3320 if ((notaDecl == NULL) && (doc->extSubset != NULL)) 3321 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName); 3322 3323 if ((notaDecl == NULL) && (ctxt != NULL)) { 3324 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION, 3325 "NOTATION %s is not declared\n", 3326 notationName, NULL, NULL); 3327 return(0); 3328 } 3329 return(1); 3330} 3331#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ 3332 3333/** 3334 * xmlIsMixedElement: 3335 * @doc: the document 3336 * @name: the element name 3337 * 3338 * Search in the DtDs whether an element accept Mixed content (or ANY) 3339 * basically if it is supposed to accept text childs 3340 * 3341 * returns 0 if no, 1 if yes, and -1 if no element description is available 3342 */ 3343 3344int 3345xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { 3346 xmlElementPtr elemDecl; 3347 3348 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1); 3349 3350 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name); 3351 if ((elemDecl == NULL) && (doc->extSubset != NULL)) 3352 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name); 3353 if (elemDecl == NULL) return(-1); 3354 switch (elemDecl->etype) { 3355 case XML_ELEMENT_TYPE_UNDEFINED: 3356 return(-1); 3357 case XML_ELEMENT_TYPE_ELEMENT: 3358 return(0); 3359 case XML_ELEMENT_TYPE_EMPTY: 3360 /* 3361 * return 1 for EMPTY since we want VC error to pop up 3362 * on <empty> </empty> for example 3363 */ 3364 case XML_ELEMENT_TYPE_ANY: 3365 case XML_ELEMENT_TYPE_MIXED: 3366 return(1); 3367 } 3368 return(1); 3369} 3370 3371#ifdef LIBXML_VALID_ENABLED 3372 3373static int 3374xmlIsDocNameStartChar(xmlDocPtr doc, int c) { 3375 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { 3376 /* 3377 * Use the new checks of production [4] [4a] amd [5] of the 3378 * Update 5 of XML-1.0 3379 */ 3380 if (((c >= 'a') && (c <= 'z')) || 3381 ((c >= 'A') && (c <= 'Z')) || 3382 (c == '_') || (c == ':') || 3383 ((c >= 0xC0) && (c <= 0xD6)) || 3384 ((c >= 0xD8) && (c <= 0xF6)) || 3385 ((c >= 0xF8) && (c <= 0x2FF)) || 3386 ((c >= 0x370) && (c <= 0x37D)) || 3387 ((c >= 0x37F) && (c <= 0x1FFF)) || 3388 ((c >= 0x200C) && (c <= 0x200D)) || 3389 ((c >= 0x2070) && (c <= 0x218F)) || 3390 ((c >= 0x2C00) && (c <= 0x2FEF)) || 3391 ((c >= 0x3001) && (c <= 0xD7FF)) || 3392 ((c >= 0xF900) && (c <= 0xFDCF)) || 3393 ((c >= 0xFDF0) && (c <= 0xFFFD)) || 3394 ((c >= 0x10000) && (c <= 0xEFFFF))) 3395 return(1); 3396 } else { 3397 if (IS_LETTER(c) || (c == '_') || (c == ':')) 3398 return(1); 3399 } 3400 return(0); 3401} 3402 3403static int 3404xmlIsDocNameChar(xmlDocPtr doc, int c) { 3405 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { 3406 /* 3407 * Use the new checks of production [4] [4a] amd [5] of the 3408 * Update 5 of XML-1.0 3409 */ 3410 if (((c >= 'a') && (c <= 'z')) || 3411 ((c >= 'A') && (c <= 'Z')) || 3412 ((c >= '0') && (c <= '9')) || /* !start */ 3413 (c == '_') || (c == ':') || 3414 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ 3415 ((c >= 0xC0) && (c <= 0xD6)) || 3416 ((c >= 0xD8) && (c <= 0xF6)) || 3417 ((c >= 0xF8) && (c <= 0x2FF)) || 3418 ((c >= 0x300) && (c <= 0x36F)) || /* !start */ 3419 ((c >= 0x370) && (c <= 0x37D)) || 3420 ((c >= 0x37F) && (c <= 0x1FFF)) || 3421 ((c >= 0x200C) && (c <= 0x200D)) || 3422 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ 3423 ((c >= 0x2070) && (c <= 0x218F)) || 3424 ((c >= 0x2C00) && (c <= 0x2FEF)) || 3425 ((c >= 0x3001) && (c <= 0xD7FF)) || 3426 ((c >= 0xF900) && (c <= 0xFDCF)) || 3427 ((c >= 0xFDF0) && (c <= 0xFFFD)) || 3428 ((c >= 0x10000) && (c <= 0xEFFFF))) 3429 return(1); 3430 } else { 3431 if ((IS_LETTER(c)) || (IS_DIGIT(c)) || 3432 (c == '.') || (c == '-') || 3433 (c == '_') || (c == ':') || 3434 (IS_COMBINING(c)) || 3435 (IS_EXTENDER(c))) 3436 return(1); 3437 } 3438 return(0); 3439} 3440 3441/** 3442 * xmlValidateNameValue: 3443 * @doc: pointer to the document or NULL 3444 * @value: an Name value 3445 * 3446 * Validate that the given value match Name production 3447 * 3448 * returns 1 if valid or 0 otherwise 3449 */ 3450 3451static int 3452xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) { 3453 const xmlChar *cur; 3454 int val, len; 3455 3456 if (value == NULL) return(0); 3457 cur = value; 3458 val = xmlStringCurrentChar(NULL, cur, &len); 3459 cur += len; 3460 if (!xmlIsDocNameStartChar(doc, val)) 3461 return(0); 3462 3463 val = xmlStringCurrentChar(NULL, cur, &len); 3464 cur += len; 3465 while (xmlIsDocNameChar(doc, val)) { 3466 val = xmlStringCurrentChar(NULL, cur, &len); 3467 cur += len; 3468 } 3469 3470 if (val != 0) return(0); 3471 3472 return(1); 3473} 3474 3475/** 3476 * xmlValidateNameValue: 3477 * @value: an Name value 3478 * 3479 * Validate that the given value match Name production 3480 * 3481 * returns 1 if valid or 0 otherwise 3482 */ 3483 3484int 3485xmlValidateNameValue(const xmlChar *value) { 3486 return(xmlValidateNameValueInternal(NULL, value)); 3487} 3488 3489/** 3490 * xmlValidateNamesValueInternal: 3491 * @doc: pointer to the document or NULL 3492 * @value: an Names value 3493 * 3494 * Validate that the given value match Names production 3495 * 3496 * returns 1 if valid or 0 otherwise 3497 */ 3498 3499static int 3500xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) { 3501 const xmlChar *cur; 3502 int val, len; 3503 3504 if (value == NULL) return(0); 3505 cur = value; 3506 val = xmlStringCurrentChar(NULL, cur, &len); 3507 cur += len; 3508 3509 if (!xmlIsDocNameStartChar(doc, val)) 3510 return(0); 3511 3512 val = xmlStringCurrentChar(NULL, cur, &len); 3513 cur += len; 3514 while (xmlIsDocNameChar(doc, val)) { 3515 val = xmlStringCurrentChar(NULL, cur, &len); 3516 cur += len; 3517 } 3518 3519 /* Should not test IS_BLANK(val) here -- see erratum E20*/ 3520 while (val == 0x20) { 3521 while (val == 0x20) { 3522 val = xmlStringCurrentChar(NULL, cur, &len); 3523 cur += len; 3524 } 3525 3526 if (!xmlIsDocNameStartChar(doc, val)) 3527 return(0); 3528 3529 val = xmlStringCurrentChar(NULL, cur, &len); 3530 cur += len; 3531 3532 while (xmlIsDocNameChar(doc, val)) { 3533 val = xmlStringCurrentChar(NULL, cur, &len); 3534 cur += len; 3535 } 3536 } 3537 3538 if (val != 0) return(0); 3539 3540 return(1); 3541} 3542 3543/** 3544 * xmlValidateNamesValue: 3545 * @value: an Names value 3546 * 3547 * Validate that the given value match Names production 3548 * 3549 * returns 1 if valid or 0 otherwise 3550 */ 3551 3552int 3553xmlValidateNamesValue(const xmlChar *value) { 3554 return(xmlValidateNamesValueInternal(NULL, value)); 3555} 3556 3557/** 3558 * xmlValidateNmtokenValueInternal: 3559 * @doc: pointer to the document or NULL 3560 * @value: an Nmtoken value 3561 * 3562 * Validate that the given value match Nmtoken production 3563 * 3564 * [ VC: Name Token ] 3565 * 3566 * returns 1 if valid or 0 otherwise 3567 */ 3568 3569static int 3570xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) { 3571 const xmlChar *cur; 3572 int val, len; 3573 3574 if (value == NULL) return(0); 3575 cur = value; 3576 val = xmlStringCurrentChar(NULL, cur, &len); 3577 cur += len; 3578 3579 if (!xmlIsDocNameChar(doc, val)) 3580 return(0); 3581 3582 val = xmlStringCurrentChar(NULL, cur, &len); 3583 cur += len; 3584 while (xmlIsDocNameChar(doc, val)) { 3585 val = xmlStringCurrentChar(NULL, cur, &len); 3586 cur += len; 3587 } 3588 3589 if (val != 0) return(0); 3590 3591 return(1); 3592} 3593 3594/** 3595 * xmlValidateNmtokenValue: 3596 * @value: an Nmtoken value 3597 * 3598 * Validate that the given value match Nmtoken production 3599 * 3600 * [ VC: Name Token ] 3601 * 3602 * returns 1 if valid or 0 otherwise 3603 */ 3604 3605int 3606xmlValidateNmtokenValue(const xmlChar *value) { 3607 return(xmlValidateNmtokenValueInternal(NULL, value)); 3608} 3609 3610/** 3611 * xmlValidateNmtokensValueInternal: 3612 * @doc: pointer to the document or NULL 3613 * @value: an Nmtokens value 3614 * 3615 * Validate that the given value match Nmtokens production 3616 * 3617 * [ VC: Name Token ] 3618 * 3619 * returns 1 if valid or 0 otherwise 3620 */ 3621 3622static int 3623xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) { 3624 const xmlChar *cur; 3625 int val, len; 3626 3627 if (value == NULL) return(0); 3628 cur = value; 3629 val = xmlStringCurrentChar(NULL, cur, &len); 3630 cur += len; 3631 3632 while (IS_BLANK(val)) { 3633 val = xmlStringCurrentChar(NULL, cur, &len); 3634 cur += len; 3635 } 3636 3637 if (!xmlIsDocNameChar(doc, val)) 3638 return(0); 3639 3640 while (xmlIsDocNameChar(doc, val)) { 3641 val = xmlStringCurrentChar(NULL, cur, &len); 3642 cur += len; 3643 } 3644 3645 /* Should not test IS_BLANK(val) here -- see erratum E20*/ 3646 while (val == 0x20) { 3647 while (val == 0x20) { 3648 val = xmlStringCurrentChar(NULL, cur, &len); 3649 cur += len; 3650 } 3651 if (val == 0) return(1); 3652 3653 if (!xmlIsDocNameChar(doc, val)) 3654 return(0); 3655 3656 val = xmlStringCurrentChar(NULL, cur, &len); 3657 cur += len; 3658 3659 while (xmlIsDocNameChar(doc, val)) { 3660 val = xmlStringCurrentChar(NULL, cur, &len); 3661 cur += len; 3662 } 3663 } 3664 3665 if (val != 0) return(0); 3666 3667 return(1); 3668} 3669 3670/** 3671 * xmlValidateNmtokensValue: 3672 * @value: an Nmtokens value 3673 * 3674 * Validate that the given value match Nmtokens production 3675 * 3676 * [ VC: Name Token ] 3677 * 3678 * returns 1 if valid or 0 otherwise 3679 */ 3680 3681int 3682xmlValidateNmtokensValue(const xmlChar *value) { 3683 return(xmlValidateNmtokensValueInternal(NULL, value)); 3684} 3685 3686/** 3687 * xmlValidateNotationDecl: 3688 * @ctxt: the validation context 3689 * @doc: a document instance 3690 * @nota: a notation definition 3691 * 3692 * Try to validate a single notation definition 3693 * basically it does the following checks as described by the 3694 * XML-1.0 recommendation: 3695 * - it seems that no validity constraint exists on notation declarations 3696 * But this function get called anyway ... 3697 * 3698 * returns 1 if valid or 0 otherwise 3699 */ 3700 3701int 3702xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED, 3703 xmlNotationPtr nota ATTRIBUTE_UNUSED) { 3704 int ret = 1; 3705 3706 return(ret); 3707} 3708 3709/** 3710 * xmlValidateAttributeValueInternal: 3711 * @doc: the document 3712 * @type: an attribute type 3713 * @value: an attribute value 3714 * 3715 * Validate that the given attribute value match the proper production 3716 * 3717 * returns 1 if valid or 0 otherwise 3718 */ 3719 3720static int 3721xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, 3722 const xmlChar *value) { 3723 switch (type) { 3724 case XML_ATTRIBUTE_ENTITIES: 3725 case XML_ATTRIBUTE_IDREFS: 3726 return(xmlValidateNamesValueInternal(doc, value)); 3727 case XML_ATTRIBUTE_ENTITY: 3728 case XML_ATTRIBUTE_IDREF: 3729 case XML_ATTRIBUTE_ID: 3730 case XML_ATTRIBUTE_NOTATION: 3731 return(xmlValidateNameValueInternal(doc, value)); 3732 case XML_ATTRIBUTE_NMTOKENS: 3733 case XML_ATTRIBUTE_ENUMERATION: 3734 return(xmlValidateNmtokensValueInternal(doc, value)); 3735 case XML_ATTRIBUTE_NMTOKEN: 3736 return(xmlValidateNmtokenValueInternal(doc, value)); 3737 case XML_ATTRIBUTE_CDATA: 3738 break; 3739 } 3740 return(1); 3741} 3742 3743/** 3744 * xmlValidateAttributeValue: 3745 * @type: an attribute type 3746 * @value: an attribute value 3747 * 3748 * Validate that the given attribute value match the proper production 3749 * 3750 * [ VC: ID ] 3751 * Values of type ID must match the Name production.... 3752 * 3753 * [ VC: IDREF ] 3754 * Values of type IDREF must match the Name production, and values 3755 * of type IDREFS must match Names ... 3756 * 3757 * [ VC: Entity Name ] 3758 * Values of type ENTITY must match the Name production, values 3759 * of type ENTITIES must match Names ... 3760 * 3761 * [ VC: Name Token ] 3762 * Values of type NMTOKEN must match the Nmtoken production; values 3763 * of type NMTOKENS must match Nmtokens. 3764 * 3765 * returns 1 if valid or 0 otherwise 3766 */ 3767int 3768xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) { 3769 return(xmlValidateAttributeValueInternal(NULL, type, value)); 3770} 3771 3772/** 3773 * xmlValidateAttributeValue2: 3774 * @ctxt: the validation context 3775 * @doc: the document 3776 * @name: the attribute name (used for error reporting only) 3777 * @type: the attribute type 3778 * @value: the attribute value 3779 * 3780 * Validate that the given attribute value match a given type. 3781 * This typically cannot be done before having finished parsing 3782 * the subsets. 3783 * 3784 * [ VC: IDREF ] 3785 * Values of type IDREF must match one of the declared IDs 3786 * Values of type IDREFS must match a sequence of the declared IDs 3787 * each Name must match the value of an ID attribute on some element 3788 * in the XML document; i.e. IDREF values must match the value of 3789 * some ID attribute 3790 * 3791 * [ VC: Entity Name ] 3792 * Values of type ENTITY must match one declared entity 3793 * Values of type ENTITIES must match a sequence of declared entities 3794 * 3795 * [ VC: Notation Attributes ] 3796 * all notation names in the declaration must be declared. 3797 * 3798 * returns 1 if valid or 0 otherwise 3799 */ 3800 3801static int 3802xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 3803 const xmlChar *name, xmlAttributeType type, const xmlChar *value) { 3804 int ret = 1; 3805 switch (type) { 3806 case XML_ATTRIBUTE_IDREFS: 3807 case XML_ATTRIBUTE_IDREF: 3808 case XML_ATTRIBUTE_ID: 3809 case XML_ATTRIBUTE_NMTOKENS: 3810 case XML_ATTRIBUTE_ENUMERATION: 3811 case XML_ATTRIBUTE_NMTOKEN: 3812 case XML_ATTRIBUTE_CDATA: 3813 break; 3814 case XML_ATTRIBUTE_ENTITY: { 3815 xmlEntityPtr ent; 3816 3817 ent = xmlGetDocEntity(doc, value); 3818 /* yeah it's a bit messy... */ 3819 if ((ent == NULL) && (doc->standalone == 1)) { 3820 doc->standalone = 0; 3821 ent = xmlGetDocEntity(doc, value); 3822 } 3823 if (ent == NULL) { 3824 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 3825 XML_DTD_UNKNOWN_ENTITY, 3826 "ENTITY attribute %s reference an unknown entity \"%s\"\n", 3827 name, value, NULL); 3828 ret = 0; 3829 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 3830 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 3831 XML_DTD_ENTITY_TYPE, 3832 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n", 3833 name, value, NULL); 3834 ret = 0; 3835 } 3836 break; 3837 } 3838 case XML_ATTRIBUTE_ENTITIES: { 3839 xmlChar *dup, *nam = NULL, *cur, save; 3840 xmlEntityPtr ent; 3841 3842 dup = xmlStrdup(value); 3843 if (dup == NULL) 3844 return(0); 3845 cur = dup; 3846 while (*cur != 0) { 3847 nam = cur; 3848 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 3849 save = *cur; 3850 *cur = 0; 3851 ent = xmlGetDocEntity(doc, nam); 3852 if (ent == NULL) { 3853 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 3854 XML_DTD_UNKNOWN_ENTITY, 3855 "ENTITIES attribute %s reference an unknown entity \"%s\"\n", 3856 name, nam, NULL); 3857 ret = 0; 3858 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 3859 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 3860 XML_DTD_ENTITY_TYPE, 3861 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n", 3862 name, nam, NULL); 3863 ret = 0; 3864 } 3865 if (save == 0) 3866 break; 3867 *cur = save; 3868 while (IS_BLANK_CH(*cur)) cur++; 3869 } 3870 xmlFree(dup); 3871 break; 3872 } 3873 case XML_ATTRIBUTE_NOTATION: { 3874 xmlNotationPtr nota; 3875 3876 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 3877 if ((nota == NULL) && (doc->extSubset != NULL)) 3878 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 3879 3880 if (nota == NULL) { 3881 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 3882 XML_DTD_UNKNOWN_NOTATION, 3883 "NOTATION attribute %s reference an unknown notation \"%s\"\n", 3884 name, value, NULL); 3885 ret = 0; 3886 } 3887 break; 3888 } 3889 } 3890 return(ret); 3891} 3892 3893/** 3894 * xmlValidCtxtNormalizeAttributeValue: 3895 * @ctxt: the validation context 3896 * @doc: the document 3897 * @elem: the parent 3898 * @name: the attribute name 3899 * @value: the attribute value 3900 * @ctxt: the validation context or NULL 3901 * 3902 * Does the validation related extra step of the normalization of attribute 3903 * values: 3904 * 3905 * If the declared value is not CDATA, then the XML processor must further 3906 * process the normalized attribute value by discarding any leading and 3907 * trailing space (#x20) characters, and by replacing sequences of space 3908 * (#x20) characters by single space (#x20) character. 3909 * 3910 * Also check VC: Standalone Document Declaration in P32, and update 3911 * ctxt->valid accordingly 3912 * 3913 * returns a new normalized string if normalization is needed, NULL otherwise 3914 * the caller must free the returned value. 3915 */ 3916 3917xmlChar * 3918xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 3919 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { 3920 xmlChar *ret; 3921 xmlAttributePtr attrDecl = NULL; 3922 int extsubset = 0; 3923 3924 if (doc == NULL) return(NULL); 3925 if (elem == NULL) return(NULL); 3926 if (name == NULL) return(NULL); 3927 if (value == NULL) return(NULL); 3928 3929 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 3930 xmlChar fn[50]; 3931 xmlChar *fullname; 3932 3933 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 3934 if (fullname == NULL) 3935 return(NULL); 3936 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); 3937 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 3938 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); 3939 if (attrDecl != NULL) 3940 extsubset = 1; 3941 } 3942 if ((fullname != fn) && (fullname != elem->name)) 3943 xmlFree(fullname); 3944 } 3945 if ((attrDecl == NULL) && (doc->intSubset != NULL)) 3946 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); 3947 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 3948 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); 3949 if (attrDecl != NULL) 3950 extsubset = 1; 3951 } 3952 3953 if (attrDecl == NULL) 3954 return(NULL); 3955 if (attrDecl->atype == XML_ATTRIBUTE_CDATA) 3956 return(NULL); 3957 3958 ret = xmlStrdup(value); 3959 if (ret == NULL) 3960 return(NULL); 3961 xmlValidNormalizeString(ret); 3962 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { 3963 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE, 3964"standalone: %s on %s value had to be normalized based on external subset declaration\n", 3965 name, elem->name, NULL); 3966 ctxt->valid = 0; 3967 } 3968 return(ret); 3969} 3970 3971/** 3972 * xmlValidNormalizeAttributeValue: 3973 * @doc: the document 3974 * @elem: the parent 3975 * @name: the attribute name 3976 * @value: the attribute value 3977 * 3978 * Does the validation related extra step of the normalization of attribute 3979 * values: 3980 * 3981 * If the declared value is not CDATA, then the XML processor must further 3982 * process the normalized attribute value by discarding any leading and 3983 * trailing space (#x20) characters, and by replacing sequences of space 3984 * (#x20) characters by single space (#x20) character. 3985 * 3986 * Returns a new normalized string if normalization is needed, NULL otherwise 3987 * the caller must free the returned value. 3988 */ 3989 3990xmlChar * 3991xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, 3992 const xmlChar *name, const xmlChar *value) { 3993 xmlChar *ret; 3994 xmlAttributePtr attrDecl = NULL; 3995 3996 if (doc == NULL) return(NULL); 3997 if (elem == NULL) return(NULL); 3998 if (name == NULL) return(NULL); 3999 if (value == NULL) return(NULL); 4000 4001 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 4002 xmlChar fn[50]; 4003 xmlChar *fullname; 4004 4005 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 4006 if (fullname == NULL) 4007 return(NULL); 4008 if ((fullname != fn) && (fullname != elem->name)) 4009 xmlFree(fullname); 4010 } 4011 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); 4012 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4013 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); 4014 4015 if (attrDecl == NULL) 4016 return(NULL); 4017 if (attrDecl->atype == XML_ATTRIBUTE_CDATA) 4018 return(NULL); 4019 4020 ret = xmlStrdup(value); 4021 if (ret == NULL) 4022 return(NULL); 4023 xmlValidNormalizeString(ret); 4024 return(ret); 4025} 4026 4027static void 4028xmlValidateAttributeIdCallback(void *payload, void *data, 4029 const xmlChar *name ATTRIBUTE_UNUSED) { 4030 xmlAttributePtr attr = (xmlAttributePtr) payload; 4031 int *count = (int *) data; 4032 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++; 4033} 4034 4035/** 4036 * xmlValidateAttributeDecl: 4037 * @ctxt: the validation context 4038 * @doc: a document instance 4039 * @attr: an attribute definition 4040 * 4041 * Try to validate a single attribute definition 4042 * basically it does the following checks as described by the 4043 * XML-1.0 recommendation: 4044 * - [ VC: Attribute Default Legal ] 4045 * - [ VC: Enumeration ] 4046 * - [ VC: ID Attribute Default ] 4047 * 4048 * The ID/IDREF uniqueness and matching are done separately 4049 * 4050 * returns 1 if valid or 0 otherwise 4051 */ 4052 4053int 4054xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 4055 xmlAttributePtr attr) { 4056 int ret = 1; 4057 int val; 4058 CHECK_DTD; 4059 if(attr == NULL) return(1); 4060 4061 /* Attribute Default Legal */ 4062 /* Enumeration */ 4063 if (attr->defaultValue != NULL) { 4064 val = xmlValidateAttributeValueInternal(doc, attr->atype, 4065 attr->defaultValue); 4066 if (val == 0) { 4067 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT, 4068 "Syntax of default value for attribute %s of %s is not valid\n", 4069 attr->name, attr->elem, NULL); 4070 } 4071 ret &= val; 4072 } 4073 4074 /* ID Attribute Default */ 4075 if ((attr->atype == XML_ATTRIBUTE_ID)&& 4076 (attr->def != XML_ATTRIBUTE_IMPLIED) && 4077 (attr->def != XML_ATTRIBUTE_REQUIRED)) { 4078 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED, 4079 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n", 4080 attr->name, attr->elem, NULL); 4081 ret = 0; 4082 } 4083 4084 /* One ID per Element Type */ 4085 if (attr->atype == XML_ATTRIBUTE_ID) { 4086 int nbId; 4087 4088 /* the trick is that we parse DtD as their own internal subset */ 4089 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, 4090 attr->elem); 4091 if (elem != NULL) { 4092 nbId = xmlScanIDAttributeDecl(NULL, elem, 0); 4093 } else { 4094 xmlAttributeTablePtr table; 4095 4096 /* 4097 * The attribute may be declared in the internal subset and the 4098 * element in the external subset. 4099 */ 4100 nbId = 0; 4101 if (doc->intSubset != NULL) { 4102 table = (xmlAttributeTablePtr) doc->intSubset->attributes; 4103 xmlHashScan3(table, NULL, NULL, attr->elem, 4104 xmlValidateAttributeIdCallback, &nbId); 4105 } 4106 } 4107 if (nbId > 1) { 4108 4109 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 4110 "Element %s has %d ID attribute defined in the internal subset : %s\n", 4111 attr->elem, nbId, attr->name); 4112 } else if (doc->extSubset != NULL) { 4113 int extId = 0; 4114 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); 4115 if (elem != NULL) { 4116 extId = xmlScanIDAttributeDecl(NULL, elem, 0); 4117 } 4118 if (extId > 1) { 4119 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 4120 "Element %s has %d ID attribute defined in the external subset : %s\n", 4121 attr->elem, extId, attr->name); 4122 } else if (extId + nbId > 1) { 4123 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 4124"Element %s has ID attributes defined in the internal and external subset : %s\n", 4125 attr->elem, attr->name, NULL); 4126 } 4127 } 4128 } 4129 4130 /* Validity Constraint: Enumeration */ 4131 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) { 4132 xmlEnumerationPtr tree = attr->tree; 4133 while (tree != NULL) { 4134 if (xmlStrEqual(tree->name, attr->defaultValue)) break; 4135 tree = tree->next; 4136 } 4137 if (tree == NULL) { 4138 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE, 4139"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n", 4140 attr->defaultValue, attr->name, attr->elem); 4141 ret = 0; 4142 } 4143 } 4144 4145 return(ret); 4146} 4147 4148/** 4149 * xmlValidateElementDecl: 4150 * @ctxt: the validation context 4151 * @doc: a document instance 4152 * @elem: an element definition 4153 * 4154 * Try to validate a single element definition 4155 * basically it does the following checks as described by the 4156 * XML-1.0 recommendation: 4157 * - [ VC: One ID per Element Type ] 4158 * - [ VC: No Duplicate Types ] 4159 * - [ VC: Unique Element Type Declaration ] 4160 * 4161 * returns 1 if valid or 0 otherwise 4162 */ 4163 4164int 4165xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 4166 xmlElementPtr elem) { 4167 int ret = 1; 4168 xmlElementPtr tst; 4169 4170 CHECK_DTD; 4171 4172 if (elem == NULL) return(1); 4173 4174#if 0 4175#ifdef LIBXML_REGEXP_ENABLED 4176 /* Build the regexp associated to the content model */ 4177 ret = xmlValidBuildContentModel(ctxt, elem); 4178#endif 4179#endif 4180 4181 /* No Duplicate Types */ 4182 if (elem->etype == XML_ELEMENT_TYPE_MIXED) { 4183 xmlElementContentPtr cur, next; 4184 const xmlChar *name; 4185 4186 cur = elem->content; 4187 while (cur != NULL) { 4188 if (cur->type != XML_ELEMENT_CONTENT_OR) break; 4189 if (cur->c1 == NULL) break; 4190 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { 4191 name = cur->c1->name; 4192 next = cur->c2; 4193 while (next != NULL) { 4194 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) { 4195 if ((xmlStrEqual(next->name, name)) && 4196 (xmlStrEqual(next->prefix, cur->c1->prefix))) { 4197 if (cur->c1->prefix == NULL) { 4198 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 4199 "Definition of %s has duplicate references of %s\n", 4200 elem->name, name, NULL); 4201 } else { 4202 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 4203 "Definition of %s has duplicate references of %s:%s\n", 4204 elem->name, cur->c1->prefix, name); 4205 } 4206 ret = 0; 4207 } 4208 break; 4209 } 4210 if (next->c1 == NULL) break; 4211 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break; 4212 if ((xmlStrEqual(next->c1->name, name)) && 4213 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) { 4214 if (cur->c1->prefix == NULL) { 4215 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 4216 "Definition of %s has duplicate references to %s\n", 4217 elem->name, name, NULL); 4218 } else { 4219 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 4220 "Definition of %s has duplicate references to %s:%s\n", 4221 elem->name, cur->c1->prefix, name); 4222 } 4223 ret = 0; 4224 } 4225 next = next->c2; 4226 } 4227 } 4228 cur = cur->c2; 4229 } 4230 } 4231 4232 /* VC: Unique Element Type Declaration */ 4233 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name); 4234 if ((tst != NULL ) && (tst != elem) && 4235 ((tst->prefix == elem->prefix) || 4236 (xmlStrEqual(tst->prefix, elem->prefix))) && 4237 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { 4238 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, 4239 "Redefinition of element %s\n", 4240 elem->name, NULL, NULL); 4241 ret = 0; 4242 } 4243 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name); 4244 if ((tst != NULL ) && (tst != elem) && 4245 ((tst->prefix == elem->prefix) || 4246 (xmlStrEqual(tst->prefix, elem->prefix))) && 4247 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { 4248 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, 4249 "Redefinition of element %s\n", 4250 elem->name, NULL, NULL); 4251 ret = 0; 4252 } 4253 /* One ID per Element Type 4254 * already done when registering the attribute 4255 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { 4256 ret = 0; 4257 } */ 4258 return(ret); 4259} 4260 4261/** 4262 * xmlValidateOneAttribute: 4263 * @ctxt: the validation context 4264 * @doc: a document instance 4265 * @elem: an element instance 4266 * @attr: an attribute instance 4267 * @value: the attribute value (without entities processing) 4268 * 4269 * Try to validate a single attribute for an element 4270 * basically it does the following checks as described by the 4271 * XML-1.0 recommendation: 4272 * - [ VC: Attribute Value Type ] 4273 * - [ VC: Fixed Attribute Default ] 4274 * - [ VC: Entity Name ] 4275 * - [ VC: Name Token ] 4276 * - [ VC: ID ] 4277 * - [ VC: IDREF ] 4278 * - [ VC: Entity Name ] 4279 * - [ VC: Notation Attributes ] 4280 * 4281 * The ID/IDREF uniqueness and matching are done separately 4282 * 4283 * returns 1 if valid or 0 otherwise 4284 */ 4285 4286int 4287xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 4288 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) 4289{ 4290 xmlAttributePtr attrDecl = NULL; 4291 int val; 4292 int ret = 1; 4293 4294 CHECK_DTD; 4295 if ((elem == NULL) || (elem->name == NULL)) return(0); 4296 if ((attr == NULL) || (attr->name == NULL)) return(0); 4297 4298 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 4299 xmlChar fn[50]; 4300 xmlChar *fullname; 4301 4302 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 4303 if (fullname == NULL) 4304 return(0); 4305 if (attr->ns != NULL) { 4306 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, 4307 attr->name, attr->ns->prefix); 4308 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4309 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, 4310 attr->name, attr->ns->prefix); 4311 } else { 4312 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name); 4313 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4314 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 4315 fullname, attr->name); 4316 } 4317 if ((fullname != fn) && (fullname != elem->name)) 4318 xmlFree(fullname); 4319 } 4320 if (attrDecl == NULL) { 4321 if (attr->ns != NULL) { 4322 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, 4323 attr->name, attr->ns->prefix); 4324 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4325 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, 4326 attr->name, attr->ns->prefix); 4327 } else { 4328 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, 4329 elem->name, attr->name); 4330 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4331 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 4332 elem->name, attr->name); 4333 } 4334 } 4335 4336 4337 /* Validity Constraint: Attribute Value Type */ 4338 if (attrDecl == NULL) { 4339 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 4340 "No declaration for attribute %s of element %s\n", 4341 attr->name, elem->name, NULL); 4342 return(0); 4343 } 4344 attr->atype = attrDecl->atype; 4345 4346 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); 4347 if (val == 0) { 4348 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 4349 "Syntax of value for attribute %s of %s is not valid\n", 4350 attr->name, elem->name, NULL); 4351 ret = 0; 4352 } 4353 4354 /* Validity constraint: Fixed Attribute Default */ 4355 if (attrDecl->def == XML_ATTRIBUTE_FIXED) { 4356 if (!xmlStrEqual(value, attrDecl->defaultValue)) { 4357 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 4358 "Value for attribute %s of %s is different from default \"%s\"\n", 4359 attr->name, elem->name, attrDecl->defaultValue); 4360 ret = 0; 4361 } 4362 } 4363 4364 /* Validity Constraint: ID uniqueness */ 4365 if (attrDecl->atype == XML_ATTRIBUTE_ID) { 4366 if (xmlAddID(ctxt, doc, value, attr) == NULL) 4367 ret = 0; 4368 } 4369 4370 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || 4371 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { 4372 if (xmlAddRef(ctxt, doc, value, attr) == NULL) 4373 ret = 0; 4374 } 4375 4376 /* Validity Constraint: Notation Attributes */ 4377 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { 4378 xmlEnumerationPtr tree = attrDecl->tree; 4379 xmlNotationPtr nota; 4380 4381 /* First check that the given NOTATION was declared */ 4382 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 4383 if (nota == NULL) 4384 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 4385 4386 if (nota == NULL) { 4387 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 4388 "Value \"%s\" for attribute %s of %s is not a declared Notation\n", 4389 value, attr->name, elem->name); 4390 ret = 0; 4391 } 4392 4393 /* Second, verify that it's among the list */ 4394 while (tree != NULL) { 4395 if (xmlStrEqual(tree->name, value)) break; 4396 tree = tree->next; 4397 } 4398 if (tree == NULL) { 4399 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 4400"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n", 4401 value, attr->name, elem->name); 4402 ret = 0; 4403 } 4404 } 4405 4406 /* Validity Constraint: Enumeration */ 4407 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { 4408 xmlEnumerationPtr tree = attrDecl->tree; 4409 while (tree != NULL) { 4410 if (xmlStrEqual(tree->name, value)) break; 4411 tree = tree->next; 4412 } 4413 if (tree == NULL) { 4414 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 4415 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n", 4416 value, attr->name, elem->name); 4417 ret = 0; 4418 } 4419 } 4420 4421 /* Fixed Attribute Default */ 4422 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && 4423 (!xmlStrEqual(attrDecl->defaultValue, value))) { 4424 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 4425 "Value for attribute %s of %s must be \"%s\"\n", 4426 attr->name, elem->name, attrDecl->defaultValue); 4427 ret = 0; 4428 } 4429 4430 /* Extra check for the attribute value */ 4431 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name, 4432 attrDecl->atype, value); 4433 4434 return(ret); 4435} 4436 4437/** 4438 * xmlValidateOneNamespace: 4439 * @ctxt: the validation context 4440 * @doc: a document instance 4441 * @elem: an element instance 4442 * @prefix: the namespace prefix 4443 * @ns: an namespace declaration instance 4444 * @value: the attribute value (without entities processing) 4445 * 4446 * Try to validate a single namespace declaration for an element 4447 * basically it does the following checks as described by the 4448 * XML-1.0 recommendation: 4449 * - [ VC: Attribute Value Type ] 4450 * - [ VC: Fixed Attribute Default ] 4451 * - [ VC: Entity Name ] 4452 * - [ VC: Name Token ] 4453 * - [ VC: ID ] 4454 * - [ VC: IDREF ] 4455 * - [ VC: Entity Name ] 4456 * - [ VC: Notation Attributes ] 4457 * 4458 * The ID/IDREF uniqueness and matching are done separately 4459 * 4460 * returns 1 if valid or 0 otherwise 4461 */ 4462 4463int 4464xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 4465xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { 4466 /* xmlElementPtr elemDecl; */ 4467 xmlAttributePtr attrDecl = NULL; 4468 int val; 4469 int ret = 1; 4470 4471 CHECK_DTD; 4472 if ((elem == NULL) || (elem->name == NULL)) return(0); 4473 if ((ns == NULL) || (ns->href == NULL)) return(0); 4474 4475 if (prefix != NULL) { 4476 xmlChar fn[50]; 4477 xmlChar *fullname; 4478 4479 fullname = xmlBuildQName(elem->name, prefix, fn, 50); 4480 if (fullname == NULL) { 4481 xmlVErrMemory(ctxt, "Validating namespace"); 4482 return(0); 4483 } 4484 if (ns->prefix != NULL) { 4485 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, 4486 ns->prefix, BAD_CAST "xmlns"); 4487 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4488 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, 4489 ns->prefix, BAD_CAST "xmlns"); 4490 } else { 4491 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, 4492 BAD_CAST "xmlns"); 4493 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4494 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, 4495 BAD_CAST "xmlns"); 4496 } 4497 if ((fullname != fn) && (fullname != elem->name)) 4498 xmlFree(fullname); 4499 } 4500 if (attrDecl == NULL) { 4501 if (ns->prefix != NULL) { 4502 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, 4503 ns->prefix, BAD_CAST "xmlns"); 4504 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4505 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, 4506 ns->prefix, BAD_CAST "xmlns"); 4507 } else { 4508 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, 4509 elem->name, BAD_CAST "xmlns"); 4510 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 4511 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 4512 elem->name, BAD_CAST "xmlns"); 4513 } 4514 } 4515 4516 4517 /* Validity Constraint: Attribute Value Type */ 4518 if (attrDecl == NULL) { 4519 if (ns->prefix != NULL) { 4520 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 4521 "No declaration for attribute xmlns:%s of element %s\n", 4522 ns->prefix, elem->name, NULL); 4523 } else { 4524 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 4525 "No declaration for attribute xmlns of element %s\n", 4526 elem->name, NULL, NULL); 4527 } 4528 return(0); 4529 } 4530 4531 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); 4532 if (val == 0) { 4533 if (ns->prefix != NULL) { 4534 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, 4535 "Syntax of value for attribute xmlns:%s of %s is not valid\n", 4536 ns->prefix, elem->name, NULL); 4537 } else { 4538 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, 4539 "Syntax of value for attribute xmlns of %s is not valid\n", 4540 elem->name, NULL, NULL); 4541 } 4542 ret = 0; 4543 } 4544 4545 /* Validity constraint: Fixed Attribute Default */ 4546 if (attrDecl->def == XML_ATTRIBUTE_FIXED) { 4547 if (!xmlStrEqual(value, attrDecl->defaultValue)) { 4548 if (ns->prefix != NULL) { 4549 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 4550 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n", 4551 ns->prefix, elem->name, attrDecl->defaultValue); 4552 } else { 4553 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 4554 "Value for attribute xmlns of %s is different from default \"%s\"\n", 4555 elem->name, attrDecl->defaultValue, NULL); 4556 } 4557 ret = 0; 4558 } 4559 } 4560 4561 /* 4562 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions 4563 * xmlAddID and xmlAddRef for namespace declarations, but it makes 4564 * no practical sense to use ID types anyway. 4565 */ 4566#if 0 4567 /* Validity Constraint: ID uniqueness */ 4568 if (attrDecl->atype == XML_ATTRIBUTE_ID) { 4569 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) 4570 ret = 0; 4571 } 4572 4573 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || 4574 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { 4575 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) 4576 ret = 0; 4577 } 4578#endif 4579 4580 /* Validity Constraint: Notation Attributes */ 4581 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { 4582 xmlEnumerationPtr tree = attrDecl->tree; 4583 xmlNotationPtr nota; 4584 4585 /* First check that the given NOTATION was declared */ 4586 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 4587 if (nota == NULL) 4588 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 4589 4590 if (nota == NULL) { 4591 if (ns->prefix != NULL) { 4592 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 4593 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n", 4594 value, ns->prefix, elem->name); 4595 } else { 4596 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 4597 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n", 4598 value, elem->name, NULL); 4599 } 4600 ret = 0; 4601 } 4602 4603 /* Second, verify that it's among the list */ 4604 while (tree != NULL) { 4605 if (xmlStrEqual(tree->name, value)) break; 4606 tree = tree->next; 4607 } 4608 if (tree == NULL) { 4609 if (ns->prefix != NULL) { 4610 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 4611"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n", 4612 value, ns->prefix, elem->name); 4613 } else { 4614 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 4615"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n", 4616 value, elem->name, NULL); 4617 } 4618 ret = 0; 4619 } 4620 } 4621 4622 /* Validity Constraint: Enumeration */ 4623 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { 4624 xmlEnumerationPtr tree = attrDecl->tree; 4625 while (tree != NULL) { 4626 if (xmlStrEqual(tree->name, value)) break; 4627 tree = tree->next; 4628 } 4629 if (tree == NULL) { 4630 if (ns->prefix != NULL) { 4631 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 4632"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n", 4633 value, ns->prefix, elem->name); 4634 } else { 4635 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 4636"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n", 4637 value, elem->name, NULL); 4638 } 4639 ret = 0; 4640 } 4641 } 4642 4643 /* Fixed Attribute Default */ 4644 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && 4645 (!xmlStrEqual(attrDecl->defaultValue, value))) { 4646 if (ns->prefix != NULL) { 4647 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 4648 "Value for attribute xmlns:%s of %s must be \"%s\"\n", 4649 ns->prefix, elem->name, attrDecl->defaultValue); 4650 } else { 4651 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 4652 "Value for attribute xmlns of %s must be \"%s\"\n", 4653 elem->name, attrDecl->defaultValue, NULL); 4654 } 4655 ret = 0; 4656 } 4657 4658 /* Extra check for the attribute value */ 4659 if (ns->prefix != NULL) { 4660 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix, 4661 attrDecl->atype, value); 4662 } else { 4663 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns", 4664 attrDecl->atype, value); 4665 } 4666 4667 return(ret); 4668} 4669 4670#ifndef LIBXML_REGEXP_ENABLED 4671/** 4672 * xmlValidateSkipIgnorable: 4673 * @ctxt: the validation context 4674 * @child: the child list 4675 * 4676 * Skip ignorable elements w.r.t. the validation process 4677 * 4678 * returns the first element to consider for validation of the content model 4679 */ 4680 4681static xmlNodePtr 4682xmlValidateSkipIgnorable(xmlNodePtr child) { 4683 while (child != NULL) { 4684 switch (child->type) { 4685 /* These things are ignored (skipped) during validation. */ 4686 case XML_PI_NODE: 4687 case XML_COMMENT_NODE: 4688 case XML_XINCLUDE_START: 4689 case XML_XINCLUDE_END: 4690 child = child->next; 4691 break; 4692 case XML_TEXT_NODE: 4693 if (xmlIsBlankNode(child)) 4694 child = child->next; 4695 else 4696 return(child); 4697 break; 4698 /* keep current node */ 4699 default: 4700 return(child); 4701 } 4702 } 4703 return(child); 4704} 4705 4706/** 4707 * xmlValidateElementType: 4708 * @ctxt: the validation context 4709 * 4710 * Try to validate the content model of an element internal function 4711 * 4712 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity 4713 * reference is found and -3 if the validation succeeded but 4714 * the content model is not determinist. 4715 */ 4716 4717static int 4718xmlValidateElementType(xmlValidCtxtPtr ctxt) { 4719 int ret = -1; 4720 int determinist = 1; 4721 4722 NODE = xmlValidateSkipIgnorable(NODE); 4723 if ((NODE == NULL) && (CONT == NULL)) 4724 return(1); 4725 if ((NODE == NULL) && 4726 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || 4727 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) { 4728 return(1); 4729 } 4730 if (CONT == NULL) return(-1); 4731 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) 4732 return(-2); 4733 4734 /* 4735 * We arrive here when more states need to be examined 4736 */ 4737cont: 4738 4739 /* 4740 * We just recovered from a rollback generated by a possible 4741 * epsilon transition, go directly to the analysis phase 4742 */ 4743 if (STATE == ROLLBACK_PARENT) { 4744 ret = 1; 4745 goto analyze; 4746 } 4747 4748 /* 4749 * we may have to save a backup state here. This is the equivalent 4750 * of handling epsilon transition in NFAs. 4751 */ 4752 if ((CONT != NULL) && 4753 ((CONT->parent == NULL) || 4754 (CONT->parent == (xmlElementContentPtr) 1) || 4755 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) && 4756 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || 4757 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) || 4758 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) { 4759 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0) 4760 return(0); 4761 } 4762 4763 4764 /* 4765 * Check first if the content matches 4766 */ 4767 switch (CONT->type) { 4768 case XML_ELEMENT_CONTENT_PCDATA: 4769 if (NODE == NULL) { 4770 ret = 0; 4771 break; 4772 } 4773 if (NODE->type == XML_TEXT_NODE) { 4774 /* 4775 * go to next element in the content model 4776 * skipping ignorable elems 4777 */ 4778 do { 4779 NODE = NODE->next; 4780 NODE = xmlValidateSkipIgnorable(NODE); 4781 if ((NODE != NULL) && 4782 (NODE->type == XML_ENTITY_REF_NODE)) 4783 return(-2); 4784 } while ((NODE != NULL) && 4785 ((NODE->type != XML_ELEMENT_NODE) && 4786 (NODE->type != XML_TEXT_NODE) && 4787 (NODE->type != XML_CDATA_SECTION_NODE))); 4788 ret = 1; 4789 break; 4790 } else { 4791 ret = 0; 4792 break; 4793 } 4794 break; 4795 case XML_ELEMENT_CONTENT_ELEMENT: 4796 if (NODE == NULL) { 4797 ret = 0; 4798 break; 4799 } 4800 ret = ((NODE->type == XML_ELEMENT_NODE) && 4801 (xmlStrEqual(NODE->name, CONT->name))); 4802 if (ret == 1) { 4803 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 4804 ret = (CONT->prefix == NULL); 4805 } else if (CONT->prefix == NULL) { 4806 ret = 0; 4807 } else { 4808 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix); 4809 } 4810 } 4811 if (ret == 1) { 4812 /* 4813 * go to next element in the content model 4814 * skipping ignorable elems 4815 */ 4816 do { 4817 NODE = NODE->next; 4818 NODE = xmlValidateSkipIgnorable(NODE); 4819 if ((NODE != NULL) && 4820 (NODE->type == XML_ENTITY_REF_NODE)) 4821 return(-2); 4822 } while ((NODE != NULL) && 4823 ((NODE->type != XML_ELEMENT_NODE) && 4824 (NODE->type != XML_TEXT_NODE) && 4825 (NODE->type != XML_CDATA_SECTION_NODE))); 4826 } else { 4827 ret = 0; 4828 break; 4829 } 4830 break; 4831 case XML_ELEMENT_CONTENT_OR: 4832 /* 4833 * Small optimization. 4834 */ 4835 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { 4836 if ((NODE == NULL) || 4837 (!xmlStrEqual(NODE->name, CONT->c1->name))) { 4838 DEPTH++; 4839 CONT = CONT->c2; 4840 goto cont; 4841 } 4842 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 4843 ret = (CONT->c1->prefix == NULL); 4844 } else if (CONT->c1->prefix == NULL) { 4845 ret = 0; 4846 } else { 4847 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); 4848 } 4849 if (ret == 0) { 4850 DEPTH++; 4851 CONT = CONT->c2; 4852 goto cont; 4853 } 4854 } 4855 4856 /* 4857 * save the second branch 'or' branch 4858 */ 4859 if (vstateVPush(ctxt, CONT->c2, NODE, DEPTH + 1, 4860 OCCURS, ROLLBACK_OR) < 0) 4861 return(-1); 4862 DEPTH++; 4863 CONT = CONT->c1; 4864 goto cont; 4865 case XML_ELEMENT_CONTENT_SEQ: 4866 /* 4867 * Small optimization. 4868 */ 4869 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) && 4870 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) || 4871 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) { 4872 if ((NODE == NULL) || 4873 (!xmlStrEqual(NODE->name, CONT->c1->name))) { 4874 DEPTH++; 4875 CONT = CONT->c2; 4876 goto cont; 4877 } 4878 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 4879 ret = (CONT->c1->prefix == NULL); 4880 } else if (CONT->c1->prefix == NULL) { 4881 ret = 0; 4882 } else { 4883 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); 4884 } 4885 if (ret == 0) { 4886 DEPTH++; 4887 CONT = CONT->c2; 4888 goto cont; 4889 } 4890 } 4891 DEPTH++; 4892 CONT = CONT->c1; 4893 goto cont; 4894 } 4895 4896 /* 4897 * At this point handle going up in the tree 4898 */ 4899 if (ret == -1) { 4900 return(ret); 4901 } 4902analyze: 4903 while (CONT != NULL) { 4904 /* 4905 * First do the analysis depending on the occurrence model at 4906 * this level. 4907 */ 4908 if (ret == 0) { 4909 switch (CONT->ocur) { 4910 xmlNodePtr cur; 4911 4912 case XML_ELEMENT_CONTENT_ONCE: 4913 cur = ctxt->vstate->node; 4914 if (vstateVPop(ctxt) < 0 ) { 4915 return(0); 4916 } 4917 if (cur != ctxt->vstate->node) 4918 determinist = -3; 4919 goto cont; 4920 case XML_ELEMENT_CONTENT_PLUS: 4921 if (OCCURRENCE == 0) { 4922 cur = ctxt->vstate->node; 4923 if (vstateVPop(ctxt) < 0 ) { 4924 return(0); 4925 } 4926 if (cur != ctxt->vstate->node) 4927 determinist = -3; 4928 goto cont; 4929 } 4930 ret = 1; 4931 break; 4932 case XML_ELEMENT_CONTENT_MULT: 4933 ret = 1; 4934 break; 4935 case XML_ELEMENT_CONTENT_OPT: 4936 ret = 1; 4937 break; 4938 } 4939 } else { 4940 switch (CONT->ocur) { 4941 case XML_ELEMENT_CONTENT_OPT: 4942 ret = 1; 4943 break; 4944 case XML_ELEMENT_CONTENT_ONCE: 4945 ret = 1; 4946 break; 4947 case XML_ELEMENT_CONTENT_PLUS: 4948 if (STATE == ROLLBACK_PARENT) { 4949 ret = 1; 4950 break; 4951 } 4952 if (NODE == NULL) { 4953 ret = 1; 4954 break; 4955 } 4956 SET_OCCURRENCE; 4957 goto cont; 4958 case XML_ELEMENT_CONTENT_MULT: 4959 if (STATE == ROLLBACK_PARENT) { 4960 ret = 1; 4961 break; 4962 } 4963 if (NODE == NULL) { 4964 ret = 1; 4965 break; 4966 } 4967 /* SET_OCCURRENCE; */ 4968 goto cont; 4969 } 4970 } 4971 STATE = 0; 4972 4973 /* 4974 * Then act accordingly at the parent level 4975 */ 4976 RESET_OCCURRENCE; 4977 if ((CONT->parent == NULL) || 4978 (CONT->parent == (xmlElementContentPtr) 1)) 4979 break; 4980 4981 switch (CONT->parent->type) { 4982 case XML_ELEMENT_CONTENT_PCDATA: 4983 return(-1); 4984 case XML_ELEMENT_CONTENT_ELEMENT: 4985 return(-1); 4986 case XML_ELEMENT_CONTENT_OR: 4987 if (ret == 1) { 4988 CONT = CONT->parent; 4989 DEPTH--; 4990 } else { 4991 CONT = CONT->parent; 4992 DEPTH--; 4993 } 4994 break; 4995 case XML_ELEMENT_CONTENT_SEQ: 4996 if (ret == 0) { 4997 CONT = CONT->parent; 4998 DEPTH--; 4999 } else if (CONT == CONT->parent->c1) { 5000 CONT = CONT->parent->c2; 5001 goto cont; 5002 } else { 5003 CONT = CONT->parent; 5004 DEPTH--; 5005 } 5006 } 5007 } 5008 if (NODE != NULL) { 5009 xmlNodePtr cur; 5010 5011 cur = ctxt->vstate->node; 5012 if (vstateVPop(ctxt) < 0 ) { 5013 return(0); 5014 } 5015 if (cur != ctxt->vstate->node) 5016 determinist = -3; 5017 goto cont; 5018 } 5019 if (ret == 0) { 5020 xmlNodePtr cur; 5021 5022 cur = ctxt->vstate->node; 5023 if (vstateVPop(ctxt) < 0 ) { 5024 return(0); 5025 } 5026 if (cur != ctxt->vstate->node) 5027 determinist = -3; 5028 goto cont; 5029 } 5030 return(determinist); 5031} 5032#endif 5033 5034/** 5035 * xmlSnprintfElements: 5036 * @buf: an output buffer 5037 * @size: the size of the buffer 5038 * @content: An element 5039 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise 5040 * 5041 * This will dump the list of elements to the buffer 5042 * Intended just for the debug routine 5043 */ 5044static void 5045xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) { 5046 xmlNodePtr cur; 5047 int len; 5048 5049 if (node == NULL) return; 5050 if (glob) strcat(buf, "("); 5051 cur = node; 5052 while (cur != NULL) { 5053 len = strlen(buf); 5054 if (size - len < 50) { 5055 if ((size - len > 4) && (buf[len - 1] != '.')) 5056 strcat(buf, " ..."); 5057 return; 5058 } 5059 switch (cur->type) { 5060 case XML_ELEMENT_NODE: 5061 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 5062 if (size - len < xmlStrlen(cur->ns->prefix) + 10) { 5063 if ((size - len > 4) && (buf[len - 1] != '.')) 5064 strcat(buf, " ..."); 5065 return; 5066 } 5067 strcat(buf, (char *) cur->ns->prefix); 5068 strcat(buf, ":"); 5069 } 5070 if (size - len < xmlStrlen(cur->name) + 10) { 5071 if ((size - len > 4) && (buf[len - 1] != '.')) 5072 strcat(buf, " ..."); 5073 return; 5074 } 5075 strcat(buf, (char *) cur->name); 5076 if (cur->next != NULL) 5077 strcat(buf, " "); 5078 break; 5079 case XML_TEXT_NODE: 5080 if (xmlIsBlankNode(cur)) 5081 break; 5082 /* Falls through. */ 5083 case XML_CDATA_SECTION_NODE: 5084 case XML_ENTITY_REF_NODE: 5085 strcat(buf, "CDATA"); 5086 if (cur->next != NULL) 5087 strcat(buf, " "); 5088 break; 5089 case XML_ATTRIBUTE_NODE: 5090 case XML_DOCUMENT_NODE: 5091 case XML_HTML_DOCUMENT_NODE: 5092 case XML_DOCUMENT_TYPE_NODE: 5093 case XML_DOCUMENT_FRAG_NODE: 5094 case XML_NOTATION_NODE: 5095 case XML_NAMESPACE_DECL: 5096 strcat(buf, "???"); 5097 if (cur->next != NULL) 5098 strcat(buf, " "); 5099 break; 5100 case XML_ENTITY_NODE: 5101 case XML_PI_NODE: 5102 case XML_DTD_NODE: 5103 case XML_COMMENT_NODE: 5104 case XML_ELEMENT_DECL: 5105 case XML_ATTRIBUTE_DECL: 5106 case XML_ENTITY_DECL: 5107 case XML_XINCLUDE_START: 5108 case XML_XINCLUDE_END: 5109 break; 5110 } 5111 cur = cur->next; 5112 } 5113 if (glob) strcat(buf, ")"); 5114} 5115 5116/** 5117 * xmlValidateElementContent: 5118 * @ctxt: the validation context 5119 * @child: the child list 5120 * @elemDecl: pointer to the element declaration 5121 * @warn: emit the error message 5122 * @parent: the parent element (for error reporting) 5123 * 5124 * Try to validate the content model of an element 5125 * 5126 * returns 1 if valid or 0 if not and -1 in case of error 5127 */ 5128 5129static int 5130xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, 5131 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) { 5132 int ret = 1; 5133#ifndef LIBXML_REGEXP_ENABLED 5134 xmlNodePtr repl = NULL, last = NULL, tmp; 5135#endif 5136 xmlNodePtr cur; 5137 xmlElementContentPtr cont; 5138 const xmlChar *name; 5139 5140 if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL)) 5141 return(-1); 5142 cont = elemDecl->content; 5143 name = elemDecl->name; 5144 5145#ifdef LIBXML_REGEXP_ENABLED 5146 /* Build the regexp associated to the content model */ 5147 if (elemDecl->contModel == NULL) 5148 ret = xmlValidBuildContentModel(ctxt, elemDecl); 5149 if (elemDecl->contModel == NULL) { 5150 return(-1); 5151 } else { 5152 xmlRegExecCtxtPtr exec; 5153 5154 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) { 5155 return(-1); 5156 } 5157 ctxt->nodeMax = 0; 5158 ctxt->nodeNr = 0; 5159 ctxt->nodeTab = NULL; 5160 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); 5161 if (exec != NULL) { 5162 cur = child; 5163 while (cur != NULL) { 5164 switch (cur->type) { 5165 case XML_ENTITY_REF_NODE: 5166 /* 5167 * Push the current node to be able to roll back 5168 * and process within the entity 5169 */ 5170 if ((cur->children != NULL) && 5171 (cur->children->children != NULL)) { 5172 nodeVPush(ctxt, cur); 5173 cur = cur->children->children; 5174 continue; 5175 } 5176 break; 5177 case XML_TEXT_NODE: 5178 if (xmlIsBlankNode(cur)) 5179 break; 5180 ret = 0; 5181 goto fail; 5182 case XML_CDATA_SECTION_NODE: 5183 /* TODO */ 5184 ret = 0; 5185 goto fail; 5186 case XML_ELEMENT_NODE: 5187 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 5188 xmlChar fn[50]; 5189 xmlChar *fullname; 5190 5191 fullname = xmlBuildQName(cur->name, 5192 cur->ns->prefix, fn, 50); 5193 if (fullname == NULL) { 5194 ret = -1; 5195 goto fail; 5196 } 5197 ret = xmlRegExecPushString(exec, fullname, NULL); 5198 if ((fullname != fn) && (fullname != cur->name)) 5199 xmlFree(fullname); 5200 } else { 5201 ret = xmlRegExecPushString(exec, cur->name, NULL); 5202 } 5203 break; 5204 default: 5205 break; 5206 } 5207 /* 5208 * Switch to next element 5209 */ 5210 cur = cur->next; 5211 while (cur == NULL) { 5212 cur = nodeVPop(ctxt); 5213 if (cur == NULL) 5214 break; 5215 cur = cur->next; 5216 } 5217 } 5218 ret = xmlRegExecPushString(exec, NULL, NULL); 5219fail: 5220 xmlRegFreeExecCtxt(exec); 5221 } 5222 } 5223#else /* LIBXML_REGEXP_ENABLED */ 5224 /* 5225 * Allocate the stack 5226 */ 5227 ctxt->vstateMax = 8; 5228 ctxt->vstateTab = (xmlValidState *) xmlMalloc( 5229 ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 5230 if (ctxt->vstateTab == NULL) { 5231 xmlVErrMemory(ctxt, "malloc failed"); 5232 return(-1); 5233 } 5234 /* 5235 * The first entry in the stack is reserved to the current state 5236 */ 5237 ctxt->nodeMax = 0; 5238 ctxt->nodeNr = 0; 5239 ctxt->nodeTab = NULL; 5240 ctxt->vstate = &ctxt->vstateTab[0]; 5241 ctxt->vstateNr = 1; 5242 CONT = cont; 5243 NODE = child; 5244 DEPTH = 0; 5245 OCCURS = 0; 5246 STATE = 0; 5247 ret = xmlValidateElementType(ctxt); 5248 if ((ret == -3) && (warn)) { 5249 char expr[5000]; 5250 expr[0] = 0; 5251 xmlSnprintfElementContent(expr, 5000, elemDecl->content, 1); 5252 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, 5253 XML_DTD_CONTENT_NOT_DETERMINIST, 5254 "Content model of %s is not deterministic: %s\n", 5255 name, BAD_CAST expr, NULL); 5256 } else if (ret == -2) { 5257 /* 5258 * An entities reference appeared at this level. 5259 * Build a minimal representation of this node content 5260 * sufficient to run the validation process on it 5261 */ 5262 cur = child; 5263 while (cur != NULL) { 5264 switch (cur->type) { 5265 case XML_ENTITY_REF_NODE: 5266 /* 5267 * Push the current node to be able to roll back 5268 * and process within the entity 5269 */ 5270 if ((cur->children != NULL) && 5271 (cur->children->children != NULL)) { 5272 nodeVPush(ctxt, cur); 5273 cur = cur->children->children; 5274 continue; 5275 } 5276 break; 5277 case XML_TEXT_NODE: 5278 if (xmlIsBlankNode(cur)) 5279 break; 5280 /* no break on purpose */ 5281 case XML_CDATA_SECTION_NODE: 5282 /* no break on purpose */ 5283 case XML_ELEMENT_NODE: 5284 /* 5285 * Allocate a new node and minimally fills in 5286 * what's required 5287 */ 5288 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 5289 if (tmp == NULL) { 5290 xmlVErrMemory(ctxt, "malloc failed"); 5291 xmlFreeNodeList(repl); 5292 ret = -1; 5293 goto done; 5294 } 5295 tmp->type = cur->type; 5296 tmp->name = cur->name; 5297 tmp->ns = cur->ns; 5298 tmp->next = NULL; 5299 tmp->content = NULL; 5300 if (repl == NULL) 5301 repl = last = tmp; 5302 else { 5303 last->next = tmp; 5304 last = tmp; 5305 } 5306 if (cur->type == XML_CDATA_SECTION_NODE) { 5307 /* 5308 * E59 spaces in CDATA does not match the 5309 * nonterminal S 5310 */ 5311 tmp->content = xmlStrdup(BAD_CAST "CDATA"); 5312 } 5313 break; 5314 default: 5315 break; 5316 } 5317 /* 5318 * Switch to next element 5319 */ 5320 cur = cur->next; 5321 while (cur == NULL) { 5322 cur = nodeVPop(ctxt); 5323 if (cur == NULL) 5324 break; 5325 cur = cur->next; 5326 } 5327 } 5328 5329 /* 5330 * Relaunch the validation 5331 */ 5332 ctxt->vstate = &ctxt->vstateTab[0]; 5333 ctxt->vstateNr = 1; 5334 CONT = cont; 5335 NODE = repl; 5336 DEPTH = 0; 5337 OCCURS = 0; 5338 STATE = 0; 5339 ret = xmlValidateElementType(ctxt); 5340 } 5341#endif /* LIBXML_REGEXP_ENABLED */ 5342 if ((warn) && ((ret != 1) && (ret != -3))) { 5343 if (ctxt != NULL) { 5344 char expr[5000]; 5345 char list[5000]; 5346 5347 expr[0] = 0; 5348 xmlSnprintfElementContent(&expr[0], 5000, cont, 1); 5349 list[0] = 0; 5350#ifndef LIBXML_REGEXP_ENABLED 5351 if (repl != NULL) 5352 xmlSnprintfElements(&list[0], 5000, repl, 1); 5353 else 5354#endif /* LIBXML_REGEXP_ENABLED */ 5355 xmlSnprintfElements(&list[0], 5000, child, 1); 5356 5357 if (name != NULL) { 5358 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 5359 "Element %s content does not follow the DTD, expecting %s, got %s\n", 5360 name, BAD_CAST expr, BAD_CAST list); 5361 } else { 5362 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 5363 "Element content does not follow the DTD, expecting %s, got %s\n", 5364 BAD_CAST expr, BAD_CAST list, NULL); 5365 } 5366 } else { 5367 if (name != NULL) { 5368 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 5369 "Element %s content does not follow the DTD\n", 5370 name, NULL, NULL); 5371 } else { 5372 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 5373 "Element content does not follow the DTD\n", 5374 NULL, NULL, NULL); 5375 } 5376 } 5377 ret = 0; 5378 } 5379 if (ret == -3) 5380 ret = 1; 5381 5382#ifndef LIBXML_REGEXP_ENABLED 5383done: 5384 /* 5385 * Deallocate the copy if done, and free up the validation stack 5386 */ 5387 while (repl != NULL) { 5388 tmp = repl->next; 5389 xmlFree(repl); 5390 repl = tmp; 5391 } 5392 ctxt->vstateMax = 0; 5393 if (ctxt->vstateTab != NULL) { 5394 xmlFree(ctxt->vstateTab); 5395 ctxt->vstateTab = NULL; 5396 } 5397#endif 5398 ctxt->nodeMax = 0; 5399 ctxt->nodeNr = 0; 5400 if (ctxt->nodeTab != NULL) { 5401 xmlFree(ctxt->nodeTab); 5402 ctxt->nodeTab = NULL; 5403 } 5404 return(ret); 5405 5406} 5407 5408/** 5409 * xmlValidateCdataElement: 5410 * @ctxt: the validation context 5411 * @doc: a document instance 5412 * @elem: an element instance 5413 * 5414 * Check that an element follows #CDATA 5415 * 5416 * returns 1 if valid or 0 otherwise 5417 */ 5418static int 5419xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5420 xmlNodePtr elem) { 5421 int ret = 1; 5422 xmlNodePtr cur, child; 5423 5424 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) || 5425 (elem->type != XML_ELEMENT_NODE)) 5426 return(0); 5427 5428 child = elem->children; 5429 5430 cur = child; 5431 while (cur != NULL) { 5432 switch (cur->type) { 5433 case XML_ENTITY_REF_NODE: 5434 /* 5435 * Push the current node to be able to roll back 5436 * and process within the entity 5437 */ 5438 if ((cur->children != NULL) && 5439 (cur->children->children != NULL)) { 5440 nodeVPush(ctxt, cur); 5441 cur = cur->children->children; 5442 continue; 5443 } 5444 break; 5445 case XML_COMMENT_NODE: 5446 case XML_PI_NODE: 5447 case XML_TEXT_NODE: 5448 case XML_CDATA_SECTION_NODE: 5449 break; 5450 default: 5451 ret = 0; 5452 goto done; 5453 } 5454 /* 5455 * Switch to next element 5456 */ 5457 cur = cur->next; 5458 while (cur == NULL) { 5459 cur = nodeVPop(ctxt); 5460 if (cur == NULL) 5461 break; 5462 cur = cur->next; 5463 } 5464 } 5465done: 5466 ctxt->nodeMax = 0; 5467 ctxt->nodeNr = 0; 5468 if (ctxt->nodeTab != NULL) { 5469 xmlFree(ctxt->nodeTab); 5470 ctxt->nodeTab = NULL; 5471 } 5472 return(ret); 5473} 5474 5475#ifdef LIBXML_REGEXP_ENABLED 5476/** 5477 * xmlValidateCheckMixed: 5478 * @ctxt: the validation context 5479 * @cont: the mixed content model 5480 * @qname: the qualified name as appearing in the serialization 5481 * 5482 * Check if the given node is part of the content model. 5483 * 5484 * Returns 1 if yes, 0 if no, -1 in case of error 5485 */ 5486static int 5487xmlValidateCheckMixed(xmlValidCtxtPtr ctxt, 5488 xmlElementContentPtr cont, const xmlChar *qname) { 5489 const xmlChar *name; 5490 int plen; 5491 name = xmlSplitQName3(qname, &plen); 5492 5493 if (name == NULL) { 5494 while (cont != NULL) { 5495 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 5496 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname))) 5497 return(1); 5498 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 5499 (cont->c1 != NULL) && 5500 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 5501 if ((cont->c1->prefix == NULL) && 5502 (xmlStrEqual(cont->c1->name, qname))) 5503 return(1); 5504 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 5505 (cont->c1 == NULL) || 5506 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 5507 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 5508 "Internal: MIXED struct corrupted\n", 5509 NULL); 5510 break; 5511 } 5512 cont = cont->c2; 5513 } 5514 } else { 5515 while (cont != NULL) { 5516 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 5517 if ((cont->prefix != NULL) && 5518 (xmlStrncmp(cont->prefix, qname, plen) == 0) && 5519 (xmlStrEqual(cont->name, name))) 5520 return(1); 5521 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 5522 (cont->c1 != NULL) && 5523 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 5524 if ((cont->c1->prefix != NULL) && 5525 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) && 5526 (xmlStrEqual(cont->c1->name, name))) 5527 return(1); 5528 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 5529 (cont->c1 == NULL) || 5530 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 5531 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 5532 "Internal: MIXED struct corrupted\n", 5533 NULL); 5534 break; 5535 } 5536 cont = cont->c2; 5537 } 5538 } 5539 return(0); 5540} 5541#endif /* LIBXML_REGEXP_ENABLED */ 5542 5543/** 5544 * xmlValidGetElemDecl: 5545 * @ctxt: the validation context 5546 * @doc: a document instance 5547 * @elem: an element instance 5548 * @extsubset: pointer, (out) indicate if the declaration was found 5549 * in the external subset. 5550 * 5551 * Finds a declaration associated to an element in the document. 5552 * 5553 * returns the pointer to the declaration or NULL if not found. 5554 */ 5555static xmlElementPtr 5556xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5557 xmlNodePtr elem, int *extsubset) { 5558 xmlElementPtr elemDecl = NULL; 5559 const xmlChar *prefix = NULL; 5560 5561 if ((ctxt == NULL) || (doc == NULL) || 5562 (elem == NULL) || (elem->name == NULL)) 5563 return(NULL); 5564 if (extsubset != NULL) 5565 *extsubset = 0; 5566 5567 /* 5568 * Fetch the declaration for the qualified name 5569 */ 5570 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) 5571 prefix = elem->ns->prefix; 5572 5573 if (prefix != NULL) { 5574 elemDecl = xmlGetDtdQElementDesc(doc->intSubset, 5575 elem->name, prefix); 5576 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 5577 elemDecl = xmlGetDtdQElementDesc(doc->extSubset, 5578 elem->name, prefix); 5579 if ((elemDecl != NULL) && (extsubset != NULL)) 5580 *extsubset = 1; 5581 } 5582 } 5583 5584 /* 5585 * Fetch the declaration for the non qualified name 5586 * This is "non-strict" validation should be done on the 5587 * full QName but in that case being flexible makes sense. 5588 */ 5589 if (elemDecl == NULL) { 5590 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); 5591 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 5592 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); 5593 if ((elemDecl != NULL) && (extsubset != NULL)) 5594 *extsubset = 1; 5595 } 5596 } 5597 if (elemDecl == NULL) { 5598 xmlErrValidNode(ctxt, elem, 5599 XML_DTD_UNKNOWN_ELEM, 5600 "No declaration for element %s\n", 5601 elem->name, NULL, NULL); 5602 } 5603 return(elemDecl); 5604} 5605 5606#ifdef LIBXML_REGEXP_ENABLED 5607/** 5608 * xmlValidatePushElement: 5609 * @ctxt: the validation context 5610 * @doc: a document instance 5611 * @elem: an element instance 5612 * @qname: the qualified name as appearing in the serialization 5613 * 5614 * Push a new element start on the validation stack. 5615 * 5616 * returns 1 if no validation problem was found or 0 otherwise 5617 */ 5618int 5619xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5620 xmlNodePtr elem, const xmlChar *qname) { 5621 int ret = 1; 5622 xmlElementPtr eDecl; 5623 int extsubset = 0; 5624 5625 if (ctxt == NULL) 5626 return(0); 5627/* printf("PushElem %s\n", qname); */ 5628 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5629 xmlValidStatePtr state = ctxt->vstate; 5630 xmlElementPtr elemDecl; 5631 5632 /* 5633 * Check the new element against the content model of the new elem. 5634 */ 5635 if (state->elemDecl != NULL) { 5636 elemDecl = state->elemDecl; 5637 5638 switch(elemDecl->etype) { 5639 case XML_ELEMENT_TYPE_UNDEFINED: 5640 ret = 0; 5641 break; 5642 case XML_ELEMENT_TYPE_EMPTY: 5643 xmlErrValidNode(ctxt, state->node, 5644 XML_DTD_NOT_EMPTY, 5645 "Element %s was declared EMPTY this one has content\n", 5646 state->node->name, NULL, NULL); 5647 ret = 0; 5648 break; 5649 case XML_ELEMENT_TYPE_ANY: 5650 /* I don't think anything is required then */ 5651 break; 5652 case XML_ELEMENT_TYPE_MIXED: 5653 /* simple case of declared as #PCDATA */ 5654 if ((elemDecl->content != NULL) && 5655 (elemDecl->content->type == 5656 XML_ELEMENT_CONTENT_PCDATA)) { 5657 xmlErrValidNode(ctxt, state->node, 5658 XML_DTD_NOT_PCDATA, 5659 "Element %s was declared #PCDATA but contains non text nodes\n", 5660 state->node->name, NULL, NULL); 5661 ret = 0; 5662 } else { 5663 ret = xmlValidateCheckMixed(ctxt, elemDecl->content, 5664 qname); 5665 if (ret != 1) { 5666 xmlErrValidNode(ctxt, state->node, 5667 XML_DTD_INVALID_CHILD, 5668 "Element %s is not declared in %s list of possible children\n", 5669 qname, state->node->name, NULL); 5670 } 5671 } 5672 break; 5673 case XML_ELEMENT_TYPE_ELEMENT: 5674 /* 5675 * TODO: 5676 * VC: Standalone Document Declaration 5677 * - element types with element content, if white space 5678 * occurs directly within any instance of those types. 5679 */ 5680 if (state->exec != NULL) { 5681 ret = xmlRegExecPushString(state->exec, qname, NULL); 5682 if (ret < 0) { 5683 xmlErrValidNode(ctxt, state->node, 5684 XML_DTD_CONTENT_MODEL, 5685 "Element %s content does not follow the DTD, Misplaced %s\n", 5686 state->node->name, qname, NULL); 5687 ret = 0; 5688 } else { 5689 ret = 1; 5690 } 5691 } 5692 break; 5693 } 5694 } 5695 } 5696 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 5697 vstateVPush(ctxt, eDecl, elem); 5698 return(ret); 5699} 5700 5701/** 5702 * xmlValidatePushCData: 5703 * @ctxt: the validation context 5704 * @data: some character data read 5705 * @len: the length of the data 5706 * 5707 * check the CData parsed for validation in the current stack 5708 * 5709 * returns 1 if no validation problem was found or 0 otherwise 5710 */ 5711int 5712xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) { 5713 int ret = 1; 5714 5715/* printf("CDATA %s %d\n", data, len); */ 5716 if (ctxt == NULL) 5717 return(0); 5718 if (len <= 0) 5719 return(ret); 5720 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5721 xmlValidStatePtr state = ctxt->vstate; 5722 xmlElementPtr elemDecl; 5723 5724 /* 5725 * Check the new element against the content model of the new elem. 5726 */ 5727 if (state->elemDecl != NULL) { 5728 elemDecl = state->elemDecl; 5729 5730 switch(elemDecl->etype) { 5731 case XML_ELEMENT_TYPE_UNDEFINED: 5732 ret = 0; 5733 break; 5734 case XML_ELEMENT_TYPE_EMPTY: 5735 xmlErrValidNode(ctxt, state->node, 5736 XML_DTD_NOT_EMPTY, 5737 "Element %s was declared EMPTY this one has content\n", 5738 state->node->name, NULL, NULL); 5739 ret = 0; 5740 break; 5741 case XML_ELEMENT_TYPE_ANY: 5742 break; 5743 case XML_ELEMENT_TYPE_MIXED: 5744 break; 5745 case XML_ELEMENT_TYPE_ELEMENT: { 5746 int i; 5747 5748 for (i = 0;i < len;i++) { 5749 if (!IS_BLANK_CH(data[i])) { 5750 xmlErrValidNode(ctxt, state->node, 5751 XML_DTD_CONTENT_MODEL, 5752 "Element %s content does not follow the DTD, Text not allowed\n", 5753 state->node->name, NULL, NULL); 5754 ret = 0; 5755 goto done; 5756 } 5757 } 5758 /* 5759 * TODO: 5760 * VC: Standalone Document Declaration 5761 * element types with element content, if white space 5762 * occurs directly within any instance of those types. 5763 */ 5764 break; 5765 } 5766 } 5767 } 5768 } 5769done: 5770 return(ret); 5771} 5772 5773/** 5774 * xmlValidatePopElement: 5775 * @ctxt: the validation context 5776 * @doc: a document instance 5777 * @elem: an element instance 5778 * @qname: the qualified name as appearing in the serialization 5779 * 5780 * Pop the element end from the validation stack. 5781 * 5782 * returns 1 if no validation problem was found or 0 otherwise 5783 */ 5784int 5785xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, 5786 xmlNodePtr elem ATTRIBUTE_UNUSED, 5787 const xmlChar *qname ATTRIBUTE_UNUSED) { 5788 int ret = 1; 5789 5790 if (ctxt == NULL) 5791 return(0); 5792/* printf("PopElem %s\n", qname); */ 5793 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5794 xmlValidStatePtr state = ctxt->vstate; 5795 xmlElementPtr elemDecl; 5796 5797 /* 5798 * Check the new element against the content model of the new elem. 5799 */ 5800 if (state->elemDecl != NULL) { 5801 elemDecl = state->elemDecl; 5802 5803 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) { 5804 if (state->exec != NULL) { 5805 ret = xmlRegExecPushString(state->exec, NULL, NULL); 5806 if (ret <= 0) { 5807 xmlErrValidNode(ctxt, state->node, 5808 XML_DTD_CONTENT_MODEL, 5809 "Element %s content does not follow the DTD, Expecting more children\n", 5810 state->node->name, NULL,NULL); 5811 ret = 0; 5812 } else { 5813 /* 5814 * previous validation errors should not generate 5815 * a new one here 5816 */ 5817 ret = 1; 5818 } 5819 } 5820 } 5821 } 5822 vstateVPop(ctxt); 5823 } 5824 return(ret); 5825} 5826#endif /* LIBXML_REGEXP_ENABLED */ 5827 5828/** 5829 * xmlValidateOneElement: 5830 * @ctxt: the validation context 5831 * @doc: a document instance 5832 * @elem: an element instance 5833 * 5834 * Try to validate a single element and it's attributes, 5835 * basically it does the following checks as described by the 5836 * XML-1.0 recommendation: 5837 * - [ VC: Element Valid ] 5838 * - [ VC: Required Attribute ] 5839 * Then call xmlValidateOneAttribute() for each attribute present. 5840 * 5841 * The ID/IDREF checkings are done separately 5842 * 5843 * returns 1 if valid or 0 otherwise 5844 */ 5845 5846int 5847xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5848 xmlNodePtr elem) { 5849 xmlElementPtr elemDecl = NULL; 5850 xmlElementContentPtr cont; 5851 xmlAttributePtr attr; 5852 xmlNodePtr child; 5853 int ret = 1, tmp; 5854 const xmlChar *name; 5855 int extsubset = 0; 5856 5857 CHECK_DTD; 5858 5859 if (elem == NULL) return(0); 5860 switch (elem->type) { 5861 case XML_ATTRIBUTE_NODE: 5862 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5863 "Attribute element not expected\n", NULL, NULL ,NULL); 5864 return(0); 5865 case XML_TEXT_NODE: 5866 if (elem->children != NULL) { 5867 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5868 "Text element has children !\n", 5869 NULL,NULL,NULL); 5870 return(0); 5871 } 5872 if (elem->ns != NULL) { 5873 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5874 "Text element has namespace !\n", 5875 NULL,NULL,NULL); 5876 return(0); 5877 } 5878 if (elem->content == NULL) { 5879 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5880 "Text element has no content !\n", 5881 NULL,NULL,NULL); 5882 return(0); 5883 } 5884 return(1); 5885 case XML_XINCLUDE_START: 5886 case XML_XINCLUDE_END: 5887 return(1); 5888 case XML_CDATA_SECTION_NODE: 5889 case XML_ENTITY_REF_NODE: 5890 case XML_PI_NODE: 5891 case XML_COMMENT_NODE: 5892 return(1); 5893 case XML_ENTITY_NODE: 5894 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5895 "Entity element not expected\n", NULL, NULL ,NULL); 5896 return(0); 5897 case XML_NOTATION_NODE: 5898 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5899 "Notation element not expected\n", NULL, NULL ,NULL); 5900 return(0); 5901 case XML_DOCUMENT_NODE: 5902 case XML_DOCUMENT_TYPE_NODE: 5903 case XML_DOCUMENT_FRAG_NODE: 5904 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5905 "Document element not expected\n", NULL, NULL ,NULL); 5906 return(0); 5907 case XML_HTML_DOCUMENT_NODE: 5908 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5909 "HTML Document not expected\n", NULL, NULL ,NULL); 5910 return(0); 5911 case XML_ELEMENT_NODE: 5912 break; 5913 default: 5914 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5915 "unknown element type\n", NULL, NULL ,NULL); 5916 return(0); 5917 } 5918 5919 /* 5920 * Fetch the declaration 5921 */ 5922 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 5923 if (elemDecl == NULL) 5924 return(0); 5925 5926 /* 5927 * If vstateNr is not zero that means continuous validation is 5928 * activated, do not try to check the content model at that level. 5929 */ 5930 if (ctxt->vstateNr == 0) { 5931 /* Check that the element content matches the definition */ 5932 switch (elemDecl->etype) { 5933 case XML_ELEMENT_TYPE_UNDEFINED: 5934 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, 5935 "No declaration for element %s\n", 5936 elem->name, NULL, NULL); 5937 return(0); 5938 case XML_ELEMENT_TYPE_EMPTY: 5939 if (elem->children != NULL) { 5940 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY, 5941 "Element %s was declared EMPTY this one has content\n", 5942 elem->name, NULL, NULL); 5943 ret = 0; 5944 } 5945 break; 5946 case XML_ELEMENT_TYPE_ANY: 5947 /* I don't think anything is required then */ 5948 break; 5949 case XML_ELEMENT_TYPE_MIXED: 5950 5951 /* simple case of declared as #PCDATA */ 5952 if ((elemDecl->content != NULL) && 5953 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { 5954 ret = xmlValidateOneCdataElement(ctxt, doc, elem); 5955 if (!ret) { 5956 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA, 5957 "Element %s was declared #PCDATA but contains non text nodes\n", 5958 elem->name, NULL, NULL); 5959 } 5960 break; 5961 } 5962 child = elem->children; 5963 /* Hum, this start to get messy */ 5964 while (child != NULL) { 5965 if (child->type == XML_ELEMENT_NODE) { 5966 name = child->name; 5967 if ((child->ns != NULL) && (child->ns->prefix != NULL)) { 5968 xmlChar fn[50]; 5969 xmlChar *fullname; 5970 5971 fullname = xmlBuildQName(child->name, child->ns->prefix, 5972 fn, 50); 5973 if (fullname == NULL) 5974 return(0); 5975 cont = elemDecl->content; 5976 while (cont != NULL) { 5977 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 5978 if (xmlStrEqual(cont->name, fullname)) 5979 break; 5980 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 5981 (cont->c1 != NULL) && 5982 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 5983 if (xmlStrEqual(cont->c1->name, fullname)) 5984 break; 5985 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 5986 (cont->c1 == NULL) || 5987 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 5988 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 5989 "Internal: MIXED struct corrupted\n", 5990 NULL); 5991 break; 5992 } 5993 cont = cont->c2; 5994 } 5995 if ((fullname != fn) && (fullname != child->name)) 5996 xmlFree(fullname); 5997 if (cont != NULL) 5998 goto child_ok; 5999 } 6000 cont = elemDecl->content; 6001 while (cont != NULL) { 6002 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 6003 if (xmlStrEqual(cont->name, name)) break; 6004 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 6005 (cont->c1 != NULL) && 6006 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) { 6007 if (xmlStrEqual(cont->c1->name, name)) break; 6008 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 6009 (cont->c1 == NULL) || 6010 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) { 6011 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 6012 "Internal: MIXED struct corrupted\n", 6013 NULL); 6014 break; 6015 } 6016 cont = cont->c2; 6017 } 6018 if (cont == NULL) { 6019 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD, 6020 "Element %s is not declared in %s list of possible children\n", 6021 name, elem->name, NULL); 6022 ret = 0; 6023 } 6024 } 6025child_ok: 6026 child = child->next; 6027 } 6028 break; 6029 case XML_ELEMENT_TYPE_ELEMENT: 6030 if ((doc->standalone == 1) && (extsubset == 1)) { 6031 /* 6032 * VC: Standalone Document Declaration 6033 * - element types with element content, if white space 6034 * occurs directly within any instance of those types. 6035 */ 6036 child = elem->children; 6037 while (child != NULL) { 6038 if (child->type == XML_TEXT_NODE) { 6039 const xmlChar *content = child->content; 6040 6041 while (IS_BLANK_CH(*content)) 6042 content++; 6043 if (*content == 0) { 6044 xmlErrValidNode(ctxt, elem, 6045 XML_DTD_STANDALONE_WHITE_SPACE, 6046"standalone: %s declared in the external subset contains white spaces nodes\n", 6047 elem->name, NULL, NULL); 6048 ret = 0; 6049 break; 6050 } 6051 } 6052 child =child->next; 6053 } 6054 } 6055 child = elem->children; 6056 cont = elemDecl->content; 6057 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); 6058 if (tmp <= 0) 6059 ret = tmp; 6060 break; 6061 } 6062 } /* not continuous */ 6063 6064 /* [ VC: Required Attribute ] */ 6065 attr = elemDecl->attributes; 6066 while (attr != NULL) { 6067 if (attr->def == XML_ATTRIBUTE_REQUIRED) { 6068 int qualified = -1; 6069 6070 if ((attr->prefix == NULL) && 6071 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 6072 xmlNsPtr ns; 6073 6074 ns = elem->nsDef; 6075 while (ns != NULL) { 6076 if (ns->prefix == NULL) 6077 goto found; 6078 ns = ns->next; 6079 } 6080 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 6081 xmlNsPtr ns; 6082 6083 ns = elem->nsDef; 6084 while (ns != NULL) { 6085 if (xmlStrEqual(attr->name, ns->prefix)) 6086 goto found; 6087 ns = ns->next; 6088 } 6089 } else { 6090 xmlAttrPtr attrib; 6091 6092 attrib = elem->properties; 6093 while (attrib != NULL) { 6094 if (xmlStrEqual(attrib->name, attr->name)) { 6095 if (attr->prefix != NULL) { 6096 xmlNsPtr nameSpace = attrib->ns; 6097 6098 if (nameSpace == NULL) 6099 nameSpace = elem->ns; 6100 /* 6101 * qualified names handling is problematic, having a 6102 * different prefix should be possible but DTDs don't 6103 * allow to define the URI instead of the prefix :-( 6104 */ 6105 if (nameSpace == NULL) { 6106 if (qualified < 0) 6107 qualified = 0; 6108 } else if (!xmlStrEqual(nameSpace->prefix, 6109 attr->prefix)) { 6110 if (qualified < 1) 6111 qualified = 1; 6112 } else 6113 goto found; 6114 } else { 6115 /* 6116 * We should allow applications to define namespaces 6117 * for their application even if the DTD doesn't 6118 * carry one, otherwise, basically we would always 6119 * break. 6120 */ 6121 goto found; 6122 } 6123 } 6124 attrib = attrib->next; 6125 } 6126 } 6127 if (qualified == -1) { 6128 if (attr->prefix == NULL) { 6129 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 6130 "Element %s does not carry attribute %s\n", 6131 elem->name, attr->name, NULL); 6132 ret = 0; 6133 } else { 6134 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 6135 "Element %s does not carry attribute %s:%s\n", 6136 elem->name, attr->prefix,attr->name); 6137 ret = 0; 6138 } 6139 } else if (qualified == 0) { 6140 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX, 6141 "Element %s required attribute %s:%s has no prefix\n", 6142 elem->name, attr->prefix, attr->name); 6143 } else if (qualified == 1) { 6144 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX, 6145 "Element %s required attribute %s:%s has different prefix\n", 6146 elem->name, attr->prefix, attr->name); 6147 } 6148 } else if (attr->def == XML_ATTRIBUTE_FIXED) { 6149 /* 6150 * Special tests checking #FIXED namespace declarations 6151 * have the right value since this is not done as an 6152 * attribute checking 6153 */ 6154 if ((attr->prefix == NULL) && 6155 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 6156 xmlNsPtr ns; 6157 6158 ns = elem->nsDef; 6159 while (ns != NULL) { 6160 if (ns->prefix == NULL) { 6161 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 6162 xmlErrValidNode(ctxt, elem, 6163 XML_DTD_ELEM_DEFAULT_NAMESPACE, 6164 "Element %s namespace name for default namespace does not match the DTD\n", 6165 elem->name, NULL, NULL); 6166 ret = 0; 6167 } 6168 goto found; 6169 } 6170 ns = ns->next; 6171 } 6172 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 6173 xmlNsPtr ns; 6174 6175 ns = elem->nsDef; 6176 while (ns != NULL) { 6177 if (xmlStrEqual(attr->name, ns->prefix)) { 6178 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 6179 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 6180 "Element %s namespace name for %s does not match the DTD\n", 6181 elem->name, ns->prefix, NULL); 6182 ret = 0; 6183 } 6184 goto found; 6185 } 6186 ns = ns->next; 6187 } 6188 } 6189 } 6190found: 6191 attr = attr->nexth; 6192 } 6193 return(ret); 6194} 6195 6196/** 6197 * xmlValidateRoot: 6198 * @ctxt: the validation context 6199 * @doc: a document instance 6200 * 6201 * Try to validate a the root element 6202 * basically it does the following check as described by the 6203 * XML-1.0 recommendation: 6204 * - [ VC: Root Element Type ] 6205 * it doesn't try to recurse or apply other check to the element 6206 * 6207 * returns 1 if valid or 0 otherwise 6208 */ 6209 6210int 6211xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6212 xmlNodePtr root; 6213 int ret; 6214 6215 if (doc == NULL) return(0); 6216 6217 root = xmlDocGetRootElement(doc); 6218 if ((root == NULL) || (root->name == NULL)) { 6219 xmlErrValid(ctxt, XML_DTD_NO_ROOT, 6220 "no root element\n", NULL); 6221 return(0); 6222 } 6223 6224 /* 6225 * When doing post validation against a separate DTD, those may 6226 * no internal subset has been generated 6227 */ 6228 if ((doc->intSubset != NULL) && 6229 (doc->intSubset->name != NULL)) { 6230 /* 6231 * Check first the document root against the NQName 6232 */ 6233 if (!xmlStrEqual(doc->intSubset->name, root->name)) { 6234 if ((root->ns != NULL) && (root->ns->prefix != NULL)) { 6235 xmlChar fn[50]; 6236 xmlChar *fullname; 6237 6238 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); 6239 if (fullname == NULL) { 6240 xmlVErrMemory(ctxt, NULL); 6241 return(0); 6242 } 6243 ret = xmlStrEqual(doc->intSubset->name, fullname); 6244 if ((fullname != fn) && (fullname != root->name)) 6245 xmlFree(fullname); 6246 if (ret == 1) 6247 goto name_ok; 6248 } 6249 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) && 6250 (xmlStrEqual(root->name, BAD_CAST "html"))) 6251 goto name_ok; 6252 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME, 6253 "root and DTD name do not match '%s' and '%s'\n", 6254 root->name, doc->intSubset->name, NULL); 6255 return(0); 6256 } 6257 } 6258name_ok: 6259 return(1); 6260} 6261 6262 6263/** 6264 * xmlValidateElement: 6265 * @ctxt: the validation context 6266 * @doc: a document instance 6267 * @root: an element instance 6268 * 6269 * Try to validate the subtree under an element 6270 * 6271 * returns 1 if valid or 0 otherwise 6272 */ 6273 6274int 6275xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) { 6276 xmlNodePtr elem; 6277 xmlAttrPtr attr; 6278 xmlNsPtr ns; 6279 const xmlChar *value; 6280 int ret = 1; 6281 6282 if (root == NULL) return(0); 6283 6284 CHECK_DTD; 6285 6286 elem = root; 6287 while (1) { 6288 ret &= xmlValidateOneElement(ctxt, doc, elem); 6289 6290 if (elem->type == XML_ELEMENT_NODE) { 6291 attr = elem->properties; 6292 while (attr != NULL) { 6293 value = xmlNodeListGetString(doc, attr->children, 0); 6294 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); 6295 if (value != NULL) 6296 xmlFree((char *)value); 6297 attr= attr->next; 6298 } 6299 6300 ns = elem->nsDef; 6301 while (ns != NULL) { 6302 if (elem->ns == NULL) 6303 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL, 6304 ns, ns->href); 6305 else 6306 ret &= xmlValidateOneNamespace(ctxt, doc, elem, 6307 elem->ns->prefix, ns, 6308 ns->href); 6309 ns = ns->next; 6310 } 6311 6312 if (elem->children != NULL) { 6313 elem = elem->children; 6314 continue; 6315 } 6316 } 6317 6318 while (1) { 6319 if (elem == root) 6320 goto done; 6321 if (elem->next != NULL) 6322 break; 6323 elem = elem->parent; 6324 } 6325 elem = elem->next; 6326 } 6327 6328done: 6329 return(ret); 6330} 6331 6332/** 6333 * xmlValidateRef: 6334 * @ref: A reference to be validated 6335 * @ctxt: Validation context 6336 * @name: Name of ID we are searching for 6337 * 6338 */ 6339static void 6340xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, 6341 const xmlChar *name) { 6342 xmlAttrPtr id; 6343 xmlAttrPtr attr; 6344 6345 if (ref == NULL) 6346 return; 6347 if ((ref->attr == NULL) && (ref->name == NULL)) 6348 return; 6349 attr = ref->attr; 6350 if (attr == NULL) { 6351 xmlChar *dup, *str = NULL, *cur, save; 6352 6353 dup = xmlStrdup(name); 6354 if (dup == NULL) { 6355 ctxt->valid = 0; 6356 return; 6357 } 6358 cur = dup; 6359 while (*cur != 0) { 6360 str = cur; 6361 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 6362 save = *cur; 6363 *cur = 0; 6364 id = xmlGetID(ctxt->doc, str); 6365 if (id == NULL) { 6366 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID, 6367 "attribute %s line %d references an unknown ID \"%s\"\n", 6368 ref->name, ref->lineno, str); 6369 ctxt->valid = 0; 6370 } 6371 if (save == 0) 6372 break; 6373 *cur = save; 6374 while (IS_BLANK_CH(*cur)) cur++; 6375 } 6376 xmlFree(dup); 6377 } else if (attr->atype == XML_ATTRIBUTE_IDREF) { 6378 id = xmlGetID(ctxt->doc, name); 6379 if (id == NULL) { 6380 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 6381 "IDREF attribute %s references an unknown ID \"%s\"\n", 6382 attr->name, name, NULL); 6383 ctxt->valid = 0; 6384 } 6385 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { 6386 xmlChar *dup, *str = NULL, *cur, save; 6387 6388 dup = xmlStrdup(name); 6389 if (dup == NULL) { 6390 xmlVErrMemory(ctxt, "IDREFS split"); 6391 ctxt->valid = 0; 6392 return; 6393 } 6394 cur = dup; 6395 while (*cur != 0) { 6396 str = cur; 6397 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 6398 save = *cur; 6399 *cur = 0; 6400 id = xmlGetID(ctxt->doc, str); 6401 if (id == NULL) { 6402 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 6403 "IDREFS attribute %s references an unknown ID \"%s\"\n", 6404 attr->name, str, NULL); 6405 ctxt->valid = 0; 6406 } 6407 if (save == 0) 6408 break; 6409 *cur = save; 6410 while (IS_BLANK_CH(*cur)) cur++; 6411 } 6412 xmlFree(dup); 6413 } 6414} 6415 6416/** 6417 * xmlWalkValidateList: 6418 * @data: Contents of current link 6419 * @user: Value supplied by the user 6420 * 6421 * Returns 0 to abort the walk or 1 to continue 6422 */ 6423static int 6424xmlWalkValidateList(const void *data, void *user) 6425{ 6426 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user; 6427 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name); 6428 return 1; 6429} 6430 6431/** 6432 * xmlValidateCheckRefCallback: 6433 * @ref_list: List of references 6434 * @ctxt: Validation context 6435 * @name: Name of ID we are searching for 6436 * 6437 */ 6438static void 6439xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { 6440 xmlListPtr ref_list = (xmlListPtr) payload; 6441 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; 6442 xmlValidateMemo memo; 6443 6444 if (ref_list == NULL) 6445 return; 6446 memo.ctxt = ctxt; 6447 memo.name = name; 6448 6449 xmlListWalk(ref_list, xmlWalkValidateList, &memo); 6450 6451} 6452 6453/** 6454 * xmlValidateDocumentFinal: 6455 * @ctxt: the validation context 6456 * @doc: a document instance 6457 * 6458 * Does the final step for the document validation once all the 6459 * incremental validation steps have been completed 6460 * 6461 * basically it does the following checks described by the XML Rec 6462 * 6463 * Check all the IDREF/IDREFS attributes definition for validity 6464 * 6465 * returns 1 if valid or 0 otherwise 6466 */ 6467 6468int 6469xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6470 xmlRefTablePtr table; 6471 unsigned int save; 6472 6473 if (ctxt == NULL) 6474 return(0); 6475 if (doc == NULL) { 6476 xmlErrValid(ctxt, XML_DTD_NO_DOC, 6477 "xmlValidateDocumentFinal: doc == NULL\n", NULL); 6478 return(0); 6479 } 6480 6481 /* trick to get correct line id report */ 6482 save = ctxt->flags; 6483 ctxt->flags &= ~XML_VCTXT_USE_PCTXT; 6484 6485 /* 6486 * Check all the NOTATION/NOTATIONS attributes 6487 */ 6488 /* 6489 * Check all the ENTITY/ENTITIES attributes definition for validity 6490 */ 6491 /* 6492 * Check all the IDREF/IDREFS attributes definition for validity 6493 */ 6494 table = (xmlRefTablePtr) doc->refs; 6495 ctxt->doc = doc; 6496 ctxt->valid = 1; 6497 xmlHashScan(table, xmlValidateCheckRefCallback, ctxt); 6498 6499 ctxt->flags = save; 6500 return(ctxt->valid); 6501} 6502 6503/** 6504 * xmlValidateDtd: 6505 * @ctxt: the validation context 6506 * @doc: a document instance 6507 * @dtd: a dtd instance 6508 * 6509 * Try to validate the document against the dtd instance 6510 * 6511 * Basically it does check all the definitions in the DtD. 6512 * Note the the internal subset (if present) is de-coupled 6513 * (i.e. not used), which could give problems if ID or IDREF 6514 * is present. 6515 * 6516 * returns 1 if valid or 0 otherwise 6517 */ 6518 6519int 6520xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { 6521 int ret; 6522 xmlDtdPtr oldExt, oldInt; 6523 xmlNodePtr root; 6524 6525 if (dtd == NULL) return(0); 6526 if (doc == NULL) return(0); 6527 oldExt = doc->extSubset; 6528 oldInt = doc->intSubset; 6529 doc->extSubset = dtd; 6530 doc->intSubset = NULL; 6531 ret = xmlValidateRoot(ctxt, doc); 6532 if (ret == 0) { 6533 doc->extSubset = oldExt; 6534 doc->intSubset = oldInt; 6535 return(ret); 6536 } 6537 if (doc->ids != NULL) { 6538 xmlFreeIDTable(doc->ids); 6539 doc->ids = NULL; 6540 } 6541 if (doc->refs != NULL) { 6542 xmlFreeRefTable(doc->refs); 6543 doc->refs = NULL; 6544 } 6545 root = xmlDocGetRootElement(doc); 6546 ret = xmlValidateElement(ctxt, doc, root); 6547 ret &= xmlValidateDocumentFinal(ctxt, doc); 6548 doc->extSubset = oldExt; 6549 doc->intSubset = oldInt; 6550 return(ret); 6551} 6552 6553static void 6554xmlValidateNotationCallback(void *payload, void *data, 6555 const xmlChar *name ATTRIBUTE_UNUSED) { 6556 xmlEntityPtr cur = (xmlEntityPtr) payload; 6557 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; 6558 if (cur == NULL) 6559 return; 6560 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 6561 xmlChar *notation = cur->content; 6562 6563 if (notation != NULL) { 6564 int ret; 6565 6566 ret = xmlValidateNotationUse(ctxt, cur->doc, notation); 6567 if (ret != 1) { 6568 ctxt->valid = 0; 6569 } 6570 } 6571 } 6572} 6573 6574static void 6575xmlValidateAttributeCallback(void *payload, void *data, 6576 const xmlChar *name ATTRIBUTE_UNUSED) { 6577 xmlAttributePtr cur = (xmlAttributePtr) payload; 6578 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data; 6579 int ret; 6580 xmlDocPtr doc; 6581 xmlElementPtr elem = NULL; 6582 6583 if (cur == NULL) 6584 return; 6585 switch (cur->atype) { 6586 case XML_ATTRIBUTE_CDATA: 6587 case XML_ATTRIBUTE_ID: 6588 case XML_ATTRIBUTE_IDREF : 6589 case XML_ATTRIBUTE_IDREFS: 6590 case XML_ATTRIBUTE_NMTOKEN: 6591 case XML_ATTRIBUTE_NMTOKENS: 6592 case XML_ATTRIBUTE_ENUMERATION: 6593 break; 6594 case XML_ATTRIBUTE_ENTITY: 6595 case XML_ATTRIBUTE_ENTITIES: 6596 case XML_ATTRIBUTE_NOTATION: 6597 if (cur->defaultValue != NULL) { 6598 6599 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, 6600 cur->atype, cur->defaultValue); 6601 if ((ret == 0) && (ctxt->valid == 1)) 6602 ctxt->valid = 0; 6603 } 6604 if (cur->tree != NULL) { 6605 xmlEnumerationPtr tree = cur->tree; 6606 while (tree != NULL) { 6607 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, 6608 cur->name, cur->atype, tree->name); 6609 if ((ret == 0) && (ctxt->valid == 1)) 6610 ctxt->valid = 0; 6611 tree = tree->next; 6612 } 6613 } 6614 } 6615 if (cur->atype == XML_ATTRIBUTE_NOTATION) { 6616 doc = cur->doc; 6617 if (cur->elem == NULL) { 6618 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 6619 "xmlValidateAttributeCallback(%s): internal error\n", 6620 (const char *) cur->name); 6621 return; 6622 } 6623 6624 if (doc != NULL) 6625 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); 6626 if ((elem == NULL) && (doc != NULL)) 6627 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); 6628 if ((elem == NULL) && (cur->parent != NULL) && 6629 (cur->parent->type == XML_DTD_NODE)) 6630 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); 6631 if (elem == NULL) { 6632 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, 6633 "attribute %s: could not find decl for element %s\n", 6634 cur->name, cur->elem, NULL); 6635 return; 6636 } 6637 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) { 6638 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION, 6639 "NOTATION attribute %s declared for EMPTY element %s\n", 6640 cur->name, cur->elem, NULL); 6641 ctxt->valid = 0; 6642 } 6643 } 6644} 6645 6646/** 6647 * xmlValidateDtdFinal: 6648 * @ctxt: the validation context 6649 * @doc: a document instance 6650 * 6651 * Does the final step for the dtds validation once all the 6652 * subsets have been parsed 6653 * 6654 * basically it does the following checks described by the XML Rec 6655 * - check that ENTITY and ENTITIES type attributes default or 6656 * possible values matches one of the defined entities. 6657 * - check that NOTATION type attributes default or 6658 * possible values matches one of the defined notations. 6659 * 6660 * returns 1 if valid or 0 if invalid and -1 if not well-formed 6661 */ 6662 6663int 6664xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6665 xmlDtdPtr dtd; 6666 xmlAttributeTablePtr table; 6667 xmlEntitiesTablePtr entities; 6668 6669 if ((doc == NULL) || (ctxt == NULL)) return(0); 6670 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) 6671 return(0); 6672 ctxt->doc = doc; 6673 ctxt->valid = 1; 6674 dtd = doc->intSubset; 6675 if ((dtd != NULL) && (dtd->attributes != NULL)) { 6676 table = (xmlAttributeTablePtr) dtd->attributes; 6677 xmlHashScan(table, xmlValidateAttributeCallback, ctxt); 6678 } 6679 if ((dtd != NULL) && (dtd->entities != NULL)) { 6680 entities = (xmlEntitiesTablePtr) dtd->entities; 6681 xmlHashScan(entities, xmlValidateNotationCallback, ctxt); 6682 } 6683 dtd = doc->extSubset; 6684 if ((dtd != NULL) && (dtd->attributes != NULL)) { 6685 table = (xmlAttributeTablePtr) dtd->attributes; 6686 xmlHashScan(table, xmlValidateAttributeCallback, ctxt); 6687 } 6688 if ((dtd != NULL) && (dtd->entities != NULL)) { 6689 entities = (xmlEntitiesTablePtr) dtd->entities; 6690 xmlHashScan(entities, xmlValidateNotationCallback, ctxt); 6691 } 6692 return(ctxt->valid); 6693} 6694 6695/** 6696 * xmlValidateDocument: 6697 * @ctxt: the validation context 6698 * @doc: a document instance 6699 * 6700 * Try to validate the document instance 6701 * 6702 * basically it does the all the checks described by the XML Rec 6703 * i.e. validates the internal and external subset (if present) 6704 * and validate the document tree. 6705 * 6706 * returns 1 if valid or 0 otherwise 6707 */ 6708 6709int 6710xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6711 int ret; 6712 xmlNodePtr root; 6713 6714 if (doc == NULL) 6715 return(0); 6716 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { 6717 xmlErrValid(ctxt, XML_DTD_NO_DTD, 6718 "no DTD found!\n", NULL); 6719 return(0); 6720 } 6721 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) || 6722 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) { 6723 xmlChar *sysID; 6724 if (doc->intSubset->SystemID != NULL) { 6725 sysID = xmlBuildURI(doc->intSubset->SystemID, 6726 doc->URL); 6727 if (sysID == NULL) { 6728 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6729 "Could not build URI for external subset \"%s\"\n", 6730 (const char *) doc->intSubset->SystemID); 6731 return 0; 6732 } 6733 } else 6734 sysID = NULL; 6735 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, 6736 (const xmlChar *)sysID); 6737 if (sysID != NULL) 6738 xmlFree(sysID); 6739 if (doc->extSubset == NULL) { 6740 if (doc->intSubset->SystemID != NULL) { 6741 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6742 "Could not load the external subset \"%s\"\n", 6743 (const char *) doc->intSubset->SystemID); 6744 } else { 6745 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6746 "Could not load the external subset \"%s\"\n", 6747 (const char *) doc->intSubset->ExternalID); 6748 } 6749 return(0); 6750 } 6751 } 6752 6753 if (doc->ids != NULL) { 6754 xmlFreeIDTable(doc->ids); 6755 doc->ids = NULL; 6756 } 6757 if (doc->refs != NULL) { 6758 xmlFreeRefTable(doc->refs); 6759 doc->refs = NULL; 6760 } 6761 ret = xmlValidateDtdFinal(ctxt, doc); 6762 if (!xmlValidateRoot(ctxt, doc)) return(0); 6763 6764 root = xmlDocGetRootElement(doc); 6765 ret &= xmlValidateElement(ctxt, doc, root); 6766 ret &= xmlValidateDocumentFinal(ctxt, doc); 6767 return(ret); 6768} 6769 6770/************************************************************************ 6771 * * 6772 * Routines for dynamic validation editing * 6773 * * 6774 ************************************************************************/ 6775 6776/** 6777 * xmlValidGetPotentialChildren: 6778 * @ctree: an element content tree 6779 * @names: an array to store the list of child names 6780 * @len: a pointer to the number of element in the list 6781 * @max: the size of the array 6782 * 6783 * Build/extend a list of potential children allowed by the content tree 6784 * 6785 * returns the number of element in the list, or -1 in case of error. 6786 */ 6787 6788int 6789xmlValidGetPotentialChildren(xmlElementContent *ctree, 6790 const xmlChar **names, 6791 int *len, int max) { 6792 int i; 6793 6794 if ((ctree == NULL) || (names == NULL) || (len == NULL)) 6795 return(-1); 6796 if (*len >= max) return(*len); 6797 6798 switch (ctree->type) { 6799 case XML_ELEMENT_CONTENT_PCDATA: 6800 for (i = 0; i < *len;i++) 6801 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len); 6802 names[(*len)++] = BAD_CAST "#PCDATA"; 6803 break; 6804 case XML_ELEMENT_CONTENT_ELEMENT: 6805 for (i = 0; i < *len;i++) 6806 if (xmlStrEqual(ctree->name, names[i])) return(*len); 6807 names[(*len)++] = ctree->name; 6808 break; 6809 case XML_ELEMENT_CONTENT_SEQ: 6810 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 6811 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 6812 break; 6813 case XML_ELEMENT_CONTENT_OR: 6814 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 6815 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 6816 break; 6817 } 6818 6819 return(*len); 6820} 6821 6822/* 6823 * Dummy function to suppress messages while we try out valid elements 6824 */ 6825static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, 6826 const char *msg ATTRIBUTE_UNUSED, ...) { 6827 return; 6828} 6829 6830/** 6831 * xmlValidGetValidElements: 6832 * @prev: an element to insert after 6833 * @next: an element to insert next 6834 * @names: an array to store the list of child names 6835 * @max: the size of the array 6836 * 6837 * This function returns the list of authorized children to insert 6838 * within an existing tree while respecting the validity constraints 6839 * forced by the Dtd. The insertion point is defined using @prev and 6840 * @next in the following ways: 6841 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ... 6842 * to insert next 'node': xmlValidGetValidElements(node, node->next, ... 6843 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ... 6844 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs, 6845 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ... 6846 * 6847 * pointers to the element names are inserted at the beginning of the array 6848 * and do not need to be freed. 6849 * 6850 * returns the number of element in the list, or -1 in case of error. If 6851 * the function returns the value @max the caller is invited to grow the 6852 * receiving array and retry. 6853 */ 6854 6855int 6856xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, 6857 int max) { 6858 xmlValidCtxt vctxt; 6859 int nb_valid_elements = 0; 6860 const xmlChar *elements[256]={0}; 6861 int nb_elements = 0, i; 6862 const xmlChar *name; 6863 6864 xmlNode *ref_node; 6865 xmlNode *parent; 6866 xmlNode *test_node; 6867 6868 xmlNode *prev_next; 6869 xmlNode *next_prev; 6870 xmlNode *parent_childs; 6871 xmlNode *parent_last; 6872 6873 xmlElement *element_desc; 6874 6875 if (prev == NULL && next == NULL) 6876 return(-1); 6877 6878 if (names == NULL) return(-1); 6879 if (max <= 0) return(-1); 6880 6881 memset(&vctxt, 0, sizeof (xmlValidCtxt)); 6882 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */ 6883 6884 nb_valid_elements = 0; 6885 ref_node = prev ? prev : next; 6886 parent = ref_node->parent; 6887 6888 /* 6889 * Retrieves the parent element declaration 6890 */ 6891 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset, 6892 parent->name); 6893 if ((element_desc == NULL) && (parent->doc->extSubset != NULL)) 6894 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset, 6895 parent->name); 6896 if (element_desc == NULL) return(-1); 6897 6898 /* 6899 * Do a backup of the current tree structure 6900 */ 6901 prev_next = prev ? prev->next : NULL; 6902 next_prev = next ? next->prev : NULL; 6903 parent_childs = parent->children; 6904 parent_last = parent->last; 6905 6906 /* 6907 * Creates a dummy node and insert it into the tree 6908 */ 6909 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL); 6910 if (test_node == NULL) 6911 return(-1); 6912 6913 test_node->parent = parent; 6914 test_node->prev = prev; 6915 test_node->next = next; 6916 name = test_node->name; 6917 6918 if (prev) prev->next = test_node; 6919 else parent->children = test_node; 6920 6921 if (next) next->prev = test_node; 6922 else parent->last = test_node; 6923 6924 /* 6925 * Insert each potential child node and check if the parent is 6926 * still valid 6927 */ 6928 nb_elements = xmlValidGetPotentialChildren(element_desc->content, 6929 elements, &nb_elements, 256); 6930 6931 for (i = 0;i < nb_elements;i++) { 6932 test_node->name = elements[i]; 6933 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) { 6934 int j; 6935 6936 for (j = 0; j < nb_valid_elements;j++) 6937 if (xmlStrEqual(elements[i], names[j])) break; 6938 names[nb_valid_elements++] = elements[i]; 6939 if (nb_valid_elements >= max) break; 6940 } 6941 } 6942 6943 /* 6944 * Restore the tree structure 6945 */ 6946 if (prev) prev->next = prev_next; 6947 if (next) next->prev = next_prev; 6948 parent->children = parent_childs; 6949 parent->last = parent_last; 6950 6951 /* 6952 * Free up the dummy node 6953 */ 6954 test_node->name = name; 6955 xmlFreeNode(test_node); 6956 6957 return(nb_valid_elements); 6958} 6959#endif /* LIBXML_VALID_ENABLED */