From 816e53ca385b64c18c9c7cfca569c4d747634e97 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 17 Aug 2011 18:33:45 +0200 Subject: Add DLL-loading head This patch adds several functions to make loading shared libraries dynamically easier. This will be used to load the GLES emulation libraries. Change-Id: Ib401af339530bc647bfa86fb23a2840fe0a201dd --- android/utils/dll.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++ android/utils/dll.h | 44 ++++++++++++ android/utils/path.c | 55 +++++++++++++++ android/utils/path.h | 6 ++ 4 files changed, 299 insertions(+) create mode 100644 android/utils/dll.c create mode 100644 android/utils/dll.h (limited to 'android/utils') diff --git a/android/utils/dll.c b/android/utils/dll.c new file mode 100644 index 0000000..a46a462 --- /dev/null +++ b/android/utils/dll.c @@ -0,0 +1,194 @@ +/* Copyright (C) 2011 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include +#include +#include + +#include + +/* Utility function, append one string to another, caller must free result */ +static char* +append_string( const char* str1, const char* str2 ) +{ + int len1 = strlen(str1); + int len2 = strlen(str2); + char* result = malloc(len1+len2+1); + + if (result != NULL) { + memcpy(result, str1, len1); + memcpy(result + len1, str2, len2); + result[len1+len2] = '\0'; + } + return result; +} + +#ifdef _WIN32 + +#include + +/* This function is used to revert all forward slashes (/) in a path + * string into unquoted backwards one (\). This is necessary because + * LoadLibrary() and AddDllDirectory() do not support forward slashes. + * + * Caller must free the result string + */ +static char* +reverse_slashes( const char* path ) +{ + int len = strlen(path); + char* result = malloc(len+1); + int nn; + + for (nn = 0; nn < len; nn++) { + int ch = path[nn]; + if (ch == '/') { + ch = '\\'; + } + result[nn] = (char)ch; + } + result[nn] = '\0'; + + return result; +} + +ADynamicLibrary* +adynamicLibrary_open( const char* libraryName, + char** pError) +{ + char* libName = (char*) libraryName; + void* result; + + /* Append a .dll to the library name if it doesn't have an extension */ + if (strchr(libraryName,'.') == NULL) { + libName = append_string(libraryName, ".dll"); + } + + /* Now do our magic */ + *pError = NULL; + result = (ADynamicLibrary*) LoadLibrary( libName ); + if (result == NULL) { + *pError = ASTRDUP("Could not load DLL!"); + } + + /* Free the library name if we modified it */ + if (libName != libraryName) { + free(libName); + } + + return (ADynamicLibrary*) result; +} + +void* +adynamicLibrary_findSymbol( ADynamicLibrary* lib, + const char* symbolName, + char** pError) +{ + void* result; + + *pError = NULL; + + if (lib == NULL) { + *pError = strdup("NULL library pointer"); + return NULL; + } + if (symbolName == NULL || symbolName[0] == '\0') { + *pError = strdup("NULL or empty symbolName"); + return NULL; + } + result = GetProcAddress( (HMODULE)lib, symbolName ); + if (result == NULL) { + *pError = ASTRDUP("Could not find symbol"); + } + return result; +} + +/* Close/unload a given dynamic library */ +void +adynamicLibrary_close( ADynamicLibrary* lib ) +{ + if (lib != NULL) { + FreeLibrary( (HMODULE)lib ); + } +} + +#else /* !_WIN32 */ + +#include +#include + +ADynamicLibrary* +adynamicLibrary_open( const char* libraryName, + char** pError) +{ + char* libName = (char*) libraryName; + void* result; + +#ifdef __APPLE__ +# define SO_EXTENSION ".dylib" +#else +# define SO_EXTENSION ".so" +#endif + + /* Append a .so to the library name if it doesn't have an extension */ + if (strchr(libraryName,'.') == NULL) { + libName = append_string(libraryName, SO_EXTENSION); + } + + /* Now do our magic */ + *pError = NULL; + result = dlopen( libName, RTLD_LAZY ); + if (result == NULL) { + *pError = strdup(dlerror()); + } + + /* Free the library name if we modified it */ + if (libName != (char*)libraryName) { + free(libName); + } + + return (ADynamicLibrary*) result; +} + +void* +adynamicLibrary_findSymbol( ADynamicLibrary* lib, + const char* symbolName, + char** pError) +{ + void* result; + + *pError = NULL; + + if (lib == NULL) { + *pError = strdup("NULL library pointer"); + return NULL; + } + if (symbolName == NULL || symbolName[0] == '\0') { + *pError = strdup("NULL or empty symbolName"); + return NULL; + } + result = dlsym(lib, symbolName); + if (result == NULL) { + *pError = strdup(dlerror()); + } + return result; +} + +/* Close/unload a given dynamic library */ +void +adynamicLibrary_close( ADynamicLibrary* lib ) +{ + if (lib != NULL) { + dlclose(lib); + } +} + +#endif /* !_WIN32 */ diff --git a/android/utils/dll.h b/android/utils/dll.h new file mode 100644 index 0000000..66f3a6d --- /dev/null +++ b/android/utils/dll.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2011 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef ANDROID_UTILS_DLL_H +#define ANDROID_UTILS_DLL_H + +/* Opaque type to model a dynamic library handle */ +typedef struct ADynamicLibrary ADynamicLibrary; + +/* Try to load/open a dynamic library named 'libraryName', looking for + * it in the optional paths listed by 'libraryPaths'. + * + * Once opened, you can use adynamicLibrary_findSymbol() and + * adynamicLibrary_close() on it. + * + * libraryName :: library name, if no extension is provided, then '.so' + * will be appended on Unix systems, or '.dll' on Windows. + * + * pError :: On success, '*pError' will be set to NULL. On error, it will + * point to a string describing the error, which must be freed by + * the caller. + * + * returns an ADynamicLibrary pointer. + */ +ADynamicLibrary* adynamicLibrary_open( const char* libraryName, + char** pError); + +/* Find a symbol inside a dynamic library. */ +void* adynamicLibrary_findSymbol( ADynamicLibrary* lib, + const char* symbolName, + char** pError); + +/* Close/unload a given dynamic library */ +void adynamicLibrary_close( ADynamicLibrary* lib ); + +#endif /* ANDROID_UTILS_DLL_H */ diff --git a/android/utils/path.c b/android/utils/path.c index f64e517..1bcdc4e 100644 --- a/android/utils/path.c +++ b/android/utils/path.c @@ -427,6 +427,61 @@ path_is_absolute( const char* path ) #endif } +char* +path_get_absolute( const char* path ) +{ + if (path_is_absolute(path)) { + return ASTRDUP(path); + } + +#ifdef _WIN32 + { + char* result; + int pathLen = strlen(path); + int currentLen = GetCurrentDirectory(0, NULL); + + if (currentLen <= 0) { + /* Could not get size of working directory. something is + * really fishy here, return a simple copy */ + return ASTRDUP(path); + } + result = malloc(currentLen + pathLen + 2); + + GetCurrentDirectory(currentLen+1, result); + if (currentLen == 0 || result[currentLen-1] != '\\') { + result[currentLen++] = '\\'; + } + memcpy(result + currentLen, path, pathLen+1); + + return result; + } +#else + { + int pathLen = strlen(path); + char currentDir[PATH_MAX]; + int currentLen; + char* result; + + if (getcwd(currentDir, sizeof(currentDir)) == NULL) { + /* Could not get the current working directory. something is really + * fishy here, so don't do anything and return a copy */ + return ASTRDUP(path); + } + + /* Make a new path with / */ + currentLen = strlen(currentDir); + result = malloc(currentLen + pathLen + 2); + + memcpy(result, currentDir, currentLen); + if (currentLen == 0 || result[currentLen-1] != '/') { + result[currentLen++] = '/'; + } + memcpy(result + currentLen, path, pathLen+1); + + return result; + } +#endif +} /** OTHER FILE UTILITIES ** diff --git a/android/utils/path.h b/android/utils/path.h index 419e6bf..2926e5e 100644 --- a/android/utils/path.h +++ b/android/utils/path.h @@ -118,6 +118,12 @@ extern char* path_basename( const char* path ); */ extern char* path_search_exec( const char* filename ); +/* Return the absolute version of a path. If 'path' is already absolute, + * this will be a simple copy. Otherwise, this function will prepend the + * current working directory to the result. + */ +extern char* path_get_absolute( const char* path ); + /** OTHER FILE UTILITIES ** ** path_empty_file() creates an empty file at a given path location. -- cgit v1.1