/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.44 from the
 * contents of LibXSLT.xs. Do not edit this file, edit LibXSLT.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "LibXSLT.xs"
/* $Id$ */
/*
 * This is free software, you may use it and distribute it under the same terms as
 * Perl itself.
 *
 * Copyright 2001-2009 AxKit.com Ltd.
*/

#ifdef __cplusplus
extern "C" {
#endif
#include <libxslt/xsltconfig.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libxslt/imports.h>
#include <libxslt/extensions.h>
#include <libxslt/security.h>
#ifdef HAVE_EXSLT
#include <libexslt/exslt.h>
#include <libexslt/exsltconfig.h>
#endif
#include <libxml/xmlmemory.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/xpathInternals.h>
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "perl-libxml-mm.h"
#include "ppport.h"
#ifdef __cplusplus
}
#endif

#define SET_CB(cb, fld) \
    RETVAL = cb ? newSVsv(cb) : &PL_sv_undef;\
    if (SvOK(fld)) {\
        if (cb) {\
            if (cb != fld) {\
                sv_setsv(cb, fld);\
            }\
        }\
        else {\
            cb = newSVsv(fld);\
        }\
    }\
    else {\
        if (cb) {\
            SvREFCNT_dec(cb);\
            cb = NULL;\
        }\
    }

#define SET_CB2(cb, fld) cb=fld;

static SV * LibXSLT_debug_cb = NULL;
static HV * LibXSLT_HV_allCallbacks = NULL;
SV* x_PROXY_NODE_REGISTRY_MUTEX = NULL;

void
LibXSLT_free_all_callbacks(void)
{
    if (LibXSLT_debug_cb) {
        SvREFCNT_dec(LibXSLT_debug_cb);
        LibXSLT_debug_cb = NULL;
    }
}

int
LibXSLT_iowrite_scalar(void * context, const char * buffer, int len)
{
    SV * scalar;

    scalar = (SV *)context;

    sv_catpvn(scalar, (const char*)buffer, len);

    return len;
}

int
LibXSLT_ioclose_scalar(void * context)
{
    return 0;
}

int
LibXSLT_iowrite_fh(void * context, const char * buffer, int len)
{
    dSP;

    SV * ioref;
    SV * tbuff;
    SV * results;
    int cnt;

    ENTER;
    SAVETMPS;

    ioref = (SV *)context;

    tbuff = newSVpvn((char*)buffer, len);

    PUSHMARK(SP);
    EXTEND(SP, 2);
    PUSHs(ioref);
    PUSHs(sv_2mortal(tbuff));
    PUTBACK;

    cnt = call_method("print", G_SCALAR | G_EVAL);

    SPAGAIN;

    if (cnt != 1) {
        croak("fh->print() method call failed");
    }

    results = POPs;

    if (!SvOK(results)) {
        croak("print to fh failed");
    }

    PUTBACK;

    FREETMPS;
    LEAVE;

    return len;
}

int
LibXSLT_ioclose_fh(void * context)
{
    return 0; /* we let Perl close the FH */
}

void
LibXSLT_error_handler_ctx(void * ctxt, const char * msg, ...)
{
	va_list args;
	SV * saved_error = (SV *) ctxt;

	/* If saved_error is null we croak with the error */
	if( saved_error == NULL ) {
		SV * sv = sv_2mortal(newSV(0));
		va_start(args, msg);
   		sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
   		va_end(args);
		croak("%s", SvPV_nolen(sv));
	/* Otherwise, save the error */
	} else {
		va_start(args, msg);
   		sv_vcatpvfn(saved_error, msg, strlen(msg), &args, NULL, 0, NULL);
		va_end(args);
	}
}

static void
LibXSLT_init_error_ctx(SV * saved_error)
{
  xmlSetGenericErrorFunc((void *) saved_error, (xmlGenericErrorFunc) LibXSLT_error_handler_ctx);
  xsltSetGenericErrorFunc((void *) saved_error, (xmlGenericErrorFunc) LibXSLT_error_handler_ctx);
}

static void
LibXSLT_report_error_ctx(SV * saved_error, int warn_only)
{
    if( 0 < SvCUR( saved_error ) ) {
      if ( warn_only ) {
	warn("%s", SvPV_nolen(saved_error));
      } else {
	croak("%s", SvPV_nolen(saved_error));
      }
    }
}

void
LibXSLT_debug_handler(void * ctxt, const char * msg, ...)
{
    dSP;

    va_list args;
    SV * sv;

    sv = NEWSV(0,512);

    va_start(args, msg);
    sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
    va_end(args);

    if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
        int cnt = 0;

        ENTER;
        SAVETMPS;

        PUSHMARK(SP);
        EXTEND(SP, 1);
        PUSHs(sv);
        PUTBACK;

        cnt = call_sv(LibXSLT_debug_cb, G_SCALAR | G_EVAL);

        SPAGAIN;

        if (cnt != 1) {
            croak("debug handler call failed");
        }

        PUTBACK;

        FREETMPS;
        LEAVE;
    }

    SvREFCNT_dec(sv);
}

