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