1 #include "common.h"
2 
3 #include <dlfcn.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7 
8 #include "file.h"
9 #include "image.h"
10 #include "loaders.h"
11 
12 static ImlibLoader *loaders = NULL;
13 
14 ImlibLoader       **
__imlib_GetLoaderList(void)15 __imlib_GetLoaderList(void)
16 {
17    return &loaders;
18 }
19 
20 /* try dlopen()ing the file if we succeed finish filling out the malloced */
21 /* loader struct and return it */
22 static ImlibLoader *
__imlib_ProduceLoader(char * file)23 __imlib_ProduceLoader(char *file)
24 {
25    ImlibLoader        *l;
26    void                (*l_formats)(ImlibLoader * l);
27 
28    l = malloc(sizeof(ImlibLoader));
29    l->num_formats = 0;
30    l->formats = NULL;
31    l->handle = dlopen(file, RTLD_NOW | RTLD_LOCAL);
32    if (!l->handle)
33      {
34         free(l);
35         return NULL;
36      }
37    l->load = dlsym(l->handle, "load");
38    l->load2 = dlsym(l->handle, "load2");
39    l->save = dlsym(l->handle, "save");
40    l_formats = dlsym(l->handle, "formats");
41 
42    /* each loader must provide formats() and at least load() or save() */
43    if (!l_formats || !(l->load2 || l->load || l->save))
44      {
45         dlclose(l->handle);
46         free(l);
47         return NULL;
48      }
49    l_formats(l);
50    l->file = strdup(file);
51    l->next = NULL;
52    return l;
53 }
54 
55 /* fre the struct for a loader and close its dlopen'd handle */
56 static void
__imlib_ConsumeLoader(ImlibLoader * l)57 __imlib_ConsumeLoader(ImlibLoader * l)
58 {
59    if (l->file)
60       free(l->file);
61    if (l->handle)
62       dlclose(l->handle);
63    if (l->formats)
64      {
65         int                 i;
66 
67         for (i = 0; i < l->num_formats; i++)
68            free(l->formats[i]);
69         free(l->formats);
70      }
71    free(l);
72 }
73 
74 /* remove all loaders int eh list we have cached so we can re-load them */
75 void
__imlib_RemoveAllLoaders(void)76 __imlib_RemoveAllLoaders(void)
77 {
78    ImlibLoader        *l, *il;
79 
80    l = loaders;
81    while (l)
82      {
83         il = l;
84         l = l->next;
85         __imlib_ConsumeLoader(il);
86      }
87    loaders = NULL;
88 }
89 
90 /* find all the loaders we can find and load them up to see what they can */
91 /* load / save */
92 void
__imlib_LoadAllLoaders(void)93 __imlib_LoadAllLoaders(void)
94 {
95    int                 i, num;
96    char              **list;
97 
98    if (loaders)
99       return;
100 
101    /* list all the loaders imlib can find */
102    list = __imlib_ListModules(__imlib_PathToLoaders(), &num);
103    /* no loaders? well don't load anything */
104    if (!list)
105       return;
106 
107    /* go through the list of filenames for loader .so's and load them */
108    /* (or try) and if it succeeds, append to our loader list */
109    for (i = num - 1; i >= 0; i--)
110      {
111         ImlibLoader        *l;
112 
113         l = __imlib_ProduceLoader(list[i]);
114         if (l)
115           {
116              l->next = loaders;
117              loaders = l;
118           }
119         if (list[i])
120            free(list[i]);
121      }
122    free(list);
123 }
124 
125 __EXPORT__ ImlibLoader *
__imlib_FindBestLoaderForFormat(const char * format,int for_save)126 __imlib_FindBestLoaderForFormat(const char *format, int for_save)
127 {
128    ImlibLoader        *l;
129 
130    if (!format || format[0] == '\0')
131       return NULL;
132 
133    /* go through the loaders - first loader that claims to handle that */
134    /* image type (extension wise) wins as a first guess to use - NOTE */
135    /* this is an OPTIMISATION - it is possible the file has no extension */
136    /* or has an unrecognised one but still is loadable by a loader. */
137    /* if thkis initial loader failes to load the load mechanism will */
138    /* systematically go from most recently used to least recently used */
139    /* loader until one succeeds - or none are left and all have failed */
140    /* and only if all fail does the laod fail. the lao9der that does */
141    /* succeed gets it way to the head of the list so it's going */
142    /* to be used first next time in this search mechanims - this */
143    /* assumes you tend to laod a few image types and ones generally */
144    /* of the same format */
145    for (l = loaders; l; l = l->next)
146      {
147         int                 i;
148 
149         /* go through all the formats that loader supports */
150         for (i = 0; i < l->num_formats; i++)
151           {
152              /* does it match ? */
153              if (strcasecmp(l->formats[i], format) == 0)
154                {
155                   /* does it provide the function we need? */
156                   if ((for_save && l->save) ||
157                       (!for_save && (l->load || l->load2)))
158                      goto done;
159                }
160           }
161      }
162 
163  done:
164    return l;
165 }
166 
167 __EXPORT__ ImlibLoader *
__imlib_FindBestLoaderForFile(const char * file,int for_save)168 __imlib_FindBestLoaderForFile(const char *file, int for_save)
169 {
170    ImlibLoader        *l;
171 
172    l = __imlib_FindBestLoaderForFormat(__imlib_FileExtension(file), for_save);
173 
174    return l;
175 }
176 
177 ImlibLoader        *
__imlib_FindBestLoaderForFileFormat(const char * file,const char * format,int for_save)178 __imlib_FindBestLoaderForFileFormat(const char *file, const char *format,
179                                     int for_save)
180 {
181    /* if the format is provided ("png" "jpg" etc.) use that */
182    /* otherwise us the file extension */
183    if (format)
184       return __imlib_FindBestLoaderForFormat(format, for_save);
185    else
186       return __imlib_FindBestLoaderForFile(file, for_save);
187 }
188 
189 __EXPORT__ void
__imlib_LoaderSetFormats(ImlibLoader * l,const char * const * fmt,unsigned int num)190 __imlib_LoaderSetFormats(ImlibLoader * l,
191                          const char *const *fmt, unsigned int num)
192 {
193    unsigned int        i;
194 
195    l->num_formats = num;
196    l->formats = malloc(sizeof(char *) * num);
197 
198    for (i = 0; i < num; i++)
199       l->formats[i] = strdup(fmt[i]);
200 }
201