PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/libxml - libxml.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 516 584 88.4 %
Date: 2014-11-22 Functions: 51 52 98.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:17 +0000 (45 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.