SDL_sysfilesystem.c (4998B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 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 "../../core/windows/SDL_windows.h" 29 #include <shlobj.h> 30 31 #include "SDL_error.h" 32 #include "SDL_stdinc.h" 33 #include "SDL_filesystem.h" 34 35 char * 36 SDL_GetBasePath(void) 37 { 38 typedef DWORD (WINAPI *GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD); 39 GetModuleFileNameExW_t pGetModuleFileNameExW; 40 DWORD buflen = 128; 41 WCHAR *path = NULL; 42 HANDLE psapi = LoadLibrary(L"psapi.dll"); 43 char *retval = NULL; 44 DWORD len = 0; 45 int i; 46 47 if (!psapi) { 48 WIN_SetError("Couldn't load psapi.dll"); 49 return NULL; 50 } 51 52 pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW"); 53 if (!pGetModuleFileNameExW) { 54 WIN_SetError("Couldn't find GetModuleFileNameExW"); 55 FreeLibrary(psapi); 56 return NULL; 57 } 58 59 while (SDL_TRUE) { 60 void *ptr = SDL_realloc(path, buflen * sizeof (WCHAR)); 61 if (!ptr) { 62 SDL_free(path); 63 FreeLibrary(psapi); 64 SDL_OutOfMemory(); 65 return NULL; 66 } 67 68 path = (WCHAR *) ptr; 69 70 len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen); 71 if (len != buflen) { 72 break; 73 } 74 75 /* buffer too small? Try again. */ 76 buflen *= 2; 77 } 78 79 FreeLibrary(psapi); 80 81 if (len == 0) { 82 SDL_free(path); 83 WIN_SetError("Couldn't locate our .exe"); 84 return NULL; 85 } 86 87 for (i = len-1; i > 0; i--) { 88 if (path[i] == '\\') { 89 break; 90 } 91 } 92 93 SDL_assert(i > 0); /* Should have been an absolute path. */ 94 path[i+1] = '\0'; /* chop off filename. */ 95 96 retval = WIN_StringToUTF8(path); 97 SDL_free(path); 98 99 return retval; 100 } 101 102 char * 103 SDL_GetPrefPath(const char *org, const char *app) 104 { 105 /* 106 * Vista and later has a new API for this, but SHGetFolderPath works there, 107 * and apparently just wraps the new API. This is the new way to do it: 108 * 109 * SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, 110 * NULL, &wszPath); 111 */ 112 113 WCHAR path[MAX_PATH]; 114 char *retval = NULL; 115 WCHAR* worg = NULL; 116 WCHAR* wapp = NULL; 117 size_t new_wpath_len = 0; 118 BOOL api_result = FALSE; 119 120 if (!app) { 121 SDL_InvalidParamError("app"); 122 return NULL; 123 } 124 if (!org) { 125 org = ""; 126 } 127 128 if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path))) { 129 WIN_SetError("Couldn't locate our prefpath"); 130 return NULL; 131 } 132 133 worg = WIN_UTF8ToString(org); 134 if (worg == NULL) { 135 SDL_OutOfMemory(); 136 return NULL; 137 } 138 139 wapp = WIN_UTF8ToString(app); 140 if (wapp == NULL) { 141 SDL_free(worg); 142 SDL_OutOfMemory(); 143 return NULL; 144 } 145 146 new_wpath_len = lstrlenW(worg) + lstrlenW(wapp) + lstrlenW(path) + 3; 147 148 if ((new_wpath_len + 1) > MAX_PATH) { 149 SDL_free(worg); 150 SDL_free(wapp); 151 WIN_SetError("Path too long."); 152 return NULL; 153 } 154 155 if (*worg) { 156 lstrcatW(path, L"\\"); 157 lstrcatW(path, worg); 158 } 159 SDL_free(worg); 160 161 api_result = CreateDirectoryW(path, NULL); 162 if (api_result == FALSE) { 163 if (GetLastError() != ERROR_ALREADY_EXISTS) { 164 SDL_free(wapp); 165 WIN_SetError("Couldn't create a prefpath."); 166 return NULL; 167 } 168 } 169 170 lstrcatW(path, L"\\"); 171 lstrcatW(path, wapp); 172 SDL_free(wapp); 173 174 api_result = CreateDirectoryW(path, NULL); 175 if (api_result == FALSE) { 176 if (GetLastError() != ERROR_ALREADY_EXISTS) { 177 WIN_SetError("Couldn't create a prefpath."); 178 return NULL; 179 } 180 } 181 182 lstrcatW(path, L"\\"); 183 184 retval = WIN_StringToUTF8(path); 185 186 return retval; 187 } 188 189 #endif /* SDL_FILESYSTEM_WINDOWS */ 190 191 /* vi: set ts=4 sw=4 expandtab: */