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