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