You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
4.6 KiB

#include "utils/paths.h"
#include <optional>
#include <string>
#include <string_view>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_filesystem.h>
#else
#include <SDL.h>
#endif
#include "appfat.h"
#include "utils/file_util.h"
#include "utils/log.hpp"
5 years ago
#include "utils/sdl_ptrs.h"
#ifdef __IPHONEOS__
#include "platform/ios/ios_paths.h"
#endif
#ifdef NXDK
#define NOMINMAX 1
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#endif
namespace devilution {
namespace paths {
namespace {
std::optional<std::string> basePath;
std::optional<std::string> prefPath;
std::optional<std::string> configPath;
std::optional<std::string> assetsPath;
void AddTrailingSlash(std::string &path)
{
if (!path.empty() && path.back() != DirectorySeparator)
path += DirectorySeparator;
}
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
[[maybe_unused]] std::string FromSDL(char *s)
{
const SDLUniquePtr<char> pinned(s);
std::string result = (s != nullptr ? s : "");
5 years ago
if (s == nullptr) {
Log("{}", SDL_GetError());
SDL_ClearError();
}
return result;
}
#ifdef NXDK
const std::string &NxdkGetPrefPath()
{
static const std::string Path = []() {
const char *path = "E:\\UDATA\\devilutionx\\";
if (CreateDirectoryA(path, nullptr) == FALSE && ::GetLastError() != ERROR_ALREADY_EXISTS) {
DirErrorDlg(path);
}
return path;
}();
return Path;
}
#endif
std::string GetSdlBasePath()
{
std::string result;
#if defined(__DJGPP__)
// In DOS, use an empty base path.
#elif defined(USE_SDL3)
const char *s = SDL_GetBasePath();
if (s == nullptr) {
LogError("{}", SDL_GetError());
SDL_ClearError();
} else {
result = s;
}
#else
result = FromSDL(SDL_GetBasePath());
#endif
return result;
}
} // namespace
const std::string &BasePath()
{
if (!basePath) {
basePath = GetSdlBasePath();
}
return *basePath;
}
const std::string &PrefPath()
{
if (!prefPath) {
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
#if defined(__DJGPP__)
prefPath = std::string();
#elif defined(__IPHONEOS__)
prefPath = FromSDL(IOSGetPrefPath());
#elif defined(NXDK)
prefPath = NxdkGetPrefPath();
#else
prefPath = FromSDL(SDL_GetPrefPath("diasurgical", "devilution"));
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
#if !defined(__amigaos__) && !defined(__DJGPP__)
if (FileExistsAndIsWriteable("diablo.ini")) {
prefPath = std::string();
}
#endif
#endif
}
return *prefPath;
}
const std::string &ConfigPath()
{
if (!configPath) {
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
#if defined(__DJGPP__)
configPath = std::string();
#elif defined(__IPHONEOS__)
configPath = FromSDL(IOSGetPrefPath());
#elif defined(NXDK)
configPath = NxdkGetPrefPath();
#else
configPath = FromSDL(SDL_GetPrefPath("diasurgical", "devilution"));
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
#if !defined(__amigaos__) && !defined(__DJGPP__)
if (FileExistsAndIsWriteable("diablo.ini")) {
configPath = std::string();
}
#endif
#endif
}
return *configPath;
}
const std::string &AssetsPath()
{
if (!assetsPath) {
dos: Clean up paths for better logging 1. Prevents warnings in `--verbose` mode from unimplemented `SDL_GetBase/PrefPath`. These were the first 4 "This operation is not supported" messages that were logged previously. 2. Removes Linux directories from MPQ search paths on DOS. 3. Uses backslash directory separator on DOS. DJGPP libc supports both but this is DOS, we should use backslash. Now the `--verbose` SDL_LOG.txt looks much cleaner: ``` VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: devx in VERBOSE: Missing: fonts DEBUG: DOS: Keyboard ISR code size is 48 bytes DEBUG: Unknown pixel format DEBUG: SVGA: Ignoring mode 0x102: Bad attributes DEBUG: SVGA: Ignoring mode 0x104: Bad attributes DEBUG: SVGA: Ignoring mode 0x106: Bad attributes DEBUG: SVGA: Ignoring mode 0x107: No double-buffering DEBUG: SVGA: Ignoring mode 0x112: No double-buffering DEBUG: SVGA: Ignoring mode 0x115: No double-buffering DEBUG: SVGA: Ignoring mode 0x116: No double-buffering DEBUG: SVGA: Ignoring mode 0x117: No double-buffering DEBUG: SVGA: Ignoring mode 0x209: No double-buffering DEBUG: SVGA: Ignoring mode 0x20A: No double-buffering DEBUG: SVGA: Ignoring mode 0x225: No double-buffering DEBUG: SVGA: VBE lists 42 modes VERBOSE: Removed file: Diablo1ReadOnlyTest.foo VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Paths: base: pref: config: assets: assets\ VERBOSE: MPQ search paths: 1. '' VERBOSE: Found: DIABDAT in VERBOSE: Missing: hfbard VERBOSE: Missing: hfbarb DEBUG: That operation is not supported VERBOSE: Control: device None -> KeyboardAndMouse, mode None -> KeyboardAndMouse ```
7 months ago
#if __EMSCRIPTEN__ || defined(__DJGPP__)
assetsPath.emplace("assets" DIRECTORY_SEPARATOR_STR);
#elif defined(NXDK)
assetsPath.emplace("D:\\assets\\");
#elif defined(__3DS__) || defined(__SWITCH__)
assetsPath.emplace("romfs:/");
#elif defined(__APPLE__) && defined(USE_SDL1)
// In `Info.plist` we have
//
// <key>SDL_FILESYSTEM_BASE_DIR_TYPE</key>
// <string>resource</string>
//
// This means `SDL_GetBasePath()` returns exedir for non-bundled
// and the `app_dir.app/Resources/` for bundles.
//
// Our built-in resources are directly in the `devilutionx.app/Resources` directory
// and are normally looked up via a relative lookup in `FindAsset`.
// In SDL2, this is implemented by calling `SDL_OpenFPFromBundleOrFallback`
// from `SDL_RWFromFile` but SDL1 doesn't do it, so we set the directory explicitly.
//
// Note that SDL3 reverts to SDL1 behaviour!
// https://github.com/libsdl-org/SDL/blob/962268ca21ed10b9cee31198c22681099293f20a/docs/README-migration.md?plain=1#L1623
assetsPath.emplace(GetSdlBasePath());
#else
assetsPath.emplace(GetSdlBasePath() + ("assets" DIRECTORY_SEPARATOR_STR));
#endif
}
return *assetsPath;
}
void SetBasePath(const std::string &path)
{
basePath = path;
AddTrailingSlash(*basePath);
}
void SetPrefPath(const std::string &path)
{
prefPath = path;
AddTrailingSlash(*prefPath);
}
void SetConfigPath(const std::string &path)
{
configPath = path;
AddTrailingSlash(*configPath);
}
void SetAssetsPath(const std::string &path)
{
assetsPath = path;
AddTrailingSlash(*assetsPath);
}
} // namespace paths
} // namespace devilution