static void
LibXSLT__function (xmlXPathParserContextPtr ctxt, int nargs, SV *perl_function) {
	SV * owner_doc;
    xmlXPathObjectPtr obj,ret;
    xmlNodeSetPtr nodelist = NULL;
    int count;
    SV * perl_dispatch;
    int i;
    STRLEN len;
    SV * perl_result;
    char * tmp_string;
    STRLEN n_a;
    double tmp_double;
    int tmp_int;
    AV * array_result;
    xmlNodePtr tmp_node, tmp_node1, tmp_node2 = NULL;
    xmlDocPtr container = NULL;
    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
    dSP;

    ENTER;
    SAVETMPS;
    PUSHMARK(SP);

    XPUSHs(perl_function);

	/* clone all of the arguments into a new owning document */
	owner_doc = x_PmmNodeToSv(INT2PTR(xmlNodePtr,xmlNewDoc(NULL)), NULL);
	XPUSHs( sv_2mortal(owner_doc) );

    /* set up call to perl dispatcher function */
    for (i = 0; i < nargs; i++) {
        obj = (xmlXPathObjectPtr)valuePop(ctxt);
        switch (obj->type) {
        case XPATH_NODESET:
        case XPATH_XSLT_TREE:
            nodelist = obj->nodesetval;
			if ( nodelist == NULL )
				break;
			XPUSHs(sv_2mortal(newSVpv("XML::LibXML::NodeList", 0)));
			XPUSHs(sv_2mortal(newSViv(nodelist->nodeNr)));
			if ( nodelist->nodeNr == 0 )
				break;
            {
                const char * cls = "XML::LibXML::Node";
                xmlNodePtr tnode = NULL;
                SV * element = NULL;
                int i;
                for(i=0; i < nodelist->nodeNr; i++ ){
                    tnode = nodelist->nodeTab[i];
                    /* need to copy the node as libxml2 will free it */
                    if (tnode->type == XML_NAMESPACE_DECL) {
                        element = sv_newmortal();
                        cls = x_PmmNodeTypeName( tnode );
                        element = sv_setref_pv( element,
                                (const char *)cls,
                                (void *)xmlCopyNamespace((xmlNsPtr)tnode)
                                );
                    }
                    else {
                        xmlNodePtr tnode_cpy = xmlDocCopyNode(tnode,INT2PTR(xmlDocPtr,x_PmmNODE(SvPROXYNODE(owner_doc))),1);
                        if( tnode_cpy == NULL )
                            break;
                        element = x_PmmNodeToSv(tnode_cpy,SvPROXYNODE(owner_doc));
                    }
                    XPUSHs( sv_2mortal(element) );
                }
            }
            break;
        case XPATH_BOOLEAN:
            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Boolean", 0)));
            XPUSHs(sv_2mortal(newSViv(obj->boolval)));
            break;
        case XPATH_NUMBER:
            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Number", 0)));
            XPUSHs(sv_2mortal(newSVnv(obj->floatval)));
            break;
        case XPATH_STRING:
            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
            XPUSHs(sv_2mortal(newSVpv((char*)obj->stringval, 0)));
            break;
        default:
            /* warn("Unknown XPath return type (%d) in call to {%s}%s - assuming string", obj->type, uri, function); */
            XPUSHs(sv_2mortal(newSVpv("XML::LibXML::Literal", 0)));
            XPUSHs(sv_2mortal(newSVpv((char*)xmlXPathCastToString(obj), 0)));
        }
        xmlXPathFreeObject(obj);
    }

    /* call perl dispatcher */
    PUTBACK;

    perl_dispatch = sv_2mortal(newSVpv("XML::LibXSLT::perl_dispatcher",0));
    count = call_sv(perl_dispatch, G_SCALAR|G_EVAL);

    SPAGAIN;

    if (SvTRUE(ERRSV)) {
        (void) POPs;
        croak("LibXSLT: error coming back from perl-dispatcher in pm file. %s\n", SvPV(ERRSV, n_a));
    }

    if (count != 1) croak("LibXSLT: perl-dispatcher in pm file returned more than one argument!\n");

    perl_result = POPs;

    if (!SvOK(perl_result)) {
        ret = (xmlXPathObjectPtr)xmlXPathNewCString("");
        goto FINISH;
    }

    /* convert perl result structures to LibXML structures */
    if (sv_isobject(perl_result) &&
        (SvTYPE(SvRV(perl_result)) == SVt_PVMG ||
         SvTYPE(SvRV(perl_result)) == SVt_PVAV))
    {
        if (sv_derived_from(perl_result, "XML::LibXML::NodeList")) {
	    if (tctxt == NULL) {
              croak("LibXSLT: perl-dispatcher: internal error tctxt == NULL\n");
	    }
            ret = xmlXPathNewNodeSet(NULL);
            ret->boolval = 0;
            array_result = (AV*)SvRV(perl_result);
            while (av_len(array_result) >= 0) {
	      tmp_node1 = (xmlNodePtr)x_PmmSvNode(sv_2mortal(av_shift(array_result)));
	      if (tmp_node1) {
		container = xsltCreateRVT(tctxt);
		if (container == NULL) {
		  croak("LibXSLT: perl-dispatcher: cannot create container RVT\n");
		}
#if LIBXSLT_VERSION < 10118
		xsltRegisterTmpRVT(tctxt,container);
#else
		xsltRegisterLocalRVT(tctxt,container);
#endif
		tmp_node = xmlDocCopyNode(tmp_node1, container, 1);
		/* a wraper element is needed to wrap attributes and
		   prevent libxml2 from merging adjacent text nodes */
		tmp_node2 = xmlNewDocNode(container,NULL,(xmlChar*) "x",NULL);
		xmlAddChild((xmlNodePtr)container,tmp_node2);
		xmlAddChild(tmp_node2,tmp_node);
		xmlXPathNodeSetAdd(ret->nodesetval, tmp_node);
	      } else {
		croak("LibXSLT: perl-dispatcher returned nodelist with non-node elements\n");
	      }
	    }
            /*
             * Mark it as a function result in order to avoid garbage
             * collecting of tree fragments.
             */
            xsltExtensionInstructionResultRegister(tctxt, ret);
            goto FINISH;
        }
        else if (sv_derived_from(perl_result, "XML::LibXML::Node")) {
	  tmp_node1 = (xmlNodePtr)x_PmmSvNode(perl_result);
	  ret =  (xmlXPathObjectPtr)xmlXPathNewNodeSet(NULL);
	  ret->boolval = 0;
	  if (tmp_node1) {
	      if (tctxt == NULL) {
		croak("LibXSLT: perl-dispatcher: internal error tctxt == NULL\n");
	      }
	      container = xsltCreateRVT(tctxt);
	      if (container == NULL) {
		croak("LibXSLT: perl-dispatcher: cannot create container RVT\n");
	      }
#if LIBXSLT_VERSION < 10118
		  xsltRegisterTmpRVT(tctxt,container);
#else
		  xsltRegisterLocalRVT(tctxt,container);
#endif
	      tmp_node = xmlDocCopyNode(tmp_node1, container, 1);
	      if (tmp_node == NULL) {
		croak("LibXSLT: perl-dispatcher: cannot copy node for RVT\n");
	      }
	      if (tmp_node->type != XML_ELEMENT_NODE) {
		/* create a wrapper element */
		tmp_node2 = xmlNewDocNode(container,NULL,(xmlChar*) "x",NULL);
		xmlAddChild((xmlNodePtr)container,tmp_node2);
		xmlAddChild(tmp_node2,tmp_node);
	      } else {
		xmlAddChild((xmlNodePtr)container,tmp_node);
	      }
	      xmlXPathNodeSetAdd(ret->nodesetval,tmp_node);
	  } else {
	    croak("LibXSLT: perl-dispatcher returned a null XML::LibXML::Node object\n");
	  }
          /*
           * Mark it as a function result in order to avoid garbage
           * collecting of tree fragments.
           */
          xsltExtensionInstructionResultRegister(tctxt, ret);
	  goto FINISH;
        }
        else if (sv_derived_from(perl_result, "XML::LibXML::Boolean")) {
            tmp_int = SvIV(SvRV(perl_result));
            ret = (xmlXPathObjectPtr)xmlXPathNewBoolean(tmp_int);
            goto FINISH;
        }
        else if (sv_derived_from(perl_result, "XML::LibXML::Literal")) {
            tmp_string = SvPV(SvRV(perl_result), len);
            ret = (xmlXPathObjectPtr)xmlXPathNewCString(tmp_string);
            goto FINISH;
        }
        else if (sv_derived_from(perl_result, "XML::LibXML::Number")) {
            tmp_double = SvNV(SvRV(perl_result));
            ret = (xmlXPathObjectPtr)xmlXPathNewFloat(tmp_double);
            goto FINISH;
        }
    }
    ret = (xmlXPathObjectPtr)xmlXPathNewCString(SvPV(perl_result, len));

FINISH:
    valuePush(ctxt, ret);
    PUTBACK;
    FREETMPS;
    LEAVE;
}

