summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c')
-rw-r--r--contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c
new file mode 100644
index 0000000..39ba414
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfilesystem.c
@@ -0,0 +1,382 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_FILESYSTEM_WINDOWS
24
25/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26// System dependent filesystem routines
27
28#include "../SDL_sysfilesystem.h"
29
30#include "../../core/windows/SDL_windows.h"
31#include <shlobj.h>
32#include <initguid.h>
33
34// These aren't all defined in older SDKs, so define them here
35DEFINE_GUID(SDL_FOLDERID_Profile, 0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73);
36DEFINE_GUID(SDL_FOLDERID_Desktop, 0xB4BFCC3A, 0xDB2C, 0x424C, 0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41);
37DEFINE_GUID(SDL_FOLDERID_Documents, 0xFDD39AD0, 0x238F, 0x46AF, 0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7);
38DEFINE_GUID(SDL_FOLDERID_Downloads, 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b);
39DEFINE_GUID(SDL_FOLDERID_Music, 0x4BD8D571, 0x6D19, 0x48D3, 0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43);
40DEFINE_GUID(SDL_FOLDERID_Pictures, 0x33E28130, 0x4E1E, 0x4676, 0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB);
41DEFINE_GUID(SDL_FOLDERID_SavedGames, 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4);
42DEFINE_GUID(SDL_FOLDERID_Screenshots, 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f);
43DEFINE_GUID(SDL_FOLDERID_Templates, 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7);
44DEFINE_GUID(SDL_FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC);
45
46char *SDL_SYS_GetBasePath(void)
47{
48 DWORD buflen = 128;
49 WCHAR *path = NULL;
50 char *result = NULL;
51 DWORD len = 0;
52 int i;
53
54 while (true) {
55 void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR));
56 if (!ptr) {
57 SDL_free(path);
58 return NULL;
59 }
60
61 path = (WCHAR *)ptr;
62
63 len = GetModuleFileNameW(NULL, path, buflen);
64 // if it truncated, then len >= buflen - 1
65 // if there was enough room (or failure), len < buflen - 1
66 if (len < buflen - 1) {
67 break;
68 }
69
70 // buffer too small? Try again.
71 buflen *= 2;
72 }
73
74 if (len == 0) {
75 SDL_free(path);
76 WIN_SetError("Couldn't locate our .exe");
77 return NULL;
78 }
79
80 for (i = len - 1; i > 0; i--) {
81 if (path[i] == '\\') {
82 break;
83 }
84 }
85
86 SDL_assert(i > 0); // Should have been an absolute path.
87 path[i + 1] = '\0'; // chop off filename.
88
89 result = WIN_StringToUTF8W(path);
90 SDL_free(path);
91
92 return result;
93}
94
95char *SDL_SYS_GetPrefPath(const char *org, const char *app)
96{
97 /*
98 * Vista and later has a new API for this, but SHGetFolderPath works there,
99 * and apparently just wraps the new API. This is the new way to do it:
100 *
101 * SHGetKnownFolderPath(SDL_FOLDERID_RoamingAppData, KF_FLAG_CREATE,
102 * NULL, &wszPath);
103 */
104
105 HRESULT hr = E_FAIL;
106 WCHAR path[MAX_PATH];
107 char *result = NULL;
108 WCHAR *worg = NULL;
109 WCHAR *wapp = NULL;
110 size_t new_wpath_len = 0;
111 BOOL api_result = FALSE;
112
113 if (!app) {
114 SDL_InvalidParamError("app");
115 return NULL;
116 }
117 if (!org) {
118 org = "";
119 }
120
121 hr = SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path);
122 if (!SUCCEEDED(hr)) {
123 WIN_SetErrorFromHRESULT("Couldn't locate our prefpath", hr);
124 return NULL;
125 }
126
127 worg = WIN_UTF8ToStringW(org);
128 if (!worg) {
129 return NULL;
130 }
131
132 wapp = WIN_UTF8ToStringW(app);
133 if (!wapp) {
134 SDL_free(worg);
135 return NULL;
136 }
137
138 new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
139
140 if ((new_wpath_len + 1) > MAX_PATH) {
141 SDL_free(worg);
142 SDL_free(wapp);
143 WIN_SetError("Path too long.");
144 return NULL;
145 }
146
147 if (*worg) {
148 SDL_wcslcat(path, L"\\", SDL_arraysize(path));
149 SDL_wcslcat(path, worg, SDL_arraysize(path));
150 }
151 SDL_free(worg);
152
153 api_result = CreateDirectoryW(path, NULL);
154 if (api_result == FALSE) {
155 if (GetLastError() != ERROR_ALREADY_EXISTS) {
156 SDL_free(wapp);
157 WIN_SetError("Couldn't create a prefpath.");
158 return NULL;
159 }
160 }
161
162 SDL_wcslcat(path, L"\\", SDL_arraysize(path));
163 SDL_wcslcat(path, wapp, SDL_arraysize(path));
164 SDL_free(wapp);
165
166 api_result = CreateDirectoryW(path, NULL);
167 if (api_result == FALSE) {
168 if (GetLastError() != ERROR_ALREADY_EXISTS) {
169 WIN_SetError("Couldn't create a prefpath.");
170 return NULL;
171 }
172 }
173
174 SDL_wcslcat(path, L"\\", SDL_arraysize(path));
175
176 result = WIN_StringToUTF8W(path);
177
178 return result;
179}
180
181char *SDL_SYS_GetUserFolder(SDL_Folder folder)
182{
183 typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*);
184 HMODULE lib = LoadLibrary(L"Shell32.dll");
185 pfnSHGetKnownFolderPath pSHGetKnownFolderPath = NULL;
186 char *result = NULL;
187
188 if (lib) {
189 pSHGetKnownFolderPath = (pfnSHGetKnownFolderPath)GetProcAddress(lib, "SHGetKnownFolderPath");
190 }
191
192 if (pSHGetKnownFolderPath) {
193 GUID type; // KNOWNFOLDERID
194 HRESULT hr;
195 wchar_t *path;
196
197 switch (folder) {
198 case SDL_FOLDER_HOME:
199 type = SDL_FOLDERID_Profile;
200 break;
201
202 case SDL_FOLDER_DESKTOP:
203 type = SDL_FOLDERID_Desktop;
204 break;
205
206 case SDL_FOLDER_DOCUMENTS:
207 type = SDL_FOLDERID_Documents;
208 break;
209
210 case SDL_FOLDER_DOWNLOADS:
211 type = SDL_FOLDERID_Downloads;
212 break;
213
214 case SDL_FOLDER_MUSIC:
215 type = SDL_FOLDERID_Music;
216 break;
217
218 case SDL_FOLDER_PICTURES:
219 type = SDL_FOLDERID_Pictures;
220 break;
221
222 case SDL_FOLDER_PUBLICSHARE:
223 SDL_SetError("Public share unavailable on Windows");
224 goto done;
225
226 case SDL_FOLDER_SAVEDGAMES:
227 type = SDL_FOLDERID_SavedGames;
228 break;
229
230 case SDL_FOLDER_SCREENSHOTS:
231 type = SDL_FOLDERID_Screenshots;
232 break;
233
234 case SDL_FOLDER_TEMPLATES:
235 type = SDL_FOLDERID_Templates;
236 break;
237
238 case SDL_FOLDER_VIDEOS:
239 type = SDL_FOLDERID_Videos;
240 break;
241
242 default:
243 SDL_SetError("Invalid SDL_Folder: %d", (int)folder);
244 goto done;
245 };
246
247 hr = pSHGetKnownFolderPath(&type, 0x00008000 /* KF_FLAG_CREATE */, NULL, &path);
248 if (SUCCEEDED(hr)) {
249 result = WIN_StringToUTF8W(path);
250 } else {
251 WIN_SetErrorFromHRESULT("Couldn't get folder", hr);
252 }
253
254 } else {
255 int type;
256 HRESULT hr;
257 wchar_t path[MAX_PATH];
258
259 switch (folder) {
260 case SDL_FOLDER_HOME:
261 type = CSIDL_PROFILE;
262 break;
263
264 case SDL_FOLDER_DESKTOP:
265 type = CSIDL_DESKTOP;
266 break;
267
268 case SDL_FOLDER_DOCUMENTS:
269 type = CSIDL_MYDOCUMENTS;
270 break;
271
272 case SDL_FOLDER_DOWNLOADS:
273 SDL_SetError("Downloads folder unavailable before Vista");
274 goto done;
275
276 case SDL_FOLDER_MUSIC:
277 type = CSIDL_MYMUSIC;
278 break;
279
280 case SDL_FOLDER_PICTURES:
281 type = CSIDL_MYPICTURES;
282 break;
283
284 case SDL_FOLDER_PUBLICSHARE:
285 SDL_SetError("Public share unavailable on Windows");
286 goto done;
287
288 case SDL_FOLDER_SAVEDGAMES:
289 SDL_SetError("Saved games unavailable before Vista");
290 goto done;
291
292 case SDL_FOLDER_SCREENSHOTS:
293 SDL_SetError("Screenshots folder unavailable before Vista");
294 goto done;
295
296 case SDL_FOLDER_TEMPLATES:
297 type = CSIDL_TEMPLATES;
298 break;
299
300 case SDL_FOLDER_VIDEOS:
301 type = CSIDL_MYVIDEO;
302 break;
303
304 default:
305 SDL_SetError("Unsupported SDL_Folder on Windows before Vista: %d", (int)folder);
306 goto done;
307 };
308
309 // Create the OS-specific folder if it doesn't already exist
310 type |= CSIDL_FLAG_CREATE;
311
312#if 0
313 // Apparently the oldest, but not supported in modern Windows
314 HRESULT hr = SHGetSpecialFolderPath(NULL, path, type, TRUE);
315#endif
316
317 /* Windows 2000/XP and later, deprecated as of Windows 10 (still
318 available), available in Wine (tested 6.0.3) */
319 hr = SHGetFolderPathW(NULL, type, NULL, SHGFP_TYPE_CURRENT, path);
320
321 // use `== TRUE` for SHGetSpecialFolderPath
322 if (SUCCEEDED(hr)) {
323 result = WIN_StringToUTF8W(path);
324 } else {
325 WIN_SetErrorFromHRESULT("Couldn't get folder", hr);
326 }
327 }
328
329 if (result) {
330 char *newresult = (char *) SDL_realloc(result, SDL_strlen(result) + 2);
331
332 if (!newresult) {
333 SDL_free(result);
334 result = NULL; // will be returned
335 goto done;
336 }
337
338 result = newresult;
339 SDL_strlcat(result, "\\", SDL_strlen(result) + 2);
340 }
341
342done:
343 if (lib) {
344 FreeLibrary(lib);
345 }
346 return result;
347}
348
349char *SDL_SYS_GetCurrentDirectory(void)
350{
351 WCHAR *wstr = NULL;
352 DWORD buflen = 0;
353 while (true) {
354 const DWORD bw = GetCurrentDirectoryW(buflen, wstr);
355 if (bw == 0) {
356 WIN_SetError("GetCurrentDirectoryW failed");
357 return NULL;
358 } else if (bw < buflen) { // we got it!
359 // make sure there's a path separator at the end.
360 SDL_assert(bw < (buflen + 2));
361 if ((bw == 0) || (wstr[bw-1] != '\\')) {
362 wstr[bw] = '\\';
363 wstr[bw + 1] = '\0';
364 }
365 break;
366 }
367
368 void *ptr = SDL_realloc(wstr, (bw + 1) * sizeof (WCHAR));
369 if (!ptr) {
370 SDL_free(wstr);
371 return NULL;
372 }
373 wstr = (WCHAR *) ptr;
374 buflen = bw;
375 }
376
377 char *retval = WIN_StringToUTF8W(wstr);
378 SDL_free(wstr);
379 return retval;
380}
381
382#endif // SDL_FILESYSTEM_WINDOWS