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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Shane Caraveo <shane@php.net>                               |
                     16:    |          Wez Furlong <wez@thebrainroom.com>                          |
                     17:    +----------------------------------------------------------------------+
                     18:  */
                     19: 
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;
        !           273: }
        !           274: 
        !           275: static void _php_libxml_destroy_fci(zend_fcall_info *fci)
        !           276: {
        !           277:        if (fci->size > 0) {
        !           278:                zval_ptr_dtor(&fci->function_name);
        !           279:                if (fci->object_ptr != NULL) {
        !           280:                        zval_ptr_dtor(&fci->object_ptr);
        !           281:                }
        !           282:                fci->size = 0;
        !           283:        }
1.1       misho     284: }
                    285: 
                    286: /* Channel libxml file io layer through the PHP streams subsystem.
                    287:  * This allows use of ftps:// and https:// urls */
                    288: 
                    289: static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
                    290: {
                    291:        php_stream_statbuf ssbuf;
                    292:        php_stream_context *context = NULL;
                    293:        php_stream_wrapper *wrapper = NULL;
                    294:        char *resolved_path, *path_to_open = NULL;
                    295:        void *ret_val = NULL;
                    296:        int isescaped=0;
                    297:        xmlURI *uri;
                    298: 
                    299:        TSRMLS_FETCH();
                    300: 
1.1.1.2 ! misho     301:        uri = xmlParseURI(filename);
        !           302:        if (uri && (uri->scheme == NULL ||
        !           303:                        (xmlStrncmp(BAD_CAST uri->scheme, BAD_CAST "file", 4) == 0))) {
1.1       misho     304:                resolved_path = xmlURIUnescapeString(filename, 0, NULL);
                    305:                isescaped = 1;
                    306:        } else {
                    307:                resolved_path = (char *)filename;
                    308:        }
                    309: 
                    310:        if (uri) {
                    311:                xmlFreeURI(uri);
                    312:        }
                    313: 
                    314:        if (resolved_path == NULL) {
                    315:                return NULL;
                    316:        }
                    317: 
                    318:        /* logic copied from _php_stream_stat, but we only want to fail
                    319:           if the wrapper supports stat, otherwise, figure it out from
                    320:           the open.  This logic is only to support hiding warnings
                    321:           that the streams layer puts out at times, but for libxml we
                    322:           may try to open files that don't exist, but it is not a failure
                    323:           in xml processing (eg. DTD files)  */
1.1.1.2 ! misho     324:        wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, 0 TSRMLS_CC);
1.1       misho     325:        if (wrapper && read_only && wrapper->wops->url_stat) {
                    326:                if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
                    327:                        if (isescaped) {
                    328:                                xmlFree(resolved_path);
                    329:                        }
                    330:                        return NULL;
                    331:                }
                    332:        }
                    333: 
                    334:        context = php_stream_context_from_zval(LIBXML(stream_context), 0);
1.1.1.2 ! misho     335:        
        !           336:        ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, REPORT_ERRORS, NULL, context);
