From b149aaa00c990506514efbea7801b2739705d3e6 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 7 Dec 2019 09:41:06 +0800 Subject: [PATCH] Changed the behavior of IniConfigFolder option --- artifacts/ddraw.ini | 5 +- sfall/Modules/Scripting/Handlers/Misc.cpp | 78 +++++++++++++---------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 30366a6e..f83d7498 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -738,8 +738,9 @@ CreditsAtBottom=0 ;Paths outside of scripts folder are supported GlobalScriptPaths=scripts\gl*.int,scripts\sfall\gl*.int -;Uncomment the option to specify a common folder path for all ini files used by scripts -;You will have to put all the available ini files of the mods in this directory +;Uncomment the option to specify an additional folder path for ini files used by scripts +;The game will search for the ini files relative to this directory +;If the file is not found, the search will proceed relative to the root directory of the game ;The maximum length of the specified path is 61 characters ;IniConfigFolder=mods\iniConfigs diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index aef4a851..0513c215 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -402,6 +402,14 @@ void sf_get_npc_level(OpcodeContext& ctx) { ctx.setReturn(level); } +static bool IsSpecialIni(const char* str, const char* end) { + const char* pos = strfind(str, &::sfall::ddrawIni[2]); + if (pos && pos < end) return true; + pos = strfind(str, "f2_res.ini"); + if (pos && pos < end) return true; + return false; +} + static int ParseIniSetting(const char* iniString, const char* &key, char section[], char file[]) { key = strstr(iniString, "|"); if (!key) return -1; @@ -416,28 +424,18 @@ static int ParseIniSetting(const char* iniString, const char* &key, char section DWORD seclen = (DWORD)key - ((DWORD)iniString + filelen + 1); if (seclen > 32) return -1; + long startAt = 2; file[0] = '.'; file[1] = '\\'; - if (!ScriptExtender::iniConfigFolder.empty()) { - const char* pos = strfind(iniString, &::sfall::ddrawIni[2]); - if (pos && pos < fileEnd) goto specialIni; - pos = strfind(iniString, "f2_res.ini"); - if (pos && pos < fileEnd) goto specialIni; + + if (!ScriptExtender::iniConfigFolder.empty() && !IsSpecialIni(iniString, fileEnd)) { size_t len = ScriptExtender::iniConfigFolder.length(); // limit up to 62 characters memcpy(&file[2], ScriptExtender::iniConfigFolder.c_str(), len); - int n = 0; // position of the beginning of the file name - for (int i = filelen - 4; i > 0; i--) { - if (iniString[i] == '\\' || iniString[i] == '/') { - n = i + 1; - break; - } - } - strncpy_s(&file[2 + len], (128 - 2) - len, &iniString[n], filelen - n); // copy filename - } else { -specialIni: - memcpy(&file[2], iniString, filelen); - file[filelen + 2] = 0; + DWORD attr = GetFileAttributesA(file); + if (!(attr & FILE_ATTRIBUTE_DIRECTORY) /*&& attr != INVALID_FILE_ATTRIBUTES*/) startAt += len + 1; } + memcpy(&file[startAt], iniString, filelen); + file[startAt + filelen] = 0; memcpy(section, &iniString[filelen + 1], seclen); section[seclen] = 0; @@ -1035,21 +1033,31 @@ void sf_set_ini_setting(OpcodeContext& ctx) { ctx.setReturn(-1); } -static std::string GetIniFilePath(const ScriptValue& arg) { +static std::string GetIniFilePath(const ScriptValue &arg) { std::string fileName(".\\"); if (ScriptExtender::iniConfigFolder.empty()) { fileName += arg.strValue(); } else { fileName += ScriptExtender::iniConfigFolder; - std::string name(arg.strValue()); - int pos = name.find_last_of("\\/"); - fileName += (pos > 0) ? name.substr(pos + 1) : name; + fileName += arg.strValue(); + DWORD attr = GetFileAttributesA(fileName.c_str()); + if ((attr & FILE_ATTRIBUTE_DIRECTORY) /*|| attr == INVALID_FILE_ATTRIBUTES*/) { + auto str = arg.strValue(); + for (size_t i = 2; ; i++, str++) { + //if (*str == '.') str += (str[1] == '.') ? 3 : 2; // skip '.\' or '..\' + fileName[i] = *str; + if (!*str) break; + } + } } return fileName; } void sf_get_ini_sections(OpcodeContext& ctx) { - GetPrivateProfileSectionNamesA(ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).data()); + if (!GetPrivateProfileSectionNamesA(ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).c_str())) { + ctx.setReturn(TempArray(0, 0)); + return; + } std::vector sections; char* section = ScriptExtender::gTextBuffer; while (*section != 0) { @@ -1070,21 +1078,23 @@ void sf_get_ini_sections(OpcodeContext& ctx) { void sf_get_ini_section(OpcodeContext& ctx) { auto section = ctx.arg(1).strValue(); - GetPrivateProfileSectionA(section, ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).data()); int arrayId = TempArray(-1, 0); // associative - auto& arr = arrays[arrayId]; - char *key = ScriptExtender::gTextBuffer, *val = nullptr; - while (*key != 0) { - char* val = std::strpbrk(key, "="); - if (val != nullptr) { - *val = '\0'; - val += 1; - SetArray(arrayId, ScriptValue(key), ScriptValue(val), false); + if (GetPrivateProfileSectionA(section, ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).c_str())) { + auto& arr = arrays[arrayId]; + char *key = ScriptExtender::gTextBuffer, *val = nullptr; + while (*key != 0) { + char* val = std::strpbrk(key, "="); + if (val != nullptr) { + *val = '\0'; + val += 1; - key = val + std::strlen(val) + 1; - } else { - key += std::strlen(key) + 1; + SetArray(arrayId, ScriptValue(key), ScriptValue(val), false); + + key = val + std::strlen(val) + 1; + } else { + key += std::strlen(key) + 1; + } } } ctx.setReturn(arrayId);