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