1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*
34  *  Environment variable controls available:
35  *
36  *   - COIN_DEBUG_SIMAGE: set to 1 to get information about success or
37  *     failure of loading the simage library.
38  */
39 
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #else /* No config.h? Hmm. Assume the simage library is available for linking. */
43 #define SIMAGEWRAPPER_ASSUME_SIMAGE
44 #endif /* !HAVE_CONFIG_H */
45 
46 #include "coindefs.h"
47 #include <cassert>
48 #include <cstdlib>
49 #include <cstring>
50 #include <cstdio>
51 
52 #ifdef HAVE_LIBSIMAGE /* In case we're _not_ doing runtime linking. */
53 #define SIMAGEWRAPPER_ASSUME_SIMAGE
54 #include <simage.h>
55 #endif /* HAVE_LIBSIMAGE */
56 
57 #include <Inventor/C/basic.h>
58 #include <Inventor/C/glue/dl.h>
59 #include <Inventor/C/errors/debugerror.h>
60 #include <Inventor/C/tidbits.h>
61 
62 #include "glue/simage_wrapper.h"
63 #include "threads/threadsutilp.h"
64 #include "tidbitsp.h"
65 
66 /* ********************************************************************** */
67 
68 #ifdef __cplusplus
69 extern "C" {
70 #endif /* __cplusplus */
71 
72 static simage_wrapper_t * simage_instance = NULL;
73 static cc_libhandle simage_libhandle = NULL;
74 static int simage_failed_to_load = 0;
75 static int simage_is_initializing = 0;
76 
77 
78 /* Return value of COIN_DEBUG_SIMAGE environment variable. */
79 static int
cc_simage_debugging(void)80 cc_simage_debugging(void)
81 {
82   static int d = -1;
83   if (d == -1) {
84     const char * val = coin_getenv("COIN_DEBUG_SIMAGE");
85     d = val ? atoi(val) : 0;
86   }
87   return (d > 0) ? 1 : 0;
88 }
89 
90 /* Cleans up at exit. */
91 static void
simage_wrapper_cleanup(void)92 simage_wrapper_cleanup(void)
93 {
94 #ifdef SIMAGE_RUNTIME_LINKING
95   if (simage_libhandle) {
96     cc_dl_close(simage_libhandle);
97     simage_libhandle = NULL;
98   }
99 #endif /* SIMAGE_RUNTIME_LINKING */
100 
101   assert(simage_instance);
102   free(simage_instance);
103   simage_instance = NULL;
104   simage_failed_to_load = 0;
105   simage_is_initializing = 0;
106 }
107 
108 /* backup-functions. More robust when simage is an old version, or not
109    available */
110 
111 static int
simage_wrapper_versionMatchesAtLeast(int major,int minor,int micro)112 simage_wrapper_versionMatchesAtLeast(int major, int minor, int micro)
113 {
114   assert(simage_instance);
115   if (simage_instance->available == 0) return 0;
116   if (simage_instance->version.major < major) return 0;
117   else if (simage_instance->version.major > major) return 1;
118   if (simage_instance->version.minor < minor) return 0;
119   else if (simage_instance->version.minor > minor) return 1;
120   if (simage_instance->version.micro < micro) return 0;
121   return 1;
122 }
123 
124 static int
simage_wrapper_get_num_savers(void)125 simage_wrapper_get_num_savers(void)
126 {
127   return 0;
128 }
129 
130 static void *
simage_wrapper_get_saver_handle(int COIN_UNUSED_ARG (jada))131 simage_wrapper_get_saver_handle(int COIN_UNUSED_ARG(jada))
132 {
133   return NULL;
134 }
135 
136 static int
simage_wrapper_check_save_supported(const char * COIN_UNUSED_ARG (jada))137 simage_wrapper_check_save_supported(const char * COIN_UNUSED_ARG(jada))
138 {
139   return 0;
140 }
141 
142 static int
simage_wrapper_save_image(const char * COIN_UNUSED_ARG (jada),const unsigned char * COIN_UNUSED_ARG (jada2),int COIN_UNUSED_ARG (jada3),int COIN_UNUSED_ARG (jada4),int COIN_UNUSED_ARG (jada5),const char * COIN_UNUSED_ARG (jada6))143 simage_wrapper_save_image(const char * COIN_UNUSED_ARG(jada),
144                           const unsigned char * COIN_UNUSED_ARG(jada2),
145                           int COIN_UNUSED_ARG(jada3), int COIN_UNUSED_ARG(jada4), int COIN_UNUSED_ARG(jada5),
146                           const char * COIN_UNUSED_ARG(jada6))
147 {
148   return 0;
149 }
150 
151 static const char *
simage_wrapper_get_saver_extensions(void * COIN_UNUSED_ARG (handle))152 simage_wrapper_get_saver_extensions(void * COIN_UNUSED_ARG(handle))
153 {
154   return "";
155 }
156 
157 static const char *
simage_wrapper_get_saver_fullname(void * COIN_UNUSED_ARG (handle))158 simage_wrapper_get_saver_fullname(void * COIN_UNUSED_ARG(handle))
159 {
160   return NULL;
161 }
162 
163 static const char *
simage_wrapper_get_saver_description(void * COIN_UNUSED_ARG (handle))164 simage_wrapper_get_saver_description(void * COIN_UNUSED_ARG(handle))
165 {
166   return NULL;
167 }
168 
169 static unsigned char *
simage_wrapper_resize3d(unsigned char * COIN_UNUSED_ARG (imagedata),int COIN_UNUSED_ARG (width),int COIN_UNUSED_ARG (height),int COIN_UNUSED_ARG (numcomponents),int COIN_UNUSED_ARG (layers),int COIN_UNUSED_ARG (newwidth),int COIN_UNUSED_ARG (newheight),int COIN_UNUSED_ARG (newlayers))170 simage_wrapper_resize3d(unsigned char * COIN_UNUSED_ARG(imagedata),
171                         int COIN_UNUSED_ARG(width), int COIN_UNUSED_ARG(height),
172                         int COIN_UNUSED_ARG(numcomponents),
173                         int COIN_UNUSED_ARG(layers),
174                         int COIN_UNUSED_ARG(newwidth),
175                         int COIN_UNUSED_ARG(newheight),
176                         int COIN_UNUSED_ARG(newlayers))
177 {
178   return NULL;
179 }
180 
181 static s_params *
simage_wrapper_s_params_create(void)182 simage_wrapper_s_params_create(void)
183 {
184   return NULL;
185 }
186 
187 static void
simage_wrapper_s_params_destroy(s_params * COIN_UNUSED_ARG (params))188 simage_wrapper_s_params_destroy(s_params * COIN_UNUSED_ARG(params))
189 {
190   return;
191 }
192 
193 static void
simage_wrapper_s_params_set(s_params * COIN_UNUSED_ARG (params),...)194 simage_wrapper_s_params_set(s_params * COIN_UNUSED_ARG(params), ...)
195 {
196   return;
197 }
198 
199 static int
simage_wrapper_s_params_get(s_params * COIN_UNUSED_ARG (params),...)200 simage_wrapper_s_params_get(s_params * COIN_UNUSED_ARG(params), ...)
201 {
202   return 0;
203 }
204 
205 static s_stream *
simage_wrapper_s_stream_open(const char * COIN_UNUSED_ARG (filename),s_params * COIN_UNUSED_ARG (params))206 simage_wrapper_s_stream_open(const char * COIN_UNUSED_ARG(filename),
207               s_params * COIN_UNUSED_ARG(params) /* | NULL */)
208 {
209   return NULL;
210 }
211 
212 static s_stream *
simage_wrapper_s_stream_create(const char * COIN_UNUSED_ARG (filename),s_params * COIN_UNUSED_ARG (params))213 simage_wrapper_s_stream_create(const char * COIN_UNUSED_ARG(filename),
214                 s_params * COIN_UNUSED_ARG(params) /* | NULL */)
215 {
216   return NULL;
217 }
218 
219 static void *
simage_wrapper_s_stream_get_buffer(s_stream * COIN_UNUSED_ARG (stream),void * COIN_UNUSED_ARG (prealloc),int * COIN_UNUSED_ARG (size),s_params * COIN_UNUSED_ARG (params))220 simage_wrapper_s_stream_get_buffer(s_stream * COIN_UNUSED_ARG(stream),
221                     void * COIN_UNUSED_ARG(prealloc) /* | NULL */,
222                     int * COIN_UNUSED_ARG(size) /* | NULL */,
223                     s_params * COIN_UNUSED_ARG(params) /* | NULL */)
224 {
225   return NULL;
226 }
227 
228 static int
simage_wrapper_s_stream_put_buffer(s_stream * COIN_UNUSED_ARG (stream),void * COIN_UNUSED_ARG (buffer),int COIN_UNUSED_ARG (size),s_params * COIN_UNUSED_ARG (params))229 simage_wrapper_s_stream_put_buffer(s_stream * COIN_UNUSED_ARG(stream), void * COIN_UNUSED_ARG(buffer),
230                     int COIN_UNUSED_ARG(size), s_params * COIN_UNUSED_ARG(params) /* | NULL */)
231 {
232   return 0;
233 }
234 
235 static void
simage_wrapper_s_stream_close(s_stream * COIN_UNUSED_ARG (stream))236 simage_wrapper_s_stream_close(s_stream * COIN_UNUSED_ARG(stream))
237 {
238   return;
239 }
240 
241 static void
simage_wrapper_s_stream_destroy(s_stream * COIN_UNUSED_ARG (stream))242 simage_wrapper_s_stream_destroy(s_stream * COIN_UNUSED_ARG(stream))
243 {
244   return;
245 }
246 
247 static s_params *
simage_wrapper_s_stream_params(s_stream * COIN_UNUSED_ARG (stream))248 simage_wrapper_s_stream_params(s_stream * COIN_UNUSED_ARG(stream))
249 {
250   return NULL;
251 }
252 
253 
254 /* Implemented by using the singleton pattern. */
255 const simage_wrapper_t *
simage_wrapper(void)256 simage_wrapper(void)
257 {
258   CC_SYNC_BEGIN(simage_wrapper);
259 
260   /* FIXME: we're not thread-safe, due to the "get_last_error" design
261      of simage. Should keep a single entry-lock here to work around
262      this. 20020628 mortene. */
263 
264   if (!simage_instance && !simage_failed_to_load) {
265     /* First invocation, do initializations. */
266     simage_wrapper_t * si = (simage_wrapper_t *)malloc(sizeof(simage_wrapper_t));
267     (void)coin_atexit((coin_atexit_f *)simage_wrapper_cleanup, CC_ATEXIT_DYNLIBS);
268 
269     /* Detect recursive calls. */
270     assert(simage_is_initializing == 0);
271     simage_is_initializing = 1;
272 
273     si->versionMatchesAtLeast = simage_wrapper_versionMatchesAtLeast;
274 
275     /* The common case is that simage is either available from the
276        linking process or we're successfully going to link it in. */
277     si->available = 1;
278 
279 #ifdef SIMAGE_RUNTIME_LINKING
280     {
281       int idx;
282       const char * simage_dll_name = "simage1";
283 
284 #ifdef COIN_SYSTEM_LIBRARY_NAME
285       {
286         /* check for 'd' suffix usage in coinX.dll coinXd.dll */
287         const char * suffix = strstr(COIN_SYSTEM_LIBRARY_NAME, "d.");
288         if (suffix && (strlen(suffix) != strlen(COIN_SYSTEM_LIBRARY_NAME))) {
289           simage_dll_name = "simage1d";
290         }
291       }
292 #endif
293 
294       /* FIXME: should we get the system shared library name from an
295          Autoconf check? 20000930 mortene. */
296       const char * possiblelibnames[] = {
297         NULL, /* is set below */
298         "simage", "libsimage", "libsimage.so",
299         /* Mach dynamic library name */
300         "libsimage.dylib",
301         /* MSWindows DLL names for the simage library */
302         simage_dll_name,
303         NULL
304       };
305 
306       possiblelibnames[0] = coin_getenv("COIN_SIMAGE_LIBNAME");
307       idx = possiblelibnames[0] ? 0 : 1;
308 
309       while (!simage_libhandle && possiblelibnames[idx]) {
310         simage_libhandle = cc_dl_open(possiblelibnames[idx]);
311         idx++;
312       }
313 
314       if (cc_simage_debugging()) {
315         if (!simage_libhandle) {
316           cc_debugerror_post("simage_wrapper",
317                              "failed to load simage library.");
318         } else {
319           cc_debugerror_postinfo("simage_wrapper",
320                                  "loaded library %s",
321                                  possiblelibnames[idx-1]);
322         }
323       }
324 
325       if (!simage_libhandle) {
326         si->available = 0;
327         simage_failed_to_load = 1;
328       }
329     }
330     /* Define SIMAGEWRAPPER_REGISTER_FUNC macro. Casting the type is
331        necessary for this file to be compatible with C++ compilers. */
332 #define SIMAGEWRAPPER_REGISTER_FUNC(_funcname_, _funcsig_) \
333     si->_funcname_ = (_funcsig_)cc_dl_sym(simage_libhandle, SO__QUOTE(_funcname_))
334 
335 #elif defined(SIMAGEWRAPPER_ASSUME_SIMAGE) /* !SIMAGE_RUNTIME_LINKING */
336 
337     /* Define SIMAGEWRAPPER_REGISTER_FUNC macro. */
338 #define SIMAGEWRAPPER_REGISTER_FUNC(_funcname_, _funcsig_) \
339     si->_funcname_ = (_funcsig_)_funcname_
340 
341 #else /* !SIMAGEWRAPPER_ASSUME_SIMAGE */
342     si->available = 0;
343     /* Define SIMAGEWRAPPER_REGISTER_FUNC macro. */
344 #define SIMAGEWRAPPER_REGISTER_FUNC(_funcname_, _funcsig_) \
345     si->_funcname_ = NULL
346 
347 #endif /* !SIMAGEWRAPPER_ASSUME_SIMAGE */
348 
349     SIMAGEWRAPPER_REGISTER_FUNC(simage_version, simage_version_t);
350 
351     if (si->available && !si->simage_version) {
352       /* something is seriously wrong */
353       cc_debugerror_post("simage_wrapper",
354                          "Loaded simage DLL ok, but couldn't resolve symbol "
355                          "simage_version().");
356       si->available = 0;
357       simage_failed_to_load = 1;
358 
359       simage_instance = si;
360     }
361     else {
362       /* get version */
363       if (si->available) {
364         si->simage_version(&si->version.major,
365                            &si->version.minor,
366                            &si->version.micro);
367         if (cc_simage_debugging()) {
368           cc_debugerror_postinfo ("simage_wrapper",
369                                   "simage version: %d.%d.%d",
370                                   si->version.major,
371                                   si->version.minor,
372                                   si->version.micro);
373         }
374       }
375 
376       SIMAGEWRAPPER_REGISTER_FUNC(simage_check_supported, simage_check_supported_t);
377       SIMAGEWRAPPER_REGISTER_FUNC(simage_read_image, simage_read_image_t);
378       SIMAGEWRAPPER_REGISTER_FUNC(simage_get_last_error, simage_get_last_error_t);
379       SIMAGEWRAPPER_REGISTER_FUNC(simage_resize, simage_resize_t);
380       SIMAGEWRAPPER_REGISTER_FUNC(simage_free_image, simage_free_image_t);
381       SIMAGEWRAPPER_REGISTER_FUNC(simage_next_power_of_two, simage_next_power_of_two_t);
382 
383       /* Do this late, so we can detect recursive calls to this function. */
384       simage_instance = si;
385 
386       if (simage_wrapper_versionMatchesAtLeast(1,1,0)) {
387 #if !defined(HAVE_LIBSIMAGE) || defined(SIMAGE_VERSION_1_1)
388         SIMAGEWRAPPER_REGISTER_FUNC(simage_get_num_savers, simage_get_num_savers_t);
389         SIMAGEWRAPPER_REGISTER_FUNC(simage_get_saver_handle, simage_get_saver_handle_t);
390         SIMAGEWRAPPER_REGISTER_FUNC(simage_check_save_supported, simage_check_save_supported_t);
391         SIMAGEWRAPPER_REGISTER_FUNC(simage_save_image, simage_save_image_t);
392         SIMAGEWRAPPER_REGISTER_FUNC(simage_get_saver_extensions, simage_get_saver_extensions_t);
393         SIMAGEWRAPPER_REGISTER_FUNC(simage_get_saver_fullname, simage_get_saver_fullname_t);
394         SIMAGEWRAPPER_REGISTER_FUNC(simage_get_saver_description, simage_get_saver_description_t);
395 #endif /* !HAVE_LIBSIMAGE || SIMAGE_VERSION_1_1 */
396       }
397       else {
398         si->simage_get_saver_handle = simage_wrapper_get_saver_handle;
399         si->simage_get_num_savers = simage_wrapper_get_num_savers;
400         si->simage_check_save_supported = simage_wrapper_check_save_supported;
401         si->simage_save_image = simage_wrapper_save_image;
402         si->simage_get_saver_extensions = simage_wrapper_get_saver_extensions;
403         si->simage_get_saver_fullname = simage_wrapper_get_saver_fullname;
404         si->simage_get_saver_description = simage_wrapper_get_saver_description;
405       }
406 
407       if (simage_wrapper_versionMatchesAtLeast(1,3,0)) {
408 #if !defined(HAVE_LIBSIMAGE) || defined(SIMAGE_VERSION_1_3)
409         SIMAGEWRAPPER_REGISTER_FUNC(simage_resize3d, simage_resize3d_t);
410 #endif
411       }
412       else si->simage_resize3d = NULL;
413 
414       if (simage_wrapper_versionMatchesAtLeast(1,4,0)) {
415 #if !defined(HAVE_LIBSIMAGE) || defined(SIMAGE_VERSION_1_4)
416         SIMAGEWRAPPER_REGISTER_FUNC(simage_resize3d, simage_resize3d_t);
417 
418         SIMAGEWRAPPER_REGISTER_FUNC(s_params_create, s_params_create_t);
419         SIMAGEWRAPPER_REGISTER_FUNC(s_params_destroy, s_params_destroy_t);
420         SIMAGEWRAPPER_REGISTER_FUNC(s_params_set, s_params_set_t);
421         SIMAGEWRAPPER_REGISTER_FUNC(s_params_get, s_params_get_t);
422         SIMAGEWRAPPER_REGISTER_FUNC(s_stream_open, s_stream_open_t);
423         SIMAGEWRAPPER_REGISTER_FUNC(s_stream_get_buffer, s_stream_get_buffer_t);
424         SIMAGEWRAPPER_REGISTER_FUNC(s_stream_close, s_stream_close_t);
425         SIMAGEWRAPPER_REGISTER_FUNC(s_stream_destroy, s_stream_destroy_t);
426         SIMAGEWRAPPER_REGISTER_FUNC(s_stream_params, s_stream_params_t);
427 #endif
428       }
429       else {
430 #if 0
431         /* 20021018 thammer. I might want to use these later instead
432            of setting all of them to NULL */
433         si->s_params_set = simage_wrapper_s_params_set;
434         si->s_params_get = simage_wrapper_s_params_get;
435         si->s_stream_open = simage_wrapper_s_stream_open;
436         si->s_stream_get_buffer = simage_wrapper_s_stream_get_buffer;
437         si->s_stream_close = simage_wrapper_s_stream_close;
438         si->s_stream_destroy = simage_wrapper_s_stream_destroy;
439         si->s_stream_params = simage_wrapper_s_stream_params;
440 #endif
441         si->s_params_create = NULL;
442         si->s_params_destroy = NULL;
443         si->s_params_set = NULL;
444         si->s_params_get = NULL;
445         si->s_stream_open = NULL;
446         si->s_stream_get_buffer = NULL;
447         si->s_stream_close = NULL;
448         si->s_stream_destroy = NULL;
449         si->s_stream_params = NULL;
450       }
451     }
452     simage_is_initializing = 0;
453   }
454   CC_SYNC_END(simage_wrapper);
455   return simage_instance;
456 }
457 
458 #ifdef __cplusplus
459 } /* extern "C" */
460 #endif /* __cplusplus */
461