1/* Copyright (C) 2011 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include <android/utils/dll.h>
13#include <android/utils/system.h>
14#include <android/utils/path.h>
15
16#include <stdlib.h>
17
18/* Utility function, append one string to another, caller must free result */
19static char*
20append_string( const char* str1, const char* str2 )
21{
22    int   len1   = strlen(str1);
23    int   len2   = strlen(str2);
24    char* result = malloc(len1+len2+1);
25
26    if (result != NULL) {
27        memcpy(result, str1, len1);
28        memcpy(result + len1, str2, len2);
29        result[len1+len2] = '\0';
30    }
31    return result;
32}
33
34#ifdef _WIN32
35
36#include <windows.h>
37
38/* This function is used to revert all forward slashes (/) in a path
39 * string into unquoted backwards one (\). This is necessary because
40 * LoadLibrary() and AddDllDirectory() do not support forward slashes.
41 *
42 * Caller must free the result string
43 */
44static char*
45reverse_slashes( const char* path )
46{
47    int   len    = strlen(path);
48    char* result = malloc(len+1);
49    int   nn;
50
51    for (nn = 0; nn < len; nn++) {
52        int ch = path[nn];
53        if (ch == '/') {
54            ch = '\\';
55        }
56        result[nn] = (char)ch;
57    }
58    result[nn] = '\0';
59
60    return result;
61}
62
63ADynamicLibrary*
64adynamicLibrary_open( const char*  libraryName,
65                      char**       pError)
66{
67    char*  libName = (char*) libraryName;
68    void*  result;
69
70    /* Append a .dll to the library name if it doesn't have an extension */
71    if (strchr(libraryName,'.') == NULL) {
72        libName = append_string(libraryName, ".dll");
73    }
74
75    /* Now do our magic */
76    *pError = NULL;
77    result = (ADynamicLibrary*) LoadLibrary( libName );
78    if (result == NULL) {
79        *pError = ASTRDUP("Could not load DLL!");
80    }
81
82    /* Free the library name if we modified it */
83    if (libName != libraryName) {
84        free(libName);
85    }
86
87    return (ADynamicLibrary*) result;
88}
89
90void*
91adynamicLibrary_findSymbol( ADynamicLibrary*  lib,
92                            const char*       symbolName,
93                            char**            pError)
94{
95    void* result;
96
97    *pError = NULL;
98
99    if (lib == NULL) {
100        *pError = strdup("NULL library pointer");
101        return NULL;
102    }
103    if (symbolName == NULL || symbolName[0] == '\0') {
104        *pError = strdup("NULL or empty symbolName");
105        return NULL;
106    }
107    result = GetProcAddress( (HMODULE)lib, symbolName );
108    if (result == NULL) {
109        *pError = ASTRDUP("Could not find symbol");
110    }
111    return result;
112}
113
114/* Close/unload a given dynamic library */
115void
116adynamicLibrary_close( ADynamicLibrary*  lib )
117{
118    if (lib != NULL) {
119        FreeLibrary( (HMODULE)lib );
120    }
121}
122
123#else /* !_WIN32 */
124
125#include <dlfcn.h>
126#include <stdlib.h>
127
128ADynamicLibrary*
129adynamicLibrary_open( const char*  libraryName,
130                      char**       pError)
131{
132    char*  libName = (char*) libraryName;
133    void*  result;
134
135#ifdef __APPLE__
136#  define SO_EXTENSION ".dylib"
137#else
138#  define SO_EXTENSION ".so"
139#endif
140
141    /* Append a .so to the library name if it doesn't have an extension */
142    if (strchr(libraryName,'.') == NULL) {
143        libName = append_string(libraryName, SO_EXTENSION);
144    }
145
146    /* Now do our magic */
147    *pError = NULL;
148    result  = dlopen( libName, RTLD_LAZY );
149    if (result == NULL) {
150        *pError = strdup(dlerror());
151    }
152
153    /* Free the library name if we modified it */
154    if (libName != (char*)libraryName) {
155        free(libName);
156    }
157
158    return (ADynamicLibrary*) result;
159}
160
161void*
162adynamicLibrary_findSymbol( ADynamicLibrary*  lib,
163                            const char*       symbolName,
164                            char**            pError)
165{
166    void* result;
167
168    *pError = NULL;
169
170    if (lib == NULL) {
171        *pError = strdup("NULL library pointer");
172        return NULL;
173    }
174    if (symbolName == NULL || symbolName[0] == '\0') {
175        *pError = strdup("NULL or empty symbolName");
176        return NULL;
177    }
178    result = dlsym(lib, symbolName);
179    if (result == NULL) {
180        *pError = strdup(dlerror());
181    }
182    return result;
183}
184
185/* Close/unload a given dynamic library */
186void
187adynamicLibrary_close( ADynamicLibrary*  lib )
188{
189    if (lib != NULL) {
190        dlclose(lib);
191    }
192}
193
194#endif /* !_WIN32 */
195