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>