1.1       misho     337:        if (isescaped) {
                    338:                xmlFree(resolved_path);
                    339:        }
                    340:        return ret_val;
                    341: }
                    342: 
                    343: static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
                    344: {
                    345:        return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
                    346: }
                    347: 
                    348: static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
                    349: {
                    350:        return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
                    351: }
                    352: 
                    353: static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
                    354: {
                    355:        TSRMLS_FETCH();
                    356:        return php_stream_read((php_stream*)context, buffer, len);
                    357: }
                    358: 
                    359: static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
                    360: {
                    361:        TSRMLS_FETCH();
                    362:        return php_stream_write((php_stream*)context, buffer, len);
                    363: }
                    364: 
                    365: static int php_libxml_streams_IO_close(void *context)
                    366: {
                    367:        TSRMLS_FETCH();
                    368:        return php_stream_close((php_stream*)context);
                    369: }
                    370: 
                    371: static xmlParserInputBufferPtr
                    372: php_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc)
                    373: {
                    374:        return NULL;
                    375: }
                    376: 
                    377: static xmlParserInputBufferPtr
                    378: php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
                    379: {
                    380:        xmlParserInputBufferPtr ret;
                    381:        void *context = NULL;
                    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: {
        !           680:        /* Check whether we're running in a PHP context, since the entity loader
        !           681:         * we've defined is an application level (true global) setting */
        !           682:        if (xmlGenericError == php_libxml_error_handler) {
        !           683:                return _php_libxml_external_entity_loader(URL, ID, context);
        !           684:        } else {
        !           685:                return _php_libxml_default_entity_loader(URL, ID, context);
        !           686:        }
        !           687: }
        !           688: 
1.1       misho     689: PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
                    690: {
                    691:        va_list args;
                    692:        va_start(args, msg);
                    693:        php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
                    694:        va_end(args);
                    695: }
                    696: 
                    697: PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
                    698: {
                    699:        va_list args;
                    700:        va_start(args, msg);
                    701:        php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
                    702:        va_end(args);
                    703: }
                    704: 
                    705: PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
                    706: {
                    707:        _php_list_set_error_structure(error, NULL);
                    708: 
                    709:        return;
                    710: }
                    711: 
                    712: PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
                    713: {
                    714:        va_list args;
                    715:        va_start(args, msg);
                    716:        php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
                    717:        va_end(args);
                    718: }
                    719: 
                    720: 
                    721: PHP_LIBXML_API void php_libxml_initialize(void)
                    722: {
                    723:        if (!_php_libxml_initialized) {
                    724:                /* we should be the only one's to ever init!! */
                    725:                xmlInitParser();
1.1.1.2 ! misho     726:                
        !           727:                _php_libxml_default_entity_loader = xmlGetExternalEntityLoader();
        !           728:                xmlSetExternalEntityLoader(_php_libxml_pre_ext_ent_loader);
1.1       misho     729: 
                    730:                zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
                    731: 
                    732:                _php_libxml_initialized = 1;
                    733:        }
                    734: }
                    735: 
                    736: PHP_LIBXML_API void php_libxml_shutdown(void)
                    737: {
                    738:        if (_php_libxml_initialized) {
                    739: #if defined(LIBXML_SCHEMAS_ENABLED)
                    740:                xmlRelaxNGCleanupTypes();
                    741: #endif
                    742:                xmlCleanupParser();
                    743:                zend_hash_destroy(&php_libxml_exports);
1.1.1.2 ! misho     744:                
        !           745:                xmlSetExternalEntityLoader(_php_libxml_default_entity_loader);
1.1       misho     746:                _php_libxml_initialized = 0;
                    747:        }
                    748: }
                    749: 
                    750: PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
                    751: {
                    752:        zval *oldcontext;
                    753: 
                    754:        oldcontext = LIBXML(stream_context);
                    755:        LIBXML(stream_context) = context;
                    756:        return oldcontext;
                    757: 
                    758: }
                    759: 
                    760: static PHP_MINIT_FUNCTION(libxml)
                    761: {
                    762:        zend_class_entry ce;
                    763: 
                    764:        php_libxml_initialize();
                    765: 
                    766:        REGISTER_LONG_CONSTANT("LIBXML_VERSION",                        LIBXML_VERSION,                 CONST_CS | CONST_PERSISTENT);
                    767:        REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",       LIBXML_DOTTED_VERSION,  CONST_CS | CONST_PERSISTENT);
                    768:        REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",       (char *)xmlParserVersion,               CONST_CS | CONST_PERSISTENT);
                    769: 
                    770:        /* For use with loading xml */
                    771:        REGISTER_LONG_CONSTANT("LIBXML_NOENT",          XML_PARSE_NOENT,                CONST_CS | CONST_PERSISTENT);
                    772:        REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",        XML_PARSE_DTDLOAD,              CONST_CS | CONST_PERSISTENT);
                    773:        REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",        XML_PARSE_DTDATTR,              CONST_CS | CONST_PERSISTENT);
                    774:        REGISTER_LONG_CONSTANT("LIBXML_DTDVALID",       XML_PARSE_DTDVALID,             CONST_CS | CONST_PERSISTENT);
                    775:        REGISTER_LONG_CONSTANT("LIBXML_NOERROR",        XML_PARSE_NOERROR,              CONST_CS | CONST_PERSISTENT);
                    776:        REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",      XML_PARSE_NOWARNING,    CONST_CS | CONST_PERSISTENT);
                    777:        REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS",       XML_PARSE_NOBLANKS,             CONST_CS | CONST_PERSISTENT);
                    778:        REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE",       XML_PARSE_XINCLUDE,             CONST_CS | CONST_PERSISTENT);
                    779:        REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",        XML_PARSE_NSCLEAN,              CONST_CS | CONST_PERSISTENT);
                    780:        REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",        XML_PARSE_NOCDATA,              CONST_CS | CONST_PERSISTENT);
                    781:        REGISTER_LONG_CONSTANT("LIBXML_NONET",          XML_PARSE_NONET,                CONST_CS | CONST_PERSISTENT);
1.1.1.2 ! misho     782:        REGISTER_LONG_CONSTANT("LIBXML_PEDANTIC",       XML_PARSE_PEDANTIC,             CONST_CS | CONST_PERSISTENT);
1.1       misho     783: #if LIBXML_VERSION >= 20621
                    784:        REGISTER_LONG_CONSTANT("LIBXML_COMPACT",        XML_PARSE_COMPACT,              CONST_CS | CONST_PERSISTENT);
                    785:        REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",      XML_SAVE_NO_DECL,               CONST_CS | CONST_PERSISTENT);
                    786: #endif
                    787: #if LIBXML_VERSION >= 20703
                    788:        REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE",      XML_PARSE_HUGE,                 CONST_CS | CONST_PERSISTENT);
                    789: #endif
                    790:        REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG",     LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT);
                    791: 
1.1.1.2 ! misho     792:        /* Additional constants for use with loading html */
        !           793: #if LIBXML_VERSION >= 20707
        !           794:        REGISTER_LONG_CONSTANT("LIBXML_HTML_NOIMPLIED", HTML_PARSE_NOIMPLIED,           CONST_CS | CONST_PERSISTENT);
        !           795: #endif
        !           796: 
        !           797: #if LIBXML_VERSION >= 20708
        !           798:        REGISTER_LONG_CONSTANT("LIBXML_HTML_NODEFDTD",  HTML_PARSE_NODEFDTD,            CONST_CS | CONST_PERSISTENT);
        !           799: #endif
        !           800: 
1.1       misho     801:        /* Error levels */
                    802:        REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",               XML_ERR_NONE,           CONST_CS | CONST_PERSISTENT);
                    803:        REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",    XML_ERR_WARNING,        CONST_CS | CONST_PERSISTENT);
                    804:        REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",              XML_ERR_ERROR,          CONST_CS | CONST_PERSISTENT);
                    805:        REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",              XML_ERR_FATAL,          CONST_CS | CONST_PERSISTENT);
                    806: 
                    807:        INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
                    808:        libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
                    809: 
1.1.1.2 ! misho     810:        if (sapi_module.name) {
        !           811:                static const char * const supported_sapis[] = {
        !           812:                        "cgi-fcgi",
        !           813:                        "fpm-fcgi",
        !           814:                        "litespeed",
        !           815:                        NULL
        !           816:                };
        !           817:                const char * const *sapi_name;
        !           818: 
        !           819:                for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
        !           820:                        if (strcmp(sapi_module.name, *sapi_name) == 0) {
        !           821:                                _php_libxml_per_request_initialization = 0;
        !           822:                                break;
        !           823:                        }
        !           824:                }
        !           825:        }
        !           826: 
        !           827:        if (!_php_libxml_per_request_initialization) {
        !           828:                /* report errors via handler rather than stderr */
        !           829:                xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
        !           830:                xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
        !           831:                xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
        !           832:        }
        !           833:        
1.1       misho     834:        return SUCCESS;
                    835: }
                    836: 
                    837: 
                    838: static PHP_RINIT_FUNCTION(libxml)
                    839: {
1.1.1.2 ! misho     840:        if (_php_libxml_per_request_initialization) {
        !           841:                /* report errors via handler rather than stderr */
        !           842:                xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
        !           843:                xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
        !           844:                xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
        !           845:        }
1.1       misho     846:        return SUCCESS;
                    847: }
                    848: 
                    849: 
                    850: static PHP_MSHUTDOWN_FUNCTION(libxml)
                    851: {
1.1.1.2 ! misho     852:        if (!_php_libxml_per_request_initialization) {
        !           853:                xmlSetGenericErrorFunc(NULL, NULL);
        !           854:                xmlSetStructuredErrorFunc(NULL, NULL);
        !           855: 
        !           856:                xmlParserInputBufferCreateFilenameDefault(NULL);
        !           857:                xmlOutputBufferCreateFilenameDefault(NULL);
        !           858:        }
1.1       misho     859:        php_libxml_shutdown();
                    860: 
                    861:        return SUCCESS;
                    862: }
                    863: 
