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
[EMAIL PROTECTED]
http://www.aleksey.com/mailman/listinfo/xmlsec

Reply via email to