/* 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)