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