1 /*
2 Copyright (C) 2005-2007 Feeling Software Inc.
3 Portions of the code are:
4 Copyright (C) 2005-2007 Sony Computer Entertainment America
5
6 MIT License: http://www.opensource.org/licenses/mit-license.php
7 */
8
9 #include "StdAfx.h"
10 #include "FUPlugin.h"
11 #include "FUPluginManager.h"
12 #include "FUFileManager.h"
13
14 #ifdef WIN32
15 #include <io.h>
16 #if defined(UNICODE)
17 #define ffinddata _wfinddata_t
18 #define ffindfirst _wfindfirst
19 #define ffindclose _findclose
20 #define ffindnext _wfindnext
21 #else // UNICODE
22 #define ffinddata _finddata_t
23 #define ffindfirst _findfirst
24 #define ffindclose _findclose
25 #define ffindnext _findnext
26 #endif
27 #elif defined(__APPLE__) || defined(LINUX)
28 #include <dlfcn.h>
29 #include <dirent.h>
30 #endif //WIN32
31
32 //
33 // FUPlugin
34 //
35
36 ImplementObjectType(FUPlugin);
37
38 //
39 // FUPluginManager
40 //
41
FUPluginManager(const fchar * UNUSED (_filter))42 FUPluginManager::FUPluginManager(const fchar* UNUSED(_filter))
43 {
44 #if 0 // disabled because it causes loads of valgrind warnings on Linux
45 fstring applicationFolderName = FUFileManager::GetApplicationFolderName();
46 if (!applicationFolderName.empty())
47 {
48 LoadPluginsInFolderName(applicationFolderName, _filter);
49 }
50
51 fstring moduleFolderName = FUFileManager::GetModuleFolderName();
52 if (!moduleFolderName.empty() && !IsEquivalent(moduleFolderName, applicationFolderName))
53 {
54 LoadPluginsInFolderName(moduleFolderName, _filter);
55 }
56 #endif
57 }
58
LoadPluginsInFolderName(const fstring & folderName,const fchar * _filter)59 void FUPluginManager::LoadPluginsInFolderName(const fstring& folderName, const fchar* _filter)
60 {
61 // Append the wanted extension for the plugins.
62 FUStringBuilder pluginFolder(folderName);
63 fchar lastChar = folderName[pluginFolder.length() - 1];
64 if (lastChar != '\\' && lastChar != '/') pluginFolder.append((fchar) '/');
65 pluginFolder.append(FC("Plugins/"));
66 pluginFolderName = pluginFolder.ToString();
67
68 if (_filter == NULL || _filter[0] == 0) _filter = FC("*.*");
69 do
70 {
71 const fchar* nextFilter = fstrchr(_filter, '|');
72 fstring filter(_filter);
73 if (nextFilter != NULL)
74 {
75 filter.erase(nextFilter - _filter);
76 ++nextFilter; // skip the pipe.
77 }
78 _filter = nextFilter;
79
80 // Windows-only for now.
81 #if defined(WIN32)
82 size_t filterLength = filter.length();
83 // Iterate over all the filtered files within the given folder.
84 ffinddata folderIterator;
85 fstring searchString = pluginFolderName + filter;
86 intptr_t folderHandle = ffindfirst(searchString.c_str(), &folderIterator);
87 if (folderHandle != -1L)
88 {
89 int32 isDone = FALSE;
90 while (isDone == FALSE)
91 {
92 bool keep = false;
93 PluginLibrary* library = new PluginLibrary();
94 library->filename = pluginFolderName + folderIterator.name;
95
96 // work around for wildcards and 3 letter extensions that pick up 3+ letter extensions
97 // e.g. "dir *.fvp" in command prompt on a directory with "a.fvp", "a.fvpa", and "a.dll" returns
98 // "a.fvp" and "a.fvpa"
99 bool checkModule = true;
100 if (filterLength > 3)
101 {
102 if ((filter.at(filterLength-4) == FC('.')) && (filter.at(filterLength-3) != FC('*')) &&
103 (filter.at(filterLength-2) != FC('*')) && (filter.at(filterLength-1) != FC('*')))
104 {
105 size_t filepathLength = fstrlen(folderIterator.name);
106 checkModule = (folderIterator.name[filepathLength-4] == filter.at(filterLength-4)) &&
107 (folderIterator.name[filepathLength-3] == filter.at(filterLength-3)) &&
108 (folderIterator.name[filepathLength-2] == filter.at(filterLength-2)) &&
109 (folderIterator.name[filepathLength-1] == filter.at(filterLength-1));
110 }
111 }
112
113 library->module = LoadLibrary(library->filename.c_str());
114 if (checkModule && (library->module != NULL))
115 {
116 // Retrieve the necessary callbacks
117 library->getPluginCount = (GetPluginCount) GetProcAddress(library->module, "GetPluginCount");
118 library->getPluginType = (GetPluginType) GetProcAddress(library->module, "GetPluginType");
119 library->createPlugin = (CreatePlugin) GetProcAddress(library->module, "CreatePlugin");
120 keep = library->createPlugin != NULL && library->getPluginType != NULL && library->getPluginCount != NULL;
121 }
122
123 // This is a valid library.
124 if (keep) loadedLibraries.push_back(library);
125 else { SAFE_DELETE(library); }
126 isDone = ffindnext(folderHandle, &folderIterator);
127 }
128 ffindclose(folderHandle);
129 }
130
131 #elif defined(__APPLE__) || defined(LINUX)
132 fm::string s_filter = TO_STRING(filter);
133 if (s_filter.length() > 0 && s_filter.front() == '*') s_filter.erase(0, 1);
134 if (s_filter.length() > 0 && s_filter.back() == '*') s_filter.pop_back();
135
136 DIR* directory = opendir(TO_STRING(pluginFolderName).c_str());
137 if (directory == NULL) continue;
138
139 dirent* directoryEntry;
140 while ((directoryEntry = readdir(directory)) != NULL)
141 {
142 if (directoryEntry->d_type == DT_DIR) continue; // skip sub-folders.
143 if (strstr((const char*) directoryEntry->d_name, s_filter.c_str()) != NULL)
144 {
145 // We have a match.
146 bool keep = false;
147 PluginLibrary* library = new PluginLibrary();
148 library->filename = pluginFolderName + TO_FSTRING((const char*) directoryEntry->d_name);
149 fm::string libraryModuleFilename = TO_STRING(library->filename);
150 DEBUG_OUT("Found dynamic library: %s\n", libraryModuleFilename.c_str());
151 library->module = dlopen(libraryModuleFilename.c_str(), RTLD_NOW);
152 if (library->module != NULL)
153 {
154 // Retrieve the necessary callbacks
155 library->getPluginCount = (GetPluginCount) dlsym(library->module, "GetPluginCount");
156 library->getPluginType = (GetPluginType) dlsym(library->module, "GetPluginType");
157 library->createPlugin = (CreatePlugin) dlsym(library->module, "CreatePlugin");
158 keep = library->createPlugin != NULL && library->getPluginType != NULL && library->getPluginCount != NULL;
159 }
160
161 // This is a valid library.
162 if (keep) loadedLibraries.push_back(library);
163 else { SAFE_DELETE(library); }
164 }
165 }
166 closedir(directory);
167
168 #endif // WIN32
169 } while (_filter != NULL);
170 }
171
~FUPluginManager()172 FUPluginManager::~FUPluginManager()
173 {
174 UnloadPlugins();
175 FUAssert(loadedPlugins.empty(), return);
176
177 // Detach all the plugin libraries.
178 for (PluginLibraryList::iterator it = loadedLibraries.begin(); it != loadedLibraries.end(); ++it)
179 {
180 #if defined(WIN32)
181 if ((*it)->module != NULL) FreeLibrary((*it)->module);
182 #elif defined(LINUX) || defined(__APPLE__)
183 if ((*it)->module != NULL) dlclose((*it)->module);
184 #endif // WIN32
185 }
186 CLEAR_POINTER_VECTOR(loadedLibraries);
187 }
188
LoadPlugins(const FUObjectType & pluginType)189 void FUPluginManager::LoadPlugins(const FUObjectType& pluginType)
190 {
191 for (PluginLibraryList::iterator it = loadedLibraries.begin(); it != loadedLibraries.end(); ++it)
192 {
193 #ifndef _DEBUG
194 try
195 #endif // _DEBUG
196 {
197 DEBUG_OUT("Loading plug-in: %s\n", TO_STRING((*it)->filename).c_str());
198 FUAssert((*it)->createPlugin != NULL && (*it)->getPluginType != NULL && (*it)->getPluginCount != NULL, continue);
199 uint32 pluginCount = (*((*it)->getPluginCount))();
200 for (uint32 i = 0; i < pluginCount; ++i)
201 {
202 // Retrieve the types of all the plug-ins within this library.
203 // Compare them against the wanted types and create the wanted plug-ins.
204 const FUObjectType* type = (*((*it)->getPluginType))(i);
205 if (type->Includes(pluginType))
206 {
207 FUPlugin* plugin = (*((*it)->createPlugin))(i);
208 if (plugin == NULL) continue;
209 loadedPlugins.push_back(plugin);
210 }
211 }
212 }
213 #ifndef _DEBUG
214 catch (...)
215 {
216 fm::string _filename = TO_STRING((*it)->filename);
217 ERROR_OUT("Unhandled exception when loading plugin: %s.", _filename.c_str());
218 }
219 #endif // _DEBUG
220 }
221 }
222
AddPluginLibrary(FUPluginManager::GetPluginCount fnGetPluginCount,FUPluginManager::GetPluginType fnGetPluginType,FUPluginManager::CreatePlugin fnCreatePlugin)223 void FUPluginManager::AddPluginLibrary(FUPluginManager::GetPluginCount fnGetPluginCount, FUPluginManager::GetPluginType fnGetPluginType, FUPluginManager::CreatePlugin fnCreatePlugin)
224 {
225 PluginLibrary* library = new PluginLibrary();
226 library->getPluginCount = fnGetPluginCount;
227 library->getPluginType = fnGetPluginType;
228 library->createPlugin = fnCreatePlugin;
229 library->filename.clear();
230 library->module = NULL;
231 loadedLibraries.push_back(library);
232 }
233
UnloadPlugins()234 void FUPluginManager::UnloadPlugins()
235 {
236 loadedPlugins.clear();
237 }
238