/*################################################################################### # # 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 ; }