fallout2-ce/src/sfall_ini.cc

198 lines
5.1 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;
}
bool sfall_ini_set_int(const char* triplet, int value)
{
char stringValue[20];
compat_itoa(value, stringValue, 10);
return sfall_ini_set_string(triplet, stringValue);
}
bool sfall_ini_set_string(const char* triplet, const char* value)
{
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);
}
configSetString(&config, section, key, value);
bool saved = configWrite(&config, path, false);
configFree(&config);
return saved;
}
} // namespace fallout