summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2011-03-10 13:06:24 +0100
committerMartyn Russell <martyn@lanedo.com>2011-03-15 13:34:10 +0000
commit625d9706e7e97a9b8093b21eeb8e707f579c0b29 (patch)
treecccedeb960cbea5863f3c1ca54b632e514965d94 /src
parent18dfb327dbad2097663a3d893a79d19bebdc29a5 (diff)
downloadtracker-625d9706e7e97a9b8093b21eeb8e707f579c0b29.tar.gz
libtracker-extract: Add extractor modules manager.
This manager parses a directory of keyfiles, describing rules for matches, the modules aren't preloaded on initialization, instead they are loaded lazily as needed. This supersedes the module loading within src/tracker-extract/tracker-extract.c, and will be used as a replacement in following commits. The specific/generic matching there can be replaced by rules at different priorities calling the same module.
Diffstat (limited to 'src')
-rw-r--r--src/libtracker-extract/Makefile.am4
-rw-r--r--src/libtracker-extract/tracker-extract-module-manager.c287
-rw-r--r--src/libtracker-extract/tracker-extract-module-manager.h46
3 files changed, 337 insertions, 0 deletions
diff --git a/src/libtracker-extract/Makefile.am b/src/libtracker-extract/Makefile.am
index e4b691eab..3bdf9ad5d 100644
--- a/src/libtracker-extract/Makefile.am
+++ b/src/libtracker-extract/Makefile.am
@@ -5,6 +5,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
-DSHAREDIR=\""$(datadir)"\" \
+ -DTRACKER_EXTRACTOR_RULES_DIR=\""$(datadir)/tracker/extract-rules"\" \
$(LIBTRACKER_EXTRACT_CFLAGS)
lib_LTLIBRARIES = libtracker-extract-@TRACKER_API_VERSION@.la
@@ -15,6 +16,8 @@ libtracker_extract_@TRACKER_API_VERSION@_la_SOURCES = \
tracker-data.h \
tracker-exif.c \
tracker-exif.h \
+ tracker-extract-module-manager.c \
+ tracker-extract-module-manager.h \
tracker-guarantee.c \
tracker-guarantee.h \
tracker-iptc.c \
@@ -29,6 +32,7 @@ libtracker_extractinc_HEADERS = \
tracker-data.h \
tracker-exif.h \
tracker-extract.h \
+ tracker-extract-module-manager.h \
tracker-guarantee.h \
tracker-iptc.h \
tracker-utils.h \
diff --git a/src/libtracker-extract/tracker-extract-module-manager.c b/src/libtracker-extract/tracker-extract-module-manager.c
new file mode 100644
index 000000000..a45f68187
--- /dev/null
+++ b/src/libtracker-extract/tracker-extract-module-manager.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2010, Nokia <ivan.frade@nokia.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include "tracker-extract-module-manager.h"
+
+#define EXTRACTOR_FUNCTION "tracker_extract_get_metadata"
+
+typedef struct {
+ const gchar *module_path; /* intern string */
+ GList *patterns;
+} RuleInfo;
+
+typedef struct {
+ GModule *module;
+ TrackerExtractMetadataFunc func;
+} ModuleInfo;
+
+static GHashTable *modules = NULL;
+static GHashTable *mimetype_map = NULL;
+static gboolean initialized = FALSE;
+static GArray *rules = NULL;
+
+static gboolean
+load_extractor_rule (GKeyFile *key_file,
+ GError **error)
+{
+ gchar *module_path, **mimetypes;
+ gsize n_mimetypes, i;
+ RuleInfo rule = { 0 };
+
+ module_path = g_key_file_get_string (key_file, "ExtractorRule", "ModulePath", error);
+
+ if (!module_path) {
+ return FALSE;
+ }
+
+ mimetypes = g_key_file_get_string_list (key_file, "ExtractorRule", "MimeTypes", &n_mimetypes, error);
+
+ if (!mimetypes) {
+ g_free (module_path);
+ return FALSE;
+ }
+
+ /* Construct the rule */
+ rule.module_path = g_intern_string (module_path);
+
+ for (i = 0; i < n_mimetypes; i++) {
+ GPatternSpec *pattern;
+
+ pattern = g_pattern_spec_new (mimetypes[i]);
+ rule.patterns = g_list_prepend (rule.patterns, pattern);
+ }
+
+ if (G_UNLIKELY (!rules)) {
+ rules = g_array_new (FALSE, TRUE, sizeof (RuleInfo));
+ }
+
+ g_array_append_val (rules, rule);
+
+ return TRUE;
+}
+
+gboolean
+tracker_extract_module_manager_init (void)
+{
+ const gchar *extractors_dir, *name;
+ GList *files = NULL, *l;
+ GError *error = NULL;
+ GDir *dir;
+
+ if (initialized) {
+ return TRUE;
+ }
+
+ if (!g_module_supported ()) {
+ g_error ("Modules are not supported for this platform");
+ return FALSE;
+ }
+
+ extractors_dir = g_getenv ("TRACKER_EXTRACTOR_RULES_DIR");
+ if (G_LIKELY (extractors_dir == NULL)) {
+ extractors_dir = TRACKER_EXTRACTOR_RULES_DIR;
+ } else {
+ g_message ("Extractor rules directory is '%s' (set in env)", extractors_dir);
+ }
+
+ dir = g_dir_open (extractors_dir, 0, &error);
+
+ if (!dir) {
+ g_error ("Error opening extractor rules directory: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ files = g_list_insert_sorted (files, (gpointer) name, (GCompareFunc) g_strcmp0);
+ }
+
+ g_message ("Loading extractor rules...");
+
+ for (l = files; l; l = l->next) {
+ GKeyFile *key_file;
+ const gchar *name;
+ gchar *path;
+
+ name = l->data;
+
+ if (!g_str_has_suffix (l->data, ".rule")) {
+ g_message (" Skipping file '%s', no '.rule' suffix", name);
+ continue;
+ }
+
+ path = g_build_filename (extractors_dir, name, NULL);
+ key_file = g_key_file_new ();
+
+ if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error) ||
+ !load_extractor_rule (key_file, &error)) {
+ g_warning (" Could not load extractor rule file '%s': %s", name, error->message);
+ g_clear_error (&error);
+ continue;
+ }
+
+ g_key_file_free (key_file);
+ g_free (path);
+ }
+
+ g_message ("Extractor rules loaded");
+ g_dir_close (dir);
+
+ /* Initialize miscellaneous data */
+ mimetype_map = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ NULL);
+ initialized = TRUE;
+
+ return TRUE;
+}
+
+static RuleInfo *
+lookup_rule (const gchar *mimetype)
+{
+ RuleInfo *info;
+ gchar *reversed;
+ gint len, i;
+
+ if (!rules) {
+ return NULL;
+ }
+
+ if (!mimetype_map) {
+ info = g_hash_table_lookup (mimetype_map, mimetype);
+
+ if (info) {
+ return info;
+ }
+ }
+
+ reversed = g_strdup (mimetype);
+ g_strreverse (reversed);
+ len = strlen (mimetype);
+
+ /* Apply the rules! */
+ for (i = 0; i < rules->len; i++) {
+ GList *l;
+
+ info = &g_array_index (rules, RuleInfo, i);
+
+ for (l = info->patterns; l; l = l->next) {
+ if (g_pattern_match (l->data, len, mimetype, reversed)) {
+ /* Match, store for future queries and return */
+ g_hash_table_insert (mimetype_map, g_strdup (mimetype), info);
+ g_free (reversed);
+ return info;
+ }
+ }
+ }
+
+ g_free (reversed);
+
+ return NULL;
+}
+
+GModule *
+tracker_extract_module_manager_get_for_mimetype (const gchar *mimetype,
+ TrackerExtractMetadataFunc *func)
+{
+ TrackerExtractMetadataFunc extract_func;
+ ModuleInfo *module_info;
+ GModule *module;
+ RuleInfo *info;
+
+ if (*func) {
+ *func = NULL;
+ }
+
+ if (!initialized &&
+ !tracker_extract_module_manager_init ()) {
+ return NULL;
+ }
+
+ info = lookup_rule (mimetype);
+
+ if (!info) {
+ return NULL;
+ }
+
+ if (modules) {
+ module_info = g_hash_table_lookup (modules, info->module_path);
+
+ if (module_info) {
+ if (func) {
+ *func = module_info->func;
+ }
+
+ return module_info->module;
+ }
+ }
+
+ /* Load the module */
+ module = g_module_open (info->module_path, G_MODULE_BIND_LOCAL);
+
+ if (!module) {
+ g_warning ("Could not load module '%s': %s",
+ info->module_path,
+ g_module_error ());
+ return NULL;
+ }
+
+ g_module_make_resident (module);
+
+ if (!g_module_symbol (module, EXTRACTOR_FUNCTION, (gpointer *) &extract_func)) {
+ g_warning ("Could not load module '%s': Function %s() was not found, is it exported?",
+ g_module_name (module), EXTRACTOR_FUNCTION);
+ return NULL;
+ }
+
+ /* Add it to the cache */
+ if (G_UNLIKELY (!modules)) {
+ /* Key is an intern string, so
+ * pointer comparison suffices
+ */
+ modules = g_hash_table_new (NULL, NULL);
+ }
+
+ module_info = g_slice_new0 (ModuleInfo);
+ module_info->module = module;
+ module_info->func = extract_func;
+
+ g_hash_table_insert (modules, (gpointer) info->module_path, module_info);
+
+ if (func) {
+ *func = extract_func;
+ }
+
+ return module;
+}
+
+gboolean
+tracker_extract_module_manager_mimetype_is_handled (const gchar *mimetype)
+{
+ RuleInfo *info;
+
+ if (!initialized &&
+ !tracker_extract_module_manager_init ()) {
+ return FALSE;
+ }
+
+ info = lookup_rule (mimetype);
+ return (info != NULL);
+}
diff --git a/src/libtracker-extract/tracker-extract-module-manager.h b/src/libtracker-extract/tracker-extract-module-manager.h
new file mode 100644
index 000000000..9a7eca02b
--- /dev/null
+++ b/src/libtracker-extract/tracker-extract-module-manager.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __TRACKER_EXTRACT_MODULE_MANAGER_H__
+#define __TRACKER_EXTRACT_MODULE_MANAGER_H__
+
+#include <glib.h>
+#include <gmodule.h>
+#include <libtracker-sparql/tracker-sparql.h>
+
+G_BEGIN_DECLS
+
+#define __LIBTRACKER_EXTRACT_INSIDE__
+
+typedef gboolean (* TrackerExtractMetadataFunc) (const gchar *uri,
+ const gchar *mime_type,
+ TrackerSparqlBuilder *preupdate,
+ TrackerSparqlBuilder *metadata);
+
+
+gboolean tracker_extract_module_manager_init (void) G_GNUC_CONST;
+GModule * tracker_extract_module_manager_get_for_mimetype (const gchar *mimetype,
+ TrackerExtractMetadataFunc *func);
+gboolean tracker_extract_module_manager_mimetype_is_handled (const gchar *mimetype);
+
+#undef __LIBTRACKER_EXTRACT_INSIDE__
+
+G_END_DECLS
+
+#endif /* __TRACKER_EXTRACT_MODULE_MANAGER_H__ */