1.1.1.2 ! misho     864: static int php_libxml_post_deactivate()
1.1       misho     865: {
1.1.1.2 ! misho     866:        TSRMLS_FETCH();
1.1       misho     867:        /* reset libxml generic error handling */
1.1.1.2 ! misho     868:        if (_php_libxml_per_request_initialization) {
        !           869:                xmlSetGenericErrorFunc(NULL, NULL);
        !           870:                xmlSetStructuredErrorFunc(NULL, NULL);
1.1       misho     871: 
1.1.1.2 ! misho     872:                xmlParserInputBufferCreateFilenameDefault(NULL);
        !           873:                xmlOutputBufferCreateFilenameDefault(NULL);
        !           874:        }
1.1       misho     875: 
                    876:        if (LIBXML(stream_context)) {
                    877:                zval_ptr_dtor(&LIBXML(stream_context));
                    878:                LIBXML(stream_context) = NULL;
                    879:        }
                    880:        smart_str_free(&LIBXML(error_buffer));
                    881:        if (LIBXML(error_list)) {
                    882:                zend_llist_destroy(LIBXML(error_list));
                    883:                efree(LIBXML(error_list));
                    884:                LIBXML(error_list) = NULL;
                    885:        }
                    886:        xmlResetLastError();
1.1.1.2 ! misho     887:        
        !           888:        _php_libxml_destroy_fci(&LIBXML(entity_loader).fci);
1.1       misho     889: 
                    890:        return SUCCESS;
                    891: }
                    892: 
                    893: 
                    894: static PHP_MINFO_FUNCTION(libxml)
                    895: {
                    896:        php_info_print_table_start();
                    897:        php_info_print_table_row(2, "libXML support", "active");
                    898:        php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
                    899:        php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
                    900:        php_info_print_table_row(2, "libXML streams", "enabled");
                    901:        php_info_print_table_end();
                    902: }
                    903: /* }}} */
                    904: 
                    905: /* {{{ proto void libxml_set_streams_context(resource streams_context) 
                    906:    Set the streams context for the next libxml document load or write */
                    907: static PHP_FUNCTION(libxml_set_streams_context)
                    908: {
                    909:        zval *arg;
                    910: 
                    911:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
                    912:                return;
                    913:        }
                    914:        if (LIBXML(stream_context)) {
                    915:                zval_ptr_dtor(&LIBXML(stream_context));
                    916:                LIBXML(stream_context) = NULL;
                    917:        }
                    918:        Z_ADDREF_P(arg);
                    919:        LIBXML(stream_context) = arg;
                    920: }
                    921: /* }}} */
                    922: 
                    923: /* {{{ proto bool libxml_use_internal_errors([boolean use_errors]) 
                    924:    Disable libxml errors and allow user to fetch error information as needed */
                    925: static PHP_FUNCTION(libxml_use_internal_errors)
                    926: {
                    927:        xmlStructuredErrorFunc current_handler;
                    928:        zend_bool use_errors=0, retval;
                    929: 
                    930:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
                    931:                return;
                    932:        }
                    933: 
                    934:        current_handler = xmlStructuredError;
                    935:        if (current_handler && current_handler == php_libxml_structured_error_handler) {
                    936:                retval = 1;
                    937:        } else {
                    938:                retval = 0;
                    939:        }
                    940: 
                    941:        if (ZEND_NUM_ARGS() == 0) {
                    942:                RETURN_BOOL(retval);
                    943:        }
                    944: 
                    945:        if (use_errors == 0) {
                    946:                xmlSetStructuredErrorFunc(NULL, NULL);
                    947:                if (LIBXML(error_list)) {
                    948:                        zend_llist_destroy(LIBXML(error_list));
                    949:                        efree(LIBXML(error_list));
                    950:                        LIBXML(error_list) = NULL;
                    951:                }
                    952:        } else {
                    953:                xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
                    954:                if (LIBXML(error_list) == NULL) {
                    955:                        LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
                    956:                        zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
                    957:                }
                    958:        }
                    959:        RETURN_BOOL(retval);
                    960: }
                    961: /* }}} */
                    962: 
                    963: /* {{{ proto object libxml_get_last_error() 
                    964:    Retrieve last error from libxml */
                    965: static PHP_FUNCTION(libxml_get_last_error)
                    966: {
                    967:        xmlErrorPtr error;
                    968: 
                    969:        error = xmlGetLastError();
                    970:        
                    971:        if (error) {
                    972:                object_init_ex(return_value, libxmlerror_class_entry);
                    973:                add_property_long(return_value, "level", error->level);
                    974:                add_property_long(return_value, "code", error->code);
                    975:                add_property_long(return_value, "column", error->int2);
                    976:                if (error->message) {
                    977:                        add_property_string(return_value, "message", error->message, 1);
                    978:                } else {
                    979:                        add_property_stringl(return_value, "message", "", 0, 1);
                    980:                }
                    981:                if (error->file) {
                    982:                        add_property_string(return_value, "file", error->file, 1);
                    983:                } else {
                    984:                        add_property_stringl(return_value, "file", "", 0, 1);
                    985:                }
                    986:                add_property_long(return_value, "line", error->line);
                    987:        } else {
                    988:                RETURN_FALSE;
                    989:        }
                    990: }
                    991: /* }}} */
                    992: 
                    993: /* {{{ proto object libxml_get_errors()
                    994:    Retrieve array of errors */
                    995: static PHP_FUNCTION(libxml_get_errors)
                    996: {
                    997:        
                    998:        xmlErrorPtr error;
                    999: 
                   1000:        if (array_init(return_value) == FAILURE) {
                   1001:                RETURN_FALSE;
                   1002:        }
                   1003: 
                   1004:        if (LIBXML(error_list)) {
                   1005: 
                   1006:                error = zend_llist_get_first(LIBXML(error_list));
                   1007: 
                   1008:                while (error != NULL) {
                   1009:                        zval *z_error;
                   1010:                        MAKE_STD_ZVAL(z_error);
                   1011: 
                   1012:                        object_init_ex(z_error, libxmlerror_class_entry);
                   1013:                        add_property_long(z_error, "level", error->level);
                   1014:                        add_property_long(z_error, "code", error->code);
                   1015:                        add_property_long(z_error, "column", error->int2);
                   1016:                        if (error->message) {
                   1017:                                add_property_string(z_error, "message", error->message, 1);
                   1018:                        } else {
                   1019:                                add_property_stringl(z_error, "message", "", 0, 1);
                   1020:                        }
                   1021:                        if (error->file) {
                   1022:                                add_property_string(z_error, "file", error->file, 1);
                   1023:                        } else {
                   1024:                                add_property_stringl(z_error, "file", "", 0, 1);
                   1025:                        }
                   1026:                        add_property_long(z_error, "line", error->line);
                   1027:                        add_next_index_zval(return_value, z_error);
                   1028: 
                   1029:                        error = zend_llist_get_next(LIBXML(error_list));
                   1030:                }
                   1031:        }
                   1032: }
                   1033: /* }}} */
                   1034: 
                   1035: /* {{{ proto void libxml_clear_errors() 
                   1036:    Clear last error from libxml */
                   1037: static PHP_FUNCTION(libxml_clear_errors)
                   1038: {
                   1039:        xmlResetLastError();
                   1040:        if (LIBXML(error_list)) {
                   1041:                zend_llist_clean(LIBXML(error_list));
                   1042:        }
                   1043: }
                   1044: /* }}} */
                   1045: 
                   1046: /* {{{ proto bool libxml_disable_entity_loader([boolean disable]) 
                   1047:    Disable/Enable ability to load external entities */
                   1048: static PHP_FUNCTION(libxml_disable_entity_loader)
                   1049: {
                   1050:        zend_bool disable = 1;
                   1051:        xmlParserInputBufferCreateFilenameFunc old;
                   1052: 
                   1053:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) {
                   1054:                return;
                   1055:        }
                   1056: 
                   1057:        if (disable == 0) {
                   1058:                old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
                   1059:        } else {
                   1060:                old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_noload);
                   1061:        }
                   1062: 
                   1063:        if (old == php_libxml_input_buffer_noload) {
                   1064:                RETURN_TRUE;
                   1065:        }
                   1066: 
                   1067:        RETURN_FALSE;
                   1068: }
                   1069: /* }}} */
                   1070: 