/*
 * LibXSLT_generic_function
 *
 * Callback for global functions
 *
 */
static void
LibXSLT_generic_function (xmlXPathParserContextPtr ctxt, int nargs) {
    const char *uri, *name;
    SV *key;
    char *strkey;
    STRLEN len;
    SV **perl_function;

    uri = (const char *) ctxt->context->functionURI;
    name = (const char *) ctxt->context->function;

    key = newSVpvn("",0);
    sv_catpv(key, "{");
    sv_catpv(key, (const char*)uri);
    sv_catpv(key, "}");
    sv_catpv(key, (const char*)name);
    strkey = SvPV(key, len);
    perl_function = hv_fetch(LibXSLT_HV_allCallbacks, strkey, len, 0);
    SvREFCNT_dec(key);

    LibXSLT__function (ctxt, nargs, *perl_function);
}

/*
 * LibXSLT_context_function
 *
 * Callback for context-specific (=stylesheet specific) functions. The
 * functions themselves are stored in the StylesheetWrapper object which is
 * retrieved via the xsltTransformContext _private bit
 *
 */
static void
LibXSLT_context_function (xmlXPathParserContextPtr ctxt, int nargs) {
    const char *uri, *name;
    SV *key;
    char *strkey;
    STRLEN len;
    SV *wrapper;
    HV *functions;
    SV **ptr;
    SV **perl_function;
    AV *val;
    xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);

    wrapper = (SV *) tctxt->_private;

    key = newSVpvn("XML_LIBXSLT_FUNCTIONS", 21);
    strkey = SvPV(key, len);

    ptr = hv_fetch((HV *) SvRV(wrapper), strkey, len, 0);
    functions = (HV *) SvRV(*ptr);

    uri = (const char *) ctxt->context->functionURI;
    name = (const char *) ctxt->context->function;

    sv_setpv(key, "{");
    sv_catpv(key, (const char*)uri);
    sv_catpv(key, "}");
    sv_catpv(key, (const char*)name);
    strkey = SvPV(key, len);

    val = (AV *) SvRV(*hv_fetch(functions, strkey, len, 0));
    perl_function = av_fetch(val, 2, 0);

    SvREFCNT_dec(key);

    LibXSLT__function (ctxt, nargs, *perl_function);
}

static void
LibXSLT_context_element(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltElemPreCompPtr comp)
{
    SV *key, *wrapper, **ptr, **perl_function, *perlnode;
	HV *elements;
	AV *val;
	char *strkey;
	STRLEN len;
#if 0
    HE *ent;
#endif
    int count;
    xmlNodePtr result;

    dSP;

    wrapper = (SV *) ctxt->_private;

    key = newSVpvn("", 0);

	sv_setpv(key, "XML_LIBXSLT_ELEMENTS");
    strkey = SvPV(key, len);
    ptr = hv_fetch((HV *) SvRV(wrapper), strkey, len, 0);
	elements = (HV *) SvRV(*ptr);

	sv_setpv(key, "{");
    sv_catpv(key, (const char*)inst->ns->href);
	sv_catpv(key, "}");
	sv_catpv(key, (const char*)inst->name);
    strkey = SvPV(key, len);
    ptr = hv_fetch(elements, strkey, len, 0);
    val = (AV *) SvRV(*ptr);

    perl_function = av_fetch(val, 2, 0);

    SvREFCNT_dec(key);


    ENTER;
    SAVETMPS;
    PUSHMARK(SP);
    EXTEND(SP, 3);
    PUSHs(sv_setref_pv(sv_newmortal(), "XML::LibXSLT::TransformContext",
                (void*)ctxt));
    // node and node->doc are the document being transformed
    PUSHs(sv_2mortal(x_PmmNodeToSv(node, PmmPROXYNODE(node->doc))));
    // inst is the stylesheet's private copy of the stylesheet document
    if (PmmPROXYNODE(inst->doc) == NULL) {
        inst->doc->_private = x_PmmNewNode(INT2PTR(xmlNodePtr,inst->doc));
        // add a private reference which is cleaned up when the stylesheet
        // is destroyed
        x_PmmREFCNT_inc(PmmPROXYNODE(inst->doc));
    }
    PUSHs(sv_2mortal(x_PmmNodeToSv(inst, PmmPROXYNODE(inst->doc))));
    PUTBACK;

    count = call_sv(*perl_function, G_SCALAR);

    SPAGAIN;

    if (count != 1)
        croak("LibXSLT: element callback did not return anything");

    perlnode = POPs;

    if (perlnode != &PL_sv_undef)
    {
        result = x_PmmSvNodeExt(perlnode, 0);
        if (result == NULL)
            croak("LibXSLT: element callback did not return a XML::Node");

        x_PmmREFCNT_inc(PmmPROXYNODE(result));

        xmlAddChild(ctxt->insert, result);
    }

    FREETMPS;
    LEAVE;
}

