xmlsecurityengine/xmlsec/src/xmlsec_xpath.c
changeset 0 e35f40988205
child 24 74f0b3eb154c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlsecurityengine/xmlsec/src/xmlsec_xpath.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1158 @@
+/** 
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * XPath transform
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ * 
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
+ */
+#include "xmlsec_globals.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml2_tree.h>
+#include <libxml2_xpath.h>
+#include <libxml2_xpathinternals.h>
+#include <libxml2_xpointer.h>
+#include <libxml2_valid.h>
+#include <libxml2_globals.h>
+
+#include "xmlsec_xmlsec.h"
+#include "xmlsec_xmltree.h"
+#include "xmlsec_keys.h"
+#include "xmlsec_list.h"
+#include "xmlsec_transforms.h"
+#include "xmlsec_errors.h"
+
+
+/**************************************************************************
+ *
+ * xmlSecXPathHereFunction:
+ * @ctxt:		the ponter to XPath context.
+ * @nargs:		the arguments nubmer.
+ *
+ * The implementation of XPath "here()" function.
+ * See xmlXPtrHereFunction() in xpointer.c. the only change is that 
+ * we return NodeSet instead of NodeInterval.
+ *
+ *****************************************************************************/
+static void 
+xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(0);
+
+    if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) {
+	XP_ERROR(XPTR_SYNTAX_ERROR);
+    }
+    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->here));
+}
+
+/**************************************************************************
+ *
+ * XPath/XPointer data
+ *
+ *****************************************************************************/
+typedef struct _xmlSecXPathData			xmlSecXPathData,
+						*xmlSecXPathDataPtr;
+typedef enum {
+    xmlSecXPathDataTypeXPath,
+    xmlSecXPathDataTypeXPath2,
+    xmlSecXPathDataTypeXPointer
+} xmlSecXPathDataType;
+
+struct _xmlSecXPathData {
+    xmlSecXPathDataType			type;
+    xmlXPathContextPtr			ctx;
+    xmlChar*				expr;
+    xmlSecNodeSetOp			nodeSetOp;
+    xmlSecNodeSetType			nodeSetType;    
+};
+
+static xmlSecXPathDataPtr 	xmlSecXPathDataCreate		(xmlSecXPathDataType type);
+static void		  	xmlSecXPathDataDestroy		(xmlSecXPathDataPtr data);
+static int		  	xmlSecXPathDataSetExpr		(xmlSecXPathDataPtr data,
+								 const xmlChar* expr);
+static int 			xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, 
+								 xmlNodePtr node);
+static int		  	xmlSecXPathDataNodeRead		(xmlSecXPathDataPtr data,
+								 xmlNodePtr node);
+static xmlSecNodeSetPtr		xmlSecXPathDataExecute		(xmlSecXPathDataPtr data,
+								 xmlDocPtr doc,
+								 xmlNodePtr hereNode);
+
+static xmlSecXPathDataPtr  
+xmlSecXPathDataCreate(xmlSecXPathDataType type) {
+    xmlSecXPathDataPtr data;
+
+    data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData));
+    if(data == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_MALLOC_FAILED,
+		    "sizeof(xmlSecXPathData)=%d",
+		    sizeof(xmlSecXPathData));
+	return(NULL);
+    }
+    memset(data, 0, sizeof(xmlSecXPathData)); 
+
+    data->type = type;
+    data->nodeSetType = xmlSecNodeSetTree;
+
+    /* create xpath or xpointer context */
+    switch(data->type) {
+    case xmlSecXPathDataTypeXPath:    
+    case xmlSecXPathDataTypeXPath2:    
+	data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */
+	if(data->ctx == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlXPathNewContext",
+			XMLSEC_ERRORS_R_XML_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    xmlSecXPathDataDestroy(data);
+	    return(NULL);
+	}
+	break;
+    case xmlSecXPathDataTypeXPointer:    
+	data->ctx = xmlXPtrNewContext(NULL, NULL, NULL); /* we'll set doc in the context later */
+	if(data->ctx == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlXPtrNewContext",
+			XMLSEC_ERRORS_R_XML_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    xmlSecXPathDataDestroy(data);
+	    return(NULL);
+	}
+	break;
+    }
+
+    return(data);
+}
+
+static void				
+xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) {
+    xmlSecAssert(data != NULL);    
+
+    if(data->expr != NULL) {
+	xmlFree(data->expr);
+    }
+    if(data->ctx != NULL) {
+	xmlXPathFreeContext(data->ctx);
+    }
+    memset(data, 0, sizeof(xmlSecXPathData));  
+    xmlFree(data);
+}
+
+static int 
+xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) {
+    xmlSecAssert2(data != NULL, -1);    
+    xmlSecAssert2(data->expr == NULL, -1);
+    xmlSecAssert2(data->ctx != NULL, -1);
+    xmlSecAssert2(expr != NULL, -1);    
+            
+    data->expr = xmlStrdup(expr);
+    if(data->expr == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    NULL,
+		    XMLSEC_ERRORS_R_STRDUP_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+        return(-1);
+    }
+    return(0);
+}
+
+
+static int 
+xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) {
+    xmlNodePtr cur;
+    xmlNsPtr ns;
+    int ret;
+    
+    xmlSecAssert2(data != NULL, -1);    
+    xmlSecAssert2(data->ctx != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+
+    /* register namespaces */
+    for(cur = node; cur != NULL; cur = cur->parent) {
+	for(ns = cur->nsDef; ns != NULL; ns = ns->next) {
+	    /* check that we have no other namespace with same prefix already */
+	    if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){
+	        ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href);
+		if(ret != 0) {
+		    xmlSecError(XMLSEC_ERRORS_HERE,
+				NULL,
+			        "xmlXPathRegisterNs",
+				XMLSEC_ERRORS_R_XML_FAILED,
+			        "href=%s;prefix=%s",
+			        xmlSecErrorsSafeString(ns->href),
+				xmlSecErrorsSafeString(ns->prefix)); 
+		    return(-1);
+		}
+	    }
+	}
+    }
+    
+    return(0);
+}
+
+static int 
+xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) {
+    int ret;
+    
+    xmlSecAssert2(data != NULL, -1);    
+    xmlSecAssert2(data->expr == NULL, -1);
+    xmlSecAssert2(data->ctx != NULL, -1);
+    xmlSecAssert2(node != NULL, -1);
+
+    ret = xmlSecXPathDataRegisterNamespaces (data, node);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecXPathDataRegisterNamespaces",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+        return(-1);
+    }
+    
+    /* read node content and set expr */
+    data->expr = xmlNodeGetContent(node);
+    if(data->expr == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+		    XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+        return(-1);
+    }
+    
+    return(0);
+}
+
+static xmlSecNodeSetPtr
+xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) {
+    xmlXPathObjectPtr xpathObj = NULL; 
+    xmlSecNodeSetPtr nodes = NULL;
+
+    xmlSecAssert2(data != NULL, NULL);    
+    xmlSecAssert2(data->expr != NULL, NULL);
+    xmlSecAssert2(data->ctx != NULL, NULL);
+    xmlSecAssert2(doc != NULL, NULL);
+    xmlSecAssert2(hereNode != NULL, NULL);
+
+    /* do not forget to set the doc */
+    data->ctx->doc = doc;
+    
+    /* here function works only on the same document */
+    if(hereNode->doc == doc) {
+	xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction);
+	data->ctx->here = hereNode;
+	data->ctx->xptr = 1;
+    }
+
+    /* execute xpath or xpointer expression */
+    switch(data->type) {
+    case xmlSecXPathDataTypeXPath:    
+    case xmlSecXPathDataTypeXPath2:    
+	xpathObj = xmlXPathEvalExpression(data->expr, data->ctx);
+	if(xpathObj == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlXPathEvalExpression",
+			XMLSEC_ERRORS_R_XML_FAILED,
+			"expr=%s", 
+			xmlSecErrorsSafeString(data->expr));
+	    return(NULL);
+	}
+	break;
+    case xmlSecXPathDataTypeXPointer:    
+	xpathObj = xmlXPtrEval(data->expr, data->ctx);
+	if(xpathObj == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlXPtrEval",
+			XMLSEC_ERRORS_R_XML_FAILED,
+			"expr=%s", 
+			xmlSecErrorsSafeString(data->expr));
+	    return(NULL);
+	}
+	break;
+    }
+    
+    if (xpathObj != NULL) {
+        nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType);
+    }
+    if(nodes == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    NULL,
+		    "xmlSecNodeSetCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    "type=%d", data->nodeSetType);
+	xmlXPathFreeObject(xpathObj);     
+	return(NULL);
+    }
+    xpathObj->nodesetval = NULL;
+    xmlXPathFreeObject(xpathObj); 
+    
+    return(nodes);
+}
+
+
+/**************************************************************************
+ *
+ * XPath data list
+ *
+ *****************************************************************************/
+#define xmlSecXPathDataListId	\
+	xmlSecXPathDataListGetKlass()
+static xmlSecPtrListId 	xmlSecXPathDataListGetKlass		(void);
+static xmlSecNodeSetPtr	xmlSecXPathDataListExecute		(xmlSecPtrListPtr dataList,
+								 xmlDocPtr doc,
+								 xmlNodePtr hereNode,
+								 xmlSecNodeSetPtr nodes);
+
+static xmlSecPtrListKlass xmlSecXPathDataListKlass = {
+    BAD_CAST "xpath-data-list",
+    NULL,						/* xmlSecPtrDuplicateItemMethod duplicateItem; */
+    (xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy,	/* xmlSecPtrDestroyItemMethod destroyItem; */
+    NULL,						/* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
+    NULL,						/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
+};
+
+static xmlSecPtrListId 
+xmlSecXPathDataListGetKlass(void) {
+    return(&xmlSecXPathDataListKlass);
+}
+
+static xmlSecNodeSetPtr	
+xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc, 
+		    	   xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) {
+    xmlSecXPathDataPtr data;
+    xmlSecNodeSetPtr res, tmp, tmp2;
+    xmlSecSize pos;
+    
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL);
+    xmlSecAssert2(doc != NULL, NULL);
+    xmlSecAssert2(hereNode != NULL, NULL);
+
+    res = nodes;
+    for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) {
+        data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos);
+	if(data == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        NULL,
+			"xmlSecPtrListGetItem",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"pos=%d", pos);
+	    if((res != NULL) && (res != nodes)) {
+		xmlSecNodeSetDestroy(res);
+	    }
+	    return(NULL);
+	}
+
+	tmp = xmlSecXPathDataExecute(data, doc, hereNode);
+	if(tmp == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecXPathDataExecute",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    if((res != NULL) && (res != nodes)) {
+		xmlSecNodeSetDestroy(res);
+	    }
+	    return(NULL);
+	}    
+
+	tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp);
+	if(tmp2 == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			NULL,
+			"xmlSecNodeSetAdd",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			"xmlSecNodeSetIntersection");
+	    if((res != NULL) && (res != nodes)) {
+		xmlSecNodeSetDestroy(res);
+	    }
+	    xmlSecNodeSetDestroy(tmp);
+	    return(NULL);
+	}
+	res = tmp2;
+    }
+
+    return(res);
+}
+
+/******************************************************************************
+ *
+ * XPath/XPointer transforms
+ *
+ * xmlSecXPathDataList is located after xmlSecTransform structure
+ * 
+ *****************************************************************************/
+#define xmlSecXPathTransformSize	\
+    (sizeof(xmlSecTransform) + sizeof(xmlSecPtrList))
+#define xmlSecXPathTransformGetDataList(transform) \
+    ((xmlSecTransformCheckSize((transform), xmlSecXPathTransformSize)) ? \
+	(xmlSecPtrListPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
+	(xmlSecPtrListPtr)NULL)
+#define xmlSecTransformXPathCheckId(transform) \
+    (xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \
+     xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \
+     xmlSecTransformCheckId((transform), xmlSecTransformXPointerId))
+
+static int 		xmlSecTransformXPathInitialize	(xmlSecTransformPtr transform);
+static void		xmlSecTransformXPathFinalize	(xmlSecTransformPtr transform);
+static int 		xmlSecTransformXPathExecute	(xmlSecTransformPtr transform,
+							 int last, 
+							 xmlSecTransformCtxPtr transformCtx);
+
+static int
+xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) {	
+    xmlSecPtrListPtr dataList;
+    int ret;
+        
+    xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(dataList != NULL, -1);
+    
+    ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecPtrListInitialize",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+static void
+xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) {
+    xmlSecPtrListPtr dataList;
+
+    xmlSecAssert(xmlSecTransformXPathCheckId(transform));
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId));
+    
+    xmlSecPtrListFinalize(dataList);
+}
+
+static int
+xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last,
+			    xmlSecTransformCtxPtr transformCtx) {
+    xmlSecPtrListPtr dataList;
+    xmlDocPtr doc;
+    
+    xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1);
+    xmlSecAssert2(transform->hereNode != NULL, -1);
+    xmlSecAssert2(transform->outNodes == NULL, -1);
+    xmlSecAssert2(last != 0, -1);
+    xmlSecAssert2(transformCtx != NULL, -1);
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1);
+
+    doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
+    xmlSecAssert2(doc != NULL, -1);
+
+    transform->outNodes = xmlSecXPathDataListExecute(dataList, doc, 
+				transform->hereNode, transform->inNodes);
+    if(transform->outNodes == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataExecute",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }    
+    return(0);
+}
+
+/******************************************************************************
+ *
+ * XPath transform
+ * 
+ *****************************************************************************/
+static int 		xmlSecTransformXPathNodeRead	(xmlSecTransformPtr transform,
+							 xmlNodePtr node,
+							 xmlSecTransformCtxPtr transformCtx);
+
+static xmlSecTransformKlass xmlSecTransformXPathKlass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),		/* xmlSecSize klassSize */
+    xmlSecXPathTransformSize,			/* xmlSecSize objSize */
+
+    xmlSecNameXPath,				/* const xmlChar* name; */
+    xmlSecXPathNs, 				/* const xmlChar* href; */
+    xmlSecTransformUsageDSigTransform,		/* xmlSecTransformUsage	usage; */
+
+    xmlSecTransformXPathInitialize,		/* xmlSecTransformInitializeMethod initialize; */
+    xmlSecTransformXPathFinalize,		/* xmlSecTransformFinalizeMethod finalize; */
+    xmlSecTransformXPathNodeRead,		/* xmlSecTransformNodeReadMethod readNode; */
+    NULL,					/* xmlSecTransformNodeWriteMethod writeNode; */
+    NULL,					/* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    NULL,					/* xmlSecTransformSetKeyMethod setKey; */
+    NULL,					/* xmlSecTransformValidateMethod validate; */
+    xmlSecTransformDefaultGetDataType,		/* xmlSecTransformGetDataTypeMethod getDataType; */
+    NULL,					/* xmlSecTransformPushBinMethod pushBin; */
+    NULL,					/* xmlSecTransformPopBinMethod popBin; */
+    xmlSecTransformDefaultPushXml,		/* xmlSecTransformPushXmlMethod pushXml; */
+    xmlSecTransformDefaultPopXml,		/* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecTransformXPathExecute,		/* xmlSecTransformExecuteMethod execute; */
+    
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformXPathGetKlass:
+ *
+ * The XPath transform evaluates given XPath expression and 
+ * intersects the result with the previous nodes set. See 
+ * http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details.
+ *
+ * Returns XPath transform id.
+ */
+EXPORT_C
+xmlSecTransformId 
+xmlSecTransformXPathGetKlass(void) {
+    return(&xmlSecTransformXPathKlass);
+}
+
+static const char xpathPattern[] = "(//. | //@* | //namespace::*)[%s]";
+static int 
+xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
+    xmlSecPtrListPtr dataList;
+    xmlSecXPathDataPtr data;
+    xmlNodePtr cur;
+    xmlChar* tmp;
+    int ret;
+
+    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(transformCtx != NULL, -1);
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
+
+    /* there is only one required node */
+    cur = xmlSecGetNextElementNode(node->children);  
+    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_INVALID_NODE,
+		    "expected=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeXPath));
+	return(-1);
+    }
+    
+    /* read information from the node */
+    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath);
+    if(data == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    
+    ret = xmlSecXPathDataNodeRead(data, cur);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+        
+    /* append it to the list */
+    ret = xmlSecPtrListAdd(dataList, data);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecPtrListAdd",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+    
+    /* create full XPath expression */
+    xmlSecAssert2(data->expr != NULL, -1);
+    tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * (xmlStrlen(data->expr) + 
+						  strlen(xpathPattern) + 1));
+    if(tmp == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    NULL,
+		    XMLSEC_ERRORS_R_MALLOC_FAILED,
+		    "size=%d",
+		    xmlStrlen(data->expr) + strlen(xpathPattern) + 1);
+    	return(-1);
+    }
+    sprintf((char*)tmp, xpathPattern, (char*)data->expr);	
+    xmlFree(data->expr);
+    data->expr = tmp;
+
+    /* set correct node set type and operation */
+    data->nodeSetOp 	= xmlSecNodeSetIntersection;
+    data->nodeSetType 	= xmlSecNodeSetNormal;
+    
+    /* check that we have nothing else */
+    cur = xmlSecGetNextElementNode(cur->next);        
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+/******************************************************************************
+ *
+ * XPath2 transform
+ * 
+ *****************************************************************************/
+static int 		xmlSecTransformXPath2NodeRead	(xmlSecTransformPtr transform,
+							 xmlNodePtr node,
+							 xmlSecTransformCtxPtr transformCtx);
+static xmlSecTransformKlass xmlSecTransformXPath2Klass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),		/* xmlSecSize klassSize */
+    xmlSecXPathTransformSize,			/* xmlSecSize objSize */
+
+    xmlSecNameXPath2,				/* const xmlChar* name; */
+    xmlSecXPath2Ns, 				/* const xmlChar* href; */
+    xmlSecTransformUsageDSigTransform,		/* xmlSecTransformUsage	usage; */
+
+    xmlSecTransformXPathInitialize,		/* xmlSecTransformInitializeMethod initialize; */
+    xmlSecTransformXPathFinalize,		/* xmlSecTransformFinalizeMethod finalize; */
+    xmlSecTransformXPath2NodeRead,		/* xmlSecTransformNodeReadMethod readNode; */
+    NULL,					/* xmlSecTransformNodeWriteMethod writeNode; */
+    NULL,					/* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    NULL,					/* xmlSecTransformSetKeyMethod setKey; */
+    NULL,					/* xmlSecTransformValidateMethod validate; */
+    xmlSecTransformDefaultGetDataType,		/* xmlSecTransformGetDataTypeMethod getDataType; */
+    NULL,					/* xmlSecTransformPushBinMethod pushBin; */
+    NULL,					/* xmlSecTransformPopBinMethod popBin; */
+    xmlSecTransformDefaultPushXml,		/* xmlSecTransformPushXmlMethod pushXml; */
+    xmlSecTransformDefaultPopXml,		/* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecTransformXPathExecute,		/* xmlSecTransformExecuteMethod execute; */
+
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformXPath2GetKlass:
+ * 
+ * The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/).
+ *
+ * Returns XPath2 transform klass.
+ */
+EXPORT_C
+xmlSecTransformId 
+xmlSecTransformXPath2GetKlass(void) {
+    return(&xmlSecTransformXPath2Klass);
+}
+
+static int 
+xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
+    xmlSecPtrListPtr dataList;
+    xmlSecXPathDataPtr data;
+    xmlNodePtr cur;
+    xmlChar* op;
+    int ret;
+
+    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(transformCtx != NULL, -1);
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
+    
+    /* There are only xpath nodes */
+    cur = xmlSecGetNextElementNode(node->children);  
+    while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) {
+        /* read information from the node */
+	data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2);
+	if(data == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+			"xmlSecXPathDataCreate",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    return(-1);
+	}
+
+        ret = xmlSecXPathDataNodeRead(data, cur);
+	if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+		        xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+			"xmlSecXPathDataNodeRead",
+		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
+			XMLSEC_ERRORS_NO_MESSAGE);
+	    xmlSecXPathDataDestroy(data);
+	    return(-1);
+	}
+    
+        /* append it to the list */
+	ret = xmlSecPtrListAdd(dataList, data);
+        if(ret < 0) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		        "xmlSecPtrListAdd",
+			XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		        XMLSEC_ERRORS_NO_MESSAGE);
+	    xmlSecXPathDataDestroy(data);
+	    return(-1);
+	}
+
+	/* set correct node set type and operation */
+	data->nodeSetType = xmlSecNodeSetTree;
+	op = xmlGetProp(cur, xmlSecAttrFilter);
+	if(op == NULL) {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+			xmlSecErrorsSafeString(xmlSecAttrFilter),
+			XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
+			"node=%s",
+			xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+	    return(-1);
+	}
+        if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) {
+    	    data->nodeSetOp = xmlSecNodeSetIntersection;
+	} else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) {
+	    data->nodeSetOp = xmlSecNodeSetSubtraction;
+	} else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) {
+	    data->nodeSetOp = xmlSecNodeSetUnion;
+	} else {
+	    xmlSecError(XMLSEC_ERRORS_HERE,
+			xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+			xmlSecErrorsSafeString(xmlSecAttrFilter),
+			XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,
+			"filter=%s", 
+			xmlSecErrorsSafeString(op));
+	    xmlFree(op);
+	    return(-1);
+	}
+	xmlFree(op);
+
+        cur = xmlSecGetNextElementNode(cur->next);  
+    }
+
+    /* check that we have nothing else */
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+/******************************************************************************
+ *
+ * XPointer transform
+ * 
+ *****************************************************************************/
+static int 		xmlSecTransformXPointerNodeRead	(xmlSecTransformPtr transform,
+							 xmlNodePtr node,
+							 xmlSecTransformCtxPtr transformCtx);
+static xmlSecTransformKlass xmlSecTransformXPointerKlass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),		/* xmlSecSize klassSize */
+    xmlSecXPathTransformSize,			/* xmlSecSize objSize */
+
+    xmlSecNameXPointer,				/* const xmlChar* name; */
+    xmlSecXPointerNs, 				/* const xmlChar* href; */
+    xmlSecTransformUsageDSigTransform,		/* xmlSecTransformUsage	usage; */
+
+    xmlSecTransformXPathInitialize,		/* xmlSecTransformInitializeMethod initialize; */
+    xmlSecTransformXPathFinalize,		/* xmlSecTransformFinalizeMethod finalize; */
+    xmlSecTransformXPointerNodeRead,		/* xmlSecTransformNodeReadMethod readNode; */
+    NULL,					/* xmlSecTransformNodeWriteMethod writeNode; */
+    NULL,					/* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    NULL,					/* xmlSecTransformSetKeyMethod setKey; */
+    NULL,					/* xmlSecTransformValidateMethod validate; */
+    xmlSecTransformDefaultGetDataType,		/* xmlSecTransformGetDataTypeMethod getDataType; */
+    NULL,					/* xmlSecTransformPushBinMethod pushBin; */
+    NULL,					/* xmlSecTransformPopBinMethod popBin; */
+    xmlSecTransformDefaultPushXml,		/* xmlSecTransformPushXmlMethod pushXml; */
+    xmlSecTransformDefaultPopXml,		/* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecTransformXPathExecute,		/* xmlSecTransformExecuteMethod execute; */
+
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformXPointerGetKlass:
+ * 
+ * The XPointer transform klass 
+ * (http://www.ietf.org/internet-drafts/draft-eastlake-xmldsig-uri-02.txt).
+ *
+ * Returns XPointer transform klass.
+ */
+EXPORT_C
+xmlSecTransformId 
+xmlSecTransformXPointerGetKlass(void) {
+    return(&xmlSecTransformXPointerKlass);
+}
+
+/**
+ * xmlSecTransformXPointerSetExpr: 
+ * @transform:		the pointer to XPointer transform.
+ * @expr:		the XPointer expression.
+ * @nodeSetType:	the type of evaluated XPointer expression.
+ * @hereNode:		the pointer to "here" node.
+ *
+ * Sets the XPointer expression for an XPointer @transform.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr, 
+			    xmlSecNodeSetType  nodeSetType, xmlNodePtr hereNode) {
+    xmlSecPtrListPtr dataList;
+    xmlSecXPathDataPtr data;
+    int ret;
+
+    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
+    xmlSecAssert2(transform->hereNode == NULL, -1);
+    xmlSecAssert2(expr != NULL, -1);
+    xmlSecAssert2(hereNode != NULL, -1);    
+
+    transform->hereNode = hereNode;
+    
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
+
+    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
+    if(data == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecXPathDataRegisterNamespaces(data, hereNode);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataRegisterNamespaces",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }    
+
+    ret = xmlSecXPathDataSetExpr(data, expr);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataSetExpr",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+    
+    /* append it to the list */
+    ret = xmlSecPtrListAdd(dataList, data);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecPtrListAdd",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+
+    /* set correct node set type and operation */
+    data->nodeSetOp 	= xmlSecNodeSetIntersection;
+    data->nodeSetType 	= nodeSetType;
+    
+    return(0);
+}
+
+static int 
+xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) {
+    xmlSecPtrListPtr dataList;
+    xmlSecXPathDataPtr data;
+    xmlNodePtr cur;
+    int ret;
+
+    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1);
+    xmlSecAssert2(node != NULL, -1);
+    xmlSecAssert2(transformCtx != NULL, -1);
+
+    dataList = xmlSecXPathTransformGetDataList(transform);
+    xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1);
+    xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1);
+
+    /* there is only one required node */
+    cur = xmlSecGetNextElementNode(node->children);  
+    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_INVALID_NODE,
+		    "expected=%s",
+		    xmlSecErrorsSafeString(xmlSecNodeXPath));
+	return(-1);
+    }
+    
+    /* read information from the node */
+    data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer);
+    if(data == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    ret = xmlSecXPathDataNodeRead(data, cur);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecXPathDataNodeRead",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+    
+    /* append it to the list */
+    ret = xmlSecPtrListAdd(dataList, data);
+    if(ret < 0) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecPtrListAdd",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlSecXPathDataDestroy(data);
+	return(-1);
+    }
+
+    /* set correct node set type and operation */
+    data->nodeSetOp 	= xmlSecNodeSetIntersection;
+    data->nodeSetType 	= xmlSecNodeSetTree;
+    
+    /* check that we have nothing else */
+    cur = xmlSecGetNextElementNode(cur->next);        
+    if(cur != NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+		    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+    return(0);
+}
+
+
+/******************************************************************************
+ *
+ * Visa3DHack transform
+ * 
+ *****************************************************************************/
+#define xmlSecVisa3DHackTransformSize	\
+    (sizeof(xmlSecTransform) + sizeof(xmlChar*))
+#define xmlSecVisa3DHackTransformGetIDPtr(transform) \
+    ((xmlSecTransformCheckSize((transform), xmlSecVisa3DHackTransformSize)) ? \
+	(xmlChar**)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
+	(xmlChar**)NULL)
+#define xmlSecTransformVisa3DHackCheckId(transform) \
+    (xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId))
+
+static int 		xmlSecTransformVisa3DHackInitialize	(xmlSecTransformPtr transform);
+static void		xmlSecTransformVisa3DHackFinalize	(xmlSecTransformPtr transform);
+static int 		xmlSecTransformVisa3DHackExecute	(xmlSecTransformPtr transform,
+								 int last, 
+								 xmlSecTransformCtxPtr transformCtx);
+
+static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),		/* xmlSecSize klassSize */
+    xmlSecVisa3DHackTransformSize,		/* xmlSecSize objSize */
+
+    BAD_CAST "Visa3DHackTransform",		/* const xmlChar* name; */
+    NULL,					/* const xmlChar* href; */
+    xmlSecTransformUsageDSigTransform,		/* xmlSecTransformUsage	usage; */
+
+    xmlSecTransformVisa3DHackInitialize,	/* xmlSecTransformInitializeMethod initialize; */
+    xmlSecTransformVisa3DHackFinalize,		/* xmlSecTransformFinalizeMethod finalize; */
+    NULL,					/* xmlSecTransformNodeReadMethod readNode; */
+    NULL,					/* xmlSecTransformNodeWriteMethod writeNode; */
+    NULL,					/* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    NULL,					/* xmlSecTransformSetKeyMethod setKey; */
+    NULL,					/* xmlSecTransformValidateMethod validate; */
+    xmlSecTransformDefaultGetDataType,		/* xmlSecTransformGetDataTypeMethod getDataType; */
+    NULL,					/* xmlSecTransformPushBinMethod pushBin; */
+    NULL,					/* xmlSecTransformPopBinMethod popBin; */
+    xmlSecTransformDefaultPushXml,		/* xmlSecTransformPushXmlMethod pushXml; */
+    xmlSecTransformDefaultPopXml,		/* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecTransformVisa3DHackExecute,		/* xmlSecTransformExecuteMethod execute; */
+
+    NULL,					/* void* reserved0; */
+    NULL,					/* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformVisa3DHackGetKlass:
+ * 
+ * The Visa3DHack transform klass. The only reason why we need this 
+ * is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows 
+ * something like "#12345" in the URI attribute. 
+ *
+ * Returns Visa3DHack transform klass.
+ */
+EXPORT_C
+xmlSecTransformId 
+xmlSecTransformVisa3DHackGetKlass(void) {
+    return(&xmlSecTransformVisa3DHackKlass);
+}
+
+/**
+ * xmlSecTransformVisa3DHackSetID:
+ * @transform:		the pointer to Visa3DHack transform.
+ * @id:			the ID value.
+ *
+ * Sets the ID value for an Visa3DHack @transform.
+ *
+ * Returns 0 on success or a negative value if an error occurs.
+ */
+EXPORT_C
+int 
+xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) {
+    xmlChar** idPtr;
+    
+    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1);
+    xmlSecAssert2(id != NULL, -1);
+
+    idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
+    xmlSecAssert2(idPtr != NULL, -1);
+    xmlSecAssert2((*idPtr) == NULL, -1);
+
+    (*idPtr) = xmlStrdup(id);
+    if((*idPtr) == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlStrdup",
+		    XMLSEC_ERRORS_R_MALLOC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	return(-1);
+    }
+
+    return(0);
+}
+
+static int
+xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) {	
+    xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
+
+    return(0);
+}
+
+static void
+xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) {
+    xmlChar** idPtr;
+
+    xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform));
+
+    idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
+    xmlSecAssert(idPtr != NULL);
+    
+    if((*idPtr) != NULL) {
+	xmlFree((*idPtr));
+    }
+    (*idPtr) = NULL;
+}
+
+static int
+xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last,
+			    xmlSecTransformCtxPtr transformCtx) {
+    xmlChar** idPtr;
+    xmlDocPtr doc;
+    xmlAttrPtr attr;
+    xmlNodeSetPtr nodeSet;
+    
+    xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1);
+    xmlSecAssert2(transform->outNodes == NULL, -1);
+    xmlSecAssert2(last != 0, -1);
+    xmlSecAssert2(transformCtx != NULL, -1);
+
+    idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform);
+    xmlSecAssert2(idPtr != NULL, -1);
+    xmlSecAssert2((*idPtr) != NULL, -1);
+
+    doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc;
+    xmlSecAssert2(doc != NULL, -1);
+
+    attr = xmlGetID(doc, (*idPtr));
+    if((attr == NULL) || (attr->parent == NULL)) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlGetID",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "id=\"%s\"",
+		    xmlSecErrorsSafeString((*idPtr)));
+	return(-1);
+    }    
+
+    nodeSet = xmlXPathNodeSetCreate(attr->parent);
+    if(nodeSet == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlXPathNodeSetCreate",
+		    XMLSEC_ERRORS_R_XML_FAILED,
+		    "id=\"%s\"",
+		    xmlSecErrorsSafeString((*idPtr)));
+	return(-1);
+    }    
+
+    transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments);
+    if(transform->outNodes == NULL) {
+	xmlSecError(XMLSEC_ERRORS_HERE,
+		    xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+		    "xmlSecNodeSetCreate",
+		    XMLSEC_ERRORS_R_XMLSEC_FAILED,
+		    XMLSEC_ERRORS_NO_MESSAGE);
+	xmlXPathFreeNodeSet(nodeSet);
+	return(-1);
+    }    
+    return(0);
+}
+
+
+