📄 relaxng.c
字号:
}
ret->nbAttrLeft = ret->nbAttrs;
return (ret);
}
/**
* xmlRelaxNGCopyValidState:
* @ctxt: a Relax-NG validation context
* @state: a validation state
*
* Copy the validation state
*
* Returns the newly allocated structure or NULL in case or error
*/
static xmlRelaxNGValidStatePtr
xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGValidStatePtr state)
{
xmlRelaxNGValidStatePtr ret;
unsigned int maxAttrs;
xmlAttrPtr *attrs;
if (state == NULL)
return (NULL);
if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
ctxt->freeState->nbState--;
ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
} else {
ret =
(xmlRelaxNGValidStatePtr)
xmlMalloc(sizeof(xmlRelaxNGValidState));
if (ret == NULL) {
xmlRngVErrMemory(ctxt, "allocating states\n");
return (NULL);
}
memset(ret, 0, sizeof(xmlRelaxNGValidState));
}
attrs = ret->attrs;
maxAttrs = ret->maxAttrs;
memcpy(ret, state, sizeof(xmlRelaxNGValidState));
ret->attrs = attrs;
ret->maxAttrs = maxAttrs;
if (state->nbAttrs > 0) {
if (ret->attrs == NULL) {
ret->maxAttrs = state->maxAttrs;
ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
sizeof(xmlAttrPtr));
if (ret->attrs == NULL) {
xmlRngVErrMemory(ctxt, "allocating states\n");
ret->nbAttrs = 0;
return (ret);
}
} else if (ret->maxAttrs < state->nbAttrs) {
xmlAttrPtr *tmp;
tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
sizeof(xmlAttrPtr));
if (tmp == NULL) {
xmlRngVErrMemory(ctxt, "allocating states\n");
ret->nbAttrs = 0;
return (ret);
}
ret->maxAttrs = state->maxAttrs;
ret->attrs = tmp;
}
memcpy(ret->attrs, state->attrs,
state->nbAttrs * sizeof(xmlAttrPtr));
}
return (ret);
}
/**
* xmlRelaxNGEqualValidState:
* @ctxt: a Relax-NG validation context
* @state1: a validation state
* @state2: a validation state
*
* Compare the validation states for equality
*
* Returns 1 if equald, 0 otherwise
*/
static int
xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
xmlRelaxNGValidStatePtr state1,
xmlRelaxNGValidStatePtr state2)
{
int i;
if ((state1 == NULL) || (state2 == NULL))
return (0);
if (state1 == state2)
return (1);
if (state1->node != state2->node)
return (0);
if (state1->seq != state2->seq)
return (0);
if (state1->nbAttrLeft != state2->nbAttrLeft)
return (0);
if (state1->nbAttrs != state2->nbAttrs)
return (0);
if (state1->endvalue != state2->endvalue)
return (0);
if ((state1->value != state2->value) &&
(!xmlStrEqual(state1->value, state2->value)))
return (0);
for (i = 0; i < state1->nbAttrs; i++) {
if (state1->attrs[i] != state2->attrs[i])
return (0);
}
return (1);
}
/**
* xmlRelaxNGFreeValidState:
* @state: a validation state structure
*
* Deallocate a RelaxNG validation state structure.
*/
static void
xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGValidStatePtr state)
{
if (state == NULL)
return;
if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
}
if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
if (state->attrs != NULL)
xmlFree(state->attrs);
xmlFree(state);
} else {
xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
}
}
/************************************************************************
* *
* Semi internal functions *
* *
************************************************************************/
/**
* xmlRelaxParserSetFlag:
* @ctxt: a RelaxNG parser context
* @flags: a set of flags values
*
* Semi private function used to pass informations to a parser context
* which are a combination of xmlRelaxNGParserFlag .
*
* Returns 0 if success and -1 in case of error
*/
int
xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
{
if (ctxt == NULL) return(-1);
if (flags & XML_RELAXNGP_FREE_DOC) {
ctxt->crng |= XML_RELAXNGP_FREE_DOC;
flags -= XML_RELAXNGP_FREE_DOC;
}
if (flags & XML_RELAXNGP_CRNG) {
ctxt->crng |= XML_RELAXNGP_CRNG;
flags -= XML_RELAXNGP_CRNG;
}
if (flags != 0) return(-1);
return(0);
}
/************************************************************************
* *
* Document functions *
* *
************************************************************************/
static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
xmlDocPtr doc);
/**
* xmlRelaxNGIncludePush:
* @ctxt: the parser context
* @value: the element doc
*
* Pushes a new include on top of the include stack
*
* Returns 0 in case of error, the index in the stack otherwise
*/
static int
xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
xmlRelaxNGIncludePtr value)
{
if (ctxt->incTab == NULL) {
ctxt->incMax = 4;
ctxt->incNr = 0;
ctxt->incTab =
(xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
sizeof(ctxt->incTab[0]));
if (ctxt->incTab == NULL) {
xmlRngPErrMemory(ctxt, "allocating include\n");
return (0);
}
}
if (ctxt->incNr >= ctxt->incMax) {
ctxt->incMax *= 2;
ctxt->incTab =
(xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
ctxt->incMax *
sizeof(ctxt->incTab[0]));
if (ctxt->incTab == NULL) {
xmlRngPErrMemory(ctxt, "allocating include\n");
return (0);
}
}
ctxt->incTab[ctxt->incNr] = value;
ctxt->inc = value;
return (ctxt->incNr++);
}
/**
* xmlRelaxNGIncludePop:
* @ctxt: the parser context
*
* Pops the top include from the include stack
*
* Returns the include just removed
*/
static xmlRelaxNGIncludePtr
xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
{
xmlRelaxNGIncludePtr ret;
if (ctxt->incNr <= 0)
return (0);
ctxt->incNr--;
if (ctxt->incNr > 0)
ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
else
ctxt->inc = NULL;
ret = ctxt->incTab[ctxt->incNr];
ctxt->incTab[ctxt->incNr] = 0;
return (ret);
}
/**
* xmlRelaxNGRemoveRedefine:
* @ctxt: the parser context
* @URL: the normalized URL
* @target: the included target
* @name: the define name to eliminate
*
* Applies the elimination algorithm of 4.7
*
* Returns 0 in case of error, 1 in case of success.
*/
static int
xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
const xmlChar * URL ATTRIBUTE_UNUSED,
xmlNodePtr target, const xmlChar * name)
{
int found = 0;
xmlNodePtr tmp, tmp2;
xmlChar *name2;
#ifdef DEBUG_INCLUDE
if (name == NULL)
xmlGenericError(xmlGenericErrorContext,
"Elimination of <include> start from %s\n", URL);
else
xmlGenericError(xmlGenericErrorContext,
"Elimination of <include> define %s from %s\n",
name, URL);
#endif
tmp = target;
while (tmp != NULL) {
tmp2 = tmp->next;
if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
found = 1;
xmlUnlinkNode(tmp);
xmlFreeNode(tmp);
} else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
name2 = xmlGetProp(tmp, BAD_CAST "name");
xmlRelaxNGNormExtSpace(name2);
if (name2 != NULL) {
if (xmlStrEqual(name, name2)) {
found = 1;
xmlUnlinkNode(tmp);
xmlFreeNode(tmp);
}
xmlFree(name2);
}
} else if (IS_RELAXNG(tmp, "include")) {
xmlChar *href = NULL;
xmlRelaxNGDocumentPtr inc = tmp->psvi;
if ((inc != NULL) && (inc->doc != NULL) &&
(inc->doc->children != NULL)) {
if (xmlStrEqual
(inc->doc->children->name, BAD_CAST "grammar")) {
#ifdef DEBUG_INCLUDE
href = xmlGetProp(tmp, BAD_CAST "href");
#endif
if (xmlRelaxNGRemoveRedefine(ctxt, href,
inc->doc->children->
children, name) == 1) {
found = 1;
}
if (href != NULL)
xmlFree(href);
}
}
}
tmp = tmp2;
}
return (found);
}
/**
* xmlRelaxNGLoadInclude:
* @ctxt: the parser context
* @URL: the normalized URL
* @node: the include node.
* @ns: the namespace passed from the context.
*
* First lookup if the document is already loaded into the parser context,
* check against recursion. If not found the resource is loaded and
* the content is preprocessed before being returned back to the caller.
*
* Returns the xmlRelaxNGIncludePtr or NULL in case of error
*/
static xmlRelaxNGIncludePtr
xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
xmlNodePtr node, const xmlChar * ns)
{
xmlRelaxNGIncludePtr ret = NULL;
xmlDocPtr doc;
int i;
xmlNodePtr root, cur;
#ifdef DEBUG_INCLUDE
xmlGenericError(xmlGenericErrorContext,
"xmlRelaxNGLoadInclude(%s)\n", URL);
#endif
/*
* check against recursion in the stack
*/
for (i = 0; i < ctxt->incNr; i++) {
if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
"Detected an Include recursion for %s\n", URL,
NULL);
return (NULL);
}
}
/*
* load the document
*/
doc = xmlReadFile((const char *) URL,NULL,0);
if (doc == NULL) {
xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
"xmlRelaxNG: could not load %s\n", URL, NULL);
return (NULL);
}
#ifdef DEBUG_INCLUDE
xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
#endif
/*
* Allocate the document structures and register it first.
*/
ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
if (ret == NULL) {
xmlRngPErrMemory(ctxt, "allocating include\n");
xmlFreeDoc(doc);
return (NULL);
}
memset(ret, 0, sizeof(xmlRelaxNGInclude));
ret->doc = doc;
ret->href = xmlStrdup(URL);
ret->next = ctxt->includes;
ctxt->includes = ret;
/*
* transmit the ns if needed
*/
if (ns != NULL) {
root = xmlDocGetRootElement(doc);
if (root != NULL) {
if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
xmlSetProp(root, BAD_CAST "ns", ns);
}
}
}
/*
* push it on the stack
*/
xmlRelaxNGIncludePush(ctxt, ret);
/*
* Some preprocessing of the document content, this include recursing
* in the include stack.
*/
#ifdef DEBUG_INCLUDE
xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
#endif
doc = xmlRelaxNGCleanupDoc(ctxt, doc);
if (doc == NULL) {
ctxt->inc = NULL;
return (NULL);
}
/*
* Pop up the include from the stack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -