static void rb_gi_argument_from_ruby_array(GIArgument *argument, GITypeInfo *type_info, VALUE rb_argument) { GIArrayType array_type; GITypeInfo *element_type_info; array_type = g_type_info_get_array_type(type_info); element_type_info = g_type_info_get_param_type(type_info, 0); switch (array_type) { case GI_ARRAY_TYPE_C: rb_gi_argument_from_ruby_array_c(argument, type_info, element_type_info, rb_argument); break; case GI_ARRAY_TYPE_ARRAY: case GI_ARRAY_TYPE_PTR_ARRAY: case GI_ARRAY_TYPE_BYTE_ARRAY: /* TODO */ break; default: g_assert_not_reached(); break; } g_base_info_unref(element_type_info); }
/* Marshalls GSList or GList from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_list (lua_State *L, GITypeInfo *ti, GITypeTag list_tag, gpointer *list, int narg, GITransfer transfer) { GITypeInfo *eti; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gint index, vals = 0, to_pop, eti_guard; GSList **guard = NULL; /* Allow empty list to be expressed also as 'nil', because in C, there is no difference between NULL and empty list. */ if (lua_isnoneornil (L, narg)) index = 0; else { luaL_checktype (L, narg, LUA_TTABLE); index = lua_objlen (L, narg); } /* Get list element type info, create guard for it so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); /* Go from back and prepend to the list, which is cheaper than appending. */ guard = (GSList **) lgi_guard_create (L, list_tag == GI_TYPE_TAG_GSLIST ? (GDestroyNotify) g_slist_free : (GDestroyNotify) g_list_free); while (index > 0) { /* Retrieve index-th element from the source table and marshall it as pointer to arg. */ GIArgument eval; lua_pushnumber (L, index--); lua_gettable (L, narg); to_pop = lgi_marshal_2c (L, eti, NULL, exfer, &eval, -1, LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Prepend new list element and reassign the guard. */ if (list_tag == GI_TYPE_TAG_GSLIST) *guard = g_slist_prepend (*guard, eval.v_pointer); else *guard = (GSList *) g_list_prepend ((GList *) *guard, eval.v_pointer); lua_remove (L, - to_pop - 1); vals += to_pop; } /* Marshalled value is kept inside the guard. */ *list = *guard; lua_remove (L, eti_guard); return vals; }
static void marshal_2lua_hash (lua_State *L, GITypeInfo *ti, GIDirection dir, GITransfer xfer, GHashTable *hash_table) { GHashTableIter iter; GITypeInfo *eti[2]; gint i, guard; GIArgument eval[2]; /* Check for 'NULL' table, represent it simply as nil. */ if (hash_table == NULL) lua_pushnil (L); else { /* Get key and value type infos, guard them so that we don't leak it. */ guard = lua_gettop (L) + 1; for (i = 0; i < 2; i++) { eti[i] = g_type_info_get_param_type (ti, i); lgi_gi_info_new (L, eti[i]); } /* Create table to which we will deserialize the hashtable. */ lua_newtable (L); /* Go through the hashtable and push elements into the table. */ g_hash_table_iter_init (&iter, hash_table); while (g_hash_table_iter_next (&iter, &eval[0].v_pointer, &eval[1].v_pointer)) { /* Marshal key and value to the stack. */ for (i = 0; i < 2; i++) lgi_marshal_2lua (L, eti[i], NULL, dir, GI_TRANSFER_NOTHING, &eval[i], LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Store these two elements to the table. */ lua_settable (L, -3); } /* Free the table, if requested. */ if (xfer != GI_TRANSFER_NOTHING) g_hash_table_unref (hash_table); lua_remove (L, guard); lua_remove (L, guard); } }
static int marshal_2lua_list (lua_State *L, GITypeInfo *ti, GIDirection dir, GITypeTag list_tag, GITransfer xfer, gpointer list) { GSList *i; GITypeInfo *eti; gint index, eti_guard; /* Get element type info, guard it so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); /* Create table to which we will deserialize the list. */ lua_newtable (L); /* Go through the list and push elements into the table. */ for (i = list, index = 0; i != NULL; i = g_slist_next (i)) { /* Get access to list item. */ GIArgument *eval = (GIArgument *) &i->data; /* Store it into the table. */ lgi_marshal_2lua (L, eti, NULL, dir, (xfer == GI_TRANSFER_EVERYTHING) ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, eval, LGI_PARENT_FORCE_POINTER, NULL, NULL); lua_rawseti(L, -2, ++index); } /* Free the list, if we got its ownership. */ if (xfer != GI_TRANSFER_NOTHING) { if (list_tag == GI_TYPE_TAG_GSLIST) g_slist_free (list); else g_list_free (list); } lua_remove (L, eti_guard); return 1; }
void gy_value_push(GValue * pval, GITypeInfo * info, gy_Object* o) { GITypeTag tag = g_type_info_get_tag(info); GY_DEBUG("Pushing %s from GValue\n", g_type_tag_to_string(tag)); switch (tag) { /* basic types */ case GI_TYPE_TAG_VOID:{ GITypeInfo * cellinfo = g_type_info_get_param_type(info, 0); if (cellinfo) { GITypeTag ctag = g_type_info_get_tag(cellinfo); GY_DEBUG("void contains %s\n", g_type_tag_to_string(ctag)); g_base_info_unref(cellinfo); } ypush_nil(); break;} case GI_TYPE_TAG_BOOLEAN: *ypush_c(NULL) = g_value_get_boolean(pval); break; case GI_TYPE_TAG_INT8: *ypush_gint8(NULL) = g_value_get_schar(pval); break; case GI_TYPE_TAG_UINT8: *ypush_guint8(NULL)= g_value_get_uchar(pval); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_INT32: *ypush_gint32(NULL) = g_value_get_int(pval); break; case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_UINT32: *ypush_guint32(NULL) = g_value_get_uint(pval); break; case GI_TYPE_TAG_INT64: ypush_long(g_value_get_int64(pval)); break; case GI_TYPE_TAG_UINT64: ypush_long(g_value_get_uint64(pval)); break; case GI_TYPE_TAG_FLOAT: *ypush_f(NULL)=g_value_get_float(pval); break; case GI_TYPE_TAG_DOUBLE: ypush_double(g_value_get_double(pval)); break; case GI_TYPE_TAG_GTYPE: ypush_long(g_value_get_gtype(pval)); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: *ypush_q(NULL) = p_strcpy(g_value_get_string(pval)); break; /* array types */ case GI_TYPE_TAG_ARRAY: y_error("array"); break; /* interface types */ case GI_TYPE_TAG_INTERFACE: { GIBaseInfo * itrf = g_type_info_get_interface (info); switch(g_base_info_get_type (itrf)) { case GI_INFO_TYPE_ENUM: ypush_long(g_value_get_enum(pval)); g_base_info_unref(itrf); break; case GI_INFO_TYPE_OBJECT: { GObject * prop=g_value_get_object(pval); g_object_ref_sink(prop); if (!prop) { g_base_info_unref(itrf); y_error("get property failed"); } GY_DEBUG("pushing result... "); ypush_check(1); gy_Object * out = ypush_gy_Object(); out->info=itrf; out->object=prop; out->repo=o->repo; } break; default: g_base_info_unref(itrf); y_error ("fix me: only properties of type object supported yet"); } break; } default: y_error("Unimplemented"); } }
static gboolean type_can_be_allocated_directly(GITypeInfo *type_info) { gboolean is_simple = TRUE; if (g_type_info_is_pointer(type_info)) { if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY && g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { GITypeInfo *param_info; param_info = g_type_info_get_param_type(type_info, 0); is_simple = type_can_be_allocated_directly(param_info); g_base_info_unref((GIBaseInfo*)param_info); } else { is_simple = FALSE; } } else { switch (g_type_info_get_tag(type_info)) { case GI_TYPE_TAG_BOOLEAN: case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: case GI_TYPE_TAG_UNICHAR: break; case GI_TYPE_TAG_VOID: case GI_TYPE_TAG_GTYPE: case GI_TYPE_TAG_ERROR: case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_ARRAY: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface = g_type_info_get_interface(type_info); switch (g_base_info_get_type(interface)) { case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: if (!struct_is_simple((GIStructInfo *)interface)) is_simple = FALSE; break; case GI_INFO_TYPE_UNION: /* FIXME: Need to implement */ is_simple = FALSE; break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: break; case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_CALLBACK: case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: is_simple = FALSE; break; case GI_INFO_TYPE_INVALID_0: g_assert_not_reached(); break; } g_base_info_unref(interface); break; } } } return is_simple; }
/* Marshalls hashtable from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_hash (lua_State *L, GITypeInfo *ti, GHashTable **table, int narg, gboolean optional, GITransfer transfer) { GITypeInfo *eti[2]; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gint i, vals = 0, guard; GHashTable **guarded_table; GHashFunc hash_func; GEqualFunc equal_func; /* Represent nil as NULL table. */ if (optional && lua_isnoneornil (L, narg)) *table = NULL; else { /* Check the type; we allow tables only. */ luaL_checktype (L, narg, LUA_TTABLE); /* Get element type infos, create guard for it. */ guard = lua_gettop (L) + 1; for (i = 0; i < 2; i++) { eti[i] = g_type_info_get_param_type (ti, i); lgi_gi_info_new (L, eti[i]); } /* Create the hashtable and guard it so that it is destroyed in case something goes wrong during marshalling. */ guarded_table = (GHashTable **) lgi_guard_create (L, (GDestroyNotify) g_hash_table_destroy); vals++; /* Find out which hash_func and equal_func should be used, according to the type of the key. */ switch (g_type_info_get_tag (eti[0])) { case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: hash_func = g_str_hash; equal_func = g_str_equal; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: hash_func = g_int64_hash; equal_func = g_int64_equal; break; case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: return luaL_error (L, "hashtable with float or double is not " "supported"); default: /* For everything else, use direct hash of stored pointer. */ hash_func = NULL; equal_func = NULL; } *guarded_table = *table = g_hash_table_new (hash_func, equal_func); /* Iterate through Lua table and fill hashtable. */ lua_pushnil (L); while (lua_next (L, narg)) { GIArgument eval[2]; int key_pos = lua_gettop (L) - 1; /* Marshal key and value from the table. */ for (i = 0; i < 2; i++) vals += lgi_marshal_2c (L, eti[i], NULL, exfer, &eval[i], key_pos + i, LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Insert newly marshalled pointers into the table. */ g_hash_table_insert (*table, eval[0].v_pointer, eval[1].v_pointer); /* The great stack suffle; remove value completely and leave key on the top of the stack. Complicated by the fact that both are burried under key_pop + val_pop elements created by marshalling. */ lua_remove (L, key_pos + 1); lua_pushvalue (L, key_pos); lua_remove (L, key_pos); } /* Remove guards for element types. */ lua_remove (L, guard); lua_remove (L, guard); } return vals; }
/* Marshalls array from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_array (lua_State *L, GITypeInfo *ti, GIArrayType atype, gpointer *out_array, gssize *out_size, int narg, gboolean optional, GITransfer transfer) { GITypeInfo* eti; gssize objlen, esize; gint index, vals = 0, to_pop, eti_guard; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gboolean zero_terminated; GArray *array = NULL; /* Represent nil as NULL array. */ if (optional && lua_isnoneornil (L, narg)) { *out_size = 0; *out_array = NULL; } else { /* Get element type info, create guard for it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); esize = array_get_elt_size (eti); /* Check the type. If this is C-array of byte-sized elements, we can try special-case and accept strings or buffers. */ *out_array = NULL; if (lua_type (L, narg) != LUA_TTABLE && esize == 1 && atype == GI_ARRAY_TYPE_C) { size_t size = 0; *out_array = lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (*out_array) size = lua_objlen (L, narg); else *out_array = (gpointer *) lua_tolstring (L, narg, &size); if (transfer != GI_TRANSFER_NOTHING) *out_array = g_memdup (*out_array, size); *out_size = size; } if (!*out_array) { /* Otherwise, we allow only tables. */ luaL_checktype (L, narg, LUA_TTABLE); /* Find out how long array should we allocate. */ zero_terminated = g_type_info_is_zero_terminated (ti); objlen = lua_objlen (L, narg); *out_size = g_type_info_get_array_fixed_size (ti); if (atype != GI_ARRAY_TYPE_C || *out_size < 0) *out_size = objlen; else if (*out_size < objlen) objlen = *out_size; /* Allocate the array and wrap it into the userdata guard, if needed. */ if (*out_size > 0 || zero_terminated) { array = g_array_sized_new (zero_terminated, TRUE, esize, *out_size); g_array_set_size (array, *out_size); *lgi_guard_create (L, (GDestroyNotify) (transfer == GI_TRANSFER_EVERYTHING ? array_detach : g_array_unref)) = array; vals = 1; } /* Iterate through Lua array and fill GArray accordingly. */ for (index = 0; index < objlen; index++) { lua_pushnumber (L, index + 1); lua_gettable (L, narg); /* Marshal element retrieved from the table into target array. */ to_pop = lgi_marshal_2c (L, eti, NULL, exfer, array->data + index * esize, -1, 0, NULL, NULL); /* Remove temporary element from the stack. */ lua_remove (L, - to_pop - 1); /* Remember that some more temp elements could be pushed. */ vals += to_pop; } /* Return either GArray or direct pointer to the data, according to the array type. */ *out_array = (atype == GI_ARRAY_TYPE_ARRAY || array == NULL) ? (void *) array : (void *) array->data; } lua_remove (L, eti_guard); } return vals; }
static void marshal_2lua_array (lua_State *L, GITypeInfo *ti, GIDirection dir, GIArrayType atype, GITransfer transfer, gpointer array, gssize size, int parent) { GITypeInfo *eti; gssize len = 0, esize; gint index, eti_guard; char *data = NULL; /* Avoid propagating return value marshaling flag to array elements. */ if (parent == LGI_PARENT_IS_RETVAL) parent = 0; /* First of all, find out the length of the array. */ if (atype == GI_ARRAY_TYPE_ARRAY) { if (array) { len = ((GArray *) array)->len; data = ((GArray *) array)->data; } } else { data = array; if (g_type_info_is_zero_terminated (ti)) len = -1; else { len = g_type_info_get_array_fixed_size (ti); if (len == -1) /* Length of the array is dynamic, get it from other argument. */ len = size; } } /* Get array element type info, wrap it in the guard so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); esize = array_get_elt_size (eti); /* Note that we ignore is_pointer check for uint8 type. Although it is not exactly correct, we probably would not handle uint8* correctly anyway, this is strange type to use, and moreover this is workaround for g-ir-scanner bug which might mark elements of uint8 arrays as gconstpointer, thus setting is_pointer=true on it. See https://github.com/pavouk/lgi/issues/57 */ if (g_type_info_get_tag (eti) == GI_TYPE_TAG_UINT8) { /* UINT8 arrays are marshalled as Lua strings. */ if (len < 0) len = data ? strlen(data) : 0; lua_pushlstring (L, data, len); } else { if (array == NULL) { /* NULL array is represented by empty table for C arrays, nil for other types. */ if (atype == GI_ARRAY_TYPE_C) lua_newtable (L); else lua_pushnil (L); lua_remove (L, eti_guard); return; } /* Create Lua table which will hold the array. */ lua_createtable (L, len > 0 ? len : 0, 0); /* Iterate through array elements. */ for (index = 0; len < 0 || index < len; index++) { /* Get value from specified index. */ GIArgument *eval = (GIArgument *) (data + index * esize); /* If the array is zero-terminated, terminate now and don't include NULL entry. */ if (len < 0 && eval->v_pointer == NULL) break; /* Store value into the table. */ lgi_marshal_2lua (L, eti, NULL, dir, (transfer == GI_TRANSFER_EVERYTHING) ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, eval, parent, NULL, NULL); lua_rawseti (L, -2, index + 1); } } /* If needed, free the original array. */ if (transfer != GI_TRANSFER_NOTHING) { if (atype == GI_ARRAY_TYPE_ARRAY) g_array_free (array, TRUE); else g_free (array); } lua_remove (L, eti_guard); }
static gpointer sv_to_ghash (GITransfer transfer, GITypeInfo *type_info, SV *sv) { HV *hv; HE *he; GITransfer item_transfer; gpointer hash; GITypeInfo *key_param_info, *value_param_info; GITypeTag key_type_tag; GHashFunc hash_func; GEqualFunc equal_func; I32 n_keys; dwarn ("%s: sv %p\n", G_STRFUNC, sv); if (!gperl_sv_is_defined (sv)) return NULL; if (!gperl_sv_is_hash_ref (sv)) ccroak ("need an hash ref to convert to GHashTable"); hv = (HV *) SvRV (sv); item_transfer = GI_TRANSFER_NOTHING; switch (transfer) { case GI_TRANSFER_EVERYTHING: item_transfer = GI_TRANSFER_EVERYTHING; break; case GI_TRANSFER_CONTAINER: /* nothing special to do */ break; case GI_TRANSFER_NOTHING: /* FIXME: need to free hash after call */ break; } key_param_info = g_type_info_get_param_type (type_info, 0); value_param_info = g_type_info_get_param_type (type_info, 1); key_type_tag = g_type_info_get_tag (key_param_info); switch (key_type_tag) { case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_UTF8: hash_func = g_str_hash; equal_func = g_str_equal; break; default: hash_func = NULL; equal_func = NULL; break; } dwarn (" GHashTable with transfer %d\n" " key_param_info %p with type tag %d (%s)\n" " value_param_info %p with type tag %d (%s)\n", transfer, key_param_info, g_type_info_get_tag (key_param_info), g_type_tag_to_string (g_type_info_get_tag (key_param_info)), value_param_info, g_type_info_get_tag (value_param_info), g_type_tag_to_string (g_type_info_get_tag (value_param_info))); hash = g_hash_table_new (hash_func, equal_func); n_keys = hv_iterinit (hv); if (n_keys == 0) goto out; while ((he = hv_iternext (hv)) != NULL) { SV *sv; GIArgument arg = { 0, }; gpointer key_p, value_p; key_p = value_p = NULL; sv = hv_iterkeysv (he); if (sv && gperl_sv_is_defined (sv)) { dwarn (" converting key SV %p\n", sv); /* FIXME: Is it OK to always allow undef here? */ sv_to_arg (sv, &arg, NULL, key_param_info, item_transfer, TRUE, NULL); key_p = arg.v_pointer; } sv = hv_iterval (hv, he); if (sv && gperl_sv_is_defined (sv)) { dwarn (" converting value SV %p\n", sv); sv_to_arg (sv, &arg, NULL, key_param_info, item_transfer, TRUE, NULL); value_p = arg.v_pointer; } if (key_p != NULL && value_p != NULL) g_hash_table_insert (hash, key_p, value_p); } out: dwarn (" -> hash %p of size %d\n", hash, g_hash_table_size (hash)); g_base_info_unref ((GIBaseInfo *) key_param_info); g_base_info_unref ((GIBaseInfo *) value_param_info); return hash; }
gboolean lgi_marshal_2c_caller_alloc (lua_State *L, GITypeInfo *ti, GIArgument *val, int pos) { gboolean handled = FALSE; switch (g_type_info_get_tag (ti)) { case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *ii = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (ii); if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_UNION) { if (pos == 0) { lgi_type_get_repotype (L, G_TYPE_INVALID, ii); val->v_pointer = lgi_record_new (L, 1, FALSE); } handled = TRUE; } g_base_info_unref (ii); break; } case GI_TYPE_TAG_ARRAY: { if (g_type_info_get_array_type (ti) == GI_ARRAY_TYPE_C) { gpointer *array_guard; if (pos == 0) { gssize elt_size, size; /* Currently only fixed-size arrays are supported. */ elt_size = array_get_elt_size (g_type_info_get_param_type (ti, 0)); size = g_type_info_get_array_fixed_size (ti); g_assert (size > 0); /* Allocate underlying array. It is temporary, existing only for the duration of the call. */ array_guard = lgi_guard_create (L, (GDestroyNotify) g_array_unref); *array_guard = g_array_sized_new (FALSE, FALSE, elt_size, size); g_array_set_size (*array_guard, size); } else { /* Convert the allocated array into Lua table with contents. We have to do it in-place. */ /* Make sure that pos is absolute, so that stack shuffling below does not change the element it points to. */ if (pos < 0) pos += lua_gettop (L) + 1; /* Get GArray from the guard and unmarshal it as a full GArray into Lua. */ array_guard = lua_touserdata (L, pos); marshal_2lua_array (L, ti, GI_DIRECTION_OUT, GI_ARRAY_TYPE_ARRAY, GI_TRANSFER_EVERYTHING, *array_guard, -1, pos); /* Deactivate old guard, everything was marshalled into the newly created and marshalled table. */ *array_guard = NULL; /* Switch old value with the new data. */ lua_replace (L, pos); } handled = TRUE; } break; } default: break; } return handled; }
static SV * ghash_to_sv (GITypeInfo *info, gpointer pointer, GITransfer transfer) { GITypeInfo *key_param_info, *value_param_info; #ifdef NOISY GITypeTag key_type_tag, value_type_tag; #endif gpointer key_p, value_p; GITransfer item_transfer; GHashTableIter iter; HV *hv; if (pointer == NULL) { return &PL_sv_undef; } item_transfer = transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING; key_param_info = g_type_info_get_param_type (info, 0); value_param_info = g_type_info_get_param_type (info, 1); #ifdef NOISY key_type_tag = g_type_info_get_tag (key_param_info); value_type_tag = g_type_info_get_tag (value_param_info); #endif dwarn (" GHashTable: pointer %p\n" " key type tag %d (%s)\n" " value type tag %d (%s)\n", pointer, key_type_tag, g_type_tag_to_string (key_type_tag), value_type_tag, g_type_tag_to_string (value_type_tag)); hv = newHV (); g_hash_table_iter_init (&iter, pointer); while (g_hash_table_iter_next (&iter, &key_p, &value_p)) { GIArgument arg = { 0, }; SV *key_sv, *value_sv; dwarn (" converting key pointer %p\n", key_p); arg.v_pointer = key_p; key_sv = arg_to_sv (&arg, key_param_info, item_transfer, NULL); if (key_sv == NULL) break; dwarn (" converting value pointer %p\n", value_p); arg.v_pointer = value_p; value_sv = arg_to_sv (&arg, value_param_info, item_transfer, NULL); if (value_sv == NULL) break; (void) hv_store_ent (hv, key_sv, value_sv, 0); } g_base_info_unref ((GIBaseInfo *) key_param_info); g_base_info_unref ((GIBaseInfo *) value_param_info); return newRV_noinc ((SV *) hv); }
void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction) { GITypeTag type_tag; gboolean is_out = (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT); type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_VOID: /* Don't do anything, it's transparent to the C side */ break; case GI_TYPE_TAG_BOOLEAN: case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: case GI_TYPE_TAG_GTYPE: case GI_TYPE_TAG_UNICHAR: break; case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_UTF8: /* With allow-none support the string could be NULL */ if ((arg->v_string != NULL && (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_free (arg->v_string); } break; case GI_TYPE_TAG_ARRAY: { GArray *array; gsize i; if (arg->v_pointer == NULL) { return; } array = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; item_type_info = g_type_info_get_param_type (type_info, 0); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (i = 0; i < array->len; i++) { GIArgument *item; item = &_g_array_index (array, GIArgument, i); _pygi_argument_release (item, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_array_free (array, TRUE); } break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: /* TODO */ break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { GType type; if (arg->v_pointer == NULL) { return; } type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (g_type_is_a (type, G_TYPE_VALUE)) { GValue *value; value = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_value_unset (value); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_slice_free (GValue, value); } } else if (g_type_is_a (type, G_TYPE_CLOSURE)) { if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { g_closure_unref (arg->v_pointer); } } else if (info_type == GI_INFO_TYPE_STRUCT && g_struct_info_is_foreign ((GIStructInfo*) info)) { if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { pygi_struct_foreign_release (info, arg->v_pointer); } } else if (g_type_is_a (type, G_TYPE_BOXED)) { } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) { g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING); } break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: if (arg->v_pointer == NULL) { return; } if (is_out && transfer == GI_TRANSFER_EVERYTHING) { g_object_unref (arg->v_pointer); } break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; if (arg->v_pointer == NULL) { return; } list = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; GSList *item; item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (item = list; item != NULL; item = g_slist_next (item)) { _pygi_argument_release ( (GIArgument *) &item->data, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { if (type_tag == GI_TYPE_TAG_GLIST) { g_list_free ( (GList *) list); } else { /* type_tag == GI_TYPE_TAG_GSLIST */ g_slist_free (list); } } break; } case GI_TYPE_TAG_GHASH: { GHashTable *hash_table; if (arg->v_pointer == NULL) { return; } hash_table = arg->v_pointer; if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) { /* We created the table without a destroy function, so keys and * values need to be released. */ GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; gpointer key; gpointer value; key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); if (direction == GI_DIRECTION_IN) { item_transfer = GI_TRANSFER_NOTHING; } else { item_transfer = GI_TRANSFER_EVERYTHING; } g_hash_table_iter_init (&hash_table_iter, hash_table); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { _pygi_argument_release ( (GIArgument *) &key, key_type_info, item_transfer, direction); _pygi_argument_release ( (GIArgument *) &value, value_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) { /* Be careful to avoid keys and values being freed if the * callee gave a destroy function. */ g_hash_table_steal_all (hash_table); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_hash_table_unref (hash_table); } break; } case GI_TYPE_TAG_ERROR: { GError *error; if (arg->v_pointer == NULL) { return; } error = * (GError **) arg->v_pointer; if (error != NULL) { g_error_free (error); } g_slice_free (GError *, arg->v_pointer); break; } } }
/** * _pygi_argument_to_object: * @arg: The argument to convert to an object. * @type_info: Type info for @arg * @transfer: * * If the argument is of type array, it must be encoded in a GArray, by calling * _pygi_argument_to_array(). This logic can not be folded into this method * as determining array lengths may require access to method call arguments. * * Returns: A PyObject representing @arg */ PyObject * _pygi_argument_to_object (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer) { GITypeTag type_tag; PyObject *object = NULL; type_tag = g_type_info_get_tag (type_info); object = _pygi_marshal_to_py_basic_type (arg, type_tag, transfer); if (object) return object; switch (type_tag) { case GI_TYPE_TAG_VOID: { if (g_type_info_is_pointer (type_info)) { g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); object = PyLong_FromVoidPtr (arg->v_pointer); } break; } case GI_TYPE_TAG_ARRAY: { /* Arrays are assumed to be packed in a GArray */ GArray *array; GITypeInfo *item_type_info; GITypeTag item_type_tag; GITransfer item_transfer; gsize i, item_size; if (arg->v_pointer == NULL) return PyList_New (0); item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_type_tag = g_type_info_get_tag (item_type_info); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; array = arg->v_pointer; item_size = g_array_get_element_size (array); if (G_UNLIKELY (item_size > sizeof(GIArgument))) { g_critical ("Stack overflow protection. " "Can't copy array element into GIArgument."); return PyList_New (0); } if (item_type_tag == GI_TYPE_TAG_UINT8) { /* Return as a byte array */ object = PYGLIB_PyBytes_FromStringAndSize (array->data, array->len); } else { object = PyList_New (array->len); if (object == NULL) { g_critical ("Failure to allocate array for %u items", array->len); g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } for (i = 0; i < array->len; i++) { GIArgument item = { 0 }; PyObject *py_item; memcpy (&item, array->data + i * item_size, item_size); py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } } g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: { g_assert_not_reached(); } case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { PyObject *py_type; GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); /* Special case variant and none to force loading from py module. */ if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) { py_type = _pygi_type_import_by_gi_info (info); } else { py_type = _pygi_type_get_from_g_type (g_type); } object = pygi_arg_struct_to_py_marshal (arg, info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*is_allocated*/ is_foreign); Py_XDECREF (py_type); break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { GType type; type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (type == G_TYPE_NONE) { /* An enum with a GType of None is an enum without GType */ PyObject *py_type = _pygi_type_import_by_gi_info (info); PyObject *py_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_int)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } object = PyObject_CallFunction (py_type, "i", arg->v_int); Py_DECREF (py_args); Py_DECREF (py_type); } else if (info_type == GI_INFO_TYPE_ENUM) { object = pyg_enum_from_gtype (type, arg->v_int); } else { object = pyg_flags_from_gtype (type, arg->v_uint); } break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: object = pygi_arg_gobject_to_py_called_from_c (arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; gsize length; GITypeInfo *item_type_info; GITransfer item_transfer; gsize i; list = arg->v_pointer; length = g_slist_length (list); object = PyList_New (length); if (object == NULL) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; list != NULL; list = g_slist_next (list), i++) { GIArgument item; PyObject *py_item; item.v_pointer = list->data; py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_GHASH: { GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; GIArgument key; GIArgument value; if (arg->v_pointer == NULL) { object = Py_None; Py_INCREF (object); break; } object = PyDict_New(); if (object == NULL) { break; } key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); g_assert (g_type_info_get_tag (key_type_info) != GI_TYPE_TAG_VOID); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); g_assert (g_type_info_get_tag (value_type_info) != GI_TYPE_TAG_VOID); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; g_hash_table_iter_init (&hash_table_iter, (GHashTable *) arg->v_pointer); while (g_hash_table_iter_next (&hash_table_iter, &key.v_pointer, &value.v_pointer)) { PyObject *py_key; PyObject *py_value; int retval; py_key = _pygi_argument_to_object (&key, key_type_info, item_transfer); if (py_key == NULL) { break; } _pygi_hash_pointer_to_arg (&value, g_type_info_get_tag (value_type_info)); py_value = _pygi_argument_to_object (&value, value_type_info, item_transfer); if (py_value == NULL) { Py_DECREF (py_key); break; } retval = PyDict_SetItem (object, py_key, py_value); Py_DECREF (py_key); Py_DECREF (py_value); if (retval < 0) { Py_CLEAR (object); break; } } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); break; } case GI_TYPE_TAG_ERROR: { GError *error = (GError *) arg->v_pointer; if (error != NULL && transfer == GI_TRANSFER_NOTHING) { /* If we have not been transferred the ownership we must copy * the error, because pygi_error_check() is going to free it. */ error = g_error_copy (error); } if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; PyErr_Fetch (&err_type, &err_value, &err_trace); Py_XDECREF (err_type); Py_XDECREF (err_trace); object = err_value; } else { object = Py_None; Py_INCREF (object); break; } break; } default: { g_assert_not_reached(); } } return object; }
GIArgument _pygi_argument_from_object (PyObject *object, GITypeInfo *type_info, GITransfer transfer) { GIArgument arg; GITypeTag type_tag; gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); /* Ignores cleanup data for now. */ if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data) || PyErr_Occurred()) { return arg; } switch (type_tag) { case GI_TYPE_TAG_ARRAY: { Py_ssize_t length; gboolean is_zero_terminated; GITypeInfo *item_type_info; gsize item_size; GArray *array; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } /* Note, strings are sequences, but we cannot accept them here */ if (!PySequence_Check (object) || #if PY_VERSION_HEX < 0x03000000 PyString_Check (object) || #endif PyUnicode_Check (object)) { PyErr_SetString (PyExc_TypeError, "expected sequence"); break; } length = PySequence_Length (object); if (length < 0) { break; } is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_type_info = g_type_info_get_param_type (type_info, 0); /* we handle arrays that are really strings specially, see below */ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8) item_size = 1; else item_size = sizeof (GIArgument); array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length); if (array == NULL) { g_base_info_unref ( (GIBaseInfo *) item_type_info); PyErr_NoMemory(); break; } if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 && PYGLIB_PyBytes_Check(object)) { memcpy(array->data, PYGLIB_PyBytes_AsString(object), length); array->len = length; goto array_success; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto array_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto array_item_error; } g_array_insert_val (array, i, item); continue; array_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &array, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); array = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } array_success: arg.v_pointer = array; g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: /* This should be handled in invoke() */ g_assert_not_reached(); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { GType g_type; PyObject *py_type; gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); /* Note for G_TYPE_VALUE g_type: * This will currently leak the GValue that is allocated and * stashed in arg.v_pointer. Out argument marshaling for caller * allocated GValues already pass in memory for the GValue. * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ pygi_arg_struct_from_py_marshal (object, &arg, NULL, /*arg_name*/ info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*copy_reference*/ is_foreign, g_type_info_is_pointer (type_info)); Py_DECREF (py_type); break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { PyObject *int_; int_ = PYGLIB_PyNumber_Long (object); if (int_ == NULL) { break; } arg.v_int = PYGLIB_PyLong_AsLong (int_); Py_DECREF (int_); break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: /* An error within this call will result in a NULL arg */ pygi_arg_gobject_out_arg_from_py (object, &arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { Py_ssize_t length; GITypeInfo *item_type_info; GSList *list = NULL; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PySequence_Length (object); if (length < 0) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = length - 1; i >= 0; i--) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto list_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto list_item_error; } if (type_tag == GI_TYPE_TAG_GLIST) { list = (GSList *) g_list_prepend ( (GList *) list, item.v_pointer); } else { list = g_slist_prepend (list, item.v_pointer); } continue; list_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &list, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); list = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = list; g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_GHASH: { Py_ssize_t length; PyObject *keys; PyObject *values; GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITypeTag key_type_tag; GHashFunc hash_func; GEqualFunc equal_func; GHashTable *hash_table; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PyMapping_Length (object); if (length < 0) { break; } keys = PyMapping_Keys (object); if (keys == NULL) { break; } values = PyMapping_Values (object); if (values == NULL) { Py_DECREF (keys); break; } key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); key_type_tag = g_type_info_get_tag (key_type_info); switch (key_type_tag) { case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: hash_func = g_str_hash; equal_func = g_str_equal; break; default: hash_func = NULL; equal_func = NULL; } hash_table = g_hash_table_new (hash_func, equal_func); if (hash_table == NULL) { PyErr_NoMemory(); goto hash_table_release; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_key; PyObject *py_value; GIArgument key; GIArgument value; py_key = PyList_GET_ITEM (keys, i); py_value = PyList_GET_ITEM (values, i); key = _pygi_argument_from_object (py_key, key_type_info, item_transfer); if (PyErr_Occurred()) { goto hash_table_item_error; } value = _pygi_argument_from_object (py_value, value_type_info, item_transfer); if (PyErr_Occurred()) { _pygi_argument_release (&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); goto hash_table_item_error; } g_hash_table_insert (hash_table, key.v_pointer, _pygi_arg_to_hash_pointer (&value, g_type_info_get_tag (value_type_info))); continue; hash_table_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &hash_table, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); hash_table = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = hash_table; hash_table_release: g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); Py_DECREF (keys); Py_DECREF (values); break; } case GI_TYPE_TAG_ERROR: PyErr_SetString (PyExc_NotImplementedError, "error marshalling is not supported yet"); /* TODO */ break; default: g_assert_not_reached (); } return arg; }
/** * _pygi_argument_to_array * @arg: The argument to convert * @array_length_policy: Closure for marshalling the array length argument when needed. * @user_data1: Generic user data passed to the array_length_policy. * @user_data2: Generic user data passed to the array_length_policy. * @type_info: The type info for @arg * @out_free_array: A return location for a gboolean that indicates whether * or not the wrapped GArray should be freed * * Make sure an array type argument is wrapped in a GArray. * * Note: This method can *not* be folded into _pygi_argument_to_object() because * arrays are special in the sense that they might require access to @args in * order to get the length. * * Returns: A GArray wrapping @arg. If @out_free_array has been set to TRUE then * free the array with g_array_free() without freeing the data members. * Otherwise don't free the array. */ GArray * _pygi_argument_to_array (GIArgument *arg, PyGIArgArrayLengthPolicy array_length_policy, void *user_data1, void *user_data2, GITypeInfo *type_info, gboolean *out_free_array) { GITypeInfo *item_type_info; gboolean is_zero_terminated; gsize item_size; gssize length; GArray *g_array; g_return_val_if_fail (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY, NULL); if (arg->v_pointer == NULL) { return NULL; } switch (g_type_info_get_array_type (type_info)) { case GI_ARRAY_TYPE_C: is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_type_info = g_type_info_get_param_type (type_info, 0); item_size = _pygi_g_type_info_size (item_type_info); g_base_info_unref ( (GIBaseInfo *) item_type_info); if (is_zero_terminated) { length = g_strv_length (arg->v_pointer); } else { length = g_type_info_get_array_fixed_size (type_info); if (length < 0) { gint length_arg_pos; if (G_UNLIKELY (array_length_policy == NULL)) { g_critical ("Unable to determine array length for %p", arg->v_pointer); g_array = g_array_new (is_zero_terminated, FALSE, item_size); *out_free_array = TRUE; return g_array; } length_arg_pos = g_type_info_get_array_length (type_info); g_assert (length_arg_pos >= 0); length = array_length_policy (length_arg_pos, user_data1, user_data2); if (length < 0) { return NULL; } } } g_assert (length >= 0); g_array = g_array_new (is_zero_terminated, FALSE, item_size); g_free (g_array->data); g_array->data = arg->v_pointer; g_array->len = length; *out_free_array = TRUE; break; case GI_ARRAY_TYPE_ARRAY: case GI_ARRAY_TYPE_BYTE_ARRAY: /* Note: GByteArray is really just a GArray */ g_array = arg->v_pointer; *out_free_array = FALSE; break; case GI_ARRAY_TYPE_PTR_ARRAY: { GPtrArray *ptr_array = (GPtrArray*) arg->v_pointer; g_array = g_array_sized_new (FALSE, FALSE, sizeof(gpointer), ptr_array->len); g_array->data = (char*) ptr_array->pdata; g_array->len = ptr_array->len; *out_free_array = TRUE; break; } default: g_critical ("Unexpected array type %u", g_type_info_get_array_type (type_info)); g_array = NULL; break; } return g_array; }