[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