[gegl] Add support for filtering non-LGPL plugins



commit e236db255f7854b30b95e052e0dbb4e4424d8f04
Author: Daniel Sabo <DanielSabo gmail com>
Date:   Sat Dec 7 19:23:09 2013 -0800

    Add support for filtering non-LGPL plugins
    
    Add support for filtering operations with more restrictive
    licenses (e.g. GPL) at runtime, by default only operations
    with licenses no more restrictive than LGPL are exposed.

 bin/gegl.c                       |    4 +
 gegl/gegl-config.c               |   20 ++++-
 gegl/gegl-config.h               |    1 +
 gegl/gegl-debug.h                |    7 +-
 gegl/gegl-init.c                 |   17 ++++
 gegl/operation/gegl-operations.c |  178 +++++++++++++++++++++++++++++++++-----
 gegl/operation/gegl-operations.h |    2 +
 7 files changed, 205 insertions(+), 24 deletions(-)
---
diff --git a/bin/gegl.c b/bin/gegl.c
index 905658f..26239fd 100644
--- a/bin/gegl.c
+++ b/bin/gegl.c
@@ -86,6 +86,10 @@ main (gint    argc,
   GError      *err       = NULL;
   gchar       *path_root = NULL;
 
+  g_object_set (gegl_config (),
+                "application-license", "GPL3",
+                NULL);
+
   gegl_init (&argc, &argv);
 #ifdef HAVE_SPIRO
   gegl_path_spiro_init ();
diff --git a/gegl/gegl-config.c b/gegl/gegl-config.c
index eb3e82b..7308b56 100644
--- a/gegl/gegl-config.c
+++ b/gegl/gegl-config.c
@@ -45,7 +45,8 @@ enum
   PROP_TILE_HEIGHT,
   PROP_THREADS,
   PROP_USE_OPENCL,
-  PROP_QUEUE_SIZE
+  PROP_QUEUE_SIZE,
+  PROP_APPLICATION_LICENSE
 };
 
 static void
@@ -98,6 +99,10 @@ gegl_config_get_property (GObject    *gobject,
         g_value_set_int (value, config->queue_size);
         break;
 
+      case PROP_APPLICATION_LICENSE:
+        g_value_set_string (value, config->application_license);
+        break;
+
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
         break;
@@ -172,6 +177,11 @@ gegl_config_set_property (GObject      *gobject,
       case PROP_QUEUE_SIZE:
         config->queue_size = g_value_get_int (value);
         break;
+      case PROP_APPLICATION_LICENSE:
+        if (config->application_license)
+          g_free (config->application_license);
+        config->application_license = g_value_dup_string (value);
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
         break;
@@ -280,6 +290,14 @@ gegl_config_class_init (GeglConfigClass *klass)
                                                      2, G_MAXINT, 50 * 1024 *1024,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (gobject_class, PROP_APPLICATION_LICENSE,
+                                   g_param_spec_string ("application-license",
+                                                        "Application license",
+                                                        "A list of additional licenses to allow for 
operations",
+                                                        "",
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
 }
 
 static void
diff --git a/gegl/gegl-config.h b/gegl/gegl-config.h
index 0a170f8..3faec93 100644
--- a/gegl/gegl-config.h
+++ b/gegl/gegl-config.h
@@ -45,6 +45,7 @@ struct _GeglConfig
   gint     threads;
   gboolean use_opencl;
   gint     queue_size;
+  gchar   *application_license;
 };
 
 struct _GeglConfigClass
diff --git a/gegl/gegl-debug.h b/gegl/gegl-debug.h
index 0d87c7e..324ac72 100644
--- a/gegl/gegl-debug.h
+++ b/gegl/gegl-debug.h
@@ -15,7 +15,8 @@ typedef enum {
   GEGL_DEBUG_MISC            = 1 << 6,
   GEGL_DEBUG_INVALIDATION    = 1 << 7,
   GEGL_DEBUG_OPENCL          = 1 << 8,
-  GEGL_DEBUG_BUFFER_ALLOC    = 1 << 9
+  GEGL_DEBUG_BUFFER_ALLOC    = 1 << 9,
+  GEGL_DEBUG_LICENSE         = 1 << 10
 } GeglDebugFlag;
 
 /* only compiled in from gegl-init.c but kept here to
@@ -33,6 +34,7 @@ static const GDebugKey gegl_debug_keys[] = {
   { "invalidation",  GEGL_DEBUG_INVALIDATION},
   { "opencl",        GEGL_DEBUG_OPENCL},
   { "buffer-alloc",  GEGL_DEBUG_BUFFER_ALLOC},
+  { "license",       GEGL_DEBUG_LICENSE},
   { "all",           GEGL_DEBUG_PROCESS|
                      GEGL_DEBUG_BUFFER_LOAD|
                      GEGL_DEBUG_BUFFER_SAVE|
@@ -40,7 +42,8 @@ static const GDebugKey gegl_debug_keys[] = {
                      GEGL_DEBUG_PROCESSOR|
                      GEGL_DEBUG_CACHE|
                      GEGL_DEBUG_OPENCL|
-                     GEGL_DEBUG_BUFFER_ALLOC},
+                     GEGL_DEBUG_BUFFER_ALLOC|
+                     GEGL_DEBUG_LICENSE},
 };
 #endif /* __GEGL_INIT_C */
 
diff --git a/gegl/gegl-init.c b/gegl/gegl-init.c
index aa81ccc..ef6e89b 100644
--- a/gegl/gegl-init.c
+++ b/gegl/gegl-init.c
@@ -172,6 +172,17 @@ gegl_swap_dir (void)
 }
 
 static void
+gegl_config_application_license_notify (GObject    *gobject,
+                                        GParamSpec *pspec,
+                                        gpointer    user_data)
+{
+  GeglConfig *cfg = GEGL_CONFIG (gobject);
+
+  gegl_operations_set_licenses_from_string (cfg->application_license);
+}
+
+
+static void
 gegl_config_use_opencl_notify (GObject    *gobject,
                                GParamSpec *pspec,
                                gpointer    user_data)
@@ -663,6 +674,12 @@ gegl_post_parse_hook (GOptionContext *context,
                    NULL);
   g_object_set (config, "use-opencl", config->use_opencl, NULL);
 
+  g_signal_connect (G_OBJECT (config),
+                   "notify::application-license",
+                   G_CALLBACK (gegl_config_application_license_notify),
+                   NULL);
+  gegl_operations_set_licenses_from_string (config->application_license);
+
   return TRUE;
 }
 
