Annotation of embedaddon/php/ext/libxml/libxml.c, revision 1.1
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:
! 20: /* $Id: libxml.c 321634 2012-01-01 13:15:04Z felipe $ */
! 21:
! 22: #define IS_EXT_MODULE
! 23:
! 24: #ifdef HAVE_CONFIG_H
! 25: #include "config.h"
! 26: #endif
! 27:
! 28: #include "php.h"
! 29:
! 30: #define PHP_XML_INTERNAL
! 31: #include "zend_variables.h"
! 32: #include "ext/standard/php_string.h"
! 33: #include "ext/standard/info.h"
! 34: #include "ext/standard/file.h"
! 35:
! 36: #if HAVE_LIBXML
! 37:
! 38: #include <libxml/parser.h>
! 39: #include <libxml/parserInternals.h>
! 40: #include <libxml/tree.h>
! 41: #include <libxml/uri.h>
! 42: #include <libxml/xmlerror.h>
! 43: #include <libxml/xmlsave.h>
! 44: #ifdef LIBXML_SCHEMAS_ENABLED
! 45: #include <libxml/relaxng.h>
! 46: #endif
! 47:
! 48: #include "php_libxml.h"
! 49:
! 50: #define PHP_LIBXML_ERROR 0
! 51: #define PHP_LIBXML_CTX_ERROR 1
! 52: #define PHP_LIBXML_CTX_WARNING 2
! 53:
! 54: /* a true global for initialization */
! 55: static int _php_libxml_initialized = 0;
! 56:
! 57: typedef struct _php_libxml_func_handler {
! 58: php_libxml_export_node export_func;
! 59: } php_libxml_func_handler;
! 60:
! 61: static HashTable php_libxml_exports;
! 62:
! 63: static ZEND_DECLARE_MODULE_GLOBALS(libxml)
! 64: static PHP_GINIT_FUNCTION(libxml);
! 65:
! 66: static PHP_FUNCTION(libxml_set_streams_context);
! 67: static PHP_FUNCTION(libxml_use_internal_errors);
! 68: static PHP_FUNCTION(libxml_get_last_error);
! 69: static PHP_FUNCTION(libxml_clear_errors);
! 70: static PHP_FUNCTION(libxml_get_errors);
! 71: static PHP_FUNCTION(libxml_disable_entity_loader);
! 72:
! 73: static zend_class_entry *libxmlerror_class_entry;
! 74:
! 75: /* {{{ dynamically loadable module stuff */
! 76: #ifdef COMPILE_DL_LIBXML
! 77: ZEND_GET_MODULE(libxml)
! 78: #endif /* COMPILE_DL_LIBXML */
! 79: /* }}} */
! 80:
! 81: /* {{{ function prototypes */
! 82: static PHP_MINIT_FUNCTION(libxml);
! 83: static PHP_RINIT_FUNCTION(libxml);
! 84: static PHP_MSHUTDOWN_FUNCTION(libxml);
! 85: static PHP_RSHUTDOWN_FUNCTION(libxml);
! 86: static PHP_MINFO_FUNCTION(libxml);
! 87:
! 88: /* }}} */
! 89:
! 90: /* {{{ arginfo */
! 91: ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
! 92: ZEND_ARG_INFO(0, context)
! 93: ZEND_END_ARG_INFO()
! 94:
! 95: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0)
! 96: ZEND_ARG_INFO(0, use_errors)
! 97: ZEND_END_ARG_INFO()
! 98:
! 99: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
! 100: ZEND_END_ARG_INFO()
! 101:
! 102: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
! 103: ZEND_END_ARG_INFO()
! 104:
! 105: ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
! 106: ZEND_END_ARG_INFO()
! 107:
! 108: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0)
! 109: ZEND_ARG_INFO(0, disable)
! 110: ZEND_END_ARG_INFO()
! 111:
! 112: /* }}} */
! 113:
! 114: /* {{{ extension definition structures */
! 115: static const zend_function_entry libxml_functions[] = {
! 116: PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
! 117: PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
! 118: PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
! 119: PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
! 120: PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
! 121: PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader)
! 122: PHP_FE_END
! 123: };
! 124:
! 125: zend_module_entry libxml_module_entry = {
! 126: STANDARD_MODULE_HEADER,
! 127: "libxml", /* extension name */
! 128: libxml_functions, /* extension function list */
! 129: PHP_MINIT(libxml), /* extension-wide startup function */
! 130: PHP_MSHUTDOWN(libxml), /* extension-wide shutdown function */
! 131: PHP_RINIT(libxml), /* per-request startup function */
! 132: PHP_RSHUTDOWN(libxml), /* per-request shutdown function */
! 133: PHP_MINFO(libxml), /* information function */
! 134: NO_VERSION_YET,
! 135: PHP_MODULE_GLOBALS(libxml), /* globals descriptor */
! 136: PHP_GINIT(libxml), /* globals ctor */
! 137: NULL, /* globals dtor */
! 138: NULL, /* post deactivate */
! 139: STANDARD_MODULE_PROPERTIES_EX
! 140: };
! 141:
! 142: /* }}} */
! 143:
! 144: /* {{{ internal functions for interoperability */
! 145: static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC)
! 146: {
! 147: if (object->properties) {
! 148: object->properties = NULL;
! 149: }
! 150: php_libxml_decrement_node_ptr(object TSRMLS_CC);
! 151: return php_libxml_decrement_doc_ref(object TSRMLS_CC);
! 152: }
! 153:
! 154: static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC)
! 155: {
! 156: php_libxml_node_object *wrapper;
! 157:
! 158: php_libxml_node_ptr *nodeptr = nodep->_private;
! 159:
! 160: if (nodeptr != NULL) {
! 161: wrapper = nodeptr->_private;
! 162: if (wrapper) {
! 163: php_libxml_clear_object(wrapper TSRMLS_CC);
! 164: } else {
! 165: if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
! 166: nodeptr->node->_private = NULL;
! 167: }
! 168: nodeptr->node = NULL;
! 169: }
! 170: }
! 171:
! 172: return -1;
! 173: }
! 174:
! 175: static void php_libxml_node_free(xmlNodePtr node)
! 176: {
! 177: if(node) {
! 178: if (node->_private != NULL) {
! 179: ((php_libxml_node_ptr *) node->_private)->node = NULL;
! 180: }
! 181: switch (node->type) {
! 182: case XML_ATTRIBUTE_NODE:
! 183: xmlFreeProp((xmlAttrPtr) node);
! 184: break;
! 185: case XML_ENTITY_DECL:
! 186: case XML_ELEMENT_DECL:
! 187: case XML_ATTRIBUTE_DECL:
! 188: break;
! 189: case XML_NOTATION_NODE:
! 190: /* These require special handling */
! 191: if (node->name != NULL) {
! 192: xmlFree((char *) node->name);
! 193: }
! 194: if (((xmlEntityPtr) node)->ExternalID != NULL) {
! 195: xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
! 196: }
! 197: if (((xmlEntityPtr) node)->SystemID != NULL) {
! 198: xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
! 199: }
! 200: xmlFree(node);
! 201: break;
! 202: case XML_NAMESPACE_DECL:
! 203: if (node->ns) {
! 204: xmlFreeNs(node->ns);
! 205: node->ns = NULL;
! 206: }
! 207: node->type = XML_ELEMENT_NODE;
! 208: default:
! 209: xmlFreeNode(node);
! 210: }
! 211: }
! 212: }
! 213:
! 214: static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC)
! 215: {
! 216: xmlNodePtr curnode;
! 217:
! 218: if (node != NULL) {
! 219: curnode = node;
! 220: while (curnode != NULL) {
! 221: node = curnode;
! 222: switch (node->type) {
! 223: /* Skip property freeing for the following types */
! 224: case XML_NOTATION_NODE:
! 225: case XML_ENTITY_DECL:
! 226: break;
! 227: case XML_ENTITY_REF_NODE:
! 228: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
! 229: break;
! 230: case XML_ATTRIBUTE_NODE:
! 231: if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
! 232: xmlRemoveID(node->doc, (xmlAttrPtr) node);
! 233: }
! 234: case XML_ATTRIBUTE_DECL:
! 235: case XML_DTD_NODE:
! 236: case XML_DOCUMENT_TYPE_NODE:
! 237: case XML_NAMESPACE_DECL:
! 238: case XML_TEXT_NODE:
! 239: php_libxml_node_free_list(node->children TSRMLS_CC);
! 240: break;
! 241: default:
! 242: php_libxml_node_free_list(node->children TSRMLS_CC);
! 243: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
! 244: }
! 245:
! 246: curnode = node->next;
! 247: xmlUnlinkNode(node);
! 248: if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
! 249: node->doc = NULL;
! 250: }
! 251: php_libxml_node_free(node);
! 252: }
! 253: }
! 254: }
! 255:
! 256: /* }}} */
! 257:
! 258: /* {{{ startup, shutdown and info functions */
! 259: static PHP_GINIT_FUNCTION(libxml)
! 260: {
! 261: libxml_globals->stream_context = NULL;
! 262: libxml_globals->error_buffer.c = NULL;
! 263: libxml_globals->error_list = NULL;
! 264: }
! 265:
! 266: /* Channel libxml file io layer through the PHP streams subsystem.
! 267: * This allows use of ftps:// and https:// urls */
! 268:
! 269: static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
! 270: {
! 271: php_stream_statbuf ssbuf;
! 272: php_stream_context *context = NULL;
! 273: php_stream_wrapper *wrapper = NULL;
! 274: char *resolved_path, *path_to_open = NULL;
! 275: void *ret_val = NULL;
! 276: int isescaped=0;
! 277: xmlURI *uri;
! 278:
! 279: TSRMLS_FETCH();
! 280:
! 281: uri = xmlParseURI((xmlChar *)filename);
! 282: if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) {
! 283: resolved_path = xmlURIUnescapeString(filename, 0, NULL);
! 284: isescaped = 1;
! 285: } else {
! 286: resolved_path = (char *)filename;
! 287: }
! 288:
! 289: if (uri) {
! 290: xmlFreeURI(uri);
! 291: }
! 292:
! 293: if (resolved_path == NULL) {
! 294: return NULL;
! 295: }
! 296:
! 297: /* logic copied from _php_stream_stat, but we only want to fail
! 298: if the wrapper supports stat, otherwise, figure it out from
! 299: the open. This logic is only to support hiding warnings
! 300: that the streams layer puts out at times, but for libxml we
! 301: may try to open files that don't exist, but it is not a failure
! 302: in xml processing (eg. DTD files) */
! 303: wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
! 304: if (wrapper && read_only && wrapper->wops->url_stat) {
! 305: if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
! 306: if (isescaped) {
! 307: xmlFree(resolved_path);
! 308: }
! 309: return NULL;
! 310: }
! 311: }
! 312:
! 313: context = php_stream_context_from_zval(LIBXML(stream_context), 0);
! 314:
! 315: ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, context);
! 316: if (isescaped) {
! 317: xmlFree(resolved_path);
! 318: }
! 319: return ret_val;
! 320: }
! 321:
! 322: static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
! 323: {
! 324: return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
! 325: }
! 326:
! 327: static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
! 328: {
! 329: return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
! 330: }
! 331:
! 332: static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
! 333: {
! 334: TSRMLS_FETCH();
! 335: return php_stream_read((php_stream*)context, buffer, len);
! 336: }
! 337:
! 338: static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
! 339: {
! 340: TSRMLS_FETCH();
! 341: return php_stream_write((php_stream*)context, buffer, len);
! 342: }
! 343:
! 344: static int php_libxml_streams_IO_close(void *context)
! 345: {
! 346: TSRMLS_FETCH();
! 347: return php_stream_close((php_stream*)context);
! 348: }
! 349:
! 350: static xmlParserInputBufferPtr
! 351: php_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc)
! 352: {
! 353: return NULL;
! 354: }
! 355:
! 356: static xmlParserInputBufferPtr
! 357: php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
! 358: {
! 359: xmlParserInputBufferPtr ret;
! 360: void *context = NULL;
! 361:
! 362: if (URI == NULL)
! 363: return(NULL);
! 364:
! 365: context = php_libxml_streams_IO_open_read_wrapper(URI);
! 366:
! 367: if (context == NULL) {
! 368: return(NULL);
! 369: }
! 370:
! 371: /* Allocate the Input buffer front-end. */
! 372: ret = xmlAllocParserInputBuffer(enc);
! 373: if (ret != NULL) {
! 374: ret->context = context;
! 375: ret->readcallback = php_libxml_streams_IO_read;
! 376: ret->closecallback = php_libxml_streams_IO_close;
! 377: } else
! 378: php_libxml_streams_IO_close(context);
! 379:
! 380: return(ret);
! 381: }
! 382:
! 383: static xmlOutputBufferPtr
! 384: php_libxml_output_buffer_create_filename(const char *URI,
! 385: xmlCharEncodingHandlerPtr encoder,
! 386: int compression ATTRIBUTE_UNUSED)
! 387: {
! 388: xmlOutputBufferPtr ret;
! 389: xmlURIPtr puri;
! 390: void *context = NULL;
! 391: char *unescaped = NULL;
! 392:
! 393: if (URI == NULL)
! 394: return(NULL);
! 395:
! 396: puri = xmlParseURI(URI);
! 397: if (puri != NULL) {
! 398: if (puri->scheme != NULL)
! 399: unescaped = xmlURIUnescapeString(URI, 0, NULL);
! 400: xmlFreeURI(puri);
! 401: }
! 402:
! 403: if (unescaped != NULL) {
! 404: context = php_libxml_streams_IO_open_write_wrapper(unescaped);
! 405: xmlFree(unescaped);
! 406: }
! 407:
! 408: /* try with a non-escaped URI this may be a strange filename */
! 409: if (context == NULL) {
! 410: context = php_libxml_streams_IO_open_write_wrapper(URI);
! 411: }
! 412:
! 413: if (context == NULL) {
! 414: return(NULL);
! 415: }
! 416:
! 417: /* Allocate the Output buffer front-end. */
! 418: ret = xmlAllocOutputBuffer(encoder);
! 419: if (ret != NULL) {
! 420: ret->context = context;
! 421: ret->writecallback = php_libxml_streams_IO_write;
! 422: ret->closecallback = php_libxml_streams_IO_close;
! 423: }
! 424:
! 425: return(ret);
! 426: }
! 427:
! 428: static int _php_libxml_free_error(xmlErrorPtr error)
! 429: {
! 430: /* This will free the libxml alloc'd memory */
! 431: xmlResetError(error);
! 432: return 1;
! 433: }
! 434:
! 435: static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
! 436: {
! 437: xmlError error_copy;
! 438: int ret;
! 439:
! 440: TSRMLS_FETCH();
! 441:
! 442: memset(&error_copy, 0, sizeof(xmlError));
! 443:
! 444: if (error) {
! 445: ret = xmlCopyError(error, &error_copy);
! 446: } else {
! 447: error_copy.domain = 0;
! 448: error_copy.code = XML_ERR_INTERNAL_ERROR;
! 449: error_copy.level = XML_ERR_ERROR;
! 450: error_copy.line = 0;
! 451: error_copy.node = NULL;
! 452: error_copy.int1 = 0;
! 453: error_copy.int2 = 0;
! 454: error_copy.ctxt = NULL;
! 455: error_copy.message = xmlStrdup(msg);
! 456: error_copy.file = NULL;
! 457: error_copy.str1 = NULL;
! 458: error_copy.str2 = NULL;
! 459: error_copy.str3 = NULL;
! 460: ret = 0;
! 461: }
! 462:
! 463: if (ret == 0) {
! 464: zend_llist_add_element(LIBXML(error_list), &error_copy);
! 465: }
! 466: }
! 467:
! 468: static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC)
! 469: {
! 470: xmlParserCtxtPtr parser;
! 471:
! 472: parser = (xmlParserCtxtPtr) ctx;
! 473:
! 474: if (parser != NULL && parser->input != NULL) {
! 475: if (parser->input->filename) {
! 476: php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
! 477: } else {
! 478: php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line);
! 479: }
! 480: }
! 481: }
! 482:
! 483: void php_libxml_issue_error(int level, const char *msg TSRMLS_DC)
! 484: {
! 485: if (LIBXML(error_list)) {
! 486: _php_list_set_error_structure(NULL, msg);
! 487: } else {
! 488: php_error_docref(NULL TSRMLS_CC, level, "%s", msg);
! 489: }
! 490: }
! 491:
! 492: static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
! 493: {
! 494: char *buf;
! 495: int len, len_iter, output = 0;
! 496:
! 497: TSRMLS_FETCH();
! 498:
! 499: len = vspprintf(&buf, 0, *msg, ap);
! 500: len_iter = len;
! 501:
! 502: /* remove any trailing \n */
! 503: while (len_iter && buf[--len_iter] == '\n') {
! 504: buf[len_iter] = '\0';
! 505: output = 1;
! 506: }
! 507:
! 508: smart_str_appendl(&LIBXML(error_buffer), buf, len);
! 509:
! 510: efree(buf);
! 511:
! 512: if (output == 1) {
! 513: if (LIBXML(error_list)) {
! 514: _php_list_set_error_structure(NULL, LIBXML(error_buffer).c);
! 515: } else {
! 516: switch (error_type) {
! 517: case PHP_LIBXML_CTX_ERROR:
! 518: php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC);
! 519: break;
! 520: case PHP_LIBXML_CTX_WARNING:
! 521: php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC);
! 522: break;
! 523: default:
! 524: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c);
! 525: }
! 526: }
! 527: smart_str_free(&LIBXML(error_buffer));
! 528: }
! 529: }
! 530:
! 531: PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
! 532: {
! 533: va_list args;
! 534: va_start(args, msg);
! 535: php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
! 536: va_end(args);
! 537: }
! 538:
! 539: PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
! 540: {
! 541: va_list args;
! 542: va_start(args, msg);
! 543: php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
! 544: va_end(args);
! 545: }
! 546:
! 547: PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
! 548: {
! 549: _php_list_set_error_structure(error, NULL);
! 550:
! 551: return;
! 552: }
! 553:
! 554: PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
! 555: {
! 556: va_list args;
! 557: va_start(args, msg);
! 558: php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
! 559: va_end(args);
! 560: }
! 561:
! 562:
! 563: PHP_LIBXML_API void php_libxml_initialize(void)
! 564: {
! 565: if (!_php_libxml_initialized) {
! 566: /* we should be the only one's to ever init!! */
! 567: xmlInitParser();
! 568:
! 569: zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
! 570:
! 571: _php_libxml_initialized = 1;
! 572: }
! 573: }
! 574:
! 575: PHP_LIBXML_API void php_libxml_shutdown(void)
! 576: {
! 577: if (_php_libxml_initialized) {
! 578: #if defined(LIBXML_SCHEMAS_ENABLED)
! 579: xmlRelaxNGCleanupTypes();
! 580: #endif
! 581: xmlCleanupParser();
! 582: zend_hash_destroy(&php_libxml_exports);
! 583: _php_libxml_initialized = 0;
! 584: }
! 585: }
! 586:
! 587: PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
! 588: {
! 589: zval *oldcontext;
! 590:
! 591: oldcontext = LIBXML(stream_context);
! 592: LIBXML(stream_context) = context;
! 593: return oldcontext;
! 594:
! 595: }
! 596:
! 597: static PHP_MINIT_FUNCTION(libxml)
! 598: {
! 599: zend_class_entry ce;
! 600:
! 601: php_libxml_initialize();
! 602:
! 603: REGISTER_LONG_CONSTANT("LIBXML_VERSION", LIBXML_VERSION, CONST_CS | CONST_PERSISTENT);
! 604: REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION", LIBXML_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT);
! 605: REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION", (char *)xmlParserVersion, CONST_CS | CONST_PERSISTENT);
! 606:
! 607: /* For use with loading xml */
! 608: REGISTER_LONG_CONSTANT("LIBXML_NOENT", XML_PARSE_NOENT, CONST_CS | CONST_PERSISTENT);
! 609: REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD", XML_PARSE_DTDLOAD, CONST_CS | CONST_PERSISTENT);
! 610: REGISTER_LONG_CONSTANT("LIBXML_DTDATTR", XML_PARSE_DTDATTR, CONST_CS | CONST_PERSISTENT);
! 611: REGISTER_LONG_CONSTANT("LIBXML_DTDVALID", XML_PARSE_DTDVALID, CONST_CS | CONST_PERSISTENT);
! 612: REGISTER_LONG_CONSTANT("LIBXML_NOERROR", XML_PARSE_NOERROR, CONST_CS | CONST_PERSISTENT);
! 613: REGISTER_LONG_CONSTANT("LIBXML_NOWARNING", XML_PARSE_NOWARNING, CONST_CS | CONST_PERSISTENT);
! 614: REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS", XML_PARSE_NOBLANKS, CONST_CS | CONST_PERSISTENT);
! 615: REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE", XML_PARSE_XINCLUDE, CONST_CS | CONST_PERSISTENT);
! 616: REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN", XML_PARSE_NSCLEAN, CONST_CS | CONST_PERSISTENT);
! 617: REGISTER_LONG_CONSTANT("LIBXML_NOCDATA", XML_PARSE_NOCDATA, CONST_CS | CONST_PERSISTENT);
! 618: REGISTER_LONG_CONSTANT("LIBXML_NONET", XML_PARSE_NONET, CONST_CS | CONST_PERSISTENT);
! 619: #if LIBXML_VERSION >= 20621
! 620: REGISTER_LONG_CONSTANT("LIBXML_COMPACT", XML_PARSE_COMPACT, CONST_CS | CONST_PERSISTENT);
! 621: REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL", XML_SAVE_NO_DECL, CONST_CS | CONST_PERSISTENT);
! 622: #endif
! 623: #if LIBXML_VERSION >= 20703
! 624: REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE", XML_PARSE_HUGE, CONST_CS | CONST_PERSISTENT);
! 625: #endif
! 626: REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG", LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT);
! 627:
! 628: /* Error levels */
! 629: REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE", XML_ERR_NONE, CONST_CS | CONST_PERSISTENT);
! 630: REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING", XML_ERR_WARNING, CONST_CS | CONST_PERSISTENT);
! 631: REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR", XML_ERR_ERROR, CONST_CS | CONST_PERSISTENT);
! 632: REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL", XML_ERR_FATAL, CONST_CS | CONST_PERSISTENT);
! 633:
! 634: INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
! 635: libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
! 636:
! 637: return SUCCESS;
! 638: }
! 639:
! 640:
! 641: static PHP_RINIT_FUNCTION(libxml)
! 642: {
! 643: /* report errors via handler rather than stderr */
! 644: xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
! 645: xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
! 646: xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
! 647: return SUCCESS;
! 648: }
! 649:
! 650:
! 651: static PHP_MSHUTDOWN_FUNCTION(libxml)
! 652: {
! 653: php_libxml_shutdown();
! 654:
! 655: return SUCCESS;
! 656: }
! 657:
! 658:
! 659: static PHP_RSHUTDOWN_FUNCTION(libxml)
! 660: {
! 661: /* reset libxml generic error handling */
! 662: xmlSetGenericErrorFunc(NULL, NULL);
! 663: xmlSetStructuredErrorFunc(NULL, NULL);
! 664:
! 665: xmlParserInputBufferCreateFilenameDefault(NULL);
! 666: xmlOutputBufferCreateFilenameDefault(NULL);
! 667:
! 668: if (LIBXML(stream_context)) {
! 669: zval_ptr_dtor(&LIBXML(stream_context));
! 670: LIBXML(stream_context) = NULL;
! 671: }
! 672: smart_str_free(&LIBXML(error_buffer));
! 673: if (LIBXML(error_list)) {
! 674: zend_llist_destroy(LIBXML(error_list));
! 675: efree(LIBXML(error_list));
! 676: LIBXML(error_list) = NULL;
! 677: }
! 678: xmlResetLastError();
! 679:
! 680: return SUCCESS;
! 681: }
! 682:
! 683:
! 684: static PHP_MINFO_FUNCTION(libxml)
! 685: {
! 686: php_info_print_table_start();
! 687: php_info_print_table_row(2, "libXML support", "active");
! 688: php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
! 689: php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
! 690: php_info_print_table_row(2, "libXML streams", "enabled");
! 691: php_info_print_table_end();
! 692: }
! 693: /* }}} */
! 694:
! 695: /* {{{ proto void libxml_set_streams_context(resource streams_context)
! 696: Set the streams context for the next libxml document load or write */
! 697: static PHP_FUNCTION(libxml_set_streams_context)
! 698: {
! 699: zval *arg;
! 700:
! 701: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
! 702: return;
! 703: }
! 704: if (LIBXML(stream_context)) {
! 705: zval_ptr_dtor(&LIBXML(stream_context));
! 706: LIBXML(stream_context) = NULL;
! 707: }
! 708: Z_ADDREF_P(arg);
! 709: LIBXML(stream_context) = arg;
! 710: }
! 711: /* }}} */
! 712:
! 713: /* {{{ proto bool libxml_use_internal_errors([boolean use_errors])
! 714: Disable libxml errors and allow user to fetch error information as needed */
! 715: static PHP_FUNCTION(libxml_use_internal_errors)
! 716: {
! 717: xmlStructuredErrorFunc current_handler;
! 718: zend_bool use_errors=0, retval;
! 719:
! 720: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
! 721: return;
! 722: }
! 723:
! 724: current_handler = xmlStructuredError;
! 725: if (current_handler && current_handler == php_libxml_structured_error_handler) {
! 726: retval = 1;
! 727: } else {
! 728: retval = 0;
! 729: }
! 730:
! 731: if (ZEND_NUM_ARGS() == 0) {
! 732: RETURN_BOOL(retval);
! 733: }
! 734:
! 735: if (use_errors == 0) {
! 736: xmlSetStructuredErrorFunc(NULL, NULL);
! 737: if (LIBXML(error_list)) {
! 738: zend_llist_destroy(LIBXML(error_list));
! 739: efree(LIBXML(error_list));
! 740: LIBXML(error_list) = NULL;
! 741: }
! 742: } else {
! 743: xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
! 744: if (LIBXML(error_list) == NULL) {
! 745: LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
! 746: zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
! 747: }
! 748: }
! 749: RETURN_BOOL(retval);
! 750: }
! 751: /* }}} */
! 752:
! 753: /* {{{ proto object libxml_get_last_error()
! 754: Retrieve last error from libxml */
! 755: static PHP_FUNCTION(libxml_get_last_error)
! 756: {
! 757: xmlErrorPtr error;
! 758:
! 759: error = xmlGetLastError();
! 760:
! 761: if (error) {
! 762: object_init_ex(return_value, libxmlerror_class_entry);
! 763: add_property_long(return_value, "level", error->level);
! 764: add_property_long(return_value, "code", error->code);
! 765: add_property_long(return_value, "column", error->int2);
! 766: if (error->message) {
! 767: add_property_string(return_value, "message", error->message, 1);
! 768: } else {
! 769: add_property_stringl(return_value, "message", "", 0, 1);
! 770: }
! 771: if (error->file) {
! 772: add_property_string(return_value, "file", error->file, 1);
! 773: } else {
! 774: add_property_stringl(return_value, "file", "", 0, 1);
! 775: }
! 776: add_property_long(return_value, "line", error->line);
! 777: } else {
! 778: RETURN_FALSE;
! 779: }
! 780: }
! 781: /* }}} */
! 782:
! 783: /* {{{ proto object libxml_get_errors()
! 784: Retrieve array of errors */
! 785: static PHP_FUNCTION(libxml_get_errors)
! 786: {
! 787:
! 788: xmlErrorPtr error;
! 789:
! 790: if (array_init(return_value) == FAILURE) {
! 791: RETURN_FALSE;
! 792: }
! 793:
! 794: if (LIBXML(error_list)) {
! 795:
! 796: error = zend_llist_get_first(LIBXML(error_list));
! 797:
! 798: while (error != NULL) {
! 799: zval *z_error;
! 800: MAKE_STD_ZVAL(z_error);
! 801:
! 802: object_init_ex(z_error, libxmlerror_class_entry);
! 803: add_property_long(z_error, "level", error->level);
! 804: add_property_long(z_error, "code", error->code);
! 805: add_property_long(z_error, "column", error->int2);
! 806: if (error->message) {
! 807: add_property_string(z_error, "message", error->message, 1);
! 808: } else {
! 809: add_property_stringl(z_error, "message", "", 0, 1);
! 810: }
! 811: if (error->file) {
! 812: add_property_string(z_error, "file", error->file, 1);
! 813: } else {
! 814: add_property_stringl(z_error, "file", "", 0, 1);
! 815: }
! 816: add_property_long(z_error, "line", error->line);
! 817: add_next_index_zval(return_value, z_error);
! 818:
! 819: error = zend_llist_get_next(LIBXML(error_list));
! 820: }
! 821: }
! 822: }
! 823: /* }}} */
! 824:
! 825: /* {{{ proto void libxml_clear_errors()
! 826: Clear last error from libxml */
! 827: static PHP_FUNCTION(libxml_clear_errors)
! 828: {
! 829: xmlResetLastError();
! 830: if (LIBXML(error_list)) {
! 831: zend_llist_clean(LIBXML(error_list));
! 832: }
! 833: }
! 834: /* }}} */
! 835:
! 836: /* {{{ proto bool libxml_disable_entity_loader([boolean disable])
! 837: Disable/Enable ability to load external entities */
! 838: static PHP_FUNCTION(libxml_disable_entity_loader)
! 839: {
! 840: zend_bool disable = 1;
! 841: xmlParserInputBufferCreateFilenameFunc old;
! 842:
! 843: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) {
! 844: return;
! 845: }
! 846:
! 847: if (disable == 0) {
! 848: old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
! 849: } else {
! 850: old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_noload);
! 851: }
! 852:
! 853: if (old == php_libxml_input_buffer_noload) {
! 854: RETURN_TRUE;
! 855: }
! 856:
! 857: RETURN_FALSE;
! 858: }
! 859: /* }}} */
! 860:
! 861: /* {{{ Common functions shared by extensions */
! 862: int php_libxml_xmlCheckUTF8(const unsigned char *s)
! 863: {
! 864: int i;
! 865: unsigned char c;
! 866:
! 867: for (i = 0; (c = s[i++]);) {
! 868: if ((c & 0x80) == 0) {
! 869: } else if ((c & 0xe0) == 0xc0) {
! 870: if ((s[i++] & 0xc0) != 0x80) {
! 871: return 0;
! 872: }
! 873: } else if ((c & 0xf0) == 0xe0) {
! 874: if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
! 875: return 0;
! 876: }
! 877: } else if ((c & 0xf8) == 0xf0) {
! 878: if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
! 879: return 0;
! 880: }
! 881: } else {
! 882: return 0;
! 883: }
! 884: }
! 885: return 1;
! 886: }
! 887:
! 888: int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
! 889: {
! 890: php_libxml_func_handler export_hnd;
! 891:
! 892: /* Initialize in case this module hasnt been loaded yet */
! 893: php_libxml_initialize();
! 894: export_hnd.export_func = export_function;
! 895:
! 896: return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
! 897: }
! 898:
! 899: PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
! 900: {
! 901: zend_class_entry *ce = NULL;
! 902: xmlNodePtr node = NULL;
! 903: php_libxml_func_handler *export_hnd;
! 904:
! 905: if (object->type == IS_OBJECT) {
! 906: ce = Z_OBJCE_P(object);
! 907: while (ce->parent != NULL) {
! 908: ce = ce->parent;
! 909: }
! 910: if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd) == SUCCESS) {
! 911: node = export_hnd->export_func(object TSRMLS_CC);
! 912: }
! 913: }
! 914: return node;
! 915: }
! 916:
! 917: PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
! 918: {
! 919: int ret_refcount = -1;
! 920:
! 921: if (object != NULL && node != NULL) {
! 922: if (object->node != NULL) {
! 923: if (object->node->node == node) {
! 924: return object->node->refcount;
! 925: } else {
! 926: php_libxml_decrement_node_ptr(object TSRMLS_CC);
! 927: }
! 928: }
! 929: if (node->_private != NULL) {
! 930: object->node = node->_private;
! 931: ret_refcount = ++object->node->refcount;
! 932: /* Only dom uses _private */
! 933: if (object->node->_private == NULL) {
! 934: object->node->_private = private_data;
! 935: }
! 936: } else {
! 937: ret_refcount = 1;
! 938: object->node = emalloc(sizeof(php_libxml_node_ptr));
! 939: object->node->node = node;
! 940: object->node->refcount = 1;
! 941: object->node->_private = private_data;
! 942: node->_private = object->node;
! 943: }
! 944: }
! 945:
! 946: return ret_refcount;
! 947: }
! 948:
! 949: PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
! 950: {
! 951: int ret_refcount = -1;
! 952: php_libxml_node_ptr *obj_node;
! 953:
! 954: if (object != NULL && object->node != NULL) {
! 955: obj_node = (php_libxml_node_ptr *) object->node;
! 956: ret_refcount = --obj_node->refcount;
! 957: if (ret_refcount == 0) {
! 958: if (obj_node->node != NULL) {
! 959: obj_node->node->_private = NULL;
! 960: }
! 961: efree(obj_node);
! 962: }
! 963: object->node = NULL;
! 964: }
! 965:
! 966: return ret_refcount;
! 967: }
! 968:
! 969: PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
! 970: {
! 971: int ret_refcount = -1;
! 972:
! 973: if (object->document != NULL) {
! 974: object->document->refcount++;
! 975: ret_refcount = object->document->refcount;
! 976: } else if (docp != NULL) {
! 977: ret_refcount = 1;
! 978: object->document = emalloc(sizeof(php_libxml_ref_obj));
! 979: object->document->ptr = docp;
! 980: object->document->refcount = ret_refcount;
! 981: object->document->doc_props = NULL;
! 982: }
! 983:
! 984: return ret_refcount;
! 985: }
! 986:
! 987: PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
! 988: {
! 989: int ret_refcount = -1;
! 990:
! 991: if (object != NULL && object->document != NULL) {
! 992: ret_refcount = --object->document->refcount;
! 993: if (ret_refcount == 0) {
! 994: if (object->document->ptr != NULL) {
! 995: xmlFreeDoc((xmlDoc *) object->document->ptr);
! 996: }
! 997: if (object->document->doc_props != NULL) {
! 998: if (object->document->doc_props->classmap) {
! 999: zend_hash_destroy(object->document->doc_props->classmap);
! 1000: FREE_HASHTABLE(object->document->doc_props->classmap);
! 1001: }
! 1002: efree(object->document->doc_props);
! 1003: }
! 1004: efree(object->document);
! 1005: object->document = NULL;
! 1006: }
! 1007: }
! 1008:
! 1009: return ret_refcount;
! 1010: }
! 1011:
! 1012: PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
! 1013: {
! 1014: if (!node) {
! 1015: return;
! 1016: }
! 1017:
! 1018: switch (node->type) {
! 1019: case XML_DOCUMENT_NODE:
! 1020: case XML_HTML_DOCUMENT_NODE:
! 1021: break;
! 1022: default:
! 1023: if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
! 1024: php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
! 1025: switch (node->type) {
! 1026: /* Skip property freeing for the following types */
! 1027: case XML_ATTRIBUTE_DECL:
! 1028: case XML_DTD_NODE:
! 1029: case XML_DOCUMENT_TYPE_NODE:
! 1030: case XML_ENTITY_DECL:
! 1031: case XML_ATTRIBUTE_NODE:
! 1032: case XML_NAMESPACE_DECL:
! 1033: case XML_TEXT_NODE:
! 1034: break;
! 1035: default:
! 1036: php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
! 1037: }
! 1038: if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
! 1039: node->doc = NULL;
! 1040: }
! 1041: php_libxml_node_free(node);
! 1042: } else {
! 1043: php_libxml_unregister_node(node TSRMLS_CC);
! 1044: }
! 1045: }
! 1046: }
! 1047:
! 1048: PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
! 1049: {
! 1050: int ret_refcount = -1;
! 1051: xmlNodePtr nodep;
! 1052: php_libxml_node_ptr *obj_node;
! 1053:
! 1054: if (object != NULL && object->node != NULL) {
! 1055: obj_node = (php_libxml_node_ptr *) object->node;
! 1056: nodep = object->node->node;
! 1057: ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
! 1058: if (ret_refcount == 0) {
! 1059: php_libxml_node_free_resource(nodep TSRMLS_CC);
! 1060: } else {
! 1061: if (obj_node && object == obj_node->_private) {
! 1062: obj_node->_private = NULL;
! 1063: }
! 1064: }
! 1065: }
! 1066: if (object != NULL && object->document != NULL) {
! 1067: /* Safe to call as if the resource were freed then doc pointer is NULL */
! 1068: php_libxml_decrement_doc_ref(object TSRMLS_CC);
! 1069: }
! 1070: }
! 1071: /* }}} */
! 1072:
! 1073: #ifdef PHP_WIN32
! 1074: PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
! 1075: {
! 1076: return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
! 1077: }
! 1078: #endif
! 1079:
! 1080: #endif
! 1081:
! 1082: /*
! 1083: * Local variables:
! 1084: * tab-width: 4
! 1085: * c-basic-offset: 4
! 1086: * End:
! 1087: * vim600: sw=4 ts=4 fdm=marker
! 1088: * vim<600: sw=4 ts=4
! 1089: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>