File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / libxml / libxml.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:49 2014 UTC (10 years, 4 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Shane Caraveo <shane@php.net>                               |
   16:    |          Wez Furlong <wez@thebrainroom.com>                          |
   17:    +----------------------------------------------------------------------+
   18:  */
   19: 
   20: /* $Id: libxml.c,v 1.1.1.4 2014/06/15 20:03:49 misho Exp $ */
   21: 
   22: #define IS_EXT_MODULE
   23: 
   24: #ifdef HAVE_CONFIG_H
   25: #include "config.h"
   26: #endif
   27: 
   28: #include "php.h"
   29: #include "SAPI.h"
   30: 
   31: #define PHP_XML_INTERNAL
   32: #include "zend_variables.h"
   33: #include "ext/standard/php_string.h"
   34: #include "ext/standard/info.h"
   35: #include "ext/standard/file.h"
   36: 
   37: #if HAVE_LIBXML
   38: 
   39: #include <libxml/parser.h>
   40: #include <libxml/parserInternals.h>
   41: #include <libxml/tree.h>
   42: #include <libxml/uri.h>
   43: #include <libxml/xmlerror.h>
   44: #include <libxml/xmlsave.h>
   45: #ifdef LIBXML_SCHEMAS_ENABLED
   46: #include <libxml/relaxng.h>
   47: #endif
   48: 
   49: #include "php_libxml.h"
   50: 
   51: #define PHP_LIBXML_ERROR 0
   52: #define PHP_LIBXML_CTX_ERROR 1
   53: #define PHP_LIBXML_CTX_WARNING 2
   54: 
   55: /* a true global for initialization */
   56: static int _php_libxml_initialized = 0;
   57: static int _php_libxml_per_request_initialization = 1;
   58: static xmlExternalEntityLoader _php_libxml_default_entity_loader;
   59: 
   60: typedef struct _php_libxml_func_handler {
   61: 	php_libxml_export_node export_func;
   62: } php_libxml_func_handler;
   63: 
   64: static HashTable php_libxml_exports;
   65: 
   66: static ZEND_DECLARE_MODULE_GLOBALS(libxml)
   67: static PHP_GINIT_FUNCTION(libxml);
   68: 
   69: static PHP_FUNCTION(libxml_set_streams_context);
   70: static PHP_FUNCTION(libxml_use_internal_errors);
   71: static PHP_FUNCTION(libxml_get_last_error);
   72: static PHP_FUNCTION(libxml_clear_errors);
   73: static PHP_FUNCTION(libxml_get_errors);
   74: static PHP_FUNCTION(libxml_set_external_entity_loader);
   75: static PHP_FUNCTION(libxml_disable_entity_loader);
   76: 
   77: static zend_class_entry *libxmlerror_class_entry;
   78: 
   79: /* {{{ dynamically loadable module stuff */
   80: #ifdef COMPILE_DL_LIBXML
   81: ZEND_GET_MODULE(libxml)
   82: #endif /* COMPILE_DL_LIBXML */
   83: /* }}} */
   84: 
   85: /* {{{ function prototypes */
   86: static PHP_MINIT_FUNCTION(libxml);
   87: static PHP_RINIT_FUNCTION(libxml);
   88: static PHP_MSHUTDOWN_FUNCTION(libxml);
   89: static PHP_MINFO_FUNCTION(libxml);
   90: static int php_libxml_post_deactivate(void);
   91: 
   92: /* }}} */
   93: 
   94: /* {{{ arginfo */
   95: ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
   96: 	ZEND_ARG_INFO(0, context)
   97: ZEND_END_ARG_INFO()
   98: 
   99: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0)
  100: 	ZEND_ARG_INFO(0, use_errors)
  101: ZEND_END_ARG_INFO()
  102: 
  103: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
  104: ZEND_END_ARG_INFO()
  105: 
  106: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
  107: ZEND_END_ARG_INFO()
  108: 
  109: ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
  110: ZEND_END_ARG_INFO()
  111: 
  112: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0)
  113: 	ZEND_ARG_INFO(0, disable)
  114: ZEND_END_ARG_INFO()
  115: 
  116: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_set_external_entity_loader, 0, 0, 1)
  117: 	ZEND_ARG_INFO(0, resolver_function)
  118: ZEND_END_ARG_INFO()
  119: /* }}} */
  120: 
  121: /* {{{ extension definition structures */
  122: static const zend_function_entry libxml_functions[] = {
  123: 	PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
  124: 	PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
  125: 	PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
  126: 	PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
  127: 	PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
  128: 	PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader)
  129: 	PHP_FE(libxml_set_external_entity_loader, arginfo_libxml_set_external_entity_loader)
  130: 	PHP_FE_END
  131: };
  132: 
  133: zend_module_entry libxml_module_entry = {
  134: 	STANDARD_MODULE_HEADER,
  135: 	"libxml",                /* extension name */
  136: 	libxml_functions,        /* extension function list */
  137: 	PHP_MINIT(libxml),       /* extension-wide startup function */
  138: 	PHP_MSHUTDOWN(libxml),   /* extension-wide shutdown function */
  139: 	PHP_RINIT(libxml),       /* per-request startup function */
  140: 	NULL,                    /* per-request shutdown function */
  141: 	PHP_MINFO(libxml),       /* information function */
  142: 	NO_VERSION_YET,
  143: 	PHP_MODULE_GLOBALS(libxml), /* globals descriptor */
  144: 	PHP_GINIT(libxml),          /* globals ctor */
  145: 	NULL,                       /* globals dtor */
  146: 	php_libxml_post_deactivate, /* post deactivate */
  147: 	STANDARD_MODULE_PROPERTIES_EX
  148: };
  149: 
  150: /* }}} */
  151: 
  152: /* {{{ internal functions for interoperability */
  153: static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC)
  154: {
  155: 	if (object->properties) {
  156: 		object->properties = NULL;
  157: 	}
  158: 	php_libxml_decrement_node_ptr(object TSRMLS_CC);
  159: 	return php_libxml_decrement_doc_ref(object TSRMLS_CC);
  160: }
  161: 
  162: static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC)
  163: {
  164: 	php_libxml_node_object *wrapper;
  165: 
  166: 	php_libxml_node_ptr *nodeptr = nodep->_private;
  167: 
  168: 	if (nodeptr != NULL) {
  169: 		wrapper = nodeptr->_private;
  170: 		if (wrapper) {
  171: 			php_libxml_clear_object(wrapper TSRMLS_CC);
  172: 		} else {
  173: 			if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
  174: 				nodeptr->node->_private = NULL;
  175: 			}
  176: 			nodeptr->node = NULL;
  177: 		}
  178: 	}
  179: 
  180: 	return -1;
  181: }
  182: 
  183: static void php_libxml_node_free(xmlNodePtr node)
  184: {
  185: 	if(node) {
  186: 		if (node->_private != NULL) {
  187: 			((php_libxml_node_ptr *) node->_private)->node = NULL;
  188: 		}
  189: 		switch (node->type) {
  190: 			case XML_ATTRIBUTE_NODE:
  191: 				xmlFreeProp((xmlAttrPtr) node);
  192: 				break;
  193: 			case XML_ENTITY_DECL:
  194: 			case XML_ELEMENT_DECL:
  195: 			case XML_ATTRIBUTE_DECL:
  196: 				break;
  197: 			case XML_NOTATION_NODE:
  198: 				/* These require special handling */
  199: 				if (node->name != NULL) {
  200: 					xmlFree((char *) node->name);
  201: 				}
  202: 				if (((xmlEntityPtr) node)->ExternalID != NULL) {
  203: 					xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
  204: 				}
  205: 				if (((xmlEntityPtr) node)->SystemID != NULL) {
  206: 					xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
  207: 				}
  208: 				xmlFree(node);
  209: 				break;
  210: 			case XML_NAMESPACE_DECL:
  211: 				if (node->ns) {
  212: 					xmlFreeNs(node->ns);
  213: 					node->ns = NULL;
  214: 				}
  215: 				node->type = XML_ELEMENT_NODE;
  216: 			default:
  217: 				xmlFreeNode(node);
  218: 		}
  219: 	}
  220: }
  221: 
  222: static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC)
  223: {
  224: 	xmlNodePtr curnode;
  225: 
  226: 	if (node != NULL) {
  227: 		curnode = node;
  228: 		while (curnode != NULL) {
  229: 			node = curnode;
  230: 			switch (node->type) {
  231: 				/* Skip property freeing for the following types */
  232: 				case XML_NOTATION_NODE:
  233: 				case XML_ENTITY_DECL:
  234: 					break;
  235: 				case XML_ENTITY_REF_NODE:
  236: 					php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
  237: 					break;
  238: 				case XML_ATTRIBUTE_NODE:
  239: 						if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
  240: 							xmlRemoveID(node->doc, (xmlAttrPtr) node);
  241: 						}
  242: 				case XML_ATTRIBUTE_DECL:
  243: 				case XML_DTD_NODE:
  244: 				case XML_DOCUMENT_TYPE_NODE:
  245: 				case XML_NAMESPACE_DECL:
  246: 				case XML_TEXT_NODE:
  247: 					php_libxml_node_free_list(node->children TSRMLS_CC);
  248: 					break;
  249: 				default:
  250: 					php_libxml_node_free_list(node->children TSRMLS_CC);
  251: 					php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
  252: 			}
  253: 
  254: 			curnode = node->next;
  255: 			xmlUnlinkNode(node);
  256: 			if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
  257: 				node->doc = NULL;
  258: 			}
  259: 			php_libxml_node_free(node);
  260: 		}
  261: 	}
  262: }
  263: 
  264: /* }}} */
  265: 
  266: /* {{{ startup, shutdown and info functions */
  267: static PHP_GINIT_FUNCTION(libxml)
  268: {
  269: 	libxml_globals->stream_context = NULL;
  270: 	libxml_globals->error_buffer.c = NULL;
  271: 	libxml_globals->error_list = NULL;
  272: 	libxml_globals->entity_loader.fci.size = 0;
  273: 	libxml_globals->entity_loader_disabled = 0;
  274: }
  275: 
  276: static void _php_libxml_destroy_fci(zend_fcall_info *fci)
  277: {
  278: 	if (fci->size > 0) {
  279: 		zval_ptr_dtor(&fci->function_name);
  280: 		if (fci->object_ptr != NULL) {
  281: 			zval_ptr_dtor(&fci->object_ptr);
  282: 		}
  283: 		fci->size = 0;
  284: 	}
  285: }
  286: 
  287: /* Channel libxml file io layer through the PHP streams subsystem.
  288:  * This allows use of ftps:// and https:// urls */
  289: 
  290: static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
  291: {
  292: 	php_stream_statbuf ssbuf;
  293: 	php_stream_context *context = NULL;
  294: 	php_stream_wrapper *wrapper = NULL;
  295: 	char *resolved_path, *path_to_open = NULL;
  296: 	void *ret_val = NULL;
  297: 	int isescaped=0;
  298: 	xmlURI *uri;
  299: 
  300: 	TSRMLS_FETCH();
  301: 
  302: 	uri = xmlParseURI(filename);
  303: 	if (uri && (uri->scheme == NULL ||
  304: 			(xmlStrncmp(BAD_CAST uri->scheme, BAD_CAST "file", 4) == 0))) {
  305: 		resolved_path = xmlURIUnescapeString(filename, 0, NULL);
  306: 		isescaped = 1;
  307: 	} else {
  308: 		resolved_path = (char *)filename;
  309: 	}
  310: 
  311: 	if (uri) {
  312: 		xmlFreeURI(uri);
  313: 	}
  314: 
  315: 	if (resolved_path == NULL) {
  316: 		return NULL;
  317: 	}
  318: 
  319: 	/* logic copied from _php_stream_stat, but we only want to fail
  320: 	   if the wrapper supports stat, otherwise, figure it out from
  321: 	   the open.  This logic is only to support hiding warnings
  322: 	   that the streams layer puts out at times, but for libxml we
  323: 	   may try to open files that don't exist, but it is not a failure
  324: 	   in xml processing (eg. DTD files)  */
  325: 	wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, 0 TSRMLS_CC);
  326: 	if (wrapper && read_only && wrapper->wops->url_stat) {
  327: 		if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
  328: 			if (isescaped) {
  329: 				xmlFree(resolved_path);
  330: 			}
  331: 			return NULL;
  332: 		}
  333: 	}
  334: 
  335: 	context = php_stream_context_from_zval(LIBXML(stream_context), 0);
  336: 	
  337: 	ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, REPORT_ERRORS, NULL, context);
  338: 	if (isescaped) {
  339: 		xmlFree(resolved_path);
  340: 	}
  341: 	return ret_val;
  342: }
  343: 
  344: static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
  345: {
  346: 	return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
  347: }
  348: 
  349: static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
  350: {
  351: 	return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
  352: }
  353: 
  354: static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
  355: {
  356: 	TSRMLS_FETCH();
  357: 	return php_stream_read((php_stream*)context, buffer, len);
  358: }
  359: 
  360: static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
  361: {
  362: 	TSRMLS_FETCH();
  363: 	return php_stream_write((php_stream*)context, buffer, len);
  364: }
  365: 
  366: static int php_libxml_streams_IO_close(void *context)
  367: {
  368: 	TSRMLS_FETCH();
  369: 	return php_stream_close((php_stream*)context);
  370: }
  371: 
  372: static xmlParserInputBufferPtr
  373: php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
  374: {
  375: 	xmlParserInputBufferPtr ret;
  376: 	void *context = NULL;
  377: 	TSRMLS_FETCH();
  378: 
  379: 	if (LIBXML(entity_loader_disabled)) {
  380: 		return NULL;
  381: 	}
  382: 
  383: 	if (URI == NULL)
  384: 		return(NULL);
  385: 
  386: 	context = php_libxml_streams_IO_open_read_wrapper(URI);
  387: 
  388: 	if (context == NULL) {
  389: 		return(NULL);
  390: 	}
  391: 
  392: 	/* Allocate the Input buffer front-end. */
  393: 	ret = xmlAllocParserInputBuffer(enc);
  394: 	if (ret != NULL) {
  395: 		ret->context = context;
  396: 		ret->readcallback = php_libxml_streams_IO_read;
  397: 		ret->closecallback = php_libxml_streams_IO_close;
  398: 	} else
  399: 		php_libxml_streams_IO_close(context);
  400: 
  401: 	return(ret);
  402: }
  403: 
  404: static xmlOutputBufferPtr
  405: php_libxml_output_buffer_create_filename(const char *URI,
  406:                               xmlCharEncodingHandlerPtr encoder,
  407:                               int compression ATTRIBUTE_UNUSED)
  408: {
  409: 	xmlOutputBufferPtr ret;
  410: 	xmlURIPtr puri;
  411: 	void *context = NULL;
  412: 	char *unescaped = NULL;
  413: 
  414: 	if (URI == NULL)
  415: 		return(NULL);
  416: 
  417: 	puri = xmlParseURI(URI);
  418: 	if (puri != NULL) {
  419: 		if (puri->scheme != NULL)
  420: 			unescaped = xmlURIUnescapeString(URI, 0, NULL);
  421: 		xmlFreeURI(puri);
  422: 	}
  423: 
  424: 	if (unescaped != NULL) {
  425: 		context = php_libxml_streams_IO_open_write_wrapper(unescaped);
  426: 		xmlFree(unescaped);
  427: 	}
  428: 
  429: 	/* try with a non-escaped URI this may be a strange filename */
  430: 	if (context == NULL) {
  431: 		context = php_libxml_streams_IO_open_write_wrapper(URI);
  432: 	}
  433: 
  434: 	if (context == NULL) {
  435: 		return(NULL);
  436: 	}
  437: 
  438: 	/* Allocate the Output buffer front-end. */
  439: 	ret = xmlAllocOutputBuffer(encoder);
  440: 	if (ret != NULL) {
  441: 		ret->context = context;
  442: 		ret->writecallback = php_libxml_streams_IO_write;
  443: 		ret->closecallback = php_libxml_streams_IO_close;
  444: 	}
  445: 
  446: 	return(ret);
  447: }
  448: 
  449: static int _php_libxml_free_error(xmlErrorPtr error)
  450: {
  451: 	/* This will free the libxml alloc'd memory */
  452: 	xmlResetError(error);
  453: 	return 1;
  454: }
  455: 
  456: static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
  457: {
  458: 	xmlError error_copy;
  459: 	int ret;
  460: 
  461: 	TSRMLS_FETCH();
  462: 
  463: 	memset(&error_copy, 0, sizeof(xmlError));
  464: 
  465: 	if (error) {
  466: 		ret = xmlCopyError(error, &error_copy);
  467: 	} else {
  468: 		error_copy.domain = 0;
  469: 		error_copy.code = XML_ERR_INTERNAL_ERROR;
  470: 		error_copy.level = XML_ERR_ERROR;
  471: 		error_copy.line = 0;
  472: 		error_copy.node = NULL;
  473: 		error_copy.int1 = 0;
  474: 		error_copy.int2 = 0;
  475: 		error_copy.ctxt = NULL;
  476: 		error_copy.message = xmlStrdup(msg);
  477: 		error_copy.file = NULL;
  478: 		error_copy.str1 = NULL;
  479: 		error_copy.str2 = NULL;
  480: 		error_copy.str3 = NULL;
  481: 		ret = 0;
  482: 	}
  483: 
  484: 	if (ret == 0) {
  485: 		zend_llist_add_element(LIBXML(error_list), &error_copy);
  486: 	}
  487: }
  488: 
  489: static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC)
  490: {
  491: 	xmlParserCtxtPtr parser;
  492: 
  493: 	parser = (xmlParserCtxtPtr) ctx;
  494: 
  495: 	if (parser != NULL && parser->input != NULL) {
  496: 		if (parser->input->filename) {
  497: 			php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
  498: 		} else {
  499: 			php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line);
  500: 		}
  501: 	}
  502: }
  503: 
  504: void php_libxml_issue_error(int level, const char *msg TSRMLS_DC)
  505: {
  506: 	if (LIBXML(error_list)) {
  507: 		_php_list_set_error_structure(NULL, msg);
  508: 	} else {
  509: 		php_error_docref(NULL TSRMLS_CC, level, "%s", msg);
  510: 	}
  511: }
  512: 
  513: static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
  514: {
  515: 	char *buf;
  516: 	int len, len_iter, output = 0;
  517: 
  518: 	TSRMLS_FETCH();
  519: 
  520: 	len = vspprintf(&buf, 0, *msg, ap);
  521: 	len_iter = len;
  522: 
  523: 	/* remove any trailing \n */
  524: 	while (len_iter && buf[--len_iter] == '\n') {
  525: 		buf[len_iter] = '\0';
  526: 		output = 1;
  527: 	}
  528: 
  529: 	smart_str_appendl(&LIBXML(error_buffer), buf, len);
  530: 
  531: 	efree(buf);
  532: 
  533: 	if (output == 1) {
  534: 		if (LIBXML(error_list)) {
  535: 			_php_list_set_error_structure(NULL, LIBXML(error_buffer).c);
  536: 		} else {
  537: 			switch (error_type) {
  538: 				case PHP_LIBXML_CTX_ERROR:
  539: 					php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC);
  540: 					break;
  541: 				case PHP_LIBXML_CTX_WARNING:
  542: 					php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC);
  543: 					break;
  544: 				default:
  545: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c);
  546: 			}
  547: 		}
  548: 		smart_str_free(&LIBXML(error_buffer));
  549: 	}
  550: }
  551: 
  552: static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL,
  553: 		const char *ID, xmlParserCtxtPtr context)
  554: {
  555: 	xmlParserInputPtr	ret			= NULL;
  556: 	const char			*resource	= NULL;
  557: 	zval				*public		= NULL,
  558: 						*system		= NULL,
  559: 						*ctxzv		= NULL,
  560: 						**params[]	= {&public, &system, &ctxzv},
  561: 						*retval_ptr	= NULL;
  562: 	int					retval;
  563: 	zend_fcall_info		*fci;
  564: 	TSRMLS_FETCH();
  565: 
  566: 	fci = &LIBXML(entity_loader).fci;
  567: 	
  568: 	if (fci->size == 0) {
  569: 		/* no custom user-land callback set up; delegate to original loader */
  570: 		return _php_libxml_default_entity_loader(URL, ID, context);
  571: 	}
  572: 
  573: 	ALLOC_INIT_ZVAL(public);
  574: 	if (ID != NULL) {
  575: 		ZVAL_STRING(public, ID, 1);
  576: 	}
  577: 	ALLOC_INIT_ZVAL(system);
  578: 	if (URL != NULL) {
  579: 		ZVAL_STRING(system, URL, 1);
  580: 	}
  581: 	MAKE_STD_ZVAL(ctxzv);
  582: 	array_init_size(ctxzv, 4);
  583: 
  584: #define ADD_NULL_OR_STRING_KEY(memb) \
  585: 	if (context->memb == NULL) { \
  586: 		add_assoc_null_ex(ctxzv, #memb, sizeof(#memb)); \
  587: 	} else { \
  588: 		add_assoc_string_ex(ctxzv, #memb, sizeof(#memb), \
  589: 				(char *)context->memb, 1); \
  590: 	}
  591: 	
  592: 	ADD_NULL_OR_STRING_KEY(directory)
  593: 	ADD_NULL_OR_STRING_KEY(intSubName)
  594: 	ADD_NULL_OR_STRING_KEY(extSubURI)
  595: 	ADD_NULL_OR_STRING_KEY(extSubSystem)
  596: 	
  597: #undef ADD_NULL_OR_STRING_KEY
  598: 	
  599: 	fci->retval_ptr_ptr	= &retval_ptr;
  600: 	fci->params			= params;
  601: 	fci->param_count	= sizeof(params)/sizeof(*params);
  602: 	fci->no_separation	= 1;
  603: 	
  604: 	retval = zend_call_function(fci, &LIBXML(entity_loader).fcc TSRMLS_CC);
  605: 	if (retval != SUCCESS || fci->retval_ptr_ptr == NULL) {
  606: 		php_libxml_ctx_error(context,
  607: 				"Call to user entity loader callback '%s' has failed",
  608: 				fci->function_name);
  609: 	} else {
  610: 		retval_ptr = *fci->retval_ptr_ptr;
  611: 		if (retval_ptr == NULL) {
  612: 			php_libxml_ctx_error(context,
  613: 					"Call to user entity loader callback '%s' has failed; "
  614: 					"probably it has thrown an exception",
  615: 					fci->function_name);
  616: 		} else if (Z_TYPE_P(retval_ptr) == IS_STRING) {
  617: is_string:
  618: 			resource = Z_STRVAL_P(retval_ptr);
  619: 		} else if (Z_TYPE_P(retval_ptr) == IS_RESOURCE) {
  620: 			php_stream *stream;
  621: 			php_stream_from_zval_no_verify(stream, &retval_ptr);
  622: 			if (stream == NULL) {
  623: 				php_libxml_ctx_error(context,
  624: 						"The user entity loader callback '%s' has returned a "
  625: 						"resource, but it is not a stream",
  626: 						fci->function_name);
  627: 			} else {
  628: 				/* TODO: allow storing the encoding in the stream context? */
  629: 				xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
  630: 				xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc);
  631: 				if (pib == NULL) {
  632: 					php_libxml_ctx_error(context, "Could not allocate parser "
  633: 							"input buffer");
  634: 				} else {
  635: 					/* make stream not being closed when the zval is freed */
  636: 					zend_list_addref(stream->rsrc_id);
  637: 					pib->context = stream;
  638: 					pib->readcallback = php_libxml_streams_IO_read;
  639: 					pib->closecallback = php_libxml_streams_IO_close;
  640: 					
  641: 					ret = xmlNewIOInputStream(context, pib, enc);
  642: 					if (ret == NULL) {
  643: 						xmlFreeParserInputBuffer(pib);
  644: 					}
  645: 				}
  646: 			}
  647: 		} else if (Z_TYPE_P(retval_ptr) != IS_NULL) {
  648: 			/* retval not string nor resource nor null; convert to string */
  649: 			SEPARATE_ZVAL(&retval_ptr);
  650: 			convert_to_string(retval_ptr);
  651: 			goto is_string;
  652: 		} /* else is null; don't try anything */
  653: 	}
  654: 
  655: 	if (ret == NULL) {
  656: 		if (resource == NULL) {
  657: 			if (ID == NULL) {
  658: 				ID = "NULL";
  659: 			}
  660: 			php_libxml_ctx_error(context,
  661: 					"Failed to load external entity \"%s\"\n", ID);
  662: 		} else {
  663: 			/* we got the resource in the form of a string; open it */
  664: 			ret = xmlNewInputFromFile(context, resource);
  665: 		}
  666: 	}
  667: 
  668: 	zval_ptr_dtor(&public);
  669: 	zval_ptr_dtor(&system);
  670: 	zval_ptr_dtor(&ctxzv);
  671: 	if (retval_ptr != NULL) {
  672: 		zval_ptr_dtor(&retval_ptr);
  673: 	}
  674: 	return ret;
  675: }
  676: 
  677: static xmlParserInputPtr _php_libxml_pre_ext_ent_loader(const char *URL,
  678: 		const char *ID, xmlParserCtxtPtr context)
  679: {
  680: 	TSRMLS_FETCH();
  681: 
  682: 	/* Check whether we're running in a PHP context, since the entity loader
  683: 	 * we've defined is an application level (true global) setting.
  684: 	 * If we are, we also want to check whether we've finished activating
  685: 	 * the modules (RINIT phase). Using our external entity loader during a
  686: 	 * RINIT should not be problem per se (though during MINIT it is, because
  687: 	 * we don't even have a resource list by then), but then whether one
  688: 	 * extension would be using the custom external entity loader or not
  689: 	 * could depend on extension loading order
  690: 	 * (if _php_libxml_per_request_initialization */
  691: 	if (xmlGenericError == php_libxml_error_handler && PG(modules_activated)) {
  692: 		return _php_libxml_external_entity_loader(URL, ID, context);
  693: 	} else {
  694: 		return _php_libxml_default_entity_loader(URL, ID, context);
  695: 	}
  696: }
  697: 
  698: PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
  699: {
  700: 	va_list args;
  701: 	va_start(args, msg);
  702: 	php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
  703: 	va_end(args);
  704: }
  705: 
  706: PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
  707: {
  708: 	va_list args;
  709: 	va_start(args, msg);
  710: 	php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
  711: 	va_end(args);
  712: }
  713: 
  714: PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
  715: {
  716: 	_php_list_set_error_structure(error, NULL);
  717: 
  718: 	return;
  719: }
  720: 
  721: PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
  722: {
  723: 	va_list args;
  724: 	va_start(args, msg);
  725: 	php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
  726: 	va_end(args);
  727: }
  728: 
  729: 
  730: PHP_LIBXML_API void php_libxml_initialize(void)
  731: {
  732: 	if (!_php_libxml_initialized) {
  733: 		/* we should be the only one's to ever init!! */
  734: 		xmlInitParser();
  735: 		
  736: 		_php_libxml_default_entity_loader = xmlGetExternalEntityLoader();
  737: 		xmlSetExternalEntityLoader(_php_libxml_pre_ext_ent_loader);
  738: 
  739: 		zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
  740: 
  741: 		_php_libxml_initialized = 1;
  742: 	}
  743: }
  744: 
  745: PHP_LIBXML_API void php_libxml_shutdown(void)
  746: {
  747: 	if (_php_libxml_initialized) {
  748: #if defined(LIBXML_SCHEMAS_ENABLED)
  749: 		xmlRelaxNGCleanupTypes();
  750: #endif
  751: 		xmlCleanupParser();
  752: 		zend_hash_destroy(&php_libxml_exports);
  753: 		
  754: 		xmlSetExternalEntityLoader(_php_libxml_default_entity_loader);
  755: 		_php_libxml_initialized = 0;
  756: 	}
  757: }
  758: 
  759: PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
  760: {
  761: 	zval *oldcontext;
  762: 
  763: 	oldcontext = LIBXML(stream_context);
  764: 	LIBXML(stream_context) = context;
  765: 	return oldcontext;
  766: 
  767: }
  768: 
  769: static PHP_MINIT_FUNCTION(libxml)
  770: {
  771: 	zend_class_entry ce;
  772: 
  773: 	php_libxml_initialize();
  774: 
  775: 	REGISTER_LONG_CONSTANT("LIBXML_VERSION",			LIBXML_VERSION,			CONST_CS | CONST_PERSISTENT);
  776: 	REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",	LIBXML_DOTTED_VERSION,	CONST_CS | CONST_PERSISTENT);
  777: 	REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",	(char *)xmlParserVersion,		CONST_CS | CONST_PERSISTENT);
  778: 
  779: 	/* For use with loading xml */
  780: 	REGISTER_LONG_CONSTANT("LIBXML_NOENT",		XML_PARSE_NOENT,		CONST_CS | CONST_PERSISTENT);
  781: 	REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",	XML_PARSE_DTDLOAD,		CONST_CS | CONST_PERSISTENT);
  782: 	REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",	XML_PARSE_DTDATTR,		CONST_CS | CONST_PERSISTENT);
  783: 	REGISTER_LONG_CONSTANT("LIBXML_DTDVALID",	XML_PARSE_DTDVALID,		CONST_CS | CONST_PERSISTENT);
  784: 	REGISTER_LONG_CONSTANT("LIBXML_NOERROR",	XML_PARSE_NOERROR,		CONST_CS | CONST_PERSISTENT);
  785: 	REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",	XML_PARSE_NOWARNING,	CONST_CS | CONST_PERSISTENT);
  786: 	REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS",	XML_PARSE_NOBLANKS,		CONST_CS | CONST_PERSISTENT);
  787: 	REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE",	XML_PARSE_XINCLUDE,		CONST_CS | CONST_PERSISTENT);
  788: 	REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",	XML_PARSE_NSCLEAN,		CONST_CS | CONST_PERSISTENT);
  789: 	REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",	XML_PARSE_NOCDATA,		CONST_CS | CONST_PERSISTENT);
  790: 	REGISTER_LONG_CONSTANT("LIBXML_NONET",		XML_PARSE_NONET,		CONST_CS | CONST_PERSISTENT);
  791: 	REGISTER_LONG_CONSTANT("LIBXML_PEDANTIC",	XML_PARSE_PEDANTIC,		CONST_CS | CONST_PERSISTENT);
  792: #if LIBXML_VERSION >= 20621
  793: 	REGISTER_LONG_CONSTANT("LIBXML_COMPACT",	XML_PARSE_COMPACT,		CONST_CS | CONST_PERSISTENT);
  794: 	REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",	XML_SAVE_NO_DECL,		CONST_CS | CONST_PERSISTENT);
  795: #endif
  796: #if LIBXML_VERSION >= 20703
  797: 	REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE",	XML_PARSE_HUGE,			CONST_CS | CONST_PERSISTENT);
  798: #endif
  799: 	REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG",	LIBXML_SAVE_NOEMPTYTAG,	CONST_CS | CONST_PERSISTENT);
  800: 
  801: 	/* Additional constants for use with loading html */
  802: #if LIBXML_VERSION >= 20707
  803: 	REGISTER_LONG_CONSTANT("LIBXML_HTML_NOIMPLIED",	HTML_PARSE_NOIMPLIED,		CONST_CS | CONST_PERSISTENT);
  804: #endif
  805: 
  806: #if LIBXML_VERSION >= 20708
  807: 	REGISTER_LONG_CONSTANT("LIBXML_HTML_NODEFDTD",	HTML_PARSE_NODEFDTD,		CONST_CS | CONST_PERSISTENT);
  808: #endif
  809: 
  810: 	/* Error levels */
  811: 	REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",		XML_ERR_NONE,		CONST_CS | CONST_PERSISTENT);
  812: 	REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",	XML_ERR_WARNING,	CONST_CS | CONST_PERSISTENT);
  813: 	REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",		XML_ERR_ERROR,		CONST_CS | CONST_PERSISTENT);
  814: 	REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",		XML_ERR_FATAL,		CONST_CS | CONST_PERSISTENT);
  815: 
  816: 	INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
  817: 	libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
  818: 
  819: 	if (sapi_module.name) {
  820: 		static const char * const supported_sapis[] = {
  821: 			"cgi-fcgi",
  822: 			"fpm-fcgi",
  823: 			"litespeed",
  824: 			NULL
  825: 		};
  826: 		const char * const *sapi_name;
  827: 
  828: 		for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
  829: 			if (strcmp(sapi_module.name, *sapi_name) == 0) {
  830: 				_php_libxml_per_request_initialization = 0;
  831: 				break;
  832: 			}
  833: 		}
  834: 	}
  835: 
  836: 	if (!_php_libxml_per_request_initialization) {
  837: 		/* report errors via handler rather than stderr */
  838: 		xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
  839: 		xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
  840: 		xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
  841: 	}
  842: 	
  843: 	return SUCCESS;
  844: }
  845: 
  846: 
  847: static PHP_RINIT_FUNCTION(libxml)
  848: {
  849: 	if (_php_libxml_per_request_initialization) {
  850: 		/* report errors via handler rather than stderr */
  851: 		xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
  852: 		xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
  853: 		xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
  854: 	}
  855: 	return SUCCESS;
  856: }
  857: 
  858: 
  859: static PHP_MSHUTDOWN_FUNCTION(libxml)
  860: {
  861: 	if (!_php_libxml_per_request_initialization) {
  862: 		xmlSetGenericErrorFunc(NULL, NULL);
  863: 
  864: 		xmlParserInputBufferCreateFilenameDefault(NULL);
  865: 		xmlOutputBufferCreateFilenameDefault(NULL);
  866: 	}
  867: 	php_libxml_shutdown();
  868: 
  869: 	return SUCCESS;
  870: }
  871: 
  872: static int php_libxml_post_deactivate(void)
  873: {
  874: 	TSRMLS_FETCH();
  875: 	/* reset libxml generic error handling */
  876: 	if (_php_libxml_per_request_initialization) {
  877: 		xmlSetGenericErrorFunc(NULL, NULL);
  878: 
  879: 		xmlParserInputBufferCreateFilenameDefault(NULL);
  880: 		xmlOutputBufferCreateFilenameDefault(NULL);
  881: 	}
  882: 	xmlSetStructuredErrorFunc(NULL, NULL);
  883: 
  884: 	if (LIBXML(stream_context)) {
  885: 		/* the steam_context resource will be released by resource list destructor */
  886: 		efree(LIBXML(stream_context));
  887: 		LIBXML(stream_context) = NULL;
  888: 	}
  889: 	smart_str_free(&LIBXML(error_buffer));
  890: 	if (LIBXML(error_list)) {
  891: 		zend_llist_destroy(LIBXML(error_list));
  892: 		efree(LIBXML(error_list));
  893: 		LIBXML(error_list) = NULL;
  894: 	}
  895: 	xmlResetLastError();
  896: 	
  897: 	_php_libxml_destroy_fci(&LIBXML(entity_loader).fci);
  898: 
  899: 	return SUCCESS;
  900: }
  901: 
  902: 
  903: static PHP_MINFO_FUNCTION(libxml)
  904: {
  905: 	php_info_print_table_start();
  906: 	php_info_print_table_row(2, "libXML support", "active");
  907: 	php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
  908: 	php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
  909: 	php_info_print_table_row(2, "libXML streams", "enabled");
  910: 	php_info_print_table_end();
  911: }
  912: /* }}} */
  913: 
  914: /* {{{ proto void libxml_set_streams_context(resource streams_context) 
  915:    Set the streams context for the next libxml document load or write */
  916: static PHP_FUNCTION(libxml_set_streams_context)
  917: {
  918: 	zval *arg;
  919: 
  920: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg) == FAILURE) {
  921: 		return;
  922: 	}
  923: 	if (LIBXML(stream_context)) {
  924: 		zval_ptr_dtor(&LIBXML(stream_context));
  925: 		LIBXML(stream_context) = NULL;
  926: 	}
  927: 	Z_ADDREF_P(arg);
  928: 	LIBXML(stream_context) = arg;
  929: }
  930: /* }}} */
  931: 
  932: /* {{{ proto bool libxml_use_internal_errors([boolean use_errors]) 
  933:    Disable libxml errors and allow user to fetch error information as needed */
  934: static PHP_FUNCTION(libxml_use_internal_errors)
  935: {
  936: 	xmlStructuredErrorFunc current_handler;
  937: 	zend_bool use_errors=0, retval;
  938: 
  939: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
  940: 		return;
  941: 	}
  942: 
  943: 	current_handler = xmlStructuredError;
  944: 	if (current_handler && current_handler == php_libxml_structured_error_handler) {
  945: 		retval = 1;
  946: 	} else {
  947: 		retval = 0;
  948: 	}
  949: 
  950: 	if (ZEND_NUM_ARGS() == 0) {
  951: 		RETURN_BOOL(retval);
  952: 	}
  953: 
  954: 	if (use_errors == 0) {
  955: 		xmlSetStructuredErrorFunc(NULL, NULL);
  956: 		if (LIBXML(error_list)) {
  957: 			zend_llist_destroy(LIBXML(error_list));
  958: 			efree(LIBXML(error_list));
  959: 			LIBXML(error_list) = NULL;
  960: 		}
  961: 	} else {
  962: 		xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
  963: 		if (LIBXML(error_list) == NULL) {
  964: 			LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
  965: 			zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
  966: 		}
  967: 	}
  968: 	RETURN_BOOL(retval);
  969: }
  970: /* }}} */
  971: 
  972: /* {{{ proto object libxml_get_last_error() 
  973:    Retrieve last error from libxml */
  974: static PHP_FUNCTION(libxml_get_last_error)
  975: {
  976: 	xmlErrorPtr error;
  977: 
  978: 	error = xmlGetLastError();
  979: 	
  980: 	if (error) {
  981: 		object_init_ex(return_value, libxmlerror_class_entry);
  982: 		add_property_long(return_value, "level", error->level);
  983: 		add_property_long(return_value, "code", error->code);
  984: 		add_property_long(return_value, "column", error->int2);
  985: 		if (error->message) {
  986: 			add_property_string(return_value, "message", error->message, 1);
  987: 		} else {
  988: 			add_property_stringl(return_value, "message", "", 0, 1);
  989: 		}
  990: 		if (error->file) {
  991: 			add_property_string(return_value, "file", error->file, 1);
  992: 		} else {
  993: 			add_property_stringl(return_value, "file", "", 0, 1);
  994: 		}
  995: 		add_property_long(return_value, "line", error->line);
  996: 	} else {
  997: 		RETURN_FALSE;
  998: 	}
  999: }
 1000: /* }}} */
 1001: 
 1002: /* {{{ proto object libxml_get_errors()
 1003:    Retrieve array of errors */
 1004: static PHP_FUNCTION(libxml_get_errors)
 1005: {
 1006: 	
 1007: 	xmlErrorPtr error;
 1008: 
 1009: 	if (array_init(return_value) == FAILURE) {
 1010: 		RETURN_FALSE;
 1011: 	}
 1012: 
 1013: 	if (LIBXML(error_list)) {
 1014: 
 1015: 		error = zend_llist_get_first(LIBXML(error_list));
 1016: 
 1017: 		while (error != NULL) {
 1018: 			zval *z_error;
 1019: 			MAKE_STD_ZVAL(z_error);
 1020: 
 1021: 			object_init_ex(z_error, libxmlerror_class_entry);
 1022: 			add_property_long(z_error, "level", error->level);
 1023: 			add_property_long(z_error, "code", error->code);
 1024: 			add_property_long(z_error, "column", error->int2);
 1025: 			if (error->message) {
 1026: 				add_property_string(z_error, "message", error->message, 1);
 1027: 			} else {
 1028: 				add_property_stringl(z_error, "message", "", 0, 1);
 1029: 			}
 1030: 			if (error->file) {
 1031: 				add_property_string(z_error, "file", error->file, 1);
 1032: 			} else {
 1033: 				add_property_stringl(z_error, "file", "", 0, 1);
 1034: 			}
 1035: 			add_property_long(z_error, "line", error->line);
 1036: 			add_next_index_zval(return_value, z_error);
 1037: 
 1038: 			error = zend_llist_get_next(LIBXML(error_list));
 1039: 		}
 1040: 	}
 1041: }
 1042: /* }}} */
 1043: 
 1044: /* {{{ proto void libxml_clear_errors() 
 1045:    Clear last error from libxml */
 1046: static PHP_FUNCTION(libxml_clear_errors)
 1047: {
 1048: 	xmlResetLastError();
 1049: 	if (LIBXML(error_list)) {
 1050: 		zend_llist_clean(LIBXML(error_list));
 1051: 	}
 1052: }
 1053: /* }}} */
 1054: 
 1055: PHP_LIBXML_API zend_bool php_libxml_disable_entity_loader(zend_bool disable TSRMLS_DC)
 1056: {
 1057: 	zend_bool old = LIBXML(entity_loader_disabled);
 1058: 
 1059: 	LIBXML(entity_loader_disabled) = disable;
 1060: 	return old;
 1061: }
 1062: 
 1063: /* {{{ proto bool libxml_disable_entity_loader([boolean disable]) 
 1064:    Disable/Enable ability to load external entities */
 1065: static PHP_FUNCTION(libxml_disable_entity_loader)
 1066: {
 1067: 	zend_bool disable = 1;
 1068: 
 1069: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) {
 1070: 		return;
 1071: 	}
 1072: 
 1073: 	RETURN_BOOL(php_libxml_disable_entity_loader(disable TSRMLS_CC));
 1074: }
 1075: /* }}} */
 1076: 
 1077: /* {{{ proto void libxml_set_external_entity_loader(callback resolver_function) 
 1078:    Changes the default external entity loader */
 1079: static PHP_FUNCTION(libxml_set_external_entity_loader)
 1080: {
 1081: 	zend_fcall_info			fci;
 1082: 	zend_fcall_info_cache	fcc;
 1083: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!", &fci, &fcc)
 1084: 			== FAILURE) {
 1085: 		return;
 1086: 	}
 1087: 	
 1088: 	_php_libxml_destroy_fci(&LIBXML(entity_loader).fci);
 1089: 	
 1090: 	if (fci.size > 0) { /* argument not null */
 1091: 		LIBXML(entity_loader).fci = fci;
 1092: 		Z_ADDREF_P(fci.function_name);
 1093: 		if (fci.object_ptr != NULL) {
 1094: 			Z_ADDREF_P(fci.object_ptr);
 1095: 		}
 1096: 		LIBXML(entity_loader).fcc = fcc;
 1097: 	}
 1098: 	
 1099: 	RETURN_TRUE;
 1100: }
 1101: /* }}} */
 1102: 
 1103: /* {{{ Common functions shared by extensions */
 1104: int php_libxml_xmlCheckUTF8(const unsigned char *s)
 1105: {
 1106: 	int i;
 1107: 	unsigned char c;
 1108: 
 1109: 	for (i = 0; (c = s[i++]);) {
 1110: 		if ((c & 0x80) == 0) {
 1111: 		} else if ((c & 0xe0) == 0xc0) {
 1112: 			if ((s[i++] & 0xc0) != 0x80) {
 1113: 				return 0;
 1114: 			}
 1115: 		} else if ((c & 0xf0) == 0xe0) {
 1116: 			if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
 1117: 				return 0;
 1118: 			}
 1119: 		} else if ((c & 0xf8) == 0xf0) {
 1120: 			if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
 1121: 				return 0;
 1122: 			}
 1123: 		} else {
 1124: 			return 0;
 1125: 		}
 1126: 	}
 1127: 	return 1;
 1128: }
 1129: 
 1130: int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
 1131: {
 1132: 	php_libxml_func_handler export_hnd;
 1133: 	
 1134: 	/* Initialize in case this module hasnt been loaded yet */
 1135: 	php_libxml_initialize();
 1136: 	export_hnd.export_func = export_function;
 1137: 
 1138: 	return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
 1139: }
 1140: 
 1141: PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
 1142: {
 1143: 	zend_class_entry *ce = NULL;
 1144: 	xmlNodePtr node = NULL;
 1145: 	php_libxml_func_handler *export_hnd;
 1146: 
 1147: 	if (object->type == IS_OBJECT) {
 1148: 		ce = Z_OBJCE_P(object);
 1149: 		while (ce->parent != NULL) {
 1150: 			ce = ce->parent;
 1151: 		}
 1152: 		if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd)  == SUCCESS) {
 1153: 			node = export_hnd->export_func(object TSRMLS_CC);
 1154: 		}
 1155: 	}
 1156: 	return node;
 1157: }
 1158: 
 1159: PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
 1160: {
 1161: 	int ret_refcount = -1;
 1162: 
 1163: 	if (object != NULL && node != NULL) {
 1164: 		if (object->node != NULL) {
 1165: 			if (object->node->node == node) {
 1166: 				return object->node->refcount;
 1167: 			} else {
 1168: 				php_libxml_decrement_node_ptr(object TSRMLS_CC);
 1169: 			}
 1170: 		}
 1171: 		if (node->_private != NULL) {
 1172: 			object->node = node->_private;
 1173: 			ret_refcount = ++object->node->refcount;
 1174: 			/* Only dom uses _private */
 1175: 			if (object->node->_private == NULL) {
 1176: 				object->node->_private = private_data;
 1177: 			}
 1178: 		} else {
 1179: 			ret_refcount = 1;
 1180: 			object->node = emalloc(sizeof(php_libxml_node_ptr));
 1181: 			object->node->node = node;
 1182: 			object->node->refcount = 1;
 1183: 			object->node->_private = private_data;
 1184: 			node->_private = object->node;
 1185: 		}
 1186: 	}
 1187: 
 1188: 	return ret_refcount;
 1189: }
 1190: 
 1191: PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
 1192: {
 1193: 	int ret_refcount = -1;
 1194: 	php_libxml_node_ptr *obj_node;
 1195: 
 1196: 	if (object != NULL && object->node != NULL) {
 1197: 		obj_node = (php_libxml_node_ptr *) object->node;
 1198: 		ret_refcount = --obj_node->refcount;
 1199: 		if (ret_refcount == 0) {
 1200: 			if (obj_node->node != NULL) {
 1201: 				obj_node->node->_private = NULL;
 1202: 			}
 1203: 			efree(obj_node);
 1204: 		} 
 1205: 		object->node = NULL;
 1206: 	}
 1207: 
 1208: 	return ret_refcount;
 1209: }
 1210: 
 1211: PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
 1212: {
 1213: 	int ret_refcount = -1;
 1214: 
 1215: 	if (object->document != NULL) {
 1216: 		object->document->refcount++;
 1217: 		ret_refcount = object->document->refcount;
 1218: 	} else if (docp != NULL) {
 1219: 		ret_refcount = 1;
 1220: 		object->document = emalloc(sizeof(php_libxml_ref_obj));
 1221: 		object->document->ptr = docp;
 1222: 		object->document->refcount = ret_refcount;
 1223: 		object->document->doc_props = NULL;
 1224: 	}
 1225: 
 1226: 	return ret_refcount;
 1227: }
 1228: 
 1229: PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
 1230: {
 1231: 	int ret_refcount = -1;
 1232: 
 1233: 	if (object != NULL && object->document != NULL) {
 1234: 		ret_refcount = --object->document->refcount;
 1235: 		if (ret_refcount == 0) {
 1236: 			if (object->document->ptr != NULL) {
 1237: 				xmlFreeDoc((xmlDoc *) object->document->ptr);
 1238: 			}
 1239: 			if (object->document->doc_props != NULL) {
 1240: 				if (object->document->doc_props->classmap) {
 1241: 					zend_hash_destroy(object->document->doc_props->classmap);
 1242: 					FREE_HASHTABLE(object->document->doc_props->classmap);
 1243: 				}
 1244: 				efree(object->document->doc_props);
 1245: 			}
 1246: 			efree(object->document);
 1247: 			object->document = NULL;
 1248: 		}
 1249: 	}
 1250: 
 1251: 	return ret_refcount;
 1252: }
 1253: 
 1254: PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
 1255: {
 1256: 	if (!node) {
 1257: 		return;
 1258: 	}
 1259: 
 1260: 	switch (node->type) {
 1261: 		case XML_DOCUMENT_NODE:
 1262: 		case XML_HTML_DOCUMENT_NODE:
 1263: 			break;
 1264: 		default:
 1265: 			if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
 1266: 				php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
 1267: 				switch (node->type) {
 1268: 					/* Skip property freeing for the following types */
 1269: 					case XML_ATTRIBUTE_DECL:
 1270: 					case XML_DTD_NODE:
 1271: 					case XML_DOCUMENT_TYPE_NODE:
 1272: 					case XML_ENTITY_DECL:
 1273: 					case XML_ATTRIBUTE_NODE:
 1274: 					case XML_NAMESPACE_DECL:
 1275: 					case XML_TEXT_NODE:
 1276: 						break;
 1277: 					default:
 1278: 						php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
 1279: 				}
 1280: 				if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
 1281: 					node->doc = NULL;
 1282: 				}
 1283: 				php_libxml_node_free(node);
 1284: 			} else {
 1285: 				php_libxml_unregister_node(node TSRMLS_CC);
 1286: 			}
 1287: 	}
 1288: }
 1289: 
 1290: PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
 1291: {
 1292: 	int ret_refcount = -1;
 1293: 	xmlNodePtr nodep;
 1294: 	php_libxml_node_ptr *obj_node;
 1295: 
 1296: 	if (object != NULL && object->node != NULL) {
 1297: 		obj_node = (php_libxml_node_ptr *) object->node;
 1298: 		nodep = object->node->node;
 1299: 		ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
 1300: 		if (ret_refcount == 0) {
 1301: 			php_libxml_node_free_resource(nodep TSRMLS_CC);
 1302: 		} else {
 1303: 			if (obj_node && object == obj_node->_private) {
 1304: 				obj_node->_private = NULL;
 1305: 			}
 1306: 		}
 1307: 	}
 1308: 	if (object != NULL && object->document != NULL) {
 1309: 		/* Safe to call as if the resource were freed then doc pointer is NULL */
 1310: 		php_libxml_decrement_doc_ref(object TSRMLS_CC);
 1311: 	}
 1312: }
 1313: /* }}} */
 1314: 
 1315: #ifdef PHP_WIN32
 1316: PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 1317: {
 1318: 	return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
 1319: }
 1320: #endif
 1321: 
 1322: #endif
 1323: 
 1324: /*
 1325:  * Local variables:
 1326:  * tab-width: 4
 1327:  * c-basic-offset: 4
 1328:  * End:
 1329:  * vim600: sw=4 ts=4 fdm=marker
 1330:  * vim<600: sw=4 ts=4
 1331:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>