c4692995f20d4f5151860d6803c2b5216b27ce4c
[blender.git] / source / blender / blenlib / intern / dynlib.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file, with exception of below:
24  *
25  * Contributor(s): Peter O'Gorman
26  * The functions osxdlopen() and osxerror() 
27  * are Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net>
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdio.h>
35
36 #include "../PIL_dynlib.h"
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #if !defined(CHAR_MAX)
43 #define CHAR_MAX 255
44 #endif
45
46 /*
47  * XXX, should use mallocN so we can see
48  * handle's not being released. fixme zr
49  */
50  
51 #ifdef WIN32
52
53 #include <windows.h>
54
55 struct PILdynlib {
56         void *handle;
57 };
58
59 PILdynlib *PIL_dynlib_open(char *name) {
60         void *handle= LoadLibrary(name);
61
62         if (handle) {   
63                 PILdynlib *lib= malloc(sizeof(*lib));
64                 lib->handle= handle;
65                 
66                 return lib;
67         } else {
68                 return NULL;
69         }
70 }
71
72 void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) {
73         return GetProcAddress(lib->handle, symname);
74 }
75
76 char *PIL_dynlib_get_error_as_string(PILdynlib* lib) {
77         int err;
78
79         /* if lib is NULL reset the last error code */
80         if (!lib) {
81                 SetLastError(ERROR_SUCCESS);
82                 return NULL;
83         }
84
85         err= GetLastError();
86         if (err) {
87                 static char buf[1024];
88
89                 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 
90                                         NULL, 
91                                         err, 
92                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
93                                         buf, 
94                                         sizeof(buf), 
95                                         NULL))
96                         return buf;
97         }
98         
99         return NULL;
100 }
101
102 void PIL_dynlib_close(PILdynlib *lib) {
103         FreeLibrary(lib->handle);
104         
105         free(lib);
106 }
107
108 #else
109 #ifdef __APPLE__        /* MacOS X */
110
111 #include <mach-o/dyld.h>
112 #include <dlfcn.h>
113 #include <stdarg.h>
114
115 #define ERR_STR_LEN 256
116
117 struct PILdynlib {
118         void *handle;
119 };
120
121 static char *osxerror(int setget, const char *str, ...)
122 {
123         static char errstr[ERR_STR_LEN];
124         static int err_filled = 0;
125         char *retval;
126         NSLinkEditErrors ler;
127         int lerno;
128         const char *dylderrstr;
129         const char *file;
130         va_list arg;
131         if (setget <= 0)
132         {
133                 va_start(arg, str);
134                 strncpy(errstr, "dlsimple: ", ERR_STR_LEN);
135                 vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg);
136                 va_end(arg);
137         /* We prefer to use the dyld error string if setget is 0 */
138                 if (setget == 0) {
139                         NSLinkEditError(&ler, &lerno, &file, &dylderrstr);
140 //                      printf("dyld: %s\n",dylderrstr);
141                         if (dylderrstr && strlen(dylderrstr))
142                                 strncpy(errstr,dylderrstr,ERR_STR_LEN);
143                 }               
144                 err_filled = 1;
145                 retval = NULL;
146         }
147         else
148         {
149                 if (!err_filled)
150                         retval = NULL;
151                 else
152                         retval = errstr;
153                 err_filled = 0;
154         }
155         return retval;
156 }
157
158 static void *osxdlopen(const char *path, int mode)
159 {
160         void *module = 0;
161         NSObjectFileImage ofi = 0;
162         NSObjectFileImageReturnCode ofirc;
163         static int (*make_private_module_public) (NSModule module) = 0;
164         unsigned int flags =  NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
165
166         /* If we got no path, the app wants the global namespace, use -1 as the marker
167            in this case */
168         if (!path)
169                 return (void *)-1;
170
171         /* Create the object file image, works for things linked with the -bundle arg to ld */
172         ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
173         switch (ofirc)
174         {
175                 case NSObjectFileImageSuccess:
176                         /* It was okay, so use NSLinkModule to link in the image */
177                         if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
178                         module = NSLinkModule(ofi, path,flags);
179                         /* Don't forget to destroy the object file image, unless you like leaks */
180                         NSDestroyObjectFileImage(ofi);
181                         /* If the mode was global, then change the module, this avoids
182                            multiply defined symbol errors to first load private then make
183                            global. Silly, isn't it. */
184                         if ((mode & RTLD_GLOBAL))
185                         {
186                           if (!make_private_module_public)
187                           {
188                             _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", 
189                                 (unsigned long *)&make_private_module_public);
190                           }
191                           make_private_module_public(module);
192                         }
193                         break;
194                 case NSObjectFileImageInappropriateFile:
195                         /* It may have been a dynamic library rather than a bundle, try to load it */
196                         module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
197                         break;
198                 case NSObjectFileImageFailure:
199                         osxerror(0,"Object file setup failure :  \"%s\"", path);
200                         return 0;
201                 case NSObjectFileImageArch:
202                         osxerror(0,"No object for this architecture :  \"%s\"", path);
203                         return 0;
204                 case NSObjectFileImageFormat:
205                         osxerror(0,"Bad object file format :  \"%s\"", path);
206                         return 0;
207                 case NSObjectFileImageAccess:
208                         osxerror(0,"Can't read object file :  \"%s\"", path);
209                         return 0;               
210         }
211         if (!module)
212                 osxerror(0, "Can not open \"%s\"", path);
213         return module;
214 }
215
216 PILdynlib *PIL_dynlib_open(char *name) {
217         void *handle= osxdlopen(name, RTLD_LAZY);
218
219         if (handle) {   
220                 PILdynlib *lib= malloc(sizeof(*lib));
221                 lib->handle= handle;
222                 
223                 return lib;
224         } else {
225                 return NULL;
226         }
227 }
228
229 void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) 
230 {
231         int sym_len = strlen(symname);
232         void *value = NULL;
233         char *malloc_sym = NULL;
234         NSSymbol *nssym = 0;
235         malloc_sym = malloc(sym_len + 2);
236         if (malloc_sym)
237         {
238                 sprintf(malloc_sym, "_%s", symname);
239                 /* If the lib->handle is -1, if is the app global context */
240                 if (lib->handle == (void *)-1)
241                 {
242                         /* Global context, use NSLookupAndBindSymbol */
243                         if (NSIsSymbolNameDefined(malloc_sym))
244                         {
245                                 nssym = NSLookupAndBindSymbol(malloc_sym);
246                         }
247                 }
248                 /* Now see if the lib->handle is a struch mach_header* or not, use NSLookupSymbol in image
249                    for libraries, and NSLookupSymbolInModule for bundles */
250                 else
251                 {
252                         /* Check for both possible magic numbers depending on x86/ppc byte order */
253                         if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
254                                 (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
255                         {
256                                 if (NSIsSymbolNameDefinedInImage((struct mach_header *)lib->handle, malloc_sym))
257                                 {
258                                         nssym = NSLookupSymbolInImage((struct mach_header *)lib->handle,
259                                                                                                   malloc_sym,
260                                                                                                   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
261                                                                                                   | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
262                                 }
263         
264                         }
265                         else
266                         {
267                                 nssym = NSLookupSymbolInModule(lib->handle, malloc_sym);
268                         }
269                 }
270                 if (!nssym)
271                 {
272                         osxerror(0, "symname \"%s\" Not found", symname);
273                 }
274                 value = NSAddressOfSymbol(nssym);
275                 free(malloc_sym);
276         }
277         else
278         {
279                 osxerror(-1, "Unable to allocate memory");
280         }
281         return value;
282 }
283
284 char *PIL_dynlib_get_error_as_string(PILdynlib* lib) 
285 {
286         return osxerror(1, (char *)NULL);
287 }
288         
289 void PIL_dynlib_close(PILdynlib *lib) 
290 {
291         if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
292                 (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
293         {
294                 osxerror(-1, "Can't remove dynamic libraries on darwin");
295         }
296         if (!NSUnLinkModule(lib->handle, 0))
297         {
298                 osxerror(0, "unable to unlink module %s", NSNameOfModule(lib->handle));
299         }
300         
301         free(lib);
302 }
303
304 #else   /* Unix */
305
306 #include <dlfcn.h>
307
308 struct PILdynlib {
309         void *handle;
310 };
311
312 PILdynlib *PIL_dynlib_open(char *name) {
313         void *handle= dlopen(name, RTLD_LAZY);
314
315         if (handle) {   
316                 PILdynlib *lib= malloc(sizeof(*lib));
317                 lib->handle= handle;
318                 
319                 return lib;
320         } else {
321                 return NULL;
322         }
323 }
324
325 void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) {
326         return dlsym(lib->handle, symname);
327 }
328
329 char *PIL_dynlib_get_error_as_string(PILdynlib* lib) {
330         return dlerror();
331 }
332         
333 void PIL_dynlib_close(PILdynlib *lib) {
334         dlclose(lib->handle);
335         
336         free(lib);
337 }
338
339 #endif
340 #endif