Annotation of embedaddon/php/ext/libxml/libxml.c, revision 1.1.1.3

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

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