📄 xpointer.c
字号:
/*
* xpointer.c : Code to handle XML Pointer
*
* Base implementation was made accordingly to
* W3C Candidate Recommendation 7 June 2000
* http://www.w3.org/TR/2000/CR-xptr-20000607
*
* Added support for the element() scheme described in:
* W3C Proposed Recommendation 13 November 2002
* http://www.w3.org/TR/2002/PR-xptr-element-20021113/
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#define IN_LIBXML
#include "libxml.h"
/*
* TODO: better handling of error cases, the full expression should
* be parsed beforehand instead of a progressive evaluation
* TODO: Access into entities references are not supported now ...
* need a start to be able to pop out of entities refs since
* parent is the endity declaration, not the ref.
*/
#include <string.h>
#include <libxml/xpointer.h>
#include <libxml/xmlmemory.h>
#include <libxml/parserInternals.h>
#include <libxml/uri.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/xmlerror.h>
#include <libxml/globals.h>
#ifdef LIBXML_XPTR_ENABLED
/* Add support of the xmlns() xpointer scheme to initialize the namespaces */
#define XPTR_XMLNS_SCHEME
/* #define DEBUG_RANGES */
#ifdef DEBUG_RANGES
#ifdef LIBXML_DEBUG_ENABLED
#include <libxml/debugXML.h>
#endif
#endif
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define STRANGE \
xmlGenericError(xmlGenericErrorContext, \
"Internal error at %s:%d\n", \
__FILE__, __LINE__);
/************************************************************************
* *
* Some factorized error routines *
* *
************************************************************************/
/**
* xmlXPtrErrMemory:
* @extra: extra informations
*
* Handle a redefinition of attribute error
*/
static void
xmlXPtrErrMemory(const char *extra)
{
__xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
NULL, NULL, 0, 0,
"Memory allocation failed : %s\n", extra);
}
/**
* xmlXPtrErr:
* @ctxt: an XPTR evaluation context
* @extra: extra informations
*
* Handle a redefinition of attribute error
*/
static void
xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
const char * msg, const xmlChar *extra)
{
if (ctxt != NULL)
ctxt->error = error;
if ((ctxt == NULL) || (ctxt->context == NULL)) {
__xmlRaiseError(NULL, NULL, NULL,
NULL, NULL, XML_FROM_XPOINTER, error,
XML_ERR_ERROR, NULL, 0,
(const char *) extra, NULL, NULL, 0, 0,
msg, extra);
return;
}
ctxt->context->lastError.domain = XML_FROM_XPOINTER;
ctxt->context->lastError.code = error;
ctxt->context->lastError.level = XML_ERR_ERROR;
ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
ctxt->context->lastError.node = ctxt->context->debugNode;
if (ctxt->context->error != NULL) {
ctxt->context->error(ctxt->context->userData,
&ctxt->context->lastError);
} else {
__xmlRaiseError(NULL, NULL, NULL,
NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
error, XML_ERR_ERROR, NULL, 0,
(const char *) extra, (const char *) ctxt->base, NULL,
ctxt->cur - ctxt->base, 0,
msg, extra);
}
}
/************************************************************************
* *
* A few helper functions for child sequences *
* *
************************************************************************/
/* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
/**
* xmlXPtrGetArity:
* @cur: the node
*
* Returns the number of child for an element, -1 in case of error
*/
static int
xmlXPtrGetArity(xmlNodePtr cur) {
int i;
if (cur == NULL)
return(-1);
cur = cur->children;
for (i = 0;cur != NULL;cur = cur->next) {
if ((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
i++;
}
}
return(i);
}
/**
* xmlXPtrGetIndex:
* @cur: the node
*
* Returns the index of the node in its parent children list, -1
* in case of error
*/
static int
xmlXPtrGetIndex(xmlNodePtr cur) {
int i;
if (cur == NULL)
return(-1);
for (i = 1;cur != NULL;cur = cur->prev) {
if ((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
i++;
}
}
return(i);
}
/**
* xmlXPtrGetNthChild:
* @cur: the node
* @no: the child number
*
* Returns the @no'th element child of @cur or NULL
*/
static xmlNodePtr
xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
int i;
if (cur == NULL)
return(cur);
cur = cur->children;
for (i = 0;i <= no;cur = cur->next) {
if (cur == NULL)
return(cur);
if ((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
i++;
if (i == no)
break;
}
}
return(cur);
}
/************************************************************************
* *
* Handling of XPointer specific types *
* *
************************************************************************/
/**
* xmlXPtrCmpPoints:
* @node1: the first node
* @index1: the first index
* @node2: the second node
* @index2: the second index
*
* Compare two points w.r.t document order
*
* Returns -2 in case of error 1 if first point < second point, 0 if
* that's the same point, -1 otherwise
*/
static int
xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
if ((node1 == NULL) || (node2 == NULL))
return(-2);
/*
* a couple of optimizations which will avoid computations in most cases
*/
if (node1 == node2) {
if (index1 < index2)
return(1);
if (index1 > index2)
return(-1);
return(0);
}
return(xmlXPathCmpNodes(node1, node2));
}
/**
* xmlXPtrNewPoint:
* @node: the xmlNodePtr
* @indx: the indx within the node
*
* Create a new xmlXPathObjectPtr of type point
*
* Returns the newly created object.
*/
static xmlXPathObjectPtr
xmlXPtrNewPoint(xmlNodePtr node, int indx) {
xmlXPathObjectPtr ret;
if (node == NULL)
return(NULL);
if (indx < 0)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating point");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_POINT;
ret->user = (void *) node;
ret->index = indx;
return(ret);
}
/**
* xmlXPtrRangeCheckOrder:
* @range: an object range
*
* Make sure the points in the range are in the right order
*/
static void
xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
int tmp;
xmlNodePtr tmp2;
if (range == NULL)
return;
if (range->type != XPATH_RANGE)
return;
if (range->user2 == NULL)
return;
tmp = xmlXPtrCmpPoints(range->user, range->index,
range->user2, range->index2);
if (tmp == -1) {
tmp2 = range->user;
range->user = range->user2;
range->user2 = tmp2;
tmp = range->index;
range->index = range->index2;
range->index2 = tmp;
}
}
/**
* xmlXPtrRangesEqual:
* @range1: the first range
* @range2: the second range
*
* Compare two ranges
*
* Returns 1 if equal, 0 otherwise
*/
static int
xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
if (range1 == range2)
return(1);
if ((range1 == NULL) || (range2 == NULL))
return(0);
if (range1->type != range2->type)
return(0);
if (range1->type != XPATH_RANGE)
return(0);
if (range1->user != range2->user)
return(0);
if (range1->index != range2->index)
return(0);
if (range1->user2 != range2->user2)
return(0);
if (range1->index2 != range2->index2)
return(0);
return(1);
}
/**
* xmlXPtrNewRange:
* @start: the starting node
* @startindex: the start index
* @end: the ending point
* @endindex: the ending index
*
* Create a new xmlXPathObjectPtr of type range
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPtrNewRange(xmlNodePtr start, int startindex,
xmlNodePtr end, int endindex) {
xmlXPathObjectPtr ret;
if (start == NULL)
return(NULL);
if (end == NULL)
return(NULL);
if (startindex < 0)
return(NULL);
if (endindex < 0)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating range");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_RANGE;
ret->user = start;
ret->index = startindex;
ret->user2 = end;
ret->index2 = endindex;
xmlXPtrRangeCheckOrder(ret);
return(ret);
}
/**
* xmlXPtrNewRangePoints:
* @start: the starting point
* @end: the ending point
*
* Create a new xmlXPathObjectPtr of type range using 2 Points
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
xmlXPathObjectPtr ret;
if (start == NULL)
return(NULL);
if (end == NULL)
return(NULL);
if (start->type != XPATH_POINT)
return(NULL);
if (end->type != XPATH_POINT)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating range");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_RANGE;
ret->user = start->user;
ret->index = start->index;
ret->user2 = end->user;
ret->index2 = end->index;
xmlXPtrRangeCheckOrder(ret);
return(ret);
}
/**
* xmlXPtrNewRangePointNode:
* @start: the starting point
* @end: the ending node
*
* Create a new xmlXPathObjectPtr of type range from a point to a node
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
xmlXPathObjectPtr ret;
if (start == NULL)
return(NULL);
if (end == NULL)
return(NULL);
if (start->type != XPATH_POINT)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating range");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_RANGE;
ret->user = start->user;
ret->index = start->index;
ret->user2 = end;
ret->index2 = -1;
xmlXPtrRangeCheckOrder(ret);
return(ret);
}
/**
* xmlXPtrNewRangeNodePoint:
* @start: the starting node
* @end: the ending point
*
* Create a new xmlXPathObjectPtr of type range from a node to a point
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
xmlXPathObjectPtr ret;
if (start == NULL)
return(NULL);
if (end == NULL)
return(NULL);
if (start->type != XPATH_POINT)
return(NULL);
if (end->type != XPATH_POINT)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating range");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_RANGE;
ret->user = start;
ret->index = -1;
ret->user2 = end->user;
ret->index2 = end->index;
xmlXPtrRangeCheckOrder(ret);
return(ret);
}
/**
* xmlXPtrNewRangeNodes:
* @start: the starting node
* @end: the ending node
*
* Create a new xmlXPathObjectPtr of type range using 2 nodes
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
xmlXPathObjectPtr ret;
if (start == NULL)
return(NULL);
if (end == NULL)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPtrErrMemory("allocating range");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -