Load MPQ file overrides without StormLib

Also logs the overrides in verbose mode.
This commit is contained in:
Gleb Mazovetskiy 2021-10-23 10:12:14 +01:00
commit a97ffd1640
7 changed files with 57 additions and 64 deletions

View file

@ -904,7 +904,6 @@ void DiabloInit()
init_create_window();
was_window_init = true;
SFileEnableDirectAccess(true);
init_archives();
was_archives_init = true;

View file

@ -65,7 +65,7 @@ HANDLE LoadMPQ(const std::vector<std::string> &paths, const char *mpqName)
mpqAbsPath = path + mpqName;
if (SFileOpenArchive(mpqAbsPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &archive)) {
LogVerbose(" Found: {} in {}", mpqName, path);
SFileSetBasePath(path);
paths::SetMpqDir(path);
return archive;
}
if (SErrGetLastError() != STORM_ERROR_FILE_NOT_FOUND) {

View file

@ -30,9 +30,6 @@ extern "C" std::uint32_t GetLastError();
namespace devilution {
namespace {
bool directFileAccess = false;
std::optional<std::string> SBasePath;
SdlMutex Mutex;
} // namespace
@ -49,46 +46,10 @@ bool SFileCloseFileThreadSafe(HANDLE hFile)
return SFileCloseFile(hFile);
}
// Converts ASCII characters to lowercase
// Converts slash (0x2F) / backslash (0x5C) to system file-separator
unsigned char AsciiToLowerTable_Path[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
#ifdef _WIN32
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,
#else
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
#endif
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
#ifdef _WIN32
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
#else
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,
#endif
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
bool SFileOpenFile(const char *filename, HANDLE *phFile)
{
bool result = false;
if (directFileAccess && SBasePath) {
std::string path = *SBasePath + filename;
for (std::size_t i = SBasePath->size(); i < path.size(); ++i)
path[i] = AsciiToLowerTable_Path[static_cast<unsigned char>(path[i])];
result = SFileOpenFileEx((HANDLE) nullptr, path.c_str(), SFILE_OPEN_LOCAL_FILE, phFile);
}
if (!result && font_mpq != nullptr) {
result = SFileOpenFileEx((HANDLE)font_mpq, filename, SFILE_OPEN_FROM_MPQ, phFile);
}
@ -138,17 +99,6 @@ void SErrSetLastError(uint32_t dwErrCode)
::SetLastError(dwErrCode);
}
void SFileSetBasePath(string_view path)
{
SBasePath.emplace(path);
}
bool SFileEnableDirectAccess(bool enable)
{
directFileAccess = enable;
return true;
}
#if defined(_WIN64) || defined(_WIN32)
bool SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq)
{

View file

@ -249,14 +249,12 @@ void SErrSetLastError(uint32_t dwErrCode);
*/
void SStrCopy(char *dest, const char *src, int max_length);
void SFileSetBasePath(string_view path);
bool SNetGetOwnerTurnsWaiting(uint32_t *);
bool SNetUnregisterEventHandler(event_type);
bool SNetRegisterEventHandler(event_type, SEVTHANDLER);
bool SNetSetBasePlayer(int);
bool SNetInitializeProvider(uint32_t provider, struct GameData *gameData);
void SNetGetProviderCaps(struct _SNETCAPS *);
bool SFileEnableDirectAccess(bool enable);
#if defined(__GNUC__) || defined(__cplusplus)
}

View file

@ -6,6 +6,7 @@
#include "engine.h"
#include "storm/storm.h"
#include "utils/file_util.h"
#include "utils/log.hpp"
#include "utils/paths.h"
@ -100,24 +101,61 @@ SDL_RWops *SFileRw_FromStormHandle(HANDLE handle)
return result;
}
#ifdef _WIN32
constexpr char PathSeparator = '\\';
#else
constexpr char PathSeparator = '/';
#endif
// Converts ASCII characters to lowercase
// Converts slash / backslash to system file-separator
const char LowerCaseAsciiPathTable[256] {
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F',
'\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2A', '\x2B', '\x2C', '\x2D', '\x2E', PathSeparator,
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x3A', '\x3B', '\x3C', '\x3D', '\x3E', '\x3F',
'\x40', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6A', '\x6B', '\x6C', '\x6D', '\x6E', '\x6F',
'\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7A', '\x5B', PathSeparator, '\x5D', '\x5E', '\x5F',
'\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6A', '\x6B', '\x6C', '\x6D', '\x6E', '\x6F',
'\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7A', '\x7B', '\x7C', '\x7D', '\x7E', '\x7F',
'\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F',
'\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F',
'\xA0', '\xA1', '\xA2', '\xA3', '\xA4', '\xA5', '\xA6', '\xA7', '\xA8', '\xA9', '\xAA', '\xAB', '\xAC', '\xAD', '\xAE', '\xAF',
'\xB0', '\xB1', '\xB2', '\xB3', '\xB4', '\xB5', '\xB6', '\xB7', '\xB8', '\xB9', '\xBA', '\xBB', '\xBC', '\xBD', '\xBE', '\xBF',
'\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF',
'\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF',
'\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF',
'\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7', '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF'
};
} // namespace
SDL_RWops *SFileOpenRw(const char *filename)
{
std::string relativePath = filename;
for (char &c : relativePath)
c = LowerCaseAsciiPathTable[static_cast<unsigned char>(c)];
if (relativePath[0] == '/')
return SDL_RWFromFile(relativePath.c_str(), "rb");
// Files next to the MPQ archives override MPQ contents.
SDL_RWops *rwops;
if (paths::MpqDir()) {
const std::string path = *paths::MpqDir() + relativePath;
// Avoid spamming DEBUG messages if the file does not exist.
if ((FileExists(path.c_str())) && (rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr) {
LogVerbose("Loaded MPQ file override: {}", path);
return rwops;
}
}
// Load from all the MPQ archives.
HANDLE handle;
if (SFileOpenFile(filename, &handle))
return SFileRw_FromStormHandle(handle);
std::string relativePath = filename;
#ifndef _WIN32
std::replace(relativePath.begin(), relativePath.end(), '\\', '/');
#endif
SDL_RWops *rwops;
if (relativePath[0] == '/') {
return SDL_RWFromFile(relativePath.c_str(), "rb");
}
// Load from the `/assets` directory next to the devilutionx binary.
const std::string path = paths::AssetsPath() + relativePath;
if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr)
return rwops;

View file

@ -4,7 +4,6 @@
#include "utils/file_util.h"
#include "utils/log.hpp"
#include "utils/stdcompat/optional.hpp"
#include "utils/sdl_ptrs.h"
#ifdef USE_SDL1
@ -22,6 +21,7 @@ std::optional<std::string> basePath;
std::optional<std::string> prefPath;
std::optional<std::string> configPath;
std::optional<std::string> assetsPath;
std::optional<std::string> mpqDir;
void AddTrailingSlash(std::string &path)
{
@ -92,6 +92,11 @@ const std::string &AssetsPath()
return *assetsPath;
}
const std::optional<std::string> &MpqDir()
{
return mpqDir;
}
void SetBasePath(const std::string &path)
{
basePath = path;

View file

@ -2,6 +2,8 @@
#include <string>
#include "utils/stdcompat/optional.hpp"
namespace devilution {
namespace paths {
@ -11,6 +13,7 @@ const std::string &BasePath();
const std::string &PrefPath();
const std::string &ConfigPath();
const std::string &AssetsPath();
const std::optional<std::string> &MpqDir();
void SetBasePath(const std::string &path);
void SetPrefPath(const std::string &path);