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