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