diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2011-03-10 13:06:24 +0100 |
---|---|---|
committer | Martyn Russell <martyn@lanedo.com> | 2011-03-15 13:34:10 +0000 |
commit | 625d9706e7e97a9b8093b21eeb8e707f579c0b29 (patch) | |
tree | cccedeb960cbea5863f3c1ca54b632e514965d94 /src | |
parent | 18dfb327dbad2097663a3d893a79d19bebdc29a5 (diff) | |
download | tracker-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.am | 4 | ||||
-rw-r--r-- | src/libtracker-extract/tracker-extract-module-manager.c | 287 | ||||
-rw-r--r-- | src/libtracker-extract/tracker-extract-module-manager.h | 46 |
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__ */ |