diff --git a/gegl/operation/gegl-operations.c b/gegl/operation/gegl-operations.c
index 5615483..329e6a4 100644
--- a/gegl/operation/gegl-operations.c
+++ b/gegl/operation/gegl-operations.c
@@ -30,11 +30,13 @@
 #include "gegl-operations.h"
 #include "gegl-operation-context.h"
 
+static gchar     **accepted_licenses       = NULL;
+static GHashTable *known_operation_names   = NULL;
+static GHashTable *visible_operation_names = NULL;
+static GSList     *operations_list         = NULL;
+static guint       gtype_hash_serial       = 0;
 
-static GHashTable *gtype_hash        = NULL;
-static GSList     *operations_list   = NULL;
-static guint       gtype_hash_serial = 0;
-G_LOCK_DEFINE_STATIC (gtype_hash);
+static GMutex operations_cache_mutex = { 0, };
 
 void
 gegl_operation_class_register_name (GeglOperationClass *klass,
@@ -44,9 +46,9 @@ gegl_operation_class_register_name (GeglOperationClass *klass,
   GType this_type, check_type;
   this_type = G_TYPE_FROM_CLASS (klass);
 
-  G_LOCK (gtype_hash);
+  g_mutex_lock (&operations_cache_mutex);
 
-  check_type = (GType) g_hash_table_lookup (gtype_hash, name);
+  check_type = (GType) g_hash_table_lookup (known_operation_names, name);
   if (check_type && check_type != this_type)
     {
       g_warning ("Adding %s shadows %s for operation %s",
@@ -54,13 +56,10 @@ gegl_operation_class_register_name (GeglOperationClass *klass,
                   g_type_name (check_type),
                   name);
     }
-  g_hash_table_insert (gtype_hash, g_strdup (name), (gpointer) this_type);
 
-  if (!check_type && !is_compat)
-    operations_list = g_slist_insert_sorted (operations_list, (gpointer) name,
-                                             (GCompareFunc) strcmp);
+  g_hash_table_insert (known_operation_names, g_strdup (name), (gpointer) this_type);
 
-  G_UNLOCK (gtype_hash);
+  g_mutex_unlock (&operations_cache_mutex);
 }
 
 static void
@@ -87,6 +86,126 @@ add_operations (GType parent)
   g_free (types);
 }
 
+static gboolean
+gegl_operations_check_license (const gchar *operation_license)
+{
+  gint i;
+
+  if (!accepted_licenses || !accepted_licenses[0])
+    return FALSE;
+
+  if (0 == g_ascii_strcasecmp (operation_license, "GPL1+"))
+    {
+      /* Search for GPL1 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL1", accepted_licenses[i]))
+          return TRUE;
+      /* Search for GPL2 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL2", accepted_licenses[i]))
+          return TRUE;
+      /* Search for GPL3 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL3", accepted_licenses[i]))
+          return TRUE;
+    }
+  else if (0 == g_ascii_strcasecmp (operation_license, "GPL2+"))
+    {
+      /* Search for GPL2 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL2", accepted_licenses[i]))
+          return TRUE;
+      /* Search for GPL3 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL3", accepted_licenses[i]))
+          return TRUE;
+    }
+  else if (0 == g_ascii_strcasecmp (operation_license, "GPL3+"))
+    {
+      /* Search for GPL3 */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp ("GPL3", accepted_licenses[i]))
+          return TRUE;
+    }
+  else
+    {
+      /* Search for exact match */
+      for (i = 0; accepted_licenses[i]; ++i)
+        if (0 == g_ascii_strcasecmp (operation_license, accepted_licenses[i]))
+          return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gegl_operations_update_visible (void)
+{
+  g_mutex_lock (&operations_cache_mutex);
+
+  GHashTableIter iter;
+  const gchar *iter_key;
+  GType iter_value;
+
+  g_hash_table_remove_all (visible_operation_names);
+  g_slist_free (operations_list);
+
+  operations_list = NULL;
+
+  g_hash_table_iter_init (&iter, known_operation_names);
+
+  while (g_hash_table_iter_next (&iter, (gpointer)&iter_key, (gpointer)&iter_value))
+    {
+      GObjectClass *object_class;
+      GeglOperationClass *operation_class;
+
+      object_class = g_type_class_ref (iter_value);
+      operation_class = GEGL_OPERATION_CLASS (object_class);
+
+      const gchar *operation_license = g_hash_table_lookup (operation_class->keys, "license");
+
+      if (!operation_license || gegl_operations_check_license (operation_license))
+        {
+          if (operation_license)
+            {
+              GEGL_NOTE (GEGL_DEBUG_LICENSE, "Accepted %s for %s", operation_license, iter_key);
+            }
+
+          if (operation_class->name && (0 == strcmp (iter_key, operation_class->name)))
+            {
+              /* Is the primary name of the operation */
+              operations_list = g_slist_insert_sorted (operations_list, (gpointer) iter_key,
+                                                       (GCompareFunc) strcmp);
+            }
+
+          g_hash_table_insert (visible_operation_names, g_strdup (iter_key), (gpointer) iter_value);
+        }
+      else if (operation_license)
+        {
+          GEGL_NOTE (GEGL_DEBUG_LICENSE, "Rejected %s for %s", operation_license, iter_key);
+        }
+
+      g_type_class_unref (object_class);
+    }
+
+  g_mutex_unlock (&operations_cache_mutex);
+}
+
+void
+gegl_operations_set_licenses_from_string (const gchar *license_str)
+{
+  g_mutex_lock (&operations_cache_mutex);
+
+  if (accepted_licenses)
+    g_strfreev (accepted_licenses);
+
+  accepted_licenses = g_strsplit (license_str, ",", 0);
+
+  g_mutex_unlock (&operations_cache_mutex);
+
+  gegl_operations_update_visible ();
+}
+
 GType
 gegl_operation_gtype_from_name (const gchar *name)
 {
@@ -96,10 +215,13 @@ gegl_operation_gtype_from_name (const gchar *name)
   if (gtype_hash_serial != latest_serial)
     {
       add_operations (GEGL_TYPE_OPERATION);
+
       gtype_hash_serial = latest_serial;
+
+      gegl_operations_update_visible ();
     }
 
-  return (GType) g_hash_table_lookup (gtype_hash, name);
+  return (GType) g_hash_table_lookup (visible_operation_names, name);
 }
 
 gboolean
@@ -130,6 +252,8 @@ gchar **gegl_list_operations (guint *n_operations_p)
         }
     }
 
