/*###################################################################################
#
# Embperl - Copyright (c) 1997-2008 Gerald Richter / ecos gmbh www.ecos.de
# Embperl - Copyright (c) 2008-2015 Gerald Richter
# Embperl - Copyright (c) 2015-2023 actevy.io
#
# You may distribute under the terms of either the GNU General Public
# License or the Artistic License, as specified in the Perl README file.
# For use with Apache httpd and mod_perl, see also Apache copyright.
#
# THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
###################################################################################*/
#include "../ep.h"
#include "../epmacro.h"
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
// #include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxslt/xsltconfig.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libxslt/imports.h>
#ifdef WIN32
extern __declspec( dllimport ) int xmlLoadExtDtdDefaultValue;
#else
extern int xmlLoadExtDtdDefaultValue;
#endif
/* ------------------------------------------------------------------------ */
/* */
/* iowrite */
/* */
/* output callback */
/* */
/* ------------------------------------------------------------------------ */
static int iowrite (void *context,
const char *buffer,
int len)
{
return owrite ((tReq *)context, buffer, len) ;
}
/* ------------------------------------------------------------------------ */
/* */
/* embperl_LibXSLT_Text2Text */
/* */
/* Do an XSL transformation using LibXSLT. Input and Output is Text. */
/* The stylesheet is directly read from disk */
/* */
/* in pReqParameter Parameter for request */
/* xsltparameter Hash which is passed as parameters to libxslt */
/* xsltstylesheet filename of stylsheet */
/* pSource XML source in memory */
/* */
/* ------------------------------------------------------------------------ */
int embperl_LibXSLT_Text2Text (/*in*/ tReq * r,
/*in*/ HV * pReqParameter,
/*in*/ SV * pSource)
{
epTHX_
xsltStylesheetPtr cur = NULL;
xmlDocPtr doc ;
xmlDocPtr res;
HE * pEntry ;
HV * pParam ;
SV * * ppSV ;
char * pKey ;
SV * pValue ;
STRLEN len ;
I32 l ;
int n ;
const char * * pParamArray ;
const char * sStylesheet ;
char * p ;
xmlOutputBufferPtr obuf ;
sStylesheet = GetHashValueStr (aTHX_ pReqParameter, "xsltstylesheet", r -> Component.Config.sXsltstylesheet) ;
if (!sStylesheet)
{
strncpy (r -> errdat1, "XSLT", sizeof (r -> errdat1)) ;
strncpy (r -> errdat2, "No stylesheet given", sizeof (r -> errdat2)) ;
return 9999 ;
}
ppSV = hv_fetch (pReqParameter, "xsltparameter", sizeof("xsltparameter") - 1, 0) ;
if (ppSV && *ppSV)
{
if (!SvROK (*ppSV) || SvTYPE ((SV *)(pParam = (HV *)SvRV (*ppSV))) != SVt_PVHV)
{
strncpy (r -> errdat1, "XSLT", sizeof (r -> errdat1)) ;
sprintf (r -> errdat2, "%s", "xsltparameter") ;
return rcNotHashRef ;
}
n = 0 ;
hv_iterinit (pParam) ;
while ((pEntry = hv_iternext (pParam)))
{
n++ ;
}
if (!(pParamArray = _malloc(r, sizeof (const char *) * (n + 1) * 2)))
return rcOutOfMemory ;
n = 0 ;
hv_iterinit (pParam) ;
while ((pEntry = hv_iternext (pParam)))
{
pKey = hv_iterkey (pEntry, &l) ;
pValue = hv_iterval (pParam, pEntry) ;
pParamArray[n++] = pKey ;
pParamArray[n++] = SvPV (pValue, len) ;
}
pParamArray[n++] = NULL ;
}
else
{
pParamArray = NULL ;
}
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
/* xmlSetGenericErrorFunc (stderr, NULL) ; */
cur = xsltParseStylesheetFile((const xmlChar *)sStylesheet);
p = SvPV (pSource, len) ;
doc = xmlParseMemory(p, len);
res = xsltApplyStylesheet(cur, doc, pParamArray);
obuf = xmlOutputBufferCreateIO (iowrite, NULL, r, NULL) ;
xsltSaveResultTo(obuf, res, cur);
xsltFreeStylesheet(cur);
xmlFreeDoc(res);
xmlFreeDoc(doc);
xsltCleanupGlobals();
xmlCleanupParser();
return(0);
}
/*! Provider that reads compiles LibXSLT stylesheet */
typedef struct tProviderLibXSLTXSL
{
tProvider Provider ;
} tProviderLibXSLTXSL ;
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXSL_New */
/* */
/*!
* \_en
* Creates a new LibXSLT stylesheet provider and fills it with data from the hash pParam
* The resulting provider is put into the cache structure
*
* @param r Embperl request record
* @param pItem CacheItem which holds the output of the provider
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* stylesheet filename or provider for the
* stylesheet
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @return error code
* \endif
*
* \_de
* Erzeugt einen neue Provider für LibXSLT Stylesheets. Der ein Zeiger
* auf den resultierenden Provider wird in die Cachestrutr eingefügt
*
* @param r Embperl request record
* @param pItem CacheItem welches die Ausgabe des Providers
* speichert
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* stylesheet dateiname oder provider für das
* stylesheet
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXSL_New (/*in*/ req * r,
/*in*/ tCacheItem * pItem,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex)
{
int rc ;
if ((rc = Provider_NewDependOne (r, sizeof(tProviderLibXSLTXSL), "stylesheet", pItem, pProviderClass, pProviderParam, pParam, nParamIndex)) != ok)
return rc ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXSL_ErrorFunc */
/* */
/*!
* \_en
* Callback which is called when an error occurs
* \endif
*
* \_de
* Callback das im Fehlerfall aufgerufen wird
* \endif
*/
static void ProviderLibXSLT_ErrorFunc (void *ctx, const char *msg, ...)
{
tReq * r ;
SV * pSV ;
STRLEN l ;
va_list args ;
dTHX ;
r = CurrReq ; /* we cannot use ctx to pass the request, because it's not thread safe */
pSV = newSV (256) ;
va_start(args, msg) ;
sv_vsetpvfn(pSV, msg, strlen(msg), &args, Null(SV**), 0, Null(bool*)) ;
va_end(args) ;
if (!r)
PerlIO_puts (PerlIO_stderr(), SvPV(pSV, l)) ;
else
{
char * p = SvPV(pSV, l) ;
if (l && p[l-1] == '\n')
p[l-1] = '\0' ;
strncpy (r -> errdat1, p, sizeof (r -> errdat1) - 1) ;
LogError (r, rcLibXSLTError) ;
}
SvREFCNT_dec(pSV) ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_ExternalEnityLoader */
/* */
/*!
* \_en
* Callback which is called when to load an external entity. It does
* an EMbperl path search before calling libxmls function to do the work.
* \endif
*
* \_de
* Callback das aufgerufen wird um externe Entities zu laden. Es wird eine
* Suche im Embperl Pfad ausgeführt um danach libxml das eigentliche
* Laden zu überlassen.
* \endif
*/
static xmlExternalEntityLoader pCurrentExternalEntityLoader ;
static
xmlParserInputPtr
ProviderLibXSLT_ExternalEnityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt)
{
tReq * r ;
char * sFile ;
dTHX ;
r = CurrReq ;
sFile = embperl_PathSearch (r, r -> pPool, URL, r -> Component.nPathNdx) ;
if (sFile && pCurrentExternalEntityLoader)
return (*pCurrentExternalEntityLoader)(sFile, ID, ctxt) ;
else
{
strncpy (r -> errdat1, URL, sizeof(r -> errdat1) - 1) ;
LogError (r, rcNotFound) ;
return NULL ;
}
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXSL_AppendKey */
/* */
/*!
* \_en
* Append it's key to the keystring. If it depends on anything it must
* call Cache_AppendKey for any dependency.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* stylesheet filename or provider for the
* stylesheet
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @param pKey Key to which string should be appended
* @return error code
* \endif
*
* \_de
* Hängt ein eigenen Schlüssel an den Schlüsselstring an. Wenn irgednwelche
* Abhänigkeiten bestehen, muß Cache_AppendKey für alle Abhänigkeiten aufgerufen
* werden.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* stylesheet dateiname oder provider für das
* stylesheet
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @param pKey Schlüssel zu welchem hinzugefügt wird
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXSL_AppendKey (/*in*/ req * r,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex,
/*i/o*/ SV * pKey)
{
epTHX_
int rc ;
if ((rc = Cache_AppendKey (r, pProviderParam, "stylesheet", pParam, nParamIndex, pKey)) != ok)
return rc;
sv_catpv (pKey, "*libxslt-compile-xsl") ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXSL_GetContentPtr */
/* */
/*!
* \_en
* Get the whole content from the provider.
* This gets the stylesheet and compiles it
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Returns the content
* @param bUseCache Set if the content should not recomputed
* @return error code
* \endif
*
* \_de
* Holt den gesamt Inhalt vom Provider.
* Die Funktion holt sich das Stylesheet und kompiliert es
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Liefert den Inhalt
* @param bUseCache Gesetzt wenn der Inhalt nicht neu berechnet werden soll
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXSL_GetContentPtr (/*in*/ req * r,
/*in*/ tProvider * pProvider,
/*in*/ void * * pData,
/*in*/ bool bUseCache)
{
epTHX_
int rc ;
char * p ;
STRLEN len ;
SV * pSource ;
xsltStylesheetPtr cur ;
xmlDocPtr doc ;
xmlExternalEntityLoader pLoader ;
tCacheItem * pFileCache = Cache_GetDependency(r, pProvider -> pCache, 0) ;
if ((rc = Cache_GetContentSV (r, pFileCache, &pSource, bUseCache)) != ok)
return rc ;
if (!bUseCache)
{
p = SvPV (pSource, len) ;
if (p == NULL || len == 0)
{
strncpy (r -> errdat1, "LibXSLT XML stylesheet", sizeof (r -> errdat1)) ;
return rcMissingInput ;
}
r -> Component.pCurrPos = NULL ;
r -> Component.nSourceline = 1 ;
r -> Component.pSourcelinePos = NULL ;
r -> Component.pLineNoCurrPos = NULL ;
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlSetGenericErrorFunc (NULL, &ProviderLibXSLT_ErrorFunc) ;
pLoader = xmlGetExternalEntityLoader () ;
if (pLoader != &ProviderLibXSLT_ExternalEnityLoader)
pCurrentExternalEntityLoader = pLoader ;
xmlSetExternalEntityLoader (&ProviderLibXSLT_ExternalEnityLoader) ;
if ((doc = xmlParseMemory(p, len)) == NULL)
{
Cache_ReleaseContent (r, pFileCache) ;
strncpy (r -> errdat1, "XSL parse", sizeof (r -> errdat1)) ;
return rcLibXSLTError ;
}
;
if ((cur = xsltParseStylesheetDoc(doc)) == NULL)
{
xmlFreeDoc(doc) ;
Cache_ReleaseContent (r, pFileCache) ;
strncpy (r -> errdat1, "XSL compile", sizeof (r -> errdat1)) ;
return rcLibXSLTError ;
}
*pData = (void *)cur ;
}
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXSL_FreeContent */
/* */
/*!
* \_en
* Free the cached data
*
* @param r Embperl request record
* @param pProvider The provider record
* @return error code
* \endif
*
* \_de
* Gibt die gecachten Daten frei
*
* @param r Embperl request record
* @param pProvider The provider record
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXSL_FreeContent(/*in*/ req * r,
/*in*/ tCacheItem * pItem)
{
xsltStylesheetPtr pCompiledStylesheet ;
pCompiledStylesheet = (xsltStylesheetPtr)pItem -> pData ;
if (pCompiledStylesheet)
xsltFreeStylesheet(pCompiledStylesheet) ;
return ok ;
}
/* ------------------------------------------------------------------------ */
static tProviderClass ProviderClassLibXSLTXSL =
{
"text/*",
&ProviderLibXSLTXSL_New,
&ProviderLibXSLTXSL_AppendKey,
NULL,
NULL,
&ProviderLibXSLTXSL_GetContentPtr,
NULL,
&ProviderLibXSLTXSL_FreeContent,
NULL,
} ;
/*! Provider that reads compiles LibXSLT xml source */
typedef struct tProviderLibXSLTXML
{
tProvider Provider ;
} tProviderLibXSLTXML ;
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXML_New */
/* */
/*!
* \_en
* Creates a new LibXSLT xml source provider and fills it with data from the hash pParam
* The resulting provider is put into the cache structure
*
* @param r Embperl request record
* @param pItem CacheItem which holds the output of the provider
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @return error code
* \endif
*
* \_de
* Erzeugt einen neue Provider für LibXSLT XML Quellen. Der ein Zeiger
* auf den resultierenden Provider wird in die Cachestrutr eingefügt
*
* @param r Embperl request record
* @param pItem CacheItem welches die Ausgabe des Providers
* speichert
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXML_New (/*in*/ req * r,
/*in*/ tCacheItem * pItem,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex)
{
int rc ;
if ((rc = Provider_NewDependOne (r, sizeof(tProviderLibXSLTXML), "source", pItem, pProviderClass, pProviderParam, pParam, nParamIndex)) != ok)
return rc ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderFile_AppendKey */
/* */
/*!
* \_en
* Append it's key to the keystring. If it depends on anything it must
* call Cache_AppendKey for any dependency.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @param pKey Key to which string should be appended
* @return error code
* \endif
*
* \_de
* Hängt ein eigenen Schlüssel an den Schlüsselstring an. Wenn irgednwelche
* Abhänigkeiten bestehen, muß Cache_AppendKey für alle Abhänigkeiten aufgerufen
* werden.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @param pKey Schlüssel zu welchem hinzugefügt wird
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXML_AppendKey (/*in*/ req * r,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex,
/*i/o*/ SV * pKey)
{
epTHX_
int rc ;
if ((rc = Cache_AppendKey (r, pProviderParam, "source", pParam, nParamIndex, pKey)) != ok)
return rc;
sv_catpv (pKey, "*libxslt-parse-xml") ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXML_GetContentPtr */
/* */
/*!
* \_en
* Get the whole content from the provider.
* This gets the stylesheet and compiles it
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Returns the content
* @param bUseCache Set if the content should not recomputed
* @return error code
* \endif
*
* \_de
* Holt den gesamt Inhalt vom Provider.
* Die Funktion holt sich das Stylesheet und kompiliert es
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Liefert den Inhalt
* @param bUseCache Gesetzt wenn der Inhalt nicht neu berechnet werden soll
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXML_GetContentPtr (/*in*/ req * r,
/*in*/ tProvider * pProvider,
/*in*/ void * * pData,
/*in*/ bool bUseCache)
{
epTHX_
int rc ;
char * p ;
STRLEN len ;
SV * pSource ;
xmlDocPtr doc ;
xmlExternalEntityLoader pLoader ;
tCacheItem * pFileCache = Cache_GetDependency(r, pProvider -> pCache, 0) ;
if ((rc = Cache_GetContentSV (r, pFileCache, &pSource, bUseCache)) != ok)
return rc ;
if (!bUseCache)
{
p = SvPV (pSource, len) ;
if (p == NULL || len == 0)
{
strncpy (r -> errdat1, "LibXSLT XML source", sizeof (r -> errdat1)) ;
return rcMissingInput ;
}
r -> Component.pCurrPos = NULL ;
r -> Component.nSourceline = 1 ;
r -> Component.pSourcelinePos = NULL ;
r -> Component.pLineNoCurrPos = NULL ;
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlSetGenericErrorFunc (NULL, &ProviderLibXSLT_ErrorFunc) ;
pLoader = xmlGetExternalEntityLoader () ;
if (pLoader != &ProviderLibXSLT_ExternalEnityLoader)
pCurrentExternalEntityLoader = pLoader ;
xmlSetExternalEntityLoader (&ProviderLibXSLT_ExternalEnityLoader) ;
if ((doc = xmlParseMemory(p, len)) == NULL)
{
Cache_ReleaseContent (r, pFileCache) ;
strncpy (r -> errdat1, "XML parse", sizeof (r -> errdat1)) ;
return rcLibXSLTError ;
}
*pData = (void *)doc ;
}
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLTXML_FreeContent */
/* */
/*!
* \_en
* Free the cached data
*
* @param r Embperl request record
* @param pProvider The provider record
* @return error code
* \endif
*
* \_de
* Gibt die gecachten Daten frei
*
* @param r Embperl request record
* @param pProvider The provider record
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLTXML_FreeContent(/*in*/ req * r,
/*in*/ tCacheItem * pItem)
{
if (pItem -> pData)
{
xmlFreeDoc((xmlDocPtr)pItem -> pData) ;
}
return ok ;
}
/* ------------------------------------------------------------------------ */
static tProviderClass ProviderClassLibXSLTXML =
{
"text/*",
&ProviderLibXSLTXML_New,
&ProviderLibXSLTXML_AppendKey,
NULL,
NULL,
&ProviderLibXSLTXML_GetContentPtr,
NULL,
&ProviderLibXSLTXML_FreeContent,
NULL,
} ;
/*! Provider that reads compiles LibXSLT stylesheet */
typedef struct tProviderLibXSLT
{
tProvider Provider ;
SV * pOutputSV ;
const char * * pParamArray ;
} tProviderLibXSLT ;
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_iowrite */
/* */
/* output callback */
/* */
/* ------------------------------------------------------------------------ */
struct iowrite
{
tProviderLibXSLT * pProvider ;
tReq * pReq ;
} ;
static int ProviderLibXSLT_iowrite (void *context,
const char *buffer,
int len)
{
tReq * r = ((struct iowrite *)context) -> pReq ;
epTHX_
sv_catpvn (((struct iowrite *)context) -> pProvider -> pOutputSV, (char *)buffer, len) ;
return len ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_New */
/* */
/*!
* \_en
* Creates a new LibXSLT provider and fills it with data from the hash pParam
* The resulting provider is put into the cache structure
*
* @param r Embperl request record
* @param pItem CacheItem which holds the output of the provider
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* stylesheet filename or provider for the
* stylesheet
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @return error code
* \endif
*
* \_de
* Erzeugt einen neue Provider für LibXSLT. Der ein Zeiger
* auf den resultierenden Provider wird in die Cachestrutr eingefügt
*
* @param r Embperl request record
* @param pItem CacheItem welches die Ausgabe des Providers
* speichert
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* stylesheet dateiname oder provider für das
* stylesheet
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
int ProviderLibXSLT_New (/*in*/ req * r,
/*in*/ tCacheItem * pItem,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex)
{
int rc ;
if ((rc = Provider_NewDependOne (r, sizeof(tProviderLibXSLT), "source", pItem, pProviderClass, pProviderParam, pParam, nParamIndex)) != ok)
return rc ;
if ((rc = Provider_AddDependOne (r, pItem -> pProvider, "stylesheet", pItem, pProviderClass, pProviderParam, NULL, 0)) != ok)
return rc ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderFile_AppendKey */
/* */
/*!
* \_en
* Append it's key to the keystring. If it depends on anything it must
* call Cache_AppendKey for any dependency.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash of this Providers
* stylesheet filename or provider for the
* stylesheet
* @param pParam All Parameters
* @param nParamIndex If pParam is an AV, this parameter gives the index into the Array
* @param pKey Key to which string should be appended
* @return error code
* \endif
*
* \_de
* Hängt ein eigenen Schlüssel an den Schlüsselstring an. Wenn irgednwelche
* Abhänigkeiten bestehen, muß Cache_AppendKey für alle Abhänigkeiten aufgerufen
* werden.
*
* @param r Embperl request record
* @param pProviderClass Provider class record
* @param pProviderParam Parameter Hash dieses Providers
* stylesheet dateiname oder provider für das
* stylesheet
* @param pParam Parameter insgesamt
* @param nParamIndex Wenn pParam ein AV ist, gibt dieser Parameter den Index an
* @param pKey Schlüssel zu welchem hinzugefügt wird
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLT_AppendKey (/*in*/ req * r,
/*in*/ tProviderClass * pProviderClass,
/*in*/ HV * pProviderParam,
/*in*/ SV * pParam,
/*in*/ IV nParamIndex,
/*i/o*/ SV * pKey)
{
epTHX_
int rc ;
if ((rc = Cache_AppendKey (r, pProviderParam, "source", pParam, nParamIndex, pKey)) != ok)
return rc;
if ((rc = Cache_AppendKey (r, pProviderParam, "stylesheet", NULL, 0, pKey)) != ok)
return rc;
sv_catpv (pKey, "*libxslt") ;
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_UpdateParam */
/* */
/*!
* \_en
* Update the parameter of the provider
*
* @param r Embperl request record
* @param pProvider Provider record
* @param pParam Parameter Hash
* param hash with parameter
* @param pKey Key to which string should be appended
* @return error code
* \endif
*
* \_de
* Aktualisiert die Parameter des Providers
*
* @param r Embperl request record
* @param pProvider Provider record
* @param pParam Parameter Hash
* param hash mit parametern
* @param pKey Schlüssel zu welchem hinzugefügt wird
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLT_UpdateParam(/*in*/ req * r,
/*in*/ tProvider * pProvider,
/*in*/ HV * pParam)
{
epTHX_
int rc ;
HV * pParamHV ;
HE * pEntry ;
char * pKey ;
SV * pValue ;
STRLEN len ;
I32 l ;
int n ;
const char * * pParamArray ;
if ((rc = GetHashValueHREF (r, pParam, "param", &pParamHV)) != ok)
{
pParamHV = r -> Component.Param.pXsltParam ;
}
if (((tProviderLibXSLT *)pProvider) -> pParamArray)
{
free ((void *)(((tProviderLibXSLT *)pProvider) -> pParamArray)) ;
((tProviderLibXSLT *)pProvider) -> pParamArray = NULL ;
}
if (pParamHV)
{
n = hv_iterinit (pParamHV) ;
if (!(pParamArray = malloc(sizeof (const char *) * (n + 1) * 2)))
return rcOutOfMemory ;
n = 0 ;
while ((pEntry = hv_iternext (pParamHV)))
{
pKey = hv_iterkey (pEntry, &l) ;
pValue = hv_iterval (pParamHV, pEntry) ;
pParamArray[n++] = pKey ;
pParamArray[n++] = SvPV (pValue, len) ;
}
pParamArray[n++] = NULL ;
((tProviderLibXSLT *)pProvider) -> pParamArray = pParamArray ;
}
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_GetContentSV */
/* */
/*!
* \_en
* Get the whole content from the provider.
* This gets the stylesheet and compiles it
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Returns the content
* @param bUseCache Set if the content should not recomputed
* @return error code
* \endif
*
* \_de
* Holt den gesamt Inhalt vom Provider.
* Die Funktion holt sich das Stylesheet und kompiliert es
*
* @param r Embperl request record
* @param pProvider The provider record
* @param pData Liefert den Inhalt
* @param bUseCache Gesetzt wenn der Inhalt nicht neu berechnet werden soll
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLT_GetContentSV (/*in*/ req * r,
/*in*/ tProvider * pProvider,
/*in*/ SV * * pData,
/*in*/ bool bUseCache)
{
epTHX_
int rc ;
xsltStylesheetPtr cur ;
xmlDocPtr doc ;
xmlDocPtr res;
xmlOutputBufferPtr obuf ;
const xmlChar *encoding;
struct iowrite iowrite ;
tCacheItem * pSrcCache = Cache_GetDependency(r, pProvider -> pCache, 0) ;
tCacheItem * pXSLCache = Cache_GetDependency(r, pProvider -> pCache, 1) ;
if ((rc = Cache_GetContentPtr (r, pSrcCache, (void * *)&doc, bUseCache)) != ok)
return rc ;
if ((rc = Cache_GetContentPtr (r, pXSLCache, (void * *)&cur, bUseCache)) != ok)
return rc ;
if (!bUseCache)
{
if (((tProviderLibXSLT *)pProvider) -> pOutputSV)
SvREFCNT_dec (((tProviderLibXSLT *)pProvider) -> pOutputSV) ;
((tProviderLibXSLT *)pProvider) -> pOutputSV = newSVpv("", 0) ;
r -> Component.pCurrPos = NULL ;
r -> Component.nSourceline = 1 ;
r -> Component.pSourcelinePos = NULL ;
r -> Component.pLineNoCurrPos = NULL ;
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlSetGenericErrorFunc (NULL, &ProviderLibXSLT_ErrorFunc) ;
res = xsltApplyStylesheet(cur, doc, ((tProviderLibXSLT *)pProvider) -> pParamArray);
if(res == NULL)
{
strncpy (r -> errdat1, "XSLT", sizeof (r -> errdat1)) ;
return rcLibXSLTError ;
}
iowrite.pProvider = (tProviderLibXSLT *)pProvider ;
iowrite.pReq = r ;
XSLT_GET_IMPORT_PTR(encoding, cur, encoding)
if (encoding != NULL)
{
xmlCharEncodingHandlerPtr encoder;
encoder = xmlFindCharEncodingHandler((char *)encoding);
if ((encoder != NULL) &&
(xmlStrEqual((const xmlChar *)encoder->name,
(const xmlChar *) "UTF-8")))
encoder = NULL;
obuf = xmlOutputBufferCreateIO (ProviderLibXSLT_iowrite, NULL, &iowrite, encoder) ;
}
else
obuf = xmlOutputBufferCreateIO (ProviderLibXSLT_iowrite, NULL, &iowrite, NULL) ;
if(obuf == NULL)
{
strncpy (r -> errdat1, "Cannot allocate output buffer", sizeof (r -> errdat1)) ;
return rcLibXSLTError ;
}
xsltSaveResultTo(obuf, res, cur);
xmlFreeDoc(res);
xmlOutputBufferClose (obuf) ;
*pData = ((tProviderLibXSLT *)pProvider) -> pOutputSV ;
SvREFCNT_inc(*pData) ;
}
return ok ;
}
/* ------------------------------------------------------------------------ */
/* */
/* ProviderLibXSLT_FreeContent */
/* */
/*!
* \_en
* Free the cached data
*
* @param r Embperl request record
* @param pProvider The provider record
* @return error code
* \endif
*
* \_de
* Gibt die gecachten Daten frei
*
* @param r Embperl request record
* @param pProvider The provider record
* @return Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
static int ProviderLibXSLT_FreeContent(/*in*/ req * r,
/*in*/ tCacheItem * pItem)
{
epTHX_
tProviderLibXSLT * pProvider = ((tProviderLibXSLT *)pItem -> pProvider) ;
if (pProvider -> pOutputSV)
{
SvREFCNT_dec (pProvider -> pOutputSV) ;
pProvider -> pOutputSV = NULL ;
}
/*
if (pProvider -> pParamArray)
{
free (pProvider -> pParamArray) ;
pProvider -> pParamArray = NULL ;
}
*/
return ok ;
}
/* ------------------------------------------------------------------------ */
static tProviderClass ProviderClassLibXSLT =
{
"text/*",
&ProviderLibXSLT_New,
&ProviderLibXSLT_AppendKey,
&ProviderLibXSLT_UpdateParam,
&ProviderLibXSLT_GetContentSV,
NULL,
NULL,
&ProviderLibXSLT_FreeContent,
NULL,
} ;
/* ------------------------------------------------------------------------ */
int embperl_LibXSLT_Init ()
{
Cache_AddProviderClass ("libxslt-compile-xsl", &ProviderClassLibXSLTXSL) ;
Cache_AddProviderClass ("libxslt-parse-xml", &ProviderClassLibXSLTXML) ;
Cache_AddProviderClass ("libxslt", &ProviderClassLibXSLT) ;
return ok ;
}