root/ext/libxml/libxml.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_libxml_clear_object
  2. php_libxml_unregister_node
  3. php_libxml_node_free
  4. php_libxml_node_free_list
  5. PHP_GINIT_FUNCTION
  6. _php_libxml_destroy_fci
  7. php_libxml_streams_IO_open_wrapper
  8. php_libxml_streams_IO_open_read_wrapper
  9. php_libxml_streams_IO_open_write_wrapper
  10. php_libxml_streams_IO_read
  11. php_libxml_streams_IO_write
  12. php_libxml_streams_IO_close
  13. php_libxml_input_buffer_create_filename
  14. php_libxml_output_buffer_create_filename
  15. _php_libxml_free_error
  16. _php_list_set_error_structure
  17. php_libxml_ctx_error_level
  18. php_libxml_issue_error
  19. php_libxml_internal_error_handler
  20. _php_libxml_external_entity_loader
  21. _php_libxml_pre_ext_ent_loader
  22. php_libxml_ctx_error
  23. php_libxml_ctx_warning
  24. php_libxml_structured_error_handler
  25. php_libxml_error_handler
  26. php_libxml_initialize
  27. php_libxml_shutdown
  28. php_libxml_switch_context
  29. PHP_MINIT_FUNCTION
  30. PHP_RINIT_FUNCTION
  31. PHP_MSHUTDOWN_FUNCTION
  32. php_libxml_post_deactivate
  33. PHP_MINFO_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. php_libxml_disable_entity_loader
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. php_libxml_xmlCheckUTF8
  43. php_libxml_register_export
  44. php_libxml_import_node
  45. php_libxml_increment_node_ptr
  46. php_libxml_decrement_node_ptr
  47. php_libxml_increment_doc_ref
  48. php_libxml_decrement_doc_ref
  49. php_libxml_node_free_resource
  50. php_libxml_node_decrement_resource
  51. DllMain

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

/* [<][>][^][v][top][bottom][index][help] */