Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvalid.c
Go to the documentation of this file.
00001 /* 00002 * valid.c : part of the code use to do the DTD handling and the validity 00003 * checking 00004 * 00005 * See Copyright for the status of this software. 00006 * 00007 * daniel@veillard.com 00008 */ 00009 00010 #define IN_LIBXML 00011 #include "libxml.h" 00012 00013 #include <string.h> 00014 00015 #ifdef HAVE_STDLIB_H 00016 #include <stdlib.h> 00017 #endif 00018 00019 #include <libxml/xmlmemory.h> 00020 #include <libxml/hash.h> 00021 #include <libxml/uri.h> 00022 #include <libxml/valid.h> 00023 #include <libxml/parser.h> 00024 #include <libxml/parserInternals.h> 00025 #include <libxml/xmlerror.h> 00026 #include <libxml/list.h> 00027 #include <libxml/globals.h> 00028 00029 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, 00030 int create); 00031 /* #define DEBUG_VALID_ALGO */ 00032 /* #define DEBUG_REGEXP_ALGO */ 00033 00034 #define TODO \ 00035 xmlGenericError(xmlGenericErrorContext, \ 00036 "Unimplemented block at %s:%d\n", \ 00037 __FILE__, __LINE__); 00038 00039 #ifdef LIBXML_VALID_ENABLED 00040 static int 00041 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, 00042 const xmlChar *value); 00043 #endif 00044 /************************************************************************ 00045 * * 00046 * Error handling routines * 00047 * * 00048 ************************************************************************/ 00049 00057 static void 00058 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra) 00059 { 00060 xmlGenericErrorFunc channel = NULL; 00061 xmlParserCtxtPtr pctxt = NULL; 00062 void *data = NULL; 00063 00064 if (ctxt != NULL) { 00065 channel = ctxt->error; 00066 data = ctxt->userData; 00067 /* Use the special values to detect if it is part of a parsing 00068 context */ 00069 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 00070 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { 00071 long delta = (char *) ctxt - (char *) ctxt->userData; 00072 if ((delta > 0) && (delta < 250)) 00073 pctxt = ctxt->userData; 00074 } 00075 } 00076 if (extra) 00077 __xmlRaiseError(NULL, channel, data, 00078 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, 00079 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, 00080 "Memory allocation failed : %s\n", extra); 00081 else 00082 __xmlRaiseError(NULL, channel, data, 00083 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, 00084 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, 00085 "Memory allocation failed\n"); 00086 } 00087 00096 static void 00097 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, 00098 const char *msg, const char *extra) 00099 { 00100 xmlGenericErrorFunc channel = NULL; 00101 xmlParserCtxtPtr pctxt = NULL; 00102 void *data = NULL; 00103 00104 if (ctxt != NULL) { 00105 channel = ctxt->error; 00106 data = ctxt->userData; 00107 /* Use the special values to detect if it is part of a parsing 00108 context */ 00109 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 00110 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { 00111 long delta = (char *) ctxt - (char *) ctxt->userData; 00112 if ((delta > 0) && (delta < 250)) 00113 pctxt = ctxt->userData; 00114 } 00115 } 00116 if (extra) 00117 __xmlRaiseError(NULL, channel, data, 00118 pctxt, NULL, XML_FROM_VALID, error, 00119 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, 00120 msg, extra); 00121 else 00122 __xmlRaiseError(NULL, channel, data, 00123 pctxt, NULL, XML_FROM_VALID, error, 00124 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, 00125 "%s", msg); 00126 } 00127 00128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 00129 00140 static void 00141 xmlErrValidNode(xmlValidCtxtPtr ctxt, 00142 xmlNodePtr node, xmlParserErrors error, 00143 const char *msg, const xmlChar * str1, 00144 const xmlChar * str2, const xmlChar * str3) 00145 { 00146 xmlStructuredErrorFunc schannel = NULL; 00147 xmlGenericErrorFunc channel = NULL; 00148 xmlParserCtxtPtr pctxt = NULL; 00149 void *data = NULL; 00150 00151 if (ctxt != NULL) { 00152 channel = ctxt->error; 00153 data = ctxt->userData; 00154 /* Use the special values to detect if it is part of a parsing 00155 context */ 00156 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 00157 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { 00158 long delta = (char *) ctxt - (char *) ctxt->userData; 00159 if ((delta > 0) && (delta < 250)) 00160 pctxt = ctxt->userData; 00161 } 00162 } 00163 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 00164 XML_ERR_ERROR, NULL, 0, 00165 (const char *) str1, 00166 (const char *) str1, 00167 (const char *) str3, 0, 0, msg, str1, str2, str3); 00168 } 00169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ 00170 00171 #ifdef LIBXML_VALID_ENABLED 00172 00183 static void 00184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, 00185 xmlNodePtr node, xmlParserErrors error, 00186 const char *msg, const xmlChar * str1, 00187 int int2, const xmlChar * str3) 00188 { 00189 xmlStructuredErrorFunc schannel = NULL; 00190 xmlGenericErrorFunc channel = NULL; 00191 xmlParserCtxtPtr pctxt = NULL; 00192 void *data = NULL; 00193 00194 if (ctxt != NULL) { 00195 channel = ctxt->error; 00196 data = ctxt->userData; 00197 /* Use the special values to detect if it is part of a parsing 00198 context */ 00199 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 00200 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { 00201 long delta = (char *) ctxt - (char *) ctxt->userData; 00202 if ((delta > 0) && (delta < 250)) 00203 pctxt = ctxt->userData; 00204 } 00205 } 00206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 00207 XML_ERR_ERROR, NULL, 0, 00208 (const char *) str1, 00209 (const char *) str3, 00210 NULL, int2, 0, msg, str1, int2, str3); 00211 } 00212 00224 static void 00225 xmlErrValidWarning(xmlValidCtxtPtr ctxt, 00226 xmlNodePtr node, xmlParserErrors error, 00227 const char *msg, const xmlChar * str1, 00228 const xmlChar * str2, const xmlChar * str3) 00229 { 00230 xmlStructuredErrorFunc schannel = NULL; 00231 xmlGenericErrorFunc channel = NULL; 00232 xmlParserCtxtPtr pctxt = NULL; 00233 void *data = NULL; 00234 00235 if (ctxt != NULL) { 00236 channel = ctxt->warning; 00237 data = ctxt->userData; 00238 /* Use the special values to detect if it is part of a parsing 00239 context */ 00240 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 00241 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { 00242 long delta = (char *) ctxt - (char *) ctxt->userData; 00243 if ((delta > 0) && (delta < 250)) 00244 pctxt = ctxt->userData; 00245 } 00246 } 00247 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, 00248 XML_ERR_WARNING, NULL, 0, 00249 (const char *) str1, 00250 (const char *) str1, 00251 (const char *) str3, 0, 0, msg, str1, str2, str3); 00252 } 00253 00254 00255 00256 #ifdef LIBXML_REGEXP_ENABLED 00257 /* 00258 * If regexp are enabled we can do continuous validation without the 00259 * need of a tree to validate the content model. this is done in each 00260 * callbacks. 00261 * Each xmlValidState represent the validation state associated to the 00262 * set of nodes currently open from the document root to the current element. 00263 */ 00264 00265 00266 typedef struct _xmlValidState { 00267 xmlElementPtr elemDecl; /* pointer to the content model */ 00268 xmlNodePtr node; /* pointer to the current node */ 00269 xmlRegExecCtxtPtr exec; /* regexp runtime */ 00270 } _xmlValidState; 00271 00272 00273 static int 00274 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { 00275 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) { 00276 ctxt->vstateMax = 10; 00277 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * 00278 sizeof(ctxt->vstateTab[0])); 00279 if (ctxt->vstateTab == NULL) { 00280 xmlVErrMemory(ctxt, "malloc failed"); 00281 return(-1); 00282 } 00283 } 00284 00285 if (ctxt->vstateNr >= ctxt->vstateMax) { 00286 xmlValidState *tmp; 00287 00288 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 00289 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 00290 if (tmp == NULL) { 00291 xmlVErrMemory(ctxt, "realloc failed"); 00292 return(-1); 00293 } 00294 ctxt->vstateMax *= 2; 00295 ctxt->vstateTab = tmp; 00296 } 00297 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr]; 00298 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl; 00299 ctxt->vstateTab[ctxt->vstateNr].node = node; 00300 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { 00301 if (elemDecl->contModel == NULL) 00302 xmlValidBuildContentModel(ctxt, elemDecl); 00303 if (elemDecl->contModel != NULL) { 00304 ctxt->vstateTab[ctxt->vstateNr].exec = 00305 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); 00306 } else { 00307 ctxt->vstateTab[ctxt->vstateNr].exec = NULL; 00308 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, 00309 XML_ERR_INTERNAL_ERROR, 00310 "Failed to build content model regexp for %s\n", 00311 node->name, NULL, NULL); 00312 } 00313 } 00314 return(ctxt->vstateNr++); 00315 } 00316 00317 static int 00318 vstateVPop(xmlValidCtxtPtr ctxt) { 00319 xmlElementPtr elemDecl; 00320 00321 if (ctxt->vstateNr < 1) return(-1); 00322 ctxt->vstateNr--; 00323 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl; 00324 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL; 00325 ctxt->vstateTab[ctxt->vstateNr].node = NULL; 00326 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { 00327 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec); 00328 } 00329 ctxt->vstateTab[ctxt->vstateNr].exec = NULL; 00330 if (ctxt->vstateNr >= 1) 00331 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1]; 00332 else 00333 ctxt->vstate = NULL; 00334 return(ctxt->vstateNr); 00335 } 00336 00337 #else /* not LIBXML_REGEXP_ENABLED */ 00338 /* 00339 * If regexp are not enabled, it uses a home made algorithm less 00340 * complex and easier to 00341 * debug/maintain than a generic NFA -> DFA state based algo. The 00342 * only restriction is on the deepness of the tree limited by the 00343 * size of the occurs bitfield 00344 * 00345 * this is the content of a saved state for rollbacks 00346 */ 00347 00348 #define ROLLBACK_OR 0 00349 #define ROLLBACK_PARENT 1 00350 00351 typedef struct _xmlValidState { 00352 xmlElementContentPtr cont; /* pointer to the content model subtree */ 00353 xmlNodePtr node; /* pointer to the current node in the list */ 00354 long occurs;/* bitfield for multiple occurrences */ 00355 unsigned char depth; /* current depth in the overall tree */ 00356 unsigned char state; /* ROLLBACK_XXX */ 00357 } _xmlValidState; 00358 00359 #define MAX_RECURSE 25000 00360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8) 00361 #define CONT ctxt->vstate->cont 00362 #define NODE ctxt->vstate->node 00363 #define DEPTH ctxt->vstate->depth 00364 #define OCCURS ctxt->vstate->occurs 00365 #define STATE ctxt->vstate->state 00366 00367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH)) 00368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1)) 00369 00370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH) 00371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1) 00372 00373 static int 00374 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, 00375 xmlNodePtr node, unsigned char depth, long occurs, 00376 unsigned char state) { 00377 int i = ctxt->vstateNr - 1; 00378 00379 if (ctxt->vstateNr > MAX_RECURSE) { 00380 return(-1); 00381 } 00382 if (ctxt->vstateTab == NULL) { 00383 ctxt->vstateMax = 8; 00384 ctxt->vstateTab = (xmlValidState *) xmlMalloc( 00385 ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 00386 if (ctxt->vstateTab == NULL) { 00387 xmlVErrMemory(ctxt, "malloc failed"); 00388 return(-1); 00389 } 00390 } 00391 if (ctxt->vstateNr >= ctxt->vstateMax) { 00392 xmlValidState *tmp; 00393 00394 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 00395 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 00396 if (tmp == NULL) { 00397 xmlVErrMemory(ctxt, "malloc failed"); 00398 return(-1); 00399 } 00400 ctxt->vstateMax *= 2; 00401 ctxt->vstateTab = tmp; 00402 ctxt->vstate = &ctxt->vstateTab[0]; 00403 } 00404 /* 00405 * Don't push on the stack a state already here 00406 */ 00407 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) && 00408 (ctxt->vstateTab[i].node == node) && 00409 (ctxt->vstateTab[i].depth == depth) && 00410 (ctxt->vstateTab[i].occurs == occurs) && 00411 (ctxt->vstateTab[i].state == state)) 00412 return(ctxt->vstateNr); 00413 ctxt->vstateTab[ctxt->vstateNr].cont = cont; 00414 ctxt->vstateTab[ctxt->vstateNr].node = node; 00415 ctxt->vstateTab[ctxt->vstateNr].depth = depth; 00416 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs; 00417 ctxt->vstateTab[ctxt->vstateNr].state = state; 00418 return(ctxt->vstateNr++); 00419 } 00420 00421 static int 00422 vstateVPop(xmlValidCtxtPtr ctxt) { 00423 if (ctxt->vstateNr <= 1) return(-1); 00424 ctxt->vstateNr--; 00425 ctxt->vstate = &ctxt->vstateTab[0]; 00426 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont; 00427 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node; 00428 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth; 00429 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs; 00430 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state; 00431 return(ctxt->vstateNr); 00432 } 00433 00434 #endif /* LIBXML_REGEXP_ENABLED */ 00435 00436 static int 00437 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) 00438 { 00439 if (ctxt->nodeMax <= 0) { 00440 ctxt->nodeMax = 4; 00441 ctxt->nodeTab = 00442 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * 00443 sizeof(ctxt->nodeTab[0])); 00444 if (ctxt->nodeTab == NULL) { 00445 xmlVErrMemory(ctxt, "malloc failed"); 00446 ctxt->nodeMax = 0; 00447 return (0); 00448 } 00449 } 00450 if (ctxt->nodeNr >= ctxt->nodeMax) { 00451 xmlNodePtr *tmp; 00452 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, 00453 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); 00454 if (tmp == NULL) { 00455 xmlVErrMemory(ctxt, "realloc failed"); 00456 return (0); 00457 } 00458 ctxt->nodeMax *= 2; 00459 ctxt->nodeTab = tmp; 00460 } 00461 ctxt->nodeTab[ctxt->nodeNr] = value; 00462 ctxt->node = value; 00463 return (ctxt->nodeNr++); 00464 } 00465 static xmlNodePtr 00466 nodeVPop(xmlValidCtxtPtr ctxt) 00467 { 00468 xmlNodePtr ret; 00469 00470 if (ctxt->nodeNr <= 0) 00471 return (NULL); 00472 ctxt->nodeNr--; 00473 if (ctxt->nodeNr > 0) 00474 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; 00475 else 00476 ctxt->node = NULL; 00477 ret = ctxt->nodeTab[ctxt->nodeNr]; 00478 ctxt->nodeTab[ctxt->nodeNr] = NULL; 00479 return (ret); 00480 } 00481 00482 #ifdef DEBUG_VALID_ALGO 00483 static void 00484 xmlValidPrintNode(xmlNodePtr cur) { 00485 if (cur == NULL) { 00486 xmlGenericError(xmlGenericErrorContext, "null"); 00487 return; 00488 } 00489 switch (cur->type) { 00490 case XML_ELEMENT_NODE: 00491 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name); 00492 break; 00493 case XML_TEXT_NODE: 00494 xmlGenericError(xmlGenericErrorContext, "text "); 00495 break; 00496 case XML_CDATA_SECTION_NODE: 00497 xmlGenericError(xmlGenericErrorContext, "cdata "); 00498 break; 00499 case XML_ENTITY_REF_NODE: 00500 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name); 00501 break; 00502 case XML_PI_NODE: 00503 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name); 00504 break; 00505 case XML_COMMENT_NODE: 00506 xmlGenericError(xmlGenericErrorContext, "comment "); 00507 break; 00508 case XML_ATTRIBUTE_NODE: 00509 xmlGenericError(xmlGenericErrorContext, "?attr? "); 00510 break; 00511 case XML_ENTITY_NODE: 00512 xmlGenericError(xmlGenericErrorContext, "?ent? "); 00513 break; 00514 case XML_DOCUMENT_NODE: 00515 xmlGenericError(xmlGenericErrorContext, "?doc? "); 00516 break; 00517 case XML_DOCUMENT_TYPE_NODE: 00518 xmlGenericError(xmlGenericErrorContext, "?doctype? "); 00519 break; 00520 case XML_DOCUMENT_FRAG_NODE: 00521 xmlGenericError(xmlGenericErrorContext, "?frag? "); 00522 break; 00523 case XML_NOTATION_NODE: 00524 xmlGenericError(xmlGenericErrorContext, "?nota? "); 00525 break; 00526 case XML_HTML_DOCUMENT_NODE: 00527 xmlGenericError(xmlGenericErrorContext, "?html? "); 00528 break; 00529 #ifdef LIBXML_DOCB_ENABLED 00530 case XML_DOCB_DOCUMENT_NODE: 00531 xmlGenericError(xmlGenericErrorContext, "?docb? "); 00532 break; 00533 #endif 00534 case XML_DTD_NODE: 00535 xmlGenericError(xmlGenericErrorContext, "?dtd? "); 00536 break; 00537 case XML_ELEMENT_DECL: 00538 xmlGenericError(xmlGenericErrorContext, "?edecl? "); 00539 break; 00540 case XML_ATTRIBUTE_DECL: 00541 xmlGenericError(xmlGenericErrorContext, "?adecl? "); 00542 break; 00543 case XML_ENTITY_DECL: 00544 xmlGenericError(xmlGenericErrorContext, "?entdecl? "); 00545 break; 00546 case XML_NAMESPACE_DECL: 00547 xmlGenericError(xmlGenericErrorContext, "?nsdecl? "); 00548 break; 00549 case XML_XINCLUDE_START: 00550 xmlGenericError(xmlGenericErrorContext, "incstart "); 00551 break; 00552 case XML_XINCLUDE_END: 00553 xmlGenericError(xmlGenericErrorContext, "incend "); 00554 break; 00555 } 00556 } 00557 00558 static void 00559 xmlValidPrintNodeList(xmlNodePtr cur) { 00560 if (cur == NULL) 00561 xmlGenericError(xmlGenericErrorContext, "null "); 00562 while (cur != NULL) { 00563 xmlValidPrintNode(cur); 00564 cur = cur->next; 00565 } 00566 } 00567 00568 static void 00569 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) { 00570 char expr[5000]; 00571 00572 expr[0] = 0; 00573 xmlGenericError(xmlGenericErrorContext, "valid: "); 00574 xmlValidPrintNodeList(cur); 00575 xmlGenericError(xmlGenericErrorContext, "against "); 00576 xmlSnprintfElementContent(expr, 5000, cont, 1); 00577 xmlGenericError(xmlGenericErrorContext, "%s\n", expr); 00578 } 00579 00580 static void 00581 xmlValidDebugState(xmlValidStatePtr state) { 00582 xmlGenericError(xmlGenericErrorContext, "("); 00583 if (state->cont == NULL) 00584 xmlGenericError(xmlGenericErrorContext, "null,"); 00585 else 00586 switch (state->cont->type) { 00587 case XML_ELEMENT_CONTENT_PCDATA: 00588 xmlGenericError(xmlGenericErrorContext, "pcdata,"); 00589 break; 00590 case XML_ELEMENT_CONTENT_ELEMENT: 00591 xmlGenericError(xmlGenericErrorContext, "%s,", 00592 state->cont->name); 00593 break; 00594 case XML_ELEMENT_CONTENT_SEQ: 00595 xmlGenericError(xmlGenericErrorContext, "seq,"); 00596 break; 00597 case XML_ELEMENT_CONTENT_OR: 00598 xmlGenericError(xmlGenericErrorContext, "or,"); 00599 break; 00600 } 00601 xmlValidPrintNode(state->node); 00602 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)", 00603 state->depth, state->occurs, state->state); 00604 } 00605 00606 static void 00607 xmlValidStateDebug(xmlValidCtxtPtr ctxt) { 00608 int i, j; 00609 00610 xmlGenericError(xmlGenericErrorContext, "state: "); 00611 xmlValidDebugState(ctxt->vstate); 00612 xmlGenericError(xmlGenericErrorContext, " stack: %d ", 00613 ctxt->vstateNr - 1); 00614 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--) 00615 xmlValidDebugState(&ctxt->vstateTab[j]); 00616 xmlGenericError(xmlGenericErrorContext, "\n"); 00617 } 00618 00619 /***** 00620 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c); 00621 *****/ 00622 00623 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt); 00624 #define DEBUG_VALID_MSG(m) \ 00625 xmlGenericError(xmlGenericErrorContext, "%s\n", m); 00626 00627 #else 00628 #define DEBUG_VALID_STATE(n,c) 00629 #define DEBUG_VALID_MSG(m) 00630 #endif 00631 00632 /* TODO: use hash table for accesses to elem and attribute definitions */ 00633 00634 00635 #define CHECK_DTD \ 00636 if (doc == NULL) return(0); \ 00637 else if ((doc->intSubset == NULL) && \ 00638 (doc->extSubset == NULL)) return(0) 00639 00640 #ifdef LIBXML_REGEXP_ENABLED 00641 00642 /************************************************************************ 00643 * * 00644 * Content model validation based on the regexps * 00645 * * 00646 ************************************************************************/ 00647 00658 static int 00659 xmlValidBuildAContentModel(xmlElementContentPtr content, 00660 xmlValidCtxtPtr ctxt, 00661 const xmlChar *name) { 00662 if (content == NULL) { 00663 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, 00664 "Found NULL content in content model of %s\n", 00665 name, NULL, NULL); 00666 return(0); 00667 } 00668 switch (content->type) { 00669 case XML_ELEMENT_CONTENT_PCDATA: 00670 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, 00671 "Found PCDATA in content model of %s\n", 00672 name, NULL, NULL); 00673 return(0); 00674 break; 00675 case XML_ELEMENT_CONTENT_ELEMENT: { 00676 xmlAutomataStatePtr oldstate = ctxt->state; 00677 xmlChar fn[50]; 00678 xmlChar *fullname; 00679 00680 fullname = xmlBuildQName(content->name, content->prefix, fn, 50); 00681 if (fullname == NULL) { 00682 xmlVErrMemory(ctxt, "Building content model"); 00683 return(0); 00684 } 00685 00686 switch (content->ocur) { 00687 case XML_ELEMENT_CONTENT_ONCE: 00688 ctxt->state = xmlAutomataNewTransition(ctxt->am, 00689 ctxt->state, NULL, fullname, NULL); 00690 break; 00691 case XML_ELEMENT_CONTENT_OPT: 00692 ctxt->state = xmlAutomataNewTransition(ctxt->am, 00693 ctxt->state, NULL, fullname, NULL); 00694 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 00695 break; 00696 case XML_ELEMENT_CONTENT_PLUS: 00697 ctxt->state = xmlAutomataNewTransition(ctxt->am, 00698 ctxt->state, NULL, fullname, NULL); 00699 xmlAutomataNewTransition(ctxt->am, ctxt->state, 00700 ctxt->state, fullname, NULL); 00701 break; 00702 case XML_ELEMENT_CONTENT_MULT: 00703 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, 00704 ctxt->state, NULL); 00705 xmlAutomataNewTransition(ctxt->am, 00706 ctxt->state, ctxt->state, fullname, NULL); 00707 break; 00708 } 00709 if ((fullname != fn) && (fullname != content->name)) 00710 xmlFree(fullname); 00711 break; 00712 } 00713 case XML_ELEMENT_CONTENT_SEQ: { 00714 xmlAutomataStatePtr oldstate, oldend; 00715 xmlElementContentOccur ocur; 00716 00717 /* 00718 * Simply iterate over the content 00719 */ 00720 oldstate = ctxt->state; 00721 ocur = content->ocur; 00722 if (ocur != XML_ELEMENT_CONTENT_ONCE) { 00723 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); 00724 oldstate = ctxt->state; 00725 } 00726 do { 00727 xmlValidBuildAContentModel(content->c1, ctxt, name); 00728 content = content->c2; 00729 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && 00730 (content->ocur == XML_ELEMENT_CONTENT_ONCE)); 00731 xmlValidBuildAContentModel(content, ctxt, name); 00732 oldend = ctxt->state; 00733 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); 00734 switch (ocur) { 00735 case XML_ELEMENT_CONTENT_ONCE: 00736 break; 00737 case XML_ELEMENT_CONTENT_OPT: 00738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 00739 break; 00740 case XML_ELEMENT_CONTENT_MULT: 00741 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 00742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 00743 break; 00744 case XML_ELEMENT_CONTENT_PLUS: 00745 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 00746 break; 00747 } 00748 break; 00749 } 00750 case XML_ELEMENT_CONTENT_OR: { 00751 xmlAutomataStatePtr oldstate, oldend; 00752 xmlElementContentOccur ocur; 00753 00754 ocur = content->ocur; 00755 if ((ocur == XML_ELEMENT_CONTENT_PLUS) || 00756 (ocur == XML_ELEMENT_CONTENT_MULT)) { 00757 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, 00758 ctxt->state, NULL); 00759 } 00760 oldstate = ctxt->state; 00761 oldend = xmlAutomataNewState(ctxt->am); 00762 00763 /* 00764 * iterate over the subtypes and remerge the end with an 00765 * epsilon transition 00766 */ 00767 do { 00768 ctxt->state = oldstate; 00769 xmlValidBuildAContentModel(content->c1, ctxt, name); 00770 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); 00771 content = content->c2; 00772 } while ((content->type == XML_ELEMENT_CONTENT_OR) && 00773 (content->ocur == XML_ELEMENT_CONTENT_ONCE)); 00774 ctxt->state = oldstate; 00775 xmlValidBuildAContentModel(content, ctxt, name); 00776 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); 00777 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); 00778 switch (ocur) { 00779 case XML_ELEMENT_CONTENT_ONCE: 00780 break; 00781 case XML_ELEMENT_CONTENT_OPT: 00782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 00783 break; 00784 case XML_ELEMENT_CONTENT_MULT: 00785 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); 00786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 00787 break; 00788 case XML_ELEMENT_CONTENT_PLUS: 00789 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); 00790 break; 00791 } 00792 break; 00793 } 00794 default: 00795 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 00796 "ContentModel broken for element %s\n", 00797 (const char *) name); 00798 return(0); 00799 } 00800 return(1); 00801 } 00812 int 00813 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { 00814 00815 if ((ctxt == NULL) || (elem == NULL)) 00816 return(0); 00817 if (elem->type != XML_ELEMENT_DECL) 00818 return(0); 00819 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT) 00820 return(1); 00821 /* TODO: should we rebuild in this case ? */ 00822 if (elem->contModel != NULL) { 00823 if (!xmlRegexpIsDeterminist(elem->contModel)) { 00824 ctxt->valid = 0; 00825 return(0); 00826 } 00827 return(1); 00828 } 00829 00830 ctxt->am = xmlNewAutomata(); 00831 if (ctxt->am == NULL) { 00832 xmlErrValidNode(ctxt, (xmlNodePtr) elem, 00833 XML_ERR_INTERNAL_ERROR, 00834 "Cannot create automata for element %s\n", 00835 elem->name, NULL, NULL); 00836 return(0); 00837 } 00838 ctxt->state = xmlAutomataGetInitState(ctxt->am); 00839 xmlValidBuildAContentModel(elem->content, ctxt, elem->name); 00840 xmlAutomataSetFinalState(ctxt->am, ctxt->state); 00841 elem->contModel = xmlAutomataCompile(ctxt->am); 00842 if (xmlRegexpIsDeterminist(elem->contModel) != 1) { 00843 char expr[5000]; 00844 expr[0] = 0; 00845 xmlSnprintfElementContent(expr, 5000, elem->content, 1); 00846 xmlErrValidNode(ctxt, (xmlNodePtr) elem, 00847 XML_DTD_CONTENT_NOT_DETERMINIST, 00848 "Content model of %s is not determinist: %s\n", 00849 elem->name, BAD_CAST expr, NULL); 00850 #ifdef DEBUG_REGEXP_ALGO 00851 xmlRegexpPrint(stderr, elem->contModel); 00852 #endif 00853 ctxt->valid = 0; 00854 ctxt->state = NULL; 00855 xmlFreeAutomata(ctxt->am); 00856 ctxt->am = NULL; 00857 return(0); 00858 } 00859 ctxt->state = NULL; 00860 xmlFreeAutomata(ctxt->am); 00861 ctxt->am = NULL; 00862 return(1); 00863 } 00864 00865 #endif /* LIBXML_REGEXP_ENABLED */ 00866 00867 /**************************************************************** 00868 * * 00869 * Util functions for data allocation/deallocation * 00870 * * 00871 ****************************************************************/ 00872 00880 xmlValidCtxtPtr xmlNewValidCtxt(void) { 00881 xmlValidCtxtPtr ret; 00882 00883 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { 00884 xmlVErrMemory(NULL, "malloc failed"); 00885 return (NULL); 00886 } 00887 00888 (void) memset(ret, 0, sizeof (xmlValidCtxt)); 00889 00890 return (ret); 00891 } 00892 00899 void 00900 xmlFreeValidCtxt(xmlValidCtxtPtr cur) { 00901 if (cur->vstateTab != NULL) 00902 xmlFree(cur->vstateTab); 00903 if (cur->nodeTab != NULL) 00904 xmlFree(cur->nodeTab); 00905 xmlFree(cur); 00906 } 00907 00908 #endif /* LIBXML_VALID_ENABLED */ 00909 00920 xmlElementContentPtr 00921 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, 00922 xmlElementContentType type) { 00923 xmlElementContentPtr ret; 00924 xmlDictPtr dict = NULL; 00925 00926 if (doc != NULL) 00927 dict = doc->dict; 00928 00929 switch(type) { 00930 case XML_ELEMENT_CONTENT_ELEMENT: 00931 if (name == NULL) { 00932 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 00933 "xmlNewElementContent : name == NULL !\n", 00934 NULL); 00935 } 00936 break; 00937 case XML_ELEMENT_CONTENT_PCDATA: 00938 case XML_ELEMENT_CONTENT_SEQ: 00939 case XML_ELEMENT_CONTENT_OR: 00940 if (name != NULL) { 00941 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 00942 "xmlNewElementContent : name != NULL !\n", 00943 NULL); 00944 } 00945 break; 00946 default: 00947 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 00948 "Internal: ELEMENT content corrupted invalid type\n", 00949 NULL); 00950 return(NULL); 00951 } 00952 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 00953 if (ret == NULL) { 00954 xmlVErrMemory(NULL, "malloc failed"); 00955 return(NULL); 00956 } 00957 memset(ret, 0, sizeof(xmlElementContent)); 00958 ret->type = type; 00959 ret->ocur = XML_ELEMENT_CONTENT_ONCE; 00960 if (name != NULL) { 00961 int l; 00962 const xmlChar *tmp; 00963 00964 tmp = xmlSplitQName3(name, &l); 00965 if (tmp == NULL) { 00966 if (dict == NULL) 00967 ret->name = xmlStrdup(name); 00968 else 00969 ret->name = xmlDictLookup(dict, name, -1); 00970 } else { 00971 if (dict == NULL) { 00972 ret->prefix = xmlStrndup(name, l); 00973 ret->name = xmlStrdup(tmp); 00974 } else { 00975 ret->prefix = xmlDictLookup(dict, name, l); 00976 ret->name = xmlDictLookup(dict, tmp, -1); 00977 } 00978 } 00979 } 00980 return(ret); 00981 } 00982 00993 xmlElementContentPtr 00994 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) { 00995 return(xmlNewDocElementContent(NULL, name, type)); 00996 } 00997 01007 xmlElementContentPtr 01008 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { 01009 xmlElementContentPtr ret = NULL, prev = NULL, tmp; 01010 xmlDictPtr dict = NULL; 01011 01012 if (cur == NULL) return(NULL); 01013 01014 if (doc != NULL) 01015 dict = doc->dict; 01016 01017 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 01018 if (ret == NULL) { 01019 xmlVErrMemory(NULL, "malloc failed"); 01020 return(NULL); 01021 } 01022 memset(ret, 0, sizeof(xmlElementContent)); 01023 ret->type = cur->type; 01024 ret->ocur = cur->ocur; 01025 if (cur->name != NULL) { 01026 if (dict) 01027 ret->name = xmlDictLookup(dict, cur->name, -1); 01028 else 01029 ret->name = xmlStrdup(cur->name); 01030 } 01031 01032 if (cur->prefix != NULL) { 01033 if (dict) 01034 ret->prefix = xmlDictLookup(dict, cur->prefix, -1); 01035 else 01036 ret->prefix = xmlStrdup(cur->prefix); 01037 } 01038 if (cur->c1 != NULL) 01039 ret->c1 = xmlCopyDocElementContent(doc, cur->c1); 01040 if (ret->c1 != NULL) 01041 ret->c1->parent = ret; 01042 if (cur->c2 != NULL) { 01043 prev = ret; 01044 cur = cur->c2; 01045 while (cur != NULL) { 01046 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); 01047 if (tmp == NULL) { 01048 xmlVErrMemory(NULL, "malloc failed"); 01049 return(ret); 01050 } 01051 memset(tmp, 0, sizeof(xmlElementContent)); 01052 tmp->type = cur->type; 01053 tmp->ocur = cur->ocur; 01054 prev->c2 = tmp; 01055 if (cur->name != NULL) { 01056 if (dict) 01057 tmp->name = xmlDictLookup(dict, cur->name, -1); 01058 else 01059 tmp->name = xmlStrdup(cur->name); 01060 } 01061 01062 if (cur->prefix != NULL) { 01063 if (dict) 01064 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); 01065 else 01066 tmp->prefix = xmlStrdup(cur->prefix); 01067 } 01068 if (cur->c1 != NULL) 01069 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); 01070 if (tmp->c1 != NULL) 01071 tmp->c1->parent = ret; 01072 prev = tmp; 01073 cur = cur->c2; 01074 } 01075 } 01076 return(ret); 01077 } 01078 01088 xmlElementContentPtr 01089 xmlCopyElementContent(xmlElementContentPtr cur) { 01090 return(xmlCopyDocElementContent(NULL, cur)); 01091 } 01092 01100 void 01101 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { 01102 xmlElementContentPtr next; 01103 xmlDictPtr dict = NULL; 01104 01105 if (doc != NULL) 01106 dict = doc->dict; 01107 01108 while (cur != NULL) { 01109 next = cur->c2; 01110 switch (cur->type) { 01111 case XML_ELEMENT_CONTENT_PCDATA: 01112 case XML_ELEMENT_CONTENT_ELEMENT: 01113 case XML_ELEMENT_CONTENT_SEQ: 01114 case XML_ELEMENT_CONTENT_OR: 01115 break; 01116 default: 01117 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 01118 "Internal: ELEMENT content corrupted invalid type\n", 01119 NULL); 01120 return; 01121 } 01122 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1); 01123 if (dict) { 01124 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) 01125 xmlFree((xmlChar *) cur->name); 01126 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix))) 01127 xmlFree((xmlChar *) cur->prefix); 01128 } else { 01129 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 01130 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix); 01131 } 01132 xmlFree(cur); 01133 cur = next; 01134 } 01135 } 01136 01144 void 01145 xmlFreeElementContent(xmlElementContentPtr cur) { 01146 xmlFreeDocElementContent(NULL, cur); 01147 } 01148 01149 #ifdef LIBXML_OUTPUT_ENABLED 01150 01158 static void 01159 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) { 01160 if (content == NULL) return; 01161 01162 if (glob) xmlBufferWriteChar(buf, "("); 01163 switch (content->type) { 01164 case XML_ELEMENT_CONTENT_PCDATA: 01165 xmlBufferWriteChar(buf, "#PCDATA"); 01166 break; 01167 case XML_ELEMENT_CONTENT_ELEMENT: 01168 if (content->prefix != NULL) { 01169 xmlBufferWriteCHAR(buf, content->prefix); 01170 xmlBufferWriteChar(buf, ":"); 01171 } 01172 xmlBufferWriteCHAR(buf, content->name); 01173 break; 01174 case XML_ELEMENT_CONTENT_SEQ: 01175 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 01176 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 01177 xmlDumpElementContent(buf, content->c1, 1); 01178 else 01179 xmlDumpElementContent(buf, content->c1, 0); 01180 xmlBufferWriteChar(buf, " , "); 01181 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) || 01182 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) && 01183 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))) 01184 xmlDumpElementContent(buf, content->c2, 1); 01185 else 01186 xmlDumpElementContent(buf, content->c2, 0); 01187 break; 01188 case XML_ELEMENT_CONTENT_OR: 01189 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 01190 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 01191 xmlDumpElementContent(buf, content->c1, 1); 01192 else 01193 xmlDumpElementContent(buf, content->c1, 0); 01194 xmlBufferWriteChar(buf, " | "); 01195 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || 01196 ((content->c2->type == XML_ELEMENT_CONTENT_OR) && 01197 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))) 01198 xmlDumpElementContent(buf, content->c2, 1); 01199 else 01200 xmlDumpElementContent(buf, content->c2, 0); 01201 break; 01202 default: 01203 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 01204 "Internal: ELEMENT content corrupted invalid type\n", 01205 NULL); 01206 } 01207 if (glob) 01208 xmlBufferWriteChar(buf, ")"); 01209 switch (content->ocur) { 01210 case XML_ELEMENT_CONTENT_ONCE: 01211 break; 01212 case XML_ELEMENT_CONTENT_OPT: 01213 xmlBufferWriteChar(buf, "?"); 01214 break; 01215 case XML_ELEMENT_CONTENT_MULT: 01216 xmlBufferWriteChar(buf, "*"); 01217 break; 01218 case XML_ELEMENT_CONTENT_PLUS: 01219 xmlBufferWriteChar(buf, "+"); 01220 break; 01221 } 01222 } 01223 01232 void 01233 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED, 01234 xmlElementContentPtr content ATTRIBUTE_UNUSED, 01235 int englob ATTRIBUTE_UNUSED) { 01236 } 01237 #endif /* LIBXML_OUTPUT_ENABLED */ 01238 01249 void 01250 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) { 01251 int len; 01252 01253 if (content == NULL) return; 01254 len = strlen(buf); 01255 if (size - len < 50) { 01256 if ((size - len > 4) && (buf[len - 1] != '.')) 01257 strcat(buf, " ..."); 01258 return; 01259 } 01260 if (englob) strcat(buf, "("); 01261 switch (content->type) { 01262 case XML_ELEMENT_CONTENT_PCDATA: 01263 strcat(buf, "#PCDATA"); 01264 break; 01265 case XML_ELEMENT_CONTENT_ELEMENT: 01266 if (content->prefix != NULL) { 01267 if (size - len < xmlStrlen(content->prefix) + 10) { 01268 strcat(buf, " ..."); 01269 return; 01270 } 01271 strcat(buf, (char *) content->prefix); 01272 strcat(buf, ":"); 01273 } 01274 if (size - len < xmlStrlen(content->name) + 10) { 01275 strcat(buf, " ..."); 01276 return; 01277 } 01278 if (content->name != NULL) 01279 strcat(buf, (char *) content->name); 01280 break; 01281 case XML_ELEMENT_CONTENT_SEQ: 01282 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 01283 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 01284 xmlSnprintfElementContent(buf, size, content->c1, 1); 01285 else 01286 xmlSnprintfElementContent(buf, size, content->c1, 0); 01287 len = strlen(buf); 01288 if (size - len < 50) { 01289 if ((size - len > 4) && (buf[len - 1] != '.')) 01290 strcat(buf, " ..."); 01291 return; 01292 } 01293 strcat(buf, " , "); 01294 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) || 01295 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && 01296 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) 01297 xmlSnprintfElementContent(buf, size, content->c2, 1); 01298 else 01299 xmlSnprintfElementContent(buf, size, content->c2, 0); 01300 break; 01301 case XML_ELEMENT_CONTENT_OR: 01302 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || 01303 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) 01304 xmlSnprintfElementContent(buf, size, content->c1, 1); 01305 else 01306 xmlSnprintfElementContent(buf, size, content->c1, 0); 01307 len = strlen(buf); 01308 if (size - len < 50) { 01309 if ((size - len > 4) && (buf[len - 1] != '.')) 01310 strcat(buf, " ..."); 01311 return; 01312 } 01313 strcat(buf, " | "); 01314 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || 01315 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && 01316 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) 01317 xmlSnprintfElementContent(buf, size, content->c2, 1); 01318 else 01319 xmlSnprintfElementContent(buf, size, content->c2, 0); 01320 break; 01321 } 01322 if (englob) 01323 strcat(buf, ")"); 01324 switch (content->ocur) { 01325 case XML_ELEMENT_CONTENT_ONCE: 01326 break; 01327 case XML_ELEMENT_CONTENT_OPT: 01328 strcat(buf, "?"); 01329 break; 01330 case XML_ELEMENT_CONTENT_MULT: 01331 strcat(buf, "*"); 01332 break; 01333 case XML_ELEMENT_CONTENT_PLUS: 01334 strcat(buf, "+"); 01335 break; 01336 } 01337 } 01338 01339 /**************************************************************** 01340 * * 01341 * Registration of DTD declarations * 01342 * * 01343 ****************************************************************/ 01344 01351 static void 01352 xmlFreeElement(xmlElementPtr elem) { 01353 if (elem == NULL) return; 01354 xmlUnlinkNode((xmlNodePtr) elem); 01355 xmlFreeDocElementContent(elem->doc, elem->content); 01356 if (elem->name != NULL) 01357 xmlFree((xmlChar *) elem->name); 01358 if (elem->prefix != NULL) 01359 xmlFree((xmlChar *) elem->prefix); 01360 #ifdef LIBXML_REGEXP_ENABLED 01361 if (elem->contModel != NULL) 01362 xmlRegFreeRegexp(elem->contModel); 01363 #endif 01364 xmlFree(elem); 01365 } 01366 01367 01380 xmlElementPtr 01381 xmlAddElementDecl(xmlValidCtxtPtr ctxt, 01382 xmlDtdPtr dtd, const xmlChar *name, 01383 xmlElementTypeVal type, 01384 xmlElementContentPtr content) { 01385 xmlElementPtr ret; 01386 xmlElementTablePtr table; 01387 xmlAttributePtr oldAttributes = NULL; 01388 xmlChar *ns, *uqname; 01389 01390 if (dtd == NULL) { 01391 return(NULL); 01392 } 01393 if (name == NULL) { 01394 return(NULL); 01395 } 01396 01397 switch (type) { 01398 case XML_ELEMENT_TYPE_EMPTY: 01399 if (content != NULL) { 01400 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01401 "xmlAddElementDecl: content != NULL for EMPTY\n", 01402 NULL); 01403 return(NULL); 01404 } 01405 break; 01406 case XML_ELEMENT_TYPE_ANY: 01407 if (content != NULL) { 01408 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01409 "xmlAddElementDecl: content != NULL for ANY\n", 01410 NULL); 01411 return(NULL); 01412 } 01413 break; 01414 case XML_ELEMENT_TYPE_MIXED: 01415 if (content == NULL) { 01416 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01417 "xmlAddElementDecl: content == NULL for MIXED\n", 01418 NULL); 01419 return(NULL); 01420 } 01421 break; 01422 case XML_ELEMENT_TYPE_ELEMENT: 01423 if (content == NULL) { 01424 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01425 "xmlAddElementDecl: content == NULL for ELEMENT\n", 01426 NULL); 01427 return(NULL); 01428 } 01429 break; 01430 default: 01431 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01432 "Internal: ELEMENT decl corrupted invalid type\n", 01433 NULL); 01434 return(NULL); 01435 } 01436 01437 /* 01438 * check if name is a QName 01439 */ 01440 uqname = xmlSplitQName2(name, &ns); 01441 if (uqname != NULL) 01442 name = uqname; 01443 01444 /* 01445 * Create the Element table if needed. 01446 */ 01447 table = (xmlElementTablePtr) dtd->elements; 01448 if (table == NULL) { 01449 xmlDictPtr dict = NULL; 01450 01451 if (dtd->doc != NULL) 01452 dict = dtd->doc->dict; 01453 table = xmlHashCreateDict(0, dict); 01454 dtd->elements = (void *) table; 01455 } 01456 if (table == NULL) { 01457 xmlVErrMemory(ctxt, 01458 "xmlAddElementDecl: Table creation failed!\n"); 01459 if (uqname != NULL) 01460 xmlFree(uqname); 01461 if (ns != NULL) 01462 xmlFree(ns); 01463 return(NULL); 01464 } 01465 01466 /* 01467 * lookup old attributes inserted on an undefined element in the 01468 * internal subset. 01469 */ 01470 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) { 01471 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns); 01472 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { 01473 oldAttributes = ret->attributes; 01474 ret->attributes = NULL; 01475 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); 01476 xmlFreeElement(ret); 01477 } 01478 } 01479 01480 /* 01481 * The element may already be present if one of its attribute 01482 * was registered first 01483 */ 01484 ret = xmlHashLookup2(table, name, ns); 01485 if (ret != NULL) { 01486 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) { 01487 #ifdef LIBXML_VALID_ENABLED 01488 /* 01489 * The element is already defined in this DTD. 01490 */ 01491 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, 01492 "Redefinition of element %s\n", 01493 name, NULL, NULL); 01494 #endif /* LIBXML_VALID_ENABLED */ 01495 if (uqname != NULL) 01496 xmlFree(uqname); 01497 if (ns != NULL) 01498 xmlFree(ns); 01499 return(NULL); 01500 } 01501 if (ns != NULL) { 01502 xmlFree(ns); 01503 ns = NULL; 01504 } 01505 } else { 01506 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 01507 if (ret == NULL) { 01508 xmlVErrMemory(ctxt, "malloc failed"); 01509 if (uqname != NULL) 01510 xmlFree(uqname); 01511 if (ns != NULL) 01512 xmlFree(ns); 01513 return(NULL); 01514 } 01515 memset(ret, 0, sizeof(xmlElement)); 01516 ret->type = XML_ELEMENT_DECL; 01517 01518 /* 01519 * fill the structure. 01520 */ 01521 ret->name = xmlStrdup(name); 01522 if (ret->name == NULL) { 01523 xmlVErrMemory(ctxt, "malloc failed"); 01524 if (uqname != NULL) 01525 xmlFree(uqname); 01526 if (ns != NULL) 01527 xmlFree(ns); 01528 xmlFree(ret); 01529 return(NULL); 01530 } 01531 ret->prefix = ns; 01532 01533 /* 01534 * Validity Check: 01535 * Insertion must not fail 01536 */ 01537 if (xmlHashAddEntry2(table, name, ns, ret)) { 01538 #ifdef LIBXML_VALID_ENABLED 01539 /* 01540 * The element is already defined in this DTD. 01541 */ 01542 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, 01543 "Redefinition of element %s\n", 01544 name, NULL, NULL); 01545 #endif /* LIBXML_VALID_ENABLED */ 01546 xmlFreeElement(ret); 01547 if (uqname != NULL) 01548 xmlFree(uqname); 01549 return(NULL); 01550 } 01551 /* 01552 * For new element, may have attributes from earlier 01553 * definition in internal subset 01554 */ 01555 ret->attributes = oldAttributes; 01556 } 01557 01558 /* 01559 * Finish to fill the structure. 01560 */ 01561 ret->etype = type; 01562 /* 01563 * Avoid a stupid copy when called by the parser 01564 * and flag it by setting a special parent value 01565 * so the parser doesn't unallocate it. 01566 */ 01567 if ((ctxt != NULL) && 01568 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || 01569 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) { 01570 ret->content = content; 01571 if (content != NULL) 01572 content->parent = (xmlElementContentPtr) 1; 01573 } else { 01574 ret->content = xmlCopyDocElementContent(dtd->doc, content); 01575 } 01576 01577 /* 01578 * Link it to the DTD 01579 */ 01580 ret->parent = dtd; 01581 ret->doc = dtd->doc; 01582 if (dtd->last == NULL) { 01583 dtd->children = dtd->last = (xmlNodePtr) ret; 01584 } else { 01585 dtd->last->next = (xmlNodePtr) ret; 01586 ret->prev = dtd->last; 01587 dtd->last = (xmlNodePtr) ret; 01588 } 01589 if (uqname != NULL) 01590 xmlFree(uqname); 01591 return(ret); 01592 } 01593 01600 void 01601 xmlFreeElementTable(xmlElementTablePtr table) { 01602 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement); 01603 } 01604 01605 #ifdef LIBXML_TREE_ENABLED 01606 01614 static xmlElementPtr 01615 xmlCopyElement(xmlElementPtr elem) { 01616 xmlElementPtr cur; 01617 01618 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 01619 if (cur == NULL) { 01620 xmlVErrMemory(NULL, "malloc failed"); 01621 return(NULL); 01622 } 01623 memset(cur, 0, sizeof(xmlElement)); 01624 cur->type = XML_ELEMENT_DECL; 01625 cur->etype = elem->etype; 01626 if (elem->name != NULL) 01627 cur->name = xmlStrdup(elem->name); 01628 else 01629 cur->name = NULL; 01630 if (elem->prefix != NULL) 01631 cur->prefix = xmlStrdup(elem->prefix); 01632 else 01633 cur->prefix = NULL; 01634 cur->content = xmlCopyElementContent(elem->content); 01635 /* TODO : rebuild the attribute list on the copy */ 01636 cur->attributes = NULL; 01637 return(cur); 01638 } 01639 01648 xmlElementTablePtr 01649 xmlCopyElementTable(xmlElementTablePtr table) { 01650 return((xmlElementTablePtr) xmlHashCopy(table, 01651 (xmlHashCopier) xmlCopyElement)); 01652 } 01653 #endif /* LIBXML_TREE_ENABLED */ 01654 01655 #ifdef LIBXML_OUTPUT_ENABLED 01656 01664 void 01665 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { 01666 if ((buf == NULL) || (elem == NULL)) 01667 return; 01668 switch (elem->etype) { 01669 case XML_ELEMENT_TYPE_EMPTY: 01670 xmlBufferWriteChar(buf, "<!ELEMENT "); 01671 if (elem->prefix != NULL) { 01672 xmlBufferWriteCHAR(buf, elem->prefix); 01673 xmlBufferWriteChar(buf, ":"); 01674 } 01675 xmlBufferWriteCHAR(buf, elem->name); 01676 xmlBufferWriteChar(buf, " EMPTY>\n"); 01677 break; 01678 case XML_ELEMENT_TYPE_ANY: 01679 xmlBufferWriteChar(buf, "<!ELEMENT "); 01680 if (elem->prefix != NULL) { 01681 xmlBufferWriteCHAR(buf, elem->prefix); 01682 xmlBufferWriteChar(buf, ":"); 01683 } 01684 xmlBufferWriteCHAR(buf, elem->name); 01685 xmlBufferWriteChar(buf, " ANY>\n"); 01686 break; 01687 case XML_ELEMENT_TYPE_MIXED: 01688 xmlBufferWriteChar(buf, "<!ELEMENT "); 01689 if (elem->prefix != NULL) { 01690 xmlBufferWriteCHAR(buf, elem->prefix); 01691 xmlBufferWriteChar(buf, ":"); 01692 } 01693 xmlBufferWriteCHAR(buf, elem->name); 01694 xmlBufferWriteChar(buf, " "); 01695 xmlDumpElementContent(buf, elem->content, 1); 01696 xmlBufferWriteChar(buf, ">\n"); 01697 break; 01698 case XML_ELEMENT_TYPE_ELEMENT: 01699 xmlBufferWriteChar(buf, "<!ELEMENT "); 01700 if (elem->prefix != NULL) { 01701 xmlBufferWriteCHAR(buf, elem->prefix); 01702 xmlBufferWriteChar(buf, ":"); 01703 } 01704 xmlBufferWriteCHAR(buf, elem->name); 01705 xmlBufferWriteChar(buf, " "); 01706 xmlDumpElementContent(buf, elem->content, 1); 01707 xmlBufferWriteChar(buf, ">\n"); 01708 break; 01709 default: 01710 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 01711 "Internal: ELEMENT struct corrupted invalid type\n", 01712 NULL); 01713 } 01714 } 01715 01724 static void 01725 xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) { 01726 xmlDumpElementDecl(buf, elem); 01727 } 01728 01736 void 01737 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { 01738 if ((buf == NULL) || (table == NULL)) 01739 return; 01740 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf); 01741 } 01742 #endif /* LIBXML_OUTPUT_ENABLED */ 01743 01753 xmlEnumerationPtr 01754 xmlCreateEnumeration(const xmlChar *name) { 01755 xmlEnumerationPtr ret; 01756 01757 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); 01758 if (ret == NULL) { 01759 xmlVErrMemory(NULL, "malloc failed"); 01760 return(NULL); 01761 } 01762 memset(ret, 0, sizeof(xmlEnumeration)); 01763 01764 if (name != NULL) 01765 ret->name = xmlStrdup(name); 01766 return(ret); 01767 } 01768 01775 void 01776 xmlFreeEnumeration(xmlEnumerationPtr cur) { 01777 if (cur == NULL) return; 01778 01779 if (cur->next != NULL) xmlFreeEnumeration(cur->next); 01780 01781 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 01782 xmlFree(cur); 01783 } 01784 01785 #ifdef LIBXML_TREE_ENABLED 01786 01795 xmlEnumerationPtr 01796 xmlCopyEnumeration(xmlEnumerationPtr cur) { 01797 xmlEnumerationPtr ret; 01798 01799 if (cur == NULL) return(NULL); 01800 ret = xmlCreateEnumeration((xmlChar *) cur->name); 01801 01802 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); 01803 else ret->next = NULL; 01804 01805 return(ret); 01806 } 01807 #endif /* LIBXML_TREE_ENABLED */ 01808 01809 #ifdef LIBXML_OUTPUT_ENABLED 01810 01817 static void 01818 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) { 01819 if ((buf == NULL) || (cur == NULL)) 01820 return; 01821 01822 xmlBufferWriteCHAR(buf, cur->name); 01823 if (cur->next == NULL) 01824 xmlBufferWriteChar(buf, ")"); 01825 else { 01826 xmlBufferWriteChar(buf, " | "); 01827 xmlDumpEnumeration(buf, cur->next); 01828 } 01829 } 01830 #endif /* LIBXML_OUTPUT_ENABLED */ 01831 01832 #ifdef LIBXML_VALID_ENABLED 01833 01844 static int 01845 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) { 01846 xmlAttributePtr cur; 01847 int ret = 0; 01848 01849 if (elem == NULL) return(0); 01850 cur = elem->attributes; 01851 while (cur != NULL) { 01852 if (cur->atype == XML_ATTRIBUTE_ID) { 01853 ret ++; 01854 if ((ret > 1) && (err)) 01855 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID, 01856 "Element %s has too many ID attributes defined : %s\n", 01857 elem->name, cur->name, NULL); 01858 } 01859 cur = cur->nexth; 01860 } 01861 return(ret); 01862 } 01863 #endif /* LIBXML_VALID_ENABLED */ 01864 01871 static void 01872 xmlFreeAttribute(xmlAttributePtr attr) { 01873 xmlDictPtr dict; 01874 01875 if (attr == NULL) return; 01876 if (attr->doc != NULL) 01877 dict = attr->doc->dict; 01878 else 01879 dict = NULL; 01880 xmlUnlinkNode((xmlNodePtr) attr); 01881 if (attr->tree != NULL) 01882 xmlFreeEnumeration(attr->tree); 01883 if (dict) { 01884 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem))) 01885 xmlFree((xmlChar *) attr->elem); 01886 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name))) 01887 xmlFree((xmlChar *) attr->name); 01888 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix))) 01889 xmlFree((xmlChar *) attr->prefix); 01890 if ((attr->defaultValue != NULL) && 01891 (!xmlDictOwns(dict, attr->defaultValue))) 01892 xmlFree((xmlChar *) attr->defaultValue); 01893 } else { 01894 if (attr->elem != NULL) 01895 xmlFree((xmlChar *) attr->elem); 01896 if (attr->name != NULL) 01897 xmlFree((xmlChar *) attr->name); 01898 if (attr->defaultValue != NULL) 01899 xmlFree((xmlChar *) attr->defaultValue); 01900 if (attr->prefix != NULL) 01901 xmlFree((xmlChar *) attr->prefix); 01902 } 01903 xmlFree(attr); 01904 } 01905 01906 01924 xmlAttributePtr 01925 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, 01926 xmlDtdPtr dtd, const xmlChar *elem, 01927 const xmlChar *name, const xmlChar *ns, 01928 xmlAttributeType type, xmlAttributeDefault def, 01929 const xmlChar *defaultValue, xmlEnumerationPtr tree) { 01930 xmlAttributePtr ret; 01931 xmlAttributeTablePtr table; 01932 xmlElementPtr elemDef; 01933 xmlDictPtr dict = NULL; 01934 01935 if (dtd == NULL) { 01936 xmlFreeEnumeration(tree); 01937 return(NULL); 01938 } 01939 if (name == NULL) { 01940 xmlFreeEnumeration(tree); 01941 return(NULL); 01942 } 01943 if (elem == NULL) { 01944 xmlFreeEnumeration(tree); 01945 return(NULL); 01946 } 01947 if (dtd->doc != NULL) 01948 dict = dtd->doc->dict; 01949 01950 #ifdef LIBXML_VALID_ENABLED 01951 /* 01952 * Check the type and possibly the default value. 01953 */ 01954 switch (type) { 01955 case XML_ATTRIBUTE_CDATA: 01956 break; 01957 case XML_ATTRIBUTE_ID: 01958 break; 01959 case XML_ATTRIBUTE_IDREF: 01960 break; 01961 case XML_ATTRIBUTE_IDREFS: 01962 break; 01963 case XML_ATTRIBUTE_ENTITY: 01964 break; 01965 case XML_ATTRIBUTE_ENTITIES: 01966 break; 01967 case XML_ATTRIBUTE_NMTOKEN: 01968 break; 01969 case XML_ATTRIBUTE_NMTOKENS: 01970 break; 01971 case XML_ATTRIBUTE_ENUMERATION: 01972 break; 01973 case XML_ATTRIBUTE_NOTATION: 01974 break; 01975 default: 01976 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 01977 "Internal: ATTRIBUTE struct corrupted invalid type\n", 01978 NULL); 01979 xmlFreeEnumeration(tree); 01980 return(NULL); 01981 } 01982 if ((defaultValue != NULL) && 01983 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) { 01984 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT, 01985 "Attribute %s of %s: invalid default value\n", 01986 elem, name, defaultValue); 01987 defaultValue = NULL; 01988 if (ctxt != NULL) 01989 ctxt->valid = 0; 01990 } 01991 #endif /* LIBXML_VALID_ENABLED */ 01992 01993 /* 01994 * Check first that an attribute defined in the external subset wasn't 01995 * already defined in the internal subset 01996 */ 01997 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) && 01998 (dtd->doc->intSubset != NULL) && 01999 (dtd->doc->intSubset->attributes != NULL)) { 02000 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem); 02001 if (ret != NULL) { 02002 xmlFreeEnumeration(tree); 02003 return(NULL); 02004 } 02005 } 02006 02007 /* 02008 * Create the Attribute table if needed. 02009 */ 02010 table = (xmlAttributeTablePtr) dtd->attributes; 02011 if (table == NULL) { 02012 table = xmlHashCreateDict(0, dict); 02013 dtd->attributes = (void *) table; 02014 } 02015 if (table == NULL) { 02016 xmlVErrMemory(ctxt, 02017 "xmlAddAttributeDecl: Table creation failed!\n"); 02018 xmlFreeEnumeration(tree); 02019 return(NULL); 02020 } 02021 02022 02023 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); 02024 if (ret == NULL) { 02025 xmlVErrMemory(ctxt, "malloc failed"); 02026 xmlFreeEnumeration(tree); 02027 return(NULL); 02028 } 02029 memset(ret, 0, sizeof(xmlAttribute)); 02030 ret->type = XML_ATTRIBUTE_DECL; 02031 02032 /* 02033 * fill the structure. 02034 */ 02035 ret->atype = type; 02036 /* 02037 * doc must be set before possible error causes call 02038 * to xmlFreeAttribute (because it's used to check on 02039 * dict use) 02040 */ 02041 ret->doc = dtd->doc; 02042 if (dict) { 02043 ret->name = xmlDictLookup(dict, name, -1); 02044 ret->prefix = xmlDictLookup(dict, ns, -1); 02045 ret->elem = xmlDictLookup(dict, elem, -1); 02046 } else { 02047 ret->name = xmlStrdup(name); 02048 ret->prefix = xmlStrdup(ns); 02049 ret->elem = xmlStrdup(elem); 02050 } 02051 ret->def = def; 02052 ret->tree = tree; 02053 if (defaultValue != NULL) { 02054 if (dict) 02055 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); 02056 else 02057 ret->defaultValue = xmlStrdup(defaultValue); 02058 } 02059 02060 /* 02061 * Validity Check: 02062 * Search the DTD for previous declarations of the ATTLIST 02063 */ 02064 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) { 02065 #ifdef LIBXML_VALID_ENABLED 02066 /* 02067 * The attribute is already defined in this DTD. 02068 */ 02069 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED, 02070 "Attribute %s of element %s: already defined\n", 02071 name, elem, NULL); 02072 #endif /* LIBXML_VALID_ENABLED */ 02073 xmlFreeAttribute(ret); 02074 return(NULL); 02075 } 02076 02077 /* 02078 * Validity Check: 02079 * Multiple ID per element 02080 */ 02081 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1); 02082 if (elemDef != NULL) { 02083 02084 #ifdef LIBXML_VALID_ENABLED 02085 if ((type == XML_ATTRIBUTE_ID) && 02086 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) { 02087 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, 02088 "Element %s has too may ID attributes defined : %s\n", 02089 elem, name, NULL); 02090 if (ctxt != NULL) 02091 ctxt->valid = 0; 02092 } 02093 #endif /* LIBXML_VALID_ENABLED */ 02094 02095 /* 02096 * Insert namespace default def first they need to be 02097 * processed first. 02098 */ 02099 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || 02100 ((ret->prefix != NULL && 02101 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { 02102 ret->nexth = elemDef->attributes; 02103 elemDef->attributes = ret; 02104 } else { 02105 xmlAttributePtr tmp = elemDef->attributes; 02106 02107 while ((tmp != NULL) && 02108 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || 02109 ((ret->prefix != NULL && 02110 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { 02111 if (tmp->nexth == NULL) 02112 break; 02113 tmp = tmp->nexth; 02114 } 02115 if (tmp != NULL) { 02116 ret->nexth = tmp->nexth; 02117 tmp->nexth = ret; 02118 } else { 02119 ret->nexth = elemDef->attributes; 02120 elemDef->attributes = ret; 02121 } 02122 } 02123 } 02124 02125 /* 02126 * Link it to the DTD 02127 */ 02128 ret->parent = dtd; 02129 if (dtd->last == NULL) { 02130 dtd->children = dtd->last = (xmlNodePtr) ret; 02131 } else { 02132 dtd->last->next = (xmlNodePtr) ret; 02133 ret->prev = dtd->last; 02134 dtd->last = (xmlNodePtr) ret; 02135 } 02136 return(ret); 02137 } 02138 02145 void 02146 xmlFreeAttributeTable(xmlAttributeTablePtr table) { 02147 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute); 02148 } 02149 02150 #ifdef LIBXML_TREE_ENABLED 02151 02159 static xmlAttributePtr 02160 xmlCopyAttribute(xmlAttributePtr attr) { 02161 xmlAttributePtr cur; 02162 02163 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); 02164 if (cur == NULL) { 02165 xmlVErrMemory(NULL, "malloc failed"); 02166 return(NULL); 02167 } 02168 memset(cur, 0, sizeof(xmlAttribute)); 02169 cur->type = XML_ATTRIBUTE_DECL; 02170 cur->atype = attr->atype; 02171 cur->def = attr->def; 02172 cur->tree = xmlCopyEnumeration(attr->tree); 02173 if (attr->elem != NULL) 02174 cur->elem = xmlStrdup(attr->elem); 02175 if (attr->name != NULL) 02176 cur->name = xmlStrdup(attr->name); 02177 if (attr->prefix != NULL) 02178 cur->prefix = xmlStrdup(attr->prefix); 02179 if (attr->defaultValue != NULL) 02180 cur->defaultValue = xmlStrdup(attr->defaultValue); 02181 return(cur); 02182 } 02183 02192 xmlAttributeTablePtr 02193 xmlCopyAttributeTable(xmlAttributeTablePtr table) { 02194 return((xmlAttributeTablePtr) xmlHashCopy(table, 02195 (xmlHashCopier) xmlCopyAttribute)); 02196 } 02197 #endif /* LIBXML_TREE_ENABLED */ 02198 02199 #ifdef LIBXML_OUTPUT_ENABLED 02200 02208 void 02209 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { 02210 if ((buf == NULL) || (attr == NULL)) 02211 return; 02212 xmlBufferWriteChar(buf, "<!ATTLIST "); 02213 xmlBufferWriteCHAR(buf, attr->elem); 02214 xmlBufferWriteChar(buf, " "); 02215 if (attr->prefix != NULL) { 02216 xmlBufferWriteCHAR(buf, attr->prefix); 02217 xmlBufferWriteChar(buf, ":"); 02218 } 02219 xmlBufferWriteCHAR(buf, attr->name); 02220 switch (attr->atype) { 02221 case XML_ATTRIBUTE_CDATA: 02222 xmlBufferWriteChar(buf, " CDATA"); 02223 break; 02224 case XML_ATTRIBUTE_ID: 02225 xmlBufferWriteChar(buf, " ID"); 02226 break; 02227 case XML_ATTRIBUTE_IDREF: 02228 xmlBufferWriteChar(buf, " IDREF"); 02229 break; 02230 case XML_ATTRIBUTE_IDREFS: 02231 xmlBufferWriteChar(buf, " IDREFS"); 02232 break; 02233 case XML_ATTRIBUTE_ENTITY: 02234 xmlBufferWriteChar(buf, " ENTITY"); 02235 break; 02236 case XML_ATTRIBUTE_ENTITIES: 02237 xmlBufferWriteChar(buf, " ENTITIES"); 02238 break; 02239 case XML_ATTRIBUTE_NMTOKEN: 02240 xmlBufferWriteChar(buf, " NMTOKEN"); 02241 break; 02242 case XML_ATTRIBUTE_NMTOKENS: 02243 xmlBufferWriteChar(buf, " NMTOKENS"); 02244 break; 02245 case XML_ATTRIBUTE_ENUMERATION: 02246 xmlBufferWriteChar(buf, " ("); 02247 xmlDumpEnumeration(buf, attr->tree); 02248 break; 02249 case XML_ATTRIBUTE_NOTATION: 02250 xmlBufferWriteChar(buf, " NOTATION ("); 02251 xmlDumpEnumeration(buf, attr->tree); 02252 break; 02253 default: 02254 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 02255 "Internal: ATTRIBUTE struct corrupted invalid type\n", 02256 NULL); 02257 } 02258 switch (attr->def) { 02259 case XML_ATTRIBUTE_NONE: 02260 break; 02261 case XML_ATTRIBUTE_REQUIRED: 02262 xmlBufferWriteChar(buf, " #REQUIRED"); 02263 break; 02264 case XML_ATTRIBUTE_IMPLIED: 02265 xmlBufferWriteChar(buf, " #IMPLIED"); 02266 break; 02267 case XML_ATTRIBUTE_FIXED: 02268 xmlBufferWriteChar(buf, " #FIXED"); 02269 break; 02270 default: 02271 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 02272 "Internal: ATTRIBUTE struct corrupted invalid def\n", 02273 NULL); 02274 } 02275 if (attr->defaultValue != NULL) { 02276 xmlBufferWriteChar(buf, " "); 02277 xmlBufferWriteQuotedString(buf, attr->defaultValue); 02278 } 02279 xmlBufferWriteChar(buf, ">\n"); 02280 } 02281 02289 static void 02290 xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) { 02291 xmlDumpAttributeDecl(buf, attr); 02292 } 02293 02301 void 02302 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { 02303 if ((buf == NULL) || (table == NULL)) 02304 return; 02305 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf); 02306 } 02307 #endif /* LIBXML_OUTPUT_ENABLED */ 02308 02309 /************************************************************************ 02310 * * 02311 * NOTATIONs * 02312 * * 02313 ************************************************************************/ 02320 static void 02321 xmlFreeNotation(xmlNotationPtr nota) { 02322 if (nota == NULL) return; 02323 if (nota->name != NULL) 02324 xmlFree((xmlChar *) nota->name); 02325 if (nota->PublicID != NULL) 02326 xmlFree((xmlChar *) nota->PublicID); 02327 if (nota->SystemID != NULL) 02328 xmlFree((xmlChar *) nota->SystemID); 02329 xmlFree(nota); 02330 } 02331 02332 02345 xmlNotationPtr 02346 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, 02347 const xmlChar *name, 02348 const xmlChar *PublicID, const xmlChar *SystemID) { 02349 xmlNotationPtr ret; 02350 xmlNotationTablePtr table; 02351 02352 if (dtd == NULL) { 02353 return(NULL); 02354 } 02355 if (name == NULL) { 02356 return(NULL); 02357 } 02358 if ((PublicID == NULL) && (SystemID == NULL)) { 02359 return(NULL); 02360 } 02361 02362 /* 02363 * Create the Notation table if needed. 02364 */ 02365 table = (xmlNotationTablePtr) dtd->notations; 02366 if (table == NULL) { 02367 xmlDictPtr dict = NULL; 02368 if (dtd->doc != NULL) 02369 dict = dtd->doc->dict; 02370 02371 dtd->notations = table = xmlHashCreateDict(0, dict); 02372 } 02373 if (table == NULL) { 02374 xmlVErrMemory(ctxt, 02375 "xmlAddNotationDecl: Table creation failed!\n"); 02376 return(NULL); 02377 } 02378 02379 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); 02380 if (ret == NULL) { 02381 xmlVErrMemory(ctxt, "malloc failed"); 02382 return(NULL); 02383 } 02384 memset(ret, 0, sizeof(xmlNotation)); 02385 02386 /* 02387 * fill the structure. 02388 */ 02389 ret->name = xmlStrdup(name); 02390 if (SystemID != NULL) 02391 ret->SystemID = xmlStrdup(SystemID); 02392 if (PublicID != NULL) 02393 ret->PublicID = xmlStrdup(PublicID); 02394 02395 /* 02396 * Validity Check: 02397 * Check the DTD for previous declarations of the ATTLIST 02398 */ 02399 if (xmlHashAddEntry(table, name, ret)) { 02400 #ifdef LIBXML_VALID_ENABLED 02401 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, 02402 "xmlAddNotationDecl: %s already defined\n", 02403 (const char *) name); 02404 #endif /* LIBXML_VALID_ENABLED */ 02405 xmlFreeNotation(ret); 02406 return(NULL); 02407 } 02408 return(ret); 02409 } 02410 02417 void 02418 xmlFreeNotationTable(xmlNotationTablePtr table) { 02419 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation); 02420 } 02421 02422 #ifdef LIBXML_TREE_ENABLED 02423 02431 static xmlNotationPtr 02432 xmlCopyNotation(xmlNotationPtr nota) { 02433 xmlNotationPtr cur; 02434 02435 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); 02436 if (cur == NULL) { 02437 xmlVErrMemory(NULL, "malloc failed"); 02438 return(NULL); 02439 } 02440 if (nota->name != NULL) 02441 cur->name = xmlStrdup(nota->name); 02442 else 02443 cur->name = NULL; 02444 if (nota->PublicID != NULL) 02445 cur->PublicID = xmlStrdup(nota->PublicID); 02446 else 02447 cur->PublicID = NULL; 02448 if (nota->SystemID != NULL) 02449 cur->SystemID = xmlStrdup(nota->SystemID); 02450 else 02451 cur->SystemID = NULL; 02452 return(cur); 02453 } 02454 02463 xmlNotationTablePtr 02464 xmlCopyNotationTable(xmlNotationTablePtr table) { 02465 return((xmlNotationTablePtr) xmlHashCopy(table, 02466 (xmlHashCopier) xmlCopyNotation)); 02467 } 02468 #endif /* LIBXML_TREE_ENABLED */ 02469 02470 #ifdef LIBXML_OUTPUT_ENABLED 02471 02478 void 02479 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { 02480 if ((buf == NULL) || (nota == NULL)) 02481 return; 02482 xmlBufferWriteChar(buf, "<!NOTATION "); 02483 xmlBufferWriteCHAR(buf, nota->name); 02484 if (nota->PublicID != NULL) { 02485 xmlBufferWriteChar(buf, " PUBLIC "); 02486 xmlBufferWriteQuotedString(buf, nota->PublicID); 02487 if (nota->SystemID != NULL) { 02488 xmlBufferWriteChar(buf, " "); 02489 xmlBufferWriteQuotedString(buf, nota->SystemID); 02490 } 02491 } else { 02492 xmlBufferWriteChar(buf, " SYSTEM "); 02493 xmlBufferWriteQuotedString(buf, nota->SystemID); 02494 } 02495 xmlBufferWriteChar(buf, " >\n"); 02496 } 02497 02505 static void 02506 xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) { 02507 xmlDumpNotationDecl(buf, nota); 02508 } 02509 02517 void 02518 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { 02519 if ((buf == NULL) || (table == NULL)) 02520 return; 02521 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf); 02522 } 02523 #endif /* LIBXML_OUTPUT_ENABLED */ 02524 02525 /************************************************************************ 02526 * * 02527 * IDs * 02528 * * 02529 ************************************************************************/ 02537 #define DICT_FREE(str) \ 02538 if ((str) && ((!dict) || \ 02539 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ 02540 xmlFree((char *)(str)); 02541 02548 static void 02549 xmlFreeID(xmlIDPtr id) { 02550 xmlDictPtr dict = NULL; 02551 02552 if (id == NULL) return; 02553 02554 if (id->doc != NULL) 02555 dict = id->doc->dict; 02556 02557 if (id->value != NULL) 02558 DICT_FREE(id->value) 02559 if (id->name != NULL) 02560 DICT_FREE(id->name) 02561 xmlFree(id); 02562 } 02563 02564 02576 xmlIDPtr 02577 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, 02578 xmlAttrPtr attr) { 02579 xmlIDPtr ret; 02580 xmlIDTablePtr table; 02581 02582 if (doc == NULL) { 02583 return(NULL); 02584 } 02585 if (value == NULL) { 02586 return(NULL); 02587 } 02588 if (attr == NULL) { 02589 return(NULL); 02590 } 02591 02592 /* 02593 * Create the ID table if needed. 02594 */ 02595 table = (xmlIDTablePtr) doc->ids; 02596 if (table == NULL) { 02597 doc->ids = table = xmlHashCreateDict(0, doc->dict); 02598 } 02599 if (table == NULL) { 02600 xmlVErrMemory(ctxt, 02601 "xmlAddID: Table creation failed!\n"); 02602 return(NULL); 02603 } 02604 02605 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); 02606 if (ret == NULL) { 02607 xmlVErrMemory(ctxt, "malloc failed"); 02608 return(NULL); 02609 } 02610 02611 /* 02612 * fill the structure. 02613 */ 02614 ret->value = xmlStrdup(value); 02615 ret->doc = doc; 02616 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) { 02617 /* 02618 * Operating in streaming mode, attr is gonna disapear 02619 */ 02620 if (doc->dict != NULL) 02621 ret->name = xmlDictLookup(doc->dict, attr->name, -1); 02622 else 02623 ret->name = xmlStrdup(attr->name); 02624 ret->attr = NULL; 02625 } else { 02626 ret->attr = attr; 02627 ret->name = NULL; 02628 } 02629 ret->lineno = xmlGetLineNo(attr->parent); 02630 02631 if (xmlHashAddEntry(table, value, ret) < 0) { 02632 #ifdef LIBXML_VALID_ENABLED 02633 /* 02634 * The id is already defined in this DTD. 02635 */ 02636 if ((ctxt != NULL) && (ctxt->error != NULL)) { 02637 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, 02638 "ID %s already defined\n", 02639 value, NULL, NULL); 02640 } 02641 #endif /* LIBXML_VALID_ENABLED */ 02642 xmlFreeID(ret); 02643 return(NULL); 02644 } 02645 if (attr != NULL) 02646 attr->atype = XML_ATTRIBUTE_ID; 02647 return(ret); 02648 } 02649 02656 void 02657 xmlFreeIDTable(xmlIDTablePtr table) { 02658 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID); 02659 } 02660 02674 int 02675 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { 02676 if ((attr == NULL) || (attr->name == NULL)) return(0); 02677 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && 02678 (!strcmp((char *) attr->name, "id")) && 02679 (!strcmp((char *) attr->ns->prefix, "xml"))) 02680 return(1); 02681 if (doc == NULL) return(0); 02682 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) && 02683 (doc->type != XML_HTML_DOCUMENT_NODE)) { 02684 return(0); 02685 } else if (doc->type == XML_HTML_DOCUMENT_NODE) { 02686 if ((xmlStrEqual(BAD_CAST "id", attr->name)) || 02687 ((xmlStrEqual(BAD_CAST "name", attr->name)) && 02688 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a"))))) 02689 return(1); 02690 return(0); 02691 } else if (elem == NULL) { 02692 return(0); 02693 } else { 02694 xmlAttributePtr attrDecl = NULL; 02695 02696 xmlChar felem[50], fattr[50]; 02697 xmlChar *fullelemname, *fullattrname; 02698 02699 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? 02700 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : 02701 (xmlChar *)elem->name; 02702 02703 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? 02704 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : 02705 (xmlChar *)attr->name; 02706 02707 if (fullelemname != NULL && fullattrname != NULL) { 02708 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, 02709 fullattrname); 02710 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 02711 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, 02712 fullattrname); 02713 } 02714 02715 if ((fullattrname != fattr) && (fullattrname != attr->name)) 02716 xmlFree(fullattrname); 02717 if ((fullelemname != felem) && (fullelemname != elem->name)) 02718 xmlFree(fullelemname); 02719 02720 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) 02721 return(1); 02722 } 02723 return(0); 02724 } 02725 02735 int 02736 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { 02737 xmlIDTablePtr table; 02738 xmlIDPtr id; 02739 xmlChar *ID; 02740 02741 if (doc == NULL) return(-1); 02742 if (attr == NULL) return(-1); 02743 table = (xmlIDTablePtr) doc->ids; 02744 if (table == NULL) 02745 return(-1); 02746 02747 if (attr == NULL) 02748 return(-1); 02749 ID = xmlNodeListGetString(doc, attr->children, 1); 02750 if (ID == NULL) 02751 return(-1); 02752 id = xmlHashLookup(table, ID); 02753 if (id == NULL || id->attr != attr) { 02754 xmlFree(ID); 02755 return(-1); 02756 } 02757 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID); 02758 xmlFree(ID); 02759 attr->atype = 0; 02760 return(0); 02761 } 02762 02772 xmlAttrPtr 02773 xmlGetID(xmlDocPtr doc, const xmlChar *ID) { 02774 xmlIDTablePtr table; 02775 xmlIDPtr id; 02776 02777 if (doc == NULL) { 02778 return(NULL); 02779 } 02780 02781 if (ID == NULL) { 02782 return(NULL); 02783 } 02784 02785 table = (xmlIDTablePtr) doc->ids; 02786 if (table == NULL) 02787 return(NULL); 02788 02789 id = xmlHashLookup(table, ID); 02790 if (id == NULL) 02791 return(NULL); 02792 if (id->attr == NULL) { 02793 /* 02794 * We are operating on a stream, return a well known reference 02795 * since the attribute node doesn't exist anymore 02796 */ 02797 return((xmlAttrPtr) doc); 02798 } 02799 return(id->attr); 02800 } 02801 02802 /************************************************************************ 02803 * * 02804 * Refs * 02805 * * 02806 ************************************************************************/ 02807 typedef struct xmlRemoveMemo_t 02808 { 02809 xmlListPtr l; 02810 xmlAttrPtr ap; 02811 } xmlRemoveMemo; 02812 02813 typedef xmlRemoveMemo *xmlRemoveMemoPtr; 02814 02815 typedef struct xmlValidateMemo_t 02816 { 02817 xmlValidCtxtPtr ctxt; 02818 const xmlChar *name; 02819 } xmlValidateMemo; 02820 02821 typedef xmlValidateMemo *xmlValidateMemoPtr; 02822 02829 static void 02830 xmlFreeRef(xmlLinkPtr lk) { 02831 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk); 02832 if (ref == NULL) return; 02833 if (ref->value != NULL) 02834 xmlFree((xmlChar *)ref->value); 02835 if (ref->name != NULL) 02836 xmlFree((xmlChar *)ref->name); 02837 xmlFree(ref); 02838 } 02839 02846 static void 02847 xmlFreeRefList(xmlListPtr list_ref) { 02848 if (list_ref == NULL) return; 02849 xmlListDelete(list_ref); 02850 } 02851 02859 static int 02860 xmlWalkRemoveRef(const void *data, const void *user) 02861 { 02862 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr; 02863 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap; 02864 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l; 02865 02866 if (attr0 == attr1) { /* Matched: remove and terminate walk */ 02867 xmlListRemoveFirst(ref_list, (void *)data); 02868 return 0; 02869 } 02870 return 1; 02871 } 02872 02880 static int 02881 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, 02882 const void *data1 ATTRIBUTE_UNUSED) 02883 { 02884 return (0); 02885 } 02886 02898 xmlRefPtr 02899 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, 02900 xmlAttrPtr attr) { 02901 xmlRefPtr ret; 02902 xmlRefTablePtr table; 02903 xmlListPtr ref_list; 02904 02905 if (doc == NULL) { 02906 return(NULL); 02907 } 02908 if (value == NULL) { 02909 return(NULL); 02910 } 02911 if (attr == NULL) { 02912 return(NULL); 02913 } 02914 02915 /* 02916 * Create the Ref table if needed. 02917 */ 02918 table = (xmlRefTablePtr) doc->refs; 02919 if (table == NULL) { 02920 doc->refs = table = xmlHashCreateDict(0, doc->dict); 02921 } 02922 if (table == NULL) { 02923 xmlVErrMemory(ctxt, 02924 "xmlAddRef: Table creation failed!\n"); 02925 return(NULL); 02926 } 02927 02928 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); 02929 if (ret == NULL) { 02930 xmlVErrMemory(ctxt, "malloc failed"); 02931 return(NULL); 02932 } 02933 02934 /* 02935 * fill the structure. 02936 */ 02937 ret->value = xmlStrdup(value); 02938 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) { 02939 /* 02940 * Operating in streaming mode, attr is gonna disapear 02941 */ 02942 ret->name = xmlStrdup(attr->name); 02943 ret->attr = NULL; 02944 } else { 02945 ret->name = NULL; 02946 ret->attr = attr; 02947 } 02948 ret->lineno = xmlGetLineNo(attr->parent); 02949 02950 /* To add a reference :- 02951 * References are maintained as a list of references, 02952 * Lookup the entry, if no entry create new nodelist 02953 * Add the owning node to the NodeList 02954 * Return the ref 02955 */ 02956 02957 if (NULL == (ref_list = xmlHashLookup(table, value))) { 02958 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) { 02959 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 02960 "xmlAddRef: Reference list creation failed!\n", 02961 NULL); 02962 goto failed; 02963 } 02964 if (xmlHashAddEntry(table, value, ref_list) < 0) { 02965 xmlListDelete(ref_list); 02966 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 02967 "xmlAddRef: Reference list insertion failed!\n", 02968 NULL); 02969 goto failed; 02970 } 02971 } 02972 if (xmlListAppend(ref_list, ret) != 0) { 02973 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 02974 "xmlAddRef: Reference list insertion failed!\n", 02975 NULL); 02976 goto failed; 02977 } 02978 return(ret); 02979 failed: 02980 if (ret != NULL) { 02981 if (ret->value != NULL) 02982 xmlFree((char *)ret->value); 02983 if (ret->name != NULL) 02984 xmlFree((char *)ret->name); 02985 xmlFree(ret); 02986 } 02987 return(NULL); 02988 } 02989 02996 void 02997 xmlFreeRefTable(xmlRefTablePtr table) { 02998 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList); 02999 } 03000 03013 int 03014 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { 03015 if (attr == NULL) 03016 return(0); 03017 if (doc == NULL) { 03018 doc = attr->doc; 03019 if (doc == NULL) return(0); 03020 } 03021 03022 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { 03023 return(0); 03024 } else if (doc->type == XML_HTML_DOCUMENT_NODE) { 03025 /* TODO @@@ */ 03026 return(0); 03027 } else { 03028 xmlAttributePtr attrDecl; 03029 03030 if (elem == NULL) return(0); 03031 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); 03032 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 03033 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 03034 elem->name, attr->name); 03035 03036 if ((attrDecl != NULL) && 03037 (attrDecl->atype == XML_ATTRIBUTE_IDREF || 03038 attrDecl->atype == XML_ATTRIBUTE_IDREFS)) 03039 return(1); 03040 } 03041 return(0); 03042 } 03043 03053 int 03054 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) { 03055 xmlListPtr ref_list; 03056 xmlRefTablePtr table; 03057 xmlChar *ID; 03058 xmlRemoveMemo target; 03059 03060 if (doc == NULL) return(-1); 03061 if (attr == NULL) return(-1); 03062 table = (xmlRefTablePtr) doc->refs; 03063 if (table == NULL) 03064 return(-1); 03065 03066 if (attr == NULL) 03067 return(-1); 03068 ID = xmlNodeListGetString(doc, attr->children, 1); 03069 if (ID == NULL) 03070 return(-1); 03071 ref_list = xmlHashLookup(table, ID); 03072 03073 if(ref_list == NULL) { 03074 xmlFree(ID); 03075 return (-1); 03076 } 03077 /* At this point, ref_list refers to a list of references which 03078 * have the same key as the supplied attr. Our list of references 03079 * is ordered by reference address and we don't have that information 03080 * here to use when removing. We'll have to walk the list and 03081 * check for a matching attribute, when we find one stop the walk 03082 * and remove the entry. 03083 * The list is ordered by reference, so that means we don't have the 03084 * key. Passing the list and the reference to the walker means we 03085 * will have enough data to be able to remove the entry. 03086 */ 03087 target.l = ref_list; 03088 target.ap = attr; 03089 03090 /* Remove the supplied attr from our list */ 03091 xmlListWalk(ref_list, xmlWalkRemoveRef, &target); 03092 03093 /*If the list is empty then remove the list entry in the hash */ 03094 if (xmlListEmpty(ref_list)) 03095 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) 03096 xmlFreeRefList); 03097 xmlFree(ID); 03098 return(0); 03099 } 03100 03110 xmlListPtr 03111 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { 03112 xmlRefTablePtr table; 03113 03114 if (doc == NULL) { 03115 return(NULL); 03116 } 03117 03118 if (ID == NULL) { 03119 return(NULL); 03120 } 03121 03122 table = (xmlRefTablePtr) doc->refs; 03123 if (table == NULL) 03124 return(NULL); 03125 03126 return (xmlHashLookup(table, ID)); 03127 } 03128 03129 /************************************************************************ 03130 * * 03131 * Routines for validity checking * 03132 * * 03133 ************************************************************************/ 03134 03145 xmlElementPtr 03146 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { 03147 xmlElementTablePtr table; 03148 xmlElementPtr cur; 03149 xmlChar *uqname = NULL, *prefix = NULL; 03150 03151 if ((dtd == NULL) || (name == NULL)) return(NULL); 03152 if (dtd->elements == NULL) 03153 return(NULL); 03154 table = (xmlElementTablePtr) dtd->elements; 03155 03156 uqname = xmlSplitQName2(name, &prefix); 03157 if (uqname != NULL) 03158 name = uqname; 03159 cur = xmlHashLookup2(table, name, prefix); 03160 if (prefix != NULL) xmlFree(prefix); 03161 if (uqname != NULL) xmlFree(uqname); 03162 return(cur); 03163 } 03175 static xmlElementPtr 03176 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) { 03177 xmlElementTablePtr table; 03178 xmlElementPtr cur; 03179 xmlChar *uqname = NULL, *prefix = NULL; 03180 03181 if (dtd == NULL) return(NULL); 03182 if (dtd->elements == NULL) { 03183 xmlDictPtr dict = NULL; 03184 03185 if (dtd->doc != NULL) 03186 dict = dtd->doc->dict; 03187 03188 if (!create) 03189 return(NULL); 03190 /* 03191 * Create the Element table if needed. 03192 */ 03193 table = (xmlElementTablePtr) dtd->elements; 03194 if (table == NULL) { 03195 table = xmlHashCreateDict(0, dict); 03196 dtd->elements = (void *) table; 03197 } 03198 if (table == NULL) { 03199 xmlVErrMemory(NULL, "element table allocation failed"); 03200 return(NULL); 03201 } 03202 } 03203 table = (xmlElementTablePtr) dtd->elements; 03204 03205 uqname = xmlSplitQName2(name, &prefix); 03206 if (uqname != NULL) 03207 name = uqname; 03208 cur = xmlHashLookup2(table, name, prefix); 03209 if ((cur == NULL) && (create)) { 03210 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); 03211 if (cur == NULL) { 03212 xmlVErrMemory(NULL, "malloc failed"); 03213 return(NULL); 03214 } 03215 memset(cur, 0, sizeof(xmlElement)); 03216 cur->type = XML_ELEMENT_DECL; 03217 03218 /* 03219 * fill the structure. 03220 */ 03221 cur->name = xmlStrdup(name); 03222 cur->prefix = xmlStrdup(prefix); 03223 cur->etype = XML_ELEMENT_TYPE_UNDEFINED; 03224 03225 xmlHashAddEntry2(table, name, prefix, cur); 03226 } 03227 if (prefix != NULL) xmlFree(prefix); 03228 if (uqname != NULL) xmlFree(uqname); 03229 return(cur); 03230 } 03231 03243 xmlElementPtr 03244 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name, 03245 const xmlChar *prefix) { 03246 xmlElementTablePtr table; 03247 03248 if (dtd == NULL) return(NULL); 03249 if (dtd->elements == NULL) return(NULL); 03250 table = (xmlElementTablePtr) dtd->elements; 03251 03252 return(xmlHashLookup2(table, name, prefix)); 03253 } 03254 03267 xmlAttributePtr 03268 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { 03269 xmlAttributeTablePtr table; 03270 xmlAttributePtr cur; 03271 xmlChar *uqname = NULL, *prefix = NULL; 03272 03273 if (dtd == NULL) return(NULL); 03274 if (dtd->attributes == NULL) return(NULL); 03275 03276 table = (xmlAttributeTablePtr) dtd->attributes; 03277 if (table == NULL) 03278 return(NULL); 03279 03280 uqname = xmlSplitQName2(name, &prefix); 03281 03282 if (uqname != NULL) { 03283 cur = xmlHashLookup3(table, uqname, prefix, elem); 03284 if (prefix != NULL) xmlFree(prefix); 03285 if (uqname != NULL) xmlFree(uqname); 03286 } else 03287 cur = xmlHashLookup3(table, name, NULL, elem); 03288 return(cur); 03289 } 03290 03304 xmlAttributePtr 03305 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, 03306 const xmlChar *prefix) { 03307 xmlAttributeTablePtr table; 03308 03309 if (dtd == NULL) return(NULL); 03310 if (dtd->attributes == NULL) return(NULL); 03311 table = (xmlAttributeTablePtr) dtd->attributes; 03312 03313 return(xmlHashLookup3(table, name, prefix, elem)); 03314 } 03315 03326 xmlNotationPtr 03327 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { 03328 xmlNotationTablePtr table; 03329 03330 if (dtd == NULL) return(NULL); 03331 if (dtd->notations == NULL) return(NULL); 03332 table = (xmlNotationTablePtr) dtd->notations; 03333 03334 return(xmlHashLookup(table, name)); 03335 } 03336 03337 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 03338 03350 int 03351 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 03352 const xmlChar *notationName) { 03353 xmlNotationPtr notaDecl; 03354 if ((doc == NULL) || (doc->intSubset == NULL) || 03355 (notationName == NULL)) return(-1); 03356 03357 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName); 03358 if ((notaDecl == NULL) && (doc->extSubset != NULL)) 03359 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName); 03360 03361 if ((notaDecl == NULL) && (ctxt != NULL)) { 03362 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION, 03363 "NOTATION %s is not declared\n", 03364 notationName, NULL, NULL); 03365 return(0); 03366 } 03367 return(1); 03368 } 03369 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ 03370 03382 int 03383 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { 03384 xmlElementPtr elemDecl; 03385 03386 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1); 03387 03388 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name); 03389 if ((elemDecl == NULL) && (doc->extSubset != NULL)) 03390 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name); 03391 if (elemDecl == NULL) return(-1); 03392 switch (elemDecl->etype) { 03393 case XML_ELEMENT_TYPE_UNDEFINED: 03394 return(-1); 03395 case XML_ELEMENT_TYPE_ELEMENT: 03396 return(0); 03397 case XML_ELEMENT_TYPE_EMPTY: 03398 /* 03399 * return 1 for EMPTY since we want VC error to pop up 03400 * on <empty> </empty> for example 03401 */ 03402 case XML_ELEMENT_TYPE_ANY: 03403 case XML_ELEMENT_TYPE_MIXED: 03404 return(1); 03405 } 03406 return(1); 03407 } 03408 03409 #ifdef LIBXML_VALID_ENABLED 03410 03411 static int 03412 xmlIsDocNameStartChar(xmlDocPtr doc, int c) { 03413 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { 03414 /* 03415 * Use the new checks of production [4] [4a] amd [5] of the 03416 * Update 5 of XML-1.0 03417 */ 03418 if (((c >= 'a') && (c <= 'z')) || 03419 ((c >= 'A') && (c <= 'Z')) || 03420 (c == '_') || (c == ':') || 03421 ((c >= 0xC0) && (c <= 0xD6)) || 03422 ((c >= 0xD8) && (c <= 0xF6)) || 03423 ((c >= 0xF8) && (c <= 0x2FF)) || 03424 ((c >= 0x370) && (c <= 0x37D)) || 03425 ((c >= 0x37F) && (c <= 0x1FFF)) || 03426 ((c >= 0x200C) && (c <= 0x200D)) || 03427 ((c >= 0x2070) && (c <= 0x218F)) || 03428 ((c >= 0x2C00) && (c <= 0x2FEF)) || 03429 ((c >= 0x3001) && (c <= 0xD7FF)) || 03430 ((c >= 0xF900) && (c <= 0xFDCF)) || 03431 ((c >= 0xFDF0) && (c <= 0xFFFD)) || 03432 ((c >= 0x10000) && (c <= 0xEFFFF))) 03433 return(1); 03434 } else { 03435 if (IS_LETTER(c) || (c == '_') || (c == ':')) 03436 return(1); 03437 } 03438 return(0); 03439 } 03440 03441 static int 03442 xmlIsDocNameChar(xmlDocPtr doc, int c) { 03443 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { 03444 /* 03445 * Use the new checks of production [4] [4a] amd [5] of the 03446 * Update 5 of XML-1.0 03447 */ 03448 if (((c >= 'a') && (c <= 'z')) || 03449 ((c >= 'A') && (c <= 'Z')) || 03450 ((c >= '0') && (c <= '9')) || /* !start */ 03451 (c == '_') || (c == ':') || 03452 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ 03453 ((c >= 0xC0) && (c <= 0xD6)) || 03454 ((c >= 0xD8) && (c <= 0xF6)) || 03455 ((c >= 0xF8) && (c <= 0x2FF)) || 03456 ((c >= 0x300) && (c <= 0x36F)) || /* !start */ 03457 ((c >= 0x370) && (c <= 0x37D)) || 03458 ((c >= 0x37F) && (c <= 0x1FFF)) || 03459 ((c >= 0x200C) && (c <= 0x200D)) || 03460 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ 03461 ((c >= 0x2070) && (c <= 0x218F)) || 03462 ((c >= 0x2C00) && (c <= 0x2FEF)) || 03463 ((c >= 0x3001) && (c <= 0xD7FF)) || 03464 ((c >= 0xF900) && (c <= 0xFDCF)) || 03465 ((c >= 0xFDF0) && (c <= 0xFFFD)) || 03466 ((c >= 0x10000) && (c <= 0xEFFFF))) 03467 return(1); 03468 } else { 03469 if ((IS_LETTER(c)) || (IS_DIGIT(c)) || 03470 (c == '.') || (c == '-') || 03471 (c == '_') || (c == ':') || 03472 (IS_COMBINING(c)) || 03473 (IS_EXTENDER(c))) 03474 return(1); 03475 } 03476 return(0); 03477 } 03478 03489 static int 03490 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) { 03491 const xmlChar *cur; 03492 int val, len; 03493 03494 if (value == NULL) return(0); 03495 cur = value; 03496 val = xmlStringCurrentChar(NULL, cur, &len); 03497 cur += len; 03498 if (!xmlIsDocNameStartChar(doc, val)) 03499 return(0); 03500 03501 val = xmlStringCurrentChar(NULL, cur, &len); 03502 cur += len; 03503 while (xmlIsDocNameChar(doc, val)) { 03504 val = xmlStringCurrentChar(NULL, cur, &len); 03505 cur += len; 03506 } 03507 03508 if (val != 0) return(0); 03509 03510 return(1); 03511 } 03512 03522 int 03523 xmlValidateNameValue(const xmlChar *value) { 03524 return(xmlValidateNameValueInternal(NULL, value)); 03525 } 03526 03537 static int 03538 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) { 03539 const xmlChar *cur; 03540 int val, len; 03541 03542 if (value == NULL) return(0); 03543 cur = value; 03544 val = xmlStringCurrentChar(NULL, cur, &len); 03545 cur += len; 03546 03547 if (!xmlIsDocNameStartChar(doc, val)) 03548 return(0); 03549 03550 val = xmlStringCurrentChar(NULL, cur, &len); 03551 cur += len; 03552 while (xmlIsDocNameChar(doc, val)) { 03553 val = xmlStringCurrentChar(NULL, cur, &len); 03554 cur += len; 03555 } 03556 03557 /* Should not test IS_BLANK(val) here -- see erratum E20*/ 03558 while (val == 0x20) { 03559 while (val == 0x20) { 03560 val = xmlStringCurrentChar(NULL, cur, &len); 03561 cur += len; 03562 } 03563 03564 if (!xmlIsDocNameStartChar(doc, val)) 03565 return(0); 03566 03567 val = xmlStringCurrentChar(NULL, cur, &len); 03568 cur += len; 03569 03570 while (xmlIsDocNameChar(doc, val)) { 03571 val = xmlStringCurrentChar(NULL, cur, &len); 03572 cur += len; 03573 } 03574 } 03575 03576 if (val != 0) return(0); 03577 03578 return(1); 03579 } 03580 03590 int 03591 xmlValidateNamesValue(const xmlChar *value) { 03592 return(xmlValidateNamesValueInternal(NULL, value)); 03593 } 03594 03607 static int 03608 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) { 03609 const xmlChar *cur; 03610 int val, len; 03611 03612 if (value == NULL) return(0); 03613 cur = value; 03614 val = xmlStringCurrentChar(NULL, cur, &len); 03615 cur += len; 03616 03617 if (!xmlIsDocNameChar(doc, val)) 03618 return(0); 03619 03620 val = xmlStringCurrentChar(NULL, cur, &len); 03621 cur += len; 03622 while (xmlIsDocNameChar(doc, val)) { 03623 val = xmlStringCurrentChar(NULL, cur, &len); 03624 cur += len; 03625 } 03626 03627 if (val != 0) return(0); 03628 03629 return(1); 03630 } 03631 03643 int 03644 xmlValidateNmtokenValue(const xmlChar *value) { 03645 return(xmlValidateNmtokenValueInternal(NULL, value)); 03646 } 03647 03660 static int 03661 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) { 03662 const xmlChar *cur; 03663 int val, len; 03664 03665 if (value == NULL) return(0); 03666 cur = value; 03667 val = xmlStringCurrentChar(NULL, cur, &len); 03668 cur += len; 03669 03670 while (IS_BLANK(val)) { 03671 val = xmlStringCurrentChar(NULL, cur, &len); 03672 cur += len; 03673 } 03674 03675 if (!xmlIsDocNameChar(doc, val)) 03676 return(0); 03677 03678 while (xmlIsDocNameChar(doc, val)) { 03679 val = xmlStringCurrentChar(NULL, cur, &len); 03680 cur += len; 03681 } 03682 03683 /* Should not test IS_BLANK(val) here -- see erratum E20*/ 03684 while (val == 0x20) { 03685 while (val == 0x20) { 03686 val = xmlStringCurrentChar(NULL, cur, &len); 03687 cur += len; 03688 } 03689 if (val == 0) return(1); 03690 03691 if (!xmlIsDocNameChar(doc, val)) 03692 return(0); 03693 03694 val = xmlStringCurrentChar(NULL, cur, &len); 03695 cur += len; 03696 03697 while (xmlIsDocNameChar(doc, val)) { 03698 val = xmlStringCurrentChar(NULL, cur, &len); 03699 cur += len; 03700 } 03701 } 03702 03703 if (val != 0) return(0); 03704 03705 return(1); 03706 } 03707 03719 int 03720 xmlValidateNmtokensValue(const xmlChar *value) { 03721 return(xmlValidateNmtokensValueInternal(NULL, value)); 03722 } 03723 03739 int 03740 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED, 03741 xmlNotationPtr nota ATTRIBUTE_UNUSED) { 03742 int ret = 1; 03743 03744 return(ret); 03745 } 03746 03758 static int 03759 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, 03760 const xmlChar *value) { 03761 switch (type) { 03762 case XML_ATTRIBUTE_ENTITIES: 03763 case XML_ATTRIBUTE_IDREFS: 03764 return(xmlValidateNamesValueInternal(doc, value)); 03765 case XML_ATTRIBUTE_ENTITY: 03766 case XML_ATTRIBUTE_IDREF: 03767 case XML_ATTRIBUTE_ID: 03768 case XML_ATTRIBUTE_NOTATION: 03769 return(xmlValidateNameValueInternal(doc, value)); 03770 case XML_ATTRIBUTE_NMTOKENS: 03771 case XML_ATTRIBUTE_ENUMERATION: 03772 return(xmlValidateNmtokensValueInternal(doc, value)); 03773 case XML_ATTRIBUTE_NMTOKEN: 03774 return(xmlValidateNmtokenValueInternal(doc, value)); 03775 case XML_ATTRIBUTE_CDATA: 03776 break; 03777 } 03778 return(1); 03779 } 03780 03805 int 03806 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) { 03807 return(xmlValidateAttributeValueInternal(NULL, type, value)); 03808 } 03809 03839 static int 03840 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 03841 const xmlChar *name, xmlAttributeType type, const xmlChar *value) { 03842 int ret = 1; 03843 switch (type) { 03844 case XML_ATTRIBUTE_IDREFS: 03845 case XML_ATTRIBUTE_IDREF: 03846 case XML_ATTRIBUTE_ID: 03847 case XML_ATTRIBUTE_NMTOKENS: 03848 case XML_ATTRIBUTE_ENUMERATION: 03849 case XML_ATTRIBUTE_NMTOKEN: 03850 case XML_ATTRIBUTE_CDATA: 03851 break; 03852 case XML_ATTRIBUTE_ENTITY: { 03853 xmlEntityPtr ent; 03854 03855 ent = xmlGetDocEntity(doc, value); 03856 /* yeah it's a bit messy... */ 03857 if ((ent == NULL) && (doc->standalone == 1)) { 03858 doc->standalone = 0; 03859 ent = xmlGetDocEntity(doc, value); 03860 } 03861 if (ent == NULL) { 03862 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 03863 XML_DTD_UNKNOWN_ENTITY, 03864 "ENTITY attribute %s reference an unknown entity \"%s\"\n", 03865 name, value, NULL); 03866 ret = 0; 03867 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 03868 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 03869 XML_DTD_ENTITY_TYPE, 03870 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n", 03871 name, value, NULL); 03872 ret = 0; 03873 } 03874 break; 03875 } 03876 case XML_ATTRIBUTE_ENTITIES: { 03877 xmlChar *dup, *nam = NULL, *cur, save; 03878 xmlEntityPtr ent; 03879 03880 dup = xmlStrdup(value); 03881 if (dup == NULL) 03882 return(0); 03883 cur = dup; 03884 while (*cur != 0) { 03885 nam = cur; 03886 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 03887 save = *cur; 03888 *cur = 0; 03889 ent = xmlGetDocEntity(doc, nam); 03890 if (ent == NULL) { 03891 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 03892 XML_DTD_UNKNOWN_ENTITY, 03893 "ENTITIES attribute %s reference an unknown entity \"%s\"\n", 03894 name, nam, NULL); 03895 ret = 0; 03896 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 03897 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 03898 XML_DTD_ENTITY_TYPE, 03899 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n", 03900 name, nam, NULL); 03901 ret = 0; 03902 } 03903 if (save == 0) 03904 break; 03905 *cur = save; 03906 while (IS_BLANK_CH(*cur)) cur++; 03907 } 03908 xmlFree(dup); 03909 break; 03910 } 03911 case XML_ATTRIBUTE_NOTATION: { 03912 xmlNotationPtr nota; 03913 03914 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 03915 if ((nota == NULL) && (doc->extSubset != NULL)) 03916 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 03917 03918 if (nota == NULL) { 03919 xmlErrValidNode(ctxt, (xmlNodePtr) doc, 03920 XML_DTD_UNKNOWN_NOTATION, 03921 "NOTATION attribute %s reference an unknown notation \"%s\"\n", 03922 name, value, NULL); 03923 ret = 0; 03924 } 03925 break; 03926 } 03927 } 03928 return(ret); 03929 } 03930 03955 xmlChar * 03956 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 03957 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { 03958 xmlChar *ret, *dst; 03959 const xmlChar *src; 03960 xmlAttributePtr attrDecl = NULL; 03961 int extsubset = 0; 03962 03963 if (doc == NULL) return(NULL); 03964 if (elem == NULL) return(NULL); 03965 if (name == NULL) return(NULL); 03966 if (value == NULL) return(NULL); 03967 03968 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 03969 xmlChar fn[50]; 03970 xmlChar *fullname; 03971 03972 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 03973 if (fullname == NULL) 03974 return(NULL); 03975 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); 03976 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 03977 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); 03978 if (attrDecl != NULL) 03979 extsubset = 1; 03980 } 03981 if ((fullname != fn) && (fullname != elem->name)) 03982 xmlFree(fullname); 03983 } 03984 if ((attrDecl == NULL) && (doc->intSubset != NULL)) 03985 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); 03986 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 03987 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); 03988 if (attrDecl != NULL) 03989 extsubset = 1; 03990 } 03991 03992 if (attrDecl == NULL) 03993 return(NULL); 03994 if (attrDecl->atype == XML_ATTRIBUTE_CDATA) 03995 return(NULL); 03996 03997 ret = xmlStrdup(value); 03998 if (ret == NULL) 03999 return(NULL); 04000 src = value; 04001 dst = ret; 04002 while (*src == 0x20) src++; 04003 while (*src != 0) { 04004 if (*src == 0x20) { 04005 while (*src == 0x20) src++; 04006 if (*src != 0) 04007 *dst++ = 0x20; 04008 } else { 04009 *dst++ = *src++; 04010 } 04011 } 04012 *dst = 0; 04013 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { 04014 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE, 04015 "standalone: %s on %s value had to be normalized based on external subset declaration\n", 04016 name, elem->name, NULL); 04017 ctxt->valid = 0; 04018 } 04019 return(ret); 04020 } 04021 04041 xmlChar * 04042 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, 04043 const xmlChar *name, const xmlChar *value) { 04044 xmlChar *ret, *dst; 04045 const xmlChar *src; 04046 xmlAttributePtr attrDecl = NULL; 04047 04048 if (doc == NULL) return(NULL); 04049 if (elem == NULL) return(NULL); 04050 if (name == NULL) return(NULL); 04051 if (value == NULL) return(NULL); 04052 04053 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 04054 xmlChar fn[50]; 04055 xmlChar *fullname; 04056 04057 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 04058 if (fullname == NULL) 04059 return(NULL); 04060 if ((fullname != fn) && (fullname != elem->name)) 04061 xmlFree(fullname); 04062 } 04063 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); 04064 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04065 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); 04066 04067 if (attrDecl == NULL) 04068 return(NULL); 04069 if (attrDecl->atype == XML_ATTRIBUTE_CDATA) 04070 return(NULL); 04071 04072 ret = xmlStrdup(value); 04073 if (ret == NULL) 04074 return(NULL); 04075 src = value; 04076 dst = ret; 04077 while (*src == 0x20) src++; 04078 while (*src != 0) { 04079 if (*src == 0x20) { 04080 while (*src == 0x20) src++; 04081 if (*src != 0) 04082 *dst++ = 0x20; 04083 } else { 04084 *dst++ = *src++; 04085 } 04086 } 04087 *dst = 0; 04088 return(ret); 04089 } 04090 04091 static void 04092 xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count, 04093 const xmlChar* name ATTRIBUTE_UNUSED) { 04094 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++; 04095 } 04096 04115 int 04116 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 04117 xmlAttributePtr attr) { 04118 int ret = 1; 04119 int val; 04120 CHECK_DTD; 04121 if(attr == NULL) return(1); 04122 04123 /* Attribute Default Legal */ 04124 /* Enumeration */ 04125 if (attr->defaultValue != NULL) { 04126 val = xmlValidateAttributeValueInternal(doc, attr->atype, 04127 attr->defaultValue); 04128 if (val == 0) { 04129 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT, 04130 "Syntax of default value for attribute %s of %s is not valid\n", 04131 attr->name, attr->elem, NULL); 04132 } 04133 ret &= val; 04134 } 04135 04136 /* ID Attribute Default */ 04137 if ((attr->atype == XML_ATTRIBUTE_ID)&& 04138 (attr->def != XML_ATTRIBUTE_IMPLIED) && 04139 (attr->def != XML_ATTRIBUTE_REQUIRED)) { 04140 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED, 04141 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n", 04142 attr->name, attr->elem, NULL); 04143 ret = 0; 04144 } 04145 04146 /* One ID per Element Type */ 04147 if (attr->atype == XML_ATTRIBUTE_ID) { 04148 int nbId; 04149 04150 /* the trick is that we parse DtD as their own internal subset */ 04151 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, 04152 attr->elem); 04153 if (elem != NULL) { 04154 nbId = xmlScanIDAttributeDecl(NULL, elem, 0); 04155 } else { 04156 xmlAttributeTablePtr table; 04157 04158 /* 04159 * The attribute may be declared in the internal subset and the 04160 * element in the external subset. 04161 */ 04162 nbId = 0; 04163 if (doc->intSubset != NULL) { 04164 table = (xmlAttributeTablePtr) doc->intSubset->attributes; 04165 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner) 04166 xmlValidateAttributeIdCallback, &nbId); 04167 } 04168 } 04169 if (nbId > 1) { 04170 04171 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 04172 "Element %s has %d ID attribute defined in the internal subset : %s\n", 04173 attr->elem, nbId, attr->name); 04174 } else if (doc->extSubset != NULL) { 04175 int extId = 0; 04176 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); 04177 if (elem != NULL) { 04178 extId = xmlScanIDAttributeDecl(NULL, elem, 0); 04179 } 04180 if (extId > 1) { 04181 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 04182 "Element %s has %d ID attribute defined in the external subset : %s\n", 04183 attr->elem, extId, attr->name); 04184 } else if (extId + nbId > 1) { 04185 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, 04186 "Element %s has ID attributes defined in the internal and external subset : %s\n", 04187 attr->elem, attr->name, NULL); 04188 } 04189 } 04190 } 04191 04192 /* Validity Constraint: Enumeration */ 04193 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) { 04194 xmlEnumerationPtr tree = attr->tree; 04195 while (tree != NULL) { 04196 if (xmlStrEqual(tree->name, attr->defaultValue)) break; 04197 tree = tree->next; 04198 } 04199 if (tree == NULL) { 04200 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE, 04201 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n", 04202 attr->defaultValue, attr->name, attr->elem); 04203 ret = 0; 04204 } 04205 } 04206 04207 return(ret); 04208 } 04209 04226 int 04227 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 04228 xmlElementPtr elem) { 04229 int ret = 1; 04230 xmlElementPtr tst; 04231 04232 CHECK_DTD; 04233 04234 if (elem == NULL) return(1); 04235 04236 #if 0 04237 #ifdef LIBXML_REGEXP_ENABLED 04238 /* Build the regexp associated to the content model */ 04239 ret = xmlValidBuildContentModel(ctxt, elem); 04240 #endif 04241 #endif 04242 04243 /* No Duplicate Types */ 04244 if (elem->etype == XML_ELEMENT_TYPE_MIXED) { 04245 xmlElementContentPtr cur, next; 04246 const xmlChar *name; 04247 04248 cur = elem->content; 04249 while (cur != NULL) { 04250 if (cur->type != XML_ELEMENT_CONTENT_OR) break; 04251 if (cur->c1 == NULL) break; 04252 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { 04253 name = cur->c1->name; 04254 next = cur->c2; 04255 while (next != NULL) { 04256 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) { 04257 if ((xmlStrEqual(next->name, name)) && 04258 (xmlStrEqual(next->prefix, cur->c1->prefix))) { 04259 if (cur->c1->prefix == NULL) { 04260 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 04261 "Definition of %s has duplicate references of %s\n", 04262 elem->name, name, NULL); 04263 } else { 04264 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 04265 "Definition of %s has duplicate references of %s:%s\n", 04266 elem->name, cur->c1->prefix, name); 04267 } 04268 ret = 0; 04269 } 04270 break; 04271 } 04272 if (next->c1 == NULL) break; 04273 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break; 04274 if ((xmlStrEqual(next->c1->name, name)) && 04275 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) { 04276 if (cur->c1->prefix == NULL) { 04277 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 04278 "Definition of %s has duplicate references to %s\n", 04279 elem->name, name, NULL); 04280 } else { 04281 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, 04282 "Definition of %s has duplicate references to %s:%s\n", 04283 elem->name, cur->c1->prefix, name); 04284 } 04285 ret = 0; 04286 } 04287 next = next->c2; 04288 } 04289 } 04290 cur = cur->c2; 04291 } 04292 } 04293 04294 /* VC: Unique Element Type Declaration */ 04295 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name); 04296 if ((tst != NULL ) && (tst != elem) && 04297 ((tst->prefix == elem->prefix) || 04298 (xmlStrEqual(tst->prefix, elem->prefix))) && 04299 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { 04300 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, 04301 "Redefinition of element %s\n", 04302 elem->name, NULL, NULL); 04303 ret = 0; 04304 } 04305 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name); 04306 if ((tst != NULL ) && (tst != elem) && 04307 ((tst->prefix == elem->prefix) || 04308 (xmlStrEqual(tst->prefix, elem->prefix))) && 04309 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { 04310 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, 04311 "Redefinition of element %s\n", 04312 elem->name, NULL, NULL); 04313 ret = 0; 04314 } 04315 /* One ID per Element Type 04316 * already done when registering the attribute 04317 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { 04318 ret = 0; 04319 } */ 04320 return(ret); 04321 } 04322 04348 int 04349 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 04350 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) 04351 { 04352 xmlAttributePtr attrDecl = NULL; 04353 int val; 04354 int ret = 1; 04355 04356 CHECK_DTD; 04357 if ((elem == NULL) || (elem->name == NULL)) return(0); 04358 if ((attr == NULL) || (attr->name == NULL)) return(0); 04359 04360 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { 04361 xmlChar fn[50]; 04362 xmlChar *fullname; 04363 04364 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); 04365 if (fullname == NULL) 04366 return(0); 04367 if (attr->ns != NULL) { 04368 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, 04369 attr->name, attr->ns->prefix); 04370 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04371 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, 04372 attr->name, attr->ns->prefix); 04373 } else { 04374 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name); 04375 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04376 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 04377 fullname, attr->name); 04378 } 04379 if ((fullname != fn) && (fullname != elem->name)) 04380 xmlFree(fullname); 04381 } 04382 if (attrDecl == NULL) { 04383 if (attr->ns != NULL) { 04384 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, 04385 attr->name, attr->ns->prefix); 04386 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04387 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, 04388 attr->name, attr->ns->prefix); 04389 } else { 04390 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, 04391 elem->name, attr->name); 04392 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04393 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 04394 elem->name, attr->name); 04395 } 04396 } 04397 04398 04399 /* Validity Constraint: Attribute Value Type */ 04400 if (attrDecl == NULL) { 04401 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 04402 "No declaration for attribute %s of element %s\n", 04403 attr->name, elem->name, NULL); 04404 return(0); 04405 } 04406 attr->atype = attrDecl->atype; 04407 04408 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); 04409 if (val == 0) { 04410 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 04411 "Syntax of value for attribute %s of %s is not valid\n", 04412 attr->name, elem->name, NULL); 04413 ret = 0; 04414 } 04415 04416 /* Validity constraint: Fixed Attribute Default */ 04417 if (attrDecl->def == XML_ATTRIBUTE_FIXED) { 04418 if (!xmlStrEqual(value, attrDecl->defaultValue)) { 04419 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 04420 "Value for attribute %s of %s is different from default \"%s\"\n", 04421 attr->name, elem->name, attrDecl->defaultValue); 04422 ret = 0; 04423 } 04424 } 04425 04426 /* Validity Constraint: ID uniqueness */ 04427 if (attrDecl->atype == XML_ATTRIBUTE_ID) { 04428 if (xmlAddID(ctxt, doc, value, attr) == NULL) 04429 ret = 0; 04430 } 04431 04432 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || 04433 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { 04434 if (xmlAddRef(ctxt, doc, value, attr) == NULL) 04435 ret = 0; 04436 } 04437 04438 /* Validity Constraint: Notation Attributes */ 04439 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { 04440 xmlEnumerationPtr tree = attrDecl->tree; 04441 xmlNotationPtr nota; 04442 04443 /* First check that the given NOTATION was declared */ 04444 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 04445 if (nota == NULL) 04446 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 04447 04448 if (nota == NULL) { 04449 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 04450 "Value \"%s\" for attribute %s of %s is not a declared Notation\n", 04451 value, attr->name, elem->name); 04452 ret = 0; 04453 } 04454 04455 /* Second, verify that it's among the list */ 04456 while (tree != NULL) { 04457 if (xmlStrEqual(tree->name, value)) break; 04458 tree = tree->next; 04459 } 04460 if (tree == NULL) { 04461 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 04462 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n", 04463 value, attr->name, elem->name); 04464 ret = 0; 04465 } 04466 } 04467 04468 /* Validity Constraint: Enumeration */ 04469 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { 04470 xmlEnumerationPtr tree = attrDecl->tree; 04471 while (tree != NULL) { 04472 if (xmlStrEqual(tree->name, value)) break; 04473 tree = tree->next; 04474 } 04475 if (tree == NULL) { 04476 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 04477 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n", 04478 value, attr->name, elem->name); 04479 ret = 0; 04480 } 04481 } 04482 04483 /* Fixed Attribute Default */ 04484 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && 04485 (!xmlStrEqual(attrDecl->defaultValue, value))) { 04486 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 04487 "Value for attribute %s of %s must be \"%s\"\n", 04488 attr->name, elem->name, attrDecl->defaultValue); 04489 ret = 0; 04490 } 04491 04492 /* Extra check for the attribute value */ 04493 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name, 04494 attrDecl->atype, value); 04495 04496 return(ret); 04497 } 04498 04525 int 04526 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 04527 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { 04528 /* xmlElementPtr elemDecl; */ 04529 xmlAttributePtr attrDecl = NULL; 04530 int val; 04531 int ret = 1; 04532 04533 CHECK_DTD; 04534 if ((elem == NULL) || (elem->name == NULL)) return(0); 04535 if ((ns == NULL) || (ns->href == NULL)) return(0); 04536 04537 if (prefix != NULL) { 04538 xmlChar fn[50]; 04539 xmlChar *fullname; 04540 04541 fullname = xmlBuildQName(elem->name, prefix, fn, 50); 04542 if (fullname == NULL) { 04543 xmlVErrMemory(ctxt, "Validating namespace"); 04544 return(0); 04545 } 04546 if (ns->prefix != NULL) { 04547 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, 04548 ns->prefix, BAD_CAST "xmlns"); 04549 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04550 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, 04551 ns->prefix, BAD_CAST "xmlns"); 04552 } else { 04553 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, 04554 BAD_CAST "xmlns"); 04555 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04556 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, 04557 BAD_CAST "xmlns"); 04558 } 04559 if ((fullname != fn) && (fullname != elem->name)) 04560 xmlFree(fullname); 04561 } 04562 if (attrDecl == NULL) { 04563 if (ns->prefix != NULL) { 04564 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, 04565 ns->prefix, BAD_CAST "xmlns"); 04566 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04567 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, 04568 ns->prefix, BAD_CAST "xmlns"); 04569 } else { 04570 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, 04571 elem->name, BAD_CAST "xmlns"); 04572 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 04573 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, 04574 elem->name, BAD_CAST "xmlns"); 04575 } 04576 } 04577 04578 04579 /* Validity Constraint: Attribute Value Type */ 04580 if (attrDecl == NULL) { 04581 if (ns->prefix != NULL) { 04582 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 04583 "No declaration for attribute xmlns:%s of element %s\n", 04584 ns->prefix, elem->name, NULL); 04585 } else { 04586 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, 04587 "No declaration for attribute xmlns of element %s\n", 04588 elem->name, NULL, NULL); 04589 } 04590 return(0); 04591 } 04592 04593 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); 04594 if (val == 0) { 04595 if (ns->prefix != NULL) { 04596 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, 04597 "Syntax of value for attribute xmlns:%s of %s is not valid\n", 04598 ns->prefix, elem->name, NULL); 04599 } else { 04600 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, 04601 "Syntax of value for attribute xmlns of %s is not valid\n", 04602 elem->name, NULL, NULL); 04603 } 04604 ret = 0; 04605 } 04606 04607 /* Validity constraint: Fixed Attribute Default */ 04608 if (attrDecl->def == XML_ATTRIBUTE_FIXED) { 04609 if (!xmlStrEqual(value, attrDecl->defaultValue)) { 04610 if (ns->prefix != NULL) { 04611 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 04612 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n", 04613 ns->prefix, elem->name, attrDecl->defaultValue); 04614 } else { 04615 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, 04616 "Value for attribute xmlns of %s is different from default \"%s\"\n", 04617 elem->name, attrDecl->defaultValue, NULL); 04618 } 04619 ret = 0; 04620 } 04621 } 04622 04623 /* Validity Constraint: ID uniqueness */ 04624 if (attrDecl->atype == XML_ATTRIBUTE_ID) { 04625 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) 04626 ret = 0; 04627 } 04628 04629 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || 04630 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { 04631 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) 04632 ret = 0; 04633 } 04634 04635 /* Validity Constraint: Notation Attributes */ 04636 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { 04637 xmlEnumerationPtr tree = attrDecl->tree; 04638 xmlNotationPtr nota; 04639 04640 /* First check that the given NOTATION was declared */ 04641 nota = xmlGetDtdNotationDesc(doc->intSubset, value); 04642 if (nota == NULL) 04643 nota = xmlGetDtdNotationDesc(doc->extSubset, value); 04644 04645 if (nota == NULL) { 04646 if (ns->prefix != NULL) { 04647 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 04648 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n", 04649 value, ns->prefix, elem->name); 04650 } else { 04651 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, 04652 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n", 04653 value, elem->name, NULL); 04654 } 04655 ret = 0; 04656 } 04657 04658 /* Second, verify that it's among the list */ 04659 while (tree != NULL) { 04660 if (xmlStrEqual(tree->name, value)) break; 04661 tree = tree->next; 04662 } 04663 if (tree == NULL) { 04664 if (ns->prefix != NULL) { 04665 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 04666 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n", 04667 value, ns->prefix, elem->name); 04668 } else { 04669 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, 04670 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n", 04671 value, elem->name, NULL); 04672 } 04673 ret = 0; 04674 } 04675 } 04676 04677 /* Validity Constraint: Enumeration */ 04678 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { 04679 xmlEnumerationPtr tree = attrDecl->tree; 04680 while (tree != NULL) { 04681 if (xmlStrEqual(tree->name, value)) break; 04682 tree = tree->next; 04683 } 04684 if (tree == NULL) { 04685 if (ns->prefix != NULL) { 04686 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 04687 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n", 04688 value, ns->prefix, elem->name); 04689 } else { 04690 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, 04691 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n", 04692 value, elem->name, NULL); 04693 } 04694 ret = 0; 04695 } 04696 } 04697 04698 /* Fixed Attribute Default */ 04699 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && 04700 (!xmlStrEqual(attrDecl->defaultValue, value))) { 04701 if (ns->prefix != NULL) { 04702 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 04703 "Value for attribute xmlns:%s of %s must be \"%s\"\n", 04704 ns->prefix, elem->name, attrDecl->defaultValue); 04705 } else { 04706 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 04707 "Value for attribute xmlns of %s must be \"%s\"\n", 04708 elem->name, attrDecl->defaultValue, NULL); 04709 } 04710 ret = 0; 04711 } 04712 04713 /* Extra check for the attribute value */ 04714 if (ns->prefix != NULL) { 04715 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix, 04716 attrDecl->atype, value); 04717 } else { 04718 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns", 04719 attrDecl->atype, value); 04720 } 04721 04722 return(ret); 04723 } 04724 04725 #ifndef LIBXML_REGEXP_ENABLED 04726 04736 static xmlNodePtr 04737 xmlValidateSkipIgnorable(xmlNodePtr child) { 04738 while (child != NULL) { 04739 switch (child->type) { 04740 /* These things are ignored (skipped) during validation. */ 04741 case XML_PI_NODE: 04742 case XML_COMMENT_NODE: 04743 case XML_XINCLUDE_START: 04744 case XML_XINCLUDE_END: 04745 child = child->next; 04746 break; 04747 case XML_TEXT_NODE: 04748 if (xmlIsBlankNode(child)) 04749 child = child->next; 04750 else 04751 return(child); 04752 break; 04753 /* keep current node */ 04754 default: 04755 return(child); 04756 } 04757 } 04758 return(child); 04759 } 04760 04772 static int 04773 xmlValidateElementType(xmlValidCtxtPtr ctxt) { 04774 int ret = -1; 04775 int determinist = 1; 04776 04777 NODE = xmlValidateSkipIgnorable(NODE); 04778 if ((NODE == NULL) && (CONT == NULL)) 04779 return(1); 04780 if ((NODE == NULL) && 04781 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || 04782 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) { 04783 return(1); 04784 } 04785 if (CONT == NULL) return(-1); 04786 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) 04787 return(-2); 04788 04789 /* 04790 * We arrive here when more states need to be examined 04791 */ 04792 cont: 04793 04794 /* 04795 * We just recovered from a rollback generated by a possible 04796 * epsilon transition, go directly to the analysis phase 04797 */ 04798 if (STATE == ROLLBACK_PARENT) { 04799 DEBUG_VALID_MSG("restored parent branch"); 04800 DEBUG_VALID_STATE(NODE, CONT) 04801 ret = 1; 04802 goto analyze; 04803 } 04804 04805 DEBUG_VALID_STATE(NODE, CONT) 04806 /* 04807 * we may have to save a backup state here. This is the equivalent 04808 * of handling epsilon transition in NFAs. 04809 */ 04810 if ((CONT != NULL) && 04811 ((CONT->parent == NULL) || 04812 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) && 04813 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || 04814 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) || 04815 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) { 04816 DEBUG_VALID_MSG("saving parent branch"); 04817 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0) 04818 return(0); 04819 } 04820 04821 04822 /* 04823 * Check first if the content matches 04824 */ 04825 switch (CONT->type) { 04826 case XML_ELEMENT_CONTENT_PCDATA: 04827 if (NODE == NULL) { 04828 DEBUG_VALID_MSG("pcdata failed no node"); 04829 ret = 0; 04830 break; 04831 } 04832 if (NODE->type == XML_TEXT_NODE) { 04833 DEBUG_VALID_MSG("pcdata found, skip to next"); 04834 /* 04835 * go to next element in the content model 04836 * skipping ignorable elems 04837 */ 04838 do { 04839 NODE = NODE->next; 04840 NODE = xmlValidateSkipIgnorable(NODE); 04841 if ((NODE != NULL) && 04842 (NODE->type == XML_ENTITY_REF_NODE)) 04843 return(-2); 04844 } while ((NODE != NULL) && 04845 ((NODE->type != XML_ELEMENT_NODE) && 04846 (NODE->type != XML_TEXT_NODE) && 04847 (NODE->type != XML_CDATA_SECTION_NODE))); 04848 ret = 1; 04849 break; 04850 } else { 04851 DEBUG_VALID_MSG("pcdata failed"); 04852 ret = 0; 04853 break; 04854 } 04855 break; 04856 case XML_ELEMENT_CONTENT_ELEMENT: 04857 if (NODE == NULL) { 04858 DEBUG_VALID_MSG("element failed no node"); 04859 ret = 0; 04860 break; 04861 } 04862 ret = ((NODE->type == XML_ELEMENT_NODE) && 04863 (xmlStrEqual(NODE->name, CONT->name))); 04864 if (ret == 1) { 04865 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 04866 ret = (CONT->prefix == NULL); 04867 } else if (CONT->prefix == NULL) { 04868 ret = 0; 04869 } else { 04870 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix); 04871 } 04872 } 04873 if (ret == 1) { 04874 DEBUG_VALID_MSG("element found, skip to next"); 04875 /* 04876 * go to next element in the content model 04877 * skipping ignorable elems 04878 */ 04879 do { 04880 NODE = NODE->next; 04881 NODE = xmlValidateSkipIgnorable(NODE); 04882 if ((NODE != NULL) && 04883 (NODE->type == XML_ENTITY_REF_NODE)) 04884 return(-2); 04885 } while ((NODE != NULL) && 04886 ((NODE->type != XML_ELEMENT_NODE) && 04887 (NODE->type != XML_TEXT_NODE) && 04888 (NODE->type != XML_CDATA_SECTION_NODE))); 04889 } else { 04890 DEBUG_VALID_MSG("element failed"); 04891 ret = 0; 04892 break; 04893 } 04894 break; 04895 case XML_ELEMENT_CONTENT_OR: 04896 /* 04897 * Small optimization. 04898 */ 04899 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { 04900 if ((NODE == NULL) || 04901 (!xmlStrEqual(NODE->name, CONT->c1->name))) { 04902 DEPTH++; 04903 CONT = CONT->c2; 04904 goto cont; 04905 } 04906 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 04907 ret = (CONT->c1->prefix == NULL); 04908 } else if (CONT->c1->prefix == NULL) { 04909 ret = 0; 04910 } else { 04911 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); 04912 } 04913 if (ret == 0) { 04914 DEPTH++; 04915 CONT = CONT->c2; 04916 goto cont; 04917 } 04918 } 04919 04920 /* 04921 * save the second branch 'or' branch 04922 */ 04923 DEBUG_VALID_MSG("saving 'or' branch"); 04924 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1), 04925 OCCURS, ROLLBACK_OR) < 0) 04926 return(-1); 04927 DEPTH++; 04928 CONT = CONT->c1; 04929 goto cont; 04930 case XML_ELEMENT_CONTENT_SEQ: 04931 /* 04932 * Small optimization. 04933 */ 04934 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) && 04935 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) || 04936 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) { 04937 if ((NODE == NULL) || 04938 (!xmlStrEqual(NODE->name, CONT->c1->name))) { 04939 DEPTH++; 04940 CONT = CONT->c2; 04941 goto cont; 04942 } 04943 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { 04944 ret = (CONT->c1->prefix == NULL); 04945 } else if (CONT->c1->prefix == NULL) { 04946 ret = 0; 04947 } else { 04948 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); 04949 } 04950 if (ret == 0) { 04951 DEPTH++; 04952 CONT = CONT->c2; 04953 goto cont; 04954 } 04955 } 04956 DEPTH++; 04957 CONT = CONT->c1; 04958 goto cont; 04959 } 04960 04961 /* 04962 * At this point handle going up in the tree 04963 */ 04964 if (ret == -1) { 04965 DEBUG_VALID_MSG("error found returning"); 04966 return(ret); 04967 } 04968 analyze: 04969 while (CONT != NULL) { 04970 /* 04971 * First do the analysis depending on the occurrence model at 04972 * this level. 04973 */ 04974 if (ret == 0) { 04975 switch (CONT->ocur) { 04976 xmlNodePtr cur; 04977 04978 case XML_ELEMENT_CONTENT_ONCE: 04979 cur = ctxt->vstate->node; 04980 DEBUG_VALID_MSG("Once branch failed, rollback"); 04981 if (vstateVPop(ctxt) < 0 ) { 04982 DEBUG_VALID_MSG("exhaustion, failed"); 04983 return(0); 04984 } 04985 if (cur != ctxt->vstate->node) 04986 determinist = -3; 04987 goto cont; 04988 case XML_ELEMENT_CONTENT_PLUS: 04989 if (OCCURRENCE == 0) { 04990 cur = ctxt->vstate->node; 04991 DEBUG_VALID_MSG("Plus branch failed, rollback"); 04992 if (vstateVPop(ctxt) < 0 ) { 04993 DEBUG_VALID_MSG("exhaustion, failed"); 04994 return(0); 04995 } 04996 if (cur != ctxt->vstate->node) 04997 determinist = -3; 04998 goto cont; 04999 } 05000 DEBUG_VALID_MSG("Plus branch found"); 05001 ret = 1; 05002 break; 05003 case XML_ELEMENT_CONTENT_MULT: 05004 #ifdef DEBUG_VALID_ALGO 05005 if (OCCURRENCE == 0) { 05006 DEBUG_VALID_MSG("Mult branch failed"); 05007 } else { 05008 DEBUG_VALID_MSG("Mult branch found"); 05009 } 05010 #endif 05011 ret = 1; 05012 break; 05013 case XML_ELEMENT_CONTENT_OPT: 05014 DEBUG_VALID_MSG("Option branch failed"); 05015 ret = 1; 05016 break; 05017 } 05018 } else { 05019 switch (CONT->ocur) { 05020 case XML_ELEMENT_CONTENT_OPT: 05021 DEBUG_VALID_MSG("Option branch succeeded"); 05022 ret = 1; 05023 break; 05024 case XML_ELEMENT_CONTENT_ONCE: 05025 DEBUG_VALID_MSG("Once branch succeeded"); 05026 ret = 1; 05027 break; 05028 case XML_ELEMENT_CONTENT_PLUS: 05029 if (STATE == ROLLBACK_PARENT) { 05030 DEBUG_VALID_MSG("Plus branch rollback"); 05031 ret = 1; 05032 break; 05033 } 05034 if (NODE == NULL) { 05035 DEBUG_VALID_MSG("Plus branch exhausted"); 05036 ret = 1; 05037 break; 05038 } 05039 DEBUG_VALID_MSG("Plus branch succeeded, continuing"); 05040 SET_OCCURRENCE; 05041 goto cont; 05042 case XML_ELEMENT_CONTENT_MULT: 05043 if (STATE == ROLLBACK_PARENT) { 05044 DEBUG_VALID_MSG("Mult branch rollback"); 05045 ret = 1; 05046 break; 05047 } 05048 if (NODE == NULL) { 05049 DEBUG_VALID_MSG("Mult branch exhausted"); 05050 ret = 1; 05051 break; 05052 } 05053 DEBUG_VALID_MSG("Mult branch succeeded, continuing"); 05054 /* SET_OCCURRENCE; */ 05055 goto cont; 05056 } 05057 } 05058 STATE = 0; 05059 05060 /* 05061 * Then act accordingly at the parent level 05062 */ 05063 RESET_OCCURRENCE; 05064 if (CONT->parent == NULL) 05065 break; 05066 05067 switch (CONT->parent->type) { 05068 case XML_ELEMENT_CONTENT_PCDATA: 05069 DEBUG_VALID_MSG("Error: parent pcdata"); 05070 return(-1); 05071 case XML_ELEMENT_CONTENT_ELEMENT: 05072 DEBUG_VALID_MSG("Error: parent element"); 05073 return(-1); 05074 case XML_ELEMENT_CONTENT_OR: 05075 if (ret == 1) { 05076 DEBUG_VALID_MSG("Or succeeded"); 05077 CONT = CONT->parent; 05078 DEPTH--; 05079 } else { 05080 DEBUG_VALID_MSG("Or failed"); 05081 CONT = CONT->parent; 05082 DEPTH--; 05083 } 05084 break; 05085 case XML_ELEMENT_CONTENT_SEQ: 05086 if (ret == 0) { 05087 DEBUG_VALID_MSG("Sequence failed"); 05088 CONT = CONT->parent; 05089 DEPTH--; 05090 } else if (CONT == CONT->parent->c1) { 05091 DEBUG_VALID_MSG("Sequence testing 2nd branch"); 05092 CONT = CONT->parent->c2; 05093 goto cont; 05094 } else { 05095 DEBUG_VALID_MSG("Sequence succeeded"); 05096 CONT = CONT->parent; 05097 DEPTH--; 05098 } 05099 } 05100 } 05101 if (NODE != NULL) { 05102 xmlNodePtr cur; 05103 05104 cur = ctxt->vstate->node; 05105 DEBUG_VALID_MSG("Failed, remaining input, rollback"); 05106 if (vstateVPop(ctxt) < 0 ) { 05107 DEBUG_VALID_MSG("exhaustion, failed"); 05108 return(0); 05109 } 05110 if (cur != ctxt->vstate->node) 05111 determinist = -3; 05112 goto cont; 05113 } 05114 if (ret == 0) { 05115 xmlNodePtr cur; 05116 05117 cur = ctxt->vstate->node; 05118 DEBUG_VALID_MSG("Failure, rollback"); 05119 if (vstateVPop(ctxt) < 0 ) { 05120 DEBUG_VALID_MSG("exhaustion, failed"); 05121 return(0); 05122 } 05123 if (cur != ctxt->vstate->node) 05124 determinist = -3; 05125 goto cont; 05126 } 05127 return(determinist); 05128 } 05129 #endif 05130 05141 static void 05142 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) { 05143 xmlNodePtr cur; 05144 int len; 05145 05146 if (node == NULL) return; 05147 if (glob) strcat(buf, "("); 05148 cur = node; 05149 while (cur != NULL) { 05150 len = strlen(buf); 05151 if (size - len < 50) { 05152 if ((size - len > 4) && (buf[len - 1] != '.')) 05153 strcat(buf, " ..."); 05154 return; 05155 } 05156 switch (cur->type) { 05157 case XML_ELEMENT_NODE: 05158 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 05159 if (size - len < xmlStrlen(cur->ns->prefix) + 10) { 05160 if ((size - len > 4) && (buf[len - 1] != '.')) 05161 strcat(buf, " ..."); 05162 return; 05163 } 05164 strcat(buf, (char *) cur->ns->prefix); 05165 strcat(buf, ":"); 05166 } 05167 if (size - len < xmlStrlen(cur->name) + 10) { 05168 if ((size - len > 4) && (buf[len - 1] != '.')) 05169 strcat(buf, " ..."); 05170 return; 05171 } 05172 strcat(buf, (char *) cur->name); 05173 if (cur->next != NULL) 05174 strcat(buf, " "); 05175 break; 05176 case XML_TEXT_NODE: 05177 if (xmlIsBlankNode(cur)) 05178 break; 05179 case XML_CDATA_SECTION_NODE: 05180 case XML_ENTITY_REF_NODE: 05181 strcat(buf, "CDATA"); 05182 if (cur->next != NULL) 05183 strcat(buf, " "); 05184 break; 05185 case XML_ATTRIBUTE_NODE: 05186 case XML_DOCUMENT_NODE: 05187 #ifdef LIBXML_DOCB_ENABLED 05188 case XML_DOCB_DOCUMENT_NODE: 05189 #endif 05190 case XML_HTML_DOCUMENT_NODE: 05191 case XML_DOCUMENT_TYPE_NODE: 05192 case XML_DOCUMENT_FRAG_NODE: 05193 case XML_NOTATION_NODE: 05194 case XML_NAMESPACE_DECL: 05195 strcat(buf, "???"); 05196 if (cur->next != NULL) 05197 strcat(buf, " "); 05198 break; 05199 case XML_ENTITY_NODE: 05200 case XML_PI_NODE: 05201 case XML_DTD_NODE: 05202 case XML_COMMENT_NODE: 05203 case XML_ELEMENT_DECL: 05204 case XML_ATTRIBUTE_DECL: 05205 case XML_ENTITY_DECL: 05206 case XML_XINCLUDE_START: 05207 case XML_XINCLUDE_END: 05208 break; 05209 } 05210 cur = cur->next; 05211 } 05212 if (glob) strcat(buf, ")"); 05213 } 05214 05228 static int 05229 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, 05230 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) { 05231 int ret = 1; 05232 #ifndef LIBXML_REGEXP_ENABLED 05233 xmlNodePtr repl = NULL, last = NULL, tmp; 05234 #endif 05235 xmlNodePtr cur; 05236 xmlElementContentPtr cont; 05237 const xmlChar *name; 05238 05239 if (elemDecl == NULL) 05240 return(-1); 05241 cont = elemDecl->content; 05242 name = elemDecl->name; 05243 05244 #ifdef LIBXML_REGEXP_ENABLED 05245 /* Build the regexp associated to the content model */ 05246 if (elemDecl->contModel == NULL) 05247 ret = xmlValidBuildContentModel(ctxt, elemDecl); 05248 if (elemDecl->contModel == NULL) { 05249 return(-1); 05250 } else { 05251 xmlRegExecCtxtPtr exec; 05252 05253 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) { 05254 return(-1); 05255 } 05256 ctxt->nodeMax = 0; 05257 ctxt->nodeNr = 0; 05258 ctxt->nodeTab = NULL; 05259 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); 05260 if (exec != NULL) { 05261 cur = child; 05262 while (cur != NULL) { 05263 switch (cur->type) { 05264 case XML_ENTITY_REF_NODE: 05265 /* 05266 * Push the current node to be able to roll back 05267 * and process within the entity 05268 */ 05269 if ((cur->children != NULL) && 05270 (cur->children->children != NULL)) { 05271 nodeVPush(ctxt, cur); 05272 cur = cur->children->children; 05273 continue; 05274 } 05275 break; 05276 case XML_TEXT_NODE: 05277 if (xmlIsBlankNode(cur)) 05278 break; 05279 ret = 0; 05280 goto fail; 05281 case XML_CDATA_SECTION_NODE: 05282 /* TODO */ 05283 ret = 0; 05284 goto fail; 05285 case XML_ELEMENT_NODE: 05286 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { 05287 xmlChar fn[50]; 05288 xmlChar *fullname; 05289 05290 fullname = xmlBuildQName(cur->name, 05291 cur->ns->prefix, fn, 50); 05292 if (fullname == NULL) { 05293 ret = -1; 05294 goto fail; 05295 } 05296 ret = xmlRegExecPushString(exec, fullname, NULL); 05297 if ((fullname != fn) && (fullname != cur->name)) 05298 xmlFree(fullname); 05299 } else { 05300 ret = xmlRegExecPushString(exec, cur->name, NULL); 05301 } 05302 break; 05303 default: 05304 break; 05305 } 05306 /* 05307 * Switch to next element 05308 */ 05309 cur = cur->next; 05310 while (cur == NULL) { 05311 cur = nodeVPop(ctxt); 05312 if (cur == NULL) 05313 break; 05314 cur = cur->next; 05315 } 05316 } 05317 ret = xmlRegExecPushString(exec, NULL, NULL); 05318 fail: 05319 xmlRegFreeExecCtxt(exec); 05320 } 05321 } 05322 #else /* LIBXML_REGEXP_ENABLED */ 05323 /* 05324 * Allocate the stack 05325 */ 05326 ctxt->vstateMax = 8; 05327 ctxt->vstateTab = (xmlValidState *) xmlMalloc( 05328 ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); 05329 if (ctxt->vstateTab == NULL) { 05330 xmlVErrMemory(ctxt, "malloc failed"); 05331 return(-1); 05332 } 05333 /* 05334 * The first entry in the stack is reserved to the current state 05335 */ 05336 ctxt->nodeMax = 0; 05337 ctxt->nodeNr = 0; 05338 ctxt->nodeTab = NULL; 05339 ctxt->vstate = &ctxt->vstateTab[0]; 05340 ctxt->vstateNr = 1; 05341 CONT = cont; 05342 NODE = child; 05343 DEPTH = 0; 05344 OCCURS = 0; 05345 STATE = 0; 05346 ret = xmlValidateElementType(ctxt); 05347 if ((ret == -3) && (warn)) { 05348 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST, 05349 "Content model for Element %s is ambiguous\n", 05350 name, NULL, NULL); 05351 } else if (ret == -2) { 05352 /* 05353 * An entities reference appeared at this level. 05354 * Buid a minimal representation of this node content 05355 * sufficient to run the validation process on it 05356 */ 05357 DEBUG_VALID_MSG("Found an entity reference, linearizing"); 05358 cur = child; 05359 while (cur != NULL) { 05360 switch (cur->type) { 05361 case XML_ENTITY_REF_NODE: 05362 /* 05363 * Push the current node to be able to roll back 05364 * and process within the entity 05365 */ 05366 if ((cur->children != NULL) && 05367 (cur->children->children != NULL)) { 05368 nodeVPush(ctxt, cur); 05369 cur = cur->children->children; 05370 continue; 05371 } 05372 break; 05373 case XML_TEXT_NODE: 05374 if (xmlIsBlankNode(cur)) 05375 break; 05376 /* no break on purpose */ 05377 case XML_CDATA_SECTION_NODE: 05378 /* no break on purpose */ 05379 case XML_ELEMENT_NODE: 05380 /* 05381 * Allocate a new node and minimally fills in 05382 * what's required 05383 */ 05384 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 05385 if (tmp == NULL) { 05386 xmlVErrMemory(ctxt, "malloc failed"); 05387 xmlFreeNodeList(repl); 05388 ret = -1; 05389 goto done; 05390 } 05391 tmp->type = cur->type; 05392 tmp->name = cur->name; 05393 tmp->ns = cur->ns; 05394 tmp->next = NULL; 05395 tmp->content = NULL; 05396 if (repl == NULL) 05397 repl = last = tmp; 05398 else { 05399 last->next = tmp; 05400 last = tmp; 05401 } 05402 if (cur->type == XML_CDATA_SECTION_NODE) { 05403 /* 05404 * E59 spaces in CDATA does not match the 05405 * nonterminal S 05406 */ 05407 tmp->content = xmlStrdup(BAD_CAST "CDATA"); 05408 } 05409 break; 05410 default: 05411 break; 05412 } 05413 /* 05414 * Switch to next element 05415 */ 05416 cur = cur->next; 05417 while (cur == NULL) { 05418 cur = nodeVPop(ctxt); 05419 if (cur == NULL) 05420 break; 05421 cur = cur->next; 05422 } 05423 } 05424 05425 /* 05426 * Relaunch the validation 05427 */ 05428 ctxt->vstate = &ctxt->vstateTab[0]; 05429 ctxt->vstateNr = 1; 05430 CONT = cont; 05431 NODE = repl; 05432 DEPTH = 0; 05433 OCCURS = 0; 05434 STATE = 0; 05435 ret = xmlValidateElementType(ctxt); 05436 } 05437 #endif /* LIBXML_REGEXP_ENABLED */ 05438 if ((warn) && ((ret != 1) && (ret != -3))) { 05439 if (ctxt != NULL) { 05440 char expr[5000]; 05441 char list[5000]; 05442 05443 expr[0] = 0; 05444 xmlSnprintfElementContent(&expr[0], 5000, cont, 1); 05445 list[0] = 0; 05446 #ifndef LIBXML_REGEXP_ENABLED 05447 if (repl != NULL) 05448 xmlSnprintfElements(&list[0], 5000, repl, 1); 05449 else 05450 #endif /* LIBXML_REGEXP_ENABLED */ 05451 xmlSnprintfElements(&list[0], 5000, child, 1); 05452 05453 if (name != NULL) { 05454 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 05455 "Element %s content does not follow the DTD, expecting %s, got %s\n", 05456 name, BAD_CAST expr, BAD_CAST list); 05457 } else { 05458 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 05459 "Element content does not follow the DTD, expecting %s, got %s\n", 05460 BAD_CAST expr, BAD_CAST list, NULL); 05461 } 05462 } else { 05463 if (name != NULL) { 05464 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 05465 "Element %s content does not follow the DTD\n", 05466 name, NULL, NULL); 05467 } else { 05468 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, 05469 "Element content does not follow the DTD\n", 05470 NULL, NULL, NULL); 05471 } 05472 } 05473 ret = 0; 05474 } 05475 if (ret == -3) 05476 ret = 1; 05477 05478 #ifndef LIBXML_REGEXP_ENABLED 05479 done: 05480 /* 05481 * Deallocate the copy if done, and free up the validation stack 05482 */ 05483 while (repl != NULL) { 05484 tmp = repl->next; 05485 xmlFree(repl); 05486 repl = tmp; 05487 } 05488 ctxt->vstateMax = 0; 05489 if (ctxt->vstateTab != NULL) { 05490 xmlFree(ctxt->vstateTab); 05491 ctxt->vstateTab = NULL; 05492 } 05493 #endif 05494 ctxt->nodeMax = 0; 05495 ctxt->nodeNr = 0; 05496 if (ctxt->nodeTab != NULL) { 05497 xmlFree(ctxt->nodeTab); 05498 ctxt->nodeTab = NULL; 05499 } 05500 return(ret); 05501 05502 } 05503 05514 static int 05515 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 05516 xmlNodePtr elem) { 05517 int ret = 1; 05518 xmlNodePtr cur, child; 05519 05520 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL)) 05521 return(0); 05522 05523 child = elem->children; 05524 05525 cur = child; 05526 while (cur != NULL) { 05527 switch (cur->type) { 05528 case XML_ENTITY_REF_NODE: 05529 /* 05530 * Push the current node to be able to roll back 05531 * and process within the entity 05532 */ 05533 if ((cur->children != NULL) && 05534 (cur->children->children != NULL)) { 05535 nodeVPush(ctxt, cur); 05536 cur = cur->children->children; 05537 continue; 05538 } 05539 break; 05540 case XML_COMMENT_NODE: 05541 case XML_PI_NODE: 05542 case XML_TEXT_NODE: 05543 case XML_CDATA_SECTION_NODE: 05544 break; 05545 default: 05546 ret = 0; 05547 goto done; 05548 } 05549 /* 05550 * Switch to next element 05551 */ 05552 cur = cur->next; 05553 while (cur == NULL) { 05554 cur = nodeVPop(ctxt); 05555 if (cur == NULL) 05556 break; 05557 cur = cur->next; 05558 } 05559 } 05560 done: 05561 ctxt->nodeMax = 0; 05562 ctxt->nodeNr = 0; 05563 if (ctxt->nodeTab != NULL) { 05564 xmlFree(ctxt->nodeTab); 05565 ctxt->nodeTab = NULL; 05566 } 05567 return(ret); 05568 } 05569 05580 static int 05581 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt, 05582 xmlElementContentPtr cont, const xmlChar *qname) { 05583 const xmlChar *name; 05584 int plen; 05585 name = xmlSplitQName3(qname, &plen); 05586 05587 if (name == NULL) { 05588 while (cont != NULL) { 05589 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 05590 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname))) 05591 return(1); 05592 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 05593 (cont->c1 != NULL) && 05594 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 05595 if ((cont->c1->prefix == NULL) && 05596 (xmlStrEqual(cont->c1->name, qname))) 05597 return(1); 05598 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 05599 (cont->c1 == NULL) || 05600 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 05601 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 05602 "Internal: MIXED struct corrupted\n", 05603 NULL); 05604 break; 05605 } 05606 cont = cont->c2; 05607 } 05608 } else { 05609 while (cont != NULL) { 05610 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 05611 if ((cont->prefix != NULL) && 05612 (xmlStrncmp(cont->prefix, qname, plen) == 0) && 05613 (xmlStrEqual(cont->name, name))) 05614 return(1); 05615 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 05616 (cont->c1 != NULL) && 05617 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 05618 if ((cont->c1->prefix != NULL) && 05619 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) && 05620 (xmlStrEqual(cont->c1->name, name))) 05621 return(1); 05622 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 05623 (cont->c1 == NULL) || 05624 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 05625 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 05626 "Internal: MIXED struct corrupted\n", 05627 NULL); 05628 break; 05629 } 05630 cont = cont->c2; 05631 } 05632 } 05633 return(0); 05634 } 05635 05648 static xmlElementPtr 05649 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 05650 xmlNodePtr elem, int *extsubset) { 05651 xmlElementPtr elemDecl = NULL; 05652 const xmlChar *prefix = NULL; 05653 05654 if ((ctxt == NULL) || (doc == NULL) || 05655 (elem == NULL) || (elem->name == NULL)) 05656 return(NULL); 05657 if (extsubset != NULL) 05658 *extsubset = 0; 05659 05660 /* 05661 * Fetch the declaration for the qualified name 05662 */ 05663 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) 05664 prefix = elem->ns->prefix; 05665 05666 if (prefix != NULL) { 05667 elemDecl = xmlGetDtdQElementDesc(doc->intSubset, 05668 elem->name, prefix); 05669 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 05670 elemDecl = xmlGetDtdQElementDesc(doc->extSubset, 05671 elem->name, prefix); 05672 if ((elemDecl != NULL) && (extsubset != NULL)) 05673 *extsubset = 1; 05674 } 05675 } 05676 05677 /* 05678 * Fetch the declaration for the non qualified name 05679 * This is "non-strict" validation should be done on the 05680 * full QName but in that case being flexible makes sense. 05681 */ 05682 if (elemDecl == NULL) { 05683 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); 05684 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 05685 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); 05686 if ((elemDecl != NULL) && (extsubset != NULL)) 05687 *extsubset = 1; 05688 } 05689 } 05690 if (elemDecl == NULL) { 05691 xmlErrValidNode(ctxt, elem, 05692 XML_DTD_UNKNOWN_ELEM, 05693 "No declaration for element %s\n", 05694 elem->name, NULL, NULL); 05695 } 05696 return(elemDecl); 05697 } 05698 05699 #ifdef LIBXML_REGEXP_ENABLED 05700 05711 int 05712 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 05713 xmlNodePtr elem, const xmlChar *qname) { 05714 int ret = 1; 05715 xmlElementPtr eDecl; 05716 int extsubset = 0; 05717 05718 if (ctxt == NULL) 05719 return(0); 05720 /* printf("PushElem %s\n", qname); */ 05721 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 05722 xmlValidStatePtr state = ctxt->vstate; 05723 xmlElementPtr elemDecl; 05724 05725 /* 05726 * Check the new element agaisnt the content model of the new elem. 05727 */ 05728 if (state->elemDecl != NULL) { 05729 elemDecl = state->elemDecl; 05730 05731 switch(elemDecl->etype) { 05732 case XML_ELEMENT_TYPE_UNDEFINED: 05733 ret = 0; 05734 break; 05735 case XML_ELEMENT_TYPE_EMPTY: 05736 xmlErrValidNode(ctxt, state->node, 05737 XML_DTD_NOT_EMPTY, 05738 "Element %s was declared EMPTY this one has content\n", 05739 state->node->name, NULL, NULL); 05740 ret = 0; 05741 break; 05742 case XML_ELEMENT_TYPE_ANY: 05743 /* I don't think anything is required then */ 05744 break; 05745 case XML_ELEMENT_TYPE_MIXED: 05746 /* simple case of declared as #PCDATA */ 05747 if ((elemDecl->content != NULL) && 05748 (elemDecl->content->type == 05749 XML_ELEMENT_CONTENT_PCDATA)) { 05750 xmlErrValidNode(ctxt, state->node, 05751 XML_DTD_NOT_PCDATA, 05752 "Element %s was declared #PCDATA but contains non text nodes\n", 05753 state->node->name, NULL, NULL); 05754 ret = 0; 05755 } else { 05756 ret = xmlValidateCheckMixed(ctxt, elemDecl->content, 05757 qname); 05758 if (ret != 1) { 05759 xmlErrValidNode(ctxt, state->node, 05760 XML_DTD_INVALID_CHILD, 05761 "Element %s is not declared in %s list of possible children\n", 05762 qname, state->node->name, NULL); 05763 } 05764 } 05765 break; 05766 case XML_ELEMENT_TYPE_ELEMENT: 05767 /* 05768 * TODO: 05769 * VC: Standalone Document Declaration 05770 * - element types with element content, if white space 05771 * occurs directly within any instance of those types. 05772 */ 05773 if (state->exec != NULL) { 05774 ret = xmlRegExecPushString(state->exec, qname, NULL); 05775 if (ret < 0) { 05776 xmlErrValidNode(ctxt, state->node, 05777 XML_DTD_CONTENT_MODEL, 05778 "Element %s content does not follow the DTD, Misplaced %s\n", 05779 state->node->name, qname, NULL); 05780 ret = 0; 05781 } else { 05782 ret = 1; 05783 } 05784 } 05785 break; 05786 } 05787 } 05788 } 05789 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 05790 vstateVPush(ctxt, eDecl, elem); 05791 return(ret); 05792 } 05793 05804 int 05805 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) { 05806 int ret = 1; 05807 05808 /* printf("CDATA %s %d\n", data, len); */ 05809 if (ctxt == NULL) 05810 return(0); 05811 if (len <= 0) 05812 return(ret); 05813 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 05814 xmlValidStatePtr state = ctxt->vstate; 05815 xmlElementPtr elemDecl; 05816 05817 /* 05818 * Check the new element agaisnt the content model of the new elem. 05819 */ 05820 if (state->elemDecl != NULL) { 05821 elemDecl = state->elemDecl; 05822 05823 switch(elemDecl->etype) { 05824 case XML_ELEMENT_TYPE_UNDEFINED: 05825 ret = 0; 05826 break; 05827 case XML_ELEMENT_TYPE_EMPTY: 05828 xmlErrValidNode(ctxt, state->node, 05829 XML_DTD_NOT_EMPTY, 05830 "Element %s was declared EMPTY this one has content\n", 05831 state->node->name, NULL, NULL); 05832 ret = 0; 05833 break; 05834 case XML_ELEMENT_TYPE_ANY: 05835 break; 05836 case XML_ELEMENT_TYPE_MIXED: 05837 break; 05838 case XML_ELEMENT_TYPE_ELEMENT: 05839 if (len > 0) { 05840 int i; 05841 05842 for (i = 0;i < len;i++) { 05843 if (!IS_BLANK_CH(data[i])) { 05844 xmlErrValidNode(ctxt, state->node, 05845 XML_DTD_CONTENT_MODEL, 05846 "Element %s content does not follow the DTD, Text not allowed\n", 05847 state->node->name, NULL, NULL); 05848 ret = 0; 05849 goto done; 05850 } 05851 } 05852 /* 05853 * TODO: 05854 * VC: Standalone Document Declaration 05855 * element types with element content, if white space 05856 * occurs directly within any instance of those types. 05857 */ 05858 } 05859 break; 05860 } 05861 } 05862 } 05863 done: 05864 return(ret); 05865 } 05866 05878 int 05879 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, 05880 xmlNodePtr elem ATTRIBUTE_UNUSED, 05881 const xmlChar *qname ATTRIBUTE_UNUSED) { 05882 int ret = 1; 05883 05884 if (ctxt == NULL) 05885 return(0); 05886 /* printf("PopElem %s\n", qname); */ 05887 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 05888 xmlValidStatePtr state = ctxt->vstate; 05889 xmlElementPtr elemDecl; 05890 05891 /* 05892 * Check the new element agaisnt the content model of the new elem. 05893 */ 05894 if (state->elemDecl != NULL) { 05895 elemDecl = state->elemDecl; 05896 05897 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) { 05898 if (state->exec != NULL) { 05899 ret = xmlRegExecPushString(state->exec, NULL, NULL); 05900 if (ret == 0) { 05901 xmlErrValidNode(ctxt, state->node, 05902 XML_DTD_CONTENT_MODEL, 05903 "Element %s content does not follow the DTD, Expecting more child\n", 05904 state->node->name, NULL,NULL); 05905 } else { 05906 /* 05907 * previous validation errors should not generate 05908 * a new one here 05909 */ 05910 ret = 1; 05911 } 05912 } 05913 } 05914 } 05915 vstateVPop(ctxt); 05916 } 05917 return(ret); 05918 } 05919 #endif /* LIBXML_REGEXP_ENABLED */ 05920 05939 int 05940 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 05941 xmlNodePtr elem) { 05942 xmlElementPtr elemDecl = NULL; 05943 xmlElementContentPtr cont; 05944 xmlAttributePtr attr; 05945 xmlNodePtr child; 05946 int ret = 1, tmp; 05947 const xmlChar *name; 05948 int extsubset = 0; 05949 05950 CHECK_DTD; 05951 05952 if (elem == NULL) return(0); 05953 switch (elem->type) { 05954 case XML_ATTRIBUTE_NODE: 05955 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05956 "Attribute element not expected\n", NULL, NULL ,NULL); 05957 return(0); 05958 case XML_TEXT_NODE: 05959 if (elem->children != NULL) { 05960 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05961 "Text element has children !\n", 05962 NULL,NULL,NULL); 05963 return(0); 05964 } 05965 if (elem->ns != NULL) { 05966 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05967 "Text element has namespace !\n", 05968 NULL,NULL,NULL); 05969 return(0); 05970 } 05971 if (elem->content == NULL) { 05972 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05973 "Text element has no content !\n", 05974 NULL,NULL,NULL); 05975 return(0); 05976 } 05977 return(1); 05978 case XML_XINCLUDE_START: 05979 case XML_XINCLUDE_END: 05980 return(1); 05981 case XML_CDATA_SECTION_NODE: 05982 case XML_ENTITY_REF_NODE: 05983 case XML_PI_NODE: 05984 case XML_COMMENT_NODE: 05985 return(1); 05986 case XML_ENTITY_NODE: 05987 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05988 "Entity element not expected\n", NULL, NULL ,NULL); 05989 return(0); 05990 case XML_NOTATION_NODE: 05991 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05992 "Notation element not expected\n", NULL, NULL ,NULL); 05993 return(0); 05994 case XML_DOCUMENT_NODE: 05995 case XML_DOCUMENT_TYPE_NODE: 05996 case XML_DOCUMENT_FRAG_NODE: 05997 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 05998 "Document element not expected\n", NULL, NULL ,NULL); 05999 return(0); 06000 case XML_HTML_DOCUMENT_NODE: 06001 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 06002 "HTML Document not expected\n", NULL, NULL ,NULL); 06003 return(0); 06004 case XML_ELEMENT_NODE: 06005 break; 06006 default: 06007 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 06008 "unknown element type\n", NULL, NULL ,NULL); 06009 return(0); 06010 } 06011 06012 /* 06013 * Fetch the declaration 06014 */ 06015 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 06016 if (elemDecl == NULL) 06017 return(0); 06018 06019 /* 06020 * If vstateNr is not zero that means continuous validation is 06021 * activated, do not try to check the content model at that level. 06022 */ 06023 if (ctxt->vstateNr == 0) { 06024 /* Check that the element content matches the definition */ 06025 switch (elemDecl->etype) { 06026 case XML_ELEMENT_TYPE_UNDEFINED: 06027 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, 06028 "No declaration for element %s\n", 06029 elem->name, NULL, NULL); 06030 return(0); 06031 case XML_ELEMENT_TYPE_EMPTY: 06032 if (elem->children != NULL) { 06033 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY, 06034 "Element %s was declared EMPTY this one has content\n", 06035 elem->name, NULL, NULL); 06036 ret = 0; 06037 } 06038 break; 06039 case XML_ELEMENT_TYPE_ANY: 06040 /* I don't think anything is required then */ 06041 break; 06042 case XML_ELEMENT_TYPE_MIXED: 06043 06044 /* simple case of declared as #PCDATA */ 06045 if ((elemDecl->content != NULL) && 06046 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { 06047 ret = xmlValidateOneCdataElement(ctxt, doc, elem); 06048 if (!ret) { 06049 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA, 06050 "Element %s was declared #PCDATA but contains non text nodes\n", 06051 elem->name, NULL, NULL); 06052 } 06053 break; 06054 } 06055 child = elem->children; 06056 /* Hum, this start to get messy */ 06057 while (child != NULL) { 06058 if (child->type == XML_ELEMENT_NODE) { 06059 name = child->name; 06060 if ((child->ns != NULL) && (child->ns->prefix != NULL)) { 06061 xmlChar fn[50]; 06062 xmlChar *fullname; 06063 06064 fullname = xmlBuildQName(child->name, child->ns->prefix, 06065 fn, 50); 06066 if (fullname == NULL) 06067 return(0); 06068 cont = elemDecl->content; 06069 while (cont != NULL) { 06070 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 06071 if (xmlStrEqual(cont->name, fullname)) 06072 break; 06073 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 06074 (cont->c1 != NULL) && 06075 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 06076 if (xmlStrEqual(cont->c1->name, fullname)) 06077 break; 06078 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 06079 (cont->c1 == NULL) || 06080 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 06081 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 06082 "Internal: MIXED struct corrupted\n", 06083 NULL); 06084 break; 06085 } 06086 cont = cont->c2; 06087 } 06088 if ((fullname != fn) && (fullname != child->name)) 06089 xmlFree(fullname); 06090 if (cont != NULL) 06091 goto child_ok; 06092 } 06093 cont = elemDecl->content; 06094 while (cont != NULL) { 06095 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 06096 if (xmlStrEqual(cont->name, name)) break; 06097 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 06098 (cont->c1 != NULL) && 06099 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) { 06100 if (xmlStrEqual(cont->c1->name, name)) break; 06101 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 06102 (cont->c1 == NULL) || 06103 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) { 06104 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 06105 "Internal: MIXED struct corrupted\n", 06106 NULL); 06107 break; 06108 } 06109 cont = cont->c2; 06110 } 06111 if (cont == NULL) { 06112 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD, 06113 "Element %s is not declared in %s list of possible children\n", 06114 name, elem->name, NULL); 06115 ret = 0; 06116 } 06117 } 06118 child_ok: 06119 child = child->next; 06120 } 06121 break; 06122 case XML_ELEMENT_TYPE_ELEMENT: 06123 if ((doc->standalone == 1) && (extsubset == 1)) { 06124 /* 06125 * VC: Standalone Document Declaration 06126 * - element types with element content, if white space 06127 * occurs directly within any instance of those types. 06128 */ 06129 child = elem->children; 06130 while (child != NULL) { 06131 if (child->type == XML_TEXT_NODE) { 06132 const xmlChar *content = child->content; 06133 06134 while (IS_BLANK_CH(*content)) 06135 content++; 06136 if (*content == 0) { 06137 xmlErrValidNode(ctxt, elem, 06138 XML_DTD_STANDALONE_WHITE_SPACE, 06139 "standalone: %s declared in the external subset contains white spaces nodes\n", 06140 elem->name, NULL, NULL); 06141 ret = 0; 06142 break; 06143 } 06144 } 06145 child =child->next; 06146 } 06147 } 06148 child = elem->children; 06149 cont = elemDecl->content; 06150 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); 06151 if (tmp <= 0) 06152 ret = tmp; 06153 break; 06154 } 06155 } /* not continuous */ 06156 06157 /* [ VC: Required Attribute ] */ 06158 attr = elemDecl->attributes; 06159 while (attr != NULL) { 06160 if (attr->def == XML_ATTRIBUTE_REQUIRED) { 06161 int qualified = -1; 06162 06163 if ((attr->prefix == NULL) && 06164 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 06165 xmlNsPtr ns; 06166 06167 ns = elem->nsDef; 06168 while (ns != NULL) { 06169 if (ns->prefix == NULL) 06170 goto found; 06171 ns = ns->next; 06172 } 06173 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 06174 xmlNsPtr ns; 06175 06176 ns = elem->nsDef; 06177 while (ns != NULL) { 06178 if (xmlStrEqual(attr->name, ns->prefix)) 06179 goto found; 06180 ns = ns->next; 06181 } 06182 } else { 06183 xmlAttrPtr attrib; 06184 06185 attrib = elem->properties; 06186 while (attrib != NULL) { 06187 if (xmlStrEqual(attrib->name, attr->name)) { 06188 if (attr->prefix != NULL) { 06189 xmlNsPtr nameSpace = attrib->ns; 06190 06191 if (nameSpace == NULL) 06192 nameSpace = elem->ns; 06193 /* 06194 * qualified names handling is problematic, having a 06195 * different prefix should be possible but DTDs don't 06196 * allow to define the URI instead of the prefix :-( 06197 */ 06198 if (nameSpace == NULL) { 06199 if (qualified < 0) 06200 qualified = 0; 06201 } else if (!xmlStrEqual(nameSpace->prefix, 06202 attr->prefix)) { 06203 if (qualified < 1) 06204 qualified = 1; 06205 } else 06206 goto found; 06207 } else { 06208 /* 06209 * We should allow applications to define namespaces 06210 * for their application even if the DTD doesn't 06211 * carry one, otherwise, basically we would always 06212 * break. 06213 */ 06214 goto found; 06215 } 06216 } 06217 attrib = attrib->next; 06218 } 06219 } 06220 if (qualified == -1) { 06221 if (attr->prefix == NULL) { 06222 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 06223 "Element %s does not carry attribute %s\n", 06224 elem->name, attr->name, NULL); 06225 ret = 0; 06226 } else { 06227 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 06228 "Element %s does not carry attribute %s:%s\n", 06229 elem->name, attr->prefix,attr->name); 06230 ret = 0; 06231 } 06232 } else if (qualified == 0) { 06233 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX, 06234 "Element %s required attribute %s:%s has no prefix\n", 06235 elem->name, attr->prefix, attr->name); 06236 } else if (qualified == 1) { 06237 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX, 06238 "Element %s required attribute %s:%s has different prefix\n", 06239 elem->name, attr->prefix, attr->name); 06240 } 06241 } else if (attr->def == XML_ATTRIBUTE_FIXED) { 06242 /* 06243 * Special tests checking #FIXED namespace declarations 06244 * have the right value since this is not done as an 06245 * attribute checking 06246 */ 06247 if ((attr->prefix == NULL) && 06248 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 06249 xmlNsPtr ns; 06250 06251 ns = elem->nsDef; 06252 while (ns != NULL) { 06253 if (ns->prefix == NULL) { 06254 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 06255 xmlErrValidNode(ctxt, elem, 06256 XML_DTD_ELEM_DEFAULT_NAMESPACE, 06257 "Element %s namespace name for default namespace does not match the DTD\n", 06258 elem->name, NULL, NULL); 06259 ret = 0; 06260 } 06261 goto found; 06262 } 06263 ns = ns->next; 06264 } 06265 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 06266 xmlNsPtr ns; 06267 06268 ns = elem->nsDef; 06269 while (ns != NULL) { 06270 if (xmlStrEqual(attr->name, ns->prefix)) { 06271 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 06272 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 06273 "Element %s namespace name for %s does not match the DTD\n", 06274 elem->name, ns->prefix, NULL); 06275 ret = 0; 06276 } 06277 goto found; 06278 } 06279 ns = ns->next; 06280 } 06281 } 06282 } 06283 found: 06284 attr = attr->nexth; 06285 } 06286 return(ret); 06287 } 06288 06303 int 06304 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 06305 xmlNodePtr root; 06306 int ret; 06307 06308 if (doc == NULL) return(0); 06309 06310 root = xmlDocGetRootElement(doc); 06311 if ((root == NULL) || (root->name == NULL)) { 06312 xmlErrValid(ctxt, XML_DTD_NO_ROOT, 06313 "no root element\n", NULL); 06314 return(0); 06315 } 06316 06317 /* 06318 * When doing post validation against a separate DTD, those may 06319 * no internal subset has been generated 06320 */ 06321 if ((doc->intSubset != NULL) && 06322 (doc->intSubset->name != NULL)) { 06323 /* 06324 * Check first the document root against the NQName 06325 */ 06326 if (!xmlStrEqual(doc->intSubset->name, root->name)) { 06327 if ((root->ns != NULL) && (root->ns->prefix != NULL)) { 06328 xmlChar fn[50]; 06329 xmlChar *fullname; 06330 06331 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); 06332 if (fullname == NULL) { 06333 xmlVErrMemory(ctxt, NULL); 06334 return(0); 06335 } 06336 ret = xmlStrEqual(doc->intSubset->name, fullname); 06337 if ((fullname != fn) && (fullname != root->name)) 06338 xmlFree(fullname); 06339 if (ret == 1) 06340 goto name_ok; 06341 } 06342 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) && 06343 (xmlStrEqual(root->name, BAD_CAST "html"))) 06344 goto name_ok; 06345 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME, 06346 "root and DTD name do not match '%s' and '%s'\n", 06347 root->name, doc->intSubset->name, NULL); 06348 return(0); 06349 } 06350 } 06351 name_ok: 06352 return(1); 06353 } 06354 06355 06367 int 06368 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { 06369 xmlNodePtr child; 06370 xmlAttrPtr attr; 06371 xmlNsPtr ns; 06372 const xmlChar *value; 06373 int ret = 1; 06374 06375 if (elem == NULL) return(0); 06376 06377 /* 06378 * XInclude elements were added after parsing in the infoset, 06379 * they don't really mean anything validation wise. 06380 */ 06381 if ((elem->type == XML_XINCLUDE_START) || 06382 (elem->type == XML_XINCLUDE_END)) 06383 return(1); 06384 06385 CHECK_DTD; 06386 06387 /* 06388 * Entities references have to be handled separately 06389 */ 06390 if (elem->type == XML_ENTITY_REF_NODE) { 06391 return(1); 06392 } 06393 06394 ret &= xmlValidateOneElement(ctxt, doc, elem); 06395 if (elem->type == XML_ELEMENT_NODE) { 06396 attr = elem->properties; 06397 while (attr != NULL) { 06398 value = xmlNodeListGetString(doc, attr->children, 0); 06399 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); 06400 if (value != NULL) 06401 xmlFree((char *)value); 06402 attr= attr->next; 06403 } 06404 ns = elem->nsDef; 06405 while (ns != NULL) { 06406 if (elem->ns == NULL) 06407 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL, 06408 ns, ns->href); 06409 else 06410 ret &= xmlValidateOneNamespace(ctxt, doc, elem, 06411 elem->ns->prefix, ns, ns->href); 06412 ns = ns->next; 06413 } 06414 } 06415 child = elem->children; 06416 while (child != NULL) { 06417 ret &= xmlValidateElement(ctxt, doc, child); 06418 child = child->next; 06419 } 06420 06421 return(ret); 06422 } 06423 06431 static void 06432 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, 06433 const xmlChar *name) { 06434 xmlAttrPtr id; 06435 xmlAttrPtr attr; 06436 06437 if (ref == NULL) 06438 return; 06439 if ((ref->attr == NULL) && (ref->name == NULL)) 06440 return; 06441 attr = ref->attr; 06442 if (attr == NULL) { 06443 xmlChar *dup, *str = NULL, *cur, save; 06444 06445 dup = xmlStrdup(name); 06446 if (dup == NULL) { 06447 ctxt->valid = 0; 06448 return; 06449 } 06450 cur = dup; 06451 while (*cur != 0) { 06452 str = cur; 06453 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 06454 save = *cur; 06455 *cur = 0; 06456 id = xmlGetID(ctxt->doc, str); 06457 if (id == NULL) { 06458 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID, 06459 "attribute %s line %d references an unknown ID \"%s\"\n", 06460 ref->name, ref->lineno, str); 06461 ctxt->valid = 0; 06462 } 06463 if (save == 0) 06464 break; 06465 *cur = save; 06466 while (IS_BLANK_CH(*cur)) cur++; 06467 } 06468 xmlFree(dup); 06469 } else if (attr->atype == XML_ATTRIBUTE_IDREF) { 06470 id = xmlGetID(ctxt->doc, name); 06471 if (id == NULL) { 06472 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 06473 "IDREF attribute %s references an unknown ID \"%s\"\n", 06474 attr->name, name, NULL); 06475 ctxt->valid = 0; 06476 } 06477 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { 06478 xmlChar *dup, *str = NULL, *cur, save; 06479 06480 dup = xmlStrdup(name); 06481 if (dup == NULL) { 06482 xmlVErrMemory(ctxt, "IDREFS split"); 06483 ctxt->valid = 0; 06484 return; 06485 } 06486 cur = dup; 06487 while (*cur != 0) { 06488 str = cur; 06489 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 06490 save = *cur; 06491 *cur = 0; 06492 id = xmlGetID(ctxt->doc, str); 06493 if (id == NULL) { 06494 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 06495 "IDREFS attribute %s references an unknown ID \"%s\"\n", 06496 attr->name, str, NULL); 06497 ctxt->valid = 0; 06498 } 06499 if (save == 0) 06500 break; 06501 *cur = save; 06502 while (IS_BLANK_CH(*cur)) cur++; 06503 } 06504 xmlFree(dup); 06505 } 06506 } 06507 06515 static int 06516 xmlWalkValidateList(const void *data, const void *user) 06517 { 06518 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user; 06519 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name); 06520 return 1; 06521 } 06522 06530 static void 06531 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt, 06532 const xmlChar *name) { 06533 xmlValidateMemo memo; 06534 06535 if (ref_list == NULL) 06536 return; 06537 memo.ctxt = ctxt; 06538 memo.name = name; 06539 06540 xmlListWalk(ref_list, xmlWalkValidateList, &memo); 06541 06542 } 06543 06559 int 06560 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 06561 xmlRefTablePtr table; 06562 06563 if (ctxt == NULL) 06564 return(0); 06565 if (doc == NULL) { 06566 xmlErrValid(ctxt, XML_DTD_NO_DOC, 06567 "xmlValidateDocumentFinal: doc == NULL\n", NULL); 06568 return(0); 06569 } 06570 06571 /* 06572 * Check all the NOTATION/NOTATIONS attributes 06573 */ 06574 /* 06575 * Check all the ENTITY/ENTITIES attributes definition for validity 06576 */ 06577 /* 06578 * Check all the IDREF/IDREFS attributes definition for validity 06579 */ 06580 table = (xmlRefTablePtr) doc->refs; 06581 ctxt->doc = doc; 06582 ctxt->valid = 1; 06583 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt); 06584 return(ctxt->valid); 06585 } 06586 06603 int 06604 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { 06605 int ret; 06606 xmlDtdPtr oldExt, oldInt; 06607 xmlNodePtr root; 06608 06609 if (dtd == NULL) return(0); 06610 if (doc == NULL) return(0); 06611 oldExt = doc->extSubset; 06612 oldInt = doc->intSubset; 06613 doc->extSubset = dtd; 06614 doc->intSubset = NULL; 06615 ret = xmlValidateRoot(ctxt, doc); 06616 if (ret == 0) { 06617 doc->extSubset = oldExt; 06618 doc->intSubset = oldInt; 06619 return(ret); 06620 } 06621 if (doc->ids != NULL) { 06622 xmlFreeIDTable(doc->ids); 06623 doc->ids = NULL; 06624 } 06625 if (doc->refs != NULL) { 06626 xmlFreeRefTable(doc->refs); 06627 doc->refs = NULL; 06628 } 06629 root = xmlDocGetRootElement(doc); 06630 ret = xmlValidateElement(ctxt, doc, root); 06631 ret &= xmlValidateDocumentFinal(ctxt, doc); 06632 doc->extSubset = oldExt; 06633 doc->intSubset = oldInt; 06634 return(ret); 06635 } 06636 06637 static void 06638 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt, 06639 const xmlChar *name ATTRIBUTE_UNUSED) { 06640 if (cur == NULL) 06641 return; 06642 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 06643 xmlChar *notation = cur->content; 06644 06645 if (notation != NULL) { 06646 int ret; 06647 06648 ret = xmlValidateNotationUse(ctxt, cur->doc, notation); 06649 if (ret != 1) { 06650 ctxt->valid = 0; 06651 } 06652 } 06653 } 06654 } 06655 06656 static void 06657 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt, 06658 const xmlChar *name ATTRIBUTE_UNUSED) { 06659 int ret; 06660 xmlDocPtr doc; 06661 xmlElementPtr elem = NULL; 06662 06663 if (cur == NULL) 06664 return; 06665 switch (cur->atype) { 06666 case XML_ATTRIBUTE_CDATA: 06667 case XML_ATTRIBUTE_ID: 06668 case XML_ATTRIBUTE_IDREF : 06669 case XML_ATTRIBUTE_IDREFS: 06670 case XML_ATTRIBUTE_NMTOKEN: 06671 case XML_ATTRIBUTE_NMTOKENS: 06672 case XML_ATTRIBUTE_ENUMERATION: 06673 break; 06674 case XML_ATTRIBUTE_ENTITY: 06675 case XML_ATTRIBUTE_ENTITIES: 06676 case XML_ATTRIBUTE_NOTATION: 06677 if (cur->defaultValue != NULL) { 06678 06679 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, 06680 cur->atype, cur->defaultValue); 06681 if ((ret == 0) && (ctxt->valid == 1)) 06682 ctxt->valid = 0; 06683 } 06684 if (cur->tree != NULL) { 06685 xmlEnumerationPtr tree = cur->tree; 06686 while (tree != NULL) { 06687 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, 06688 cur->name, cur->atype, tree->name); 06689 if ((ret == 0) && (ctxt->valid == 1)) 06690 ctxt->valid = 0; 06691 tree = tree->next; 06692 } 06693 } 06694 } 06695 if (cur->atype == XML_ATTRIBUTE_NOTATION) { 06696 doc = cur->doc; 06697 if (cur->elem == NULL) { 06698 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 06699 "xmlValidateAttributeCallback(%s): internal error\n", 06700 (const char *) cur->name); 06701 return; 06702 } 06703 06704 if (doc != NULL) 06705 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); 06706 if ((elem == NULL) && (doc != NULL)) 06707 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); 06708 if ((elem == NULL) && (cur->parent != NULL) && 06709 (cur->parent->type == XML_DTD_NODE)) 06710 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); 06711 if (elem == NULL) { 06712 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, 06713 "attribute %s: could not find decl for element %s\n", 06714 cur->name, cur->elem, NULL); 06715 return; 06716 } 06717 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) { 06718 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION, 06719 "NOTATION attribute %s declared for EMPTY element %s\n", 06720 cur->name, cur->elem, NULL); 06721 ctxt->valid = 0; 06722 } 06723 } 06724 } 06725 06743 int 06744 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 06745 xmlDtdPtr dtd; 06746 xmlAttributeTablePtr table; 06747 xmlEntitiesTablePtr entities; 06748 06749 if ((doc == NULL) || (ctxt == NULL)) return(0); 06750 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) 06751 return(0); 06752 ctxt->doc = doc; 06753 ctxt->valid = 1; 06754 dtd = doc->intSubset; 06755 if ((dtd != NULL) && (dtd->attributes != NULL)) { 06756 table = (xmlAttributeTablePtr) dtd->attributes; 06757 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); 06758 } 06759 if ((dtd != NULL) && (dtd->entities != NULL)) { 06760 entities = (xmlEntitiesTablePtr) dtd->entities; 06761 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, 06762 ctxt); 06763 } 06764 dtd = doc->extSubset; 06765 if ((dtd != NULL) && (dtd->attributes != NULL)) { 06766 table = (xmlAttributeTablePtr) dtd->attributes; 06767 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); 06768 } 06769 if ((dtd != NULL) && (dtd->entities != NULL)) { 06770 entities = (xmlEntitiesTablePtr) dtd->entities; 06771 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, 06772 ctxt); 06773 } 06774 return(ctxt->valid); 06775 } 06776 06791 int 06792 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 06793 int ret; 06794 xmlNodePtr root; 06795 06796 if (doc == NULL) 06797 return(0); 06798 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { 06799 xmlErrValid(ctxt, XML_DTD_NO_DTD, 06800 "no DTD found!\n", NULL); 06801 return(0); 06802 } 06803 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) || 06804 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) { 06805 xmlChar *sysID; 06806 if (doc->intSubset->SystemID != NULL) { 06807 sysID = xmlBuildURI(doc->intSubset->SystemID, 06808 doc->URL); 06809 if (sysID == NULL) { 06810 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 06811 "Could not build URI for external subset \"%s\"\n", 06812 (const char *) doc->intSubset->SystemID); 06813 return 0; 06814 } 06815 } else 06816 sysID = NULL; 06817 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, 06818 (const xmlChar *)sysID); 06819 if (sysID != NULL) 06820 xmlFree(sysID); 06821 if (doc->extSubset == NULL) { 06822 if (doc->intSubset->SystemID != NULL) { 06823 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 06824 "Could not load the external subset \"%s\"\n", 06825 (const char *) doc->intSubset->SystemID); 06826 } else { 06827 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 06828 "Could not load the external subset \"%s\"\n", 06829 (const char *) doc->intSubset->ExternalID); 06830 } 06831 return(0); 06832 } 06833 } 06834 06835 if (doc->ids != NULL) { 06836 xmlFreeIDTable(doc->ids); 06837 doc->ids = NULL; 06838 } 06839 if (doc->refs != NULL) { 06840 xmlFreeRefTable(doc->refs); 06841 doc->refs = NULL; 06842 } 06843 ret = xmlValidateDtdFinal(ctxt, doc); 06844 if (!xmlValidateRoot(ctxt, doc)) return(0); 06845 06846 root = xmlDocGetRootElement(doc); 06847 ret &= xmlValidateElement(ctxt, doc, root); 06848 ret &= xmlValidateDocumentFinal(ctxt, doc); 06849 return(ret); 06850 } 06851 06852 /************************************************************************ 06853 * * 06854 * Routines for dynamic validation editing * 06855 * * 06856 ************************************************************************/ 06857 06870 int 06871 xmlValidGetPotentialChildren(xmlElementContent *ctree, 06872 const xmlChar **names, 06873 int *len, int max) { 06874 int i; 06875 06876 if ((ctree == NULL) || (names == NULL) || (len == NULL)) 06877 return(-1); 06878 if (*len >= max) return(*len); 06879 06880 switch (ctree->type) { 06881 case XML_ELEMENT_CONTENT_PCDATA: 06882 for (i = 0; i < *len;i++) 06883 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len); 06884 names[(*len)++] = BAD_CAST "#PCDATA"; 06885 break; 06886 case XML_ELEMENT_CONTENT_ELEMENT: 06887 for (i = 0; i < *len;i++) 06888 if (xmlStrEqual(ctree->name, names[i])) return(*len); 06889 names[(*len)++] = ctree->name; 06890 break; 06891 case XML_ELEMENT_CONTENT_SEQ: 06892 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 06893 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 06894 break; 06895 case XML_ELEMENT_CONTENT_OR: 06896 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 06897 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 06898 break; 06899 } 06900 06901 return(*len); 06902 } 06903 06904 /* 06905 * Dummy function to suppress messages while we try out valid elements 06906 */ 06907 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, 06908 const char *msg ATTRIBUTE_UNUSED, ...) { 06909 return; 06910 } 06911 06937 int 06938 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, 06939 int max) { 06940 xmlValidCtxt vctxt; 06941 int nb_valid_elements = 0; 06942 const xmlChar *elements[256]; 06943 int nb_elements = 0, i; 06944 const xmlChar *name; 06945 06946 xmlNode *ref_node; 06947 xmlNode *parent; 06948 xmlNode *test_node; 06949 06950 xmlNode *prev_next; 06951 xmlNode *next_prev; 06952 xmlNode *parent_childs; 06953 xmlNode *parent_last; 06954 06955 xmlElement *element_desc; 06956 06957 if (prev == NULL && next == NULL) 06958 return(-1); 06959 06960 if (names == NULL) return(-1); 06961 if (max <= 0) return(-1); 06962 06963 memset(&vctxt, 0, sizeof (xmlValidCtxt)); 06964 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */ 06965 06966 nb_valid_elements = 0; 06967 ref_node = prev ? prev : next; 06968 parent = ref_node->parent; 06969 06970 /* 06971 * Retrieves the parent element declaration 06972 */ 06973 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset, 06974 parent->name); 06975 if ((element_desc == NULL) && (parent->doc->extSubset != NULL)) 06976 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset, 06977 parent->name); 06978 if (element_desc == NULL) return(-1); 06979 06980 /* 06981 * Do a backup of the current tree structure 06982 */ 06983 prev_next = prev ? prev->next : NULL; 06984 next_prev = next ? next->prev : NULL; 06985 parent_childs = parent->children; 06986 parent_last = parent->last; 06987 06988 /* 06989 * Creates a dummy node and insert it into the tree 06990 */ 06991 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL); 06992 test_node->parent = parent; 06993 test_node->prev = prev; 06994 test_node->next = next; 06995 name = test_node->name; 06996 06997 if (prev) prev->next = test_node; 06998 else parent->children = test_node; 06999 07000 if (next) next->prev = test_node; 07001 else parent->last = test_node; 07002 07003 /* 07004 * Insert each potential child node and check if the parent is 07005 * still valid 07006 */ 07007 nb_elements = xmlValidGetPotentialChildren(element_desc->content, 07008 elements, &nb_elements, 256); 07009 07010 for (i = 0;i < nb_elements;i++) { 07011 test_node->name = elements[i]; 07012 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) { 07013 int j; 07014 07015 for (j = 0; j < nb_valid_elements;j++) 07016 if (xmlStrEqual(elements[i], names[j])) break; 07017 names[nb_valid_elements++] = elements[i]; 07018 if (nb_valid_elements >= max) break; 07019 } 07020 } 07021 07022 /* 07023 * Restore the tree structure 07024 */ 07025 if (prev) prev->next = prev_next; 07026 if (next) next->prev = next_prev; 07027 parent->children = parent_childs; 07028 parent->last = parent_last; 07029 07030 /* 07031 * Free up the dummy node 07032 */ 07033 test_node->name = name; 07034 xmlFreeNode(test_node); 07035 07036 return(nb_valid_elements); 07037 } 07038 #endif /* LIBXML_VALID_ENABLED */ 07039 07040 #define bottom_valid 07041 #include "elfgcchack.h" Generated on Sun May 27 2012 04:34:45 for ReactOS by
1.7.6.1
|