int
LibXSLT_security_check(xsltSecurityOption option,
                       xsltSecurityPrefsPtr sec,
                       xsltTransformContextPtr ctxt,
                       const char * value)
{
   int result = 0;

   {
      int count;

      dTHX;
      dSP;

      ENTER;
      SAVETMPS;

      PUSHMARK(SP);
      EXTEND(SP, 3);
      PUSHs(sv_2mortal(newSViv(option)));
      PUSHs(sv_setref_pv(sv_newmortal(), "XML::LibXSLT::TransformContext",
                         (void*)ctxt));
      PUSHs(sv_2mortal(newSVpv((char*)value, 0)));
      PUTBACK;

      count = call_pv("XML::LibXSLT::Security::_security_check",
                      G_SCALAR | G_EVAL);

      SPAGAIN;

      if (count != 1) {
         croak("security callbacks must return a single value");
      }

      if (SvTRUE(ERRSV)) {
          (void) POPs;
         croak("security callback died: %s", SvPV_nolen(ERRSV));
      }

      result = POPi;

      PUTBACK;
      FREETMPS;
      LEAVE;
   }

   return result;
}

int
LibXSLT_security_read_file(xsltSecurityPrefsPtr sec,
                           xsltTransformContextPtr ctxt,
                           const char * value)
{
   return LibXSLT_security_check(XSLT_SECPREF_READ_FILE, sec, ctxt, value);
}

int
LibXSLT_security_write_file(xsltSecurityPrefsPtr sec,
                           xsltTransformContextPtr ctxt,
                           const char * value)
{
   return LibXSLT_security_check(XSLT_SECPREF_WRITE_FILE, sec, ctxt, value);
}

int
LibXSLT_security_create_dir(xsltSecurityPrefsPtr sec,
                            xsltTransformContextPtr ctxt,
                            const char * value)
{
   return LibXSLT_security_check(XSLT_SECPREF_CREATE_DIRECTORY, sec, ctxt, value);
}

int
LibXSLT_security_read_net(xsltSecurityPrefsPtr sec,
                          xsltTransformContextPtr ctxt,
                          const char * value)
{
   return LibXSLT_security_check(XSLT_SECPREF_READ_NETWORK, sec, ctxt, value);
}

int
LibXSLT_security_write_net(xsltSecurityPrefsPtr sec,
                           xsltTransformContextPtr ctxt,
                           const char * value)
{
   return LibXSLT_security_check(XSLT_SECPREF_WRITE_NETWORK, sec, ctxt, value);
}

xsltSecurityPrefsPtr
LibXSLT_init_security_prefs(xsltTransformContextPtr ctxt)
{
   xsltSecurityPrefsPtr sec = NULL;
   sec = xsltNewSecurityPrefs();

   xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE,
                        LibXSLT_security_read_file);
   xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE,
                        LibXSLT_security_write_file);
   xsltSetSecurityPrefs(sec, XSLT_SECPREF_CREATE_DIRECTORY,
                        LibXSLT_security_create_dir);
   xsltSetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK,
                        LibXSLT_security_read_net);
   xsltSetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK,
                        LibXSLT_security_write_net);

   xsltSetCtxtSecurityPrefs(sec, ctxt);

   return sec;
}

void
LibXSLT_free_security_prefs(xsltSecurityPrefsPtr sec,
                            xsltTransformContextPtr ctxt)
{
   xsltFreeSecurityPrefs(sec);
}

/*
 * LibXSLT_init_functions
 *
 * Add functions registered in $stylesheet->register_function() to the new
 * stylesheet context. This iterates over a hash ref keyed on the uri/name of
 * the functions and adds them to the new context that is used to perform the
 * transform. The value of the hash is [uri, name, callback] (saves us the
 * trouble of parsing the key). This is called by transform().
 *
 */
void
LibXSLT_init_functions(xsltTransformContextPtr ctxt, SV *wrapper)
{
    SV **ptr;
    HV *functions;
    HE *key;
    AV *val;
    char *uri, *name;
    const char strkey[] = "XML_LIBXSLT_FUNCTIONS";

    ptr = hv_fetch((HV *) SvRV(wrapper), strkey, strlen(strkey), 0);
	/* make sure the user hasn't screwed up our StylesheetWrapper object */
    if (ptr == NULL)
        croak("XML_LIBXSLT_FUNCTIONS is undef in StylesheetWrapper");
    if (SvTYPE(SvRV(*ptr)) != SVt_PVHV)
        croak("XML_LIBXSLT_FUNCTIONS is not a HASHREF in StylesheetWrapper");

    functions = (HV *) SvRV(*ptr);
    hv_iterinit(functions);
    while ((key = hv_iternext(functions)))
    {
        val = (AV *) SvRV(HeVAL(key)); /* [uri, name, callback] */
        uri = SvPV_nolen (*av_fetch (val, 0, 0));
        name = SvPV_nolen (*av_fetch (val, 1, 0));
        xsltRegisterExtFunction (ctxt,
                (const xmlChar *)name,
                (const xmlChar *)uri,
                LibXSLT_context_function
                );
    }
}

void
LibXSLT_init_elements(xsltTransformContextPtr ctxt, SV *wrapper)
{
    SV **ptr;
    HV *functions;
    HE *key;
    AV *val;
    char *uri, *name;
    const char strkey[] = "XML_LIBXSLT_ELEMENTS";

    ptr = hv_fetch((HV *) SvRV(wrapper), strkey, strlen(strkey), 0);
	/* make sure the user hasn't screwed up our StylesheetWrapper object */
    if (ptr == NULL)
        croak("XML_LIBXSLT_ELEMENTS is undef in StylesheetWrapper");
    if (SvTYPE(SvRV(*ptr)) != SVt_PVHV)
        croak("XML_LIBXSLT_ELEMENTS is not a HASHREF in StylesheetWrapper");

    functions = (HV *) SvRV(*ptr);
    hv_iterinit(functions);
    while ((key = hv_iternext(functions)))
    {
        val = (AV *) SvRV(HeVAL(key)); /* [uri, name, callback] */
        uri = SvPV_nolen (*av_fetch (val, 0, 0));
        name = SvPV_nolen (*av_fetch (val, 1, 0));
        xsltRegisterExtElement (ctxt,
                (const xmlChar *)name,
                (const xmlChar *)uri,
                LibXSLT_context_element
                );
    }
}

#line 800 "LibXSLT.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 944 "LibXSLT.c"

XS_EUPXS(XS_XML__LibXSLT_END); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_END)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
#line 811 "LibXSLT.xs"
        xsltCleanupGlobals();
#line 955 "LibXSLT.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_XML__LibXSLT_HAVE_EXSLT); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_HAVE_EXSLT)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 816 "LibXSLT.xs"
#ifdef HAVE_EXSLT
        RETVAL = 1;
#else
        RETVAL = 0;
