📄 valid.c.svn-base
字号:
/* * valid.c : part of the code use to do the DTD handling and the validity * checking * * See Copyright for the status of this software. * * daniel@veillard.com */#define IN_LIBXML#include "libxml.h"#include <string.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#include <libxml/xmlmemory.h>#include <libxml/hash.h>#include <libxml/valid.h>#include <libxml/parser.h>#include <libxml/parserInternals.h>#include <libxml/xmlerror.h>#include <libxml/list.h>#include <libxml/globals.h>static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create);/* #define DEBUG_VALID_ALGO *//* #define DEBUG_REGEXP_ALGO */#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);/************************************************************************ * * * Error handling routines * * * ************************************************************************//** * xmlVErrMemory: * @ctxt: an XML validation parser context * @extra: extra informations * * Handle an out of memory error */static voidxmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra){ xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL; if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; pctxt = ctxt->userData; } if (extra) __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, "Memory allocation failed : %s\n", extra); else __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "Memory allocation failed\n");}/** * xmlErrValid: * @ctxt: an XML validation parser context * @error: the error number * @extra: extra informations * * Handle a validation error */static voidxmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, const char *msg, const char *extra){ xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL; if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; pctxt = ctxt->userData; } if (extra) __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, msg, extra); else __xmlRaiseError(NULL, channel, data, pctxt, NULL, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, msg);}#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)/** * xmlErrValidNode: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra informations * @str2: extra informations * @str3: extra informations * * Handle a validation error, provide contextual informations */static voidxmlErrValidNode(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL; if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; pctxt = ctxt->userData; } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str1, (const char *) str3, 0, 0, msg, str1, str2, str3);}#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */#ifdef LIBXML_VALID_ENABLED/** * xmlErrValidNodeNr: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra informations * @int2: extra informations * @str3: extra informations * * Handle a validation error, provide contextual informations */static voidxmlErrValidNodeNr(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, int int2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL; if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; pctxt = ctxt->userData; } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_ERROR, NULL, 0, (const char *) str1, (const char *) str3, NULL, int2, 0, msg, str1, int2, str3);}/** * xmlErrValidWarning: * @ctxt: an XML validation parser context * @node: the node raising the error * @error: the error number * @str1: extra information * @str2: extra information * @str3: extra information * * Handle a validation error, provide contextual information */static voidxmlErrValidWarning(xmlValidCtxtPtr ctxt, xmlNodePtr node, xmlParserErrors error, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3){ xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; xmlParserCtxtPtr pctxt = NULL; void *data = NULL; if (ctxt != NULL) { channel = ctxt->error; data = ctxt->userData; pctxt = ctxt->userData; } __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, XML_ERR_WARNING, NULL, 0, (const char *) str1, (const char *) str1, (const char *) str3, 0, 0, msg, str1, str2, str3);}#ifdef LIBXML_REGEXP_ENABLED/* * If regexp are enabled we can do continuous validation without the * need of a tree to validate the content model. this is done in each * callbacks. * Each xmlValidState represent the validation state associated to the * set of nodes currently open from the document root to the current element. */typedef struct _xmlValidState { xmlElementPtr elemDecl; /* pointer to the content model */ xmlNodePtr node; /* pointer to the current node */ xmlRegExecCtxtPtr exec; /* regexp runtime */} _xmlValidState;static intvstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) { ctxt->vstateMax = 10; ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } } if (ctxt->vstateNr >= ctxt->vstateMax) { xmlValidState *tmp; tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "realloc failed"); return(-1); } ctxt->vstateMax *= 2; ctxt->vstateTab = tmp; } ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr]; ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl; ctxt->vstateTab[ctxt->vstateNr].node = node; if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { if (elemDecl->contModel == NULL) xmlValidBuildContentModel(ctxt, elemDecl); if (elemDecl->contModel != NULL) { ctxt->vstateTab[ctxt->vstateNr].exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); } else { ctxt->vstateTab[ctxt->vstateNr].exec = NULL; xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, XML_ERR_INTERNAL_ERROR, "Failed to build content model regexp for %s\n", node->name, NULL, NULL); } } return(ctxt->vstateNr++);}static intvstateVPop(xmlValidCtxtPtr ctxt) { xmlElementPtr elemDecl; if (ctxt->vstateNr < 1) return(-1); ctxt->vstateNr--; elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl; ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL; ctxt->vstateTab[ctxt->vstateNr].node = NULL; if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec); } ctxt->vstateTab[ctxt->vstateNr].exec = NULL; if (ctxt->vstateNr >= 1) ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1]; else ctxt->vstate = NULL; return(ctxt->vstateNr);}#else /* not LIBXML_REGEXP_ENABLED *//* * If regexp are not enabled, it uses a home made algorithm less * complex and easier to * debug/maintain than a generic NFA -> DFA state based algo. The * only restriction is on the deepness of the tree limited by the * size of the occurs bitfield * * this is the content of a saved state for rollbacks */#define ROLLBACK_OR 0#define ROLLBACK_PARENT 1typedef struct _xmlValidState { xmlElementContentPtr cont; /* pointer to the content model subtree */ xmlNodePtr node; /* pointer to the current node in the list */ long occurs;/* bitfield for multiple occurrences */ unsigned char depth; /* current depth in the overall tree */ unsigned char state; /* ROLLBACK_XXX */} _xmlValidState;#define MAX_RECURSE 25000#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)#define CONT ctxt->vstate->cont#define NODE ctxt->vstate->node#define DEPTH ctxt->vstate->depth#define OCCURS ctxt->vstate->occurs#define STATE ctxt->vstate->state#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)static intvstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, xmlNodePtr node, unsigned char depth, long occurs, unsigned char state) { int i = ctxt->vstateNr - 1; if (ctxt->vstateNr > MAX_RECURSE) { return(-1); } if (ctxt->vstateTab == NULL) { ctxt->vstateMax = 8; ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } } if (ctxt->vstateNr >= ctxt->vstateMax) { xmlValidState *tmp; tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "malloc failed"); return(-1); } ctxt->vstateMax *= 2; ctxt->vstateTab = tmp; ctxt->vstate = &ctxt->vstateTab[0]; } /* * Don't push on the stack a state already here */ if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) && (ctxt->vstateTab[i].node == node) && (ctxt->vstateTab[i].depth == depth) && (ctxt->vstateTab[i].occurs == occurs) && (ctxt->vstateTab[i].state == state)) return(ctxt->vstateNr); ctxt->vstateTab[ctxt->vstateNr].cont = cont; ctxt->vstateTab[ctxt->vstateNr].node = node; ctxt->vstateTab[ctxt->vstateNr].depth = depth; ctxt->vstateTab[ctxt->vstateNr].occurs = occurs; ctxt->vstateTab[ctxt->vstateNr].state = state; return(ctxt->vstateNr++);}static intvstateVPop(xmlValidCtxtPtr ctxt) { if (ctxt->vstateNr <= 1) return(-1); ctxt->vstateNr--; ctxt->vstate = &ctxt->vstateTab[0]; ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont; ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node; ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth; ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs; ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state; return(ctxt->vstateNr);}#endif /* LIBXML_REGEXP_ENABLED */static intnodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value){ if (ctxt->nodeMax <= 0) { ctxt->nodeMax = 4; ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); if (ctxt->nodeTab == NULL) { xmlVErrMemory(ctxt, "malloc failed"); ctxt->nodeMax = 0; return (0); } } if (ctxt->nodeNr >= ctxt->nodeMax) { xmlNodePtr *tmp; tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { xmlVErrMemory(ctxt, "realloc failed"); return (0); } ctxt->nodeMax *= 2; ctxt->nodeTab = tmp; } ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++);}static xmlNodePtrnodeVPop(xmlValidCtxtPtr ctxt){ xmlNodePtr ret; if (ctxt->nodeNr <= 0) return (0); ctxt->nodeNr--; if (ctxt->nodeNr > 0) ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; else ctxt->node = NULL; ret = ctxt->nodeTab[ctxt->nodeNr]; ctxt->nodeTab[ctxt->nodeNr] = 0; return (ret);}#ifdef DEBUG_VALID_ALGOstatic voidxmlValidPrintNode(xmlNodePtr cur) { if (cur == NULL) { xmlGenericError(xmlGenericErrorContext, "null"); return; } switch (cur->type) { case XML_ELEMENT_NODE: xmlGenericError(xmlGenericErrorContext, "%s ", cur->name); break; case XML_TEXT_NODE: xmlGenericError(xmlGenericErrorContext, "text "); break; case XML_CDATA_SECTION_NODE: xmlGenericError(xmlGenericErrorContext, "cdata "); break; case XML_ENTITY_REF_NODE: xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name); break; case XML_PI_NODE: xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name); break; case XML_COMMENT_NODE: xmlGenericError(xmlGenericErrorContext, "comment "); break; case XML_ATTRIBUTE_NODE: xmlGenericError(xmlGenericErrorContext, "?attr? "); break; case XML_ENTITY_NODE: xmlGenericError(xmlGenericErrorContext, "?ent? "); break; case XML_DOCUMENT_NODE: xmlGenericError(xmlGenericErrorContext, "?doc? "); break; case XML_DOCUMENT_TYPE_NODE: xmlGenericError(xmlGenericErrorContext, "?doctype? ");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -