#include "sfall_ini.h" #include #include #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); } bool ok = false; if (loaded) { char* stringValue; if (configGetString(&config, section, key, &stringValue)) { strncpy(value, stringValue, size - 1); value[size - 1] = '\0'; ok = true; } } configFree(&config); return ok; } } // namespace fallout