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