#endif
#line 976 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_DOTTED_VERSION); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_DOTTED_VERSION)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	char *	RETVAL;
	dXSTARG;
#line 827 "LibXSLT.xs"
        RETVAL = LIBXSLT_DOTTED_VERSION;
#line 995 "LibXSLT.c"
	sv_setpv(TARG, RETVAL);
	XSprePUSH;
	PUSHTARG;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_VERSION); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_VERSION)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 835 "LibXSLT.xs"
        RETVAL = LIBXSLT_VERSION;
#line 1015 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_RUNTIME_VERSION); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_LIBXSLT_RUNTIME_VERSION)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	int	RETVAL;
	dXSTARG;
#line 842 "LibXSLT.xs"
        RETVAL = xsltLibxsltVersion;
#line 1034 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_xinclude_default); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_xinclude_default)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "self, ...");
    {
	SV *	self = ST(0)
;
	int	RETVAL;
	dXSTARG;
#line 850 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
        RETVAL = xsltGetXIncludeDefault();
        if (items > 1) {
           xsltSetXIncludeDefault(SvIV(ST(1)));
        }
#line 1059 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_max_depth); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_max_depth)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "self, ...");
    {
	SV *	self = ST(0)
;
	int	RETVAL;
	dXSTARG;
#line 862 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
        RETVAL = xsltMaxDepth;
        if (items > 1) {
            IV val;

            val = SvIV(ST(1));
            if (val > 0) {
                xsltMaxDepth = val;
            }
        }
#line 1089 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_max_vars); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_max_vars)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "self, ...");
    {
	SV *	self = ST(0)
;
	int	RETVAL;
	dXSTARG;
#line 879 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
#if LIBXSLT_VERSION < 10127
        RETVAL = 1;
#else
        RETVAL = xsltMaxVars;
        if (items > 1) {
            IV val;

            val = SvIV(ST(1));
            if (val > 0) {
                xsltMaxVars = val;
            }
        }
#endif
#line 1123 "LibXSLT.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_register_function); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_register_function)
{
    dVAR; dXSARGS;
    if (items != 4)
       croak_xs_usage(cv,  "self, uri, name, callback");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	self = ST(0)
;
	char *	uri = (char *)SvPV_nolen(ST(1))
;
	char *	name = (char *)SvPV_nolen(ST(2))
;
	SV *	callback = ST(3)
;
#line 903 "LibXSLT.xs"
    {
        SV *key;
        STRLEN len;
        char *strkey;

        PERL_UNUSED_VAR(self);
        /* todo: Add checking of uri and name in here! */
        xsltRegisterExtModuleFunction((const xmlChar *)name,
                        (const xmlChar *)uri,
                        LibXSLT_generic_function);
        key = newSVpvn("",0);
        sv_catpv(key, "{");
        sv_catpv(key, (const char*)uri);
        sv_catpv(key, "}");
        sv_catpv(key, (const char*)name);
        strkey = SvPV(key, len);
        /* warn("Trying to store function '%s' in %d\n", strkey, LibXSLT_HV_allCallbacks); */
        (void) hv_store(LibXSLT_HV_allCallbacks, strkey, len, SvREFCNT_inc(callback), 0);
        SvREFCNT_dec(key);
    }
#line 1169 "LibXSLT.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_XML__LibXSLT_debug_callback); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_debug_callback)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "self, ...");
    {
	SV *	self = ST(0)
;
	SV *	RETVAL;
#line 928 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
        if (items > 1) {
            SV * debug_cb = ST(1);
            if (debug_cb && SvTRUE(debug_cb)) {
                SET_CB(LibXSLT_debug_cb, debug_cb);
            }
            else {
                LibXSLT_debug_cb = NULL;
            }
        }
        RETVAL = LibXSLT_debug_cb ? LibXSLT_debug_cb : &PL_sv_undef;
#line 1198 "LibXSLT.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__parse_stylesheet); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__parse_stylesheet)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "self, sv_doc");
    {
	SV *	self = ST(0)
;
	SV *	sv_doc = ST(1)
;
#line 947 "LibXSLT.xs"
        char * CLASS = "XML::LibXSLT::Stylesheet";
        xmlDocPtr doc_copy;
        xmlDocPtr doc;
        SV * saved_error = sv_2mortal(newSVpv("",0));
#line 1222 "LibXSLT.c"
	xsltStylesheetPtr	RETVAL;
#line 952 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
        if (sv_doc == NULL) {
            XSRETURN_UNDEF;
        }
        doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
        if (doc == NULL) {
            XSRETURN_UNDEF;
        }
        doc_copy = xmlCopyDoc(doc, 1);
        if (doc_copy->URL == NULL) {
          doc_copy->URL = xmlStrdup(doc->URL);
        }
        /* xmlNodeSetBase((xmlNodePtr)doc_copy, doc_copy->URL); */

        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
	else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }

        LibXSLT_init_error_ctx(saved_error);
        RETVAL = xsltParseStylesheetDoc(doc_copy);
        if (RETVAL == NULL) {
            xmlFreeDoc(doc_copy);
	    LibXSLT_report_error_ctx(saved_error,0);
            XSRETURN_UNDEF;
        }
	LibXSLT_report_error_ctx(saved_error,1);
#line 1254 "LibXSLT.c"
	{
	    SV * RETVALSV;
	    RETVALSV = sv_newmortal();
	    sv_setref_pv( RETVALSV, (char *)CLASS, (void*)RETVAL );
	    ST(0) = RETVALSV;
	}
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__parse_stylesheet_file); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__parse_stylesheet_file)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "self, filename");
    {
	SV *	self = ST(0)
;
	const char *	filename = (const char *)SvPV_nolen(ST(1))
;
#line 989 "LibXSLT.xs"
        char * CLASS = "XML::LibXSLT::Stylesheet";
        SV * saved_error = sv_2mortal(newSVpv("",0));
#line 1280 "LibXSLT.c"
	xsltStylesheetPtr	RETVAL;
#line 992 "LibXSLT.xs"
        PERL_UNUSED_VAR(self);
        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }

        LibXSLT_init_error_ctx(saved_error);
        RETVAL = xsltParseStylesheetFile((const xmlChar *)filename);
        if (RETVAL == NULL) {
            LibXSLT_report_error_ctx(saved_error,0);
            XSRETURN_UNDEF;
        }
        LibXSLT_report_error_ctx(saved_error,1);
#line 1298 "LibXSLT.c"
	{
	    SV * RETVALSV;
	    RETVALSV = sv_newmortal();
	    sv_setref_pv( RETVALSV, (char *)CLASS, (void*)RETVAL );
	    ST(0) = RETVALSV;
	}
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT_INIT_THREAD_SUPPORT); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT_INIT_THREAD_SUPPORT)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
#line 1013 "LibXSLT.xs"
       if (x_PROXY_NODE_REGISTRY_MUTEX != NULL) {
	  croak("XML::LibXSLT::INIT_THREAD_SUPPORT can only be called once!\n");
       }
       x_PROXY_NODE_REGISTRY_MUTEX = get_sv("XML::LibXML::__PROXY_NODE_REGISTRY_MUTEX",0);
