// Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "emugl/common/shared_library.h" #include #include #include #ifndef _WIN32 #include #include #endif namespace emugl { // static SharedLibrary* SharedLibrary::open(const char* libraryName) { char error[1]; return open(libraryName, error, sizeof(error)); } #ifdef _WIN32 // static SharedLibrary* SharedLibrary::open(const char* libraryName, char* error, size_t errorSize) { HMODULE lib = LoadLibrary(libraryName); if (lib) { return new SharedLibrary(lib); } if (errorSize == 0) { return NULL; } // Convert error into human-readable message. DWORD errorCode = ::GetLastError(); LPSTR message = NULL; size_t messageLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &message, 0, NULL); int ret = snprintf(error, errorSize, "%.*s", (int)messageLen, message); if (ret < 0 || ret == static_cast(errorSize)) { // snprintf() on Windows doesn't behave as expected by C99, // this path is to ensure that the result is always properly // zero-terminated. ret = static_cast(errorSize - 1); error[ret] = '\0'; } // Remove any trailing \r\n added by FormatMessage if (ret > 0 && error[ret - 1] == '\n') { error[--ret] = '\0'; } if (ret > 0 && error[ret - 1] == '\r') { error[--ret] = '\0'; } return NULL; } SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {} SharedLibrary::~SharedLibrary() { if (mLib) { FreeLibrary(mLib); } } SharedLibrary::FunctionPtr SharedLibrary::findSymbol( const char* symbolName) const { if (!mLib || !symbolName) { return NULL; } return reinterpret_cast( GetProcAddress(mLib, symbolName)); } #else // !_WIN32 // static SharedLibrary* SharedLibrary::open(const char* libraryName, char* error, size_t errorSize) { const char* libPath = libraryName; char* path = NULL; const char* libBaseName = strrchr(libraryName, '/'); if (!libBaseName) { libBaseName = libraryName; } if (!strchr(libBaseName, '.')) { // There is no extension in this library name, so append one. #ifdef __APPLE__ static const char kDllExtension[] = ".dylib"; #else static const char kDllExtension[] = ".so"; #endif size_t pathLen = strlen(libraryName) + sizeof(kDllExtension); path = static_cast(malloc(pathLen)); snprintf(path, pathLen, "%s%s", libraryName, kDllExtension); libPath = path; } dlerror(); // clear error. #ifdef __APPLE__ // On OSX, some libraries don't include an extension (notably OpenGL) // On OSX we try to open |libraryName| first. If that doesn't exist, // we try |libraryName|.dylib void* lib = dlopen(libraryName, RTLD_NOW); if (lib == NULL) { lib = dlopen(libPath, RTLD_NOW); } #else void* lib = dlopen(libPath, RTLD_NOW); #endif if (path) { free(path); } if (lib) { return new SharedLibrary(lib); } snprintf(error, errorSize, "%s", dlerror()); return NULL; } SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {} SharedLibrary::~SharedLibrary() { if (mLib) { dlclose(mLib); } } SharedLibrary::FunctionPtr SharedLibrary::findSymbol( const char* symbolName) const { if (!mLib || !symbolName) { return NULL; } return reinterpret_cast(dlsym(mLib, symbolName)); } #endif // !_WIN32 } // namespace emugl