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