#line 1322 "LibXSLT.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_transform); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_transform)
{
    dVAR; dXSARGS;
    if (items < 3)
       croak_xs_usage(cv,  "self, wrapper, sv_doc, ...");
    {
	xsltStylesheetPtr	self;
	SV *	wrapper = ST(1)
;
	SV *	sv_doc = ST(2)
;
#line 1028 "LibXSLT.xs"
	const char *xslt_params[255]; /* note really only 254 entries here - last one is NULL */
        xmlDocPtr real_dom;
        xmlDocPtr doc;
        xmlNodePtr dtd_prev = NULL;
        xmlNodePtr dtd_next = NULL;
        SV * saved_error = sv_2mortal(newSVpv("",0));
        xsltTransformContextPtr ctxt;
        xsltSecurityPrefsPtr sec;
#line 1349 "LibXSLT.c"
	SV *	RETVAL;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::transform() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1037 "LibXSLT.xs"
        if (sv_doc == NULL) {
            XSRETURN_UNDEF;
        }
        doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
        if (doc == NULL) {
            XSRETURN_UNDEF;
        }
        xslt_params[0] = 0;
        if (items > 256) {
            croak("Too many parameters in transform()");
        }
        if ((items - 3) % 2) {
            croak("Odd number of parameters");
        }
        if (items > 3) {
            int i;
            for (i = 3; (i < items && i < 256); i++) {
                xslt_params[i - 3] = (char *)SvPV(ST(i), PL_na);
            }
            xslt_params[i - 3] = 0;
        }

        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }

        LibXSLT_init_error_ctx(saved_error);

        /* we need own context to distinguish
         * <xsl:message terminate="no">
         * from those with terminate="yes" and fatal errors */
	ctxt = xsltNewTransformContext(self, doc);
        if (ctxt == NULL) {
	    croak("Could not create transformation context");
	}
        ctxt->xinclude = 1;
        ctxt->_private = (void *) wrapper;
        sec = LibXSLT_init_security_prefs(ctxt);
        LibXSLT_init_functions(ctxt, wrapper);
        LibXSLT_init_elements(ctxt, wrapper);

        if (doc->intSubset != NULL) {
	  /* Note: libxslt will unlink intSubset, we
	     want to restore it when done
	   */
          dtd_prev = doc->intSubset->prev;
          dtd_next = doc->intSubset->next;
	}

	real_dom = xsltApplyStylesheetUser(self, doc, xslt_params,
					   NULL, NULL, ctxt);
        if (doc->intSubset != NULL &&
	    doc->prev == NULL && doc->next == NULL) {
           xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
	   cur->prev = dtd_prev;
	   cur->next = dtd_next;
           if (dtd_prev) dtd_prev->next = cur;
	   if (dtd_next) dtd_next->prev = cur;
	   if (doc->children == dtd_next) doc->children = cur;
	   if (doc->last == dtd_prev) doc->last = cur;
	}
        if ((real_dom != NULL) && (ctxt->state != XSLT_STATE_OK)) {
          /* fatal error */
             xmlFreeDoc(real_dom);
             real_dom = NULL;
	}
        LibXSLT_free_security_prefs(sec, ctxt);
	xsltFreeTransformContext(ctxt);

        /* real_dom = xsltApplyStylesheet(self, doc, xslt_params); */
        if (real_dom == NULL) {
            if ( real_dom != NULL ) xmlFreeDoc( real_dom );
            LibXSLT_report_error_ctx(saved_error,0);
            croak("Unknown error applying stylesheet");
        }
        if (real_dom->type == XML_HTML_DOCUMENT_NODE) {
            if (self->method != NULL) {
                xmlFree(self->method);
            }
            self->method = (xmlChar *) xmlMalloc(5);
            strcpy((char *) self->method, "html");
        }
        /* non-fatal: probably just a message from the stylesheet */
        LibXSLT_report_error_ctx(saved_error,1);
        RETVAL = x_PmmNodeToSv((xmlNodePtr)real_dom, NULL);
#line 1448 "LibXSLT.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_transform_file); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_transform_file)
{
    dVAR; dXSARGS;
    if (items < 3)
       croak_xs_usage(cv,  "self, wrapper, filename, ...");
    {
	xsltStylesheetPtr	self;
	SV *	wrapper = ST(1)
;
	char *	filename = (char *)SvPV_nolen(ST(2))
;
#line 1136 "LibXSLT.xs"
        const char *xslt_params[255];
        xmlDocPtr real_dom;
        xmlDocPtr source_dom;
        SV * saved_error = sv_2mortal(newSVpv("",0));
        xsltTransformContextPtr ctxt;
        xsltSecurityPrefsPtr sec;
#line 1475 "LibXSLT.c"
	SV *	RETVAL;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::transform_file() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1143 "LibXSLT.xs"
        xslt_params[0] = 0;
        if (items > 256) {
            croak("Too many parameters in transform()");
        }
        if ((items - 3) % 2) {
            croak("Odd number of parameters");
        }
        if (items > 3) {
            int i;
            for (i = 3; (i < items && i < 256); i++) {
                xslt_params[i - 3] = (char *)SvPV(ST(i), PL_na);
            }
            xslt_params[i - 3] = 0;
        }
        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }
        LibXSLT_init_error_ctx(saved_error);
        source_dom = xmlParseFile(filename);
        if ( source_dom == NULL ) {
            LibXSLT_report_error_ctx(saved_error,0);
            croak("Unknown error loading source document");
        } else {
	  /*real_dom = xsltApplyStylesheet(self, source_dom, xslt_params);*/

	   ctxt = xsltNewTransformContext(self, source_dom);
	   if (ctxt == NULL) {
	     croak("Could not create transformation context");
	   }
	   ctxt->xinclude = 1;
           ctxt->_private = (void *) wrapper;
           sec = LibXSLT_init_security_prefs(ctxt);
           LibXSLT_init_functions(ctxt, wrapper);
           LibXSLT_init_elements(ctxt, wrapper);
	   real_dom = xsltApplyStylesheetUser(self, source_dom, xslt_params,
					      NULL, NULL, ctxt);
	   if ((ctxt->state != XSLT_STATE_OK) && real_dom) {
               /* fatal error */
               xmlFreeDoc(real_dom);
               real_dom = NULL;
           }
           LibXSLT_free_security_prefs(sec, ctxt);
	   xsltFreeTransformContext(ctxt);

	   xmlFreeDoc( source_dom );
        }

        if (real_dom == NULL) {
            LibXSLT_report_error_ctx(saved_error,0);
            croak("Unknown error applying stylesheet");
        }
        /* non-fatal: probably just a message from the stylesheet */
        LibXSLT_report_error_ctx(saved_error,1);
        if (real_dom->type == XML_HTML_DOCUMENT_NODE) {
            if (self->method != NULL) {
                xmlFree(self->method);
            }
            self->method = xmlStrdup((const xmlChar *) "html");
        }
        RETVAL = x_PmmNodeToSv((xmlNodePtr)real_dom, NULL);
#line 1549 "LibXSLT.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	xsltStylesheetPtr	self;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::DESTROY() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1214 "LibXSLT.xs"
        if (self == NULL) {
            XSRETURN_UNDEF;
        }
        if (PmmPROXYNODE(self->doc)) {
            if (x_PmmREFCNT(PmmPROXYNODE(self->doc)) > 1)
                warn("LibXSLT: reference to stylesheet document outside of stylesheet scope"); // perhaps croak() ?
            else
                xmlFree(PmmPROXYNODE(self->doc));
        }
        xsltFreeStylesheet(self);
#line 1584 "LibXSLT.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet__output_string); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet__output_string)
{
    dVAR; dXSARGS;
    if (items < 2 || items > 3)
       croak_xs_usage(cv,  "self, sv_doc, bytes_vs_chars=0");
    {
	xsltStylesheetPtr	self;
	SV *	sv_doc = ST(1)
;
	int	bytes_vs_chars;
#line 1231 "LibXSLT.xs"
        xmlOutputBufferPtr output;
        SV * results = newSVpv("", 0);
        const xmlChar *encoding = NULL;
        xmlCharEncodingHandlerPtr encoder = NULL;
        xmlDocPtr doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
#line 1607 "LibXSLT.c"
	SV *	RETVAL;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::_output_string() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;

	if (items < 3)
	    bytes_vs_chars = 0;
	else {
	    bytes_vs_chars = (int)SvIV(ST(2))
;
	}
#line 1237 "LibXSLT.xs"
        XSLT_GET_IMPORT_PTR(encoding, self, encoding)
        if (encoding != NULL) {
            encoder = xmlFindCharEncodingHandler((char *)encoding);
            if ((encoder != NULL) &&
                 (xmlStrEqual((const xmlChar *)encoder->name,
                              (const xmlChar *) "UTF-8")))
                encoder = NULL;
        }

        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }
        output = xmlOutputBufferCreateIO(
            (xmlOutputWriteCallback) LibXSLT_iowrite_scalar,
            (xmlOutputCloseCallback) LibXSLT_ioclose_scalar,
            (void*)results,
            (bytes_vs_chars == 2) ? NULL : encoder
	    );
        if (xsltSaveResultTo(output, doc, self) == -1) {
            croak("output to scalar failed");
        }
        xmlOutputBufferClose(output);

        if ((bytes_vs_chars == 2) ||
            ((bytes_vs_chars == 0) && xmlStrEqual(encoding, (const xmlChar *) "UTF-8"))) {
	  SvUTF8_on( results );
	}
        RETVAL = results;
#line 1656 "LibXSLT.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_fh); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_fh)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "self, sv_doc, fh");
    {
	xsltStylesheetPtr	self;
	SV *	sv_doc = ST(1)
;
	SV *	fh = ST(2)
;
#line 1277 "LibXSLT.xs"
        xmlOutputBufferPtr output;
        const xmlChar *encoding = NULL;
        xmlCharEncodingHandlerPtr encoder = NULL;
        xmlDocPtr doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
#line 1681 "LibXSLT.c"

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::output_fh() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1282 "LibXSLT.xs"
        XSLT_GET_IMPORT_PTR(encoding, self, encoding)
        if (encoding != NULL) {
            encoder = xmlFindCharEncodingHandler((char *)encoding);
            if ((encoder != NULL) &&
                 (xmlStrEqual((const xmlChar *)encoder->name,
                              (const xmlChar *) "UTF-8")))
                encoder = NULL;
        }

        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }
        output = xmlOutputBufferCreateIO(
            (xmlOutputWriteCallback) LibXSLT_iowrite_fh,
            (xmlOutputCloseCallback) LibXSLT_ioclose_fh,
            (void*)fh,
            encoder
            );
        if (xsltSaveResultTo(output, doc, self) == -1) {
            croak("output to fh failed");
        }
        xmlOutputBufferClose(output);
#line 1716 "LibXSLT.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_file); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_file)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "self, sv_doc, filename");
    {
	xsltStylesheetPtr	self;
	SV *	sv_doc = ST(1)
;
	char *	filename = (char *)SvPV_nolen(ST(2))
;
#line 1314 "LibXSLT.xs"
        xmlDocPtr doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
#line 1736 "LibXSLT.c"

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::output_file() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1316 "LibXSLT.xs"
        if (LibXSLT_debug_cb && SvTRUE(LibXSLT_debug_cb)) {
            xsltSetGenericDebugFunc(PerlIO_stderr(), (xmlGenericErrorFunc)LibXSLT_debug_handler);
        }
        else {
            xsltSetGenericDebugFunc(NULL, NULL);
        }
        xsltSaveResultToFilename(filename, doc, self, 0);
#line 1753 "LibXSLT.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_media_type); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_media_type)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	xsltStylesheetPtr	self;
#line 1328 "LibXSLT.xs"
    	xmlChar *mediaType;
    	xmlChar *method;
#line 1770 "LibXSLT.c"
	char *	RETVAL;
	dXSTARG;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::media_type() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1331 "LibXSLT.xs"
    	XSLT_GET_IMPORT_PTR(mediaType, self, mediaType);

	if(mediaType == NULL) {
    	    XSLT_GET_IMPORT_PTR(method, self, method);
            RETVAL = "text/xml";
            /* this below is rather simplistic, but should work for most cases */
            if (method != NULL) {
        	if (xmlStrcmp(method, (xmlChar*) "html") == 0) {
                    RETVAL = "text/html";
        	}
        	else if (xmlStrcmp(method, (xmlChar*) "text") == 0) {
                    RETVAL = "text/plain";
        	}
            }
        }
	else {
	    RETVAL = (char*) mediaType;
	}
#line 1800 "LibXSLT.c"
	sv_setpv(TARG, RETVAL);
	XSprePUSH;
	PUSHTARG;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_method); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_method)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	xsltStylesheetPtr	self;
#line 1356 "LibXSLT.xs"
    	xmlChar *method;
#line 1819 "LibXSLT.c"
	char *	RETVAL;
	dXSTARG;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::output_method() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1358 "LibXSLT.xs"
    	XSLT_GET_IMPORT_PTR(method, self, method)

        RETVAL = (char*) method;
        if (RETVAL == NULL) {
            /* read http://www.w3.org/TR/xslt#output and tell me how
               you'd implement this the way it says to. */
            RETVAL = "xml";
        }
#line 1839 "LibXSLT.c"
	sv_setpv(TARG, RETVAL);
	XSprePUSH;
	PUSHTARG;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_encoding); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__Stylesheet_output_encoding)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	xsltStylesheetPtr	self;
