1/*---------------------------------------------------------------------------*
2 |              PDFlib - A library for generating PDF on the fly             |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 |                                                                           |
7 |    This software is subject to the PDFlib license. It is NOT in the       |
8 |    public domain. Extended versions and commercial licenses are           |
9 |    available, please check http://www.pdflib.com.                         |
10 |                                                                           |
11 *---------------------------------------------------------------------------*/
12
13/* $Id: pdflibdl.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * C wrapper code for dynamically loading the PDFlib DLL at runtime.
16 *
17 * This module is not supported on all platforms.
18 *
19 */
20
21#include <stdlib.h>
22
23#include "pdflibdl.h"
24
25/* enable this to avoid error messages */
26//#define PDF_SILENT
27
28/* ---------------------------------- WIN32 ----------------------------- */
29
30#ifdef WIN32
31
32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
34#include <winbase.h>
35#undef WIN32_LEAN_AND_MEAN
36
37#define PDF_DLLNAME			"pdflib.dll"
38
39static void *
40pdf_dlopen(const char *filename)
41{
42    return (void *) LoadLibrary(filename);
43}
44
45static void *
46pdf_dlsym(void *handle, const char *funcname)
47{
48    return (void *) GetProcAddress((HINSTANCE) handle, funcname);
49}
50
51static void
52pdf_dlclose(void *handle)
53{
54    (void) FreeLibrary((HINSTANCE) handle);
55}
56
57/* ---------------------------------- MVS ----------------------------- */
58
59#elif defined(__MVS__)
60
61#include <dynit.h>
62#include <dll.h>
63
64#define PDF_DLLNAME			"PDFLIB"
65
66static void *
67pdf_dlopen(const char *filename)
68{
69    return dllload(filename);
70}
71
72static void *
73pdf_dlsym(void *handle, const char *funcname)
74{
75    return dllqueryfn((dllhandle *) handle, funcname);
76}
77
78static void pdf_dlclose(void *handle)
79{
80    (void) dllfree((dllhandle *) handle);
81}
82
83/* ---------------------------------- Linux  ----------------------------- */
84
85#elif defined(linux)
86
87#include <dlfcn.h>
88
89#define PDF_DLLNAME			"libpdf.so"
90
91static void *
92pdf_dlopen(const char *filename)
93{
94    return dlopen(filename, RTLD_LAZY);
95}
96
97static void *
98pdf_dlsym(void *handle, const char *funcname)
99{
100    return dlsym(handle, funcname);
101}
102
103static void pdf_dlclose(void *handle)
104{
105    (void) dlclose(handle);
106}
107
108/* ---------------------------------- Mac OS X  ----------------------------- */
109
110#elif defined(__ppc__) && defined(__APPLE__)
111
112#define PDF_DLLNAME			"libpdf.dylib"
113
114/*
115 * The dl code for Mac OS X has been butchered from dlcompat,
116 * see http://www.opendarwin.org/projects/dlcompat
117 * It contained the copyright notice below.
118 */
119
120/*
121Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net>
122
123Permission is hereby granted, free of charge, to any person obtaining
124a copy of this software and associated documentation files (the
125"Software"), to deal in the Software without restriction, including
126without limitation the rights to use, copy, modify, merge, publish,
127distribute, sublicense, and/or sell copies of the Software, and to
128permit persons to whom the Software is furnished to do so, subject to
129the following conditions:
130
131The above copyright notice and this permission notice shall be
132included in all copies or substantial portions of the Software.
133
134THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
135EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
136MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
137NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
138LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
139OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
140WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
141*/
142
143#include <string.h>
144#include <mach-o/dyld.h>
145
146#if defined (__GNUC__) && __GNUC__ > 3
147#define dl_restrict __restrict
148#else
149#define dl_restrict
150#endif
151/*
152 * Structure filled in by dladdr().
153 */
154
155typedef struct dl_info {
156        const char      *dli_fname;     /* Pathname of shared object */
157        void            *dli_fbase;     /* Base address of shared object */
158        const char      *dli_sname;     /* Name of nearest symbol */
159        void            *dli_saddr;     /* Address of nearest symbol */
160} Dl_info;
161
162#define RTLD_LAZY	0x1
163#define RTLD_NOW	0x2
164#define RTLD_LOCAL	0x4
165#define RTLD_GLOBAL	0x8
166#define RTLD_NOLOAD	0x10
167#define RTLD_NODELETE	0x80
168
169/*
170 * Special handle arguments for dlsym().
171 */
172#define	RTLD_NEXT		((void *) -1)	/* Search subsequent objects. */
173#define	RTLD_DEFAULT	((void *) -2)	/* Use default search algorithm. */
174
175static void *dlsymIntern(void *handle, const char *symbol);
176
177void *pdf_dlopen(const char *path)
178{
179    int mode = RTLD_LAZY;
180    void *module = 0;
181    NSObjectFileImage ofi = 0;
182    NSObjectFileImageReturnCode ofirc;
183    static int (*make_private_module_public) (NSModule module) = 0;
184    unsigned int flags =
185	NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
186
187/* If we got no path, the app wants the global namespace, use -1 as the marker
188       in this case */
189    if (!path)
190	    return (void *)-1;
191
192    /* Create the object file image, works for things linked with the
193	-bundle arg to ld */
194    ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
195    switch (ofirc)
196    {
197	case NSObjectFileImageSuccess:
198		/* It was okay, so use NSLinkModule to link in the image */
199		if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
200		module = NSLinkModule(ofi, path,flags);
201    /* Don't forget to destroy the object file image, unless you like leaks */
202		NSDestroyObjectFileImage(ofi);
203	    /* If the mode was global, then change the module, this avoids
204	       multiply defined symbol errors to first load private then make
205	       global. Silly, isn't it. */
206		if ((mode & RTLD_GLOBAL))
207		{
208		  if (!make_private_module_public)
209		  {
210		    _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
211			(unsigned long *)&make_private_module_public);
212		  }
213		  make_private_module_public(module);
214		}
215		break;
216	case NSObjectFileImageInappropriateFile:
217/* It may have been a dynamic library rather than a bundle, try to load it */
218		module =
219		    (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
220		break;
221	case NSObjectFileImageFailure:
222		/*
223		error(0,"Object file setup failure :  \"%s\"", path);
224		*/
225		return 0;
226	case NSObjectFileImageArch:
227		/*
228		error(0,"No object for this architecture :  \"%s\"", path);
229		*/
230		return 0;
231	case NSObjectFileImageFormat:
232		/*
233		error(0,"Bad object file format :  \"%s\"", path);
234		*/
235		return 0;
236	case NSObjectFileImageAccess:
237		/*
238		error(0,"Can't read object file :  \"%s\"", path);
239		*/
240		return 0;
241    }
242    if (!module)
243	    /*
244	    error(0, "Can not open \"%s\"", path);
245	    */
246	    ;
247
248    return module;
249}
250
251/* dlsymIntern is used by dlsym to find the symbol */
252void *dlsymIntern(void *handle, const char *symbol)
253{
254    NSSymbol *nssym = 0;
255    /* If the handle is -1, if is the app global context */
256    if (handle == (void *)-1)
257    {
258	/* Global context, use NSLookupAndBindSymbol */
259	if (NSIsSymbolNameDefined(symbol))
260	{
261		nssym = NSLookupAndBindSymbol(symbol);
262	}
263
264    }
265    /* Now see if the handle is a struch mach_header* or not, use
266	NSLookupSymbol in image for libraries, and NSLookupSymbolInModule
267	for bundles */
268    else
269    {
270    /* Check for both possible magic numbers depending on x86/ppc byte order */
271	if ((((struct mach_header *)handle)->magic == MH_MAGIC) ||
272		(((struct mach_header *)handle)->magic == MH_CIGAM))
273	{
274	if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol))
275	    {
276		nssym = NSLookupSymbolInImage((struct mach_header *)handle,
277			symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
278			| NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
279	    }
280
281	}
282	else
283	{
284		nssym = NSLookupSymbolInModule(handle, symbol);
285	}
286    }
287    if (!nssym)
288    {
289	/*
290	error(0, "Symbol \"%s\" Not found", symbol);
291	*/
292	return NULL;
293    }
294    return NSAddressOfSymbol(nssym);
295}
296
297int pdf_dlclose(void *handle)
298{
299    if ((((struct mach_header *)handle)->magic == MH_MAGIC) ||
300	    (((struct mach_header *)handle)->magic == MH_CIGAM))
301    {
302	    /*
303	    error(-1, "Can't remove dynamic libraries on darwin");
304	    */
305	    return 0;
306    }
307    if (!NSUnLinkModule(handle, 0))
308    {
309	    /*
310	    error(0, "unable to unlink module %s", NSNameOfModule(handle));
311	    */
312	    return 1;
313    }
314    return 0;
315}
316
317/* dlsym, prepend the underscore and call dlsymIntern */
318void *pdf_dlsym(void *handle, const char *symbol)
319{
320    static char undersym[257];	/* Saves calls to malloc(3) */
321    int sym_len = strlen(symbol);
322    void *value = NULL;
323    char *malloc_sym = NULL;
324
325    if (sym_len < 256)
326    {
327	    snprintf(undersym, 256, "_%s", symbol);
328	    value = dlsymIntern(handle, undersym);
329    }
330    else
331    {
332	    malloc_sym = malloc(sym_len + 2);
333	    if (malloc_sym)
334	    {
335		    sprintf(malloc_sym, "_%s", symbol);
336		    value = dlsymIntern(handle, malloc_sym);
337		    free(malloc_sym);
338	    }
339	    else
340	    {
341		    /*
342		    error(-1, "Unable to allocate memory");
343		    */
344	    }
345    }
346    return value;
347}
348
349/* ---------------------------------- AS/400  ----------------------------- */
350
351#elif defined __ILEC400__
352
353#include <string.h>
354
355#include <miptrnam.h>
356#include <qleawi.h>
357#include <qusec.h>
358#include "mgosifc.h"
359
360#define PDF_DLLNAME			"PDFLIB"
361
362static void *
363pdf_dlopen(const char *filename)
364{
365    char libName[11], objName[11], *s;
366    HMODULE handle;
367    _SYSPTR pSrvPgm;
368    Qle_ABP_Info_t actInfo;
369    int actInfoLen;
370    Qus_EC_t errCode;
371
372    memset(libName, '\0', sizeof(libName));
373    if ((s = strchr(filename, '/')) == NULL) {
374	s = filename;
375    } else {
376	memcpy(libName, filename,  s - filename);
377	if (!strcmp(libName, "*LIBL"))
378	    libName[0] = '\0';
379	s += 1;
380    }
381    strcpy(objName, s);
382
383    /* Get system pointer to service program */
384    pSrvPgm = rslvsp(WLI_SRVPGM, objName, libName, _AUTH_NONE);
385
386    /* Activate Bound Program */
387    handle = malloc(sizeof(int));
388    actInfoLen = sizeof(actInfo);
389    errCode.Bytes_Provided = sizeof(errCode);
390    QleActBndPgm(&pSrvPgm, handle, &actInfo, &actInfoLen, &errCode);
391
392    if (errCode.Bytes_Available > 0)
393	return NULL;
394
395    return (void *) handle;
396}
397
398static void *
399pdf_dlsym(void *handle, const char *funcname)
400{
401    int expID;
402    int expNameLen;
403    void *ret;
404    int expType;
405    Qus_EC_t errCode;
406
407    expID = 0;
408    expNameLen = strlen(funcname);
409    errCode.Bytes_Provided = sizeof(errCode);
410    QleGetExp((HMODULE) handle,
411	&expID, &expNameLen, funcname, &ret, &expType, &errCode);
412
413    if (errCode.Bytes_Available > 0)
414	return NULL;
415
416    return ret;
417}
418
419static void pdf_dlclose(void *handle)
420{
421    free((HMODULE) handle);
422}
423
424/* ---------------------------------- unknown  ----------------------------- */
425
426#else
427
428#error No DLL loading code for this platform available!
429
430#endif
431
432/* ---------------------------------- generic  ----------------------------- */
433
434static void
435pdf_dlerror(const char *msg)
436{
437#ifndef PDF_SILENT
438    fprintf(stderr, msg);
439#endif
440}
441
442/* Load the PDFlib DLL and fetch the API structure */
443
444PDFLIB_API PDFlib_api * PDFLIB_CALL
445PDF_new_dl(PDF **pp)
446{
447    PDFlib_api *PDFlib, *(PDFLIB_CALL *get_api)(void);
448    char buf[256];
449    void *handle;
450    PDF *p;
451
452    /* load the PDFLIB DLL... */
453    handle = pdf_dlopen(PDF_DLLNAME);
454
455    if (!handle)
456    {
457	pdf_dlerror("Error: couldn't load PDFlib DLL\n");
458	return NULL;
459    }
460
461    /* ...and fetch function pointers */
462    get_api = (PDFlib_api *(PDFLIB_CALL *)(void))
463		pdf_dlsym(handle, "PDF_get_api");
464
465    if (get_api == NULL)
466    {
467	pdf_dlerror(
468	    "Error: couldn't find function PDF_get_api in PDFlib DLL\n");
469	pdf_dlclose(handle);
470	return NULL;
471    }
472
473    /* Fetch the API structure and boot the library. */
474    PDFlib = (*get_api)();
475
476    /*
477     * Check the version number of the loaded DLL against that of
478     * the included header file to avoid version mismatch.
479     */
480
481    if (PDFlib->sizeof_PDFlib_api != sizeof(PDFlib_api) ||
482	PDFlib->major != PDFLIB_MAJORVERSION ||
483	PDFlib->minor != PDFLIB_MINORVERSION) {
484	sprintf(buf,
485	"Error: loaded wrong version of PDFlib DLL\n"
486	"Expected version %d.%d (API size %d), loaded %d.%d (API size %d)\n",
487	PDFLIB_MAJORVERSION, PDFLIB_MINORVERSION, sizeof(PDFlib_api),
488	PDFlib->major, PDFlib->minor, PDFlib->sizeof_PDFlib_api);
489	pdf_dlerror(buf);
490	pdf_dlclose(handle);
491	return NULL;
492    }
493
494    /* Boot the library. */
495    PDFlib->PDF_boot();
496
497    /*
498     * Create a new PDFlib object; use PDF_new2() so that we can store
499     * the DLL handle within PDFlib and later retrieve it.
500     */
501    if ((p = PDFlib->PDF_new2(NULL, NULL, NULL, NULL, handle)) == (PDF *) NULL)
502    {
503        pdf_dlerror("Couldn't create PDFlib object (out of memory)!\n");
504        return NULL;
505    }
506
507    /* Make the PDF * available to the client and return */
508    *pp = p;
509    return PDFlib;
510}
511
512/* delete the PDFlib object and unload the previously loaded PDFlib DLL */
513
514PDFLIB_API void PDFLIB_CALL
515PDF_delete_dl(PDFlib_api *PDFlib, PDF *p)
516{
517    void *handle;
518
519    if (!PDFlib || !p)
520	return;
521
522    /* fetch the DLL handle (previously stored in PDFlib) */
523    handle = PDFlib->PDF_get_opaque(p);
524
525    if (!handle)
526	return;
527
528    PDFlib->PDF_delete(p);
529    PDFlib->PDF_shutdown();
530
531    pdf_dlclose(handle);
532}
533