[xmlsec] About xmlParseInNodeContext() in libxml2.
Aleksey Sanin
aleksey at aleksey.com
Fri Sep 17 08:08:13 PDT 2004
Thanks a lot! I'll take a look at your changes this weekend!
Aleksey
Tomas Sieger wrote:
> Aleksey Sanin wrote:
>
>>> Write me if you need more help following this complex hack (e.g. to
>>> send sources).
>>
>>
>> I am interested :) It would be really great if you can share your
>> changes. It seems that this solves the problem and does not require
>> the latest libxml2. In the ideal case I would love to have both:
>> your patch for old libxml2 and xmlParseInNodeContext() for newer
>> libxml2.
>>
>
> Ok, I'm sending a diff to xmltree.c. I've tried to follow the XMLSec
> coding rules, but I guess a review is a must ;-).
> Note newly created functions in xmltree.c are static - please publish
> them if you think it is a good idea.
>
> best regards,
> Tomas
>
>
> ------------------------------------------------------------------------
>
> Index: xmltree.c
> ===================================================================
> RCS file: /cvs/gnome/xmlsec/src/xmltree.c,v
> retrieving revision 1.38
> diff -c -r1.38 xmltree.c
> *** xmltree.c 17 Jun 2004 18:17:06 -0000 1.38
> --- xmltree.c 17 Sep 2004 09:40:16 -0000
> ***************
> *** 16,21 ****
> --- 16,22 ----
>
> #include <libxml/tree.h>
> #include <libxml/valid.h>
> + #include <libxml/xmlstring.h>
> #include <libxml/xpath.h>
> #include <libxml/xpathInternals.h>
>
> ***************
> *** 474,479 ****
> --- 475,674 ----
>
>
> /**
> + * xmlSecGatherNamespaceDeclarations
> + * @node: node affected by namespace declarations
> + *
> + * Gathers namespace declarations from the "ancestor-or-self" axis of @node,
> + * i.e. those applying to @node. Only namespaces having a prefix are gathered
> + * (default namespaces are not gathered).
> + *
> + * Returns NULL if no namespace declarations found or an allocated string
> + * containing namespace declarations in format
> + * 'xmlns:PREFIX_1="URI_1" xmlns:PREFIX_2="URI_2"... '. Note there is
> + * a trailing space in the string. The string must be freed by the caller.
> + */
> + static xmlChar *
> + xmlSecGatherNamespaceDeclarations(xmlNodePtr node) {
> + static const char *nsDeclPart1 = "xmlns:";
> + static const char *nsDeclPart3 = "=\"";
> + static const char *nsDeclPart5 = "\" ";
> + int nsDeclSkeletLen;
> + xmlChar *namespaceDecls;
> + xmlNsPtr *ns;
> +
> + xmlSecAssert2(node != NULL, NULL);
> +
> + nsDeclSkeletLen = strlen(nsDeclPart1) +
> + strlen(nsDeclPart3) +
> + strlen(nsDeclPart5);
> +
> + /* get applying namespaces */
> + ns = xmlGetNsList(node->doc, node);
> + if(ns != NULL) {
> + /* convert the namespaces into text (namespace declarations) */
> +
> + xmlNsPtr *p;
> + xmlChar *s;
> + int size;
> +
> + /* determine namespace declarations length */
> + size = 0;
> + for(p = ns; *p != NULL; p++) {
> + if((*p)->prefix != NULL) {
> + size += nsDeclSkeletLen +
> + xmlStrlen((*p)->prefix) +
> + ((*p)->href ? xmlStrlen((*p)->href) : 0 );
> + }
> + }
> + size++; /* trailing zero */
> +
> + /* allocate buffer for namespace declarations */
> + namespaceDecls = (xmlChar *) xmlMalloc(size);
> + if(namespaceDecls == NULL) {
> + xmlSecError(XMLSEC_ERRORS_HERE,
> + NULL,
> + "xmlMalloc",
> + XMLSEC_ERRORS_R_MALLOC_FAILED,
> + XMLSEC_ERRORS_NO_MESSAGE);
> + xmlFree(ns);
> + return(NULL);
> + }
> +
> + /* write namespace declarations */
> + s = namespaceDecls;
> + for(p = ns; *p != NULL; p++) {
> + if((*p)->prefix != NULL) {
> + int wroteLen;
> + wroteLen = xmlStrPrintf(s, size, BAD_CAST "%s%s%s%s%s",
> + nsDeclPart1,
> + (const char *)(*p)->prefix,
> + nsDeclPart3,
> + (*p)->href != NULL ? (const char *)(*p)->href : "",
> + nsDeclPart5);
> + xmlSecAssert2(wroteLen != -1, NULL);
> + s += wroteLen;
> + size -= wroteLen;
> + }
> + }
> + xmlFree(ns);
> + }
> + else namespaceDecls = NULL;
> + return(namespaceDecls);
> + }
> +
> + /**
> + * xmlSecIsNsInNsList
> + * @ns: namespace to be find in @nsList
> + * @nsList: namespace list
> + *
> + * Finds @ns in @nsList.
> + *
> + * Returns 1 if @ns found in @nsList, 0 if @ns not found in @nsList or
> + * a negative value if an error occurs.
> + */
> + static int
> + xmlSecIsNsInNsList(xmlNsPtr ns, xmlNsPtr *nsList) {
> + xmlNsPtr *ptr;
> +
> + xmlSecAssert2(ns != NULL, -1);
> + xmlSecAssert2(nsList != NULL, -1);
> +
> + for(ptr = nsList; *ptr != NULL; ptr++) {
> + if(ns == *ptr) return 1;
> + }
> + return 0;
> + }
> +
> + /**
> + * xmlSecGetNsFromNsList
> + * @prefix: namespace prefix
> + * @nsList: namespace list
> + *
> + * Returns namespace having prefix @prefix or NULL if no namespace having
> + * prefix @prefix found or an error occurs.
> + */
> + static xmlNsPtr
> + xmlSecGetNsFromNsList(const xmlChar *prefix, xmlNsPtr *nsList) {
> + xmlNsPtr *ptr;
> +
> + xmlSecAssert2(prefix != NULL, NULL);
> + xmlSecAssert2(nsList != NULL, NULL);
> +
> + for(ptr = nsList; *ptr != NULL; ptr++) {
> + if(xmlStrEqual(prefix, (*ptr)->prefix)) return(*ptr);
> + }
> + return(NULL);
> + }
> +
> + /**
> + * xmlSecReplaceNodeNamespaces
> + * @node: node where to replace the namespaces
> + * @curNsList: current namespace list
> + * @newNsList: new namespace list
> + *
> + * Replaces namespaces appearing at @node, its attributes and, recursively,
> + * at its descendants and their attributes, in this manner: every use of
> + * a namespace from @curNsList gets repointed to namespace declaration from
> + * @newNsList.
> + *
> + * Returns 0 on success or a negative value if an error occurs.
> + */
> + static int
> + xmlSecReplaceNodeNamespaces(xmlNodePtr node, xmlNsPtr *curNsList, xmlNsPtr *newNsList) {
> + xmlAttrPtr attr;
> + xmlNodePtr n;
> + int rc;
> +
> + xmlSecAssert2(node != NULL, -1);
> + xmlSecAssert2(curNsList != NULL, -1);
> + xmlSecAssert2(newNsList != NULL, -1);
> +
> + /* fix attributes */
> + for(attr = node->properties; attr != NULL; attr = attr->next) {
> + if(attr->ns != NULL) {
> + rc = xmlSecIsNsInNsList(attr->ns, curNsList);
> + if(rc < 0) {
> + xmlSecError(XMLSEC_ERRORS_HERE,
> + NULL,
> + NULL,
> + XMLSEC_ERRORS_R_XMLSEC_FAILED,
> + XMLSEC_ERRORS_NO_MESSAGE);
> + return(-1);
> + }
> + if(rc == 1) {
> + /* TODO: namespace lookup may be faster than this silly sequential lookup */
> + attr->ns = xmlSecGetNsFromNsList(attr->ns->prefix, newNsList);
> + }
> + }
> + }
> +
> + /* fix the node itself */
> + rc = xmlSecIsNsInNsList(node->ns, curNsList);
> + if(node->ns != NULL) {
> + if(rc < 0) {
> + xmlSecError(XMLSEC_ERRORS_HERE,
> + NULL,
> + NULL,
> + XMLSEC_ERRORS_R_XMLSEC_FAILED,
> + XMLSEC_ERRORS_NO_MESSAGE);
> + return(-1);
> + }
> + if(rc == 1) {
> + /* TODO: namespace lookup may be faster than this silly sequential lookup */
> + node->ns = xmlSecGetNsFromNsList(node->ns->prefix, newNsList);
> + }
> + }
> +
> + /* fix descendants */
> + for(n = xmlSecGetNextElementNode(node->children);
> + n != NULL;
> + n = xmlSecGetNextElementNode(n->next)) {
> + xmlSecReplaceNodeNamespaces(n, curNsList, newNsList);
> + }
> + return(0);
> + }
> +
> + /**
> * xmlSecReplaceNodeBuffer:
> * @node: the current node.
> * @buffer: the XML data.
> ***************
> *** 486,499 ****
> int
> xmlSecReplaceNodeBuffer(xmlNodePtr node,
> const xmlSecByte *buffer, xmlSecSize size) {
> ! static const char dummyPrefix[] = "<dummy>";
> static const char dummyPostfix[] = "</dummy>";
> xmlDocPtr doc;
> xmlNodePtr ptr1, ptr2;
>
> xmlSecAssert2(node != NULL, -1);
> !
> ! doc = xmlSecParseMemoryExt((xmlSecByte*)dummyPrefix, strlen(dummyPrefix),
> buffer, size,
> (xmlSecByte*)dummyPostfix, strlen(dummyPostfix));
> if(doc == NULL){
> --- 681,729 ----
> int
> xmlSecReplaceNodeBuffer(xmlNodePtr node,
> const xmlSecByte *buffer, xmlSecSize size) {
> ! static const char dummyPrefixPart1[] = "<dummy ";
> ! const char *dummyPrefixPart2;
> ! static const char dummyPrefixPart3[] = ">";
> ! xmlChar *dummyPrefix;
> ! int dummyPrefixSize;
> static const char dummyPostfix[] = "</dummy>";
> + xmlChar *namespaceDecls;
> xmlDocPtr doc;
> xmlNodePtr ptr1, ptr2;
> + xmlNsPtr *curNsList;
> + xmlNsPtr *newNsList;
>
> xmlSecAssert2(node != NULL, -1);
> !
> ! /* get namespace declarations applying to 'node' ... */
> ! namespaceDecls = xmlSecGatherNamespaceDeclarations(node);
> ! if(namespaceDecls != NULL) {
> ! dummyPrefixPart2 = (const char *)namespaceDecls;
> ! }
> ! else {
> ! dummyPrefixPart2 = "";
> ! }
> !
> ! /* ... and put it in the parser context (the <dummy> opening tag) */
> ! dummyPrefixSize =
> ! strlen(dummyPrefixPart1) +
> ! strlen(dummyPrefixPart2) +
> ! strlen(dummyPrefixPart3) + 1;
> ! dummyPrefix = xmlMalloc(dummyPrefixSize);
> ! if(dummyPrefix == NULL) {
> ! xmlSecError(XMLSEC_ERRORS_HERE,
> ! NULL,
> ! "xmlMalloc",
> ! XMLSEC_ERRORS_R_MALLOC_FAILED,
> ! XMLSEC_ERRORS_NO_MESSAGE);
> ! xmlFree(namespaceDecls);
> ! return(-1);
> ! }
> ! xmlStrPrintf(dummyPrefix, dummyPrefixSize, BAD_CAST "%s%s%s",
> ! dummyPrefixPart1, dummyPrefixPart2, dummyPrefixPart3);
> ! xmlFree(namespaceDecls);
> !
> ! doc = xmlSecParseMemoryExt((xmlSecByte*)dummyPrefix, dummyPrefixSize-1,
> buffer, size,
> (xmlSecByte*)dummyPostfix, strlen(dummyPostfix));
> if(doc == NULL){
> ***************
> *** 502,507 ****
> --- 732,738 ----
> "xmlSecParseMemoryExt",
> XMLSEC_ERRORS_R_XMLSEC_FAILED,
> XMLSEC_ERRORS_NO_MESSAGE);
> + xmlFree(dummyPrefix);
> return(-1);
> }
>
> ***************
> *** 513,531 ****
> XMLSEC_ERRORS_R_XML_FAILED,
> "root is null");
> xmlFreeDoc(doc);
> return(-1);
> }
> !
> ptr1 = ptr1->children;
> while(ptr1 != NULL) {
> ptr2 = ptr1->next;
> xmlUnlinkNode(ptr1);
> xmlAddPrevSibling(node, ptr1);
> ptr1 = ptr2;
> }
>
> xmlUnlinkNode(node);
> xmlFreeNode(node);
> xmlFreeDoc(doc);
> return(0);
> }
> --- 744,796 ----
> XMLSEC_ERRORS_R_XML_FAILED,
> "root is null");
> xmlFreeDoc(doc);
> + xmlFree(dummyPrefix);
> return(-1);
> }
> !
> ! /* get namespace list applying to the parsed node
> ! * (the namespaces are declared at the <dummy> element)
> ! */
> ! curNsList = xmlGetNsList(ptr1->doc, ptr1);
> ! /* get namespace list applying to node->parent (if any) */
> ! if(node->parent != NULL) {
> ! newNsList = xmlGetNsList(node->parent->doc, node->parent);
> ! }
> ! else newNsList = NULL;
> !
> ptr1 = ptr1->children;
> while(ptr1 != NULL) {
> ptr2 = ptr1->next;
> xmlUnlinkNode(ptr1);
> xmlAddPrevSibling(node, ptr1);
> + if((curNsList != NULL) && (newNsList != NULL)) {
> + /* repoint namespaces in the parsed document from those
> + * declared at the <dummy> alement to those appearing in
> + * the original tree
> + */
> + if(xmlSecReplaceNodeNamespaces(ptr1, curNsList, newNsList) < 0) {
> + xmlSecError(XMLSEC_ERRORS_HERE,
> + NULL,
> + NULL,
> + XMLSEC_ERRORS_R_XMLSEC_FAILED,
> + XMLSEC_ERRORS_NO_MESSAGE);
> + xmlFree(curNsList);
> + xmlFree(newNsList);
> + xmlUnlinkNode(node);
> + xmlFreeNode(node);
> + xmlFree(dummyPrefix);
> + xmlFreeDoc(doc);
> + return(-1);
> + }
> + }
> ptr1 = ptr2;
> }
>
> + xmlFree(curNsList);
> + xmlFree(newNsList);
> xmlUnlinkNode(node);
> xmlFreeNode(node);
> + xmlFree(dummyPrefix);
> xmlFreeDoc(doc);
> return(0);
> }
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> xmlsec mailing list
> xmlsec at aleksey.com
> http://www.aleksey.com/mailman/listinfo/xmlsec
More information about the xmlsec
mailing list