Files
php-gtk-src/main/phpg_gvalue.c
Elizabeth M Smith b9901ae600 Segfault bug on win32 and windows build system
issue with the zend destructor using type and getting confused when
there was no type - only showed up on release builds on win32 (grrr
stupid thing) - also fixed the compiler detection and flags.  This
probably breaks things for older then 2008 compilers, really don't care
2012-08-14 21:40:50 -04:00

556 lines
18 KiB
C

/*
* PHP-GTK - The PHP language bindings for GTK+
*
* Copyright (C) 2001-2008 Andrei Zmievski <andrei@php.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "php_gtk.h"
#if HAVE_PHP_GTK
/*
* GValue related functions
*/
/* {{{ PHP_GTK_API phpg_gvalue_to_zval() */
PHP_GTK_API int phpg_gvalue_to_zval(const GValue *gval, zval **value, zend_bool copy_boxed, zend_bool do_utf8 TSRMLS_DC)
{
assert(value != NULL);
switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(gval))) {
case G_TYPE_INVALID:
case G_TYPE_NONE:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_NULL(*value);
break;
case G_TYPE_CHAR:
{
gchar val = g_value_get_char(gval);
MAKE_ZVAL_IF_NULL(*value);
ZVAL_STRINGL(*value, (char *)&val, 1, 1);
}
break;
case G_TYPE_UCHAR:
{
guchar val = g_value_get_uchar(gval);
MAKE_ZVAL_IF_NULL(*value);
ZVAL_STRINGL(*value, (char *)&val, 1, 1);
}
break;
case G_TYPE_BOOLEAN:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_BOOL(*value, g_value_get_boolean(gval));
break;
case G_TYPE_INT:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_int(gval));
break;
case G_TYPE_LONG:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_long(gval));
break;
case G_TYPE_UINT:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_uint(gval));
break;
case G_TYPE_ULONG:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_ulong(gval));
break;
case G_TYPE_FLOAT:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_DOUBLE(*value, (double)g_value_get_float(gval));
break;
case G_TYPE_DOUBLE:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_DOUBLE(*value, (double)g_value_get_double(gval));
break;
case G_TYPE_ENUM:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_enum(gval));
break;
case G_TYPE_FLAGS:
MAKE_ZVAL_IF_NULL(*value);
ZVAL_LONG(*value, (long)g_value_get_flags(gval));
break;
case G_TYPE_STRING:
{
gchar *cp = NULL;
gsize cp_len = 0;
zend_bool free_cp = 0;
const gchar *str = g_value_get_string(gval);
MAKE_ZVAL_IF_NULL(*value);
if (str != NULL) {
if (do_utf8) {
cp = phpg_from_utf8(str, strlen(str), &cp_len, &free_cp TSRMLS_CC);
if (cp) {
str = cp;
} else {
php_error(E_WARNING, "Could not convert string from UTF-8");
}
}
ZVAL_STRING(*value, (char *)str, 1);
if (free_cp) {
g_free(cp);
}
} else
ZVAL_NULL(*value);
}
break;
case G_TYPE_PARAM:
phpg_paramspec_new(value, g_value_get_param(gval) TSRMLS_CC);
break;
case G_TYPE_OBJECT:
phpg_gobject_new(value, g_value_get_object(gval) TSRMLS_CC);
break;
case G_TYPE_INTERFACE:
if (g_type_is_a(G_VALUE_TYPE(gval), G_TYPE_OBJECT)) {
phpg_gobject_new(value, g_value_get_object(gval) TSRMLS_CC);
} else {
php_error(E_WARNING, "Could not access interface %s", g_type_name(G_VALUE_TYPE(gval)));
MAKE_STD_ZVAL(*value);
ZVAL_NULL(*value);
return FAILURE;
}
break;
case G_TYPE_POINTER:
phpg_gpointer_new(value, G_VALUE_TYPE(gval), g_value_get_pointer(gval) TSRMLS_CC);
break;
case G_TYPE_BOXED:
{
phpg_gboxed_marshal_t *gbm;
if (G_VALUE_HOLDS(gval, G_TYPE_PHP_VALUE)) {
zval *object = (zval *) g_value_dup_boxed(gval);
MAKE_ZVAL_IF_NULL(*value);
ZVAL_NULL(*value);
if (object) {
REPLACE_ZVAL_VALUE(value, object, 1);
zval_ptr_dtor(&object);
return SUCCESS;
} else {
ZVAL_NULL(*value);
return FAILURE;
}
} else if (G_VALUE_HOLDS(gval, G_TYPE_VALUE_ARRAY)) {
int i;
zval *item;
int value_count;
GValueArray *array = (GValueArray *) g_value_get_boxed(gval);
MAKE_ZVAL_IF_NULL(*value);
array_init(*value);
value_count = array->n_values;
for (i = 0; i < value_count; i++) {
MAKE_STD_ZVAL(item);
phpg_gvalue_to_zval(array->values + i, &item, copy_boxed, TRUE TSRMLS_CC);
add_next_index_zval(*value, item);
}
} else if ((gbm = phpg_gboxed_lookup_custom(G_VALUE_TYPE(gval)))) {
MAKE_STD_ZVAL(*value);
return gbm->to_zval(gval, value TSRMLS_CC);
} else {
if (copy_boxed) {
phpg_gboxed_new(value, G_VALUE_TYPE(gval), g_value_get_boxed(gval), TRUE, TRUE TSRMLS_CC);
} else {
phpg_gboxed_new(value, G_VALUE_TYPE(gval), g_value_get_boxed(gval), FALSE, FALSE TSRMLS_CC);
}
}
break;
}
default:
php_error(E_WARNING, "PHP-GTK internal error: unsupported type %s", g_type_name(G_VALUE_TYPE(gval)));
MAKE_STD_ZVAL(*value);
ZVAL_NULL(*value);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_GTK_API phpg_gvalue_from_zval() */
PHP_GTK_API int phpg_gvalue_from_zval(GValue *gval, zval **value, zend_bool do_utf8 TSRMLS_DC)
{
switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(gval))) {
/*
* For whatever reason, we should apparently respect that the gval may be of these
* types and they do not need a value.
*/
case G_TYPE_INVALID:
case G_TYPE_NONE:
break;
case G_TYPE_BOOLEAN:
convert_to_boolean_ex(value);
g_value_set_boolean(gval, (gboolean)Z_BVAL_PP(value));
break;
case G_TYPE_CHAR:
convert_to_string_ex(value);
g_value_set_char(gval, Z_STRVAL_PP(value)[0]);
break;
case G_TYPE_UCHAR:
convert_to_string_ex(value);
g_value_set_uchar(gval, (guchar)Z_STRVAL_PP(value)[0]);
break;
case G_TYPE_INT:
convert_to_long_ex(value);
g_value_set_int(gval, (gint)Z_LVAL_PP(value));
break;
case G_TYPE_UINT:
convert_to_long_ex(value);
g_value_set_uint(gval, (guint)Z_LVAL_PP(value));
break;
case G_TYPE_LONG:
convert_to_long_ex(value);
g_value_set_long(gval, (glong)Z_LVAL_PP(value));
break;
case G_TYPE_ULONG:
convert_to_long_ex(value);
g_value_set_ulong(gval, (gulong)Z_LVAL_PP(value));
break;
case G_TYPE_FLOAT:
convert_to_double_ex(value);
g_value_set_float(gval, (gfloat)Z_DVAL_PP(value));
break;
case G_TYPE_DOUBLE:
convert_to_double_ex(value);
g_value_set_double(gval, Z_DVAL_PP(value));
break;
case G_TYPE_ENUM:
{
gint val = 0;
if (phpg_gvalue_get_enum(G_VALUE_TYPE(gval), *value, &val) == FAILURE) {
return FAILURE;
}
g_value_set_enum(gval, val);
break;
}
case G_TYPE_FLAGS:
{
gint val = 0;
if (phpg_gvalue_get_flags(G_VALUE_TYPE(gval), *value, &val) == FAILURE) {
return FAILURE;
}
g_value_set_flags(gval, val);
break;
}
case G_TYPE_STRING:
{
gchar *utf8 = NULL;
gsize utf8_len = 0;
zend_bool free_utf8 = 0;
gchar *str;
convert_to_string_ex(value);
str = Z_STRVAL_PP(value);
if (do_utf8) {
utf8 = phpg_to_utf8(Z_STRVAL_PP(value), Z_STRLEN_PP(value), &utf8_len, &free_utf8 TSRMLS_CC);
if (utf8) {
str = utf8;
} else {
php_error(E_WARNING, "Could not convert string to UTF-8");
}
}
g_value_set_string(gval, str);
if (free_utf8) {
g_free(utf8);
}
break;
}
case G_TYPE_POINTER:
if (Z_TYPE_PP(value) == IS_NULL) {
g_value_set_pointer(gval, NULL);
} else if (Z_TYPE_PP(value) == IS_OBJECT
&& instanceof_function(Z_OBJCE_PP(value), gpointer_ce TSRMLS_CC)
&& G_VALUE_HOLDS(gval, ((phpg_gpointer_t*)PHPG_GET(*value))->gtype)) {
g_value_set_pointer(gval, ((phpg_gpointer_t*)PHPG_GET(*value))->pointer);
} else {
return FAILURE;
}
break;
case G_TYPE_BOXED:
{
phpg_gboxed_marshal_t *gbm;
if (Z_TYPE_PP(value) == IS_NULL) {
g_value_set_boxed(gval, NULL);
/*
* We should be safe just setting the zval here, since G_TYPE_PHP_VALUE is
* supposed to take any zval type.
*/
} else if (G_VALUE_HOLDS(gval, G_TYPE_PHP_VALUE)) {
g_value_set_boxed(gval, *value);
} else if (Z_TYPE_PP(value) == IS_OBJECT
&& instanceof_function(Z_OBJCE_PP(value), gboxed_ce TSRMLS_CC)
&& G_VALUE_HOLDS(gval, ((phpg_gboxed_t*)PHPG_GET(*value))->gtype)) {
g_value_set_boxed(gval, PHPG_GBOXED(*value));
} else if ((gbm = phpg_gboxed_lookup_custom(G_VALUE_TYPE(gval)))) {
return gbm->from_zval(*value, gval TSRMLS_CC);
} else
return FAILURE;
break;
}
case G_TYPE_PARAM:
if (php_gtk_check_class(*value, gparamspec_ce)) {
g_value_set_param(gval, PHPG_GPARAMSPEC(*value));
} else {
return FAILURE;
}
break;
case G_TYPE_OBJECT:
if (Z_TYPE_PP(value) == IS_NULL) {
g_value_set_object(gval, NULL);
} else if (Z_TYPE_P(*value) == IS_OBJECT
&& instanceof_function(Z_OBJCE_PP(value), gobject_ce TSRMLS_CC)
&& G_TYPE_CHECK_INSTANCE_TYPE(PHPG_GOBJECT(*value), G_VALUE_TYPE(gval))) {
g_value_set_object(gval, PHPG_GOBJECT(*value));
} else
return FAILURE;
break;
case G_TYPE_INTERFACE:
if (g_type_is_a(G_VALUE_TYPE(gval), G_TYPE_OBJECT) &&
Z_TYPE_PP(value) == IS_OBJECT &&
G_TYPE_CHECK_INSTANCE_TYPE(PHPG_GOBJECT(*value), G_VALUE_TYPE(gval))) {
g_value_set_object(gval, PHPG_GOBJECT(*value));
} else {
php_error(E_WARNING, "Could not access interface %s", g_type_name(G_VALUE_TYPE(gval)));
return FAILURE;
}
break;
default:
php_error(E_WARNING, "PHP-GTK internal error: unsupported type %s", g_type_name(G_VALUE_TYPE(gval)));
return FAILURE;
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_GTK_API phpg_param_gvalue_to_zval() */
PHP_GTK_API int phpg_param_gvalue_to_zval(const GValue *gval, zval **value, zend_bool copy_boxed, const GParamSpec *pspec TSRMLS_DC)
{
if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
/* TODO */
return FAILURE;
} else {
return phpg_gvalue_to_zval(gval, value, copy_boxed, TRUE TSRMLS_CC);
}
}
/* }}} */
/* {{{ PHP_GTK_API phpg_param_gvalue_from_zval() */
PHP_GTK_API int phpg_param_gvalue_from_zval(GValue *gval, zval **value, const GParamSpec *pspec TSRMLS_DC)
{
if (G_IS_PARAM_SPEC_UNICHAR(pspec)) {
/* TODO */
return FAILURE;
} else {
return phpg_gvalue_from_zval(gval, value, TRUE TSRMLS_CC);
}
}
/* }}} */
/* {{{ PHP_GTK_API phpg_gvalues_to_array() */
PHP_GTK_API zval *phpg_gvalues_to_array(const GValue *values, uint n_values)
{
zval *hash;
zval *item = NULL;
int i;
int value_count;
MAKE_STD_ZVAL(hash);
array_init(hash);
value_count = n_values;
for (i = 0; i < value_count; i++) {
//item = phpg_gvalue_to_zval(&values[i], FALSE);
if (!item) {
MAKE_STD_ZVAL(item);
ZVAL_NULL(item);
}
zend_hash_next_index_insert(Z_ARRVAL_P(hash), &item, sizeof(zval *), NULL);
}
return hash;
}
/* }}} */
/* {{{ PHP_GTK_API phpg_gvalue_get_enum() */
PHP_GTK_API int phpg_gvalue_get_enum(GType enum_type, zval *enum_val, gint *result)
{
if (result == NULL)
return FAILURE;
if (enum_val == NULL) {
*result = 0;
} else if (Z_TYPE_P(enum_val) == IS_LONG) {
*result = Z_LVAL_P(enum_val);
} else if (Z_TYPE_P(enum_val) == IS_STRING) {
GEnumClass *eclass = NULL;
GEnumValue *info = NULL;
if (enum_type != G_TYPE_NONE) {
eclass = G_ENUM_CLASS(g_type_class_ref(enum_type));
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of enum");
return FAILURE;
}
info = g_enum_get_value_by_name(eclass, Z_STRVAL_P(enum_val));
if (info == NULL) {
info = g_enum_get_value_by_nick(eclass, Z_STRVAL_P(enum_val));
}
g_type_class_unref(eclass);
if (info != NULL) {
*result = info->value;
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to enum", Z_STRVAL_P(enum_val));
return FAILURE;
}
} else {
php_error(E_WARNING, "PHP-GTK internal error: enums must be strings or integers");
return FAILURE;
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_GTK_API phpg_gvalue_get_flags() */
PHP_GTK_API int phpg_gvalue_get_flags(GType flags_type, zval *flags_val, gint *result)
{
GFlagsClass *fclass = NULL;
GFlagsValue *info = NULL;
if (result == NULL)
return FAILURE;
if (flags_val == NULL) {
*result = 0;
} else if (Z_TYPE_P(flags_val) == IS_LONG) {
*result = Z_LVAL_P(flags_val);
} else if (Z_TYPE_P(flags_val) == IS_STRING) {
if (flags_type != G_TYPE_NONE) {
fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type));
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of flags");
return FAILURE;
}
info = g_flags_get_value_by_name(fclass, Z_STRVAL_P(flags_val));
if (info == NULL) {
info = g_flags_get_value_by_nick(fclass, Z_STRVAL_P(flags_val));
}
g_type_class_unref(fclass);
if (info != NULL) {
*result = info->value;
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to flags", Z_STRVAL_P(flags_val));
return FAILURE;
}
} else if (Z_TYPE_P(flags_val) == IS_ARRAY) {
zval **flag;
*result = 0;
if (flags_type != G_TYPE_NONE) {
fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type));
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not obtain the type of flags");
return FAILURE;
}
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(flags_val));
zend_hash_get_current_data(Z_ARRVAL_P(flags_val), (void **)&flag) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(flags_val))) {
if (Z_TYPE_PP(flag) == IS_LONG) {
*result |= Z_LVAL_PP(flag);
} else if (Z_TYPE_PP(flag) == IS_STRING) {
info = g_flags_get_value_by_name(fclass, Z_STRVAL_PP(flag));
if (info == NULL) {
info = g_flags_get_value_by_nick(fclass, Z_STRVAL_PP(flag));
}
if (info != NULL) {
*result |= info->value;
} else {
php_error(E_WARNING, "PHP-GTK internal error: could not convert '%s' to flags", Z_STRVAL_PP(flag));
g_type_class_unref(fclass);
return FAILURE;
}
} else {
php_error(E_WARNING, "PHP-GTK flag arrays can contain only integers or strings");
g_type_class_unref(fclass);
return 0;
}
}
g_type_class_unref(fclass);
} else {
php_error(E_WARNING, "PHP-GTK flags must be strings, integers, or arrays of strings or integers");
return FAILURE;
}
return SUCCESS;
}
/* }}} */
#endif
/* vim: set fdm=marker et : */