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: 525 589 89.1 %
Date: 2014-07-21 Functions: 49 50 98.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:12 +0000 (8 days ago)

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