
In conf_apply_rules, check input argument is a table before assuming it is and potentially crashing. Add check also in wplua_table_to_properties to avoid similar bugs.
353 lines
10 KiB
C
353 lines
10 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "wplua.h"
|
|
#include "private.h"
|
|
#include <wp/wp.h>
|
|
|
|
WpProperties *
|
|
wplua_table_to_properties (lua_State *L, int idx)
|
|
{
|
|
WpProperties *p = wp_properties_new_empty ();
|
|
const gchar *key, *value;
|
|
int table = lua_absindex (L, idx);
|
|
|
|
if (lua_type (L, table) != LUA_TTABLE) {
|
|
wp_critical ("skipping non-table value");
|
|
return p;
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
while (lua_next (L, table) != 0) {
|
|
/* copy key & value to convert them to string */
|
|
key = luaL_tolstring (L, -2, NULL);
|
|
value = luaL_tolstring (L, -2, NULL);
|
|
wp_properties_set (p, key, value);
|
|
lua_pop (L, 3);
|
|
}
|
|
|
|
/* sort, because the lua table has a random order and it's too messy to read */
|
|
wp_properties_sort (p);
|
|
|
|
return p;
|
|
}
|
|
|
|
void
|
|
wplua_properties_to_table (lua_State *L, WpProperties *p)
|
|
{
|
|
lua_newtable (L);
|
|
if (p) {
|
|
g_autoptr (WpIterator) it = wp_properties_new_iterator (p);
|
|
GValue v = G_VALUE_INIT;
|
|
const gchar *key, *value;
|
|
|
|
while (wp_iterator_next (it, &v)) {
|
|
WpPropertiesItem *pi = g_value_get_boxed (&v);
|
|
key = wp_properties_item_get_key (pi);
|
|
value = wp_properties_item_get_value (pi);
|
|
lua_pushstring (L, key);
|
|
lua_pushstring (L, value);
|
|
lua_settable (L, -3);
|
|
g_value_unset (&v);
|
|
}
|
|
}
|
|
}
|
|
|
|
GVariant *
|
|
wplua_lua_to_gvariant (lua_State *L, int idx)
|
|
{
|
|
switch (lua_type (L, idx)) {
|
|
case LUA_TNIL:
|
|
return g_variant_new ("()");
|
|
case LUA_TBOOLEAN:
|
|
return g_variant_new_boolean (lua_toboolean (L, idx));
|
|
case LUA_TNUMBER:
|
|
if (lua_isinteger (L, idx))
|
|
return g_variant_new_int64 (lua_tointeger (L, idx));
|
|
else
|
|
return g_variant_new_double (lua_tonumber (L, idx));
|
|
case LUA_TSTRING:
|
|
return g_variant_new_string (lua_tostring (L, idx));
|
|
case LUA_TTABLE: {
|
|
GVariantBuilder b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
|
const gchar *key;
|
|
int table = lua_absindex (L, idx);
|
|
|
|
lua_pushnil (L);
|
|
while (lua_next (L, table) != 0) {
|
|
/* copy key to convert it to string */
|
|
lua_pushvalue (L, -2);
|
|
key = lua_tostring (L, -1);
|
|
g_variant_builder_add (&b, "{sv}", key, wplua_lua_to_gvariant (L, -2));
|
|
lua_pop (L, 2);
|
|
}
|
|
return g_variant_builder_end (&b);
|
|
}
|
|
default:
|
|
wp_warning ("skipping bad value (its type cannot be represented in GVariant)");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
wplua_gvariant_to_lua (lua_State *L, GVariant *variant)
|
|
{
|
|
if (variant == NULL || g_variant_is_of_type (variant, G_VARIANT_TYPE_UNIT)) {
|
|
lua_pushnil (L);
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16)) {
|
|
lua_pushinteger (L, g_variant_get_int16 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32)) {
|
|
lua_pushinteger (L, g_variant_get_int32 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64)) {
|
|
lua_pushinteger (L, g_variant_get_int64 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16)) {
|
|
lua_pushinteger (L, g_variant_get_uint16 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) {
|
|
lua_pushinteger (L, g_variant_get_uint32 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64)) {
|
|
lua_pushinteger (L, g_variant_get_uint64 (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE)) {
|
|
lua_pushnumber (L, g_variant_get_double (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) {
|
|
lua_pushboolean (L, g_variant_get_boolean (variant));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) {
|
|
lua_pushstring (L, g_variant_get_string (variant, NULL));
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARIANT)) {
|
|
g_autoptr (GVariant) v = g_variant_get_variant (variant);
|
|
wplua_gvariant_to_lua (L, v);
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DICTIONARY)) {
|
|
gsize n_children, i;
|
|
n_children = g_variant_n_children (variant);
|
|
lua_createtable (L, 0, n_children);
|
|
for (i = 0; i < n_children; i++) {
|
|
g_autoptr (GVariant) key, value;
|
|
g_variant_get_child (variant, i, "{@?@*}", &key, &value);
|
|
wplua_gvariant_to_lua (L, key);
|
|
/* if the key is a string convertible to integer, convert it */
|
|
if (lua_type (L, -1) == LUA_TSTRING) {
|
|
int isnum = 0;
|
|
lua_Integer num = lua_tointegerx (L, -1, &isnum);
|
|
if (isnum) {
|
|
lua_pop (L, 1);
|
|
lua_pushinteger (L, num);
|
|
}
|
|
}
|
|
wplua_gvariant_to_lua (L, value);
|
|
lua_settable (L, -3);
|
|
}
|
|
}
|
|
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY)) {
|
|
gsize n_children, i;
|
|
n_children = g_variant_n_children (variant);
|
|
lua_createtable (L, n_children, 0);
|
|
for (i = 0; i < n_children; i++) {
|
|
g_autoptr (GVariant) value;
|
|
value = g_variant_get_child_value (variant, i);
|
|
wplua_gvariant_to_lua (L, value);
|
|
lua_seti (L, -2, i + 1);
|
|
}
|
|
}
|
|
else {
|
|
g_autofree gchar *type_name =
|
|
g_variant_type_dup_string (g_variant_get_type (variant));
|
|
wp_warning ("Unhandled GVariant type %s", type_name);
|
|
lua_pushnil (L);
|
|
}
|
|
}
|
|
|
|
gint
|
|
wplua_lua_to_enum (lua_State *L, int idx, GType enum_type)
|
|
{
|
|
if (lua_type (L, idx) == LUA_TSTRING) {
|
|
g_autoptr (GEnumClass) klass = g_type_class_ref (enum_type);
|
|
GEnumValue *value = g_enum_get_value_by_nick (klass, lua_tostring (L, idx));
|
|
if (value)
|
|
return value->value;
|
|
else
|
|
luaL_error (L, "Invalid enum value '%s'", lua_tostring (L, idx));
|
|
}
|
|
return lua_tointeger (L, idx);
|
|
}
|
|
|
|
void
|
|
wplua_enum_to_lua (lua_State *L, gint enum_val, GType enum_type)
|
|
{
|
|
g_autoptr (GEnumClass) klass = g_type_class_ref (enum_type);
|
|
GEnumValue *value = g_enum_get_value (klass, enum_val);
|
|
if (value)
|
|
lua_pushstring (L, value->value_nick);
|
|
else
|
|
lua_pushinteger (L, enum_val);
|
|
}
|
|
|
|
void
|
|
wplua_lua_to_gvalue (lua_State *L, int idx, GValue *v)
|
|
{
|
|
switch (g_type_fundamental (G_VALUE_TYPE (v))) {
|
|
case G_TYPE_CHAR:
|
|
if (lua_type (L, idx) == LUA_TSTRING)
|
|
g_value_set_schar (v, *lua_tostring (L, idx));
|
|
else
|
|
g_value_set_schar (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_UCHAR:
|
|
g_value_set_uchar (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_INT:
|
|
g_value_set_int (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_UINT:
|
|
g_value_set_uint (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_LONG:
|
|
g_value_set_long (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_ULONG:
|
|
g_value_set_ulong (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_INT64:
|
|
g_value_set_int64 (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_UINT64:
|
|
g_value_set_uint64 (v, lua_tonumber (L, idx));
|
|
break;
|
|
case G_TYPE_FLOAT:
|
|
g_value_set_float (v, lua_tonumber (L, idx));
|
|
break;
|
|
case G_TYPE_DOUBLE:
|
|
g_value_set_double (v, lua_tonumber (L, idx));
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
g_value_set_boolean (v, lua_toboolean (L, idx));
|
|
break;
|
|
case G_TYPE_STRING:
|
|
g_value_set_string (v, lua_tostring (L, idx));
|
|
break;
|
|
case G_TYPE_POINTER:
|
|
if (lua_type (L, idx) == LUA_TLIGHTUSERDATA)
|
|
g_value_set_pointer (v, lua_touserdata (L, idx));
|
|
break;
|
|
case G_TYPE_BOXED:
|
|
if (_wplua_isgvalue_userdata (L, idx, G_VALUE_TYPE (v)))
|
|
g_value_set_boxed (v, wplua_toboxed (L, idx));
|
|
/* table -> WpProperties */
|
|
else if (lua_istable (L, idx) && G_VALUE_TYPE (v) == WP_TYPE_PROPERTIES)
|
|
g_value_take_boxed (v, wplua_table_to_properties (L, idx));
|
|
break;
|
|
case G_TYPE_OBJECT:
|
|
case G_TYPE_INTERFACE:
|
|
if (_wplua_isgvalue_userdata (L, idx, G_VALUE_TYPE (v)))
|
|
g_value_set_object (v, wplua_toobject (L, idx));
|
|
break;
|
|
case G_TYPE_ENUM:
|
|
g_value_set_enum (v, wplua_lua_to_enum (L, idx, G_VALUE_TYPE (v)));
|
|
break;
|
|
case G_TYPE_FLAGS:
|
|
g_value_set_flags (v, lua_tointeger (L, idx));
|
|
break;
|
|
case G_TYPE_VARIANT:
|
|
g_value_set_variant (v, wplua_lua_to_gvariant (L, idx));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
wplua_gvalue_to_lua (lua_State *L, const GValue *v)
|
|
{
|
|
switch (g_type_fundamental (G_VALUE_TYPE (v))) {
|
|
case G_TYPE_CHAR:
|
|
lua_pushinteger (L, g_value_get_schar (v));
|
|
break;
|
|
case G_TYPE_UCHAR:
|
|
lua_pushinteger (L, g_value_get_uchar (v));
|
|
break;
|
|
case G_TYPE_INT:
|
|
lua_pushinteger (L, g_value_get_int (v));
|
|
break;
|
|
case G_TYPE_UINT:
|
|
lua_pushinteger (L, g_value_get_uint (v));
|
|
break;
|
|
case G_TYPE_LONG:
|
|
lua_pushinteger (L, g_value_get_long (v));
|
|
break;
|
|
case G_TYPE_ULONG:
|
|
lua_pushinteger (L, g_value_get_ulong (v));
|
|
break;
|
|
case G_TYPE_INT64:
|
|
lua_pushinteger (L, g_value_get_int64 (v));
|
|
break;
|
|
case G_TYPE_UINT64:
|
|
lua_pushnumber (L, g_value_get_uint64 (v));
|
|
break;
|
|
case G_TYPE_FLOAT:
|
|
lua_pushnumber (L, g_value_get_float (v));
|
|
break;
|
|
case G_TYPE_DOUBLE:
|
|
lua_pushnumber (L, g_value_get_double (v));
|
|
break;
|
|
case G_TYPE_BOOLEAN:
|
|
lua_pushboolean (L, g_value_get_boolean (v));
|
|
break;
|
|
case G_TYPE_STRING:
|
|
lua_pushstring (L, g_value_get_string (v));
|
|
break;
|
|
case G_TYPE_POINTER:
|
|
lua_pushlightuserdata (L, g_value_get_pointer (v));
|
|
break;
|
|
case G_TYPE_BOXED:
|
|
if (G_VALUE_TYPE (v) == WP_TYPE_PROPERTIES)
|
|
wplua_properties_to_table (L, g_value_get_boxed (v));
|
|
else
|
|
wplua_pushboxed (L, G_VALUE_TYPE (v), g_value_dup_boxed (v));
|
|
break;
|
|
case G_TYPE_OBJECT:
|
|
case G_TYPE_INTERFACE: {
|
|
GObject *object = g_value_dup_object (v);
|
|
if (object)
|
|
wplua_pushobject (L, object);
|
|
else
|
|
lua_pushnil (L);
|
|
break;
|
|
}
|
|
case G_TYPE_ENUM:
|
|
wplua_enum_to_lua (L, g_value_get_enum (v), G_VALUE_TYPE (v));
|
|
break;
|
|
case G_TYPE_FLAGS:
|
|
/* FIXME: push as userdata with methods */
|
|
lua_pushinteger (L, g_value_get_flags (v));
|
|
break;
|
|
case G_TYPE_PARAM: {
|
|
GParamSpec *pspec = g_value_get_param (v);
|
|
lua_pushstring (L, pspec->name);
|
|
break;
|
|
}
|
|
case G_TYPE_VARIANT: {
|
|
GVariant *variant = g_value_get_variant (v);
|
|
wplua_gvariant_to_lua (L, variant);
|
|
break;
|
|
}
|
|
default:
|
|
lua_pushnil (L);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|