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