[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / DllLoader / dll.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "dll.h"
22 #include "DllLoader.h"
23 #include "DllLoaderContainer.h"
24 #include "dll_tracker.h"
25 #include "dll_util.h"
26 #include <climits>
27 #include "filesystem/SpecialProtocol.h"
28 #include "utils/log.h"
29
30 #define DEFAULT_DLLPATH "special://xbmc/system/players/mplayer/codecs/"
31 #define HIGH_WORD(a) ((uintptr_t)(a) >> 16)
32 #define LOW_WORD(a) ((WORD)(((uintptr_t)(a)) & MAXWORD))
33
34 //#define API_DEBUG
35
36 char* getpath(char *buf, const char *full)
37 {
38   const char* pos;
39   if ((pos = strrchr(full, PATH_SEPARATOR_CHAR)))
40   {
41     strncpy(buf, full, pos - full + 1 );
42     buf[pos - full + 1] = 0;
43     return buf;
44   }
45   else
46   {
47     buf[0] = 0;
48     return buf;
49   }
50 }
51
52 extern "C" HMODULE __stdcall dllLoadLibraryExtended(LPCSTR lib_file, LPCSTR sourcedll)
53 {
54   char libname[MAX_PATH + 1] = {};
55   char libpath[MAX_PATH + 1] = {};
56   LibraryLoader* dll = NULL;
57
58   /* extract name */
59   const char* p = strrchr(lib_file, PATH_SEPARATOR_CHAR);
60   if (p)
61     strcpy(libname, p+1);
62   else
63     strcpy(libname, lib_file);
64
65   if( libname[0] == '\0' )
66     return NULL;
67
68   /* extract path */
69   getpath(libpath, lib_file);
70
71   if (sourcedll)
72   {
73     /* also check for invalid paths wich begin with a \ */
74     if( libpath[0] == '\0' || libpath[0] == PATH_SEPARATOR_CHAR )
75     {
76       /* use calling dll's path as base address for this call */
77       getpath(libpath, sourcedll);
78
79       /* mplayer has all it's dlls in a codecs subdirectory */
80       if (strstr(sourcedll, "mplayer.dll"))
81         strcat(libpath, "codecs\\");
82     }
83   }
84
85   /* if we still don't have a path, use default path */
86   if( libpath[0] == '\0' )
87     strcpy(libpath, DEFAULT_DLLPATH);
88
89   /* msdn docs state */
90   /* "If no file name extension is specified in the lpFileName parameter, the default library extension .dll is appended.  */
91   /* However, the file name string can include a trailing point character (.) to indicate that the module name has no extension." */
92   if( strrchr(libname, '.') == NULL )
93     strcat(libname, ".dll");
94   else if( libname[strlen(libname)-1] == '.' )
95     libname[strlen(libname)-1] = '\0';
96
97   dll = DllLoaderContainer::LoadModule(libname, libpath);
98
99   if (dll)
100     return (HMODULE)dll->GetHModule();
101
102   CLog::Log(LOGERROR, "LoadLibrary('%s') failed", libname);
103   return NULL;
104 }
105
106 extern "C" HMODULE __stdcall dllLoadLibraryA(LPCSTR file)
107 {
108   return dllLoadLibraryExtended(file, NULL);
109 }
110
111 #define DONT_RESOLVE_DLL_REFERENCES   0x00000001
112 #define LOAD_LIBRARY_AS_DATAFILE      0x00000002
113 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
114 #define LOAD_IGNORE_CODE_AUTHZ_LEVEL  0x00000010
115
116 extern "C" HMODULE __stdcall dllLoadLibraryExExtended(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags, LPCSTR sourcedll)
117 {
118   char strFlags[512];
119   strFlags[0] = '\0';
120
121   if (dwFlags & DONT_RESOLVE_DLL_REFERENCES) strcat(strFlags, "\n - DONT_RESOLVE_DLL_REFERENCES");
122   if (dwFlags & LOAD_IGNORE_CODE_AUTHZ_LEVEL) strcat(strFlags, "\n - LOAD_IGNORE_CODE_AUTHZ_LEVEL");
123   if (dwFlags & LOAD_LIBRARY_AS_DATAFILE) strcat(strFlags, "\n - LOAD_LIBRARY_AS_DATAFILE");
124   if (dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) strcat(strFlags, "\n - LOAD_WITH_ALTERED_SEARCH_PATH");
125
126   CLog::Log(LOGDEBUG, "LoadLibraryExA called with flags: %s", strFlags);
127
128   return dllLoadLibraryExtended(lpLibFileName, sourcedll);
129 }
130
131 extern "C" HMODULE __stdcall dllLoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
132 {
133   return dllLoadLibraryExExtended(lpLibFileName, hFile, dwFlags, NULL);
134 }
135
136 extern "C" BOOL __stdcall dllFreeLibrary(HINSTANCE hLibModule)
137 {
138   LibraryLoader* dllhandle = DllLoaderContainer::GetModule(hLibModule);
139
140   if( !dllhandle )
141   {
142     CLog::Log(LOGERROR, "%s - Invalid hModule specified",__FUNCTION__);
143     return 1;
144   }
145
146   // to make sure systems dlls are never deleted
147   if (dllhandle->IsSystemDll()) return 1;
148
149   DllLoaderContainer::ReleaseModule(dllhandle);
150
151   return 1;
152 }
153
154 extern "C" FARPROC __stdcall dllGetProcAddress(HMODULE hModule, LPCSTR function)
155 {
156   uintptr_t loc = (uintptr_t)_ReturnAddress();
157
158   void* address = NULL;
159   LibraryLoader* dll = DllLoaderContainer::GetModule(hModule);
160
161   if( !dll )
162   {
163     CLog::Log(LOGERROR, "%s - Invalid hModule specified",__FUNCTION__);
164     return NULL;
165   }
166
167   /* how can somebody get the stupid idea to create such a stupid function */
168   /* where you never know if the given pointer is a pointer or a value */
169   if( HIGH_WORD(function) == 0 && LOW_WORD(function) < 1000)
170   {
171     if( dll->ResolveOrdinal(LOW_WORD(function), &address) )
172     {
173       CLog::Log(LOGDEBUG, "%s(%p(%s), %d) => %p", __FUNCTION__, hModule, dll->GetName(), LOW_WORD(function), address);
174     }
175     else if( dll->IsSystemDll() )
176     {
177       char ordinal[5];
178       sprintf(ordinal, "%d", LOW_WORD(function));
179       address = (void*)create_dummy_function(dll->GetName(), ordinal);
180
181       /* add to tracklist if we are tracking this source dll */
182       DllTrackInfo* track = tracker_get_dlltrackinfo(loc);
183       if( track )
184         tracker_dll_data_track(track->pDll, (uintptr_t)address);
185
186       CLog::Log(LOGDEBUG, "%s - created dummy function %s!%s",__FUNCTION__, dll->GetName(), ordinal);
187     }
188     else
189     {
190       address = NULL;
191       CLog::Log(LOGDEBUG, "%s(%p(%s), '%s') => %p",__FUNCTION__ , hModule, dll->GetName(), function, address);
192     }
193   }
194   else
195   {
196     if( dll->ResolveExport(function, &address) )
197     {
198       CLog::Log(LOGDEBUG, "%s(%p(%s), '%s') => %p",__FUNCTION__ , hModule, dll->GetName(), function, address);
199     }
200     else
201     {
202       DllTrackInfo* track = tracker_get_dlltrackinfo(loc);
203       /* some dll's require us to always return a function or it will fail, other's  */
204       /* decide functionallity depending on if the functions exist and may fail      */
205       if( dll->IsSystemDll() && track
206        && stricmp(track->pDll->GetName(), "CoreAVCDecoder.ax") == 0 )
207       {
208         address = (void*)create_dummy_function(dll->GetName(), function);
209         tracker_dll_data_track(track->pDll, (uintptr_t)address);
210         CLog::Log(LOGDEBUG, "%s - created dummy function %s!%s", __FUNCTION__, dll->GetName(), function);
211       }
212       else
213       {
214         address = NULL;
215         CLog::Log(LOGDEBUG, "%s(%p(%s), '%s') => %p", __FUNCTION__, hModule, dll->GetName(), function, address);
216       }
217     }
218   }
219
220   return (FARPROC)address;
221 }
222
223 extern "C" HMODULE WINAPI dllGetModuleHandleA(LPCSTR lpModuleName)
224 {
225   /*
226   If the file name extension is omitted, the default library extension .dll is appended.
227   The file name string can include a trailing point character (.) to indicate that the module name has no extension.
228   The string does not have to specify a path. When specifying a path, be sure to use backslashes (\), not forward slashes (/).
229   The name is compared (case independently)
230   If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).
231   */
232
233   if( lpModuleName == NULL )
234     return NULL;
235
236   char* strModuleName = new char[strlen(lpModuleName) + 5];
237   strcpy(strModuleName, lpModuleName);
238
239   if (strrchr(strModuleName, '.') == 0) strcat(strModuleName, ".dll");
240
241   //CLog::Log(LOGDEBUG, "GetModuleHandleA(%s) .. looking up", lpModuleName);
242
243   LibraryLoader *p = DllLoaderContainer::GetModule(strModuleName);
244   delete []strModuleName;
245
246   if (p)
247   {
248     //CLog::Log(LOGDEBUG, "GetModuleHandleA('%s') => 0x%x", lpModuleName, h);
249     return (HMODULE)p->GetHModule();
250   }
251
252   CLog::Log(LOGDEBUG, "GetModuleHandleA('%s') failed", lpModuleName);
253   return NULL;
254 }
255
256 extern "C" DWORD WINAPI dllGetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
257 {
258   if (NULL == hModule)
259   {
260 #ifdef _WIN32
261     return GetModuleFileNameA(hModule, lpFilename, nSize);
262 #else
263     CLog::Log(LOGDEBUG, "%s - No hModule specified", __FUNCTION__);
264     return 0;
265 #endif
266   }
267
268   LibraryLoader* dll = DllLoaderContainer::GetModule(hModule);
269   if( !dll )
270   {
271     CLog::Log(LOGERROR, "%s - Invalid hModule specified", __FUNCTION__);
272     return 0;
273   }
274
275   char* sName = dll->GetFileName();
276   if (sName)
277   {
278     strncpy(lpFilename, sName, nSize);
279     lpFilename[nSize] = 0;
280     return strlen(lpFilename);
281   }
282
283   return 0;
284 }