/* Creates or marshalls content of GIArgument to/from lua according to specified typeinfo. arg, ptr = marshal.argument() value = marshal.argument(arg, typeinfo, transfer) marshal.argument(arg, typeinfo, transfer, value) */ static int marshal_argument (lua_State *L) { GITypeInfo **info; GITransfer transfer; GIArgument *arg; if (lua_isnone (L, 1)) { /* Create new argument userdata. */ GIArgument *arg = lua_newuserdata (L, sizeof (*arg)); memset (arg, 0, sizeof (*arg)); lua_pushlightuserdata (L, arg); return 2; } arg = lua_touserdata (L, 1); info = luaL_checkudata (L, 2, LGI_GI_INFO); transfer = luaL_checkoption (L, 3, transfers[0], transfers); if (lua_isnone (L, 4)) { lgi_marshal_2lua (L, *info, NULL, GI_DIRECTION_IN, transfer, arg, 0, NULL, NULL); return 1; } else { lua_pop (L, lgi_marshal_2c (L, *info, NULL, transfer, arg, 4, 0, NULL, NULL)); return 0; } }
/* Instantiate constant from given gi_info. */ static int core_constant (lua_State *L) { /* Get typeinfo of the constant. */ GIArgument val; GIConstantInfo *ci = *(GIConstantInfo **) luaL_checkudata (L, 1, LGI_GI_INFO); GITypeInfo *ti = g_constant_info_get_type (ci); lgi_gi_info_new (L, ti); g_constant_info_get_value (ci, &val); lgi_marshal_2lua (L, ti, GI_TRANSFER_NOTHING, &val, 0, NULL, NULL); return 1; }
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; }
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); }
int lgi_marshal_field (lua_State *L, gpointer object, gboolean getmode, int parent_arg, int field_arg, int val_arg) { GITypeInfo *ti; int to_remove, nret; /* Check the type of the field information. */ if (lgi_udata_test (L, field_arg, LGI_GI_INFO)) { GIFieldInfo **fi = lua_touserdata (L, field_arg); GIFieldInfoFlags flags; /* Check, whether field is readable/writable. */ flags = g_field_info_get_flags (*fi); if ((flags & (getmode ? GI_FIELD_IS_READABLE : GI_FIELD_IS_WRITABLE)) == 0) { /* Check, whether parent did not disable access checks completely. */ lua_getfield (L, -1, "_allow"); if (!lua_toboolean (L, -1)) { /* Prepare proper error message. */ lua_concat (L, lgi_type_get_name (L, g_base_info_get_container (*fi))); return luaL_error (L, "%s: field `%s' is not %s", lua_tostring (L, -1), g_base_info_get_name (*fi), getmode ? "readable" : "writable"); } lua_pop (L, 1); } /* Map GIArgument to proper memory location, get typeinfo of the field and perform actual marshalling. */ object = (char *) object + g_field_info_get_offset (*fi); ti = g_field_info_get_type (*fi); lgi_gi_info_new (L, ti); to_remove = lua_gettop (L); } else { /* Consult field table, get kind of field and offset. */ int kind; lgi_makeabs (L, field_arg); luaL_checktype (L, field_arg, LUA_TTABLE); lua_rawgeti (L, field_arg, 1); object = (char *) object + lua_tointeger (L, -1); lua_rawgeti (L, field_arg, 2); kind = lua_tonumber (L, -1); lua_pop (L, 2); /* Load type information from the table and decide how to handle it according to 'kind' */ lua_rawgeti (L, field_arg, 3); switch (kind) { case 0: /* field[3] contains typeinfo, load it and fall through. */ ti = *(GITypeInfo **) luaL_checkudata (L, -1, LGI_GI_INFO); to_remove = lua_gettop (L); break; case 1: case 2: { GIArgument *arg = (GIArgument *) object; if (getmode) { if (kind == 1) { object = arg->v_pointer; parent_arg = 0; } lgi_record_2lua (L, object, FALSE, parent_arg); return 1; } else { g_assert (kind == 1); lgi_record_2c (L, val_arg, arg->v_pointer, FALSE, TRUE, FALSE, FALSE); return 0; } break; } case 3: { /* Get the typeinfo for marshalling the numeric enum value. */ lua_rawgeti (L, field_arg, 4); ti = *(GITypeInfo **) luaL_checkudata (L, -1, LGI_GI_INFO); if (getmode) { /* Use typeinfo to unmarshal numeric value. */ lgi_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, GI_TRANSFER_NOTHING, object, 0, NULL, NULL); /* Replace numeric field with symbolic value. */ lua_gettable (L, -3); lua_replace (L, -3); lua_pop (L, 1); return 1; } else { /* Convert enum symbol to numeric value. */ if (lua_type (L, val_arg != LUA_TNUMBER)) { lua_pushvalue (L, -1); lua_pushvalue (L, val_arg); lua_call (L, 1, 1); lua_replace (L, val_arg); } /* Use typeinfo to marshal the numeric value. */ lgi_marshal_2c (L, ti, NULL, GI_TRANSFER_NOTHING, object, val_arg, 0, NULL, NULL); lua_pop (L, 2); return 0; } } default: return luaL_error (L, "field has bad kind %d", kind); } } if (getmode) { lgi_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, GI_TRANSFER_NOTHING, object, parent_arg, NULL, NULL); nret = 1; } else { lgi_marshal_2c (L, ti, NULL, GI_TRANSFER_EVERYTHING, object, val_arg, 0, NULL, NULL); nret = 0; } lua_remove (L, to_remove); return nret; }