📄 valid.c
字号:
/*
* 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/uri.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 void
xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
{
xmlGenericErrorFunc channel = NULL;
xmlParserCtxtPtr pctxt = NULL;
void *data = NULL;
if (ctxt != NULL) {
channel = ctxt->error;
data = ctxt->userData;
/* Use the special values to detect if it is part of a parsing
context */
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
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 void
xmlErrValid(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;
/* Use the special values to detect if it is part of a parsing
context */
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
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 void
xmlErrValidNode(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;
/* Use the special values to detect if it is part of a parsing
context */
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
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 void
xmlErrValidNodeNr(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;
/* Use the special values to detect if it is part of a parsing
context */
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
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 void
xmlErrValidWarning(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->warning;
data = ctxt->userData;
/* Use the special values to detect if it is part of a parsing
context */
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
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 int
vstateVPush(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 int
vstateVPop(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 1
typedef 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 int
vstateVPush(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 int
vstateVPop(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 int
nodeVPush(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 xmlNodePtr
nodeVPop(xmlValidCtxtPtr ctxt)
{
xmlNodePtr ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -