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