bool platform_ensure_directory_exists(const utf8 *path) { mode_t mask = getumask(); char buffer[MAX_PATH]; platform_utf8_to_multibyte(path, buffer, MAX_PATH); log_verbose("Create directory: %s", buffer); for (char *p = buffer + 1; *p != '\0'; p++) { if (*p == '/') { // Temporarily truncate *p = '\0'; log_verbose("mkdir(%s)", buffer); if (mkdir(buffer, mask) != 0) { if (errno != EEXIST) { return false; } } // Restore truncation *p = '/'; } } log_verbose("mkdir(%s)", buffer); if (mkdir(buffer, mask) != 0) { if (errno != EEXIST) { return false; } } return true; }
bool platform_file_exists(const utf8 *path) { char buffer[MAX_PATH]; platform_utf8_to_multibyte(path, buffer, MAX_PATH); bool exists = access(buffer, F_OK) != -1; log_verbose("file '%s' exists = %i", buffer, exists); return exists; }
bool platform_original_game_data_exists(const utf8 *path) { char buffer[MAX_PATH]; platform_utf8_to_multibyte(path, buffer, MAX_PATH); char checkPath[MAX_PATH]; safe_strcpy(checkPath, buffer, MAX_PATH); safe_strcat_path(checkPath, "Data", MAX_PATH); safe_strcat_path(checkPath, "g1.dat", MAX_PATH); return platform_file_exists(checkPath); }
bool platform_directory_exists(const utf8 *path) { char buffer[MAX_PATH]; platform_utf8_to_multibyte(path, buffer, MAX_PATH); struct stat dirinfo; sint32 result = stat(buffer, &dirinfo); log_verbose("checking dir %s, result = %d, is_dir = %d", buffer, result, S_ISDIR(dirinfo.st_mode)); if ((result != 0) || !S_ISDIR(dirinfo.st_mode)) { return false; } return true; }
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; }
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); g_file_pattern = strndup(file_name, pattern_length); for (sint32 j = 0; j < pattern_length; j++) { g_file_pattern[j] = (char)toupper(g_file_pattern[j]); } log_verbose("looking for file matching %s", g_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(g_file_pattern); g_file_pattern = NULL; return i; } } free(dir_name); free(g_file_pattern); g_file_pattern = NULL; return -1; }
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); g_file_pattern = strndup(file_name, pattern_length); for (sint32 j = 0; j < pattern_length; j++) { g_file_pattern[j] = (char)toupper(g_file_pattern[j]); } log_verbose("looking for file matching %s", g_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]); } enumFileInfo->handle = 0; enumFileInfo->active = 1; free(dir_name); free(g_file_pattern); g_file_pattern = NULL; return i; } } free(dir_name); free(g_file_pattern); g_file_pattern = NULL; return -1; }