/* babl - dynamically extendable universal pixel conversion library. * Copyright (C) 2005, Øyvind Kolås. * * 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 3 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, see * . */ #define BABL_DYNAMIC_EXTENSIONS #include "config.h" #ifdef BABL_DYNAMIC_EXTENSIONS /* must be defined before inclusion of babl-internal.h */ #undef BABL_INIT_HOOK #define BABL_INIT_HOOK init_hook (); dynamic_init_hook (); #endif #define NEEDS_BABL_DB #include "babl-internal.h" #include "babl-db.h" #include "babl-base.h" #include #include static Babl *babl_extension_current_extender = NULL; Babl * babl_extender (void) { if (babl_extension_current_extender) return babl_extension_current_extender; return NULL; } void babl_set_extender (Babl *new_extender) { babl_extension_current_extender = new_extender; } static int babl_extension_destroy (void *data); static Babl * extension_new (const char *path, void *dl_handle, void (*destroy)(void)) { Babl *babl; babl = babl_malloc (sizeof (BablExtension) + strlen (path) + 1); babl_set_destructor (babl, babl_extension_destroy); babl->instance.name = (char *) babl + sizeof (BablExtension); strcpy (babl->instance.name, path); babl->instance.id = 0; babl->class_type = BABL_EXTENSION; babl->extension.dl_handle = dl_handle; babl->extension.destroy = destroy; return babl; } static Babl *babl_quiet = NULL; Babl * babl_extension_quiet_log (void) { if (babl_quiet) return babl_quiet; babl_quiet = extension_new ("", NULL, NULL); return babl_quiet; } Babl * babl_extension_base (void) { Babl *babl; void *dl_handle = NULL; void (*destroy)(void) = NULL; if (!db) { babl_extension_quiet_log (); babl_set_extender (NULL); db = babl_db_init (); } babl = extension_new ("BablBase", dl_handle, destroy); babl_set_extender (babl); { Babl *ret = babl_db_insert (db, babl); if (ret != babl) babl_free (babl); else babl_base_init (); babl = ret; } babl_set_extender (NULL); return babl; } void babl_extension_deinit (void) { babl_free (babl_quiet); babl_quiet = NULL; } #ifdef BABL_DYNAMIC_EXTENSIONS #include #include #include #include #ifdef HAVE_DLFCN_H #ifndef WIN32 #include #define HLIB void * #endif /* WIN32 */ #elif HAVE_DL_H #include #include #if !defined(DYNAMIC_PATH) # define DYNAMIC_PATH 0 #endif #if !defined(BIND_RESTRICTED) # define BIND_RESTRICTED 0 #endif #define RTLD_NOW (BIND_IMMEDIATE|BIND_NONFATAL|DYNAMIC_PATH) #define HLIB shl_t #define dlopen(path, flags) shl_load (path, flags, 0L) #define dlclose(handle) shl_unload (handle) #define dlerror() strerror (errno) static void * dlsym (HLIB handle, const char *name) { void *address = 0; shl_findsym(&handle, name, TYPE_UNDEFINED, &address); return address; } #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #define HLIB HINSTANCE #define dlopen(a, b) LoadLibrary (a) #define dlsym(l, s) GetProcAddress (l, s) #define dlclose(l) FreeLibrary (l) #define dlerror() GetLastError () #endif typedef int (*BablExtensionInitFunc) (void); typedef void (*BablExtensionDestroyFunc)(void); static Babl * load_failed (Babl *babl) { if (babl) { babl_free (babl); } babl_set_extender (NULL); return NULL; } static Babl * babl_extension_load (const char *path) { Babl *babl = NULL; /* do the actual loading thing */ HLIB dl_handle = NULL; BablExtensionInitFunc init = NULL; BablExtensionDestroyFunc destroy = NULL; dl_handle = dlopen (path, RTLD_NOW); if (!dl_handle) { babl_log ("dlopen() failed:\n\t%s", dlerror ()); return load_failed (babl); } init = (BablExtensionInitFunc) dlsym (dl_handle, "init"); if (!init) { babl_log ("\n\tint babl_extension_init() function not found in extension '%s'", path); dlclose (dl_handle); return load_failed (babl); } destroy = (BablExtensionDestroyFunc) dlsym (dl_handle, "destroy"); babl = extension_new (path, dl_handle, destroy); babl_set_extender (babl); if (init ()) { babl_log ("babl_extension_init() in extension '%s' failed (return!=0)", path); dlclose (dl_handle); return load_failed (babl); } babl_db_insert (db, babl); if (babl == babl_db_exist_by_name (db, path)) { babl_set_extender (NULL); return babl; } else { return load_failed (babl); } } static void babl_extension_load_dir (const char *base_path) { DIR *dir; if ((dir = opendir (base_path))) { struct dirent *dentry; while ((dentry = readdir (dir)) != NULL) { if (dentry->d_name[0] != '.') { char *path = NULL; char *extension; path = babl_strcat (path, base_path); path = babl_strcat (path, BABL_DIR_SEPARATOR); path = babl_strcat (path, dentry->d_name); if ((extension = strrchr (dentry->d_name, '.')) != NULL && !strcmp (extension, SHREXT)) { babl_extension_load (path); } babl_free (path); } } closedir (dir); } } static char * expand_path (char *path) { char *src; char *dst; dst = NULL; src = path; while (*src) { char *home; switch (*src) { case '~': home = getenv ("HOME"); if (NULL != home) dst = babl_strcat (dst, home); break; default: { char tmp[2] = "?"; tmp[0] = *src; dst = babl_strcat (dst, tmp); } } src++; } return dst; } /* parse the provided colon seperated list of paths to search */ void babl_extension_load_dir_list (const char *dir_list) { int eos = 0; const char *src; char *path, *dst; path = babl_strdup (dir_list); src = dir_list; dst = path; while (!eos) { switch (*src) { case '\0': eos = 1; /* don't break here, the path needs to be processed */ case BABL_PATH_SEPARATOR: { char *expanded_path = expand_path (path); if (expanded_path) { babl_extension_load_dir (expanded_path); babl_free (expanded_path); } } dst = path; src++; *dst = '\0'; break; default: *(dst++) = *(src++); *dst = '\0'; break; } } babl_free (path); if (babl_db_count (db) <= 1) { babl_log ("WARNING: the babl installation seems broken, no extensions found in queried\n" "BABL_PATH (%s) this means no SIMD/instructions/special case fast paths and\n" "only slow reference conversions are available, applications might still\n" "run but software relying on babl for conversions will be slow\n", dir_list); } } #endif static int babl_extension_destroy (void *data) { Babl *babl = data; if (babl->extension.destroy) babl->extension.destroy (); if (babl->extension.dl_handle) dlclose (babl->extension.dl_handle); return 0; } BABL_CLASS_IMPLEMENT (extension)