XML-LibXSLT
view release on metacpan or search on metacpan
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)
MODULE = XML::LibXSLT PACKAGE = XML::LibXSLT::Stylesheet
PROTOTYPES: DISABLE
SV *
transform(self, wrapper, sv_doc, ...)
xsltStylesheetPtr self
SV * wrapper
SV * sv_doc
PREINIT:
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;
CODE:
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);
}
# set last entry to NULL
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);
OUTPUT:
RETVAL
SV *
transform_file(self, wrapper, filename, ...)
xsltStylesheetPtr self
SV * wrapper
char * filename
PREINIT:
# note really only 254 entries here - last one is NULL
const char *xslt_params[255];
xmlDocPtr real_dom;
xmlDocPtr source_dom;
SV * saved_error = sv_2mortal(newSVpv("",0));
xsltTransformContextPtr ctxt;
xsltSecurityPrefsPtr sec;
CODE:
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);
}
# set last entry to NULL
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);
OUTPUT:
RETVAL
void
DESTROY(self)
xsltStylesheetPtr self
CODE:
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);
SV *
_output_string(self, sv_doc, bytes_vs_chars=0)
xsltStylesheetPtr self
SV * sv_doc
int bytes_vs_chars
PREINIT:
xmlOutputBufferPtr output;
SV * results = newSVpv("", 0);
const xmlChar *encoding = NULL;
xmlCharEncodingHandlerPtr encoder = NULL;
xmlDocPtr doc = (xmlDocPtr)x_PmmSvNode( sv_doc );
CODE:
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);
}
( run in 2.960 seconds using v1.01-cache-2.11-cpan-8f98c5d2c55 )