Back to index

php5  5.3.10
libxml.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Shane Caraveo <shane@php.net>                               |
00016    |          Wez Furlong <wez@thebrainroom.com>                          |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: libxml.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #define IS_EXT_MODULE
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "php.h"
00029 
00030 #define PHP_XML_INTERNAL
00031 #include "zend_variables.h"
00032 #include "ext/standard/php_string.h"
00033 #include "ext/standard/info.h"
00034 #include "ext/standard/file.h"
00035 
00036 #if HAVE_LIBXML
00037 
00038 #include <libxml/parser.h>
00039 #include <libxml/parserInternals.h>
00040 #include <libxml/tree.h>
00041 #include <libxml/uri.h>
00042 #include <libxml/xmlerror.h>
00043 #include <libxml/xmlsave.h>
00044 #ifdef LIBXML_SCHEMAS_ENABLED
00045 #include <libxml/relaxng.h>
00046 #endif
00047 
00048 #include "php_libxml.h"
00049 
00050 #define PHP_LIBXML_ERROR 0
00051 #define PHP_LIBXML_CTX_ERROR 1
00052 #define PHP_LIBXML_CTX_WARNING 2
00053 
00054 /* a true global for initialization */
00055 static int _php_libxml_initialized = 0;
00056 
00057 typedef struct _php_libxml_func_handler {
00058        php_libxml_export_node export_func;
00059 } php_libxml_func_handler;
00060 
00061 static HashTable php_libxml_exports;
00062 
00063 static ZEND_DECLARE_MODULE_GLOBALS(libxml)
00064 static PHP_GINIT_FUNCTION(libxml);
00065 
00066 static PHP_FUNCTION(libxml_set_streams_context);
00067 static PHP_FUNCTION(libxml_use_internal_errors);
00068 static PHP_FUNCTION(libxml_get_last_error);
00069 static PHP_FUNCTION(libxml_clear_errors);
00070 static PHP_FUNCTION(libxml_get_errors);
00071 static PHP_FUNCTION(libxml_disable_entity_loader);
00072 
00073 static zend_class_entry *libxmlerror_class_entry;
00074 
00075 /* {{{ dynamically loadable module stuff */
00076 #ifdef COMPILE_DL_LIBXML
00077 ZEND_GET_MODULE(libxml)
00078 #endif /* COMPILE_DL_LIBXML */
00079 /* }}} */
00080 
00081 /* {{{ function prototypes */
00082 static PHP_MINIT_FUNCTION(libxml);
00083 static PHP_RINIT_FUNCTION(libxml);
00084 static PHP_MSHUTDOWN_FUNCTION(libxml);
00085 static PHP_RSHUTDOWN_FUNCTION(libxml);
00086 static PHP_MINFO_FUNCTION(libxml);
00087 
00088 /* }}} */
00089 
00090 /* {{{ arginfo */
00091 ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
00092        ZEND_ARG_INFO(0, context)
00093 ZEND_END_ARG_INFO()
00094 
00095 ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0)
00096        ZEND_ARG_INFO(0, use_errors)
00097 ZEND_END_ARG_INFO()
00098 
00099 ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
00100 ZEND_END_ARG_INFO()
00101 
00102 ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
00103 ZEND_END_ARG_INFO()
00104 
00105 ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
00106 ZEND_END_ARG_INFO()
00107 
00108 ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0)
00109        ZEND_ARG_INFO(0, disable)
00110 ZEND_END_ARG_INFO()
00111 
00112 /* }}} */
00113 
00114 /* {{{ extension definition structures */
00115 static const zend_function_entry libxml_functions[] = {
00116        PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
00117        PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
00118        PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
00119        PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
00120        PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
00121        PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader)
00122        PHP_FE_END
00123 };
00124 
00125 zend_module_entry libxml_module_entry = {
00126        STANDARD_MODULE_HEADER,
00127        "libxml",                /* extension name */
00128        libxml_functions,        /* extension function list */
00129        PHP_MINIT(libxml),       /* extension-wide startup function */
00130        PHP_MSHUTDOWN(libxml),   /* extension-wide shutdown function */
00131        PHP_RINIT(libxml),       /* per-request startup function */
00132        PHP_RSHUTDOWN(libxml),   /* per-request shutdown function */
00133        PHP_MINFO(libxml),       /* information function */
00134        NO_VERSION_YET,
00135        PHP_MODULE_GLOBALS(libxml), /* globals descriptor */
00136        PHP_GINIT(libxml),          /* globals ctor */
00137        NULL,                       /* globals dtor */
00138        NULL,                       /* post deactivate */
00139        STANDARD_MODULE_PROPERTIES_EX
00140 };
00141 
00142 /* }}} */
00143 
00144 /* {{{ internal functions for interoperability */
00145 static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC)
00146 {
00147        if (object->properties) {
00148               object->properties = NULL;
00149        }
00150        php_libxml_decrement_node_ptr(object TSRMLS_CC);
00151        return php_libxml_decrement_doc_ref(object TSRMLS_CC);
00152 }
00153 
00154 static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC)
00155 {
00156        php_libxml_node_object *wrapper;
00157 
00158        php_libxml_node_ptr *nodeptr = nodep->_private;
00159 
00160        if (nodeptr != NULL) {
00161               wrapper = nodeptr->_private;
00162               if (wrapper) {
00163                      php_libxml_clear_object(wrapper TSRMLS_CC);
00164               } else {
00165                      if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
00166                             nodeptr->node->_private = NULL;
00167                      }
00168                      nodeptr->node = NULL;
00169               }
00170        }
00171 
00172        return -1;
00173 }
00174 
00175 static void php_libxml_node_free(xmlNodePtr node)
00176 {
00177        if(node) {
00178               if (node->_private != NULL) {
00179                      ((php_libxml_node_ptr *) node->_private)->node = NULL;
00180               }
00181               switch (node->type) {
00182                      case XML_ATTRIBUTE_NODE:
00183                             xmlFreeProp((xmlAttrPtr) node);
00184                             break;
00185                      case XML_ENTITY_DECL:
00186                      case XML_ELEMENT_DECL:
00187                      case XML_ATTRIBUTE_DECL:
00188                             break;
00189                      case XML_NOTATION_NODE:
00190                             /* These require special handling */
00191                             if (node->name != NULL) {
00192                                    xmlFree((char *) node->name);
00193                             }
00194                             if (((xmlEntityPtr) node)->ExternalID != NULL) {
00195                                    xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
00196                             }
00197                             if (((xmlEntityPtr) node)->SystemID != NULL) {
00198                                    xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
00199                             }
00200                             xmlFree(node);
00201                             break;
00202                      case XML_NAMESPACE_DECL:
00203                             if (node->ns) {
00204                                    xmlFreeNs(node->ns);
00205                                    node->ns = NULL;
00206                             }
00207                             node->type = XML_ELEMENT_NODE;
00208                      default:
00209                             xmlFreeNode(node);
00210               }
00211        }
00212 }
00213 
00214 static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC)
00215 {
00216        xmlNodePtr curnode;
00217 
00218        if (node != NULL) {
00219               curnode = node;
00220               while (curnode != NULL) {
00221                      node = curnode;
00222                      switch (node->type) {
00223                             /* Skip property freeing for the following types */
00224                             case XML_NOTATION_NODE:
00225                             case XML_ENTITY_DECL:
00226                                    break;
00227                             case XML_ENTITY_REF_NODE:
00228                                    php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
00229                                    break;
00230                             case XML_ATTRIBUTE_NODE:
00231                                           if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
00232                                                  xmlRemoveID(node->doc, (xmlAttrPtr) node);
00233                                           }
00234                             case XML_ATTRIBUTE_DECL:
00235                             case XML_DTD_NODE:
00236                             case XML_DOCUMENT_TYPE_NODE:
00237                             case XML_NAMESPACE_DECL:
00238                             case XML_TEXT_NODE:
00239                                    php_libxml_node_free_list(node->children TSRMLS_CC);
00240                                    break;
00241                             default:
00242                                    php_libxml_node_free_list(node->children TSRMLS_CC);
00243                                    php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
00244                      }
00245 
00246                      curnode = node->next;
00247                      xmlUnlinkNode(node);
00248                      if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
00249                             node->doc = NULL;
00250                      }
00251                      php_libxml_node_free(node);
00252               }
00253        }
00254 }
00255 
00256 /* }}} */
00257 
00258 /* {{{ startup, shutdown and info functions */
00259 static PHP_GINIT_FUNCTION(libxml)
00260 {
00261        libxml_globals->stream_context = NULL;
00262        libxml_globals->error_buffer.c = NULL;
00263        libxml_globals->error_list = NULL;
00264 }
00265 
00266 /* Channel libxml file io layer through the PHP streams subsystem.
00267  * This allows use of ftps:// and https:// urls */
00268 
00269 static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
00270 {
00271        php_stream_statbuf ssbuf;
00272        php_stream_context *context = NULL;
00273        php_stream_wrapper *wrapper = NULL;
00274        char *resolved_path, *path_to_open = NULL;
00275        void *ret_val = NULL;
00276        int isescaped=0;
00277        xmlURI *uri;
00278 
00279        TSRMLS_FETCH();
00280 
00281        uri = xmlParseURI((xmlChar *)filename);
00282        if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) {
00283               resolved_path = xmlURIUnescapeString(filename, 0, NULL);
00284               isescaped = 1;
00285        } else {
00286               resolved_path = (char *)filename;
00287        }
00288 
00289        if (uri) {
00290               xmlFreeURI(uri);
00291        }
00292 
00293        if (resolved_path == NULL) {
00294               return NULL;
00295        }
00296 
00297        /* logic copied from _php_stream_stat, but we only want to fail
00298           if the wrapper supports stat, otherwise, figure it out from
00299           the open.  This logic is only to support hiding warnings
00300           that the streams layer puts out at times, but for libxml we
00301           may try to open files that don't exist, but it is not a failure
00302           in xml processing (eg. DTD files)  */
00303        wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
00304        if (wrapper && read_only && wrapper->wops->url_stat) {
00305               if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
00306                      if (isescaped) {
00307                             xmlFree(resolved_path);
00308                      }
00309                      return NULL;
00310               }
00311        }
00312 
00313        context = php_stream_context_from_zval(LIBXML(stream_context), 0);
00314 
00315        ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, context);
00316        if (isescaped) {
00317               xmlFree(resolved_path);
00318        }
00319        return ret_val;
00320 }
00321 
00322 static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
00323 {
00324        return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
00325 }
00326 
00327 static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
00328 {
00329        return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
00330 }
00331 
00332 static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
00333 {
00334        TSRMLS_FETCH();
00335        return php_stream_read((php_stream*)context, buffer, len);
00336 }
00337 
00338 static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
00339 {
00340        TSRMLS_FETCH();
00341        return php_stream_write((php_stream*)context, buffer, len);
00342 }
00343 
00344 static int php_libxml_streams_IO_close(void *context)
00345 {
00346        TSRMLS_FETCH();
00347        return php_stream_close((php_stream*)context);
00348 }
00349 
00350 static xmlParserInputBufferPtr
00351 php_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc)
00352 {
00353        return NULL;
00354 }
00355 
00356 static xmlParserInputBufferPtr
00357 php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
00358 {
00359        xmlParserInputBufferPtr ret;
00360        void *context = NULL;
00361 
00362        if (URI == NULL)
00363               return(NULL);
00364 
00365        context = php_libxml_streams_IO_open_read_wrapper(URI);
00366 
00367        if (context == NULL) {
00368               return(NULL);
00369        }
00370 
00371        /* Allocate the Input buffer front-end. */
00372        ret = xmlAllocParserInputBuffer(enc);
00373        if (ret != NULL) {
00374               ret->context = context;
00375               ret->readcallback = php_libxml_streams_IO_read;
00376               ret->closecallback = php_libxml_streams_IO_close;
00377        } else
00378               php_libxml_streams_IO_close(context);
00379 
00380        return(ret);
00381 }
00382 
00383 static xmlOutputBufferPtr
00384 php_libxml_output_buffer_create_filename(const char *URI,
00385                               xmlCharEncodingHandlerPtr encoder,
00386                               int compression ATTRIBUTE_UNUSED)
00387 {
00388        xmlOutputBufferPtr ret;
00389        xmlURIPtr puri;
00390        void *context = NULL;
00391        char *unescaped = NULL;
00392 
00393        if (URI == NULL)
00394               return(NULL);
00395 
00396        puri = xmlParseURI(URI);
00397        if (puri != NULL) {
00398               if (puri->scheme != NULL)
00399                      unescaped = xmlURIUnescapeString(URI, 0, NULL);
00400               xmlFreeURI(puri);
00401        }
00402 
00403        if (unescaped != NULL) {
00404               context = php_libxml_streams_IO_open_write_wrapper(unescaped);
00405               xmlFree(unescaped);
00406        }
00407 
00408        /* try with a non-escaped URI this may be a strange filename */
00409        if (context == NULL) {
00410               context = php_libxml_streams_IO_open_write_wrapper(URI);
00411        }
00412 
00413        if (context == NULL) {
00414               return(NULL);
00415        }
00416 
00417        /* Allocate the Output buffer front-end. */
00418        ret = xmlAllocOutputBuffer(encoder);
00419        if (ret != NULL) {
00420               ret->context = context;
00421               ret->writecallback = php_libxml_streams_IO_write;
00422               ret->closecallback = php_libxml_streams_IO_close;
00423        }
00424 
00425        return(ret);
00426 }
00427 
00428 static int _php_libxml_free_error(xmlErrorPtr error)
00429 {
00430        /* This will free the libxml alloc'd memory */
00431        xmlResetError(error);
00432        return 1;
00433 }
00434 
00435 static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
00436 {
00437        xmlError error_copy;
00438        int ret;
00439 
00440        TSRMLS_FETCH();
00441 
00442        memset(&error_copy, 0, sizeof(xmlError));
00443 
00444        if (error) {
00445               ret = xmlCopyError(error, &error_copy);
00446        } else {
00447               error_copy.domain = 0;
00448               error_copy.code = XML_ERR_INTERNAL_ERROR;
00449               error_copy.level = XML_ERR_ERROR;
00450               error_copy.line = 0;
00451               error_copy.node = NULL;
00452               error_copy.int1 = 0;
00453               error_copy.int2 = 0;
00454               error_copy.ctxt = NULL;
00455               error_copy.message = xmlStrdup(msg);
00456               error_copy.file = NULL;
00457               error_copy.str1 = NULL;
00458               error_copy.str2 = NULL;
00459               error_copy.str3 = NULL;
00460               ret = 0;
00461        }
00462 
00463        if (ret == 0) {
00464               zend_llist_add_element(LIBXML(error_list), &error_copy);
00465        }
00466 }
00467 
00468 static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC)
00469 {
00470        xmlParserCtxtPtr parser;
00471 
00472        parser = (xmlParserCtxtPtr) ctx;
00473 
00474        if (parser != NULL && parser->input != NULL) {
00475               if (parser->input->filename) {
00476                      php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
00477               } else {
00478                      php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line);
00479               }
00480        }
00481 }
00482 
00483 void php_libxml_issue_error(int level, const char *msg TSRMLS_DC)
00484 {
00485        if (LIBXML(error_list)) {
00486               _php_list_set_error_structure(NULL, msg);
00487        } else {
00488               php_error_docref(NULL TSRMLS_CC, level, "%s", msg);
00489        }
00490 }
00491 
00492 static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
00493 {
00494        char *buf;
00495        int len, len_iter, output = 0;
00496 
00497        TSRMLS_FETCH();
00498 
00499        len = vspprintf(&buf, 0, *msg, ap);
00500        len_iter = len;
00501 
00502        /* remove any trailing \n */
00503        while (len_iter && buf[--len_iter] == '\n') {
00504               buf[len_iter] = '\0';
00505               output = 1;
00506        }
00507 
00508        smart_str_appendl(&LIBXML(error_buffer), buf, len);
00509 
00510        efree(buf);
00511 
00512        if (output == 1) {
00513               if (LIBXML(error_list)) {
00514                      _php_list_set_error_structure(NULL, LIBXML(error_buffer).c);
00515               } else {
00516                      switch (error_type) {
00517                             case PHP_LIBXML_CTX_ERROR:
00518                                    php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC);
00519                                    break;
00520                             case PHP_LIBXML_CTX_WARNING:
00521                                    php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC);
00522                                    break;
00523                             default:
00524                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c);
00525                      }
00526               }
00527               smart_str_free(&LIBXML(error_buffer));
00528        }
00529 }
00530 
00531 PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
00532 {
00533        va_list args;
00534        va_start(args, msg);
00535        php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
00536        va_end(args);
00537 }
00538 
00539 PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
00540 {
00541        va_list args;
00542        va_start(args, msg);
00543        php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
00544        va_end(args);
00545 }
00546 
00547 PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
00548 {
00549        _php_list_set_error_structure(error, NULL);
00550 
00551        return;
00552 }
00553 
00554 PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
00555 {
00556        va_list args;
00557        va_start(args, msg);
00558        php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
00559        va_end(args);
00560 }
00561 
00562 
00563 PHP_LIBXML_API void php_libxml_initialize(void)
00564 {
00565        if (!_php_libxml_initialized) {
00566               /* we should be the only one's to ever init!! */
00567               xmlInitParser();
00568 
00569               zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
00570 
00571               _php_libxml_initialized = 1;
00572        }
00573 }
00574 
00575 PHP_LIBXML_API void php_libxml_shutdown(void)
00576 {
00577        if (_php_libxml_initialized) {
00578 #if defined(LIBXML_SCHEMAS_ENABLED)
00579               xmlRelaxNGCleanupTypes();
00580 #endif
00581               xmlCleanupParser();
00582               zend_hash_destroy(&php_libxml_exports);
00583               _php_libxml_initialized = 0;
00584        }
00585 }
00586 
00587 PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
00588 {
00589        zval *oldcontext;
00590 
00591        oldcontext = LIBXML(stream_context);
00592        LIBXML(stream_context) = context;
00593        return oldcontext;
00594 
00595 }
00596 
00597 static PHP_MINIT_FUNCTION(libxml)
00598 {
00599        zend_class_entry ce;
00600 
00601        php_libxml_initialize();
00602 
00603        REGISTER_LONG_CONSTANT("LIBXML_VERSION",                LIBXML_VERSION,                    CONST_CS | CONST_PERSISTENT);
00604        REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",       LIBXML_DOTTED_VERSION,      CONST_CS | CONST_PERSISTENT);
00605        REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",       (char *)xmlParserVersion,          CONST_CS | CONST_PERSISTENT);
00606 
00607        /* For use with loading xml */
00608        REGISTER_LONG_CONSTANT("LIBXML_NOENT",           XML_PARSE_NOENT,            CONST_CS | CONST_PERSISTENT);
00609        REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",  XML_PARSE_DTDLOAD,          CONST_CS | CONST_PERSISTENT);
00610        REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",  XML_PARSE_DTDATTR,          CONST_CS | CONST_PERSISTENT);
00611        REGISTER_LONG_CONSTANT("LIBXML_DTDVALID", XML_PARSE_DTDVALID,         CONST_CS | CONST_PERSISTENT);
00612        REGISTER_LONG_CONSTANT("LIBXML_NOERROR",  XML_PARSE_NOERROR,          CONST_CS | CONST_PERSISTENT);
00613        REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",       XML_PARSE_NOWARNING, CONST_CS | CONST_PERSISTENT);
00614        REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS", XML_PARSE_NOBLANKS,         CONST_CS | CONST_PERSISTENT);
00615        REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE", XML_PARSE_XINCLUDE,         CONST_CS | CONST_PERSISTENT);
00616        REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",  XML_PARSE_NSCLEAN,          CONST_CS | CONST_PERSISTENT);
00617        REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",  XML_PARSE_NOCDATA,          CONST_CS | CONST_PERSISTENT);
00618        REGISTER_LONG_CONSTANT("LIBXML_NONET",           XML_PARSE_NONET,            CONST_CS | CONST_PERSISTENT);
00619 #if LIBXML_VERSION >= 20621
00620        REGISTER_LONG_CONSTANT("LIBXML_COMPACT",  XML_PARSE_COMPACT,          CONST_CS | CONST_PERSISTENT);
00621        REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",       XML_SAVE_NO_DECL,           CONST_CS | CONST_PERSISTENT);
00622 #endif
00623 #if LIBXML_VERSION >= 20703
00624        REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE",       XML_PARSE_HUGE,                    CONST_CS | CONST_PERSISTENT);
00625 #endif
00626        REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG",      LIBXML_SAVE_NOEMPTYTAG,     CONST_CS | CONST_PERSISTENT);
00627 
00628        /* Error levels */
00629        REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",        XML_ERR_NONE,        CONST_CS | CONST_PERSISTENT);
00630        REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",     XML_ERR_WARNING,     CONST_CS | CONST_PERSISTENT);
00631        REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",              XML_ERR_ERROR,              CONST_CS | CONST_PERSISTENT);
00632        REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",              XML_ERR_FATAL,              CONST_CS | CONST_PERSISTENT);
00633 
00634        INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
00635        libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
00636 
00637        return SUCCESS;
00638 }
00639 
00640 
00641 static PHP_RINIT_FUNCTION(libxml)
00642 {
00643        /* report errors via handler rather than stderr */
00644        xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
00645        xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
00646        xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
00647        return SUCCESS;
00648 }
00649 
00650 
00651 static PHP_MSHUTDOWN_FUNCTION(libxml)
00652 {
00653        php_libxml_shutdown();
00654 
00655        return SUCCESS;
00656 }
00657 
00658 
00659 static PHP_RSHUTDOWN_FUNCTION(libxml)
00660 {
00661        /* reset libxml generic error handling */
00662        xmlSetGenericErrorFunc(NULL, NULL);
00663        xmlSetStructuredErrorFunc(NULL, NULL);
00664 
00665        xmlParserInputBufferCreateFilenameDefault(NULL);
00666        xmlOutputBufferCreateFilenameDefault(NULL);
00667 
00668        if (LIBXML(stream_context)) {
00669               zval_ptr_dtor(&LIBXML(stream_context));
00670               LIBXML(stream_context) = NULL;
00671        }
00672        smart_str_free(&LIBXML(error_buffer));
00673        if (LIBXML(error_list)) {
00674               zend_llist_destroy(LIBXML(error_list));
00675               efree(LIBXML(error_list));
00676               LIBXML(error_list) = NULL;
00677        }
00678        xmlResetLastError();
00679 
00680        return SUCCESS;
00681 }
00682 
00683 
00684 static PHP_MINFO_FUNCTION(libxml)
00685 {
00686        php_info_print_table_start();
00687        php_info_print_table_row(2, "libXML support", "active");
00688        php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
00689        php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
00690        php_info_print_table_row(2, "libXML streams", "enabled");
00691        php_info_print_table_end();
00692 }
00693 /* }}} */
00694 
00695 /* {{{ proto void libxml_set_streams_context(resource streams_context) 
00696    Set the streams context for the next libxml document load or write */
00697 static PHP_FUNCTION(libxml_set_streams_context)
00698 {
00699        zval *arg;
00700 
00701        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
00702               return;
00703        }
00704        if (LIBXML(stream_context)) {
00705               zval_ptr_dtor(&LIBXML(stream_context));
00706               LIBXML(stream_context) = NULL;
00707        }
00708        Z_ADDREF_P(arg);
00709        LIBXML(stream_context) = arg;
00710 }
00711 /* }}} */
00712 
00713 /* {{{ proto bool libxml_use_internal_errors([boolean use_errors]) 
00714    Disable libxml errors and allow user to fetch error information as needed */
00715 static PHP_FUNCTION(libxml_use_internal_errors)
00716 {
00717        xmlStructuredErrorFunc current_handler;
00718        zend_bool use_errors=0, retval;
00719 
00720        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
00721               return;
00722        }
00723 
00724        current_handler = xmlStructuredError;
00725        if (current_handler && current_handler == php_libxml_structured_error_handler) {
00726               retval = 1;
00727        } else {
00728               retval = 0;
00729        }
00730 
00731        if (ZEND_NUM_ARGS() == 0) {
00732               RETURN_BOOL(retval);
00733        }
00734 
00735        if (use_errors == 0) {
00736               xmlSetStructuredErrorFunc(NULL, NULL);
00737               if (LIBXML(error_list)) {
00738                      zend_llist_destroy(LIBXML(error_list));
00739                      efree(LIBXML(error_list));
00740                      LIBXML(error_list) = NULL;
00741               }
00742        } else {
00743               xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
00744               if (LIBXML(error_list) == NULL) {
00745                      LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
00746                      zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
00747               }
00748        }
00749        RETURN_BOOL(retval);
00750 }
00751 /* }}} */
00752 
00753 /* {{{ proto object libxml_get_last_error() 
00754    Retrieve last error from libxml */
00755 static PHP_FUNCTION(libxml_get_last_error)
00756 {
00757        xmlErrorPtr error;
00758 
00759        error = xmlGetLastError();
00760        
00761        if (error) {
00762               object_init_ex(return_value, libxmlerror_class_entry);
00763               add_property_long(return_value, "level", error->level);
00764               add_property_long(return_value, "code", error->code);
00765               add_property_long(return_value, "column", error->int2);
00766               if (error->message) {
00767                      add_property_string(return_value, "message", error->message, 1);
00768               } else {
00769                      add_property_stringl(return_value, "message", "", 0, 1);
00770               }
00771               if (error->file) {
00772                      add_property_string(return_value, "file", error->file, 1);
00773               } else {
00774                      add_property_stringl(return_value, "file", "", 0, 1);
00775               }
00776               add_property_long(return_value, "line", error->line);
00777        } else {
00778               RETURN_FALSE;
00779        }
00780 }
00781 /* }}} */
00782 
00783 /* {{{ proto object libxml_get_errors()
00784    Retrieve array of errors */
00785 static PHP_FUNCTION(libxml_get_errors)
00786 {
00787        
00788        xmlErrorPtr error;
00789 
00790        if (array_init(return_value) == FAILURE) {
00791               RETURN_FALSE;
00792        }
00793 
00794        if (LIBXML(error_list)) {
00795 
00796               error = zend_llist_get_first(LIBXML(error_list));
00797 
00798               while (error != NULL) {
00799                      zval *z_error;
00800                      MAKE_STD_ZVAL(z_error);
00801 
00802                      object_init_ex(z_error, libxmlerror_class_entry);
00803                      add_property_long(z_error, "level", error->level);
00804                      add_property_long(z_error, "code", error->code);
00805                      add_property_long(z_error, "column", error->int2);
00806                      if (error->message) {
00807                             add_property_string(z_error, "message", error->message, 1);
00808                      } else {
00809                             add_property_stringl(z_error, "message", "", 0, 1);
00810                      }
00811                      if (error->file) {
00812                             add_property_string(z_error, "file", error->file, 1);
00813                      } else {
00814                             add_property_stringl(z_error, "file", "", 0, 1);
00815                      }
00816                      add_property_long(z_error, "line", error->line);
00817                      add_next_index_zval(return_value, z_error);
00818 
00819                      error = zend_llist_get_next(LIBXML(error_list));
00820               }
00821        }
00822 }
00823 /* }}} */
00824 
00825 /* {{{ proto void libxml_clear_errors() 
00826    Clear last error from libxml */
00827 static PHP_FUNCTION(libxml_clear_errors)
00828 {
00829        xmlResetLastError();
00830        if (LIBXML(error_list)) {
00831               zend_llist_clean(LIBXML(error_list));
00832        }
00833 }
00834 /* }}} */
00835 
00836 /* {{{ proto bool libxml_disable_entity_loader([boolean disable]) 
00837    Disable/Enable ability to load external entities */
00838 static PHP_FUNCTION(libxml_disable_entity_loader)
00839 {
00840        zend_bool disable = 1;
00841        xmlParserInputBufferCreateFilenameFunc old;
00842 
00843        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) {
00844               return;
00845        }
00846 
00847        if (disable == 0) {
00848               old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
00849        } else {
00850               old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_noload);
00851        }
00852 
00853        if (old == php_libxml_input_buffer_noload) {
00854               RETURN_TRUE;
00855        }
00856 
00857        RETURN_FALSE;
00858 }
00859 /* }}} */
00860 
00861 /* {{{ Common functions shared by extensions */
00862 int php_libxml_xmlCheckUTF8(const unsigned char *s)
00863 {
00864        int i;
00865        unsigned char c;
00866 
00867        for (i = 0; (c = s[i++]);) {
00868               if ((c & 0x80) == 0) {
00869               } else if ((c & 0xe0) == 0xc0) {
00870                      if ((s[i++] & 0xc0) != 0x80) {
00871                             return 0;
00872                      }
00873               } else if ((c & 0xf0) == 0xe0) {
00874                      if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
00875                             return 0;
00876                      }
00877               } else if ((c & 0xf8) == 0xf0) {
00878                      if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
00879                             return 0;
00880                      }
00881               } else {
00882                      return 0;
00883               }
00884        }
00885        return 1;
00886 }
00887 
00888 int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
00889 {
00890        php_libxml_func_handler export_hnd;
00891        
00892        /* Initialize in case this module hasnt been loaded yet */
00893        php_libxml_initialize();
00894        export_hnd.export_func = export_function;
00895 
00896        return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
00897 }
00898 
00899 PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
00900 {
00901        zend_class_entry *ce = NULL;
00902        xmlNodePtr node = NULL;
00903        php_libxml_func_handler *export_hnd;
00904 
00905        if (object->type == IS_OBJECT) {
00906               ce = Z_OBJCE_P(object);
00907               while (ce->parent != NULL) {
00908                      ce = ce->parent;
00909               }
00910               if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd)  == SUCCESS) {
00911                      node = export_hnd->export_func(object TSRMLS_CC);
00912               }
00913        }
00914        return node;
00915 }
00916 
00917 PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
00918 {
00919        int ret_refcount = -1;
00920 
00921        if (object != NULL && node != NULL) {
00922               if (object->node != NULL) {
00923                      if (object->node->node == node) {
00924                             return object->node->refcount;
00925                      } else {
00926                             php_libxml_decrement_node_ptr(object TSRMLS_CC);
00927                      }
00928               }
00929               if (node->_private != NULL) {
00930                      object->node = node->_private;
00931                      ret_refcount = ++object->node->refcount;
00932                      /* Only dom uses _private */
00933                      if (object->node->_private == NULL) {
00934                             object->node->_private = private_data;
00935                      }
00936               } else {
00937                      ret_refcount = 1;
00938                      object->node = emalloc(sizeof(php_libxml_node_ptr));
00939                      object->node->node = node;
00940                      object->node->refcount = 1;
00941                      object->node->_private = private_data;
00942                      node->_private = object->node;
00943               }
00944        }
00945 
00946        return ret_refcount;
00947 }
00948 
00949 PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
00950 {
00951        int ret_refcount = -1;
00952        php_libxml_node_ptr *obj_node;
00953 
00954        if (object != NULL && object->node != NULL) {
00955               obj_node = (php_libxml_node_ptr *) object->node;
00956               ret_refcount = --obj_node->refcount;
00957               if (ret_refcount == 0) {
00958                      if (obj_node->node != NULL) {
00959                             obj_node->node->_private = NULL;
00960                      }
00961                      efree(obj_node);
00962               } 
00963               object->node = NULL;
00964        }
00965 
00966        return ret_refcount;
00967 }
00968 
00969 PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
00970 {
00971        int ret_refcount = -1;
00972 
00973        if (object->document != NULL) {
00974               object->document->refcount++;
00975               ret_refcount = object->document->refcount;
00976        } else if (docp != NULL) {
00977               ret_refcount = 1;
00978               object->document = emalloc(sizeof(php_libxml_ref_obj));
00979               object->document->ptr = docp;
00980               object->document->refcount = ret_refcount;
00981               object->document->doc_props = NULL;
00982        }
00983 
00984        return ret_refcount;
00985 }
00986 
00987 PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
00988 {
00989        int ret_refcount = -1;
00990 
00991        if (object != NULL && object->document != NULL) {
00992               ret_refcount = --object->document->refcount;
00993               if (ret_refcount == 0) {
00994                      if (object->document->ptr != NULL) {
00995                             xmlFreeDoc((xmlDoc *) object->document->ptr);
00996                      }
00997                      if (object->document->doc_props != NULL) {
00998                             if (object->document->doc_props->classmap) {
00999                                    zend_hash_destroy(object->document->doc_props->classmap);
01000                                    FREE_HASHTABLE(object->document->doc_props->classmap);
01001                             }
01002                             efree(object->document->doc_props);
01003                      }
01004                      efree(object->document);
01005                      object->document = NULL;
01006               }
01007        }
01008 
01009        return ret_refcount;
01010 }
01011 
01012 PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
01013 {
01014        if (!node) {
01015               return;
01016        }
01017 
01018        switch (node->type) {
01019               case XML_DOCUMENT_NODE:
01020               case XML_HTML_DOCUMENT_NODE:
01021                      break;
01022               default:
01023                      if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
01024                             php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
01025                             switch (node->type) {
01026                                    /* Skip property freeing for the following types */
01027                                    case XML_ATTRIBUTE_DECL:
01028                                    case XML_DTD_NODE:
01029                                    case XML_DOCUMENT_TYPE_NODE:
01030                                    case XML_ENTITY_DECL:
01031                                    case XML_ATTRIBUTE_NODE:
01032                                    case XML_NAMESPACE_DECL:
01033                                    case XML_TEXT_NODE:
01034                                           break;
01035                                    default:
01036                                           php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
01037                             }
01038                             if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
01039                                    node->doc = NULL;
01040                             }
01041                             php_libxml_node_free(node);
01042                      } else {
01043                             php_libxml_unregister_node(node TSRMLS_CC);
01044                      }
01045        }
01046 }
01047 
01048 PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
01049 {
01050        int ret_refcount = -1;
01051        xmlNodePtr nodep;
01052        php_libxml_node_ptr *obj_node;
01053 
01054        if (object != NULL && object->node != NULL) {
01055               obj_node = (php_libxml_node_ptr *) object->node;
01056               nodep = object->node->node;
01057               ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
01058               if (ret_refcount == 0) {
01059                      php_libxml_node_free_resource(nodep TSRMLS_CC);
01060               } else {
01061                      if (obj_node && object == obj_node->_private) {
01062                             obj_node->_private = NULL;
01063                      }
01064               }
01065        }
01066        if (object != NULL && object->document != NULL) {
01067               /* Safe to call as if the resource were freed then doc pointer is NULL */
01068               php_libxml_decrement_doc_ref(object TSRMLS_CC);
01069        }
01070 }
01071 /* }}} */
01072 
01073 #ifdef PHP_WIN32
01074 PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
01075 {
01076        return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
01077 }
01078 #endif
01079 
01080 #endif
01081 
01082 /*
01083  * Local variables:
01084  * tab-width: 4
01085  * c-basic-offset: 4
01086  * End:
01087  * vim600: sw=4 ts=4 fdm=marker
01088  * vim<600: sw=4 ts=4
01089  */