fix invalid mapping detection
[ardour.git] / libs / ardour / msvc / msvc_libardour.cc
1 /*
2     Copyright (C) 2009 John Emmas
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #if (defined(PLATFORM_WINDOWS) && !defined(COMPILER_CYGWIN))
21 #include <shlobj.h>
22 #include <glibmm.h>
23 #ifdef COMPILER_MSVC
24 #pragma warning(disable:4996)
25 #endif
26 #else
27 #include <glib.h>
28 #endif
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ardour/msvc_libardour.h>
33
34 namespace ARDOUR {
35
36 //***************************************************************
37 //
38 // placeholder_for_non_msvc_specific_function()
39 //
40 // Description
41 //
42 //      Returns:
43 //
44 //    On Success:
45 //
46 //    On Failure:
47 //
48 /* LIBARDOUR_API char* LIBARDOUR_APICALLTYPE
49    placeholder_for_non_msvc_specific_function()
50 {
51 char *pRet = buffer;
52
53         return (pRet);
54 }
55 */
56
57 }  // namespace ARDOUR
58
59 #ifdef COMPILER_MSVC
60
61 #include <errno.h>
62
63 namespace ARDOUR {
64
65 //***************************************************************
66 //
67 //      symlink()
68 //
69 // Emulates POSIX symlink() but creates a Windows shortcut. To
70 // create a Windows shortcut the supplied shortcut name must end
71 // in ".lnk"
72 // Note that you can only create a shortcut in a folder for which
73 // you have appropriate access rights. Note also that the folder
74 // must already exist. If it doesn't exist or if you don't have
75 // sufficient access rights to it, symlink() will generate an
76 // error (in common with its POSIX counterpart).
77 //
78 //      Returns:
79 //
80 //    On Success: Zero
81 //    On Failure: -1 ('errno' will contain the specific error)
82 //
83 LIBARDOUR_API int LIBARDOUR_APICALLTYPE
84 symlink(const char *dest, const char *shortcut, const char *working_directory /*= NULL */)
85 {
86 IShellLinkA  *pISL = NULL;
87 IPersistFile *ppf  = NULL;
88 int           ret  = (-1);
89
90         if ((NULL == dest) || (NULL == shortcut) || (strlen(shortcut) < 5) || (strlen(dest) == 0))
91                 _set_errno(EINVAL);
92         else if ((strlen(shortcut) > _MAX_PATH) || (strlen(dest) > _MAX_PATH))
93                 _set_errno(ENAMETOOLONG);
94         else if (Glib::file_test(shortcut, Glib::FILE_TEST_EXISTS))
95                 _set_errno(EEXIST);
96         else
97         {
98                 HRESULT hRet = 0;
99
100                 if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
101                 {
102                         if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
103                         {
104                                 char  sc_path_lower_case[_MAX_PATH];
105                                 WCHAR shortcut_path[_MAX_PATH];
106
107                                 // Fail if the path isn't a shortcut
108                                 strcpy(sc_path_lower_case, shortcut);
109                                 strlwr(sc_path_lower_case);
110                                 const char *p = strlen(sc_path_lower_case) + sc_path_lower_case - 4;
111
112                                 if (0 == strcmp(p, ".lnk"))
113                                 {
114                                         HRESULT hr;
115
116                                         // We're apparently been given valid Windows shortcut name
117                                         MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
118
119                                         // Create the shortcut
120                                         if (FAILED (hr = ppf->Load(shortcut_path, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE)))
121                                                 hr = ppf->Save(shortcut_path, TRUE);
122
123                                         if (S_OK == hr)
124                                         {
125                                                 // Set its target path
126                                                 if (S_OK == pISL->SetPath(dest))
127                                                 {
128                                                         // Set its working directory
129                                                         if (working_directory)
130                                                                 p = working_directory;
131                                                         else
132                                                                 p = "";
133
134                                                         if (S_OK == pISL->SetWorkingDirectory(p))
135                                                         {
136                                                                 // Set its 'Show' command
137                                                                 if (S_OK == pISL->SetShowCmd(SW_SHOWNORMAL))
138                                                                 {
139                                                                         // And finally, set its icon to the same file as the target.
140                                                                         // For the time being, don't fail if the target has no icon.
141                                                         if (Glib::file_test(dest, Glib::FILE_TEST_IS_DIR))
142                                                                                 pISL->SetIconLocation("%SystemRoot%\\system32\\shell32.dll", 1);
143                                                                         else
144                                                                                 pISL->SetIconLocation(dest, 0);
145
146                                                                         if (S_OK == ppf->Save(shortcut_path, FALSE))
147                                                                         {
148                                                                                 Sleep(1500);
149
150                                                                                 ret = 0;
151                                                                                 // _set_errno(0);
152                                                                         }
153                                                                         else
154                                                                                 _set_errno(EACCES);
155                                                                 }
156                                                                 else
157                                                                         _set_errno(EACCES);
158                                                         }
159                                                         else
160                                                                 _set_errno(EACCES);
161                                                 }
162                                                 else
163                                                         _set_errno(EACCES);
164                                         }
165                                         else
166                                                 _set_errno(EBADF);
167                                 }
168                                 else
169                                         _set_errno(EACCES);
170                         }
171                         else
172                                 _set_errno(EBADF);
173                 }
174                 else
175                 {
176                         if (E_POINTER == hRet)
177                                 _set_errno(EINVAL);
178                         else
179                                 _set_errno(EIO);
180                 }
181         }
182
183         return (ret);
184 }
185
186
187 //***************************************************************
188 //
189 //      readlink()
190 //
191 // Emulates POSIX readlink() but using Windows shortcuts
192 // Doesn't (currently) resolve shortcuts to shortcuts. This would
193 // be quite simple to incorporate but we'd need to check for
194 // recursion (i.e. a shortcut that points to an earlier shortcut
195 // in the same chain).
196 //
197 //      Returns:
198 //
199 //    On Success: Zero
200 //    On Failure: -1 ('errno' will contain the specific error)
201 //
202 LIBARDOUR_API int LIBARDOUR_APICALLTYPE
203 readlink(const char *__restrict shortcut, char *__restrict buf, size_t bufsize)
204 {
205 IShellLinkA  *pISL = NULL;
206 IPersistFile *ppf  = NULL;
207 int           ret  = (-1);
208
209         if ((NULL == shortcut) || (NULL == buf) || (strlen(shortcut) < 5) || (bufsize == 0))
210                 _set_errno(EINVAL);
211         else if ((bufsize > _MAX_PATH) || (strlen(shortcut) > _MAX_PATH))
212                 _set_errno(ENAMETOOLONG);
213         else
214         {
215                 HRESULT hRet = 0;
216
217                 if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
218                 {
219                         if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
220                         {
221                                 char  target_path[_MAX_PATH];
222                                 WCHAR shortcut_path[_MAX_PATH];
223
224                                 // Fail if the path isn't a shortcut
225                                 strcpy(target_path, shortcut); // Use 'target_path' temporarily
226                                 strlwr(target_path);
227                                 const char *p = strlen(target_path) + target_path - 4;
228
229                                 if (0 == strcmp(p, ".lnk"))
230                                 {
231                                         // We're apparently pointing to a valid Windows shortcut
232                                         MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
233
234                                         // Load the shortcut into our persistent file
235                                         if (SUCCEEDED (ppf->Load(shortcut_path, 0)))
236                                         {
237                                                 // Read the target information from the shortcut object
238                                                 if (S_OK == (pISL->GetPath (target_path, _MAX_PATH, NULL, SLGP_UNCPRIORITY)))
239                                                 {
240                                                         strncpy(buf, target_path, bufsize);
241                                                         ret = ((ret = strlen(buf)) > bufsize) ? bufsize : ret;
242                                                         // _set_errno(0);
243                                                 }
244                                                 else
245                                                         _set_errno(EACCES);
246                                         }
247                                         else
248                                                 _set_errno(EBADF);
249                                 }
250                                 else
251                                         _set_errno(EINVAL);
252                         }
253                         else
254                                 _set_errno(EBADF);
255                 }
256                 else
257                 {
258                         if (E_POINTER == hRet)
259                                 _set_errno(EINVAL);
260                         else
261                                 _set_errno(EIO);
262                 }
263
264                 if (ppf)
265                         ppf->Release();
266
267                 if (pISL)
268                         pISL->Release();
269         }
270
271         return (ret);
272 }
273
274 }  // namespace ARDOUR
275
276 #endif  // COMPILER_MSVC