diff options
| author | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
| commit | 5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch) | |
| tree | 8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/filesystem | |
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/filesystem')
19 files changed, 3517 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem.c b/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem.c new file mode 100644 index 0000000..b115019 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem.c | |||
| @@ -0,0 +1,530 @@ | |||
| 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 | |||
| 22 | #include "SDL_internal.h" | ||
| 23 | |||
| 24 | #include "SDL_filesystem_c.h" | ||
| 25 | #include "SDL_sysfilesystem.h" | ||
| 26 | #include "../stdlib/SDL_sysstdlib.h" | ||
| 27 | |||
| 28 | bool SDL_RemovePath(const char *path) | ||
| 29 | { | ||
| 30 | if (!path) { | ||
| 31 | return SDL_InvalidParamError("path"); | ||
| 32 | } | ||
| 33 | return SDL_SYS_RemovePath(path); | ||
| 34 | } | ||
| 35 | |||
| 36 | bool SDL_RenamePath(const char *oldpath, const char *newpath) | ||
| 37 | { | ||
| 38 | if (!oldpath) { | ||
| 39 | return SDL_InvalidParamError("oldpath"); | ||
| 40 | } else if (!newpath) { | ||
| 41 | return SDL_InvalidParamError("newpath"); | ||
| 42 | } | ||
| 43 | return SDL_SYS_RenamePath(oldpath, newpath); | ||
| 44 | } | ||
| 45 | |||
| 46 | bool SDL_CopyFile(const char *oldpath, const char *newpath) | ||
| 47 | { | ||
| 48 | if (!oldpath) { | ||
| 49 | return SDL_InvalidParamError("oldpath"); | ||
| 50 | } else if (!newpath) { | ||
| 51 | return SDL_InvalidParamError("newpath"); | ||
| 52 | } | ||
| 53 | return SDL_SYS_CopyFile(oldpath, newpath); | ||
| 54 | } | ||
| 55 | |||
| 56 | bool SDL_CreateDirectory(const char *path) | ||
| 57 | { | ||
| 58 | if (!path) { | ||
| 59 | return SDL_InvalidParamError("path"); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool retval = SDL_SYS_CreateDirectory(path); | ||
| 63 | if (!retval && *path) { // maybe we're missing parent directories? | ||
| 64 | char *parents = SDL_strdup(path); | ||
| 65 | if (!parents) { | ||
| 66 | return false; // oh well. | ||
| 67 | } | ||
| 68 | |||
| 69 | // in case there was a separator at the end of the path and it was | ||
| 70 | // upsetting something, chop it off. | ||
| 71 | const size_t slen = SDL_strlen(parents); | ||
| 72 | #ifdef SDL_PLATFORM_WINDOWS | ||
| 73 | if ((parents[slen - 1] == '/') || (parents[slen - 1] == '\\')) | ||
| 74 | #else | ||
| 75 | if (parents[slen - 1] == '/') | ||
| 76 | #endif | ||
| 77 | { | ||
| 78 | parents[slen - 1] = '\0'; | ||
| 79 | retval = SDL_SYS_CreateDirectory(parents); | ||
| 80 | } | ||
| 81 | |||
| 82 | if (!retval) { | ||
| 83 | for (char *ptr = parents; *ptr; ptr++) { | ||
| 84 | const char ch = *ptr; | ||
| 85 | #ifdef SDL_PLATFORM_WINDOWS | ||
| 86 | const bool issep = (ch == '/') || (ch == '\\'); | ||
| 87 | if (issep && ((ptr - parents) == 2) && (parents[1] == ':')) { | ||
| 88 | continue; // it's just the drive letter, skip it. | ||
| 89 | } | ||
| 90 | #else | ||
| 91 | const bool issep = (ch == '/'); | ||
| 92 | if (issep && ((ptr - parents) == 0)) { | ||
| 93 | continue; // it's just the root directory, skip it. | ||
| 94 | } | ||
| 95 | #endif | ||
| 96 | |||
| 97 | if (issep) { | ||
| 98 | *ptr = '\0'; | ||
| 99 | // (this does not fail if the path already exists as a directory.) | ||
| 100 | retval = SDL_SYS_CreateDirectory(parents); | ||
| 101 | if (!retval) { // still failing when making parents? Give up. | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | *ptr = ch; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | // last chance: did it work this time? | ||
| 109 | retval = SDL_SYS_CreateDirectory(parents); | ||
| 110 | } | ||
| 111 | |||
| 112 | SDL_free(parents); | ||
| 113 | } | ||
| 114 | return retval; | ||
| 115 | } | ||
| 116 | |||
| 117 | bool SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata) | ||
| 118 | { | ||
| 119 | if (!path) { | ||
| 120 | return SDL_InvalidParamError("path"); | ||
| 121 | } else if (!callback) { | ||
| 122 | return SDL_InvalidParamError("callback"); | ||
| 123 | } | ||
| 124 | return SDL_SYS_EnumerateDirectory(path, callback, userdata); | ||
| 125 | } | ||
| 126 | |||
| 127 | bool SDL_GetPathInfo(const char *path, SDL_PathInfo *info) | ||
| 128 | { | ||
| 129 | SDL_PathInfo dummy; | ||
| 130 | |||
| 131 | if (!info) { | ||
| 132 | info = &dummy; | ||
| 133 | } | ||
| 134 | SDL_zerop(info); | ||
| 135 | |||
| 136 | if (!path) { | ||
| 137 | return SDL_InvalidParamError("path"); | ||
| 138 | } | ||
| 139 | |||
| 140 | return SDL_SYS_GetPathInfo(path, info); | ||
| 141 | } | ||
| 142 | |||
| 143 | static bool EverythingMatch(const char *pattern, const char *str, bool *matched_to_dir) | ||
| 144 | { | ||
| 145 | SDL_assert(pattern == NULL); | ||
| 146 | SDL_assert(str != NULL); | ||
| 147 | SDL_assert(matched_to_dir != NULL); | ||
| 148 | |||
| 149 | *matched_to_dir = true; | ||
| 150 | return true; // everything matches! | ||
| 151 | } | ||
| 152 | |||
| 153 | // this is just '*' and '?', with '/' matching nothing. | ||
| 154 | static bool WildcardMatch(const char *pattern, const char *str, bool *matched_to_dir) | ||
| 155 | { | ||
| 156 | SDL_assert(pattern != NULL); | ||
| 157 | SDL_assert(str != NULL); | ||
| 158 | SDL_assert(matched_to_dir != NULL); | ||
| 159 | |||
| 160 | const char *str_backtrack = NULL; | ||
| 161 | const char *pattern_backtrack = NULL; | ||
| 162 | char sch_backtrack = 0; | ||
| 163 | char sch = *str; | ||
| 164 | char pch = *pattern; | ||
| 165 | |||
| 166 | while (sch) { | ||
| 167 | if (pch == '*') { | ||
| 168 | str_backtrack = str; | ||
| 169 | pattern_backtrack = ++pattern; | ||
| 170 | sch_backtrack = sch; | ||
| 171 | pch = *pattern; | ||
| 172 | } else if (pch == sch) { | ||
| 173 | if (pch == '/') { | ||
| 174 | str_backtrack = pattern_backtrack = NULL; | ||
| 175 | } | ||
| 176 | sch = *(++str); | ||
| 177 | pch = *(++pattern); | ||
| 178 | } else if ((pch == '?') && (sch != '/')) { // end of string (checked at `while`) or path separator do not match '?'. | ||
| 179 | sch = *(++str); | ||
| 180 | pch = *(++pattern); | ||
| 181 | } else if (!pattern_backtrack || (sch_backtrack == '/')) { // we didn't have a match. Are we in a '*' and NOT on a path separator? Keep going. Otherwise, fail. | ||
| 182 | *matched_to_dir = false; | ||
| 183 | return false; | ||
| 184 | } else { // still here? Wasn't a match, but we're definitely in a '*' pattern. | ||
| 185 | str = ++str_backtrack; | ||
| 186 | pattern = pattern_backtrack; | ||
| 187 | sch_backtrack = sch; | ||
| 188 | sch = *str; | ||
| 189 | pch = *pattern; | ||
| 190 | } | ||
| 191 | |||
| 192 | #ifdef SDL_PLATFORM_WINDOWS | ||
| 193 | if (sch == '\\') { | ||
| 194 | sch = '/'; | ||
| 195 | } | ||
| 196 | #endif | ||
| 197 | } | ||
| 198 | |||
| 199 | // '*' at the end can be ignored, they are allowed to match nothing. | ||
| 200 | while (pch == '*') { | ||
| 201 | pch = *(++pattern); | ||
| 202 | } | ||
| 203 | |||
| 204 | *matched_to_dir = ((pch == '/') || (pch == '\0')); // end of string and the pattern is complete or failed at a '/'? We should descend into this directory. | ||
| 205 | |||
| 206 | return (pch == '\0'); // survived the whole pattern? That's a match! | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | // Note that this will currently encode illegal codepoints: UTF-16 surrogates, 0xFFFE, and 0xFFFF. | ||
| 211 | // and a codepoint > 0x10FFFF will fail the same as if there wasn't enough memory. | ||
| 212 | // clean this up if you want to move this to SDL_string.c. | ||
| 213 | static size_t EncodeCodepointToUtf8(char *ptr, Uint32 cp, size_t remaining) | ||
| 214 | { | ||
| 215 | if (cp < 0x80) { // fits in a single UTF-8 byte. | ||
| 216 | if (remaining) { | ||
| 217 | *ptr = (char) cp; | ||
| 218 | return 1; | ||
| 219 | } | ||
| 220 | } else if (cp < 0x800) { // fits in 2 bytes. | ||
| 221 | if (remaining >= 2) { | ||
| 222 | ptr[0] = (char) ((cp >> 6) | 128 | 64); | ||
| 223 | ptr[1] = (char) (cp & 0x3F) | 128; | ||
| 224 | return 2; | ||
| 225 | } | ||
| 226 | } else if (cp < 0x10000) { // fits in 3 bytes. | ||
| 227 | if (remaining >= 3) { | ||
| 228 | ptr[0] = (char) ((cp >> 12) | 128 | 64 | 32); | ||
| 229 | ptr[1] = (char) ((cp >> 6) & 0x3F) | 128; | ||
| 230 | ptr[2] = (char) (cp & 0x3F) | 128; | ||
| 231 | return 3; | ||
| 232 | } | ||
| 233 | } else if (cp <= 0x10FFFF) { // fits in 4 bytes. | ||
| 234 | if (remaining >= 4) { | ||
| 235 | ptr[0] = (char) ((cp >> 18) | 128 | 64 | 32 | 16); | ||
| 236 | ptr[1] = (char) ((cp >> 12) & 0x3F) | 128; | ||
| 237 | ptr[2] = (char) ((cp >> 6) & 0x3F) | 128; | ||
| 238 | ptr[3] = (char) (cp & 0x3F) | 128; | ||
| 239 | return 4; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static char *CaseFoldUtf8String(const char *fname) | ||
| 247 | { | ||
| 248 | SDL_assert(fname != NULL); | ||
| 249 | const size_t allocation = (SDL_strlen(fname) + 1) * 3 * 4; | ||
| 250 | char *result = (char *) SDL_malloc(allocation); // lazy: just allocating the max needed. | ||
| 251 | if (!result) { | ||
| 252 | return NULL; | ||
| 253 | } | ||
| 254 | |||
| 255 | Uint32 codepoint; | ||
| 256 | char *ptr = result; | ||
| 257 | size_t remaining = allocation; | ||
| 258 | while ((codepoint = SDL_StepUTF8(&fname, NULL)) != 0) { | ||
| 259 | Uint32 folded[3]; | ||
| 260 | const int num_folded = SDL_CaseFoldUnicode(codepoint, folded); | ||
| 261 | SDL_assert(num_folded > 0); | ||
| 262 | SDL_assert(num_folded <= SDL_arraysize(folded)); | ||
| 263 | for (int i = 0; i < num_folded; i++) { | ||
| 264 | SDL_assert(remaining > 0); | ||
| 265 | const size_t rc = EncodeCodepointToUtf8(ptr, folded[i], remaining); | ||
| 266 | SDL_assert(rc > 0); | ||
| 267 | SDL_assert(rc < remaining); | ||
| 268 | remaining -= rc; | ||
| 269 | ptr += rc; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | SDL_assert(remaining > 0); | ||
| 274 | remaining--; | ||
| 275 | *ptr = '\0'; | ||
| 276 | |||
| 277 | if (remaining > 0) { | ||
| 278 | SDL_assert(allocation > remaining); | ||
| 279 | ptr = (char *)SDL_realloc(result, allocation - remaining); // shrink it down. | ||
| 280 | if (ptr) { // shouldn't fail, but if it does, `result` is still valid. | ||
| 281 | result = ptr; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | return result; | ||
| 286 | } | ||
| 287 | |||
| 288 | |||
| 289 | typedef struct GlobDirCallbackData | ||
| 290 | { | ||
| 291 | bool (*matcher)(const char *pattern, const char *str, bool *matched_to_dir); | ||
| 292 | const char *pattern; | ||
| 293 | int num_entries; | ||
| 294 | SDL_GlobFlags flags; | ||
| 295 | SDL_GlobEnumeratorFunc enumerator; | ||
| 296 | SDL_GlobGetPathInfoFunc getpathinfo; | ||
| 297 | void *fsuserdata; | ||
| 298 | size_t basedirlen; | ||
| 299 | SDL_IOStream *string_stream; | ||
| 300 | } GlobDirCallbackData; | ||
| 301 | |||
| 302 | static SDL_EnumerationResult SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, const char *fname) | ||
| 303 | { | ||
| 304 | SDL_assert(userdata != NULL); | ||
| 305 | SDL_assert(dirname != NULL); | ||
| 306 | SDL_assert(fname != NULL); | ||
| 307 | |||
| 308 | //SDL_Log("GlobDirectoryCallback('%s', '%s')", dirname, fname); | ||
| 309 | |||
| 310 | GlobDirCallbackData *data = (GlobDirCallbackData *) userdata; | ||
| 311 | |||
| 312 | // !!! FIXME: if we're careful, we can keep a single buffer in `data` that we push and pop paths off the end of as we walk the tree, | ||
| 313 | // !!! FIXME: and only casefold the new pieces instead of allocating and folding full paths for all of this. | ||
| 314 | |||
| 315 | char *fullpath = NULL; | ||
| 316 | if (SDL_asprintf(&fullpath, "%s%s", dirname, fname) < 0) { | ||
| 317 | return SDL_ENUM_FAILURE; | ||
| 318 | } | ||
| 319 | |||
| 320 | char *folded = NULL; | ||
| 321 | if (data->flags & SDL_GLOB_CASEINSENSITIVE) { | ||
| 322 | folded = CaseFoldUtf8String(fullpath); | ||
| 323 | if (!folded) { | ||
| 324 | return SDL_ENUM_FAILURE; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | bool matched_to_dir = false; | ||
| 329 | const bool matched = data->matcher(data->pattern, (folded ? folded : fullpath) + data->basedirlen, &matched_to_dir); | ||
| 330 | //SDL_Log("GlobDirectoryCallback: Considered %spath='%s' vs pattern='%s': %smatched (matched_to_dir=%s)", folded ? "(folded) " : "", (folded ? folded : fullpath) + data->basedirlen, data->pattern, matched ? "" : "NOT ", matched_to_dir ? "TRUE" : "FALSE"); | ||
| 331 | SDL_free(folded); | ||
| 332 | |||
| 333 | if (matched) { | ||
| 334 | const char *subpath = fullpath + data->basedirlen; | ||
| 335 | const size_t slen = SDL_strlen(subpath) + 1; | ||
| 336 | if (SDL_WriteIO(data->string_stream, subpath, slen) != slen) { | ||
| 337 | SDL_free(fullpath); | ||
| 338 | return SDL_ENUM_FAILURE; // stop enumerating, return failure to the app. | ||
| 339 | } | ||
| 340 | data->num_entries++; | ||
| 341 | } | ||
| 342 | |||
| 343 | SDL_EnumerationResult result = SDL_ENUM_CONTINUE; // keep enumerating by default. | ||
| 344 | if (matched_to_dir) { | ||
| 345 | SDL_PathInfo info; | ||
| 346 | if (data->getpathinfo(fullpath, &info, data->fsuserdata) && (info.type == SDL_PATHTYPE_DIRECTORY)) { | ||
| 347 | //SDL_Log("GlobDirectoryCallback: Descending into subdir '%s'", fname); | ||
| 348 | if (!data->enumerator(fullpath, GlobDirectoryCallback, data, data->fsuserdata)) { | ||
| 349 | result = SDL_ENUM_FAILURE; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | SDL_free(fullpath); | ||
| 355 | |||
| 356 | return result; | ||
| 357 | } | ||
| 358 | |||
| 359 | char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count, SDL_GlobEnumeratorFunc enumerator, SDL_GlobGetPathInfoFunc getpathinfo, void *userdata) | ||
| 360 | { | ||
| 361 | int dummycount; | ||
| 362 | if (!count) { | ||
| 363 | count = &dummycount; | ||
| 364 | } | ||
| 365 | *count = 0; | ||
| 366 | |||
| 367 | if (!path) { | ||
| 368 | SDL_InvalidParamError("path"); | ||
| 369 | return NULL; | ||
| 370 | } | ||
| 371 | |||
| 372 | // if path ends with any slash, chop them off, so we don't confuse the pattern matcher later. | ||
| 373 | char *pathcpy = NULL; | ||
| 374 | size_t pathlen = SDL_strlen(path); | ||
| 375 | if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) { | ||
| 376 | pathcpy = SDL_strdup(path); | ||
| 377 | if (!pathcpy) { | ||
| 378 | return NULL; | ||
| 379 | } | ||
| 380 | char *ptr = &pathcpy[pathlen-1]; | ||
| 381 | while ((ptr >= pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) { | ||
| 382 | *(ptr--) = '\0'; | ||
| 383 | } | ||
| 384 | path = pathcpy; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (!pattern) { | ||
| 388 | flags &= ~SDL_GLOB_CASEINSENSITIVE; // avoid some unnecessary allocations and work later. | ||
| 389 | } | ||
| 390 | |||
| 391 | char *folded = NULL; | ||
| 392 | if (flags & SDL_GLOB_CASEINSENSITIVE) { | ||
| 393 | SDL_assert(pattern != NULL); | ||
| 394 | folded = CaseFoldUtf8String(pattern); | ||
| 395 | if (!folded) { | ||
| 396 | SDL_free(pathcpy); | ||
| 397 | return NULL; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | GlobDirCallbackData data; | ||
| 402 | SDL_zero(data); | ||
| 403 | data.string_stream = SDL_IOFromDynamicMem(); | ||
| 404 | if (!data.string_stream) { | ||
| 405 | SDL_free(folded); | ||
| 406 | SDL_free(pathcpy); | ||
| 407 | return NULL; | ||
| 408 | } | ||
| 409 | |||
| 410 | if (!pattern) { | ||
| 411 | data.matcher = EverythingMatch; // no pattern? Everything matches. | ||
| 412 | |||
| 413 | // !!! FIXME | ||
| 414 | //} else if (flags & SDL_GLOB_GITIGNORE) { | ||
| 415 | // data.matcher = GitIgnoreMatch; | ||
| 416 | |||
| 417 | } else { | ||
| 418 | data.matcher = WildcardMatch; | ||
| 419 | } | ||
| 420 | |||
| 421 | data.pattern = folded ? folded : pattern; | ||
| 422 | data.flags = flags; | ||
| 423 | data.enumerator = enumerator; | ||
| 424 | data.getpathinfo = getpathinfo; | ||
| 425 | data.fsuserdata = userdata; | ||
| 426 | data.basedirlen = *path ? (SDL_strlen(path) + 1) : 0; // +1 for the '/' we'll be adding. | ||
| 427 | |||
| 428 | |||
| 429 | char **result = NULL; | ||
| 430 | if (data.enumerator(path, GlobDirectoryCallback, &data, data.fsuserdata)) { | ||
| 431 | const size_t streamlen = (size_t) SDL_GetIOSize(data.string_stream); | ||
| 432 | const size_t buflen = streamlen + ((data.num_entries + 1) * sizeof (char *)); // +1 for NULL terminator at end of array. | ||
| 433 | result = (char **) SDL_malloc(buflen); | ||
| 434 | if (result) { | ||
| 435 | if (data.num_entries > 0) { | ||
| 436 | Sint64 iorc = SDL_SeekIO(data.string_stream, 0, SDL_IO_SEEK_SET); | ||
| 437 | SDL_assert(iorc == 0); // this should never fail for a memory stream! | ||
| 438 | char *ptr = (char *) (result + (data.num_entries + 1)); | ||
| 439 | iorc = SDL_ReadIO(data.string_stream, ptr, streamlen); | ||
| 440 | SDL_assert(iorc == (Sint64) streamlen); // this should never fail for a memory stream! | ||
| 441 | for (int i = 0; i < data.num_entries; i++) { | ||
| 442 | result[i] = ptr; | ||
| 443 | ptr += SDL_strlen(ptr) + 1; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | result[data.num_entries] = NULL; // NULL terminate the list. | ||
| 447 | *count = data.num_entries; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | SDL_CloseIO(data.string_stream); | ||
| 452 | SDL_free(folded); | ||
| 453 | SDL_free(pathcpy); | ||
| 454 | |||
| 455 | return result; | ||
| 456 | } | ||
| 457 | |||
| 458 | static bool GlobDirectoryGetPathInfo(const char *path, SDL_PathInfo *info, void *userdata) | ||
| 459 | { | ||
| 460 | return SDL_GetPathInfo(path, info); | ||
| 461 | } | ||
| 462 | |||
| 463 | static bool GlobDirectoryEnumerator(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata) | ||
| 464 | { | ||
| 465 | return SDL_EnumerateDirectory(path, cb, cbuserdata); | ||
| 466 | } | ||
| 467 | |||
| 468 | char **SDL_GlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count) | ||
| 469 | { | ||
| 470 | //SDL_Log("SDL_GlobDirectory('%s', '%s') ...", path, pattern); | ||
| 471 | return SDL_InternalGlobDirectory(path, pattern, flags, count, GlobDirectoryEnumerator, GlobDirectoryGetPathInfo, NULL); | ||
| 472 | } | ||
| 473 | |||
| 474 | |||
| 475 | static char *CachedBasePath = NULL; | ||
| 476 | |||
| 477 | const char *SDL_GetBasePath(void) | ||
| 478 | { | ||
| 479 | if (!CachedBasePath) { | ||
| 480 | CachedBasePath = SDL_SYS_GetBasePath(); | ||
| 481 | } | ||
| 482 | return CachedBasePath; | ||
| 483 | } | ||
| 484 | |||
| 485 | |||
| 486 | static char *CachedUserFolders[SDL_FOLDER_COUNT]; | ||
| 487 | |||
| 488 | const char *SDL_GetUserFolder(SDL_Folder folder) | ||
| 489 | { | ||
| 490 | const int idx = (int) folder; | ||
| 491 | if ((idx < 0) || (idx >= SDL_arraysize(CachedUserFolders))) { | ||
| 492 | SDL_InvalidParamError("folder"); | ||
| 493 | return NULL; | ||
| 494 | } | ||
| 495 | |||
| 496 | if (!CachedUserFolders[idx]) { | ||
| 497 | CachedUserFolders[idx] = SDL_SYS_GetUserFolder(folder); | ||
| 498 | } | ||
| 499 | return CachedUserFolders[idx]; | ||
| 500 | } | ||
| 501 | |||
| 502 | |||
| 503 | char *SDL_GetPrefPath(const char *org, const char *app) | ||
| 504 | { | ||
| 505 | return SDL_SYS_GetPrefPath(org, app); | ||
| 506 | } | ||
| 507 | |||
| 508 | char *SDL_GetCurrentDirectory(void) | ||
| 509 | { | ||
| 510 | return SDL_SYS_GetCurrentDirectory(); | ||
| 511 | } | ||
| 512 | |||
| 513 | void SDL_InitFilesystem(void) | ||
| 514 | { | ||
| 515 | } | ||
| 516 | |||
| 517 | void SDL_QuitFilesystem(void) | ||
| 518 | { | ||
| 519 | if (CachedBasePath) { | ||
| 520 | SDL_free(CachedBasePath); | ||
| 521 | CachedBasePath = NULL; | ||
| 522 | } | ||
| 523 | for (int i = 0; i < SDL_arraysize(CachedUserFolders); i++) { | ||
| 524 | if (CachedUserFolders[i]) { | ||
| 525 | SDL_free(CachedUserFolders[i]); | ||
| 526 | CachedUserFolders[i] = NULL; | ||
| 527 | } | ||
| 528 | } | ||
| 529 | } | ||
| 530 | |||
diff --git a/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem_c.h b/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem_c.h new file mode 100644 index 0000000..8cfdcab --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/SDL_filesystem_c.h | |||
| @@ -0,0 +1,29 @@ | |||
| 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 | |||
| 22 | #ifndef SDL_filesystem_c_h_ | ||
| 23 | #define SDL_filesystem_c_h_ | ||
| 24 | |||
| 25 | extern void SDL_InitFilesystem(void); | ||
| 26 | extern void SDL_QuitFilesystem(void); | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
diff --git a/contrib/SDL-3.2.8/src/filesystem/SDL_sysfilesystem.h b/contrib/SDL-3.2.8/src/filesystem/SDL_sysfilesystem.h new file mode 100644 index 0000000..f9f4c59 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/SDL_sysfilesystem.h | |||
| @@ -0,0 +1,43 @@ | |||
| 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 | |||
| 22 | #ifndef SDL_sysfilesystem_h_ | ||
| 23 | #define SDL_sysfilesystem_h_ | ||
| 24 | |||
| 25 | // return a string that we can SDL_free(). It will be cached at the higher level. | ||
| 26 | extern char *SDL_SYS_GetBasePath(void); | ||
| 27 | extern char *SDL_SYS_GetPrefPath(const char *org, const char *app); | ||
| 28 | extern char *SDL_SYS_GetUserFolder(SDL_Folder folder); | ||
| 29 | extern char *SDL_SYS_GetCurrentDirectory(void); | ||
| 30 | |||
| 31 | extern bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata); | ||
| 32 | extern bool SDL_SYS_RemovePath(const char *path); | ||
| 33 | extern bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath); | ||
| 34 | extern bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath); | ||
| 35 | extern bool SDL_SYS_CreateDirectory(const char *path); | ||
| 36 | extern bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info); | ||
| 37 | |||
| 38 | typedef bool (*SDL_GlobEnumeratorFunc)(const char *path, SDL_EnumerateDirectoryCallback cb, void *cbuserdata, void *userdata); | ||
| 39 | typedef bool (*SDL_GlobGetPathInfoFunc)(const char *path, SDL_PathInfo *info, void *userdata); | ||
| 40 | extern char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count, SDL_GlobEnumeratorFunc enumerator, SDL_GlobGetPathInfoFunc getpathinfo, void *userdata); | ||
| 41 | |||
| 42 | #endif | ||
| 43 | |||
diff --git a/contrib/SDL-3.2.8/src/filesystem/android/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/android/SDL_sysfilesystem.c new file mode 100644 index 0000000..bb42409 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/android/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,62 @@ | |||
| 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_ANDROID | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <unistd.h> | ||
| 31 | |||
| 32 | char *SDL_SYS_GetBasePath(void) | ||
| 33 | { | ||
| 34 | // The current working directory is / on Android | ||
| 35 | SDL_Unsupported(); | ||
| 36 | return NULL; | ||
| 37 | } | ||
| 38 | |||
| 39 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 40 | { | ||
| 41 | const char *path = SDL_GetAndroidInternalStoragePath(); | ||
| 42 | if (path) { | ||
| 43 | size_t pathlen = SDL_strlen(path) + 2; | ||
| 44 | char *fullpath = (char *)SDL_malloc(pathlen); | ||
| 45 | if (!fullpath) { | ||
| 46 | return NULL; | ||
| 47 | } | ||
| 48 | SDL_snprintf(fullpath, pathlen, "%s/", path); | ||
| 49 | return fullpath; | ||
| 50 | } | ||
| 51 | return NULL; | ||
| 52 | } | ||
| 53 | |||
| 54 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 55 | { | ||
| 56 | /* TODO: see https://developer.android.com/reference/android/os/Environment#lfields | ||
| 57 | and https://stackoverflow.com/questions/39332085/get-path-to-pictures-directory */ | ||
| 58 | SDL_Unsupported(); | ||
| 59 | return NULL; | ||
| 60 | } | ||
| 61 | |||
| 62 | #endif // SDL_FILESYSTEM_ANDROID | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/cocoa/SDL_sysfilesystem.m b/contrib/SDL-3.2.8/src/filesystem/cocoa/SDL_sysfilesystem.m new file mode 100644 index 0000000..5818764 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/cocoa/SDL_sysfilesystem.m | |||
| @@ -0,0 +1,240 @@ | |||
| 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_COCOA | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <Foundation/Foundation.h> | ||
| 31 | #include <sys/stat.h> | ||
| 32 | #include <sys/types.h> | ||
| 33 | |||
| 34 | char *SDL_SYS_GetBasePath(void) | ||
| 35 | { | ||
| 36 | @autoreleasepool { | ||
| 37 | NSBundle *bundle = [NSBundle mainBundle]; | ||
| 38 | const char *baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String]; | ||
| 39 | const char *base = NULL; | ||
| 40 | char *result = NULL; | ||
| 41 | |||
| 42 | if (baseType == NULL) { | ||
| 43 | baseType = "resource"; | ||
| 44 | } | ||
| 45 | if (SDL_strcasecmp(baseType, "bundle") == 0) { | ||
| 46 | base = [[bundle bundlePath] fileSystemRepresentation]; | ||
| 47 | } else if (SDL_strcasecmp(baseType, "parent") == 0) { | ||
| 48 | base = [[[bundle bundlePath] stringByDeletingLastPathComponent] fileSystemRepresentation]; | ||
| 49 | } else { | ||
| 50 | // this returns the exedir for non-bundled and the resourceDir for bundled apps | ||
| 51 | base = [[bundle resourcePath] fileSystemRepresentation]; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (base) { | ||
| 55 | const size_t len = SDL_strlen(base) + 2; | ||
| 56 | result = (char *)SDL_malloc(len); | ||
| 57 | if (result != NULL) { | ||
| 58 | SDL_snprintf(result, len, "%s/", base); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | return result; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 67 | { | ||
| 68 | @autoreleasepool { | ||
| 69 | char *result = NULL; | ||
| 70 | NSArray *array; | ||
| 71 | |||
| 72 | if (!app) { | ||
| 73 | SDL_InvalidParamError("app"); | ||
| 74 | return NULL; | ||
| 75 | } | ||
| 76 | if (!org) { | ||
| 77 | org = ""; | ||
| 78 | } | ||
| 79 | |||
| 80 | #ifndef SDL_PLATFORM_TVOS | ||
| 81 | array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); | ||
| 82 | #else | ||
| 83 | /* tvOS does not have persistent local storage! | ||
| 84 | * The only place on-device where we can store data is | ||
| 85 | * a cache directory that the OS can empty at any time. | ||
| 86 | * | ||
| 87 | * It's therefore very likely that save data will be erased | ||
| 88 | * between sessions. If you want your app's save data to | ||
| 89 | * actually stick around, you'll need to use iCloud storage. | ||
| 90 | */ | ||
| 91 | { | ||
| 92 | static bool shown = false; | ||
| 93 | if (!shown) { | ||
| 94 | shown = true; | ||
| 95 | SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "tvOS does not have persistent local storage! Use iCloud storage if you want your data to persist between sessions."); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); | ||
| 100 | #endif // !SDL_PLATFORM_TVOS | ||
| 101 | |||
| 102 | if ([array count] > 0) { // we only want the first item in the list. | ||
| 103 | NSString *str = [array objectAtIndex:0]; | ||
| 104 | const char *base = [str fileSystemRepresentation]; | ||
| 105 | if (base) { | ||
| 106 | const size_t len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4; | ||
| 107 | result = (char *)SDL_malloc(len); | ||
| 108 | if (result != NULL) { | ||
| 109 | char *ptr; | ||
| 110 | if (*org) { | ||
| 111 | SDL_snprintf(result, len, "%s/%s/%s/", base, org, app); | ||
| 112 | } else { | ||
| 113 | SDL_snprintf(result, len, "%s/%s/", base, app); | ||
| 114 | } | ||
| 115 | for (ptr = result + 1; *ptr; ptr++) { | ||
| 116 | if (*ptr == '/') { | ||
| 117 | *ptr = '\0'; | ||
| 118 | mkdir(result, 0700); | ||
| 119 | *ptr = '/'; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | mkdir(result, 0700); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | return result; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 132 | { | ||
| 133 | @autoreleasepool { | ||
| 134 | #ifdef SDL_PLATFORM_TVOS | ||
| 135 | SDL_SetError("tvOS does not have persistent storage"); | ||
| 136 | return NULL; | ||
| 137 | #else | ||
| 138 | char *result = NULL; | ||
| 139 | const char* base; | ||
| 140 | NSArray *array; | ||
| 141 | NSSearchPathDirectory dir; | ||
| 142 | NSString *str; | ||
| 143 | char *ptr; | ||
| 144 | |||
| 145 | switch (folder) { | ||
| 146 | case SDL_FOLDER_HOME: | ||
| 147 | base = SDL_getenv("HOME"); | ||
| 148 | |||
| 149 | if (!base) { | ||
| 150 | SDL_SetError("No $HOME environment variable available"); | ||
| 151 | return NULL; | ||
| 152 | } | ||
| 153 | |||
| 154 | goto append_slash; | ||
| 155 | |||
| 156 | case SDL_FOLDER_DESKTOP: | ||
| 157 | dir = NSDesktopDirectory; | ||
| 158 | break; | ||
| 159 | |||
| 160 | case SDL_FOLDER_DOCUMENTS: | ||
| 161 | dir = NSDocumentDirectory; | ||
| 162 | break; | ||
| 163 | |||
| 164 | case SDL_FOLDER_DOWNLOADS: | ||
| 165 | dir = NSDownloadsDirectory; | ||
| 166 | break; | ||
| 167 | |||
| 168 | case SDL_FOLDER_MUSIC: | ||
| 169 | dir = NSMusicDirectory; | ||
| 170 | break; | ||
| 171 | |||
| 172 | case SDL_FOLDER_PICTURES: | ||
| 173 | dir = NSPicturesDirectory; | ||
| 174 | break; | ||
| 175 | |||
| 176 | case SDL_FOLDER_PUBLICSHARE: | ||
| 177 | dir = NSSharedPublicDirectory; | ||
| 178 | break; | ||
| 179 | |||
| 180 | case SDL_FOLDER_SAVEDGAMES: | ||
| 181 | SDL_SetError("Saved games folder not supported on Cocoa"); | ||
| 182 | return NULL; | ||
| 183 | |||
| 184 | case SDL_FOLDER_SCREENSHOTS: | ||
| 185 | SDL_SetError("Screenshots folder not supported on Cocoa"); | ||
| 186 | return NULL; | ||
| 187 | |||
| 188 | case SDL_FOLDER_TEMPLATES: | ||
| 189 | SDL_SetError("Templates folder not supported on Cocoa"); | ||
| 190 | return NULL; | ||
| 191 | |||
| 192 | case SDL_FOLDER_VIDEOS: | ||
| 193 | dir = NSMoviesDirectory; | ||
| 194 | break; | ||
| 195 | |||
| 196 | default: | ||
| 197 | SDL_SetError("Invalid SDL_Folder: %d", (int) folder); | ||
| 198 | return NULL; | ||
| 199 | }; | ||
| 200 | |||
| 201 | array = NSSearchPathForDirectoriesInDomains(dir, NSUserDomainMask, YES); | ||
| 202 | |||
| 203 | if ([array count] <= 0) { | ||
| 204 | SDL_SetError("Directory not found"); | ||
| 205 | return NULL; | ||
| 206 | } | ||
| 207 | |||
| 208 | str = [array objectAtIndex:0]; | ||
| 209 | base = [str fileSystemRepresentation]; | ||
| 210 | if (!base) { | ||
| 211 | SDL_SetError("Couldn't get folder path"); | ||
| 212 | return NULL; | ||
| 213 | } | ||
| 214 | |||
| 215 | append_slash: | ||
| 216 | result = SDL_malloc(SDL_strlen(base) + 2); | ||
| 217 | if (result == NULL) { | ||
| 218 | return NULL; | ||
| 219 | } | ||
| 220 | |||
| 221 | if (SDL_snprintf(result, SDL_strlen(base) + 2, "%s/", base) < 0) { | ||
| 222 | SDL_SetError("Couldn't snprintf folder path for Cocoa: %s", base); | ||
| 223 | SDL_free(result); | ||
| 224 | return NULL; | ||
| 225 | } | ||
| 226 | |||
| 227 | for (ptr = result + 1; *ptr; ptr++) { | ||
| 228 | if (*ptr == '/') { | ||
| 229 | *ptr = '\0'; | ||
| 230 | mkdir(result, 0700); | ||
| 231 | *ptr = '/'; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | return result; | ||
| 236 | #endif // SDL_PLATFORM_TVOS | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | #endif // SDL_FILESYSTEM_COCOA | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfilesystem.c new file mode 100644 index 0000000..5634c70 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,54 @@ | |||
| 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 | #if defined(SDL_FILESYSTEM_DUMMY) || defined(SDL_FILESYSTEM_DISABLED) | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | char *SDL_SYS_GetBasePath(void) | ||
| 31 | { | ||
| 32 | SDL_Unsupported(); | ||
| 33 | return NULL; | ||
| 34 | } | ||
| 35 | |||
| 36 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 37 | { | ||
| 38 | SDL_Unsupported(); | ||
| 39 | return NULL; | ||
| 40 | } | ||
| 41 | |||
| 42 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 43 | { | ||
| 44 | SDL_Unsupported(); | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 | |||
| 48 | char *SDL_SYS_GetCurrentDirectory(void) | ||
| 49 | { | ||
| 50 | SDL_Unsupported(); | ||
| 51 | return NULL; | ||
| 52 | } | ||
| 53 | |||
| 54 | #endif // SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfsops.c b/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfsops.c new file mode 100644 index 0000000..d8553e9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/dummy/SDL_sysfsops.c | |||
| @@ -0,0 +1,62 @@ | |||
| 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 | |||
| 22 | #include "SDL_internal.h" | ||
| 23 | |||
| 24 | #if defined(SDL_FSOPS_DUMMY) | ||
| 25 | |||
| 26 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 27 | // System dependent filesystem routines | ||
| 28 | |||
| 29 | #include "../SDL_sysfilesystem.h" | ||
| 30 | |||
| 31 | bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) | ||
| 32 | { | ||
| 33 | return SDL_Unsupported(); | ||
| 34 | } | ||
| 35 | |||
| 36 | bool SDL_SYS_RemovePath(const char *path) | ||
| 37 | { | ||
| 38 | return SDL_Unsupported(); | ||
| 39 | } | ||
| 40 | |||
| 41 | bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath) | ||
| 42 | { | ||
| 43 | return SDL_Unsupported(); | ||
| 44 | } | ||
| 45 | |||
| 46 | bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath) | ||
| 47 | { | ||
| 48 | return SDL_Unsupported(); | ||
| 49 | } | ||
| 50 | |||
| 51 | bool SDL_SYS_CreateDirectory(const char *path) | ||
| 52 | { | ||
| 53 | return SDL_Unsupported(); | ||
| 54 | } | ||
| 55 | |||
| 56 | bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info) | ||
| 57 | { | ||
| 58 | return SDL_Unsupported(); | ||
| 59 | } | ||
| 60 | |||
| 61 | #endif // SDL_FSOPS_DUMMY | ||
| 62 | |||
diff --git a/contrib/SDL-3.2.8/src/filesystem/emscripten/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/emscripten/SDL_sysfilesystem.c new file mode 100644 index 0000000..29dc053 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/emscripten/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,116 @@ | |||
| 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_EMSCRIPTEN | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <errno.h> | ||
| 31 | #include <sys/stat.h> | ||
| 32 | |||
| 33 | #include <emscripten/emscripten.h> | ||
| 34 | |||
| 35 | char *SDL_SYS_GetBasePath(void) | ||
| 36 | { | ||
| 37 | return SDL_strdup("/"); | ||
| 38 | } | ||
| 39 | |||
| 40 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 41 | { | ||
| 42 | const char *append = "/libsdl/"; | ||
| 43 | char *result; | ||
| 44 | char *ptr = NULL; | ||
| 45 | size_t len = 0; | ||
| 46 | |||
| 47 | if (!app) { | ||
| 48 | SDL_InvalidParamError("app"); | ||
| 49 | return NULL; | ||
| 50 | } | ||
| 51 | if (!org) { | ||
| 52 | org = ""; | ||
| 53 | } | ||
| 54 | |||
| 55 | len = SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; | ||
| 56 | result = (char *)SDL_malloc(len); | ||
| 57 | if (!result) { | ||
| 58 | return NULL; | ||
| 59 | } | ||
| 60 | |||
| 61 | if (*org) { | ||
| 62 | SDL_snprintf(result, len, "%s%s/%s/", append, org, app); | ||
| 63 | } else { | ||
| 64 | SDL_snprintf(result, len, "%s%s/", append, app); | ||
| 65 | } | ||
| 66 | |||
| 67 | for (ptr = result + 1; *ptr; ptr++) { | ||
| 68 | if (*ptr == '/') { | ||
| 69 | *ptr = '\0'; | ||
| 70 | if (mkdir(result, 0700) != 0 && errno != EEXIST) { | ||
| 71 | goto error; | ||
| 72 | } | ||
| 73 | *ptr = '/'; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | if (mkdir(result, 0700) != 0 && errno != EEXIST) { | ||
| 78 | error: | ||
| 79 | SDL_SetError("Couldn't create directory '%s': '%s'", result, strerror(errno)); | ||
| 80 | SDL_free(result); | ||
| 81 | return NULL; | ||
| 82 | } | ||
| 83 | |||
| 84 | return result; | ||
| 85 | } | ||
| 86 | |||
| 87 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 88 | { | ||
| 89 | const char *home = NULL; | ||
| 90 | |||
| 91 | if (folder != SDL_FOLDER_HOME) { | ||
| 92 | SDL_SetError("Emscripten only supports the home folder"); | ||
| 93 | return NULL; | ||
| 94 | } | ||
| 95 | |||
| 96 | home = SDL_getenv("HOME"); | ||
| 97 | if (!home) { | ||
| 98 | SDL_SetError("No $HOME environment variable available"); | ||
| 99 | return NULL; | ||
| 100 | } | ||
| 101 | |||
| 102 | char *result = SDL_malloc(SDL_strlen(home) + 2); | ||
| 103 | if (!result) { | ||
| 104 | return NULL; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (SDL_snprintf(result, SDL_strlen(home) + 2, "%s/", home) < 0) { | ||
| 108 | SDL_SetError("Couldn't snprintf home path for Emscripten: %s", home); | ||
| 109 | SDL_free(result); | ||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | return result; | ||
| 114 | } | ||
| 115 | |||
| 116 | #endif // SDL_FILESYSTEM_EMSCRIPTEN | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/gdk/SDL_sysfilesystem.cpp b/contrib/SDL-3.2.8/src/filesystem/gdk/SDL_sysfilesystem.cpp new file mode 100644 index 0000000..ffafe43 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/gdk/SDL_sysfilesystem.cpp | |||
| @@ -0,0 +1,150 @@ | |||
| 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 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 24 | // System dependent filesystem routines | ||
| 25 | |||
| 26 | extern "C" { | ||
| 27 | #include "../SDL_sysfilesystem.h" | ||
| 28 | } | ||
| 29 | |||
| 30 | #include "../../core/windows/SDL_windows.h" | ||
| 31 | #include <SDL3/SDL_hints.h> | ||
| 32 | #include <SDL3/SDL_system.h> | ||
| 33 | #include <SDL3/SDL_filesystem.h> | ||
| 34 | #include <XGameSaveFiles.h> | ||
| 35 | |||
| 36 | char * | ||
| 37 | SDL_SYS_GetBasePath(void) | ||
| 38 | { | ||
| 39 | /* NOTE: This function is a UTF8 version of the Win32 SDL_GetBasePath()! | ||
| 40 | * The GDK actually _recommends_ the 'A' functions over the 'W' functions :o | ||
| 41 | */ | ||
| 42 | DWORD buflen = 128; | ||
| 43 | CHAR *path = NULL; | ||
| 44 | DWORD len = 0; | ||
| 45 | int i; | ||
| 46 | |||
| 47 | while (true) { | ||
| 48 | void *ptr = SDL_realloc(path, buflen * sizeof(CHAR)); | ||
| 49 | if (!ptr) { | ||
| 50 | SDL_free(path); | ||
| 51 | return NULL; | ||
| 52 | } | ||
| 53 | |||
| 54 | path = (CHAR *)ptr; | ||
| 55 | |||
| 56 | len = GetModuleFileNameA(NULL, path, buflen); | ||
| 57 | // if it truncated, then len >= buflen - 1 | ||
| 58 | // if there was enough room (or failure), len < buflen - 1 | ||
| 59 | if (len < buflen - 1) { | ||
| 60 | break; | ||
| 61 | } | ||
| 62 | |||
| 63 | // buffer too small? Try again. | ||
| 64 | buflen *= 2; | ||
| 65 | } | ||
| 66 | |||
| 67 | if (len == 0) { | ||
| 68 | SDL_free(path); | ||
| 69 | WIN_SetError("Couldn't locate our .exe"); | ||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | for (i = len - 1; i > 0; i--) { | ||
| 74 | if (path[i] == '\\') { | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | SDL_assert(i > 0); // Should have been an absolute path. | ||
| 80 | path[i + 1] = '\0'; // chop off filename. | ||
| 81 | |||
| 82 | return path; | ||
| 83 | } | ||
| 84 | |||
| 85 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 86 | { | ||
| 87 | XUserHandle user = NULL; | ||
| 88 | XAsyncBlock block = { 0 }; | ||
| 89 | char *folderPath; | ||
| 90 | HRESULT result; | ||
| 91 | const char *csid = SDL_GetHint("SDL_GDK_SERVICE_CONFIGURATION_ID"); | ||
| 92 | |||
| 93 | if (!app) { | ||
| 94 | SDL_InvalidParamError("app"); | ||
| 95 | return NULL; | ||
| 96 | } | ||
| 97 | |||
| 98 | // This should be set before calling SDL_GetPrefPath! | ||
| 99 | if (!csid) { | ||
| 100 | SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Set SDL_GDK_SERVICE_CONFIGURATION_ID before calling SDL_GetPrefPath!"); | ||
| 101 | return SDL_strdup("T:\\"); | ||
| 102 | } | ||
| 103 | |||
| 104 | if (!SDL_GetGDKDefaultUser(&user)) { | ||
| 105 | // Error already set, just return | ||
| 106 | return NULL; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (FAILED(result = XGameSaveFilesGetFolderWithUiAsync(user, csid, &block))) { | ||
| 110 | WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiAsync", result); | ||
| 111 | return NULL; | ||
| 112 | } | ||
| 113 | |||
| 114 | folderPath = (char*) SDL_malloc(MAX_PATH); | ||
| 115 | do { | ||
| 116 | result = XGameSaveFilesGetFolderWithUiResult(&block, MAX_PATH, folderPath); | ||
| 117 | } while (result == E_PENDING); | ||
| 118 | if (FAILED(result)) { | ||
| 119 | WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiResult", result); | ||
| 120 | SDL_free(folderPath); | ||
| 121 | return NULL; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* We aren't using 'app' here because the container rules are a lot more | ||
| 125 | * strict than the NTFS rules, so it will most likely be invalid :( | ||
| 126 | */ | ||
| 127 | SDL_strlcat(folderPath, "\\SDLPrefPath\\", MAX_PATH); | ||
| 128 | if (CreateDirectoryA(folderPath, NULL) == FALSE) { | ||
| 129 | if (GetLastError() != ERROR_ALREADY_EXISTS) { | ||
| 130 | WIN_SetError("CreateDirectoryA"); | ||
| 131 | SDL_free(folderPath); | ||
| 132 | return NULL; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | return folderPath; | ||
| 136 | } | ||
| 137 | |||
| 138 | // TODO | ||
| 139 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 140 | { | ||
| 141 | SDL_Unsupported(); | ||
| 142 | return NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | // TODO | ||
| 146 | char *SDL_SYS_GetCurrentDirectory(void) | ||
| 147 | { | ||
| 148 | SDL_Unsupported(); | ||
| 149 | return NULL; | ||
| 150 | } | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/haiku/SDL_sysfilesystem.cc b/contrib/SDL-3.2.8/src/filesystem/haiku/SDL_sysfilesystem.cc new file mode 100644 index 0000000..af8b5ab --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/haiku/SDL_sysfilesystem.cc | |||
| @@ -0,0 +1,156 @@ | |||
| 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_HAIKU | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | extern "C" { | ||
| 29 | #include "../SDL_sysfilesystem.h" | ||
| 30 | } | ||
| 31 | |||
| 32 | #include <kernel/image.h> | ||
| 33 | #include <storage/Directory.h> | ||
| 34 | #include <storage/Entry.h> | ||
| 35 | #include <storage/FindDirectory.h> | ||
| 36 | #include <storage/Path.h> | ||
| 37 | |||
| 38 | |||
| 39 | char *SDL_SYS_GetBasePath(void) | ||
| 40 | { | ||
| 41 | char name[MAXPATHLEN]; | ||
| 42 | |||
| 43 | if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, name, sizeof(name)) != B_OK) { | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | |||
| 47 | BEntry entry(name, true); | ||
| 48 | BPath path; | ||
| 49 | status_t rc = entry.GetPath(&path); // (path) now has binary's path. | ||
| 50 | SDL_assert(rc == B_OK); | ||
| 51 | rc = path.GetParent(&path); // chop filename, keep directory. | ||
| 52 | SDL_assert(rc == B_OK); | ||
| 53 | const char *str = path.Path(); | ||
| 54 | SDL_assert(str != NULL); | ||
| 55 | |||
| 56 | const size_t len = SDL_strlen(str); | ||
| 57 | char *result = (char *) SDL_malloc(len + 2); | ||
| 58 | if (result) { | ||
| 59 | SDL_memcpy(result, str, len); | ||
| 60 | result[len] = '/'; | ||
| 61 | result[len+1] = '\0'; | ||
| 62 | } | ||
| 63 | |||
| 64 | return result; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 69 | { | ||
| 70 | // !!! FIXME: is there a better way to do this? | ||
| 71 | const char *home = SDL_getenv("HOME"); | ||
| 72 | const char *append = "/config/settings/"; | ||
| 73 | size_t len = SDL_strlen(home); | ||
| 74 | |||
| 75 | if (!app) { | ||
| 76 | SDL_InvalidParamError("app"); | ||
| 77 | return NULL; | ||
| 78 | } | ||
| 79 | if (!org) { | ||
| 80 | org = ""; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (!len || (home[len - 1] == '/')) { | ||
| 84 | ++append; // home empty or ends with separator, skip the one from append | ||
| 85 | } | ||
| 86 | len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; | ||
| 87 | char *result = (char *) SDL_malloc(len); | ||
| 88 | if (result) { | ||
| 89 | if (*org) { | ||
| 90 | SDL_snprintf(result, len, "%s%s%s/%s/", home, append, org, app); | ||
| 91 | } else { | ||
| 92 | SDL_snprintf(result, len, "%s%s%s/", home, append, app); | ||
| 93 | } | ||
| 94 | create_directory(result, 0700); // Haiku api: creates missing dirs | ||
| 95 | } | ||
| 96 | |||
| 97 | return result; | ||
| 98 | } | ||
| 99 | |||
| 100 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 101 | { | ||
| 102 | const char *home = NULL; | ||
| 103 | char *result; | ||
| 104 | |||
| 105 | home = SDL_getenv("HOME"); | ||
| 106 | if (!home) { | ||
| 107 | SDL_SetError("No $HOME environment variable available"); | ||
| 108 | return NULL; | ||
| 109 | } | ||
| 110 | |||
| 111 | switch (folder) { | ||
| 112 | case SDL_FOLDER_HOME: | ||
| 113 | result = (char *) SDL_malloc(SDL_strlen(home) + 2); | ||
| 114 | if (!result) { | ||
| 115 | return NULL; | ||
| 116 | } | ||
| 117 | |||
| 118 | if (SDL_snprintf(result, SDL_strlen(home) + 2, "%s/", home) < 0) { | ||
| 119 | SDL_SetError("Couldn't snprintf home path for Haiku: %s", home); | ||
| 120 | SDL_free(result); | ||
| 121 | return NULL; | ||
| 122 | } | ||
| 123 | |||
| 124 | return result; | ||
| 125 | |||
| 126 | // TODO: Is Haiku's desktop folder always ~/Desktop/ ? | ||
| 127 | case SDL_FOLDER_DESKTOP: | ||
| 128 | result = (char *) SDL_malloc(SDL_strlen(home) + 10); | ||
| 129 | if (!result) { | ||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (SDL_snprintf(result, SDL_strlen(home) + 10, "%s/Desktop/", home) < 0) { | ||
| 134 | SDL_SetError("Couldn't snprintf desktop path for Haiku: %s/Desktop/", home); | ||
| 135 | SDL_free(result); | ||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | |||
| 139 | return result; | ||
| 140 | |||
| 141 | case SDL_FOLDER_DOCUMENTS: | ||
| 142 | case SDL_FOLDER_DOWNLOADS: | ||
| 143 | case SDL_FOLDER_MUSIC: | ||
| 144 | case SDL_FOLDER_PICTURES: | ||
| 145 | case SDL_FOLDER_PUBLICSHARE: | ||
| 146 | case SDL_FOLDER_SAVEDGAMES: | ||
| 147 | case SDL_FOLDER_SCREENSHOTS: | ||
| 148 | case SDL_FOLDER_TEMPLATES: | ||
| 149 | case SDL_FOLDER_VIDEOS: | ||
| 150 | default: | ||
| 151 | SDL_SetError("Only HOME and DESKTOP available on Haiku"); | ||
| 152 | return NULL; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | #endif // SDL_FILESYSTEM_HAIKU | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/n3ds/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/n3ds/SDL_sysfilesystem.c new file mode 100644 index 0000000..8386a91 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/n3ds/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,90 @@ | |||
| 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_N3DS | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <3ds.h> | ||
| 31 | #include <dirent.h> | ||
| 32 | #include <errno.h> | ||
| 33 | |||
| 34 | static char *MakePrefPath(const char *app); | ||
| 35 | static bool CreatePrefPathDir(const char *pref); | ||
| 36 | |||
| 37 | char *SDL_SYS_GetBasePath(void) | ||
| 38 | { | ||
| 39 | char *base_path = SDL_strdup("romfs:/"); | ||
| 40 | return base_path; | ||
| 41 | } | ||
| 42 | |||
| 43 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 44 | { | ||
| 45 | char *pref_path = NULL; | ||
| 46 | if (!app) { | ||
| 47 | SDL_InvalidParamError("app"); | ||
| 48 | return NULL; | ||
| 49 | } | ||
| 50 | |||
| 51 | pref_path = MakePrefPath(app); | ||
| 52 | if (!pref_path) { | ||
| 53 | return NULL; | ||
| 54 | } | ||
| 55 | |||
| 56 | if (!CreatePrefPathDir(pref_path)) { | ||
| 57 | SDL_free(pref_path); | ||
| 58 | return NULL; | ||
| 59 | } | ||
| 60 | |||
| 61 | return pref_path; | ||
| 62 | } | ||
| 63 | |||
| 64 | // TODO | ||
| 65 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 66 | { | ||
| 67 | SDL_Unsupported(); | ||
| 68 | return NULL; | ||
| 69 | } | ||
| 70 | |||
| 71 | static char *MakePrefPath(const char *app) | ||
| 72 | { | ||
| 73 | char *pref_path; | ||
| 74 | if (SDL_asprintf(&pref_path, "sdmc:/3ds/%s/", app) < 0) { | ||
| 75 | return NULL; | ||
| 76 | } | ||
| 77 | return pref_path; | ||
| 78 | } | ||
| 79 | |||
| 80 | static bool CreatePrefPathDir(const char *pref) | ||
| 81 | { | ||
| 82 | int result = mkdir(pref, 0666); | ||
| 83 | |||
| 84 | if (result == -1 && errno != EEXIST) { | ||
| 85 | return SDL_SetError("Failed to create '%s' (%s)", pref, strerror(errno)); | ||
| 86 | } | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | #endif // SDL_FILESYSTEM_N3DS | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/posix/SDL_sysfsops.c b/contrib/SDL-3.2.8/src/filesystem/posix/SDL_sysfsops.c new file mode 100644 index 0000000..015b8d4 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/posix/SDL_sysfsops.c | |||
| @@ -0,0 +1,246 @@ | |||
| 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 | |||
| 22 | #include "SDL_internal.h" | ||
| 23 | |||
| 24 | #if defined(SDL_FSOPS_POSIX) | ||
| 25 | |||
| 26 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 27 | // System dependent filesystem routines | ||
| 28 | |||
| 29 | #include "../SDL_sysfilesystem.h" | ||
| 30 | |||
| 31 | #include <stdio.h> | ||
| 32 | #include <string.h> | ||
| 33 | #include <errno.h> | ||
| 34 | #include <dirent.h> | ||
| 35 | #include <sys/stat.h> | ||
| 36 | #include <unistd.h> | ||
| 37 | |||
| 38 | bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) | ||
| 39 | { | ||
| 40 | char *pathwithsep = NULL; | ||
| 41 | int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", path); | ||
| 42 | if ((pathwithseplen == -1) || (!pathwithsep)) { | ||
| 43 | return false; | ||
| 44 | } | ||
| 45 | |||
| 46 | // trim down to a single path separator at the end, in case the caller added one or more. | ||
| 47 | pathwithseplen--; | ||
| 48 | while ((pathwithseplen >= 0) && (pathwithsep[pathwithseplen] == '/')) { | ||
| 49 | pathwithsep[pathwithseplen--] = '\0'; | ||
| 50 | } | ||
| 51 | |||
| 52 | DIR *dir = opendir(pathwithsep); | ||
| 53 | if (!dir) { | ||
| 54 | SDL_free(pathwithsep); | ||
| 55 | return SDL_SetError("Can't open directory: %s", strerror(errno)); | ||
| 56 | } | ||
| 57 | |||
| 58 | // make sure there's a path separator at the end now for the actual callback. | ||
| 59 | pathwithsep[++pathwithseplen] = '/'; | ||
| 60 | pathwithsep[++pathwithseplen] = '\0'; | ||
| 61 | |||
| 62 | SDL_EnumerationResult result = SDL_ENUM_CONTINUE; | ||
| 63 | struct dirent *ent; | ||
| 64 | while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL)) { | ||
| 65 | const char *name = ent->d_name; | ||
| 66 | if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) { | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | result = cb(userdata, pathwithsep, name); | ||
| 70 | } | ||
| 71 | |||
| 72 | closedir(dir); | ||
| 73 | |||
| 74 | SDL_free(pathwithsep); | ||
| 75 | |||
| 76 | return (result != SDL_ENUM_FAILURE); | ||
| 77 | } | ||
| 78 | |||
| 79 | bool SDL_SYS_RemovePath(const char *path) | ||
| 80 | { | ||
| 81 | int rc = remove(path); | ||
| 82 | if (rc < 0) { | ||
| 83 | if (errno == ENOENT) { | ||
| 84 | // It's already gone, this is a success | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | return SDL_SetError("Can't remove path: %s", strerror(errno)); | ||
| 88 | } | ||
| 89 | return true; | ||
| 90 | } | ||
| 91 | |||
| 92 | bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath) | ||
| 93 | { | ||
| 94 | if (rename(oldpath, newpath) < 0) { | ||
| 95 | return SDL_SetError("Can't rename path: %s", strerror(errno)); | ||
| 96 | } | ||
| 97 | return true; | ||
| 98 | } | ||
| 99 | |||
| 100 | bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath) | ||
| 101 | { | ||
| 102 | char *buffer = NULL; | ||
| 103 | SDL_IOStream *input = NULL; | ||
| 104 | SDL_IOStream *output = NULL; | ||
| 105 | const size_t maxlen = 4096; | ||
| 106 | size_t len; | ||
| 107 | bool result = false; | ||
| 108 | |||
| 109 | input = SDL_IOFromFile(oldpath, "rb"); | ||
| 110 | if (!input) { | ||
| 111 | goto done; | ||
| 112 | } | ||
| 113 | |||
| 114 | output = SDL_IOFromFile(newpath, "wb"); | ||
| 115 | if (!output) { | ||
| 116 | goto done; | ||
| 117 | } | ||
| 118 | |||
| 119 | buffer = (char *)SDL_malloc(maxlen); | ||
| 120 | if (!buffer) { | ||
| 121 | goto done; | ||
| 122 | } | ||
| 123 | |||
| 124 | while ((len = SDL_ReadIO(input, buffer, maxlen)) > 0) { | ||
| 125 | if (SDL_WriteIO(output, buffer, len) < len) { | ||
| 126 | goto done; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | if (SDL_GetIOStatus(input) != SDL_IO_STATUS_EOF) { | ||
| 130 | goto done; | ||
| 131 | } | ||
| 132 | |||
| 133 | SDL_CloseIO(input); | ||
| 134 | input = NULL; | ||
| 135 | |||
| 136 | if (!SDL_FlushIO(output)) { | ||
| 137 | goto done; | ||
| 138 | } | ||
| 139 | |||
| 140 | result = SDL_CloseIO(output); | ||
| 141 | output = NULL; // it's gone, even if it failed. | ||
| 142 | |||
| 143 | done: | ||
| 144 | if (output) { | ||
| 145 | SDL_CloseIO(output); | ||
| 146 | } | ||
| 147 | if (input) { | ||
| 148 | SDL_CloseIO(input); | ||
| 149 | } | ||
| 150 | SDL_free(buffer); | ||
| 151 | |||
| 152 | return result; | ||
| 153 | } | ||
| 154 | |||
| 155 | bool SDL_SYS_CreateDirectory(const char *path) | ||
| 156 | { | ||
| 157 | const int rc = mkdir(path, 0770); | ||
| 158 | if (rc < 0) { | ||
| 159 | const int origerrno = errno; | ||
| 160 | if (origerrno == EEXIST) { | ||
| 161 | struct stat statbuf; | ||
| 162 | if ((stat(path, &statbuf) == 0) && (S_ISDIR(statbuf.st_mode))) { | ||
| 163 | return true; // it already exists and it's a directory, consider it success. | ||
| 164 | } | ||
| 165 | } | ||
| 166 | return SDL_SetError("Can't create directory: %s", strerror(origerrno)); | ||
| 167 | } | ||
| 168 | return true; | ||
| 169 | } | ||
| 170 | |||
| 171 | bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info) | ||
| 172 | { | ||
| 173 | struct stat statbuf; | ||
| 174 | const int rc = stat(path, &statbuf); | ||
| 175 | if (rc < 0) { | ||
| 176 | return SDL_SetError("Can't stat: %s", strerror(errno)); | ||
| 177 | } else if (S_ISREG(statbuf.st_mode)) { | ||
| 178 | info->type = SDL_PATHTYPE_FILE; | ||
| 179 | info->size = (Uint64) statbuf.st_size; | ||
| 180 | } else if (S_ISDIR(statbuf.st_mode)) { | ||
| 181 | info->type = SDL_PATHTYPE_DIRECTORY; | ||
| 182 | info->size = 0; | ||
| 183 | } else { | ||
| 184 | info->type = SDL_PATHTYPE_OTHER; | ||
| 185 | info->size = (Uint64) statbuf.st_size; | ||
| 186 | } | ||
| 187 | |||
| 188 | #if defined(HAVE_ST_MTIM) | ||
| 189 | // POSIX.1-2008 standard | ||
| 190 | info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctim.tv_sec) + statbuf.st_ctim.tv_nsec; | ||
| 191 | info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtim.tv_sec) + statbuf.st_mtim.tv_nsec; | ||
| 192 | info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atim.tv_sec) + statbuf.st_atim.tv_nsec; | ||
| 193 | #elif defined(SDL_PLATFORM_APPLE) | ||
| 194 | /* Apple platform stat structs use 'st_*timespec' naming. */ | ||
| 195 | info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctimespec.tv_sec) + statbuf.st_ctimespec.tv_nsec; | ||
| 196 | info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtimespec.tv_sec) + statbuf.st_mtimespec.tv_nsec; | ||
| 197 | info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atimespec.tv_sec) + statbuf.st_atimespec.tv_nsec; | ||
| 198 | #else | ||
| 199 | info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctime); | ||
| 200 | info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtime); | ||
| 201 | info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atime); | ||
| 202 | #endif | ||
| 203 | return true; | ||
| 204 | } | ||
| 205 | |||
| 206 | // Note that this isn't actually part of filesystem, not fsops, but everything that uses posix fsops uses this implementation, even with separate filesystem code. | ||
| 207 | char *SDL_SYS_GetCurrentDirectory(void) | ||
| 208 | { | ||
| 209 | size_t buflen = 64; | ||
| 210 | char *buf = NULL; | ||
| 211 | |||
| 212 | while (true) { | ||
| 213 | void *ptr = SDL_realloc(buf, buflen); | ||
| 214 | if (!ptr) { | ||
| 215 | SDL_free(buf); | ||
| 216 | return NULL; | ||
| 217 | } | ||
| 218 | buf = (char *) ptr; | ||
| 219 | |||
| 220 | if (getcwd(buf, buflen-1) != NULL) { | ||
| 221 | break; // we got it! | ||
| 222 | } | ||
| 223 | |||
| 224 | if (errno == ERANGE) { | ||
| 225 | buflen *= 2; // try again with a bigger buffer. | ||
| 226 | continue; | ||
| 227 | } | ||
| 228 | |||
| 229 | SDL_free(buf); | ||
| 230 | SDL_SetError("getcwd failed: %s", strerror(errno)); | ||
| 231 | return NULL; | ||
| 232 | } | ||
| 233 | |||
| 234 | // make sure there's a path separator at the end. | ||
| 235 | SDL_assert(SDL_strlen(buf) < (buflen + 2)); | ||
| 236 | buflen = SDL_strlen(buf); | ||
| 237 | if ((buflen == 0) || (buf[buflen-1] != '/')) { | ||
| 238 | buf[buflen] = '/'; | ||
| 239 | buf[buflen + 1] = '\0'; | ||
| 240 | } | ||
| 241 | |||
| 242 | return buf; | ||
| 243 | } | ||
| 244 | |||
| 245 | #endif // SDL_FSOPS_POSIX | ||
| 246 | |||
diff --git a/contrib/SDL-3.2.8/src/filesystem/ps2/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/ps2/SDL_sysfilesystem.c new file mode 100644 index 0000000..ca69c2b --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/ps2/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,119 @@ | |||
| 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_PS2 | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | |||
| 33 | char *SDL_SYS_GetBasePath(void) | ||
| 34 | { | ||
| 35 | char *result = NULL; | ||
| 36 | size_t len; | ||
| 37 | char cwd[FILENAME_MAX]; | ||
| 38 | |||
| 39 | getcwd(cwd, sizeof(cwd)); | ||
| 40 | len = SDL_strlen(cwd) + 2; | ||
| 41 | result = (char *)SDL_malloc(len); | ||
| 42 | if (result) { | ||
| 43 | SDL_snprintf(result, len, "%s/", cwd); | ||
| 44 | } | ||
| 45 | |||
| 46 | return result; | ||
| 47 | } | ||
| 48 | |||
| 49 | // Do a recursive mkdir of parents folders | ||
| 50 | static void recursive_mkdir(const char *dir) | ||
| 51 | { | ||
| 52 | char tmp[FILENAME_MAX]; | ||
| 53 | const char *base = SDL_GetBasePath(); | ||
| 54 | char *p = NULL; | ||
| 55 | size_t len; | ||
| 56 | |||
| 57 | SDL_snprintf(tmp, sizeof(tmp), "%s", dir); | ||
| 58 | len = SDL_strlen(tmp); | ||
| 59 | if (tmp[len - 1] == '/') { | ||
| 60 | tmp[len - 1] = 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | for (p = tmp + 1; *p; p++) { | ||
| 64 | if (*p == '/') { | ||
| 65 | *p = 0; | ||
| 66 | // Just creating subfolders from current path | ||
| 67 | if (base && SDL_strstr(tmp, base) != NULL) { | ||
| 68 | mkdir(tmp, S_IRWXU); | ||
| 69 | } | ||
| 70 | |||
| 71 | *p = '/'; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | mkdir(tmp, S_IRWXU); | ||
| 76 | } | ||
| 77 | |||
| 78 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 79 | { | ||
| 80 | char *result = NULL; | ||
| 81 | size_t len; | ||
| 82 | |||
| 83 | if (!app) { | ||
| 84 | SDL_InvalidParamError("app"); | ||
| 85 | return NULL; | ||
| 86 | } | ||
| 87 | |||
| 88 | if (!org) { | ||
| 89 | org = ""; | ||
| 90 | } | ||
| 91 | |||
| 92 | const char *base = SDL_GetBasePath(); | ||
| 93 | if (!base) { | ||
| 94 | return NULL; | ||
| 95 | } | ||
| 96 | |||
| 97 | len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4; | ||
| 98 | result = (char *)SDL_malloc(len); | ||
| 99 | if (result) { | ||
| 100 | if (*org) { | ||
| 101 | SDL_snprintf(result, len, "%s%s/%s/", base, org, app); | ||
| 102 | } else { | ||
| 103 | SDL_snprintf(result, len, "%s%s/", base, app); | ||
| 104 | } | ||
| 105 | |||
| 106 | recursive_mkdir(result); | ||
| 107 | } | ||
| 108 | |||
| 109 | return result; | ||
| 110 | } | ||
| 111 | |||
| 112 | // TODO | ||
| 113 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 114 | { | ||
| 115 | SDL_Unsupported(); | ||
| 116 | return NULL; | ||
| 117 | } | ||
| 118 | |||
| 119 | #endif // SDL_FILESYSTEM_PS2 | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/psp/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/psp/SDL_sysfilesystem.c new file mode 100644 index 0000000..4b40055 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/psp/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,89 @@ | |||
| 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_PSP | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | |||
| 33 | char *SDL_SYS_GetBasePath(void) | ||
| 34 | { | ||
| 35 | char *result = NULL; | ||
| 36 | size_t len; | ||
| 37 | char cwd[FILENAME_MAX]; | ||
| 38 | |||
| 39 | getcwd(cwd, sizeof(cwd)); | ||
| 40 | len = SDL_strlen(cwd) + 2; | ||
| 41 | result = (char *)SDL_malloc(len); | ||
| 42 | if (result) { | ||
| 43 | SDL_snprintf(result, len, "%s/", cwd); | ||
| 44 | } | ||
| 45 | |||
| 46 | return result; | ||
| 47 | } | ||
| 48 | |||
| 49 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 50 | { | ||
| 51 | char *result = NULL; | ||
| 52 | size_t len; | ||
| 53 | if (!app) { | ||
| 54 | SDL_InvalidParamError("app"); | ||
| 55 | return NULL; | ||
| 56 | } | ||
| 57 | |||
| 58 | const char *base = SDL_GetBasePath(); | ||
| 59 | if (!base) { | ||
| 60 | return NULL; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (!org) { | ||
| 64 | org = ""; | ||
| 65 | } | ||
| 66 | |||
| 67 | len = SDL_strlen(base) + SDL_strlen(org) + SDL_strlen(app) + 4; | ||
| 68 | result = (char *)SDL_malloc(len); | ||
| 69 | if (result) { | ||
| 70 | if (*org) { | ||
| 71 | SDL_snprintf(result, len, "%s%s/%s/", base, org, app); | ||
| 72 | } else { | ||
| 73 | SDL_snprintf(result, len, "%s%s/", base, app); | ||
| 74 | } | ||
| 75 | |||
| 76 | mkdir(result, 0755); | ||
| 77 | } | ||
| 78 | |||
| 79 | return result; | ||
| 80 | } | ||
| 81 | |||
| 82 | // TODO | ||
| 83 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 84 | { | ||
| 85 | SDL_Unsupported(); | ||
| 86 | return NULL; | ||
| 87 | } | ||
| 88 | |||
| 89 | #endif // SDL_FILESYSTEM_PSP | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/riscos/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/riscos/SDL_sysfilesystem.c new file mode 100644 index 0000000..95ed80f --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/riscos/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,208 @@ | |||
| 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_RISCOS | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <kernel.h> | ||
| 31 | #include <swis.h> | ||
| 32 | #include <unixlib/local.h> | ||
| 33 | |||
| 34 | // Wrapper around __unixify_std that uses SDL's memory allocators | ||
| 35 | static char *SDL_unixify_std(const char *ro_path, char *buffer, size_t buf_len, int filetype) | ||
| 36 | { | ||
| 37 | const char *const in_buf = buffer; // = NULL if we allocate the buffer. | ||
| 38 | |||
| 39 | if (!buffer) { | ||
| 40 | /* This matches the logic in __unixify, with an additional byte for the | ||
| 41 | * extra path separator. | ||
| 42 | */ | ||
| 43 | buf_len = SDL_strlen(ro_path) + 14 + 1; | ||
| 44 | buffer = SDL_malloc(buf_len); | ||
| 45 | |||
| 46 | if (!buffer) { | ||
| 47 | return NULL; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | if (!__unixify_std(ro_path, buffer, buf_len, filetype)) { | ||
| 52 | if (!in_buf) { | ||
| 53 | SDL_free(buffer); | ||
| 54 | } | ||
| 55 | |||
| 56 | SDL_SetError("Could not convert '%s' to a Unix-style path", ro_path); | ||
| 57 | return NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* HACK: It's necessary to add an extra path separator here since SDL's API | ||
| 61 | * requires it, however paths with trailing separators aren't normally valid | ||
| 62 | * on RISC OS. | ||
| 63 | */ | ||
| 64 | if (__get_riscosify_control() & __RISCOSIFY_NO_PROCESS) | ||
| 65 | SDL_strlcat(buffer, ".", buf_len); | ||
| 66 | else | ||
| 67 | SDL_strlcat(buffer, "/", buf_len); | ||
| 68 | |||
| 69 | return buffer; | ||
| 70 | } | ||
| 71 | |||
| 72 | static char *canonicalisePath(const char *path, const char *pathVar) | ||
| 73 | { | ||
| 74 | _kernel_oserror *error; | ||
| 75 | _kernel_swi_regs regs; | ||
| 76 | char *buf; | ||
| 77 | |||
| 78 | regs.r[0] = 37; | ||
| 79 | regs.r[1] = (int)path; | ||
| 80 | regs.r[2] = 0; | ||
| 81 | regs.r[3] = (int)pathVar; | ||
| 82 | regs.r[4] = 0; | ||
| 83 | regs.r[5] = 0; | ||
| 84 | error = _kernel_swi(OS_FSControl, ®s, ®s); | ||
| 85 | if (error) { | ||
| 86 | SDL_SetError("Couldn't canonicalise path: %s", error->errmess); | ||
| 87 | return NULL; | ||
| 88 | } | ||
| 89 | |||
| 90 | regs.r[5] = 1 - regs.r[5]; | ||
| 91 | buf = SDL_malloc(regs.r[5]); | ||
| 92 | if (!buf) { | ||
| 93 | return NULL; | ||
| 94 | } | ||
| 95 | regs.r[2] = (int)buf; | ||
| 96 | error = _kernel_swi(OS_FSControl, ®s, ®s); | ||
| 97 | if (error) { | ||
| 98 | SDL_SetError("Couldn't canonicalise path: %s", error->errmess); | ||
| 99 | SDL_free(buf); | ||
| 100 | return NULL; | ||
| 101 | } | ||
| 102 | |||
| 103 | return buf; | ||
| 104 | } | ||
| 105 | |||
| 106 | static _kernel_oserror *createDirectoryRecursive(char *path) | ||
| 107 | { | ||
| 108 | char *ptr = NULL; | ||
| 109 | _kernel_oserror *error; | ||
| 110 | _kernel_swi_regs regs; | ||
| 111 | regs.r[0] = 8; | ||
| 112 | regs.r[1] = (int)path; | ||
| 113 | regs.r[2] = 0; | ||
| 114 | |||
| 115 | for (ptr = path + 1; *ptr; ptr++) { | ||
| 116 | if (*ptr == '.') { | ||
| 117 | *ptr = '\0'; | ||
| 118 | error = _kernel_swi(OS_File, ®s, ®s); | ||
| 119 | *ptr = '.'; | ||
| 120 | if (error) { | ||
| 121 | return error; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | return _kernel_swi(OS_File, ®s, ®s); | ||
| 126 | } | ||
| 127 | |||
| 128 | char *SDL_SYS_GetBasePath(void) | ||
| 129 | { | ||
| 130 | _kernel_swi_regs regs; | ||
| 131 | _kernel_oserror *error; | ||
| 132 | char *canon, *ptr, *result; | ||
| 133 | |||
| 134 | error = _kernel_swi(OS_GetEnv, ®s, ®s); | ||
| 135 | if (error) { | ||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | |||
| 139 | canon = canonicalisePath((const char *)regs.r[0], "Run$Path"); | ||
| 140 | if (!canon) { | ||
| 141 | return NULL; | ||
| 142 | } | ||
| 143 | |||
| 144 | // chop off filename. | ||
| 145 | ptr = SDL_strrchr(canon, '.'); | ||
| 146 | if (ptr) { | ||
| 147 | *ptr = '\0'; | ||
| 148 | } | ||
| 149 | |||
| 150 | result = SDL_unixify_std(canon, NULL, 0, __RISCOSIFY_FILETYPE_NOTSPECIFIED); | ||
| 151 | SDL_free(canon); | ||
| 152 | return result; | ||
| 153 | } | ||
| 154 | |||
| 155 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 156 | { | ||
| 157 | char *canon, *dir, *result; | ||
| 158 | size_t len; | ||
| 159 | _kernel_oserror *error; | ||
| 160 | |||
| 161 | if (!app) { | ||
| 162 | SDL_InvalidParamError("app"); | ||
| 163 | return NULL; | ||
| 164 | } | ||
| 165 | if (!org) { | ||
| 166 | org = ""; | ||
| 167 | } | ||
| 168 | |||
| 169 | canon = canonicalisePath("<Choices$Write>", "Run$Path"); | ||
| 170 | if (!canon) { | ||
| 171 | return NULL; | ||
| 172 | } | ||
| 173 | |||
| 174 | len = SDL_strlen(canon) + SDL_strlen(org) + SDL_strlen(app) + 4; | ||
| 175 | dir = (char *)SDL_malloc(len); | ||
| 176 | if (!dir) { | ||
| 177 | SDL_free(canon); | ||
| 178 | return NULL; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (*org) { | ||
| 182 | SDL_snprintf(dir, len, "%s.%s.%s", canon, org, app); | ||
| 183 | } else { | ||
| 184 | SDL_snprintf(dir, len, "%s.%s", canon, app); | ||
| 185 | } | ||
| 186 | |||
| 187 | SDL_free(canon); | ||
| 188 | |||
| 189 | error = createDirectoryRecursive(dir); | ||
| 190 | if (error) { | ||
| 191 | SDL_SetError("Couldn't create directory: %s", error->errmess); | ||
| 192 | SDL_free(dir); | ||
| 193 | return NULL; | ||
| 194 | } | ||
| 195 | |||
| 196 | result = SDL_unixify_std(dir, NULL, 0, __RISCOSIFY_FILETYPE_NOTSPECIFIED); | ||
| 197 | SDL_free(dir); | ||
| 198 | return result; | ||
| 199 | } | ||
| 200 | |||
| 201 | // TODO | ||
| 202 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 203 | { | ||
| 204 | SDL_Unsupported(); | ||
| 205 | return NULL; | ||
| 206 | } | ||
| 207 | |||
| 208 | #endif // SDL_FILESYSTEM_RISCOS | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/unix/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/unix/SDL_sysfilesystem.c new file mode 100644 index 0000000..b0f2dd5 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/unix/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,618 @@ | |||
| 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_UNIX | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <stdio.h> | ||
| 31 | #include <sys/stat.h> | ||
| 32 | #include <sys/types.h> | ||
| 33 | #include <dirent.h> | ||
| 34 | #include <errno.h> | ||
| 35 | #include <fcntl.h> | ||
| 36 | #include <limits.h> | ||
| 37 | #include <stdlib.h> | ||
| 38 | #include <string.h> | ||
| 39 | #include <unistd.h> | ||
| 40 | |||
| 41 | #if defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_OPENBSD) | ||
| 42 | #include <sys/sysctl.h> | ||
| 43 | #endif | ||
| 44 | |||
| 45 | static char *readSymLink(const char *path) | ||
| 46 | { | ||
| 47 | char *result = NULL; | ||
| 48 | ssize_t len = 64; | ||
| 49 | ssize_t rc = -1; | ||
| 50 | |||
| 51 | while (1) { | ||
| 52 | char *ptr = (char *)SDL_realloc(result, (size_t)len); | ||
| 53 | if (!ptr) { | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | |||
| 57 | result = ptr; | ||
| 58 | |||
| 59 | rc = readlink(path, result, len); | ||
| 60 | if (rc == -1) { | ||
| 61 | break; // not a symlink, i/o error, etc. | ||
| 62 | } else if (rc < len) { | ||
| 63 | result[rc] = '\0'; // readlink doesn't null-terminate. | ||
| 64 | return result; // we're good to go. | ||
| 65 | } | ||
| 66 | |||
| 67 | len *= 2; // grow buffer, try again. | ||
| 68 | } | ||
| 69 | |||
| 70 | SDL_free(result); | ||
| 71 | return NULL; | ||
| 72 | } | ||
| 73 | |||
| 74 | #ifdef SDL_PLATFORM_OPENBSD | ||
| 75 | static char *search_path_for_binary(const char *bin) | ||
| 76 | { | ||
| 77 | const char *envr_real = SDL_getenv("PATH"); | ||
| 78 | char *envr; | ||
| 79 | size_t alloc_size; | ||
| 80 | char *exe = NULL; | ||
| 81 | char *start = envr; | ||
| 82 | char *ptr; | ||
| 83 | |||
| 84 | if (!envr_real) { | ||
| 85 | SDL_SetError("No $PATH set"); | ||
| 86 | return NULL; | ||
| 87 | } | ||
| 88 | |||
| 89 | envr = SDL_strdup(envr_real); | ||
| 90 | if (!envr) { | ||
| 91 | return NULL; | ||
| 92 | } | ||
| 93 | |||
| 94 | SDL_assert(bin != NULL); | ||
| 95 | |||
| 96 | alloc_size = SDL_strlen(bin) + SDL_strlen(envr) + 2; | ||
| 97 | exe = (char *)SDL_malloc(alloc_size); | ||
| 98 | |||
| 99 | do { | ||
| 100 | ptr = SDL_strchr(start, ':'); // find next $PATH separator. | ||
| 101 | if (ptr != start) { | ||
| 102 | if (ptr) { | ||
| 103 | *ptr = '\0'; | ||
| 104 | } | ||
| 105 | |||
| 106 | // build full binary path... | ||
| 107 | SDL_snprintf(exe, alloc_size, "%s%s%s", start, (ptr && (ptr[-1] == '/')) ? "" : "/", bin); | ||
| 108 | |||
| 109 | if (access(exe, X_OK) == 0) { // Exists as executable? We're done. | ||
| 110 | SDL_free(envr); | ||
| 111 | return exe; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | start = ptr + 1; // start points to beginning of next element. | ||
| 115 | } while (ptr); | ||
| 116 | |||
| 117 | SDL_free(envr); | ||
| 118 | SDL_free(exe); | ||
| 119 | |||
| 120 | SDL_SetError("Process not found in $PATH"); | ||
| 121 | return NULL; // doesn't exist in path. | ||
| 122 | } | ||
| 123 | #endif | ||
| 124 | |||
| 125 | char *SDL_SYS_GetBasePath(void) | ||
| 126 | { | ||
| 127 | char *result = NULL; | ||
| 128 | |||
| 129 | #ifdef SDL_PLATFORM_FREEBSD | ||
| 130 | char fullpath[PATH_MAX]; | ||
| 131 | size_t buflen = sizeof(fullpath); | ||
| 132 | const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; | ||
| 133 | if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) { | ||
| 134 | result = SDL_strdup(fullpath); | ||
| 135 | if (!result) { | ||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | #endif | ||
| 140 | #ifdef SDL_PLATFORM_OPENBSD | ||
| 141 | // Please note that this will fail if the process was launched with a relative path and $PWD + the cwd have changed, or argv is altered. So don't do that. Or add a new sysctl to OpenBSD. | ||
| 142 | char **cmdline; | ||
| 143 | size_t len; | ||
| 144 | const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; | ||
| 145 | if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) { | ||
| 146 | char *exe, *pwddst; | ||
| 147 | char *realpathbuf = (char *)SDL_malloc(PATH_MAX + 1); | ||
| 148 | if (!realpathbuf) { | ||
| 149 | return NULL; | ||
| 150 | } | ||
| 151 | |||
| 152 | cmdline = SDL_malloc(len); | ||
| 153 | if (!cmdline) { | ||
| 154 | SDL_free(realpathbuf); | ||
| 155 | return NULL; | ||
| 156 | } | ||
| 157 | |||
| 158 | sysctl(mib, 4, cmdline, &len, NULL, 0); | ||
| 159 | |||
| 160 | exe = cmdline[0]; | ||
| 161 | pwddst = NULL; | ||
| 162 | if (SDL_strchr(exe, '/') == NULL) { // not a relative or absolute path, check $PATH for it | ||
| 163 | exe = search_path_for_binary(cmdline[0]); | ||
| 164 | } else { | ||
| 165 | if (exe && *exe == '.') { | ||
| 166 | const char *pwd = SDL_getenv("PWD"); | ||
| 167 | if (pwd && *pwd) { | ||
| 168 | SDL_asprintf(&pwddst, "%s/%s", pwd, exe); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | if (exe) { | ||
| 174 | if (!pwddst) { | ||
| 175 | if (realpath(exe, realpathbuf) != NULL) { | ||
| 176 | result = realpathbuf; | ||
| 177 | } | ||
| 178 | } else { | ||
| 179 | if (realpath(pwddst, realpathbuf) != NULL) { | ||
| 180 | result = realpathbuf; | ||
| 181 | } | ||
| 182 | SDL_free(pwddst); | ||
| 183 | } | ||
| 184 | |||
| 185 | if (exe != cmdline[0]) { | ||
| 186 | SDL_free(exe); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | if (!result) { | ||
| 191 | SDL_free(realpathbuf); | ||
| 192 | } | ||
| 193 | |||
| 194 | SDL_free(cmdline); | ||
| 195 | } | ||
| 196 | #endif | ||
| 197 | |||
| 198 | // is a Linux-style /proc filesystem available? | ||
| 199 | if (!result && (access("/proc", F_OK) == 0)) { | ||
| 200 | /* !!! FIXME: after 2.0.6 ships, let's delete this code and just | ||
| 201 | use the /proc/%llu version. There's no reason to have | ||
| 202 | two copies of this plus all the #ifdefs. --ryan. */ | ||
| 203 | #ifdef SDL_PLATFORM_FREEBSD | ||
| 204 | result = readSymLink("/proc/curproc/file"); | ||
| 205 | #elif defined(SDL_PLATFORM_NETBSD) | ||
| 206 | result = readSymLink("/proc/curproc/exe"); | ||
| 207 | #elif defined(SDL_PLATFORM_SOLARIS) | ||
| 208 | result = readSymLink("/proc/self/path/a.out"); | ||
| 209 | #else | ||
| 210 | result = readSymLink("/proc/self/exe"); // linux. | ||
| 211 | if (!result) { | ||
| 212 | // older kernels don't have /proc/self ... try PID version... | ||
| 213 | char path[64]; | ||
| 214 | const int rc = SDL_snprintf(path, sizeof(path), | ||
| 215 | "/proc/%llu/exe", | ||
| 216 | (unsigned long long)getpid()); | ||
| 217 | if ((rc > 0) && (rc < sizeof(path))) { | ||
| 218 | result = readSymLink(path); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | #endif | ||
| 222 | } | ||
| 223 | |||
| 224 | #ifdef SDL_PLATFORM_SOLARIS // try this as a fallback if /proc didn't pan out | ||
| 225 | if (!result) { | ||
| 226 | const char *path = getexecname(); | ||
| 227 | if ((path) && (path[0] == '/')) { // must be absolute path... | ||
| 228 | result = SDL_strdup(path); | ||
| 229 | if (!result) { | ||
| 230 | return NULL; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | #endif | ||
| 235 | /* If we had access to argv[0] here, we could check it for a path, | ||
| 236 | or troll through $PATH looking for it, too. */ | ||
| 237 | |||
| 238 | if (result) { // chop off filename. | ||
| 239 | char *ptr = SDL_strrchr(result, '/'); | ||
| 240 | if (ptr) { | ||
| 241 | *(ptr + 1) = '\0'; | ||
| 242 | } else { // shouldn't happen, but just in case... | ||
| 243 | SDL_free(result); | ||
| 244 | result = NULL; | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | if (result) { | ||
| 249 | // try to shrink buffer... | ||
| 250 | char *ptr = (char *)SDL_realloc(result, SDL_strlen(result) + 1); | ||
| 251 | if (ptr) { | ||
| 252 | result = ptr; // oh well if it failed. | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | return result; | ||
| 257 | } | ||
| 258 | |||
| 259 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 260 | { | ||
| 261 | /* | ||
| 262 | * We use XDG's base directory spec, even if you're not on Linux. | ||
| 263 | * This isn't strictly correct, but the results are relatively sane | ||
| 264 | * in any case. | ||
| 265 | * | ||
| 266 | * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||
| 267 | */ | ||
| 268 | const char *envr = SDL_getenv("XDG_DATA_HOME"); | ||
| 269 | const char *append; | ||
| 270 | char *result = NULL; | ||
| 271 | char *ptr = NULL; | ||
| 272 | size_t len = 0; | ||
| 273 | |||
| 274 | if (!app) { | ||
| 275 | SDL_InvalidParamError("app"); | ||
| 276 | return NULL; | ||
| 277 | } | ||
| 278 | if (!org) { | ||
| 279 | org = ""; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (!envr) { | ||
| 283 | // You end up with "$HOME/.local/share/Game Name 2" | ||
| 284 | envr = SDL_getenv("HOME"); | ||
| 285 | if (!envr) { | ||
| 286 | // we could take heroic measures with /etc/passwd, but oh well. | ||
| 287 | SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set"); | ||
| 288 | return NULL; | ||
| 289 | } | ||
| 290 | append = "/.local/share/"; | ||
| 291 | } else { | ||
| 292 | append = "/"; | ||
| 293 | } | ||
| 294 | |||
| 295 | len = SDL_strlen(envr); | ||
| 296 | if (envr[len - 1] == '/') { | ||
| 297 | append += 1; | ||
| 298 | } | ||
| 299 | |||
| 300 | len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; | ||
| 301 | result = (char *)SDL_malloc(len); | ||
| 302 | if (!result) { | ||
| 303 | return NULL; | ||
| 304 | } | ||
| 305 | |||
| 306 | if (*org) { | ||
| 307 | (void)SDL_snprintf(result, len, "%s%s%s/%s/", envr, append, org, app); | ||
| 308 | } else { | ||
| 309 | (void)SDL_snprintf(result, len, "%s%s%s/", envr, append, app); | ||
| 310 | } | ||
| 311 | |||
| 312 | for (ptr = result + 1; *ptr; ptr++) { | ||
| 313 | if (*ptr == '/') { | ||
| 314 | *ptr = '\0'; | ||
| 315 | if (mkdir(result, 0700) != 0 && errno != EEXIST) { | ||
| 316 | goto error; | ||
| 317 | } | ||
| 318 | *ptr = '/'; | ||
| 319 | } | ||
| 320 | } | ||
| 321 | if (mkdir(result, 0700) != 0 && errno != EEXIST) { | ||
| 322 | error: | ||
| 323 | SDL_SetError("Couldn't create directory '%s': '%s'", result, strerror(errno)); | ||
| 324 | SDL_free(result); | ||
| 325 | return NULL; | ||
| 326 | } | ||
| 327 | |||
| 328 | return result; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* | ||
| 332 | The two functions below (prefixed with `xdg_`) have been copied from: | ||
| 333 | https://gitlab.freedesktop.org/xdg/xdg-user-dirs/-/blob/master/xdg-user-dir-lookup.c | ||
| 334 | and have been adapted to work with SDL. They are licensed under the following | ||
| 335 | terms: | ||
| 336 | |||
| 337 | Copyright (c) 2007 Red Hat, Inc. | ||
| 338 | |||
| 339 | Permission is hereby granted, free of charge, to any person | ||
| 340 | obtaining a copy of this software and associated documentation files | ||
| 341 | (the "Software"), to deal in the Software without restriction, | ||
| 342 | including without limitation the rights to use, copy, modify, merge, | ||
| 343 | publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 344 | and to permit persons to whom the Software is furnished to do so, | ||
| 345 | subject to the following conditions: | ||
| 346 | |||
| 347 | The above copyright notice and this permission notice shall be | ||
| 348 | included in all copies or substantial portions of the Software. | ||
| 349 | |||
| 350 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 351 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 352 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 353 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
| 354 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
| 355 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 356 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 357 | SOFTWARE. | ||
| 358 | */ | ||
| 359 | static char *xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback) | ||
| 360 | { | ||
| 361 | FILE *file; | ||
| 362 | const char *home_dir, *config_home; | ||
| 363 | char *config_file; | ||
| 364 | char buffer[512]; | ||
| 365 | char *user_dir; | ||
| 366 | char *p, *d; | ||
| 367 | int len; | ||
| 368 | int relative; | ||
| 369 | size_t l; | ||
| 370 | |||
| 371 | home_dir = SDL_getenv("HOME"); | ||
| 372 | |||
| 373 | if (!home_dir) | ||
| 374 | goto error; | ||
| 375 | |||
| 376 | config_home = SDL_getenv("XDG_CONFIG_HOME"); | ||
| 377 | if (!config_home || config_home[0] == 0) | ||
| 378 | { | ||
| 379 | l = SDL_strlen (home_dir) + SDL_strlen ("/.config/user-dirs.dirs") + 1; | ||
| 380 | config_file = (char*) SDL_malloc (l); | ||
| 381 | if (!config_file) | ||
| 382 | goto error; | ||
| 383 | |||
| 384 | SDL_strlcpy (config_file, home_dir, l); | ||
| 385 | SDL_strlcat (config_file, "/.config/user-dirs.dirs", l); | ||
| 386 | } | ||
| 387 | else | ||
| 388 | { | ||
| 389 | l = SDL_strlen (config_home) + SDL_strlen ("/user-dirs.dirs") + 1; | ||
| 390 | config_file = (char*) SDL_malloc (l); | ||
| 391 | if (!config_file) | ||
| 392 | goto error; | ||
| 393 | |||
| 394 | SDL_strlcpy (config_file, config_home, l); | ||
| 395 | SDL_strlcat (config_file, "/user-dirs.dirs", l); | ||
| 396 | } | ||
| 397 | |||
| 398 | file = fopen (config_file, "r"); | ||
| 399 | SDL_free (config_file); | ||
| 400 | if (!file) | ||
| 401 | goto error; | ||
| 402 | |||
| 403 | user_dir = NULL; | ||
| 404 | while (fgets (buffer, sizeof (buffer), file)) | ||
| 405 | { | ||
| 406 | // Remove newline at end | ||
| 407 | len = SDL_strlen (buffer); | ||
| 408 | if (len > 0 && buffer[len-1] == '\n') | ||
| 409 | buffer[len-1] = 0; | ||
| 410 | |||
| 411 | p = buffer; | ||
| 412 | while (*p == ' ' || *p == '\t') | ||
| 413 | p++; | ||
| 414 | |||
| 415 | if (SDL_strncmp (p, "XDG_", 4) != 0) | ||
| 416 | continue; | ||
| 417 | p += 4; | ||
| 418 | if (SDL_strncmp (p, type, SDL_strlen (type)) != 0) | ||
| 419 | continue; | ||
| 420 | p += SDL_strlen (type); | ||
| 421 | if (SDL_strncmp (p, "_DIR", 4) != 0) | ||
| 422 | continue; | ||
| 423 | p += 4; | ||
| 424 | |||
| 425 | while (*p == ' ' || *p == '\t') | ||
| 426 | p++; | ||
| 427 | |||
| 428 | if (*p != '=') | ||
| 429 | continue; | ||
| 430 | p++; | ||
| 431 | |||
| 432 | while (*p == ' ' || *p == '\t') | ||
| 433 | p++; | ||
| 434 | |||
| 435 | if (*p != '"') | ||
| 436 | continue; | ||
| 437 | p++; | ||
| 438 | |||
| 439 | relative = 0; | ||
| 440 | if (SDL_strncmp (p, "$HOME/", 6) == 0) | ||
| 441 | { | ||
| 442 | p += 6; | ||
| 443 | relative = 1; | ||
| 444 | } | ||
| 445 | else if (*p != '/') | ||
| 446 | continue; | ||
| 447 | |||
| 448 | SDL_free (user_dir); | ||
| 449 | if (relative) | ||
| 450 | { | ||
| 451 | l = SDL_strlen (home_dir) + 1 + SDL_strlen (p) + 1; | ||
| 452 | user_dir = (char*) SDL_malloc (l); | ||
| 453 | if (!user_dir) | ||
| 454 | goto error2; | ||
| 455 | |||
| 456 | SDL_strlcpy (user_dir, home_dir, l); | ||
| 457 | SDL_strlcat (user_dir, "/", l); | ||
| 458 | } | ||
| 459 | else | ||
| 460 | { | ||
| 461 | user_dir = (char*) SDL_malloc (SDL_strlen (p) + 1); | ||
| 462 | if (!user_dir) | ||
| 463 | goto error2; | ||
| 464 | |||
| 465 | *user_dir = 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | d = user_dir + SDL_strlen (user_dir); | ||
| 469 | while (*p && *p != '"') | ||
| 470 | { | ||
| 471 | if ((*p == '\\') && (*(p+1) != 0)) | ||
| 472 | p++; | ||
| 473 | *d++ = *p++; | ||
| 474 | } | ||
| 475 | *d = 0; | ||
| 476 | } | ||
| 477 | error2: | ||
| 478 | fclose (file); | ||
| 479 | |||
| 480 | if (user_dir) | ||
| 481 | return user_dir; | ||
| 482 | |||
| 483 | error: | ||
| 484 | if (fallback) | ||
| 485 | return SDL_strdup (fallback); | ||
| 486 | return NULL; | ||
| 487 | } | ||
| 488 | |||
| 489 | static char *xdg_user_dir_lookup (const char *type) | ||
| 490 | { | ||
| 491 | const char *home_dir; | ||
| 492 | char *dir, *user_dir; | ||
| 493 | |||
| 494 | dir = xdg_user_dir_lookup_with_fallback(type, NULL); | ||
| 495 | if (dir) | ||
| 496 | return dir; | ||
| 497 | |||
| 498 | home_dir = SDL_getenv("HOME"); | ||
| 499 | |||
| 500 | if (!home_dir) | ||
| 501 | return NULL; | ||
| 502 | |||
| 503 | // Special case desktop for historical compatibility | ||
| 504 | if (SDL_strcmp(type, "DESKTOP") == 0) { | ||
| 505 | size_t length = SDL_strlen(home_dir) + SDL_strlen("/Desktop") + 1; | ||
| 506 | user_dir = (char*) SDL_malloc(length); | ||
| 507 | if (!user_dir) | ||
| 508 | return NULL; | ||
| 509 | |||
| 510 | SDL_strlcpy(user_dir, home_dir, length); | ||
| 511 | SDL_strlcat(user_dir, "/Desktop", length); | ||
| 512 | return user_dir; | ||
| 513 | } | ||
| 514 | |||
| 515 | return NULL; | ||
| 516 | } | ||
| 517 | |||
| 518 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 519 | { | ||
| 520 | const char *param = NULL; | ||
| 521 | char *result; | ||
| 522 | char *newresult; | ||
| 523 | |||
| 524 | /* According to `man xdg-user-dir`, the possible values are: | ||
| 525 | DESKTOP | ||
| 526 | DOWNLOAD | ||
| 527 | TEMPLATES | ||
| 528 | PUBLICSHARE | ||
| 529 | DOCUMENTS | ||
| 530 | MUSIC | ||
| 531 | PICTURES | ||
| 532 | VIDEOS | ||
| 533 | */ | ||
| 534 | switch(folder) { | ||
| 535 | case SDL_FOLDER_HOME: | ||
| 536 | param = SDL_getenv("HOME"); | ||
| 537 | |||
| 538 | if (!param) { | ||
| 539 | SDL_SetError("No $HOME environment variable available"); | ||
| 540 | return NULL; | ||
| 541 | } | ||
| 542 | |||
| 543 | result = SDL_strdup(param); | ||
| 544 | goto append_slash; | ||
| 545 | |||
| 546 | case SDL_FOLDER_DESKTOP: | ||
| 547 | param = "DESKTOP"; | ||
| 548 | break; | ||
| 549 | |||
| 550 | case SDL_FOLDER_DOCUMENTS: | ||
| 551 | param = "DOCUMENTS"; | ||
| 552 | break; | ||
| 553 | |||
| 554 | case SDL_FOLDER_DOWNLOADS: | ||
| 555 | param = "DOWNLOAD"; | ||
| 556 | break; | ||
| 557 | |||
| 558 | case SDL_FOLDER_MUSIC: | ||
| 559 | param = "MUSIC"; | ||
| 560 | break; | ||
| 561 | |||
| 562 | case SDL_FOLDER_PICTURES: | ||
| 563 | param = "PICTURES"; | ||
| 564 | break; | ||
| 565 | |||
| 566 | case SDL_FOLDER_PUBLICSHARE: | ||
| 567 | param = "PUBLICSHARE"; | ||
| 568 | break; | ||
| 569 | |||
| 570 | case SDL_FOLDER_SAVEDGAMES: | ||
| 571 | SDL_SetError("Saved Games folder unavailable on XDG"); | ||
| 572 | return NULL; | ||
| 573 | |||
| 574 | case SDL_FOLDER_SCREENSHOTS: | ||
| 575 | SDL_SetError("Screenshots folder unavailable on XDG"); | ||
| 576 | return NULL; | ||
| 577 | |||
| 578 | case SDL_FOLDER_TEMPLATES: | ||
| 579 | param = "TEMPLATES"; | ||
| 580 | break; | ||
| 581 | |||
| 582 | case SDL_FOLDER_VIDEOS: | ||
| 583 | param = "VIDEOS"; | ||
| 584 | break; | ||
| 585 | |||
| 586 | default: | ||
| 587 | SDL_SetError("Invalid SDL_Folder: %d", (int) folder); | ||
| 588 | return NULL; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* param *should* to be set to something at this point, but just in case */ | ||
| 592 | if (!param) { | ||
| 593 | SDL_SetError("No corresponding XDG user directory"); | ||
| 594 | return NULL; | ||
| 595 | } | ||
| 596 | |||
| 597 | result = xdg_user_dir_lookup(param); | ||
| 598 | |||
| 599 | if (!result) { | ||
| 600 | SDL_SetError("XDG directory not available"); | ||
| 601 | return NULL; | ||
| 602 | } | ||
| 603 | |||
| 604 | append_slash: | ||
| 605 | newresult = (char *) SDL_realloc(result, SDL_strlen(result) + 2); | ||
| 606 | |||
| 607 | if (!newresult) { | ||
| 608 | SDL_free(result); | ||
| 609 | return NULL; | ||
| 610 | } | ||
| 611 | |||
| 612 | result = newresult; | ||
| 613 | SDL_strlcat(result, "/", SDL_strlen(result) + 2); | ||
| 614 | |||
| 615 | return result; | ||
| 616 | } | ||
| 617 | |||
| 618 | #endif // SDL_FILESYSTEM_UNIX | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/vita/SDL_sysfilesystem.c b/contrib/SDL-3.2.8/src/filesystem/vita/SDL_sysfilesystem.c new file mode 100644 index 0000000..8b65e8a --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/vita/SDL_sysfilesystem.c | |||
| @@ -0,0 +1,92 @@ | |||
| 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_VITA | ||
| 24 | |||
| 25 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 26 | // System dependent filesystem routines | ||
| 27 | |||
| 28 | #include "../SDL_sysfilesystem.h" | ||
| 29 | |||
| 30 | #include <errno.h> | ||
| 31 | #include <stdio.h> | ||
| 32 | #include <unistd.h> | ||
| 33 | #include <stdlib.h> | ||
| 34 | #include <psp2/io/stat.h> | ||
| 35 | #include <sys/types.h> | ||
| 36 | #include <limits.h> | ||
| 37 | #include <fcntl.h> | ||
| 38 | |||
| 39 | char *SDL_SYS_GetBasePath(void) | ||
| 40 | { | ||
| 41 | return SDL_strdup("app0:/"); | ||
| 42 | } | ||
| 43 | |||
| 44 | char *SDL_SYS_GetPrefPath(const char *org, const char *app) | ||
| 45 | { | ||
| 46 | const char *envr = "ux0:/data/"; | ||
| 47 | char *result = NULL; | ||
| 48 | char *ptr = NULL; | ||
| 49 | size_t len = 0; | ||
| 50 | |||
| 51 | if (!app) { | ||
| 52 | SDL_InvalidParamError("app"); | ||
| 53 | return NULL; | ||
| 54 | } | ||
| 55 | if (!org) { | ||
| 56 | org = ""; | ||
| 57 | } | ||
| 58 | |||
| 59 | len = SDL_strlen(envr); | ||
| 60 | |||
| 61 | len += SDL_strlen(org) + SDL_strlen(app) + 3; | ||
| 62 | result = (char *)SDL_malloc(len); | ||
| 63 | if (!result) { | ||
| 64 | return NULL; | ||
| 65 | } | ||
| 66 | |||
| 67 | if (*org) { | ||
| 68 | SDL_snprintf(result, len, "%s%s/%s/", envr, org, app); | ||
| 69 | } else { | ||
| 70 | SDL_snprintf(result, len, "%s%s/", envr, app); | ||
| 71 | } | ||
| 72 | |||
| 73 | for (ptr = result + 1; *ptr; ptr++) { | ||
| 74 | if (*ptr == '/') { | ||
| 75 | *ptr = '\0'; | ||
| 76 | sceIoMkdir(result, 0777); | ||
| 77 | *ptr = '/'; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | sceIoMkdir(result, 0777); | ||
| 81 | |||
| 82 | return result; | ||
| 83 | } | ||
| 84 | |||
| 85 | // TODO | ||
| 86 | char *SDL_SYS_GetUserFolder(SDL_Folder folder) | ||
| 87 | { | ||
| 88 | SDL_Unsupported(); | ||
| 89 | return NULL; | ||
| 90 | } | ||
| 91 | |||
| 92 | #endif // SDL_FILESYSTEM_VITA | ||
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 | ||
| 35 | DEFINE_GUID(SDL_FOLDERID_Profile, 0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73); | ||
| 36 | DEFINE_GUID(SDL_FOLDERID_Desktop, 0xB4BFCC3A, 0xDB2C, 0x424C, 0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41); | ||
| 37 | DEFINE_GUID(SDL_FOLDERID_Documents, 0xFDD39AD0, 0x238F, 0x46AF, 0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7); | ||
| 38 | DEFINE_GUID(SDL_FOLDERID_Downloads, 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b); | ||
| 39 | DEFINE_GUID(SDL_FOLDERID_Music, 0x4BD8D571, 0x6D19, 0x48D3, 0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43); | ||
| 40 | DEFINE_GUID(SDL_FOLDERID_Pictures, 0x33E28130, 0x4E1E, 0x4676, 0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB); | ||
| 41 | DEFINE_GUID(SDL_FOLDERID_SavedGames, 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4); | ||
| 42 | DEFINE_GUID(SDL_FOLDERID_Screenshots, 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f); | ||
| 43 | DEFINE_GUID(SDL_FOLDERID_Templates, 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7); | ||
| 44 | DEFINE_GUID(SDL_FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC); | ||
| 45 | |||
| 46 | char *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 | |||
| 95 | char *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 | |||
| 181 | char *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 | |||
| 342 | done: | ||
| 343 | if (lib) { | ||
| 344 | FreeLibrary(lib); | ||
| 345 | } | ||
| 346 | return result; | ||
| 347 | } | ||
| 348 | |||
| 349 | char *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 | ||
diff --git a/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfsops.c b/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfsops.c new file mode 100644 index 0000000..9c48ba9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/filesystem/windows/SDL_sysfsops.c | |||
| @@ -0,0 +1,231 @@ | |||
| 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 | |||
| 22 | #include "SDL_internal.h" | ||
| 23 | |||
| 24 | #if defined(SDL_FSOPS_WINDOWS) | ||
| 25 | |||
| 26 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 27 | // System dependent filesystem routines | ||
| 28 | |||
| 29 | #include "../../core/windows/SDL_windows.h" | ||
| 30 | #include "../SDL_sysfilesystem.h" | ||
| 31 | |||
| 32 | bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) | ||
| 33 | { | ||
| 34 | SDL_EnumerationResult result = SDL_ENUM_CONTINUE; | ||
| 35 | if (*path == '\0') { // if empty (completely at the root), we need to enumerate drive letters. | ||
| 36 | const DWORD drives = GetLogicalDrives(); | ||
| 37 | char name[] = { 0, ':', '\\', '\0' }; | ||
| 38 | for (int i = 'A'; (result == SDL_ENUM_CONTINUE) && (i <= 'Z'); i++) { | ||
| 39 | if (drives & (1 << (i - 'A'))) { | ||
| 40 | name[0] = (char) i; | ||
| 41 | result = cb(userdata, "", name); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } else { | ||
| 45 | // you need a wildcard to enumerate through FindFirstFileEx(), but the wildcard is only checked in the | ||
| 46 | // filename element at the end of the path string, so always tack on a "\\*" to get everything, and | ||
| 47 | // also prevent any wildcards inserted by the app from being respected. | ||
| 48 | char *pattern = NULL; | ||
| 49 | int patternlen = SDL_asprintf(&pattern, "%s\\\\", path); // we'll replace that second '\\' in the trimdown. | ||
| 50 | if ((patternlen == -1) || (!pattern)) { | ||
| 51 | return false; | ||
| 52 | } | ||
| 53 | |||
| 54 | // trim down to a single path separator at the end, in case the caller added one or more. | ||
| 55 | patternlen--; | ||
| 56 | while ((patternlen >= 0) && ((pattern[patternlen] == '\\') || (pattern[patternlen] == '/'))) { | ||
| 57 | pattern[patternlen--] ='\0'; | ||
| 58 | } | ||
| 59 | pattern[++patternlen] = '\\'; | ||
| 60 | pattern[++patternlen] = '*'; | ||
| 61 | pattern[++patternlen] = '\0'; | ||
| 62 | |||
| 63 | WCHAR *wpattern = WIN_UTF8ToStringW(pattern); | ||
| 64 | if (!wpattern) { | ||
| 65 | SDL_free(pattern); | ||
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 69 | pattern[--patternlen] = '\0'; // chop off the '*' so we just have the dirname with a path separator. | ||
| 70 | |||
| 71 | WIN32_FIND_DATAW entw; | ||
| 72 | HANDLE dir = FindFirstFileExW(wpattern, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0); | ||
| 73 | SDL_free(wpattern); | ||
| 74 | if (dir == INVALID_HANDLE_VALUE) { | ||
| 75 | SDL_free(pattern); | ||
| 76 | return WIN_SetError("Failed to enumerate directory"); | ||
| 77 | } | ||
| 78 | |||
| 79 | do { | ||
| 80 | const WCHAR *fn = entw.cFileName; | ||
| 81 | |||
| 82 | if (fn[0] == '.') { // ignore "." and ".." | ||
| 83 | if ((fn[1] == '\0') || ((fn[1] == '.') && (fn[2] == '\0'))) { | ||
| 84 | continue; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | char *utf8fn = WIN_StringToUTF8W(fn); | ||
| 89 | if (!utf8fn) { | ||
| 90 | result = SDL_ENUM_FAILURE; | ||
| 91 | } else { | ||
| 92 | result = cb(userdata, pattern, utf8fn); | ||
| 93 | SDL_free(utf8fn); | ||
| 94 | } | ||
| 95 | } while ((result == SDL_ENUM_CONTINUE) && (FindNextFileW(dir, &entw) != 0)); | ||
| 96 | |||
| 97 | FindClose(dir); | ||
| 98 | SDL_free(pattern); | ||
| 99 | } | ||
| 100 | |||
| 101 | return (result != SDL_ENUM_FAILURE); | ||
| 102 | } | ||
| 103 | |||
| 104 | bool SDL_SYS_RemovePath(const char *path) | ||
| 105 | { | ||
| 106 | WCHAR *wpath = WIN_UTF8ToStringW(path); | ||
| 107 | if (!wpath) { | ||
| 108 | return false; | ||
| 109 | } | ||
| 110 | |||
| 111 | WIN32_FILE_ATTRIBUTE_DATA info; | ||
| 112 | if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &info)) { | ||
| 113 | SDL_free(wpath); | ||
| 114 | if (GetLastError() == ERROR_FILE_NOT_FOUND) { | ||
| 115 | // Note that ERROR_PATH_NOT_FOUND means a parent dir is missing, and we consider that an error. | ||
| 116 | return true; // thing is already gone, call it a success. | ||
| 117 | } | ||
| 118 | return WIN_SetError("Couldn't get path's attributes"); | ||
| 119 | } | ||
| 120 | |||
| 121 | const int isdir = (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); | ||
| 122 | const BOOL rc = isdir ? RemoveDirectoryW(wpath) : DeleteFileW(wpath); | ||
| 123 | SDL_free(wpath); | ||
| 124 | if (!rc) { | ||
| 125 | return WIN_SetError("Couldn't remove path"); | ||
| 126 | } | ||
| 127 | return true; | ||
| 128 | } | ||
| 129 | |||
| 130 | bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath) | ||
| 131 | { | ||
| 132 | WCHAR *woldpath = WIN_UTF8ToStringW(oldpath); | ||
| 133 | if (!woldpath) { | ||
| 134 | return false; | ||
| 135 | } | ||
| 136 | |||
| 137 | WCHAR *wnewpath = WIN_UTF8ToStringW(newpath); | ||
| 138 | if (!wnewpath) { | ||
| 139 | SDL_free(woldpath); | ||
| 140 | return false; | ||
| 141 | } | ||
| 142 | |||
| 143 | const BOOL rc = MoveFileExW(woldpath, wnewpath, MOVEFILE_REPLACE_EXISTING); | ||
| 144 | SDL_free(wnewpath); | ||
| 145 | SDL_free(woldpath); | ||
| 146 | if (!rc) { | ||
| 147 | return WIN_SetError("Couldn't rename path"); | ||
| 148 | } | ||
| 149 | return true; | ||
| 150 | } | ||
| 151 | |||
| 152 | bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath) | ||
| 153 | { | ||
| 154 | WCHAR *woldpath = WIN_UTF8ToStringW(oldpath); | ||
| 155 | if (!woldpath) { | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | |||
| 159 | WCHAR *wnewpath = WIN_UTF8ToStringW(newpath); | ||
| 160 | if (!wnewpath) { | ||
| 161 | SDL_free(woldpath); | ||
| 162 | return false; | ||
| 163 | } | ||
| 164 | |||
| 165 | const BOOL rc = CopyFileExW(woldpath, wnewpath, NULL, NULL, NULL, COPY_FILE_ALLOW_DECRYPTED_DESTINATION|COPY_FILE_NO_BUFFERING); | ||
| 166 | SDL_free(wnewpath); | ||
| 167 | SDL_free(woldpath); | ||
| 168 | if (!rc) { | ||
| 169 | return WIN_SetError("Couldn't copy path"); | ||
| 170 | } | ||
| 171 | return true; | ||
| 172 | } | ||
| 173 | |||
| 174 | bool SDL_SYS_CreateDirectory(const char *path) | ||
| 175 | { | ||
| 176 | WCHAR *wpath = WIN_UTF8ToStringW(path); | ||
| 177 | if (!wpath) { | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | |||
| 181 | DWORD rc = CreateDirectoryW(wpath, NULL); | ||
| 182 | if (!rc && (GetLastError() == ERROR_ALREADY_EXISTS)) { | ||
| 183 | WIN32_FILE_ATTRIBUTE_DATA winstat; | ||
| 184 | if (GetFileAttributesExW(wpath, GetFileExInfoStandard, &winstat)) { | ||
| 185 | if (winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | ||
| 186 | rc = 1; // exists and is already a directory: cool. | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | SDL_free(wpath); | ||
| 192 | if (!rc) { | ||
| 193 | return WIN_SetError("Couldn't create directory"); | ||
| 194 | } | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info) | ||
| 199 | { | ||
| 200 | WCHAR *wpath = WIN_UTF8ToStringW(path); | ||
| 201 | if (!wpath) { | ||
| 202 | return false; | ||
| 203 | } | ||
| 204 | |||
| 205 | WIN32_FILE_ATTRIBUTE_DATA winstat; | ||
| 206 | const BOOL rc = GetFileAttributesExW(wpath, GetFileExInfoStandard, &winstat); | ||
| 207 | SDL_free(wpath); | ||
| 208 | if (!rc) { | ||
| 209 | return WIN_SetError("Can't stat"); | ||
| 210 | } | ||
| 211 | |||
| 212 | if (winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | ||
| 213 | info->type = SDL_PATHTYPE_DIRECTORY; | ||
| 214 | info->size = 0; | ||
| 215 | } else if (winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE)) { | ||
| 216 | info->type = SDL_PATHTYPE_OTHER; | ||
| 217 | info->size = ((((Uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow); | ||
| 218 | } else { | ||
| 219 | info->type = SDL_PATHTYPE_FILE; | ||
| 220 | info->size = ((((Uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow); | ||
| 221 | } | ||
| 222 | |||
| 223 | info->create_time = SDL_TimeFromWindows(winstat.ftCreationTime.dwLowDateTime, winstat.ftCreationTime.dwHighDateTime); | ||
| 224 | info->modify_time = SDL_TimeFromWindows(winstat.ftLastWriteTime.dwLowDateTime, winstat.ftLastWriteTime.dwHighDateTime); | ||
| 225 | info->access_time = SDL_TimeFromWindows(winstat.ftLastAccessTime.dwLowDateTime, winstat.ftLastAccessTime.dwHighDateTime); | ||
| 226 | |||
| 227 | return true; | ||
| 228 | } | ||
| 229 | |||
| 230 | #endif // SDL_FSOPS_WINDOWS | ||
| 231 | |||
