1 /* libSoX minimal libtool-ltdl for MS-Windows: (c) 2009 SoX contributors
2 *
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include "win32-ltdl.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #define WIN32_LEAN_AND_MEAN 1
22 #include <windows.h>
23
24 #ifndef _countof
25 #define _countof(A) (sizeof(A)/sizeof((A)[0]))
26 #endif
27
28 static DWORD
29 s_dwLastError;
30
31 static char
32 s_szLastError[MAX_PATH];
33
34 static char
35 s_szSearchPath[MAX_PATH];
36
37 static int
CopyPath(const char * szSource,char * szDest,unsigned cchDest,int chStop)38 CopyPath(
39 const char* szSource,
40 char* szDest,
41 unsigned cchDest,
42 int chStop)
43 {
44 unsigned i = 0;
45 char ch;
46 if (szSource != 0 && cchDest != 0)
47 {
48 for (; i < cchDest - 1 && (ch = szSource[i]) != 0 && ch != chStop; i++)
49 {
50 if (ch == '/')
51 {
52 ch = '\\';
53 }
54
55 szDest[i] = ch;
56 }
57 }
58
59 if (cchDest != 0)
60 {
61 szDest[i] = 0;
62 }
63
64 return i;
65 }
66
67 static lt_dlhandle
LoadLib(const char * szFileName,const char * const szExtensions[])68 LoadLib(
69 const char* szFileName,
70 const char* const szExtensions[])
71 {
72 lt_dlhandle hMod = 0;
73 char szFull[MAX_PATH];
74 const char* szExt;
75 unsigned iPath;
76 unsigned iExtension;
77 unsigned iCur;
78 unsigned iEnd = 0;
79 unsigned cPaths = 0;
80 const char* szPaths[2];
81
82 if (!szFileName || !szFileName[0])
83 {
84 s_dwLastError = ERROR_INVALID_PARAMETER;
85 goto Done;
86 }
87
88 /* Search starting with current directory */
89 szPaths[cPaths++] = "";
90
91 /* If the file name doesn't already have a path, also search the search path. */
92 if (s_szSearchPath[0] &&
93 szFileName[0] != '/' &&
94 szFileName[0] != '\\' &&
95 szFileName[1] != ':')
96 {
97 szPaths[cPaths++] = s_szSearchPath;
98 }
99
100 for (iPath = 0; !hMod && iPath < cPaths; iPath++)
101 {
102 iEnd = 0;
103
104 /* Add search path only if non-empty and filename does not
105 * contain absolute path.
106 */
107 if (szPaths[iPath][0])
108 {
109 iEnd += CopyPath(szPaths[iPath], szFull, _countof(szFull), 0);
110
111 if (szFull[iEnd - 1] != '\\' && iEnd < _countof(szFull))
112 {
113 szFull[iEnd++] = '\\';
114 }
115 }
116
117 iEnd += CopyPath(szFileName, &szFull[iEnd], _countof(szFull)-iEnd, 0);
118 if (iEnd == _countof(szFull))
119 {
120 s_dwLastError = ERROR_BUFFER_OVERFLOW;
121 goto Done;
122 }
123
124 for (iExtension = 0; !hMod && szExtensions[iExtension]; iExtension++)
125 {
126 szExt = szExtensions[iExtension];
127 for (iCur = 0; szExt[iCur] && iEnd + iCur < _countof(szFull); iCur++)
128 {
129 szFull[iEnd + iCur] = szExt[iCur];
130 }
131
132 if (iEnd + iCur >= _countof(szFull))
133 {
134 s_dwLastError = ERROR_BUFFER_OVERFLOW;
135 goto Done;
136 }
137 else
138 {
139 szFull[iEnd + iCur] = 0;
140 }
141
142 hMod = (lt_dlhandle)LoadLibraryA(szFull);
143 }
144 }
145
146 s_dwLastError = hMod ? 0 : GetLastError();
147
148 Done:
149 return hMod;
150 }
151
152 int
lt_dlinit(void)153 lt_dlinit(void)
154 {
155 int cErrors = 0;
156 s_dwLastError = 0;
157 return cErrors;
158 }
159
160 int
lt_dlexit(void)161 lt_dlexit(void)
162 {
163 int cErrors = 0;
164 s_dwLastError = 0;
165 s_szSearchPath[0] = 0;
166 return cErrors;
167 }
168
169 int
lt_dlsetsearchpath(const char * szSearchPath)170 lt_dlsetsearchpath(const char *szSearchPath)
171 {
172 int cErrors=0;
173 s_dwLastError = 0;
174 s_szSearchPath[0] = 0;
175 if (szSearchPath)
176 {
177 int iEnd = CopyPath(szSearchPath, s_szSearchPath, _countof(s_szSearchPath), 0);
178 if (szSearchPath[iEnd])
179 {
180 /* path was truncated. */
181 cErrors++;
182 s_dwLastError = ERROR_BUFFER_OVERFLOW;
183 s_szSearchPath[0] = 0;
184 }
185 }
186
187 return cErrors;
188 }
189
190 int
lt_dlforeachfile(const char * szSearchPath,int (* pfCallback)(const char * szFileName,lt_ptr pData),lt_ptr pData)191 lt_dlforeachfile(
192 const char *szSearchPath,
193 int (*pfCallback)(const char *szFileName, lt_ptr pData),
194 lt_ptr pData)
195 {
196 char szExePath[MAX_PATH];
197 char szOnePath[MAX_PATH];
198 int cErrors = 0;
199 unsigned iSearchPath = 0;
200 unsigned iOnePath;
201 unsigned iExePath = 0;
202 unsigned cchCopied;
203 HANDLE hFind;
204 WIN32_FIND_DATAA data;
205
206 szExePath[0] = 0;
207
208 if (pfCallback == 0)
209 {
210 s_dwLastError = ERROR_INVALID_PARAMETER;
211 cErrors++;
212 goto Done;
213 }
214
215 if (szSearchPath != 0)
216 {
217 while (1)
218 {
219 while (szSearchPath[iSearchPath] == LT_PATHSEP_CHAR)
220 {
221 iSearchPath++;
222 }
223
224 if (szSearchPath[iSearchPath] == 0)
225 {
226 s_dwLastError = 0;
227 break;
228 }
229
230 if (szSearchPath[iSearchPath] == '.' &&
231 (szSearchPath[iSearchPath + 1] == '\\' || szSearchPath[iSearchPath + 1] == '/'))
232 {
233 if (szExePath[0] == 0)
234 {
235 iExePath = GetModuleFileNameA(0, szExePath, _countof(szExePath));
236 if (iExePath == 0)
237 {
238 s_dwLastError = GetLastError();
239 cErrors++;
240 goto Done;
241 }
242 else if (iExePath == _countof(szExePath))
243 {
244 s_dwLastError = ERROR_BUFFER_OVERFLOW;
245 cErrors++;
246 goto Done;
247 }
248
249 while (iExePath > 0 && szExePath[iExePath - 1] != '\\')
250 {
251 iExePath--;
252 }
253
254 if (iExePath > 0)
255 {
256 iExePath--;
257 }
258
259 szExePath[iExePath] = 0;
260 }
261
262 strcpy(szOnePath, szExePath);
263 iOnePath = iExePath;
264 iSearchPath++;
265 }
266 else
267 {
268 iOnePath = 0;
269 }
270
271 cchCopied = CopyPath(
272 szSearchPath + iSearchPath,
273 szOnePath + iOnePath,
274 _countof(szOnePath) - iOnePath,
275 LT_PATHSEP_CHAR);
276 iSearchPath += cchCopied;
277 iOnePath += cchCopied;
278
279 if (0 < iOnePath && iOnePath + 1 < _countof(szOnePath) && szOnePath[iOnePath - 1] != '\\')
280 {
281 szOnePath[iOnePath++] = '\\';
282 }
283
284 if (iOnePath + 1 >= _countof(szOnePath))
285 {
286 s_dwLastError = ERROR_BUFFER_OVERFLOW;
287 cErrors++;
288 goto Done;
289 }
290
291 szOnePath[iOnePath++] = '*';
292 szOnePath[iOnePath] = 0;
293
294 hFind = FindFirstFileA(szOnePath, &data);
295 while (hFind != INVALID_HANDLE_VALUE)
296 {
297 if (0 == (data.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_OFFLINE)))
298 {
299 cErrors = pfCallback(data.cFileName, pData);
300 if (cErrors)
301 {
302 s_dwLastError = ERROR_CANCELLED;
303 FindClose(hFind);
304 goto Done;
305 }
306 }
307
308 if (!FindNextFileA(hFind, &data))
309 {
310 s_dwLastError = ERROR_SUCCESS;
311 FindClose(hFind);
312 hFind = INVALID_HANDLE_VALUE;
313 }
314 }
315 }
316 }
317
318 Done:
319 return cErrors;
320 }
321
322 lt_dlhandle
lt_dlopen(const char * szFileName)323 lt_dlopen(
324 const char *szFileName)
325 {
326 const char* const szExtensions[] = { ".", 0 };
327 lt_dlhandle hModule = LoadLib(szFileName, szExtensions);
328 return hModule;
329 }
330
331 lt_dlhandle
lt_dlopenext(const char * szFileName)332 lt_dlopenext(
333 const char *szFileName)
334 {
335 const char* const szExtensions[] = { ".", ".la.", ".dll.", 0 };
336 lt_dlhandle hModule = LoadLib(szFileName, szExtensions);
337 return hModule;
338 }
339
340 int
lt_dlclose(lt_dlhandle handle)341 lt_dlclose(
342 lt_dlhandle handle)
343 {
344 int cErrors = 0;
345 if (FreeLibrary((HMODULE)handle))
346 {
347 s_dwLastError = 0;
348 }
349 else
350 {
351 s_dwLastError = GetLastError();
352 cErrors++;
353 }
354
355 return cErrors;
356 }
357
358 lt_ptr
lt_dlsym(lt_dlhandle hModule,const char * szSymbolName)359 lt_dlsym(
360 lt_dlhandle hModule,
361 const char *szSymbolName)
362 {
363 union {FARPROC fn; lt_ptr ptr;} func;
364 func.fn = GetProcAddress((HMODULE)hModule, szSymbolName);
365 s_dwLastError = func.fn ? 0 : GetLastError();
366 return func.ptr;
367 }
368
369 const char *
lt_dlerror(void)370 lt_dlerror(void)
371 {
372 if (!FormatMessageA(
373 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
374 0,
375 s_dwLastError,
376 0,
377 s_szLastError,
378 _countof(s_szLastError),
379 0))
380 {
381 _snprintf(s_szLastError, _countof(s_szLastError), "Unknown error %u occurred.", s_dwLastError);
382 }
383
384 return s_szLastError;
385 }
386