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 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #else /* No config.h? Hmm. Assume the zlib library is available for linking. */
36 #define ZLIBGLUE_ASSUME_ZLIB 1
37 #endif /* !HAVE_CONFIG_H */
38 
39 #include <cassert>
40 #include <cstdlib>
41 #include <cstring>
42 #include <cstdio>
43 
44 #ifdef HAVE_ZLIB /* In case we're _not_ doing runtime linking. */
45 #define ZLIBGLUE_ASSUME_ZLIB 1
46 #include <zlib.h>
47 #endif /* ZLIBGLUE_ASSUME_ZLIB */
48 
49 #include <Inventor/C/basic.h>
50 #include <Inventor/C/glue/dl.h>
51 #include <Inventor/C/errors/debugerror.h>
52 #include <Inventor/C/tidbits.h>
53 
54 #include "tidbitsp.h"
55 #include "threads/threadsutilp.h"
56 #include "glue/zlib.h"
57 #include "io/gzmemio.h"
58 
59 /* workarounds for hacks in the zlib header file. inflateInit2
60    and deflateInit2 are not functions but defines. The real
61    function names are inflateInit2_ and deflateInit2_ *sigh* */
62 
63 #ifdef deflateInit
64 #undef deflateInit
65 #endif /* deflateInit */
66 
67 #ifdef deflateInit2
68 #undef deflateInit2
69 #endif /* deflateInit2 */
70 
71 #ifdef inflateInit
72 #undef inflateInit
73 #endif /* inflateInit */
74 
75 #ifdef inflateInit2
76 #undef inflateInit2
77 #endif /* inflateInit */
78 
79 #define deflateInit2 deflateInit2_
80 #define inflateInit2 inflateInit2_
81 
82 typedef const char * (*cc_zlibglue_zlibVersion_t)(void);
83 typedef int (*cc_zlibglue_deflateInit2_t)(void * stream,
84                                         int level,
85                                         int method,
86                                         int windowbits,
87                                         int memlevel,
88                                         int strategy);
89 
90 typedef int (*cc_zlibglue_inflateInit2_t)(void * stream,
91                                           int windowbits,
92                                           const char * version,
93                                           int stream_size);
94 
95 typedef int (*cc_zlibglue_deflateEnd_t)(void * stream);
96 typedef int (*cc_zlibglue_inflateEnd_t)(void * stream);
97 typedef int (*cc_zlibglue_inflate_t)(void * stream, int flush);
98 typedef int (*cc_zlibglue_inflateReset_t)(void * stream);
99 typedef int (*cc_zlibglue_deflateParams_t)(void * stream, int level, int strategy);
100 typedef int (*cc_zlibglue_deflate_t)(void * stream, int flush);
101 
102 typedef void * (*cc_zlibglue_gzopen_t)(const char * path, const char * mode);
103 typedef void * (*cc_zlibglue_gzdopen_t)(int fd, const char * mode);
104 typedef int (*cc_zlibglue_gzsetparams_t)(void * fp, int level, int strategy);
105 typedef int (*cc_zlibglue_gzread_t)(void * fp, void * buf, unsigned int len);
106 typedef int (*cc_zlibglue_gzwrite_t)(void * fp, const void * buf, unsigned int len);
107 typedef off_t (*cc_zlibglue_gzseek_t)(void * fp, off_t offset, int whence);
108 typedef int (*cc_zlibglue_gzrewind_t)(void * fp);
109 typedef off_t (*cc_zlibglue_gztell_t)(void * fp);
110 typedef int (*cc_zlibglue_gzeof_t)(void * fp);
111 typedef int (*cc_zlibglue_gzclose_t)(void * fp);
112 typedef int (*cc_zlibglue_crc32_t)(unsigned long crc, const char * buf, unsigned int len);
113 
114 typedef struct {
115   int available;
116   cc_zlibglue_zlibVersion_t zlibVersion;
117   cc_zlibglue_deflateInit2_t deflateInit2;
118   cc_zlibglue_inflateInit2_t inflateInit2;
119   cc_zlibglue_deflateEnd_t deflateEnd;
120   cc_zlibglue_inflateEnd_t inflateEnd;
121   cc_zlibglue_inflate_t inflate;
122   cc_zlibglue_inflateReset_t inflateReset;
123   cc_zlibglue_deflateParams_t deflateParams;
124   cc_zlibglue_deflate_t deflate;
125   cc_zlibglue_gzopen_t gzopen;
126   cc_zlibglue_gzdopen_t gzdopen;
127   cc_zlibglue_gzsetparams_t gzsetparams;
128   cc_zlibglue_gzread_t gzread;
129   cc_zlibglue_gzwrite_t gzwrite;
130   cc_zlibglue_gzseek_t gzseek;
131   cc_zlibglue_gzrewind_t gzrewind;
132   cc_zlibglue_gztell_t gztell;
133   cc_zlibglue_gzeof_t gzeof;
134   cc_zlibglue_gzclose_t gzclose;
135   cc_zlibglue_crc32_t crc32;
136 } cc_zlibglue_t;
137 
138 static cc_zlibglue_t * zlib_instance = NULL;
139 static cc_libhandle zlib_libhandle = NULL;
140 static int zlib_failed_to_load = 0;
141 
142 /* Cleans up at exit. */
143 static void
zlibglue_cleanup(void)144 zlibglue_cleanup(void)
145 {
146 #ifdef ZLIB_RUNTIME_LINKING
147   if (zlib_libhandle) {
148     cc_dl_close(zlib_libhandle);
149     zlib_libhandle = NULL;
150   }
151 #endif /* ZLIB_RUNTIME_LINKING */
152   assert(zlib_instance);
153   free(zlib_instance);
154   zlib_instance = NULL;
155   zlib_failed_to_load = 0;
156 }
157 
158 static const cc_zlibglue_t *
zlibglue_init(void)159 zlibglue_init(void)
160 {
161   CC_SYNC_BEGIN(zlibglue_init);
162 
163   if (!zlib_instance && !zlib_failed_to_load) {
164     /* First invocation, do initializations. */
165     cc_zlibglue_t * zi = (cc_zlibglue_t *)malloc(sizeof(cc_zlibglue_t));
166     (void)coin_atexit((coin_atexit_f *)zlibglue_cleanup, CC_ATEXIT_DYNLIBS);
167 
168     /* The common case is that zlib is either available from the
169        linking process or we're successfully going to link it in. */
170     zi->available = 1;
171 
172 #ifdef ZLIB_RUNTIME_LINKING
173     {
174       int idx;
175       /* FIXME: should we get the system shared library name from an
176          Autoconf check? 20000930 mortene. */
177       const char * possiblelibnames[] = {
178         NULL, /* is set below */
179         "zlib1", "zlib", "libz", "libz.so",
180         "libz.dylib",
181         NULL
182       };
183 
184       possiblelibnames[0] = coin_getenv("COIN_ZLIB_LIBNAME");
185       idx = possiblelibnames[0] ? 0 : 1;
186 
187       while (!zlib_libhandle && possiblelibnames[idx]) {
188         zlib_libhandle = cc_dl_open(possiblelibnames[idx]);
189         idx++;
190       }
191 
192       if (!zlib_libhandle) {
193         zi->available = 0;
194         zlib_failed_to_load = 1;
195       }
196     }
197     /* Define ZLIBGLUE_REGISTER_FUNC macro. Casting the type is
198        necessary for this file to be compatible with C++ compilers. */
199 #define ZLIBGLUE_REGISTER_FUNC(_funcsig_, _funcname_) \
200     do { \
201       zi->_funcname_ = (_funcsig_)cc_dl_sym(zlib_libhandle, SO__QUOTE(_funcname_)); \
202       if (zi->_funcname_ == NULL) zi->available = 0; \
203     } while (0)
204 
205 #elif defined(ZLIBGLUE_ASSUME_ZLIB) /* !ZLIB_RUNTIME_LINKING */
206 
207     /* Define ZLIBGLUE_REGISTER_FUNC macro. */
208 #define ZLIBGLUE_REGISTER_FUNC(_funcsig_, _funcname_) \
209     zi->_funcname_ = (_funcsig_)_funcname_
210 
211 #else /* !ZLIBGLUE_ASSUME_ZLIB */
212     zi->available = 0;
213     /* Define ZLIBGLUE_REGISTER_FUNC macro. */
214 #define ZLIBGLUE_REGISTER_FUNC(_funcsig_, _funcname_) \
215     zi->_funcname_ = NULL
216 
217 #endif /* !ZLIBGLUE_ASSUME_ZLIB */
218 
219     if (zi->available) {
220       ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_zlibVersion_t, zlibVersion);
221     }
222 
223     if (!zi->available || !zi->zlibVersion) {
224       if (!zi->available) {
225         cc_debugerror_post("zlib glue",
226                            "Unable to load zlib DLL/shared object.");
227 
228       }
229       else {
230         /* something is seriously wrong */
231         cc_debugerror_post("zlib glue",
232                            "Loaded zlib DLL ok, but couldn't resolve symbol "
233                            "zlibVersion().");
234       }
235       zi->available = 0;
236       zlib_failed_to_load = 1;
237 
238       zlib_instance = zi;
239     }
240     else {
241       int major, minor, patch;;
242       if (!coin_parse_versionstring(zi->zlibVersion(), &major, &minor, &patch) ||
243           (major < 1) ||
244           (major == 1 && minor == 0 && patch < 2)) {
245         cc_debugerror_post("zlib glue",
246                            "Loaded zlib DLL ok, but version >= 1.0.2 is needed.");
247         zi->available = 0;
248         zlib_failed_to_load = 1;
249         zlib_instance = zi;
250       }
251       else {
252         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_deflateInit2_t, deflateInit2);
253         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_inflateInit2_t, inflateInit2);
254         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_deflateEnd_t, deflateEnd);
255         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_inflateEnd_t, inflateEnd);
256         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_inflate_t, inflate);
257         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_inflateReset_t, inflateReset);
258         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_deflateParams_t, deflateParams);
259         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_deflate_t, deflate);
260         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzopen_t, gzopen);
261         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzdopen_t, gzdopen);
262         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzsetparams_t, gzsetparams);
263         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzread_t, gzread);
264         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzwrite_t, gzwrite);
265         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzseek_t, gzseek);
266         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzrewind_t, gzrewind);
267         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gztell_t, gztell);
268         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzeof_t, gzeof);
269         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_gzclose_t, gzclose);
270         ZLIBGLUE_REGISTER_FUNC(cc_zlibglue_crc32_t, crc32);
271 
272         /* Do this late, so we can detect recursive calls to this function. */
273         zlib_instance = zi;
274       }
275     }
276   }
277   CC_SYNC_END(zlibglue_init);
278   return zlib_instance;
279 }
280 
281 
282 int
cc_zlibglue_available(void)283 cc_zlibglue_available(void)
284 {
285   zlibglue_init();
286   return zlib_instance && zlib_instance->available;
287 }
288 
289 int
cc_zlibglue_deflateInit2(void * stream,int level,int method,int windowbits,int memlevel,int strategy)290 cc_zlibglue_deflateInit2(void * stream,
291                          int level,
292                          int method,
293                          int windowbits,
294                          int memlevel,
295                          int strategy)
296 {
297   zlibglue_init();
298   return zlib_instance->deflateInit2(stream,
299                                      level,
300                                      method,
301                                      windowbits,
302                                      memlevel,
303                                      strategy);
304 }
305 
306 int
cc_zlibglue_inflateInit2(void * stream,int windowbits)307 cc_zlibglue_inflateInit2(void * stream,
308                          int windowbits)
309 {
310   zlibglue_init();
311   return zlib_instance->inflateInit2(stream,
312                                      windowbits,
313                                      zlib_instance->zlibVersion(),
314                                      cc_gzm_sizeof_z_stream());
315 }
316 
317 int
cc_zlibglue_deflateEnd(void * stream)318 cc_zlibglue_deflateEnd(void * stream)
319 {
320   zlibglue_init();
321   return zlib_instance->deflateEnd(stream);
322 }
323 
324 int
cc_zlibglue_inflateEnd(void * stream)325 cc_zlibglue_inflateEnd(void * stream)
326 {
327   zlibglue_init();
328   return zlib_instance->inflateEnd(stream);
329 }
330 
331 int
cc_zlibglue_inflate(void * stream,int flush)332 cc_zlibglue_inflate(void * stream, int flush)
333 {
334   zlibglue_init();
335   return zlib_instance->inflate(stream, flush);
336 }
337 
338 int
cc_zlibglue_inflateReset(void * stream)339 cc_zlibglue_inflateReset(void * stream)
340 {
341   zlibglue_init();
342   return zlib_instance->inflateReset(stream);
343 }
344 
345 int
cc_zlibglue_deflateParams(void * stream,int level,int strategy)346 cc_zlibglue_deflateParams(void * stream, int level, int strategy)
347 {
348   zlibglue_init();
349   return zlib_instance->deflateParams(stream, level, strategy);
350 }
351 
352 int
cc_zlibglue_deflate(void * stream,int flush)353 cc_zlibglue_deflate(void * stream, int flush)
354 {
355   zlibglue_init();
356   return zlib_instance->deflate(stream, flush);
357 }
358 
359 void *
cc_zlibglue_gzopen(const char * path,const char * mode)360 cc_zlibglue_gzopen(const char * path, const char * mode)
361 {
362   zlibglue_init();
363   return zlib_instance->gzopen(path, mode);
364 }
365 
366 void *
cc_zlibglue_gzdopen(int fd,const char * mode)367 cc_zlibglue_gzdopen(int fd, const char * mode)
368 {
369   zlibglue_init();
370   return zlib_instance->gzdopen(fd, mode);
371 }
372 
373 int
cc_zlibglue_gzsetparams(void * fp,int level,int strategy)374 cc_zlibglue_gzsetparams(void * fp, int level, int strategy)
375 {
376   zlibglue_init();
377   return zlib_instance->gzsetparams(fp, level, strategy);
378 }
379 
380 int
cc_zlibglue_gzread(void * fp,void * buf,unsigned int len)381 cc_zlibglue_gzread(void * fp, void * buf, unsigned int len)
382 {
383   zlibglue_init();
384   return zlib_instance->gzread(fp, buf, len);
385 }
386 
387 int
cc_zlibglue_gzwrite(void * fp,const void * buf,unsigned int len)388 cc_zlibglue_gzwrite(void * fp, const void * buf, unsigned int len)
389 {
390   zlibglue_init();
391   return zlib_instance->gzwrite(fp, buf, len);
392 }
393 
394 off_t
cc_zlibglue_gzseek(void * fp,off_t offset,int whence)395 cc_zlibglue_gzseek(void * fp, off_t offset, int whence)
396 {
397   zlibglue_init();
398   return zlib_instance->gzseek(fp, offset, whence);
399 }
400 
401 int
cc_zlibglue_gzrewind(void * fp)402 cc_zlibglue_gzrewind(void * fp)
403 {
404   zlibglue_init();
405   return zlib_instance->gzrewind(fp);
406 }
407 
408 off_t
cc_zlibglue_gztell(void * fp)409 cc_zlibglue_gztell(void * fp)
410 {
411   zlibglue_init();
412   return zlib_instance->gztell(fp);
413 }
414 
415 int
cc_zlibglue_gzeof(void * fp)416 cc_zlibglue_gzeof(void * fp)
417 {
418   zlibglue_init();
419   return zlib_instance->gzeof(fp);
420 }
421 
422 int
cc_zlibglue_gzclose(void * fp)423 cc_zlibglue_gzclose(void * fp)
424 {
425   zlibglue_init();
426   return zlib_instance->gzclose(fp);
427 }
428 
429 int
cc_zlibglue_crc32(unsigned long crc,const char * buf,unsigned int len)430 cc_zlibglue_crc32(unsigned long crc, const char * buf, unsigned int len)
431 {
432   zlibglue_init();
433   return zlib_instance->crc32(crc, buf, len);
434 }
435 
436 #undef deflateInit2
437 #undef inflateInit2
438