149 lines
3.8 KiB
C++
149 lines
3.8 KiB
C++
#include "sfall_ini.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
#include "config.h"
|
|
#include "platform_compat.h"
|
|
|
|
namespace fallout {
|
|
|
|
/// The max length of `fileName` chunk in the triplet.
|
|
static constexpr size_t kFileNameMaxSize = 63;
|
|
|
|
/// The max length of `section` chunk in the triplet.
|
|
static constexpr size_t kSectionMaxSize = 32;
|
|
|
|
/// Special .ini file names which are accessed without adding base path.
|
|
static constexpr const char* kSystemConfigFileNames[] = {
|
|
"ddraw.ini",
|
|
"f2_res.ini",
|
|
};
|
|
|
|
static char basePath[COMPAT_MAX_PATH];
|
|
|
|
/// Parses "fileName|section|key" triplet into parts. `fileName` and `section`
|
|
/// chunks are copied into appropriate variables. Returns the pointer to `key`,
|
|
/// or `nullptr` on any error.
|
|
static const char* parse_ini_triplet(const char* triplet, char* fileName, char* section)
|
|
{
|
|
const char* fileNameSectionSep = strchr(triplet, '|');
|
|
if (fileNameSectionSep == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
size_t fileNameLength = fileNameSectionSep - triplet;
|
|
if (fileNameLength > kFileNameMaxSize) {
|
|
return nullptr;
|
|
}
|
|
|
|
const char* sectionKeySep = strchr(fileNameSectionSep + 1, '|');
|
|
if (sectionKeySep == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
size_t sectionLength = sectionKeySep - fileNameSectionSep - 1;
|
|
if (sectionLength > kSectionMaxSize) {
|
|
return nullptr;
|
|
}
|
|
|
|
strncpy(fileName, triplet, fileNameLength);
|
|
fileName[fileNameLength] = '\0';
|
|
|
|
strncpy(section, fileNameSectionSep + 1, sectionLength);
|
|
section[sectionLength] = '\0';
|
|
|
|
return sectionKeySep + 1;
|
|
}
|
|
|
|
/// Returns `true` if given `fileName` is a special system .ini file name.
|
|
static bool is_system_file_name(const char* fileName)
|
|
{
|
|
for (auto& systemFileName : kSystemConfigFileNames) {
|
|
if (compat_stricmp(systemFileName, fileName) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void sfall_ini_set_base_path(const char* path)
|
|
{
|
|
if (path != nullptr) {
|
|
strcpy(basePath, path);
|
|
|
|
size_t length = strlen(basePath);
|
|
if (length > 0) {
|
|
if (basePath[length - 1] == '\\' || basePath[length - 1] == '/') {
|
|
basePath[length - 1] = '\0';
|
|
}
|
|
}
|
|
} else {
|
|
basePath[0] = '\0';
|
|
}
|
|
}
|
|
|
|
bool sfall_ini_get_int(const char* triplet, int* value)
|
|
{
|
|
char string[20];
|
|
if (!sfall_ini_get_string(triplet, string, sizeof(string))) {
|
|
return false;
|
|
}
|
|
|
|
*value = atol(string);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sfall_ini_get_string(const char* triplet, char* value, size_t size)
|
|
{
|
|
char fileName[kFileNameMaxSize];
|
|
char section[kSectionMaxSize];
|
|
|
|
const char* key = parse_ini_triplet(triplet, fileName, section);
|
|
if (key == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
Config config;
|
|
if (!configInit(&config)) {
|
|
return false;
|
|
}
|
|
|
|
char path[COMPAT_MAX_PATH];
|
|
bool loaded = false;
|
|
|
|
if (basePath[0] != '\0' && !is_system_file_name(fileName)) {
|
|
// Attempt to load requested file in base directory.
|
|
snprintf(path, sizeof(path), "%s\\%s", basePath, fileName);
|
|
loaded = configRead(&config, path, false);
|
|
}
|
|
|
|
if (!loaded) {
|
|
// There was no base path set, requested file is a system config, or
|
|
// non-system config file was not found the base path - attempt to load
|
|
// from current working directory.
|
|
strcpy(path, fileName);
|
|
loaded = configRead(&config, path, false);
|
|
}
|
|
|
|
// NOTE: Sfall's `GetIniSetting` returns error code (-1) only when it cannot
|
|
// parse triplet. Otherwise the default for string settings is empty string.
|
|
value[0] = '\0';
|
|
|
|
if (loaded) {
|
|
char* stringValue;
|
|
if (configGetString(&config, section, key, &stringValue)) {
|
|
strncpy(value, stringValue, size - 1);
|
|
value[size - 1] = '\0';
|
|
}
|
|
}
|
|
|
|
configFree(&config);
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace fallout
|