73b26f7b9db7d2ceb9c7a58cb979b80d037b7b18
[platform/upstream/freerdp.git] / libfreerdp / common / addin.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Addin Loader
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <winpr/crt.h>
29 #include <winpr/path.h>
30 #include <winpr/library.h>
31
32 #include <freerdp/addin.h>
33
34 LPCSTR gAddinPath = FREERDP_ADDIN_PATH;
35 LPCSTR gLibraryPath = FREERDP_LIBRARY_PATH;
36 LPCSTR gInstallPrefix = FREERDP_INSTALL_PREFIX;
37
38 LPSTR freerdp_get_library_install_path()
39 {
40         LPSTR pszPath;
41         size_t cchPath;
42         size_t cchLibraryPath;
43         size_t cchInstallPrefix;
44
45         cchLibraryPath = strlen(gLibraryPath);
46         cchInstallPrefix = strlen(gInstallPrefix);
47
48         cchPath = cchInstallPrefix + cchLibraryPath + 2;
49         pszPath = (LPSTR) malloc(cchPath + 1);
50
51         CopyMemory(pszPath, gInstallPrefix, cchInstallPrefix);
52         pszPath[cchInstallPrefix] = '\0';
53
54         NativePathCchAppendA(pszPath, cchPath + 1, gLibraryPath);
55
56         return pszPath;
57 }
58
59 LPSTR freerdp_get_dynamic_addin_install_path()
60 {
61         LPSTR pszPath;
62         size_t cchPath;
63         size_t cchAddinPath;
64         size_t cchInstallPrefix;
65
66         cchAddinPath = strlen(gAddinPath);
67         cchInstallPrefix = strlen(gInstallPrefix);
68
69         cchPath = cchInstallPrefix + cchAddinPath + 2;
70         pszPath = (LPSTR) malloc(cchPath + 1);
71
72         CopyMemory(pszPath, gInstallPrefix, cchInstallPrefix);
73         pszPath[cchInstallPrefix] = '\0';
74
75         NativePathCchAppendA(pszPath, cchPath + 1, gAddinPath);
76
77         return pszPath;
78 }
79
80 void* freerdp_load_dynamic_addin(LPCSTR pszFileName, LPCSTR pszPath, LPCSTR pszEntryName)
81 {
82         void* entry;
83         BOOL bHasExt;
84         PCSTR pszExt;
85         size_t cchExt;
86         HINSTANCE library;
87         size_t cchFileName;
88         LPSTR pszFilePath;
89         size_t cchFilePath;
90         LPSTR pszAddinFile;
91         size_t cchAddinFile;
92         LPSTR pszAddinInstallPath;
93         size_t cchAddinInstallPath;
94
95         entry = NULL;
96         cchExt = 0;
97         bHasExt = TRUE;
98         cchFileName = strlen(pszFileName);
99
100         if (PathCchFindExtensionA(pszFileName, cchFileName + 1, &pszExt) != S_OK)
101         {
102                 pszExt = PathGetSharedLibraryExtensionA(PATH_SHARED_LIB_EXT_WITH_DOT);
103                 cchExt = strlen(pszExt);
104                 bHasExt = FALSE;
105         }
106
107         pszAddinInstallPath = freerdp_get_dynamic_addin_install_path();
108         cchAddinInstallPath = strlen(pszAddinInstallPath);
109
110         cchFilePath = cchAddinInstallPath + cchFileName + 32;
111         pszFilePath = (LPSTR) malloc(cchFilePath + 1);
112
113         if (bHasExt)
114         {
115                 pszAddinFile = _strdup(pszFileName);
116                 cchAddinFile = strlen(pszAddinFile);
117         }
118         else
119         {
120                 cchAddinFile = cchFileName + cchExt + 2;
121                 pszAddinFile = (LPSTR) malloc(cchAddinFile + 1);
122                 sprintf_s(pszAddinFile, cchAddinFile, "%s%s", pszFileName, pszExt);
123                 cchAddinFile = strlen(pszAddinFile);
124         }
125
126         CopyMemory(pszFilePath, pszAddinInstallPath, cchAddinInstallPath);
127         pszFilePath[cchAddinInstallPath] = '\0';
128
129         NativePathCchAppendA((LPSTR) pszFilePath, cchFilePath + 1, pszAddinFile);
130
131         library = LoadLibraryA(pszFilePath);
132
133         free(pszAddinInstallPath);
134         free(pszAddinFile);
135         free(pszFilePath);
136
137         if (!library)
138                 return NULL;
139
140         entry = GetProcAddress(library, pszEntryName);
141
142         if (entry)
143                 return entry;
144
145         return entry;
146 }
147
148 void* freerdp_load_dynamic_channel_addin_entry(LPCSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
149 {
150         void* entry;
151         LPSTR pszFileName;
152         size_t cchFileName;
153         LPCSTR pszExtension;
154
155         pszExtension = PathGetSharedLibraryExtensionA(0);
156
157         if (pszName && pszSubsystem && pszType)
158         {
159                 cchFileName = strlen(pszName) + strlen(pszSubsystem) + strlen(pszType) + strlen(pszExtension) + 32;
160                 pszFileName = (LPSTR) malloc(cchFileName);
161                 sprintf_s(pszFileName, cchFileName, "%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension);
162                 cchFileName = strlen(pszFileName);
163         }
164         else if (pszName && pszSubsystem)
165         {
166                 cchFileName = strlen(pszName) + strlen(pszSubsystem) + strlen(pszExtension) + 32;
167                 pszFileName = (LPSTR) malloc(cchFileName);
168                 sprintf_s(pszFileName, cchFileName, "%s-client-%s.%s", pszName, pszSubsystem, pszExtension);
169                 cchFileName = strlen(pszFileName);
170         }
171         else if (pszName)
172         {
173                 cchFileName = strlen(pszName) + strlen(pszExtension) + 32;
174                 pszFileName = (LPSTR) malloc(cchFileName);
175                 sprintf_s(pszFileName, cchFileName, "%s-client.%s", pszName, pszExtension);
176                 cchFileName = strlen(pszFileName);
177         }
178         else
179         {
180                 return NULL;
181         }
182
183         if (pszSubsystem)
184         {
185                 LPSTR pszEntryName;
186                 size_t cchEntryName;
187
188                 /* subsystem add-in */
189
190                 cchEntryName = 64 + strlen(pszName);
191                 pszEntryName = (LPSTR) malloc(cchEntryName + 1);
192                 sprintf_s(pszEntryName, cchEntryName + 1, "freerdp_%s_client_subsystem_entry", pszName);
193
194                 entry = freerdp_load_dynamic_addin(pszFileName, NULL, pszEntryName);
195
196                 if (entry)
197                         return entry;
198         }
199         else
200         {
201                 /* channel add-in */
202
203                 if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
204                         entry = freerdp_load_dynamic_addin(pszFileName, NULL, "VirtualChannelEntry");
205                 else if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
206                         entry = freerdp_load_dynamic_addin(pszFileName, NULL, "DVCPluginEntry");
207                 else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
208                         entry = freerdp_load_dynamic_addin(pszFileName, NULL, "DeviceServiceEntry");
209                 else
210                         entry = freerdp_load_dynamic_addin(pszFileName, NULL, pszType);
211
212                 if (entry)
213                         return entry;
214         }
215
216         return NULL;
217 }
218
219 static FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN freerdp_load_static_channel_addin_entry = NULL;
220
221 int freerdp_register_addin_provider(FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN provider, DWORD dwFlags)
222 {
223         freerdp_load_static_channel_addin_entry = provider;
224         return 0;
225 }
226
227 void* freerdp_load_channel_addin_entry(LPCSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
228 {
229         void* entry = NULL;
230
231         if (freerdp_load_static_channel_addin_entry)
232                 entry = freerdp_load_static_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
233
234         if (!entry)
235                 entry = freerdp_load_dynamic_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
236
237         return entry;
238 }