#line 1373 "LibXSLT.xs"
    	xmlChar *encoding;
#line 1858 "LibXSLT.c"
	char *	RETVAL;
	dXSTARG;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltStylesheetPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::Stylesheet::output_encoding() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1375 "LibXSLT.xs"
    	XSLT_GET_IMPORT_PTR(encoding, self, encoding)

        RETVAL = (char*) encoding;
        if (RETVAL == NULL) {
            RETVAL = "UTF-8";
        }
#line 1876 "LibXSLT.c"
	sv_setpv(TARG, RETVAL);
	XSprePUSH;
	PUSHTARG;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_XML__LibXSLT__TransformContext_stylesheet); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_XML__LibXSLT__TransformContext_stylesheet)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	xsltTransformContextPtr	self;
	SV *	RETVAL;

    if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
            self = (xsltTransformContextPtr)SvIV((SV*)SvRV( ST(0) ));
    else{
            warn( "XML::LibXSLT::TransformContext::stylesheet() -- self is not a blessed SV reference" );
            XSRETURN_UNDEF;
    }
;
#line 1391 "LibXSLT.xs"
      RETVAL = SvREFCNT_inc((SV *) self->_private);
#line 1904 "LibXSLT.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_XML__LibXSLT); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_XML__LibXSLT)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("XML::LibXSLT::END", XS_XML__LibXSLT_END);
        newXS_deffile("XML::LibXSLT::HAVE_EXSLT", XS_XML__LibXSLT_HAVE_EXSLT);
        newXS_deffile("XML::LibXSLT::LIBXSLT_DOTTED_VERSION", XS_XML__LibXSLT_LIBXSLT_DOTTED_VERSION);
        newXS_deffile("XML::LibXSLT::LIBXSLT_VERSION", XS_XML__LibXSLT_LIBXSLT_VERSION);
        newXS_deffile("XML::LibXSLT::LIBXSLT_RUNTIME_VERSION", XS_XML__LibXSLT_LIBXSLT_RUNTIME_VERSION);
        newXS_deffile("XML::LibXSLT::xinclude_default", XS_XML__LibXSLT_xinclude_default);
        newXS_deffile("XML::LibXSLT::max_depth", XS_XML__LibXSLT_max_depth);
        newXS_deffile("XML::LibXSLT::max_vars", XS_XML__LibXSLT_max_vars);
        newXS_deffile("XML::LibXSLT::register_function", XS_XML__LibXSLT_register_function);
        newXS_deffile("XML::LibXSLT::debug_callback", XS_XML__LibXSLT_debug_callback);
        newXS_deffile("XML::LibXSLT::_parse_stylesheet", XS_XML__LibXSLT__parse_stylesheet);
        newXS_deffile("XML::LibXSLT::_parse_stylesheet_file", XS_XML__LibXSLT__parse_stylesheet_file);
        newXS_deffile("XML::LibXSLT::INIT_THREAD_SUPPORT", XS_XML__LibXSLT_INIT_THREAD_SUPPORT);
        newXS_deffile("XML::LibXSLT::Stylesheet::transform", XS_XML__LibXSLT__Stylesheet_transform);
        newXS_deffile("XML::LibXSLT::Stylesheet::transform_file", XS_XML__LibXSLT__Stylesheet_transform_file);
        newXS_deffile("XML::LibXSLT::Stylesheet::DESTROY", XS_XML__LibXSLT__Stylesheet_DESTROY);
        newXS_deffile("XML::LibXSLT::Stylesheet::_output_string", XS_XML__LibXSLT__Stylesheet__output_string);
        newXS_deffile("XML::LibXSLT::Stylesheet::output_fh", XS_XML__LibXSLT__Stylesheet_output_fh);
        newXS_deffile("XML::LibXSLT::Stylesheet::output_file", XS_XML__LibXSLT__Stylesheet_output_file);
        newXS_deffile("XML::LibXSLT::Stylesheet::media_type", XS_XML__LibXSLT__Stylesheet_media_type);
        newXS_deffile("XML::LibXSLT::Stylesheet::output_method", XS_XML__LibXSLT__Stylesheet_output_method);
        newXS_deffile("XML::LibXSLT::Stylesheet::output_encoding", XS_XML__LibXSLT__Stylesheet_output_encoding);
        newXS_deffile("XML::LibXSLT::TransformContext::stylesheet", XS_XML__LibXSLT__TransformContext_stylesheet);

    /* Initialisation Section */

#line 795 "LibXSLT.xs"
    LIBXML_TEST_VERSION
    if (xsltLibxsltVersion < LIBXSLT_VERSION) {
      warn("Warning: XML::LibXSLT compiled against libxslt %d, "
           "but runtime libxslt is older %d\n", LIBXSLT_VERSION, xsltLibxsltVersion);
    }
    xsltInit();
    xsltMaxDepth = 250;
    xsltSetXIncludeDefault(1);
    LibXSLT_HV_allCallbacks = newHV();
#ifdef HAVE_EXSLT
    exsltRegisterAll();
#endif

#line 1979 "LibXSLT.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

