svn merge -r 23207:23528 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[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         err= GetLastError();
81         if (!lib) SetLastError(ERROR_SUCCESS);
82
83         if (err) {
84                 static char buf[1024];
85
86                 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 
87                                         NULL, 
88                                         err, 
89                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
90                                         buf, 
91                                         sizeof(buf), 
92                                         NULL))
93                         return buf;
94         }
95         
96         return err;
97 }
98
99 void PIL_dynlib_close(PILdynlib *lib) {
100         FreeLibrary(lib->handle);
101         
102         free(lib);
103 }
104
105 #else
106 #ifdef __APPLE__        /* MacOS X */
107
108 #include <mach-o/dyld.h>
109 #include <dlfcn.h>
110 #include <stdarg.h>
111
112 #define ERR_STR_LEN 256
113
114 struct PILdynlib {
115         void *handle;
116 };
117
118 static char *osxerror(int setget, const char *str, ...)
119 {
120         static char errstr[ERR_STR_LEN];
121         static int err_filled = 0;
122         char *retval;
123         NSLinkEditErrors ler;
124         int lerno;
125         const char *dylderrstr;
126         const char *file;
127         va_list arg;
128         if (setget <= 0)
129         {
130                 va_start(arg, str);
131                 strncpy(errstr, "dlsimple: ", ERR_STR_LEN);
132                 vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg);
133                 va_end(arg);
134         /* We prefer to use the dyld error string if setget is 0 */
135                 if (setget == 0) {
136                         NSLinkEditError(&ler, &lerno, &file, &dylderrstr);
137 //                      printf("dyld: %s\n",dylderrstr);
138                         if (dylderrstr && strlen(dylderrstr))
139                                 strncpy(errstr,dylderrstr,ERR_STR_LEN);
140                 }               
141                 err_filled = 1;
142                 retval = NULL;
143         }
144         else
145         {
146                 if (!err_filled)
147                         retval = NULL;
148                 else
149                         retval = errstr;
150                 err_filled = 0;
151         }
152         return retval;
153 }
154
155 static void *osxdlopen(const char *path, int mode)
156 {
157         void *module = 0;
158         NSObjectFileImage ofi = 0;
159         NSObjectFileImageReturnCode ofirc;
160         static int (*make_private_module_public) (NSModule module) = 0;
161         unsigned int flags =  NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
162
163         /* If we got no path, the app wants the global namespace, use -1 as the marker
164            in this case */
165         if (!path)
166                 return (void *)-1;
167
168         /* Create the object file image, works for things linked with the -bundle arg to ld */
169         ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
170         switch (ofirc)
171         {
172                 case NSObjectFileImageSuccess:
173                         /* It was okay, so use NSLinkModule to link in the image */
174                         if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
175                         module = NSLinkModule(ofi, path,flags);
176                         /* Don't forget to destroy the object file image, unless you like leaks */
177                         NSDestroyObjectFileImage(ofi);
178                         /* If the mode was global, then change the module, this avoids
179                            multiply defined symbol errors to first load private then make
180                            global. Silly, isn't it. */
181                         if ((mode & RTLD_GLOBAL))
182                         {
183                           if (!make_private_module_public)
184                           {
185                             _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", 
186                                 (unsigned long *)&make_private_module_public);
187                           }
188                           make_private_module_public(module);
189                         }
190                         break;
191                 case NSObjectFileImageInappropriateFile:
192                         /* It may have been a dynamic library rather than a bundle, try to load it */
193                         module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
194                         break;
195                 case NSObjectFileImageFailure:
196                         osxerror(0,"Object file setup failure :  \"%s\"", path);
197                         return 0;
198                 case NSObjectFileImageArch:
199                         osxerror(0,"No object for this architecture :  \"%s\"", path);
200                         return 0;
201                 case NSObjectFileImageFormat:
202                         osxerror(0,"Bad object file format :  \"%s\"", path);
203                         return 0;
204                 case NSObjectFileImageAccess:
205                         osxerror(0,"Can't read object file :  \"%s\"", path);
206                         return 0;               
207         }
208         if (!module)
209                 osxerror(0, "Can not open \"%s\"", path);
210         return module;
211 }
212
213 PILdynlib *PIL_dynlib_open(char *name) {
214         void *handle= osxdlopen(name, RTLD_LAZY);
215
216         if (handle) {   
217                 PILdynlib *lib= malloc(sizeof(*lib));
218                 lib->handle= handle;
219                 
220                 return lib;
221         } else {
222                 return NULL;
223         }
224 }
225
226 void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) 
227 {
228         int sym_len = strlen(symname);
229         void *value = NULL;
230         char *malloc_sym = NULL;
231         NSSymbol *nssym = 0;
232         malloc_sym = malloc(sym_len + 2);
233         if (malloc_sym)
234         {
235                 sprintf(malloc_sym, "_%s", symname);
236                 /* If the lib->handle is -1, if is the app global context */
237                 if (lib->handle == (void *)-1)
238                 {
239                         /* Global context, use NSLookupAndBindSymbol */
240                         if (NSIsSymbolNameDefined(malloc_sym))
241                         {
242                                 nssym = NSLookupAndBindSymbol(malloc_sym);
243                         }
244                 }
245                 /* Now see if the lib->handle is a struch mach_header* or not, use NSLookupSymbol in image
246                    for libraries, and NSLookupSymbolInModule for bundles */
247                 else
248                 {
249                         /* Check for both possible magic numbers depending on x86/ppc byte order */
250                         if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
251                                 (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
252                         {
253                                 if (NSIsSymbolNameDefinedInImage((struct mach_header *)lib->handle, malloc_sym))
254                                 {
255                                         nssym = NSLookupSymbolInImage((struct mach_header *)lib->handle,
256                                                                                                   malloc_sym,
257                                                                                                   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
258                                                                                                   | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
259                                 }
260         
261                         }
262                         else
263                         {
264                                 nssym = NSLookupSymbolInModule(lib->handle, malloc_sym);
265                         }
266                 }
267                 if (!nssym)
268                 {
269                         osxerror(0, "symname \"%s\" Not found", symname);
270                 }
271                 value = NSAddressOfSymbol(nssym);
272                 free(malloc_sym);
273         }
274         else
275         {
276                 osxerror(-1, "Unable to allocate memory");
277         }
278         return value;
279 }
280
281 char *PIL_dynlib_get_error_as_string(PILdynlib* lib) 
282 {
283         return osxerror(1, (char *)NULL);
284 }
285         
286 void PIL_dynlib_close(PILdynlib *lib) 
287 {
288         if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
289                 (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
290         {
291                 osxerror(-1, "Can't remove dynamic libraries on darwin");
292         }
293         if (!NSUnLinkModule(lib->handle, 0))
294         {
295                 osxerror(0, "unable to unlink module %s", NSNameOfModule(lib->handle));
296         }
297         
298         free(lib);
299 }
300
301 #else   /* Unix */
302
303 #include <dlfcn.h>
304
305 struct PILdynlib {
306         void *handle;
307 };
308
309 PILdynlib *PIL_dynlib_open(char *name) {
310         void *handle= dlopen(name, RTLD_LAZY);
311
312         if (handle) {   
313                 PILdynlib *lib= malloc(sizeof(*lib));
314                 lib->handle= handle;
315                 
316                 return lib;
317         } else {
318                 return NULL;
319         }
320 }
321
322 void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) {
323         return dlsym(lib->handle, symname);
324 }
325
326 char *PIL_dynlib_get_error_as_string(PILdynlib* lib) {
327         return dlerror();
328 }
329         
330 void PIL_dynlib_close(PILdynlib *lib) {
331         dlclose(lib->handle);
332         
333         free(lib);
334 }
335
336 #endif
337 #endif