mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 11:03:00 +01:00
Remove old file enumerator functions from platform
This commit is contained in:
committed by
Michael Steenbeek
parent
cb720025fa
commit
bea500638b
@@ -104,12 +104,6 @@ bool platform_ensure_directory_exists(const utf8 *path);
|
||||
bool platform_directory_delete(const utf8 *path);
|
||||
utf8 * platform_get_absolute_path(const utf8 * relative_path, const utf8 * base_path);
|
||||
bool platform_lock_single_instance();
|
||||
sint32 platform_enumerate_files_begin(const utf8 *pattern);
|
||||
bool platform_enumerate_files_next(sint32 handle, file_info *outFileInfo);
|
||||
void platform_enumerate_files_end(sint32 handle);
|
||||
sint32 platform_enumerate_directories_begin(const utf8 *directory);
|
||||
bool platform_enumerate_directories_next(sint32 handle, utf8 *path);
|
||||
void platform_enumerate_directories_end(sint32 handle);
|
||||
bool platform_place_string_on_clipboard(utf8* target);
|
||||
|
||||
// Returns the bitmask of the GetLogicalDrives function for windows, 0 for other systems
|
||||
|
||||
@@ -302,295 +302,7 @@ bool platform_lock_single_instance()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct enumerate_file_info {
|
||||
char active;
|
||||
char pattern[MAX_PATH];
|
||||
struct dirent **fileListTemp;
|
||||
char **paths;
|
||||
sint32 cnt;
|
||||
sint32 handle;
|
||||
void* data;
|
||||
} enumerate_file_info;
|
||||
static enumerate_file_info _enumerateFileInfoList[8] = { 0 };
|
||||
|
||||
static char *_file_pattern;
|
||||
|
||||
static sint32 winfilter(const struct dirent *d)
|
||||
{
|
||||
sint32 entry_length = strnlen(d->d_name, MAX_PATH);
|
||||
char *name_upper = malloc(entry_length + 1);
|
||||
if (name_upper == NULL)
|
||||
{
|
||||
log_error("out of memory");
|
||||
return 0;
|
||||
}
|
||||
for (sint32 i = 0; i < entry_length; i++)
|
||||
{
|
||||
name_upper[i] = (char)toupper(d->d_name[i]);
|
||||
}
|
||||
name_upper[entry_length] = '\0';
|
||||
bool match = fnmatch(_file_pattern, name_upper, FNM_PATHNAME) == 0;
|
||||
//log_verbose("trying matching filename %s, result = %d", name_upper, match);
|
||||
free(name_upper);
|
||||
return match;
|
||||
}
|
||||
|
||||
sint32 platform_enumerate_files_begin(const utf8 *pattern)
|
||||
{
|
||||
char npattern[MAX_PATH];
|
||||
platform_utf8_to_multibyte(pattern, npattern, MAX_PATH);
|
||||
enumerate_file_info *enumFileInfo;
|
||||
log_verbose("begin file search, pattern: %s", npattern);
|
||||
|
||||
char *file_name = strrchr(npattern, *PATH_SEPARATOR);
|
||||
char *dir_name;
|
||||
if (file_name != NULL)
|
||||
{
|
||||
dir_name = strndup(npattern, file_name - npattern);
|
||||
file_name = &file_name[1];
|
||||
} else {
|
||||
file_name = npattern;
|
||||
dir_name = strdup(".");
|
||||
}
|
||||
|
||||
|
||||
sint32 pattern_length = strlen(file_name);
|
||||
_file_pattern = strndup(file_name, pattern_length);
|
||||
for (sint32 j = 0; j < pattern_length; j++)
|
||||
{
|
||||
_file_pattern[j] = (char)toupper(_file_pattern[j]);
|
||||
}
|
||||
log_verbose("looking for file matching %s", _file_pattern);
|
||||
sint32 cnt;
|
||||
for (sint32 i = 0; i < countof(_enumerateFileInfoList); i++) {
|
||||
enumFileInfo = &_enumerateFileInfoList[i];
|
||||
if (!enumFileInfo->active) {
|
||||
safe_strcpy(enumFileInfo->pattern, npattern, sizeof(enumFileInfo->pattern));
|
||||
cnt = scandir(dir_name, &enumFileInfo->fileListTemp, winfilter, alphasort);
|
||||
if (cnt < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
log_verbose("found %d files matching in dir '%s'", cnt, dir_name);
|
||||
enumFileInfo->cnt = cnt;
|
||||
enumFileInfo->paths = malloc(cnt * sizeof(char *));
|
||||
char **paths = enumFileInfo->paths;
|
||||
// 256 is size of dirent.d_name
|
||||
const sint32 dir_name_len = strnlen(dir_name, MAX_PATH);
|
||||
for (sint32 idx = 0; idx < cnt; idx++)
|
||||
{
|
||||
struct dirent *d = enumFileInfo->fileListTemp[idx];
|
||||
const sint32 entry_len = strnlen(d->d_name, MAX_PATH);
|
||||
// 1 for separator, 1 for trailing null
|
||||
size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2);
|
||||
paths[idx] = malloc(path_len);
|
||||
log_verbose("dir_name: %s", dir_name);
|
||||
safe_strcpy(paths[idx], dir_name, path_len);
|
||||
safe_strcat_path(paths[idx], d->d_name, path_len);
|
||||
log_verbose("paths[%d] = %s", idx, paths[idx]);
|
||||
|
||||
// macOS uses decomposed Unicode strings (e.g. an 'e' and a combining accent) in filenames
|
||||
// This causes problems with the sprite font, as the font only contains precomposed characters
|
||||
// The block below converts all filename strings to their precomposed form, preventing mojibake
|
||||
#ifdef __APPLE__
|
||||
utf8* precomp_path = macos_str_decomp_to_precomp(paths[idx]);
|
||||
size_t precomp_len = sizeof(utf8) * min(MAX_PATH, strnlen(precomp_path, MAX_PATH) + 2);
|
||||
paths[idx] = malloc(precomp_len);
|
||||
safe_strcpy(paths[idx], precomp_path, precomp_len);
|
||||
log_verbose("macOS decomp-to-precomp fix - paths[%d] = %s", idx, paths[idx]);
|
||||
#endif
|
||||
}
|
||||
enumFileInfo->handle = 0;
|
||||
enumFileInfo->active = 1;
|
||||
free(dir_name);
|
||||
free(_file_pattern);
|
||||
_file_pattern = NULL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir_name);
|
||||
free(_file_pattern);
|
||||
_file_pattern = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool platform_enumerate_files_next(sint32 handle, file_info *outFileInfo)
|
||||
{
|
||||
|
||||
if (handle < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
bool result;
|
||||
|
||||
if (enumFileInfo->handle < enumFileInfo->cnt) {
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
sint32 entryIdx = enumFileInfo->handle++;
|
||||
struct stat fileInfo;
|
||||
log_verbose("trying handle %d", entryIdx);
|
||||
char *fileName = enumFileInfo->paths[entryIdx];
|
||||
sint32 statRes;
|
||||
statRes = stat(fileName, &fileInfo);
|
||||
if (statRes == -1) {
|
||||
log_error("failed to stat file '%s'! errno = %i", fileName, errno);
|
||||
return false;
|
||||
}
|
||||
outFileInfo->path = basename(fileName);
|
||||
outFileInfo->size = fileInfo.st_size;
|
||||
outFileInfo->last_modified = fileInfo.st_mtime;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void platform_enumerate_files_end(sint32 handle)
|
||||
{
|
||||
if (handle < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
sint32 cnt = enumFileInfo->cnt;
|
||||
for (sint32 i = 0; i < cnt; i++) {
|
||||
free(enumFileInfo->fileListTemp[i]);
|
||||
free(enumFileInfo->paths[i]);
|
||||
}
|
||||
free(enumFileInfo->fileListTemp);
|
||||
free(enumFileInfo->paths);
|
||||
// FIXME: this here could have a bug
|
||||
enumFileInfo->fileListTemp = NULL;
|
||||
enumFileInfo->handle = 0;
|
||||
enumFileInfo->active = 0;
|
||||
}
|
||||
|
||||
static sint32 dirfilter(const struct dirent *d)
|
||||
{
|
||||
if (d->d_name[0] == '.') {
|
||||
return 0;
|
||||
}
|
||||
#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN)
|
||||
if (d->d_type == DT_DIR || d->d_type == DT_LNK)
|
||||
{
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error implement dirfilter!
|
||||
#endif // defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN)
|
||||
}
|
||||
|
||||
sint32 platform_enumerate_directories_begin(const utf8 *directory)
|
||||
{
|
||||
char npattern[MAX_PATH];
|
||||
sint32 length = platform_utf8_to_multibyte(directory, npattern, MAX_PATH) + 1;
|
||||
enumerate_file_info *enumFileInfo;
|
||||
log_verbose("begin directory listing, path: %s", npattern);
|
||||
|
||||
// TODO: add some checking for stringness and directoryness
|
||||
|
||||
sint32 cnt;
|
||||
for (sint32 i = 0; i < countof(_enumerateFileInfoList); i++) {
|
||||
enumFileInfo = &_enumerateFileInfoList[i];
|
||||
if (!enumFileInfo->active) {
|
||||
safe_strcpy(enumFileInfo->pattern, npattern, length);
|
||||
cnt = scandir(npattern, &enumFileInfo->fileListTemp, dirfilter, alphasort);
|
||||
if (cnt < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
log_verbose("found %d files in dir '%s'", cnt, npattern);
|
||||
enumFileInfo->cnt = cnt;
|
||||
enumFileInfo->paths = malloc(cnt * sizeof(char *));
|
||||
char **paths = enumFileInfo->paths;
|
||||
// 256 is size of dirent.d_name
|
||||
const sint32 dir_name_len = strnlen(npattern, MAX_PATH);
|
||||
for (sint32 idx = 0; idx < cnt; idx++)
|
||||
{
|
||||
struct dirent *d = enumFileInfo->fileListTemp[idx];
|
||||
const sint32 entry_len = strnlen(d->d_name, MAX_PATH);
|
||||
// 1 for separator, 1 for trailing null
|
||||
size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2);
|
||||
paths[idx] = malloc(path_len);
|
||||
log_verbose("dir_name: %s", npattern);
|
||||
safe_strcpy(paths[idx], npattern, path_len);
|
||||
safe_strcat_path(paths[idx], d->d_name, path_len);
|
||||
log_verbose("paths[%d] = %s", idx, paths[idx]);
|
||||
}
|
||||
enumFileInfo->handle = 0;
|
||||
enumFileInfo->active = 1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool platform_enumerate_directories_next(sint32 handle, utf8 *path)
|
||||
{
|
||||
if (handle < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result;
|
||||
enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
|
||||
log_verbose("handle = %d", handle);
|
||||
if (enumFileInfo->handle < enumFileInfo->cnt) {
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
sint32 entryIdx = enumFileInfo->handle++;
|
||||
struct stat fileInfo;
|
||||
char *fileName = enumFileInfo->paths[entryIdx];
|
||||
sint32 statRes;
|
||||
statRes = stat(fileName, &fileInfo);
|
||||
if (statRes == -1) {
|
||||
log_error("failed to stat file '%s'! errno = %i", fileName, errno);
|
||||
return false;
|
||||
}
|
||||
// so very, very wrong
|
||||
safe_strcpy(path, basename(fileName), MAX_PATH);
|
||||
path_end_with_separator(path, MAX_PATH);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void platform_enumerate_directories_end(sint32 handle)
|
||||
{
|
||||
if (handle < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
sint32 cnt = enumFileInfo->cnt;
|
||||
for (sint32 i = 0; i < cnt; i++) {
|
||||
free(enumFileInfo->fileListTemp[i]);
|
||||
free(enumFileInfo->paths[i]);
|
||||
}
|
||||
free(enumFileInfo->fileListTemp);
|
||||
free(enumFileInfo->paths);
|
||||
// FIXME: this here could have a bug
|
||||
enumFileInfo->fileListTemp = NULL;
|
||||
enumFileInfo->handle = 0;
|
||||
enumFileInfo->active = 0;
|
||||
}
|
||||
|
||||
sint32 platform_get_drives(){
|
||||
sint32 platform_get_drives() {
|
||||
// POSIX systems do not know drives. Return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -167,220 +167,6 @@ bool platform_lock_single_instance()
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
wchar_t pattern[MAX_PATH];
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW data;
|
||||
utf8 *outFilename;
|
||||
} enumerate_file_info;
|
||||
static enumerate_file_info _enumerateFileInfoList[8] = { 0 };
|
||||
|
||||
sint32 platform_enumerate_files_begin(const utf8 *pattern)
|
||||
{
|
||||
sint32 i;
|
||||
enumerate_file_info *enumFileInfo;
|
||||
|
||||
wchar_t *wPattern = utf8_to_widechar(pattern);
|
||||
|
||||
for (i = 0; i < countof(_enumerateFileInfoList); i++) {
|
||||
enumFileInfo = &_enumerateFileInfoList[i];
|
||||
if (!enumFileInfo->active) {
|
||||
wcsncpy(enumFileInfo->pattern, wPattern, MAX_PATH);
|
||||
enumFileInfo->handle = NULL;
|
||||
enumFileInfo->active = true;
|
||||
enumFileInfo->outFilename = NULL;
|
||||
|
||||
free(wPattern);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
free(wPattern);
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to FindFirstFile / FindNextFile searching for DOS names as well, *.doc also matches *.docx which isn't what the pattern
|
||||
* specified. This will verify if a filename does indeed match the pattern we asked for.
|
||||
* @remarks Based on algorithm (http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html)
|
||||
*/
|
||||
static bool match_wildcard(const wchar_t *fileName, const wchar_t *pattern)
|
||||
{
|
||||
while (*fileName != '\0') {
|
||||
switch (*pattern) {
|
||||
case '?':
|
||||
if (*fileName == '.') {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
do {
|
||||
pattern++;
|
||||
} while (*pattern == '*');
|
||||
if (*pattern == '\0') {
|
||||
return false;
|
||||
}
|
||||
while (*fileName != '\0') {
|
||||
if (match_wildcard(fileName++, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
if (toupper(*fileName) != toupper(*pattern)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pattern++;
|
||||
fileName++;
|
||||
}
|
||||
while (*pattern == '*') {
|
||||
++fileName;
|
||||
}
|
||||
return *pattern == '\0';
|
||||
}
|
||||
|
||||
bool platform_enumerate_files_next(sint32 handle, file_info *outFileInfo)
|
||||
{
|
||||
bool result;
|
||||
enumerate_file_info *enumFileInfo;
|
||||
HANDLE findFileHandle;
|
||||
|
||||
enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
|
||||
// Get pattern (just filename part)
|
||||
const wchar_t *patternWithoutDirectory = wcsrchr(enumFileInfo->pattern, '\\');
|
||||
if (patternWithoutDirectory == NULL) {
|
||||
patternWithoutDirectory = enumFileInfo->pattern;
|
||||
} else {
|
||||
patternWithoutDirectory++;
|
||||
}
|
||||
|
||||
do {
|
||||
if (enumFileInfo->handle == NULL) {
|
||||
findFileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data);
|
||||
if (findFileHandle != INVALID_HANDLE_VALUE) {
|
||||
enumFileInfo->handle = findFileHandle;
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
} else {
|
||||
result = FindNextFileW(enumFileInfo->handle, &enumFileInfo->data);
|
||||
}
|
||||
} while (result && !match_wildcard(enumFileInfo->data.cFileName, patternWithoutDirectory));
|
||||
|
||||
if (result) {
|
||||
outFileInfo->path = enumFileInfo->outFilename = widechar_to_utf8(enumFileInfo->data.cFileName);
|
||||
outFileInfo->size = ((uint64)enumFileInfo->data.nFileSizeHigh << 32ULL) | (uint64)enumFileInfo->data.nFileSizeLow;
|
||||
outFileInfo->last_modified = ((uint64)enumFileInfo->data.ftLastWriteTime.dwHighDateTime << 32ULL) | (uint64)enumFileInfo->data.ftLastWriteTime.dwLowDateTime;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void platform_enumerate_files_end(sint32 handle)
|
||||
{
|
||||
enumerate_file_info *enumFileInfo;
|
||||
|
||||
enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
if (enumFileInfo->handle != NULL) {
|
||||
FindClose(enumFileInfo->handle);
|
||||
enumFileInfo->handle = NULL;
|
||||
}
|
||||
enumFileInfo->active = false;
|
||||
SafeFree(enumFileInfo->outFilename);
|
||||
}
|
||||
|
||||
sint32 platform_enumerate_directories_begin(const utf8 *directory)
|
||||
{
|
||||
sint32 i;
|
||||
enumerate_file_info *enumFileInfo;
|
||||
|
||||
wchar_t *wDirectory = utf8_to_widechar(directory);
|
||||
|
||||
if (wcslen(wDirectory) + 3 >= MAX_PATH) {
|
||||
free(wDirectory);
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
for (i = 0; i < countof(_enumerateFileInfoList); i++) {
|
||||
enumFileInfo = &_enumerateFileInfoList[i];
|
||||
if (!enumFileInfo->active) {
|
||||
wcsncpy(enumFileInfo->pattern, wDirectory, MAX_PATH);
|
||||
|
||||
// Ensure pattern ends with a slash
|
||||
sint32 patternLength = lstrlenW(enumFileInfo->pattern);
|
||||
wchar_t lastChar = enumFileInfo->pattern[patternLength - 1];
|
||||
if (lastChar != '\\' && lastChar != '/') {
|
||||
wcsncat(enumFileInfo->pattern, L"\\", MAX_PATH);
|
||||
}
|
||||
|
||||
wcsncat(enumFileInfo->pattern, L"*", MAX_PATH);
|
||||
enumFileInfo->handle = NULL;
|
||||
enumFileInfo->active = true;
|
||||
enumFileInfo->outFilename = NULL;
|
||||
|
||||
free(wDirectory);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
free(wDirectory);
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
bool platform_enumerate_directories_next(sint32 handle, utf8 *path)
|
||||
{
|
||||
enumerate_file_info *enumFileInfo;
|
||||
HANDLE fileHandle;
|
||||
|
||||
enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
|
||||
if (enumFileInfo->handle == NULL) {
|
||||
fileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data);
|
||||
if (fileHandle != INVALID_HANDLE_VALUE) {
|
||||
enumFileInfo->handle = fileHandle;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!FindNextFileW(enumFileInfo->handle, &enumFileInfo->data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
while (
|
||||
(enumFileInfo->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ||
|
||||
wcschr(enumFileInfo->data.cFileName, '.') != NULL
|
||||
) {
|
||||
if (!FindNextFileW(enumFileInfo->handle, &enumFileInfo->data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
utf8 *filename = widechar_to_utf8(enumFileInfo->data.cFileName);
|
||||
safe_strcpy(path, filename, MAX_PATH);
|
||||
path_end_with_separator(path, MAX_PATH);
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
void platform_enumerate_directories_end(sint32 handle)
|
||||
{
|
||||
enumerate_file_info *enumFileInfo;
|
||||
|
||||
enumFileInfo = &_enumerateFileInfoList[handle];
|
||||
if (enumFileInfo->handle != NULL) {
|
||||
FindClose(enumFileInfo->handle);
|
||||
enumFileInfo->handle = NULL;
|
||||
}
|
||||
enumFileInfo->active = false;
|
||||
}
|
||||
|
||||
sint32 platform_get_drives()
|
||||
{
|
||||
return GetLogicalDrives();
|
||||
|
||||
Reference in New Issue
Block a user