mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-07-29 11:41:22 +03:00
- Makefile.am valid.c list.[ch]: Gary Pennington provided a
better handling of ID/IDREF and the list modules associated - configure.in: small CFLAGS cleanup Daniel
This commit is contained in:
295
valid.c
295
valid.c
@ -26,6 +26,7 @@
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/parserInternals.h>
|
||||
#include <libxml/xmlerror.h>
|
||||
#include <libxml/list.h>
|
||||
|
||||
/*
|
||||
* Generic function for accessing stacks in the Validity Context
|
||||
@ -1685,6 +1686,12 @@ xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
|
||||
* Refs *
|
||||
* *
|
||||
************************************************************************/
|
||||
typedef struct xmlRemove_t
|
||||
{
|
||||
xmlListPtr l;
|
||||
xmlAttrPtr ap;
|
||||
} xmlRemove;
|
||||
|
||||
/**
|
||||
* xmlCreateRefTable:
|
||||
*
|
||||
@ -1700,17 +1707,51 @@ xmlCreateRefTable(void) {
|
||||
|
||||
/**
|
||||
* xmlFreeRef:
|
||||
* @ref: A ref
|
||||
* @lk: A list link
|
||||
*
|
||||
* Deallocate the memory used by an ref definition
|
||||
* Deallocate the memory used by a ref definition
|
||||
*/
|
||||
void
|
||||
xmlFreeRef(xmlRefPtr ref) {
|
||||
if (ref == NULL) return;
|
||||
if (ref->value != NULL)
|
||||
xmlFree((xmlChar *) ref->value);
|
||||
memset(ref, -1, sizeof(xmlRef));
|
||||
xmlFree(ref);
|
||||
static void
|
||||
xmlFreeRef(xmlLinkPtr lk) {
|
||||
xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
|
||||
if (ref == NULL) return;
|
||||
if (ref->value != NULL)
|
||||
xmlFree((xmlChar *)ref->value);
|
||||
memset(ref, -1, sizeof(xmlRef));
|
||||
xmlFree(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlFreeRefList:
|
||||
* @list_ref: A list of references.
|
||||
*
|
||||
* Deallocate the memory used by a list of references
|
||||
*/
|
||||
static void
|
||||
xmlFreeRefList(xmlListPtr list_ref) {
|
||||
if (list_ref == NULL) return;
|
||||
xmlListDelete(list_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlWalkRemoveRef:
|
||||
* @data: Contents of current link
|
||||
* @user: Value supplied by the user
|
||||
*
|
||||
* Return 0 to abort the walk or 1 to continue
|
||||
*/
|
||||
static int
|
||||
xmlWalkRemoveRef(const void *data, const void *user)
|
||||
{
|
||||
xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
|
||||
xmlAttrPtr attr1 = ((xmlRemove *)user)->ap;
|
||||
xmlListPtr ref_list = ((xmlRemove *)user)->l;
|
||||
|
||||
if (attr0 == attr1) { /* Matched: remove and terminate walk */
|
||||
xmlListRemoveFirst(ref_list, (void *)data);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1726,63 +1767,74 @@ xmlFreeRef(xmlRefPtr ref) {
|
||||
*/
|
||||
xmlRefPtr
|
||||
xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
|
||||
xmlAttrPtr attr) {
|
||||
xmlRefPtr ret;
|
||||
xmlRefTablePtr table;
|
||||
xmlAttrPtr attr) {
|
||||
xmlRefPtr ret;
|
||||
xmlRefTablePtr table;
|
||||
xmlListPtr ref_list;
|
||||
|
||||
if (doc == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: doc == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (value == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: value == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (attr == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: attr == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (doc == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: doc == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (value == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: value == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (attr == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRefDecl: attr == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Create the Ref table if needed.
|
||||
*/
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
doc->refs = table = xmlCreateRefTable();
|
||||
if (table == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: Table creation failed!\n");
|
||||
return(NULL);
|
||||
}
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
doc->refs = table = xmlCreateRefTable();
|
||||
if (table == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: Table creation failed!\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
|
||||
if (ret == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: out of memory\n");
|
||||
return(NULL);
|
||||
}
|
||||
ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
|
||||
if (ret == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: out of memory\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* fill the structure.
|
||||
*/
|
||||
ret->value = xmlStrdup(value);
|
||||
ret->attr = attr;
|
||||
ret->value = xmlStrdup(value);
|
||||
ret->attr = attr;
|
||||
|
||||
/*
|
||||
* !!! Should we keep track of all refs ? and use xmlHashAddEntry2 ?
|
||||
*/
|
||||
if (xmlHashAddEntry(table, value, ret) < 0) {
|
||||
/*
|
||||
* Since there is no discrimination on error returns
|
||||
* from xmlHashAddEntry, I'm presuming <0 means the
|
||||
* key already exists.
|
||||
/* To add a reference :-
|
||||
* References are maintained as a list of references,
|
||||
* Lookup the entry, if no entry create new nodelist
|
||||
* Add the owning node to the NodeList
|
||||
* Return the ref
|
||||
*/
|
||||
xmlHashUpdateEntry(table, value, ret, (xmlHashDeallocator) xmlFreeRef);
|
||||
}
|
||||
return(ret);
|
||||
|
||||
if(NULL == (ref_list = xmlHashLookup(table, value))) {
|
||||
if(NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: Reference list creation failed!\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (xmlHashAddEntry(table, value, ref_list) < 0) {
|
||||
xmlListDelete(ref_list);
|
||||
xmlGenericError(xmlGenericErrorContext,
|
||||
"xmlAddRef: Reference list insertion failed!\n");
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
xmlListInsert(ref_list, ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1793,7 +1845,7 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
|
||||
*/
|
||||
void
|
||||
xmlFreeRefTable(xmlRefTablePtr table) {
|
||||
xmlHashFree(table, (xmlHashDeallocator) xmlFreeRef);
|
||||
xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,23 +1862,23 @@ xmlFreeRefTable(xmlRefTablePtr table) {
|
||||
*/
|
||||
int
|
||||
xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
|
||||
if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
|
||||
return(0);
|
||||
} else if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
||||
/* TODO @@@ */
|
||||
return(0);
|
||||
} else {
|
||||
xmlAttributePtr attrDecl;
|
||||
if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
|
||||
return(0);
|
||||
} else if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
||||
/* TODO @@@ */
|
||||
return(0);
|
||||
} else {
|
||||
xmlAttributePtr attrDecl;
|
||||
|
||||
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
|
||||
if ((attrDecl == NULL) && (doc->extSubset != NULL))
|
||||
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
|
||||
attr->name);
|
||||
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
|
||||
if ((attrDecl == NULL) && (doc->extSubset != NULL))
|
||||
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
|
||||
attr->name);
|
||||
|
||||
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1840,59 +1892,80 @@ xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
|
||||
*/
|
||||
int
|
||||
xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
|
||||
xmlAttrPtr cur;
|
||||
xmlRefTablePtr table;
|
||||
xmlChar *ID;
|
||||
xmlListPtr ref_list;
|
||||
xmlRefTablePtr table;
|
||||
xmlChar *ID;
|
||||
xmlRemove target;
|
||||
|
||||
if (doc == NULL) return(-1);
|
||||
if (attr == NULL) return(-1);
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
return(-1);
|
||||
if (doc == NULL) return(-1);
|
||||
if (attr == NULL) return(-1);
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
return(-1);
|
||||
|
||||
if (attr == NULL)
|
||||
return(-1);
|
||||
ID = xmlNodeListGetString(doc, attr->children, 1);
|
||||
if (ID == NULL)
|
||||
return(-1);
|
||||
cur = xmlHashLookup(table, ID);
|
||||
if (cur != attr) {
|
||||
if (attr == NULL)
|
||||
return(-1);
|
||||
ID = xmlNodeListGetString(doc, attr->children, 1);
|
||||
if (ID == NULL)
|
||||
return(-1);
|
||||
ref_list = xmlHashLookup(table, ID);
|
||||
|
||||
if(ref_list == NULL) {
|
||||
xmlFree(ID);
|
||||
return (-1);
|
||||
}
|
||||
/* At this point, ref_list refers to a list of references which
|
||||
* have the same key as the supplied attr. Our list of references
|
||||
* is ordered by reference address and we don't have that information
|
||||
* here to use when removing. We'll have to walk the list and
|
||||
* check for a matching attribute, when we find one stop the walk
|
||||
* and remove the entry.
|
||||
* The list is ordered by reference, so that means we don't have the
|
||||
* key. Passing the list and the reference to the walker means we
|
||||
* will have enough data to be able to remove the entry.
|
||||
*/
|
||||
target.l = ref_list;
|
||||
target.ap = attr;
|
||||
|
||||
/* Remove the supplied attr from our list */
|
||||
xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
|
||||
|
||||
/*If the list is empty then remove the list entry in the hash */
|
||||
if (xmlListEmpty(ref_list))
|
||||
xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
|
||||
xmlFreeRefList);
|
||||
xmlFree(ID);
|
||||
return(-1);
|
||||
}
|
||||
xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeRef);
|
||||
xmlFree(ID);
|
||||
return(0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlGetRef:
|
||||
* xmlGetRefs:
|
||||
* @doc: pointer to the document
|
||||
* @Ref: the Ref value
|
||||
* @ID: the ID value
|
||||
*
|
||||
* Search the next attribute declaring the given Ref
|
||||
* Find the set of references for the supplied ID.
|
||||
*
|
||||
* Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
|
||||
* Returns NULL if not found, otherwise node set for the ID.
|
||||
*/
|
||||
xmlAttrPtr
|
||||
xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
|
||||
xmlRefTablePtr table;
|
||||
xmlListPtr
|
||||
xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
|
||||
xmlRefTablePtr table;
|
||||
|
||||
if (doc == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "xmlGetRef: doc == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (doc == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "xmlGetRef: doc == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (Ref == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "xmlGetRef: Ref == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
if (ID == NULL) {
|
||||
xmlGenericError(xmlGenericErrorContext, "xmlGetRef: ID == NULL\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
return(NULL);
|
||||
table = (xmlRefTablePtr) doc->refs;
|
||||
if (table == NULL)
|
||||
return(NULL);
|
||||
|
||||
return(xmlHashLookup(table, Ref));
|
||||
return (xmlHashLookup(table, ID));
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
Reference in New Issue
Block a user