Atlas - SDL_sysfilesystem.c

Home / ext / SDL / src / filesystem / windows Lines: 1 | Size: 10945 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 hr = SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path); 114 if (!SUCCEEDED(hr)) { 115 WIN_SetErrorFromHRESULT("Couldn't locate our prefpath", hr); 116 return NULL; 117 } 118 119 worg = WIN_UTF8ToStringW(org); 120 if (!worg) { 121 return NULL; 122 } 123 124 wapp = WIN_UTF8ToStringW(app); 125 if (!wapp) { 126 SDL_free(worg); 127 return NULL; 128 } 129 130 new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3; 131 132 if ((new_wpath_len + 1) > MAX_PATH) { 133 SDL_free(worg); 134 SDL_free(wapp); 135 WIN_SetError("Path too long."); 136 return NULL; 137 } 138 139 if (*worg) { 140 SDL_wcslcat(path, L"\\", SDL_arraysize(path)); 141 SDL_wcslcat(path, worg, SDL_arraysize(path)); 142 } 143 SDL_free(worg); 144 145 api_result = CreateDirectoryW(path, NULL); 146 if (api_result == FALSE) { 147 if (GetLastError() != ERROR_ALREADY_EXISTS) { 148 SDL_free(wapp); 149 WIN_SetError("Couldn't create a prefpath."); 150 return NULL; 151 } 152 } 153 154 SDL_wcslcat(path, L"\\", SDL_arraysize(path)); 155 SDL_wcslcat(path, wapp, SDL_arraysize(path)); 156 SDL_free(wapp); 157 158 api_result = CreateDirectoryW(path, NULL); 159 if (api_result == FALSE) { 160 if (GetLastError() != ERROR_ALREADY_EXISTS) { 161 WIN_SetError("Couldn't create a prefpath."); 162 return NULL; 163 } 164 } 165 166 SDL_wcslcat(path, L"\\", SDL_arraysize(path)); 167 168 result = WIN_StringToUTF8W(path); 169 170 return result; 171} 172 173char *SDL_SYS_GetUserFolder(SDL_Folder folder) 174{ 175 typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*); 176 HMODULE lib = LoadLibraryW(L"Shell32.dll"); 177 pfnSHGetKnownFolderPath pSHGetKnownFolderPath = NULL; 178 char *result = NULL; 179 180 if (lib) { 181 pSHGetKnownFolderPath = (pfnSHGetKnownFolderPath)GetProcAddress(lib, "SHGetKnownFolderPath"); 182 } 183 184 if (pSHGetKnownFolderPath) { 185 GUID type; // KNOWNFOLDERID 186 HRESULT hr; 187 wchar_t *path; 188 189 switch (folder) { 190 case SDL_FOLDER_HOME: 191 type = SDL_FOLDERID_Profile; 192 break; 193 194 case SDL_FOLDER_DESKTOP: 195 type = SDL_FOLDERID_Desktop; 196 break; 197 198 case SDL_FOLDER_DOCUMENTS: 199 type = SDL_FOLDERID_Documents; 200 break; 201 202 case SDL_FOLDER_DOWNLOADS: 203 type = SDL_FOLDERID_Downloads; 204 break; 205 206 case SDL_FOLDER_MUSIC: 207 type = SDL_FOLDERID_Music; 208 break; 209 210 case SDL_FOLDER_PICTURES: 211 type = SDL_FOLDERID_Pictures; 212 break; 213 214 case SDL_FOLDER_PUBLICSHARE: 215 SDL_SetError("Public share unavailable on Windows"); 216 goto done; 217 218 case SDL_FOLDER_SAVEDGAMES: 219 type = SDL_FOLDERID_SavedGames; 220 break; 221 222 case SDL_FOLDER_SCREENSHOTS: 223 type = SDL_FOLDERID_Screenshots; 224 break; 225 226 case SDL_FOLDER_TEMPLATES: 227 type = SDL_FOLDERID_Templates; 228 break; 229 230 case SDL_FOLDER_VIDEOS: 231 type = SDL_FOLDERID_Videos; 232 break; 233 234 default: 235 SDL_SetError("Invalid SDL_Folder: %d", (int)folder); 236 goto done; 237 }; 238 239 hr = pSHGetKnownFolderPath(&type, 0x00008000 /* KF_FLAG_CREATE */, NULL, &path); 240 if (SUCCEEDED(hr)) { 241 result = WIN_StringToUTF8W(path); 242 } else { 243 WIN_SetErrorFromHRESULT("Couldn't get folder", hr); 244 } 245 246 } else { 247 int type; 248 HRESULT hr; 249 wchar_t path[MAX_PATH]; 250 251 switch (folder) { 252 case SDL_FOLDER_HOME: 253 type = CSIDL_PROFILE; 254 break; 255 256 case SDL_FOLDER_DESKTOP: 257 type = CSIDL_DESKTOP; 258 break; 259 260 case SDL_FOLDER_DOCUMENTS: 261 type = CSIDL_MYDOCUMENTS; 262 break; 263 264 case SDL_FOLDER_DOWNLOADS: 265 SDL_SetError("Downloads folder unavailable before Vista"); 266 goto done; 267 268 case SDL_FOLDER_MUSIC: 269 type = CSIDL_MYMUSIC; 270 break; 271 272 case SDL_FOLDER_PICTURES: 273 type = CSIDL_MYPICTURES; 274 break; 275 276 case SDL_FOLDER_PUBLICSHARE: 277 SDL_SetError("Public share unavailable on Windows"); 278 goto done; 279 280 case SDL_FOLDER_SAVEDGAMES: 281 SDL_SetError("Saved games unavailable before Vista"); 282 goto done; 283 284 case SDL_FOLDER_SCREENSHOTS: 285 SDL_SetError("Screenshots folder unavailable before Vista"); 286 goto done; 287 288 case SDL_FOLDER_TEMPLATES: 289 type = CSIDL_TEMPLATES; 290 break; 291 292 case SDL_FOLDER_VIDEOS: 293 type = CSIDL_MYVIDEO; 294 break; 295 296 default: 297 SDL_SetError("Unsupported SDL_Folder on Windows before Vista: %d", (int)folder); 298 goto done; 299 }; 300 301 // Create the OS-specific folder if it doesn't already exist 302 type |= CSIDL_FLAG_CREATE; 303 304#if 0 305 // Apparently the oldest, but not supported in modern Windows 306 HRESULT hr = SHGetSpecialFolderPath(NULL, path, type, TRUE); 307#endif 308 309 /* Windows 2000/XP and later, deprecated as of Windows 10 (still 310 available), available in Wine (tested 6.0.3) */ 311 hr = SHGetFolderPathW(NULL, type, NULL, SHGFP_TYPE_CURRENT, path); 312 313 // use `== TRUE` for SHGetSpecialFolderPath 314 if (SUCCEEDED(hr)) { 315 result = WIN_StringToUTF8W(path); 316 } else { 317 WIN_SetErrorFromHRESULT("Couldn't get folder", hr); 318 } 319 } 320 321 if (result) { 322 char *newresult = (char *) SDL_realloc(result, SDL_strlen(result) + 2); 323 324 if (!newresult) { 325 SDL_free(result); 326 result = NULL; // will be returned 327 goto done; 328 } 329 330 result = newresult; 331 SDL_strlcat(result, "\\", SDL_strlen(result) + 2); 332 } 333 334done: 335 if (lib) { 336 FreeLibrary(lib); 337 } 338 return result; 339} 340 341char *SDL_SYS_GetCurrentDirectory(void) 342{ 343 WCHAR *wstr = NULL; 344 DWORD buflen = 0; 345 while (true) { 346 const DWORD bw = GetCurrentDirectoryW(buflen, wstr); 347 if (bw == 0) { 348 WIN_SetError("GetCurrentDirectoryW failed"); 349 return NULL; 350 } else if (bw < buflen) { // we got it! 351 // make sure there's a path separator at the end. 352 SDL_assert(bw < (buflen + 2)); 353 if ((bw == 0) || (wstr[bw-1] != '\\')) { 354 wstr[bw] = '\\'; 355 wstr[bw + 1] = '\0'; 356 } 357 break; 358 } 359 360 void *ptr = SDL_realloc(wstr, (bw + 1) * sizeof (WCHAR)); 361 if (!ptr) { 362 SDL_free(wstr); 363 return NULL; 364 } 365 wstr = (WCHAR *) ptr; 366 buflen = bw; 367 } 368 369 char *retval = WIN_StringToUTF8W(wstr); 370 SDL_free(wstr); 371 return retval; 372} 373 374#endif // SDL_FILESYSTEM_WINDOWS 375
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.