diff options
author | Mike Hommey <glandium@debian.org> | 2005-07-12 19:58:48 +0000 |
---|---|---|
committer | Mike Hommey <glandium@debian.org> | 2005-07-12 19:58:48 +0000 |
commit | 112cb5bb5475afec1c1cbf1d6728ce4880d0fee8 (patch) | |
tree | 6c34596134f8665ebc180f29b50915dc70bbe5c1 /tree.c | |
parent | 0fc063df3ab2ad380d532d210dd1001de473e51b (diff) | |
download | libxml2-112cb5bb5475afec1c1cbf1d6728ce4880d0fee8.tar.gz |
Load /tmp/tmp.zfIyNk/libxml2-2.6.20 intoupstream/2.6.20
packages/libxml2/branches/upstream/current.
Diffstat (limited to 'tree.c')
-rw-r--r-- | tree.c | 1594 |
1 files changed, 1586 insertions, 8 deletions
@@ -333,7 +333,7 @@ xmlSplitQName3(const xmlChar *name, int *len) { #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) -#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) /** * xmlValidateNCName: * @value: the value to check @@ -1964,11 +1964,8 @@ xmlFreeProp(xmlAttrPtr cur) { xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); /* Check for ID removal -> leading to invalid references ! */ - if ((cur->parent != NULL) && (cur->parent->doc != NULL) && - ((cur->parent->doc->intSubset != NULL) || - (cur->parent->doc->extSubset != NULL))) { - if (xmlIsID(cur->parent->doc, cur->parent, cur)) - xmlRemoveID(cur->parent->doc, cur); + if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { + xmlRemoveID(cur->doc, cur); } if (cur->children != NULL) xmlFreeNodeList(cur->children); DICT_FREE(cur->name) @@ -3408,6 +3405,11 @@ xmlUnlinkNode(xmlNodePtr cur) { xmlNodePtr parent; parent = cur->parent; if (cur->type == XML_ATTRIBUTE_NODE) { + /* If attribute is an ID from subset then remove it */ + if ((((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID) && + xmlIsID(parent->doc, parent, (xmlAttrPtr) cur)) { + xmlRemoveID(cur->doc, (xmlAttrPtr) cur); + } if (parent->properties == (xmlAttrPtr) cur) parent->properties = ((xmlAttrPtr) cur)->next; } else { @@ -3469,7 +3471,7 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { return(old); } xmlUnlinkNode(cur); - cur->doc = old->doc; + xmlSetTreeDoc(cur, old->doc); cur->parent = old->parent; cur->next = old->next; if (cur->next != NULL) @@ -3481,6 +3483,12 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { if (cur->type == XML_ATTRIBUTE_NODE) { if (cur->parent->properties == (xmlAttrPtr)old) cur->parent->properties = ((xmlAttrPtr) cur); + + /* If old attribute is ID and defined in DTD then remove ID */ + if ((((xmlAttrPtr) old)->atype == XML_ATTRIBUTE_ID) && + xmlIsID(old->doc, old->parent, (xmlAttrPtr) old)) { + xmlRemoveID(old->doc, (xmlAttrPtr) old); + } } else { if (cur->parent->children == old) cur->parent->children = cur; @@ -5084,7 +5092,7 @@ xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { case XML_COMMENT_NODE: if (cur->content != NULL) { if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && - (!xmlDictOwns(cur->doc->dict, cur->content)))) + (xmlDictOwns(cur->doc->dict, cur->content)))) xmlFree(cur->content); } if (cur->children != NULL) xmlFreeNodeList(cur->children); @@ -7119,5 +7127,1575 @@ xmlSetCompressMode(int mode) { else xmlCompressMode = mode; } +/* +* xmlDOMWrapNewCtxt: +* +* Allocates and initializes a new DOM-wrapper context. +* +* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. +*/ +xmlDOMWrapCtxtPtr +xmlDOMWrapNewCtxt(void) +{ + xmlDOMWrapCtxtPtr ret; + + ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); + if (ret == NULL) { + xmlTreeErrMemory("allocating DOM-wrapper context"); + return (NULL); + } + memset(ret, 0, sizeof(xmlDOMWrapCtxt)); + return (ret); +} + +/* +* xmlDOMWrapFreeCtxt: +* @ctxt: the DOM-wrapper context +* +* Frees the DOM-wrapper context. +*/ +void +xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + xmlFree(ctxt); +} + +#define XML_TREE_NSMAP_PARENT -1 +#define XML_TREE_NSMAP_XML -2 +#define XML_TREE_NSMAP_DOC -3 +#define XML_TREE_NSMAP_CUSTOM -4 + +typedef struct xmlNsMapItem *xmlNsMapItemPtr; +struct xmlNsMapItem { + xmlNsMapItemPtr next; + xmlNsMapItemPtr prev; + xmlNsPtr oldNs; /* old ns decl reference */ + xmlNsPtr newNs; /* new ns decl reference */ + int shadowDepth; /* Shadowed at this depth */ + /* + * depth: + * >= 0 == @node's ns-decls + * -1 == @parent's ns-decls + * -2 == @parent's out-of-scope ns-decls + * -3 == the doc->oldNs XML ns-decl + * -4 == the doc->oldNs storage ns-decls + */ + int depth; +}; + +/* +* xmlTreeAddNsMapItem: +* @map: the ns-map +* @cur: the current map entry to append a new entry to +* @oldNs: the old ns-struct +* @newNs: the new ns-struct +* @depth: depth and ns-kind information +* +* Frees the ns-map +*/ +static xmlNsMapItemPtr +xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map, + xmlNsMapItemPtr *cur, + xmlNsPtr oldNs, + xmlNsPtr newNs, + int depth) +{ + xmlNsMapItemPtr ret; + + if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) { + /* + * Reuse. + */ + ret = (*cur)->next; + *cur = ret; + } else { + ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); + if (ret == NULL) { + xmlTreeErrMemory("allocating namespace map item"); + return (NULL); + } + memset(ret, 0, sizeof(struct xmlNsMapItem)); + if (*map == NULL) { + /* + * First ever. + */ + *map = ret; + ret->prev = ret; + if (cur != NULL) + *cur = ret; + } else { + if (cur) { + /* + * Append. + */ + (*cur)->next = ret; + ret->prev = *cur; + *cur = ret; + } else { + /* + * Set on first position. + */ + ret->next = (*map); + ret->prev = (*map)->prev; + (*map)->prev = ret; + *map = ret; + } + } + } + ret->oldNs = oldNs; + ret->newNs = newNs; + ret->shadowDepth = -1; + ret->depth = depth; + return (ret); +} + +/* +* xmlTreeFreeNsMap: +* @map: the ns-map +* +* Frees the ns-map +*/ +static void +xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map) +{ + xmlNsMapItemPtr mi = map, miprev; + + while (mi != NULL) { + miprev = mi; + mi = mi->next; + xmlFree(miprev); + } +} + +/* +* xmlTreeEnsureXMLDecl: +* @doc: the doc +* +* Ensures that there is an XML namespace declaration on the doc. +* +* Returns the XML ns-struct or NULL on API and internal errors. +*/ +static xmlNsPtr +xmlTreeEnsureXMLDecl(xmlDocPtr doc) +{ + if (doc == NULL) + return (NULL); + if (doc->oldNs != NULL) + return (doc->oldNs); + { + xmlNsPtr ns; + ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (ns == NULL) { + xmlTreeErrMemory( + "allocating the XML namespace"); + return (NULL); + } + memset(ns, 0, sizeof(xmlNs)); + ns->type = XML_LOCAL_NAMESPACE; + ns->href = xmlStrdup(XML_XML_NAMESPACE); + ns->prefix = xmlStrdup((const xmlChar *)"xml"); + doc->oldNs = ns; + return (ns); + } +} + +/* +* xmlDOMWrapStoreNs: +* @doc: the doc +* @nsName: the namespace name +* @prefix: the prefix +* +* Creates or reuses an xmlNs struct on doc->oldNs with +* the given prefix and namespace name. +* +* Returns the aquired ns struct or NULL in case of an API +* or internal error. +*/ +static xmlNsPtr +xmlDOMWrapStoreNs(xmlDocPtr doc, + const xmlChar *nsName, + const xmlChar *prefix) +{ + xmlNsPtr ns; + + if (doc == NULL) + return (NULL); + ns = xmlTreeEnsureXMLDecl(doc); + if (ns == NULL) + return (NULL); + if (ns->next != NULL) { + /* Reuse. */ + ns = ns->next; + while (ns != NULL) { + if (((ns->prefix == prefix) || + xmlStrEqual(ns->prefix, prefix)) && + xmlStrEqual(ns->href, nsName)) { + return (ns); + } + if (ns->next == NULL) + break; + ns = ns->next; + } + } + /* Create. */ + ns->next = xmlNewNs(NULL, nsName, prefix); + return (ns->next); +} + +/* +* xmlTreeLookupNsListByPrefix: +* @nsList: a list of ns-structs +* @prefix: the searched prefix +* +* Searches for a ns-decl with the given prefix in @nsList. +* +* Returns the ns-decl if found, NULL if not found and on +* API errors. +*/ +static xmlNsPtr +xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) +{ + if (nsList == NULL) + return (NULL); + { + xmlNsPtr ns; + ns = nsList; + do { + if ((prefix == ns->prefix) || + xmlStrEqual(prefix, ns->prefix)) { + return (ns); + } + ns = ns->next; + } while (ns != NULL); + } + return (NULL); +} + +/* +* +* xmlTreeGetInScopeNamespaces: +* @map: the namespace map +* @node: the node to start with +* +* Puts in-scope namespaces into the ns-map. +* +* Returns 0 on success, -1 on API or internal errors. +*/ +static int +xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map, + xmlNodePtr node) +{ + xmlNodePtr cur; + xmlNsPtr ns; + xmlNsMapItemPtr mi; + int shadowed; + + if ((map == NULL) || (*map != NULL)) + return (-1); + /* + * Get in-scope ns-decls of @parent. + */ + cur = node; + while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->nsDef != NULL) { + ns = cur->nsDef; + do { + shadowed = 0; + if (*map != NULL) { + /* + * Skip shadowed prefixes. + */ + for (mi = *map; mi != NULL; mi = mi->next) { + if ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix)) { + shadowed = 1; + break; + } + } + } + /* + * Insert mapping. + */ + mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL, + ns, XML_TREE_NSMAP_PARENT); + if (mi == NULL) + return (-1); + if (shadowed) + mi->shadowDepth = 0; + ns = ns->next; + } while (ns != NULL); + } + } + cur = cur->parent; + } + return (0); +} + +/* +* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; +* otherwise copy it, when it was in the source-dict. +*/ +#define XML_TREE_ADOPT_STR(str) \ + if (adoptStr && (str != NULL)) { \ + if (destDoc->dict) { \ + const xmlChar *old = str; \ + str = xmlDictLookup(destDoc->dict, str, -1); \ + if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ + (!xmlDictOwns(sourceDoc->dict, old))) \ + xmlFree((char *)old); \ + } else if ((sourceDoc) && (sourceDoc->dict) && \ + xmlDictOwns(sourceDoc->dict, str)) { \ + str = BAD_CAST xmlStrdup(str); \ + } \ + } + +/* +* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then +* put it in dest-dict or copy it. +*/ +#define XML_TREE_ADOPT_STR_2(str) \ + if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ + (sourceDoc->dict != NULL) && \ + xmlDictOwns(sourceDoc->dict, cur->content)) { \ + if (destDoc->dict) \ + cur->content = (xmlChar *) \ + xmlDictLookup(destDoc->dict, cur->content, -1); \ + else \ + cur->content = xmlStrdup(BAD_CAST cur->content); \ + } + +/* +* xmlDOMWrapNSNormAddNsMapItem2: +* +* For internal use. Adds a ns-decl mapping. +* +* Returns 0 on success, -1 on internal errors. +*/ +static int +xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, + xmlNsPtr oldNs, xmlNsPtr newNs) +{ + if (*list == NULL) { + *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); + if (*list == NULL) { + xmlTreeErrMemory("alloc ns map item"); + return(-1); + } + *size = 3; + *number = 0; + } else if ((*number) >= (*size)) { + *size *= 2; + *list = (xmlNsPtr *) xmlRealloc(*list, + (*size) * 2 * sizeof(xmlNsPtr)); + if (*list == NULL) { + xmlTreeErrMemory("realloc ns map item"); + return(-1); + } + } + (*list)[2 * (*number)] = oldNs; + (*list)[2 * (*number) +1] = newNs; + (*number)++; + return (0); +} + +/* +* xmlDOMWrapRemoveNode: +* @ctxt: a DOM wrapper context +* @doc: the doc +* @node: the node to be removed. +* @options: set of options, unused at the moment +* +* Unlinks the given node from its owner. +* This will substitute ns-references to node->nsDef for +* ns-references to doc->oldNs, thus ensuring the removed +* branch to be autark wrt ns-references. +* WARNING: This function is in a experimental state. +* +* Returns 0 on success, 1 if the node is not supported, +* -1 on API and internal errors. +*/ +int +xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr node, int options ATTRIBUTE_UNUSED) +{ + xmlNsPtr *list = NULL; + int sizeList, nbList, i, j; + xmlNsPtr ns; + + if ((node == NULL) || (doc == NULL) || (node->doc != doc)) + return (-1); + + /* TODO: 0 or -1 ? */ + if (node->parent == NULL) + return (0); + + switch (node->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + xmlUnlinkNode(node); + return (0); + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + break; + default: + return (1); + } + xmlUnlinkNode(node); + /* + * Save out-of-scope ns-references in doc->oldNs. + */ + do { + switch (node->type) { + case XML_ELEMENT_NODE: + if ((ctxt == NULL) && (node->nsDef != NULL)) { + ns = node->nsDef; + do { + if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, + &nbList, ns, ns) == -1) + goto internal_error; + ns = ns->next; + } while (ns != NULL); + } + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + if (node->ns != NULL) { + /* + * Find a mapping. + */ + if (list != NULL) { + for (i = 0, j = 0; i < nbList; i++, j += 2) { + if (node->ns == list[j]) { + node->ns = list[++j]; + goto next_node; + } + } + } + ns = NULL; + if (ctxt != NULL) { + /* + * User defined. + */ + } else { + /* + * Add to doc's oldNs. + */ + ns = xmlDOMWrapStoreNs(doc, node->ns->href, + node->ns->prefix); + if (ns == NULL) + goto internal_error; + } + if (ns != NULL) { + /* + * Add mapping. + */ + if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, + &nbList, node->ns, ns) == -1) + goto internal_error; + } + node->ns = ns; + } + if ((node->type == XML_ELEMENT_NODE) && + (node->properties != NULL)) { + node = (xmlNodePtr) node->properties; + continue; + } + break; + default: + goto next_sibling; + } +next_node: + if ((node->type == XML_ELEMENT_NODE) && + (node->children != NULL)) { + node = node->children; + continue; + } +next_sibling: + if (node == NULL) + break; + if (node->next != NULL) + node = node->next; + else { + node = node->parent; + goto next_sibling; + } + } while (node != NULL); + + if (list != NULL) + xmlFree(list); + return (0); + +internal_error: + if (list != NULL) + xmlFree(list); + return (-1); +} + +/* +* xmlSearchNsByHrefStrict: +* @doc: the document +* @node: the start node +* @nsName: the searched namespace name +* @retNs: the resulting ns-decl +* @prefixed: if the found ns-decl must have a prefix (for attributes) +* +* Dynamically searches for a ns-declaration which matches +* the given @nsName in the ancestor-or-self axis of @node. +* +* Returns 1 if a ns-decl was found, 0 if not and -1 on API +* and internal errors. +*/ +static int +xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName, + xmlNsPtr *retNs, int prefixed) +{ + xmlNodePtr cur, prev = NULL, out = NULL; + xmlNsPtr ns, prevns; + + if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) + return (-1); + + *retNs = NULL; + if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { + *retNs = xmlTreeEnsureXMLDecl(doc); + if (*retNs == NULL) + return (-1); + return (1); + } + cur = node; + do { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->nsDef != NULL) { + for (ns = cur->nsDef; ns != NULL; ns = ns->next) { + if (prefixed && (ns->prefix == NULL)) + continue; + if (prev != NULL) { + /* + * Check the last level of ns-decls for a + * shadowing prefix. + */ + prevns = prev->nsDef; + do { + if ((prevns->prefix == ns->prefix) || + ((prevns->prefix != NULL) && + (ns->prefix != NULL) && + xmlStrEqual(prevns->prefix, ns->prefix))) { + /* + * Shadowed. + */ + break; + } + prevns = prevns->next; + } while (prevns != NULL); + if (prevns != NULL) + continue; + } + /* + * Ns-name comparison. + */ + if ((nsName == ns->href) || + xmlStrEqual(nsName, ns->href)) { + /* + * At this point the prefix can only be shadowed, + * if we are the the (at least) 3rd level of + * ns-decls. + */ + if (out) { + int ret; + + ret = xmlNsInScope(doc, node, prev, ns->prefix); + if (ret < 0) + return (-1); + /* + * TODO: Should we try to find a matching ns-name + * only once? This here keeps on searching. + * I think we should try further since, there might + * be an other matching ns-decl with an unshadowed + * prefix. + */ + if (! ret) + continue; + } + *retNs = ns; + return (1); + } + } + out = prev; + prev = cur; + } + } else if ((node->type == XML_ENTITY_REF_NODE) || + (node->type == XML_ENTITY_NODE) || + (node->type == XML_ENTITY_DECL)) + return (0); + cur = cur->parent; + } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); + return (0); +} + +/* +* xmlDOMWrapNSNormDeclareNsForced: +* @doc: the doc +* @elem: the element-node to declare on +* @nsName: the namespace-name of the ns-decl +* @prefix: the preferred prefix of the ns-decl +* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls +* +* Declares a new namespace on @elem. It tries to use the +* given @prefix; if a ns-decl with the given prefix is already existent +* on @elem, it will generate an other prefix. +* +* Returns 1 if a ns-decl was found, 0 if not and -1 on API +* and internal errors. +*/ +static xmlNsPtr +xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *nsName, + const xmlChar *prefix, + int checkShadow) +{ + + xmlNsPtr ret; + char buf[50]; + const xmlChar *pref; + int counter = 0; + /* + * Create a ns-decl on @anchor. + */ + pref = prefix; + while (1) { + /* + * Lookup whether the prefix is unused in elem's ns-decls. + */ + if ((elem->nsDef != NULL) && + (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) + goto ns_next_prefix; + if (checkShadow && elem->parent && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + /* + * Does it shadow ancestor ns-decls? + */ + if (xmlSearchNs(doc, elem->parent, pref) != NULL) + goto ns_next_prefix; + } + ret = xmlNewNs(NULL, nsName, pref); + if (ret == NULL) + return (NULL); + if (elem->nsDef == NULL) + elem->nsDef = ret; + else { + xmlNsPtr ns2 = elem->nsDef; + while (ns2->next != NULL) + ns2 = ns2->next; + ns2->next = ret; + } + return (ret); +ns_next_prefix: + counter++; + if (counter > 1000) + return (NULL); + if (prefix == NULL) { + snprintf((char *) buf, sizeof(buf), + "default%d", counter); + } else + snprintf((char *) buf, sizeof(buf), + "%.30s%d", (char *)prefix, counter); + pref = BAD_CAST buf; + } +} + +/* +* xmlDOMWrapNSNormAquireNormalizedNs: +* @doc: the doc +* @elem: the element-node to declare namespaces on +* @ns: the ns-struct to use for the search +* @retNs: the found/created ns-struct +* @nsMap: the ns-map +* @topmi: the last ns-map entry +* @depth: the current tree depth +* @ancestorsOnly: search in ancestor ns-decls only +* @prefixed: if the searched ns-decl must have a prefix (for attributes) +* +* Searches for a matching ns-name in the ns-decls of @nsMap, if not +* found it will either declare it on @elem, or store it in doc->oldNs. +* If a new ns-decl needs to be declared on @elem, it tries to use the +* @ns->prefix for it, if this prefix is already in use on @elem, it will +* change the prefix or the new ns-decl. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, + xmlNodePtr elem, + xmlNsPtr ns, + xmlNsPtr *retNs, + xmlNsMapItemPtr *nsMap, + xmlNsMapItemPtr *topmi, + int depth, + int ancestorsOnly, + int prefixed) +{ + xmlNsMapItemPtr mi; + + if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || + (nsMap == NULL) || (topmi == NULL)) + return (-1); + + *retNs = NULL; + /* + * Handle XML namespace. + */ + if ((ns->prefix) && + (ns->prefix[0] == 'x') && + (ns->prefix[1] == 'm') && + (ns->prefix[2] == 'l') && + (ns->prefix[3] == 0)) { + /* + * Insert XML namespace mapping. + */ + *retNs = xmlTreeEnsureXMLDecl(doc); + if (*retNs == NULL) + return (-1); + return (0); + } + /* + * If the search should be done in ancestors only and no + * @elem (the first ancestor) was specified, then skip the search. + */ + if ((! (ancestorsOnly && (elem == NULL))) && + (*nsMap != NULL)) { + + /* + * Try to find an equal ns-name in in-scope ns-decls. + */ + for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) { + + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + /* + * This should be turned on to gain speed, if one knows + * that the branch itself was already ns-wellformed and no + * stale references existed. I.e. it searches in the ancestor + * axis only. + */ + ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && + /* Skip shadowed prefixes. */ + (mi->shadowDepth == -1) && + /* Skip xmlns="" or xmlns:foo="". */ + ((mi->newNs->href != NULL) && + (mi->newNs->href[0] != 0)) && + /* Ensure a prefix if wanted. */ + ((! prefixed) || (mi->newNs->prefix != NULL)) && + /* Equal ns name */ + ((mi->newNs->href == ns->href) || + xmlStrEqual(mi->newNs->href, ns->href))) { + /* Set the mapping. */ + mi->oldNs = ns; + *retNs = mi->newNs; + return (0); + } + } + } + /* + * No luck, the namespace is out of scope or shadowed. + */ + if (elem == NULL) { + xmlNsPtr tmpns; + + /* + * Store ns-decls in "oldNs" of the document-node. + */ + tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); + if (tmpns == NULL) + return (-1); + /* + * Insert mapping. + */ + if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns, + tmpns, XML_TREE_NSMAP_DOC) == NULL) { + xmlFreeNs(tmpns); + return (-1); + } + *retNs = tmpns; + } else { + xmlNsPtr tmpns; + + tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, + ns->prefix, 0); + if (tmpns == NULL) + return (-1); + + if (*nsMap != NULL) { + /* + * Does it shadow ancestor ns-decls? + */ + for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) { + if ((mi->depth < depth) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix))) { + /* + * Shadows. + */ + mi->shadowDepth = depth; + break; + } + } + } + if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns, + tmpns, depth) == NULL) { + xmlFreeNs(tmpns); + return (-1); + } + *retNs = tmpns; + } + return (0); +} + +/* +* xmlDOMWrapReconcileNamespaces: +* @ctxt: DOM wrapper context, unused at the moment +* @elem: the element-node +* @options: option flags +* +* Ensures that ns-references point to ns-decls hold on element-nodes. +* Ensures that the tree is namespace wellformed by creating additional +* ns-decls where needed. Note that, since prefixes of already existent +* ns-decls can be shadowed by this process, it could break QNames in +* attribute values or element content. +* WARNING: This function is in a experimental state. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +int +xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlNodePtr elem, + int options ATTRIBUTE_UNUSED) +{ + int depth = -1, adoptns = 0, parnsdone = 0; + xmlNsPtr ns; + xmlDocPtr doc; + xmlNodePtr cur, curElem = NULL; + xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi; + /* @ancestorsOnly should be set by an option flag. */ + int ancestorsOnly = 0; + + if ((elem == NULL) || (elem->doc == NULL) || + (elem->type != XML_ELEMENT_NODE)) + return (-1); + + doc = elem->doc; + cur = elem; + do { + switch (cur->type) { + case XML_ELEMENT_NODE: + adoptns = 1; + curElem = cur; + depth++; + /* + * Namespace declarations. + */ + if (cur->nsDef != NULL) { + for (ns = cur->nsDef; ns != NULL; ns = ns->next) { + if (! parnsdone) { + if ((elem->parent) && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + /* + * Gather ancestor in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + elem->parent) == -1) + goto internal_error; + if (nsMap != NULL) + topmi = nsMap->prev; + } + parnsdone = 1; + } + /* + * Skip ns-references handling if the referenced + * ns-decl is declared on the same element. + */ + if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) + adoptns = 0; + /* + * Does it shadow any ns-decl? + */ + if (nsMap) { + for (mi = nsMap; mi != topmi->next; mi = mi->next) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix))) { + + mi->shadowDepth = depth; + } + } + } + /* + * Push mapping. + */ + if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns, + depth) == NULL) + goto internal_error; + } + } + if (! adoptns) + goto ns_end; + + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + if (cur->ns == NULL) + goto ns_end; + if (! parnsdone) { + if ((elem->parent) && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + elem->parent) == -1) + goto internal_error; + if (nsMap != NULL) + topmi = nsMap->prev; + } + parnsdone = 1; + } + /* + * Adopt ns-references. + */ + if (nsMap != NULL) { + /* + * Search for a mapping. + */ + for (mi = nsMap; mi != topmi->next; mi = mi->next) { + if ((mi->shadowDepth == -1) && + (cur->ns == mi->oldNs)) { + + cur->ns = mi->newNs; + goto ns_end; + } + } + } + /* + * Aquire a normalized ns-decl and add it to the map. + */ + if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, + cur->ns, &ns, + &nsMap, &topmi, depth, + ancestorsOnly, + (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) + goto internal_error; + cur->ns = ns; + +ns_end: + if ((cur->type == XML_ELEMENT_NODE) && + (cur->properties != NULL)) { + /* + * Process attributes. + */ + cur = (xmlNodePtr) cur->properties; + continue; + } + break; + default: + goto next_sibling; + } + if ((cur->type == XML_ELEMENT_NODE) && + (cur->children != NULL)) { + /* + * Process content of element-nodes only. + */ + cur = cur->children; + continue; + } +next_sibling: + if (cur == elem) + break; + if (cur->type == XML_ELEMENT_NODE) { + if (nsMap != NULL) { + /* + * Pop mappings. + */ + while ((topmi->depth >= 0) && (topmi->depth >= depth)) + topmi = topmi->prev; + /* + * Unshadow. + */ + for (mi = nsMap; mi != topmi->next; mi = mi->next) + if (mi->shadowDepth >= depth) + mi->shadowDepth = -1; + } + depth--; + } + if (cur->next != NULL) + cur = cur->next; + else { + cur = cur->parent; + goto next_sibling; + } + } while (cur != NULL); + + if (nsMap != NULL) + xmlDOMWrapNSNormFreeNsMap(nsMap); + return (0); +internal_error: + if (nsMap != NULL) + xmlDOMWrapNSNormFreeNsMap(nsMap); + return (-1); +} + +/* +* xmlDOMWrapAdoptBranch: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional sourceDoc +* @node: the element-node to start with +* @destDoc: the destination doc for adoption +* @parent: the optional new parent of @node in @destDoc +* @options: option flags +* +* Ensures that ns-references point to @destDoc: either to +* elements->nsDef entries if @destParent is given, or to +* @destDoc->oldNs otherwise. +* If @destParent is given, it ensures that the tree is namespace +* wellformed by creating additional ns-decls where needed. +* Note that, since prefixes of already existent ns-decls can be +* shadowed by this process, it could break QNames in attribute +* values or element content. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options ATTRIBUTE_UNUSED) +{ + int ret = 0; + xmlNodePtr cur, curElem = NULL; + xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi; + xmlNsPtr ns; + int depth = -1, adoptStr = 1; + /* gather @parent's ns-decls. */ + int parnsdone = 0; + /* @ancestorsOnly should be set per option. */ + int ancestorsOnly = 0; + + /* + * Optimize string adoption for equal or none dicts. + */ + if ((sourceDoc != NULL) && + (sourceDoc->dict == destDoc->dict)) + adoptStr = 0; + else + adoptStr = 1; + + cur = node; + while (cur != NULL) { + if (cur->doc != sourceDoc) { + /* + * We'll assume XIncluded nodes if the doc differs. + * TODO: Do we need to reconciliate XIncluded nodes? + * This here skips XIncluded nodes and tries to handle + * broken sequences. + */ + if (cur->next == NULL) + goto leave_node; + do { + cur = cur->next; + if ((cur->type == XML_XINCLUDE_END) || + (cur->doc == node->doc)) + break; + } while (cur->next != NULL); + + if (cur->doc != node->doc) + goto leave_node; + } + cur->doc = destDoc; + switch (cur->type) { + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* + * TODO + */ + return (-1); + case XML_ELEMENT_NODE: + curElem = cur; + depth++; + /* + * Namespace declarations. + */ + if ((ctxt == NULL) && (cur->nsDef != NULL)) { + if (! parnsdone) { + if (destParent && (ctxt == NULL)) { + /* + * Gather @parent's in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; + if (nsMap != NULL) + topmi = nsMap->prev; + } + parnsdone = 1; + } + for (ns = cur->nsDef; ns != NULL; ns = ns->next) { + /* + * ns->prefix and ns->href seem not to be in the dict. + * XML_TREE_ADOPT_STR(ns->prefix) + * XML_TREE_ADOPT_STR(ns->href) + */ + /* + * Does it shadow any ns-decl? + */ + if (nsMap) { + for (mi = nsMap; mi != topmi->next; + mi = mi->next) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, + mi->newNs->prefix))) { + + mi->shadowDepth = depth; + } + } + } + /* + * Push mapping. + */ + if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, + ns, ns, depth) == NULL) + goto internal_error; + } + } + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + + if (cur->ns == NULL) + goto ns_end; + if (! parnsdone) { + if (destParent && (ctxt == NULL)) { + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; + if (nsMap != NULL) + topmi = nsMap->prev; + } + parnsdone = 1; + } + /* + * Adopt ns-references. + */ + if (nsMap != NULL) { + /* + * Search for a mapping. + */ + for (mi = nsMap; mi != topmi->next; mi = mi->next) { + if ((mi->shadowDepth == -1) && + (cur->ns == mi->oldNs)) { + + cur->ns = mi->newNs; + goto ns_end; + } + } + } + /* + * Start searching for an in-scope ns-decl. + */ + if (ctxt != NULL) { + /* + * User-defined behaviour. + */ +#if 0 + ctxt->aquireNsDecl(ctxt, cur->ns, &ns); +#endif + /* + * Insert mapping if ns is available; it's the users fault + * if not. + */ + if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, + ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) + goto internal_error; + cur->ns = ns; + } else { + /* + * Aquire a normalized ns-decl and add it to the map. + */ + if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, + /* ns-decls on curElem or on destDoc->oldNs */ + destParent ? curElem : NULL, + cur->ns, &ns, + &nsMap, &topmi, depth, + ancestorsOnly, + /* ns-decls must be prefixed for attributes. */ + (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) + goto internal_error; + cur->ns = ns; + } +ns_end: + /* + * Further node properties. + * TODO: Is this all? + */ + XML_TREE_ADOPT_STR(cur->name) + if (cur->type == XML_ELEMENT_NODE) { + cur->psvi = NULL; + cur->line = 0; + cur->extra = 0; + /* + * Walk attributes. + */ + if (cur->properties != NULL) { + /* + * Process first attribute node. + */ + cur = (xmlNodePtr) cur->properties; + continue; + } + } else { + /* + * Attributes. + */ + if ((sourceDoc != NULL) && + (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) + xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); + ((xmlAttrPtr) cur)->atype = 0; + ((xmlAttrPtr) cur)->psvi = NULL; + } + break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + /* + * This puts the content in the dest dict, only if + * it was previously in the source dict. + */ + XML_TREE_ADOPT_STR_2(cur->content) + goto leave_node; + case XML_ENTITY_REF_NODE: + /* + * Remove reference to the entitity-node. + */ + cur->content = NULL; + cur->children = NULL; + cur->last = NULL; + if ((destDoc->intSubset) || (destDoc->extSubset)) { + xmlEntityPtr ent; + /* + * Assign new entity-node if available. + */ + ent = xmlGetDocEntity(destDoc, cur->name); + if (ent != NULL) { + cur->content = ent->content; + cur->children = (xmlNodePtr) ent; + cur->last = (xmlNodePtr) ent; + } + } + goto leave_node; + case XML_PI_NODE: + XML_TREE_ADOPT_STR(cur->name) + XML_TREE_ADOPT_STR_2(cur->content) + break; + case XML_COMMENT_NODE: + break; + default: + goto internal_error; + } + /* + * Walk the tree. + */ + if (cur->children != NULL) { + cur = cur->children; + continue; + } + +leave_node: + if (cur == node) + break; + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) { + /* + * TODO: Do we expect nsDefs on XML_XINCLUDE_START? + */ + if (nsMap != NULL) { + /* + * Pop mappings. + */ + while (topmi->depth >= depth) + topmi = topmi->prev; + /* + * Unshadow. + */ + for (mi = nsMap; mi != topmi->next; mi = mi->next) + if (mi->shadowDepth >= depth) + mi->shadowDepth = -1; + } + depth--; + } + if (cur->next != NULL) + cur = cur->next; + else { + cur = cur->parent; + goto leave_node; + } + } + /* + * Cleanup. + */ + if (nsMap != NULL) + xmlDOMWrapNSNormFreeNsMap(nsMap); + return (ret); +internal_error: + if (nsMap != NULL) + xmlDOMWrapNSNormFreeNsMap(nsMap); + return (-1); +} + +/* +* xmlDOMWrapAdoptAttr: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional source document of attr +* @attr: the attribute-node to be adopted +* @destDoc: the destination doc for adoption +* @destParent: the optional new parent of @attr in @destDoc +* @options: option flags +* +* @attr is adopted by @destDoc. +* Ensures that ns-references point to @destDoc: either to +* elements->nsDef entries if @destParent is given, or to +* @destDoc->oldNs otherwise. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlAttrPtr attr, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options ATTRIBUTE_UNUSED) +{ + xmlNodePtr cur; + int adoptStr = 1; + + if ((attr == NULL) || (destDoc == NULL)) + return (-1); + + attr->doc = destDoc; + if (attr->ns != NULL) { + xmlNsPtr ns = NULL; + + if (ctxt != NULL) { + /* TODO: User defined. */ + } + /* XML Namespace. */ + if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') && + (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) { + ns = xmlTreeEnsureXMLDecl(destDoc); + } else if (destParent == NULL) { + /* + * Store in @destDoc->oldNs. + */ + ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); + } else { + /* + * Declare on @destParent. + */ + if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href, + &ns, 1) == -1) + goto internal_error; + if (ns == NULL) { + ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, + attr->ns->href, attr->ns->prefix, 1); + } + } + if (ns == NULL) + goto internal_error; + attr->ns = ns; + } + + XML_TREE_ADOPT_STR(attr->name); + attr->atype = 0; + attr->psvi = NULL; + /* + * Walk content. + */ + if (attr->children == NULL) + return (0); + cur = attr->children; + while (cur != NULL) { + cur->doc = destDoc; + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + XML_TREE_ADOPT_STR_2(cur->content) + break; + case XML_ENTITY_REF_NODE: + /* + * Remove reference to the entitity-node. + */ + cur->content = NULL; + cur->children = NULL; + cur->last = NULL; + if ((destDoc->intSubset) || (destDoc->extSubset)) { + xmlEntityPtr ent; + /* + * Assign new entity-node if available. + */ + ent = xmlGetDocEntity(destDoc, cur->name); + if (ent != NULL) { + cur->content = ent->content; + cur->children = (xmlNodePtr) ent; + cur->last = (xmlNodePtr) ent; + } + } + break; + default: + break; + } + if (cur->children != NULL) { + cur = cur->children; + continue; + } +next_sibling: + if (cur == (xmlNodePtr) attr) + break; + if (cur->next != NULL) + cur = cur->next; + else { + cur = cur->parent; + goto next_sibling; + } + } + return (0); +internal_error: + return (-1); +} + +/* +* xmlDOMWrapAdoptNode: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional sourceDoc +* @node: the node to start with +* @destDoc: the destination doc +* @destParent: the optional new parent of @node in @destDoc +* @options: option flags +* +* Ensures that ns-references point to @destDoc: either to +* elements->nsDef entries if @destParent is given, or to +* @destDoc->oldNs otherwise. +* If @destParent is given, it ensures that the tree is namespace +* wellformed by creating additional ns-decls where needed. +* Note that, since prefixes of already existent ns-decls can be +* shadowed by this process, it could break QNames in attribute +* values or element content. +* WARNING: This function is in a experimental state. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +int +xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options) +{ + if ((node == NULL) || (destDoc == NULL) || + ((destParent != NULL) && (destParent->doc != destDoc))) + return(-1); + /* + * Check node->doc sanity. + */ + if ((node->doc != NULL) && (sourceDoc != NULL) && + (node->doc != sourceDoc)) { + /* + * Might be an XIncluded node. + */ + return (-1); + } + if (sourceDoc == NULL) + sourceDoc = node->doc; + if (sourceDoc == destDoc) + return (-1); + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + break; + case XML_DOCUMENT_FRAG_NODE: + return (2); + default: + return (1); + } + /* + * Unlink only if @node was not already added to @destParent. + */ + if ((node->parent != NULL) && (destParent != node->parent)) + xmlUnlinkNode(node); + + if (node->type == XML_ELEMENT_NODE) { + return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, + destDoc, destParent, options)); + } else if (node->type == XML_ATTRIBUTE_NODE) { + return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, + (xmlAttrPtr) node, destDoc, destParent, options)); + } else { + xmlNodePtr cur = node; + int adoptStr = 1; + + cur->doc = destDoc; + /* + * Optimize string adoption. + */ + if ((sourceDoc != NULL) && + (sourceDoc->dict == destDoc->dict)) + adoptStr = 0; + switch (node->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + XML_TREE_ADOPT_STR_2(node->content) + break; + case XML_ENTITY_REF_NODE: + /* + * Remove reference to the entitity-node. + */ + node->content = NULL; + node->children = NULL; + node->last = NULL; + if ((destDoc->intSubset) || (destDoc->extSubset)) { + xmlEntityPtr ent; + /* + * Assign new entity-node if available. + */ + ent = xmlGetDocEntity(destDoc, node->name); + if (ent != NULL) { + node->content = ent->content; + node->children = (xmlNodePtr) ent; + node->last = (xmlNodePtr) ent; + } + } + XML_TREE_ADOPT_STR(node->name) + break; + case XML_PI_NODE: { + XML_TREE_ADOPT_STR(node->name) + XML_TREE_ADOPT_STR_2(node->content) + break; + } + default: + break; + } + } + return (0); +} + + #define bottom_tree #include "elfgcchack.h" |