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