#define IS_EXT_MODULE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#define PHP_XML_INTERNAL
#include "zend_variables.h"
#include "ext/standard/php_string.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
#if HAVE_LIBXML
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/tree.h>
#include <libxml/uri.h>
#include <libxml/xmlerror.h>
#include <libxml/xmlsave.h>
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#endif
#include "php_libxml.h"
#define PHP_LIBXML_ERROR 0
#define PHP_LIBXML_CTX_ERROR 1
#define PHP_LIBXML_CTX_WARNING 2
static int _php_libxml_initialized = 0;
typedef struct _php_libxml_func_handler {
php_libxml_export_node export_func;
} php_libxml_func_handler;
static HashTable php_libxml_exports;
static ZEND_DECLARE_MODULE_GLOBALS(libxml)
static PHP_GINIT_FUNCTION(libxml);
static PHP_FUNCTION(libxml_set_streams_context);
static PHP_FUNCTION(libxml_use_internal_errors);
static PHP_FUNCTION(libxml_get_last_error);
static PHP_FUNCTION(libxml_clear_errors);
static PHP_FUNCTION(libxml_get_errors);
static zend_class_entry *libxmlerror_class_entry;
#ifdef COMPILE_DL_LIBXML
ZEND_GET_MODULE(libxml)
#endif
static PHP_MINIT_FUNCTION(libxml);
static PHP_RINIT_FUNCTION(libxml);
static PHP_MSHUTDOWN_FUNCTION(libxml);
static PHP_RSHUTDOWN_FUNCTION(libxml);
static PHP_MINFO_FUNCTION(libxml);
static
ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO(arginfo_libxml_use_internal_errors, 0)
ZEND_ARG_INFO(0, use_errors)
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
ZEND_END_ARG_INFO()
static zend_function_entry libxml_functions[] = {
PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
{NULL, NULL, NULL}
};
zend_module_entry libxml_module_entry = {
STANDARD_MODULE_HEADER,
"libxml",
libxml_functions,
PHP_MINIT(libxml),
PHP_MSHUTDOWN(libxml),
PHP_RINIT(libxml),
PHP_RSHUTDOWN(libxml),
PHP_MINFO(libxml),
NO_VERSION_YET,
PHP_MODULE_GLOBALS(libxml),
PHP_GINIT(libxml),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC)
{
if (object->properties) {
object->properties = NULL;
}
php_libxml_decrement_node_ptr(object TSRMLS_CC);
return php_libxml_decrement_doc_ref(object TSRMLS_CC);
}
static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC)
{
php_libxml_node_object *wrapper;
php_libxml_node_ptr *nodeptr = nodep->_private;
if (nodeptr != NULL) {
wrapper = nodeptr->_private;
if (wrapper) {
php_libxml_clear_object(wrapper TSRMLS_CC);
} else {
if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
nodeptr->node->_private = NULL;
}
nodeptr->node = NULL;
}
}
return -1;
}
static void php_libxml_node_free(xmlNodePtr node)
{
if(node) {
if (node->_private != NULL) {
((php_libxml_node_ptr *) node->_private)->node = NULL;
}
switch (node->type) {
case XML_ATTRIBUTE_NODE:
xmlFreeProp((xmlAttrPtr) node);
break;
case XML_ENTITY_DECL:
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
break;
case XML_NOTATION_NODE:
if (node->name != NULL) {
xmlFree((char *) node->name);
}
if (((xmlEntityPtr) node)->ExternalID != NULL) {
xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
}
if (((xmlEntityPtr) node)->SystemID != NULL) {
xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
}
xmlFree(node);
break;
case XML_NAMESPACE_DECL:
if (node->ns) {
xmlFreeNs(node->ns);
node->ns = NULL;
}
node->type = XML_ELEMENT_NODE;
default:
xmlFreeNode(node);
}
}
}
static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC)
{
xmlNodePtr curnode;
if (node != NULL) {
curnode = node;
while (curnode != NULL) {
node = curnode;
switch (node->type) {
case XML_NOTATION_NODE:
break;
case XML_ENTITY_REF_NODE:
php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
break;
case XML_ATTRIBUTE_NODE:
if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
xmlRemoveID(node->doc, (xmlAttrPtr) node);
}
case XML_ATTRIBUTE_DECL:
case XML_DTD_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_ENTITY_DECL:
case XML_NAMESPACE_DECL:
case XML_TEXT_NODE:
php_libxml_node_free_list(node->children TSRMLS_CC);
break;
default:
php_libxml_node_free_list(node->children TSRMLS_CC);
php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
}
curnode = node->next;
xmlUnlinkNode(node);
if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
node->doc = NULL;
}
php_libxml_node_free(node);
}
}
}
static PHP_GINIT_FUNCTION(libxml)
{
libxml_globals->stream_context = NULL;
libxml_globals->error_buffer.c = NULL;
libxml_globals->error_list = NULL;
}
static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
{
php_stream_statbuf ssbuf;
php_stream_context *context = NULL;
php_stream_wrapper *wrapper = NULL;
char *resolved_path, *path_to_open = NULL;
void *ret_val = NULL;
int isescaped=0;
xmlURI *uri;
TSRMLS_FETCH();
uri = xmlParseURI((xmlChar *)filename);
if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) {
resolved_path = xmlURIUnescapeString(filename, 0, NULL);
isescaped = 1;
} else {
resolved_path = (char *)filename;
}
if (uri) {
xmlFreeURI(uri);
}
if (resolved_path == NULL) {
return NULL;
}
wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
if (wrapper && read_only && wrapper->wops->url_stat) {
if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
if (isescaped) {
xmlFree(resolved_path);
}
return NULL;
}
}
if (LIBXML(stream_context)) {
context = zend_fetch_resource(&LIBXML(stream_context) TSRMLS_CC, -1, "Stream-Context", NULL, 1, php_le_stream_context());
}
ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, context);
if (isescaped) {
xmlFree(resolved_path);
}
return ret_val;
}
static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
{
return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
}
static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
{
return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
}
static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
{
TSRMLS_FETCH();
return php_stream_read((php_stream*)context, buffer, len);
}
static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
{
TSRMLS_FETCH();
return php_stream_write((php_stream*)context, buffer, len);
}
static int php_libxml_streams_IO_close(void *context)
{
TSRMLS_FETCH();
return php_stream_close((php_stream*)context);
}
static xmlParserInputBufferPtr
php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
{
xmlParserInputBufferPtr ret;
void *context = NULL;
if (URI == NULL)
return(NULL);
context = php_libxml_streams_IO_open_read_wrapper(URI);
if (context == NULL) {
return(NULL);
}
ret = xmlAllocParserInputBuffer(enc);
if (ret != NULL) {
ret->context = context;
ret->readcallback = php_libxml_streams_IO_read;
ret->closecallback = php_libxml_streams_IO_close;
} else
php_libxml_streams_IO_close(context);
return(ret);
}
static xmlOutputBufferPtr
php_libxml_output_buffer_create_filename(const char *URI,
xmlCharEncodingHandlerPtr encoder,
int compression ATTRIBUTE_UNUSED)
{
xmlOutputBufferPtr ret;
xmlURIPtr puri;
void *context = NULL;
char *unescaped = NULL;
if (URI == NULL)
return(NULL);
puri = xmlParseURI(URI);
if (puri != NULL) {
if (puri->scheme != NULL)
unescaped = xmlURIUnescapeString(URI, 0, NULL);
xmlFreeURI(puri);
}
if (unescaped != NULL) {
context = php_libxml_streams_IO_open_write_wrapper(unescaped);
xmlFree(unescaped);
}
if (context == NULL) {
context = php_libxml_streams_IO_open_write_wrapper(URI);
}
if (context == NULL) {
return(NULL);
}
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = context;
ret->writecallback = php_libxml_streams_IO_write;
ret->closecallback = php_libxml_streams_IO_close;
}
return(ret);
}
static int _php_libxml_free_error(xmlErrorPtr error)
{
xmlResetError(error);
return 1;
}
static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
{
xmlError error_copy;
int ret;
TSRMLS_FETCH();
memset(&error_copy, 0, sizeof(xmlError));
if (error) {
ret = xmlCopyError(error, &error_copy);
} else {
error_copy.domain = 0;
error_copy.code = XML_ERR_INTERNAL_ERROR;
error_copy.level = XML_ERR_ERROR;
error_copy.line = 0;
error_copy.node = NULL;
error_copy.int1 = 0;
error_copy.int2 = 0;
error_copy.ctxt = NULL;
error_copy.message = xmlStrdup(msg);
error_copy.file = NULL;
error_copy.str1 = NULL;
error_copy.str2 = NULL;
error_copy.str3 = NULL;
ret = 0;
}
if (ret == 0) {
zend_llist_add_element(LIBXML(error_list), &error_copy);
}
}
static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC)
{
xmlParserCtxtPtr parser;
parser = (xmlParserCtxtPtr) ctx;
if (parser != NULL && parser->input != NULL) {
if (parser->input->filename) {
php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
} else {
php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line);
}
}
}
void php_libxml_issue_error(int level, const char *msg TSRMLS_DC)
{
if (LIBXML(error_list)) {
_php_list_set_error_structure(NULL, msg);
} else {
php_error_docref(NULL TSRMLS_CC, level, "%s", msg);
}
}
static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
{
char *buf;
int len, len_iter, output = 0;
TSRMLS_FETCH();
len = vspprintf(&buf, 0, *msg, ap);
len_iter = len;
while (len_iter && buf[--len_iter] == '\n') {
buf[len_iter] = '\0';
output = 1;
}
smart_str_appendl(&LIBXML(error_buffer), buf, len);
efree(buf);
if (output == 1) {
if (LIBXML(error_list)) {
_php_list_set_error_structure(NULL, LIBXML(error_buffer).c);
} else {
switch (error_type) {
case PHP_LIBXML_CTX_ERROR:
php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC);
break;
case PHP_LIBXML_CTX_WARNING:
php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC);
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c);
}
}
smart_str_free(&LIBXML(error_buffer));
}
}
void php_libxml_ctx_error(void *ctx, const char *msg, ...)
{
va_list args;
va_start(args, msg);
php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
va_end(args);
}
void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
{
va_list args;
va_start(args, msg);
php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
va_end(args);
}
PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
{
_php_list_set_error_structure(error, NULL);
return;
}
PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
{
va_list args;
va_start(args, msg);
php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
va_end(args);
}
PHP_LIBXML_API void php_libxml_initialize(void)
{
if (!_php_libxml_initialized) {
xmlInitParser();
zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
_php_libxml_initialized = 1;
}
}
PHP_LIBXML_API void php_libxml_shutdown(void)
{
if (_php_libxml_initialized) {
#if defined(LIBXML_SCHEMAS_ENABLED)
xmlRelaxNGCleanupTypes();
#endif
xmlCleanupParser();
zend_hash_destroy(&php_libxml_exports);
_php_libxml_initialized = 0;
}
}
PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
{
zval *oldcontext;
oldcontext = LIBXML(stream_context);
LIBXML(stream_context) = context;
return oldcontext;
}
static PHP_MINIT_FUNCTION(libxml)
{
zend_class_entry ce;
php_libxml_initialize();
REGISTER_LONG_CONSTANT("LIBXML_VERSION", LIBXML_VERSION, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION", LIBXML_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOENT", XML_PARSE_NOENT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD", XML_PARSE_DTDLOAD, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_DTDATTR", XML_PARSE_DTDATTR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_DTDVALID", XML_PARSE_DTDVALID, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOERROR", XML_PARSE_NOERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOWARNING", XML_PARSE_NOWARNING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS", XML_PARSE_NOBLANKS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE", XML_PARSE_XINCLUDE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN", XML_PARSE_NSCLEAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOCDATA", XML_PARSE_NOCDATA, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NONET", XML_PARSE_NONET, CONST_CS | CONST_PERSISTENT);
#if LIBXML_VERSION >= 20621
REGISTER_LONG_CONSTANT("LIBXML_COMPACT", XML_PARSE_COMPACT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL", XML_SAVE_NO_DECL, CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG", LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE", XML_ERR_NONE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING", XML_ERR_WARNING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR", XML_ERR_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL", XML_ERR_FATAL, CONST_CS | CONST_PERSISTENT);
INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
return SUCCESS;
}
static PHP_RINIT_FUNCTION(libxml)
{
xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
return SUCCESS;
}
static PHP_MSHUTDOWN_FUNCTION(libxml)
{
php_libxml_shutdown();
return SUCCESS;
}
static PHP_RSHUTDOWN_FUNCTION(libxml)
{
xmlSetGenericErrorFunc(NULL, NULL);
xmlSetStructuredErrorFunc(NULL, NULL);
xmlParserInputBufferCreateFilenameDefault(NULL);
xmlOutputBufferCreateFilenameDefault(NULL);
if (LIBXML(stream_context)) {
zval_ptr_dtor(&LIBXML(stream_context));
LIBXML(stream_context) = NULL;
}
smart_str_free(&LIBXML(error_buffer));
if (LIBXML(error_list)) {
zend_llist_destroy(LIBXML(error_list));
efree(LIBXML(error_list));
LIBXML(error_list) = NULL;
}
xmlResetLastError();
return SUCCESS;
}
static PHP_MINFO_FUNCTION(libxml)
{
php_info_print_table_start();
php_info_print_table_row(2, "libXML support", "active");
php_info_print_table_row(2, "libXML Version", LIBXML_DOTTED_VERSION);
php_info_print_table_row(2, "libXML streams", "enabled");
php_info_print_table_end();
}
static PHP_FUNCTION(libxml_set_streams_context)
{
zval *arg;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
return;
}
if (LIBXML(stream_context)) {
zval_ptr_dtor(&LIBXML(stream_context));
LIBXML(stream_context) = NULL;
}
ZVAL_ADDREF(arg);
LIBXML(stream_context) = arg;
}
static PHP_FUNCTION(libxml_use_internal_errors)
{
xmlStructuredErrorFunc current_handler;
zend_bool use_errors=0, retval;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
return;
}
current_handler = xmlStructuredError;
if (current_handler && current_handler == php_libxml_structured_error_handler) {
retval = 1;
} else {
retval = 0;
}
if (ZEND_NUM_ARGS() == 0) {
RETURN_BOOL(retval);
}
if (use_errors == 0) {
xmlSetStructuredErrorFunc(NULL, NULL);
if (LIBXML(error_list)) {
zend_llist_destroy(LIBXML(error_list));
efree(LIBXML(error_list));
LIBXML(error_list) = NULL;
}
} else {
xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
if (LIBXML(error_list) == NULL) {
LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
}
}
RETURN_BOOL(retval);
}
static PHP_FUNCTION(libxml_get_last_error)
{
xmlErrorPtr error;
error = xmlGetLastError();
if (error) {
object_init_ex(return_value, libxmlerror_class_entry);
add_property_long(return_value, "level", error->level);
add_property_long(return_value, "code", error->code);
add_property_long(return_value, "column", error->int2);
if (error->message) {
add_property_string(return_value, "message", error->message, 1);
} else {
add_property_stringl(return_value, "message", "", 0, 1);
}
if (error->file) {
add_property_string(return_value, "file", error->file, 1);
} else {
add_property_stringl(return_value, "file", "", 0, 1);
}
add_property_long(return_value, "line", error->line);
} else {
RETURN_FALSE;
}
}
static PHP_FUNCTION(libxml_get_errors)
{
xmlErrorPtr error;
if (array_init(return_value) == FAILURE) {
RETURN_FALSE;
}
if (LIBXML(error_list)) {
error = zend_llist_get_first(LIBXML(error_list));
while (error != NULL) {
zval *z_error;
MAKE_STD_ZVAL(z_error);
object_init_ex(z_error, libxmlerror_class_entry);
add_property_long(z_error, "level", error->level);
add_property_long(z_error, "code", error->code);
add_property_long(z_error, "column", error->int2);
if (error->message) {
add_property_string(z_error, "message", error->message, 1);
} else {
add_property_stringl(z_error, "message", "", 0, 1);
}
if (error->file) {
add_property_string(z_error, "file", error->file, 1);
} else {
add_property_stringl(z_error, "file", "", 0, 1);
}
add_property_long(z_error, "line", error->line);
add_next_index_zval(return_value, z_error);
error = zend_llist_get_next(LIBXML(error_list));
}
}
}
static PHP_FUNCTION(libxml_clear_errors)
{
xmlResetLastError();
if (LIBXML(error_list)) {
zend_llist_clean(LIBXML(error_list));
}
}
int php_libxml_xmlCheckUTF8(const unsigned char *s)
{
int i;
unsigned char c;
for (i = 0; (c = s[i++]);) {
if ((c & 0x80) == 0) {
} else if ((c & 0xe0) == 0xc0) {
if ((s[i++] & 0xc0) != 0x80) {
return 0;
}
} else if ((c & 0xf0) == 0xe0) {
if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
return 0;
}
} else if ((c & 0xf8) == 0xf0) {
if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
return 0;
}
} else {
return 0;
}
}
return 1;
}
int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
{
php_libxml_func_handler export_hnd;
php_libxml_initialize();
export_hnd.export_func = export_function;
return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
}
PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
{
zend_class_entry *ce = NULL;
xmlNodePtr node = NULL;
php_libxml_func_handler *export_hnd;
if (object->type == IS_OBJECT) {
ce = Z_OBJCE_P(object);
while (ce->parent != NULL) {
ce = ce->parent;
}
if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd) == SUCCESS) {
node = export_hnd->export_func(object TSRMLS_CC);
}
}
return node;
}
PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
{
int ret_refcount = -1;
if (object != NULL && node != NULL) {
if (object->node != NULL) {
if (object->node->node == node) {
return object->node->refcount;
} else {
php_libxml_decrement_node_ptr(object TSRMLS_CC);
}
}
if (node->_private != NULL) {
object->node = node->_private;
ret_refcount = ++object->node->refcount;
if (object->node->_private == NULL) {
object->node->_private = private_data;
}
} else {
ret_refcount = 1;
object->node = emalloc(sizeof(php_libxml_node_ptr));
object->node->node = node;
object->node->refcount = 1;
object->node->_private = private_data;
node->_private = object->node;
}
}
return ret_refcount;
}
PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
{
int ret_refcount = -1;
php_libxml_node_ptr *obj_node;
if (object != NULL && object->node != NULL) {
obj_node = (php_libxml_node_ptr *) object->node;
ret_refcount = --obj_node->refcount;
if (ret_refcount == 0) {
if (obj_node->node != NULL) {
obj_node->node->_private = NULL;
}
efree(obj_node);
}
object->node = NULL;
}
return ret_refcount;
}
PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
{
int ret_refcount = -1;
if (object->document != NULL) {
object->document->refcount++;
ret_refcount = object->document->refcount;
} else if (docp != NULL) {
ret_refcount = 1;
object->document = emalloc(sizeof(php_libxml_ref_obj));
object->document->ptr = docp;
object->document->refcount = ret_refcount;
object->document->doc_props = NULL;
}
return ret_refcount;
}
PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
{
int ret_refcount = -1;
if (object != NULL && object->document != NULL) {
ret_refcount = --object->document->refcount;
if (ret_refcount == 0) {
if (object->document->ptr != NULL) {
xmlFreeDoc((xmlDoc *) object->document->ptr);
}
if (object->document->doc_props != NULL) {
if (object->document->doc_props->classmap) {
zend_hash_destroy(object->document->doc_props->classmap);
FREE_HASHTABLE(object->document->doc_props->classmap);
}
efree(object->document->doc_props);
}
efree(object->document);
object->document = NULL;
}
}
return ret_refcount;
}
void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
{
if (!node) {
return;
}
switch (node->type) {
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
break;
default:
if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
switch (node->type) {
case XML_ATTRIBUTE_DECL:
case XML_DTD_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_ENTITY_DECL:
case XML_ATTRIBUTE_NODE:
case XML_NAMESPACE_DECL:
case XML_TEXT_NODE:
break;
default:
php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
}
if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
node->doc = NULL;
}
php_libxml_node_free(node);
} else {
php_libxml_unregister_node(node TSRMLS_CC);
}
}
}
void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
{
int ret_refcount = -1;
xmlNodePtr nodep;
php_libxml_node_ptr *obj_node;
if (object != NULL && object->node != NULL) {
obj_node = (php_libxml_node_ptr *) object->node;
nodep = object->node->node;
ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
if (ret_refcount == 0) {
php_libxml_node_free_resource(nodep TSRMLS_CC);
} else {
if (obj_node && object == obj_node->_private) {
obj_node->_private = NULL;
}
}
}
if (object != NULL && object->document != NULL) {
php_libxml_decrement_doc_ref(object TSRMLS_CC);
}
}
#ifdef PHP_WIN32
PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
}
#endif
#endif