mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-05 17:36:25 +00:00
filesystem: SDL_EnumerateDirectory() gives dirs with path seperators appended.
Fixes #11065. Fixes #11427.
This commit is contained in:
@@ -313,6 +313,9 @@ typedef enum SDL_EnumerationResult
|
|||||||
* terminate the enumeration early, and dictate the return value of the
|
* terminate the enumeration early, and dictate the return value of the
|
||||||
* enumeration function itself.
|
* enumeration function itself.
|
||||||
*
|
*
|
||||||
|
* `dirname` is guaranteed to end with a path separator ('\\' on
|
||||||
|
* Windows, '/' on most other platforms).
|
||||||
|
*
|
||||||
* \param userdata an app-controlled pointer that is passed to the callback.
|
* \param userdata an app-controlled pointer that is passed to the callback.
|
||||||
* \param dirname the directory that is being enumerated.
|
* \param dirname the directory that is being enumerated.
|
||||||
* \param fname the next entry in the enumeration.
|
* \param fname the next entry in the enumeration.
|
||||||
|
@@ -307,7 +307,7 @@ static SDL_EnumerationResult SDLCALL GlobDirectoryCallback(void *userdata, const
|
|||||||
// !!! FIXME: and only casefold the new pieces instead of allocating and folding full paths for all of this.
|
// !!! FIXME: and only casefold the new pieces instead of allocating and folding full paths for all of this.
|
||||||
|
|
||||||
char *fullpath = NULL;
|
char *fullpath = NULL;
|
||||||
if (SDL_asprintf(&fullpath, "%s/%s", dirname, fname) < 0) {
|
if (SDL_asprintf(&fullpath, "%s%s", dirname, fname) < 0) {
|
||||||
return SDL_ENUM_FAILURE;
|
return SDL_ENUM_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +417,8 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob
|
|||||||
data.enumerator = enumerator;
|
data.enumerator = enumerator;
|
||||||
data.getpathinfo = getpathinfo;
|
data.getpathinfo = getpathinfo;
|
||||||
data.fsuserdata = userdata;
|
data.fsuserdata = userdata;
|
||||||
data.basedirlen = SDL_strlen(path) + 1; // +1 for the '/' we'll be adding.
|
data.basedirlen = *path ? (SDL_strlen(path) + 1) : 0; // +1 for the '/' we'll be adding.
|
||||||
|
|
||||||
|
|
||||||
char **result = NULL;
|
char **result = NULL;
|
||||||
if (data.enumerator(path, GlobDirectoryCallback, &data, data.fsuserdata)) {
|
if (data.enumerator(path, GlobDirectoryCallback, &data, data.fsuserdata)) {
|
||||||
|
@@ -37,25 +37,42 @@
|
|||||||
|
|
||||||
bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata)
|
bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata)
|
||||||
{
|
{
|
||||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
char *pathwithsep = NULL;
|
||||||
|
int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", path);
|
||||||
|
if ((pathwithseplen == -1) || (!pathwithsep)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DIR *dir = opendir(path);
|
// trim down to a single path separator at the end, in case the caller added one or more.
|
||||||
|
pathwithseplen--;
|
||||||
|
while ((pathwithseplen >= 0) && (pathwithsep[pathwithseplen] == '/')) {
|
||||||
|
pathwithsep[pathwithseplen--] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *dir = opendir(pathwithsep);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
|
SDL_free(pathwithsep);
|
||||||
return SDL_SetError("Can't open directory: %s", strerror(errno));
|
return SDL_SetError("Can't open directory: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure there's a path separator at the end now for the actual callback.
|
||||||
|
pathwithsep[++pathwithseplen] = '/';
|
||||||
|
pathwithsep[++pathwithseplen] = '\0';
|
||||||
|
|
||||||
|
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL))
|
while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL)) {
|
||||||
{
|
|
||||||
const char *name = ent->d_name;
|
const char *name = ent->d_name;
|
||||||
if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
|
if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result = cb(userdata, path, name);
|
result = cb(userdata, pathwithsep, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
|
SDL_free(pathwithsep);
|
||||||
|
|
||||||
return (result != SDL_ENUM_FAILURE);
|
return (result != SDL_ENUM_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,35 +34,45 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
|||||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||||
if (*path == '\0') { // if empty (completely at the root), we need to enumerate drive letters.
|
if (*path == '\0') { // if empty (completely at the root), we need to enumerate drive letters.
|
||||||
const DWORD drives = GetLogicalDrives();
|
const DWORD drives = GetLogicalDrives();
|
||||||
char name[3] = { 0, ':', '\0' };
|
char name[] = { 0, ':', '\\', '\0' };
|
||||||
for (int i = 'A'; (result == SDL_ENUM_CONTINUE) && (i <= 'Z'); i++) {
|
for (int i = 'A'; (result == SDL_ENUM_CONTINUE) && (i <= 'Z'); i++) {
|
||||||
if (drives & (1 << (i - 'A'))) {
|
if (drives & (1 << (i - 'A'))) {
|
||||||
name[0] = (char) i;
|
name[0] = (char) i;
|
||||||
result = cb(userdata, path, name);
|
result = cb(userdata, "", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const size_t patternlen = SDL_strlen(path) + 3;
|
|
||||||
char *pattern = (char *) SDL_malloc(patternlen);
|
|
||||||
if (!pattern) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// you need a wildcard to enumerate through FindFirstFileEx(), but the wildcard is only checked in the
|
// you need a wildcard to enumerate through FindFirstFileEx(), but the wildcard is only checked in the
|
||||||
// filename element at the end of the path string, so always tack on a "\\*" to get everything, and
|
// filename element at the end of the path string, so always tack on a "\\*" to get everything, and
|
||||||
// also prevent any wildcards inserted by the app from being respected.
|
// also prevent any wildcards inserted by the app from being respected.
|
||||||
SDL_snprintf(pattern, patternlen, "%s\\*", path);
|
char *pattern = NULL;
|
||||||
|
int patternlen = SDL_asprintf(&pattern, "%s\\\\", path); // we'll replace that second '\\' in the trimdown.
|
||||||
WCHAR *wpattern = WIN_UTF8ToStringW(pattern);
|
if ((patternlen == -1) || (!pattern)) {
|
||||||
SDL_free(pattern);
|
|
||||||
if (!wpattern) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim down to a single path separator at the end, in case the caller added one or more.
|
||||||
|
patternlen--;
|
||||||
|
while ((patternlen >= 0) && ((pattern[patternlen] == '\\') || (pattern[patternlen] == '/'))) {
|
||||||
|
pattern[patternlen--] ='\0';
|
||||||
|
}
|
||||||
|
pattern[++patternlen] = '\\';
|
||||||
|
pattern[++patternlen] = '*';
|
||||||
|
pattern[++patternlen] = '\0';
|
||||||
|
|
||||||
|
WCHAR *wpattern = WIN_UTF8ToStringW(pattern);
|
||||||
|
if (!wpattern) {
|
||||||
|
SDL_free(pattern);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern[--patternlen] = '\0'; // chop off the '*' so we just have the dirname with a path separator.
|
||||||
|
|
||||||
WIN32_FIND_DATAW entw;
|
WIN32_FIND_DATAW entw;
|
||||||
HANDLE dir = FindFirstFileExW(wpattern, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0);
|
HANDLE dir = FindFirstFileExW(wpattern, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0);
|
||||||
SDL_free(wpattern);
|
SDL_free(wpattern);
|
||||||
if (dir == INVALID_HANDLE_VALUE) {
|
if (dir == INVALID_HANDLE_VALUE) {
|
||||||
|
SDL_free(pattern);
|
||||||
return WIN_SetError("Failed to enumerate directory");
|
return WIN_SetError("Failed to enumerate directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,12 +89,13 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
|||||||
if (!utf8fn) {
|
if (!utf8fn) {
|
||||||
result = SDL_ENUM_FAILURE;
|
result = SDL_ENUM_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
result = cb(userdata, path, utf8fn);
|
result = cb(userdata, pattern, utf8fn);
|
||||||
SDL_free(utf8fn);
|
SDL_free(utf8fn);
|
||||||
}
|
}
|
||||||
} while ((result == SDL_ENUM_CONTINUE) && (FindNextFileW(dir, &entw) != 0));
|
} while ((result == SDL_ENUM_CONTINUE) && (FindNextFileW(dir, &entw) != 0));
|
||||||
|
|
||||||
FindClose(dir);
|
FindClose(dir);
|
||||||
|
SDL_free(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (result != SDL_ENUM_FAILURE);
|
return (result != SDL_ENUM_FAILURE);
|
||||||
|
@@ -20,14 +20,7 @@ static SDL_EnumerationResult SDLCALL enum_callback(void *userdata, const char *o
|
|||||||
SDL_PathInfo info;
|
SDL_PathInfo info;
|
||||||
char *fullpath = NULL;
|
char *fullpath = NULL;
|
||||||
|
|
||||||
/* you can use '/' for a path separator on Windows, but to make the log output look correct, we'll #ifdef this... */
|
if (SDL_asprintf(&fullpath, "%s%s", origdir, fname) < 0) {
|
||||||
#ifdef SDL_PLATFORM_WINDOWS
|
|
||||||
const char *pathsep = "\\";
|
|
||||||
#else
|
|
||||||
const char *pathsep = "/";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (SDL_asprintf(&fullpath, "%s%s%s", origdir, *origdir ? pathsep : "", fname) < 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
|
||||||
return SDL_ENUM_FAILURE;
|
return SDL_ENUM_FAILURE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user