+  g_mutex_lock (&operations_cache_mutex);
+
   n_operations = g_slist_length (operations_list);
   pasp_size   += (n_operations + 1) * sizeof (gchar *);
   for (iter = operations_list; iter != NULL; iter = g_slist_next (iter))
@@ -149,30 +273,42 @@ gchar **gegl_list_operations (guint *n_operations_p)
   pasp[i] = NULL;
   if (n_operations_p)
     *n_operations_p = n_operations;
+
+  g_mutex_unlock (&operations_cache_mutex);
+
   return pasp;
 }
 
 void
 gegl_operation_gtype_init (void)
 {
-  G_LOCK (gtype_hash);
+  g_mutex_lock (&operations_cache_mutex);
 
-  if (!gtype_hash)
-    gtype_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  if (!known_operation_names)
+    known_operation_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-  G_UNLOCK (gtype_hash);
+  if (!visible_operation_names)
+    visible_operation_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  g_mutex_unlock (&operations_cache_mutex);
 }
 
 void
 gegl_operation_gtype_cleanup (void)
 {
-  G_LOCK (gtype_hash);
-  if (gtype_hash)
+  g_mutex_lock (&operations_cache_mutex);
+  if (known_operation_names)
     {
-      g_hash_table_destroy (gtype_hash);
-      gtype_hash = NULL;
+      g_hash_table_destroy (known_operation_names);
+      known_operation_names = NULL;
+
+      g_hash_table_destroy (visible_operation_names);
+      visible_operation_names = NULL;
+
+      g_slist_free (operations_list);
+      operations_list = NULL;
     }
-  G_UNLOCK (gtype_hash);
+  g_mutex_unlock (&operations_cache_mutex);
 }
 
 gboolean gegl_can_do_inplace_processing (GeglOperation       *operation,
diff --git a/gegl/operation/gegl-operations.h b/gegl/operation/gegl-operations.h
index dc9b5c3..2a58877 100644
--- a/gegl/operation/gegl-operations.h
+++ b/gegl/operation/gegl-operations.h
@@ -34,4 +34,6 @@ void       gegl_operation_class_register_name (GeglOperationClass *klass,
                                                const gchar        *name,
                                                const gboolean      is_compat);
 
+void       gegl_operations_set_licenses_from_string (const gchar *license_str);
+
 #endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]