1.1.1.2 ! misho    1071: /* {{{ proto void libxml_set_external_entity_loader(callback resolver_function) 
        !          1072:    Changes the default external entity loader */
        !          1073: static PHP_FUNCTION(libxml_set_external_entity_loader)
        !          1074: {
        !          1075:        zend_fcall_info                 fci;
        !          1076:        zend_fcall_info_cache   fcc;
        !          1077:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f!", &fci, &fcc)
        !          1078:                        == FAILURE) {
        !          1079:                return;
        !          1080:        }
        !          1081:        
        !          1082:        _php_libxml_destroy_fci(&LIBXML(entity_loader).fci);
        !          1083:        
        !          1084:        if (fci.size > 0) { /* argument not null */
        !          1085:                LIBXML(entity_loader).fci = fci;
        !          1086:                Z_ADDREF_P(fci.function_name);
        !          1087:                if (fci.object_ptr != NULL) {
        !          1088:                        Z_ADDREF_P(fci.object_ptr);
        !          1089:                }
        !          1090:                LIBXML(entity_loader).fcc = fcc;
        !          1091:        }
        !          1092:        
        !          1093:        RETURN_TRUE;
        !          1094: }
        !          1095: /* }}} */
        !          1096: 
1.1       misho    1097: /* {{{ Common functions shared by extensions */
                   1098: int php_libxml_xmlCheckUTF8(const unsigned char *s)
                   1099: {
                   1100:        int i;
                   1101:        unsigned char c;
                   1102: 
                   1103:        for (i = 0; (c = s[i++]);) {
                   1104:                if ((c & 0x80) == 0) {
                   1105:                } else if ((c & 0xe0) == 0xc0) {
                   1106:                        if ((s[i++] & 0xc0) != 0x80) {
                   1107:                                return 0;
                   1108:                        }
                   1109:                } else if ((c & 0xf0) == 0xe0) {
                   1110:                        if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
                   1111:                                return 0;
                   1112:                        }
                   1113:                } else if ((c & 0xf8) == 0xf0) {
                   1114:                        if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
                   1115:                                return 0;
                   1116:                        }
                   1117:                } else {
                   1118:                        return 0;
                   1119:                }
                   1120:        }
                   1121:        return 1;
                   1122: }
                   1123: 
                   1124: int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
                   1125: {
                   1126:        php_libxml_func_handler export_hnd;
                   1127:        
                   1128:        /* Initialize in case this module hasnt been loaded yet */
                   1129:        php_libxml_initialize();
                   1130:        export_hnd.export_func = export_function;
                   1131: 
                   1132:        return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
                   1133: }
                   1134: 
                   1135: PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
                   1136: {
                   1137:        zend_class_entry *ce = NULL;
                   1138:        xmlNodePtr node = NULL;
                   1139:        php_libxml_func_handler *export_hnd;
                   1140: 
                   1141:        if (object->type == IS_OBJECT) {
                   1142:                ce = Z_OBJCE_P(object);
                   1143:                while (ce->parent != NULL) {
                   1144:                        ce = ce->parent;
                   1145:                }
                   1146:                if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd)  == SUCCESS) {
                   1147:                        node = export_hnd->export_func(object TSRMLS_CC);
                   1148:                }
                   1149:        }
                   1150:        return node;
                   1151: }
                   1152: 
                   1153: PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
                   1154: {
                   1155:        int ret_refcount = -1;
                   1156: 
                   1157:        if (object != NULL && node != NULL) {
                   1158:                if (object->node != NULL) {
                   1159:                        if (object->node->node == node) {
                   1160:                                return object->node->refcount;
                   1161:                        } else {
                   1162:                                php_libxml_decrement_node_ptr(object TSRMLS_CC);
                   1163:                        }
                   1164:                }
                   1165:                if (node->_private != NULL) {
                   1166:                        object->node = node->_private;
                   1167:                        ret_refcount = ++object->node->refcount;
                   1168:                        /* Only dom uses _private */
                   1169:                        if (object->node->_private == NULL) {
                   1170:                                object->node->_private = private_data;
                   1171:                        }
                   1172:                } else {
                   1173:                        ret_refcount = 1;
                   1174:                        object->node = emalloc(sizeof(php_libxml_node_ptr));
                   1175:                        object->node->node = node;
                   1176:                        object->node->refcount = 1;
                   1177:                        object->node->_private = private_data;
                   1178:                        node->_private = object->node;
                   1179:                }
                   1180:        }
                   1181: 
                   1182:        return ret_refcount;
                   1183: }
                   1184: 
                   1185: PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
                   1186: {
                   1187:        int ret_refcount = -1;
                   1188:        php_libxml_node_ptr *obj_node;
                   1189: 
                   1190:        if (object != NULL && object->node != NULL) {
                   1191:                obj_node = (php_libxml_node_ptr *) object->node;
                   1192:                ret_refcount = --obj_node->refcount;
                   1193:                if (ret_refcount == 0) {
                   1194:                        if (obj_node->node != NULL) {
                   1195:                                obj_node->node->_private = NULL;
                   1196:                        }
                   1197:                        efree(obj_node);
                   1198:                } 
                   1199:                object->node = NULL;
                   1200:        }
                   1201: 
                   1202:        return ret_refcount;
                   1203: }
                   1204: 
                   1205: PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
                   1206: {
                   1207:        int ret_refcount = -1;
                   1208: 
                   1209:        if (object->document != NULL) {
                   1210:                object->document->refcount++;
                   1211:                ret_refcount = object->document->refcount;
                   1212:        } else if (docp != NULL) {
                   1213:                ret_refcount = 1;
                   1214:                object->document = emalloc(sizeof(php_libxml_ref_obj));
                   1215:                object->document->ptr = docp;
                   1216:                object->document->refcount = ret_refcount;
                   1217:                object->document->doc_props = NULL;
                   1218:        }
                   1219: 
                   1220:        return ret_refcount;
                   1221: }
                   1222: 
                   1223: PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
                   1224: {
                   1225:        int ret_refcount = -1;
                   1226: 
                   1227:        if (object != NULL && object->document != NULL) {
                   1228:                ret_refcount = --object->document->refcount;
                   1229:                if (ret_refcount == 0) {
                   1230:                        if (object->document->ptr != NULL) {
                   1231:                                xmlFreeDoc((xmlDoc *) object->document->ptr);
                   1232:                        }
                   1233:                        if (object->document->doc_props != NULL) {
                   1234:                                if (object->document->doc_props->classmap) {
                   1235:                                        zend_hash_destroy(object->document->doc_props->classmap);
                   1236:                                        FREE_HASHTABLE(object->document->doc_props->classmap);
                   1237:                                }
                   1238:                                efree(object->document->doc_props);
                   1239:                        }
                   1240:                        efree(object->document);
                   1241:                        object->document = NULL;
                   1242:                }
                   1243:        }
                   1244: 
                   1245:        return ret_refcount;
                   1246: }
                   1247: 
                   1248: PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
                   1249: {
                   1250:        if (!node) {
                   1251:                return;
                   1252:        }
                   1253: 
                   1254:        switch (node->type) {
                   1255:                case XML_DOCUMENT_NODE:
                   1256:                case XML_HTML_DOCUMENT_NODE:
                   1257:                        break;
                   1258:                default:
                   1259:                        if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
                   1260:                                php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
                   1261:                                switch (node->type) {
                   1262:                                        /* Skip property freeing for the following types */
                   1263:                                        case XML_ATTRIBUTE_DECL:
                   1264:                                        case XML_DTD_NODE:
                   1265:                                        case XML_DOCUMENT_TYPE_NODE:
                   1266:                                        case XML_ENTITY_DECL:
                   1267:                                        case XML_ATTRIBUTE_NODE:
                   1268:                                        case XML_NAMESPACE_DECL:
                   1269:                                        case XML_TEXT_NODE:
                   1270:                                                break;
                   1271:                                        default:
                   1272:                                                php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
                   1273:                                }
                   1274:                                if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
                   1275:                                        node->doc = NULL;
                   1276:                                }
                   1277:                                php_libxml_node_free(node);
                   1278:                        } else {
                   1279:                                php_libxml_unregister_node(node TSRMLS_CC);
                   1280:                        }
                   1281:        }
                   1282: }
                   1283: 
                   1284: PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
                   1285: {
                   1286:        int ret_refcount = -1;
                   1287:        xmlNodePtr nodep;
                   1288:        php_libxml_node_ptr *obj_node;
                   1289: 
                   1290:        if (object != NULL && object->node != NULL) {
                   1291:                obj_node = (php_libxml_node_ptr *) object->node;
                   1292:                nodep = object->node->node;
                   1293:                ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
                   1294:                if (ret_refcount == 0) {
                   1295:                        php_libxml_node_free_resource(nodep TSRMLS_CC);
                   1296:                } else {
                   1297:                        if (obj_node && object == obj_node->_private) {
                   1298:                                obj_node->_private = NULL;
                   1299:                        }
                   1300:                }
                   1301:        }
                   1302:        if (object != NULL && object->document != NULL) {
                   1303:                /* Safe to call as if the resource were freed then doc pointer is NULL */
                   1304:                php_libxml_decrement_doc_ref(object TSRMLS_CC);
                   1305:        }
                   1306: }
                   1307: /* }}} */
                   1308: 
                   1309: #ifdef PHP_WIN32
                   1310: PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
                   1311: {
                   1312:        return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
                   1313: }
                   1314: #endif
                   1315: 
                   1316: #endif
                   1317: 
                   1318: /*
                   1319:  * Local variables:
                   1320:  * tab-width: 4
                   1321:  * c-basic-offset: 4
                   1322:  * End:
                   1323:  * vim600: sw=4 ts=4 fdm=marker
                   1324:  * vim<600: sw=4 ts=4
                   1325:  */

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