1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-18 13:54:16 +01:00

[util] Add classes and functions to support configuration files

This commit is contained in:
Philip Rebohle 2018-08-07 14:13:57 +02:00
parent 3359b89166
commit 5e58083c01
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,86 @@
#include "config.h"
namespace dxvk {
Config::Config() { }
Config::~Config() { }
Config::Config(OptionMap&& options)
: m_options(std::move(options)) { }
void Config::merge(const Config& other) {
for (auto& pair : other.m_options)
m_options.insert(pair);
}
void Config::setOption(const std::string& key, const std::string& value) {
m_options.insert_or_assign(key, value);
}
std::string Config::getOptionValue(const char* option) const {
auto iter = m_options.find(option);
return iter != m_options.end()
? iter->second : std::string();
}
bool Config::parseOptionValue(
const std::string& value,
std::string& result) {
result = value;
return true;
}
bool Config::parseOptionValue(
const std::string& value,
bool& result) {
if (value == "True") {
result = true;
return true;
} else if (value == "False") {
result = false;
return true;
} else {
return false;
}
}
bool Config::parseOptionValue(
const std::string& value,
int32_t& result) {
if (value.size() == 0)
return false;
// Parse sign, don't allow '+'
int32_t sign = 1;
size_t start = 0;
if (value[0] == '-') {
sign = -1;
start = 1;
}
// Parse absolute number
int32_t intval = 0;
for (size_t i = start; i < value.size(); i++) {
if (value[i] < '0' || value[i] > '9')
return false;
intval *= 10;
intval += value[i] - '0';
}
// Apply sign and return
result = sign * intval;
return true;
}
}

89
src/util/config/config.h Normal file
View File

@ -0,0 +1,89 @@
#pragma once
#include <string>
#include <unordered_map>
namespace dxvk {
/**
* \brief Config option set
*
* Stores configuration options
* as a set of key-value pairs.
*/
class Config {
using OptionMap = std::unordered_map<std::string, std::string>;
public:
Config();
Config(OptionMap&& options);
~Config();
/**
* \brief Merges two configuration sets
*
* Options specified in this config object will
* not be overridden if they are specified in
* the second config object.
* \param [in] other Config set to merge.
*/
void merge(const Config& other);
/**
* \brief Sets an option
*
* \param [in] key Option name
* \param [in] value Option value
*/
void setOption(
const std::string& key,
const std::string& value);
/**
* \brief Parses an option value
*
* Retrieves the option value as a string, and then
* tries to convert that string to the given type.
* If parsing the string fails because it is either
* invalid or if the option is not defined, this
* method will return a fallback value.
*
* Currently, this supports the types \c bool,
* \c int32_t, and \c std::string.
* \tparam T Return value type
* \param [in] option Option name
* \param [in] fallback Fallback value
* \returns Parsed option value
* \returns The parsed option value
*/
template<typename T>
T getOption(const char* option, T fallback = T()) const {
const std::string& value = getOptionValue(option);
T result = fallback;
parseOptionValue(value, result);
return result;
}
private:
OptionMap m_options;
std::string getOptionValue(
const char* option) const;
static bool parseOptionValue(
const std::string& value,
std::string& result);
static bool parseOptionValue(
const std::string& value,
bool& result);
static bool parseOptionValue(
const std::string& value,
int32_t& result);
};
}

View File

@ -0,0 +1,112 @@
#include <fstream>
#include <sstream>
#include <iostream>
#include "config.h"
#include "config_user.h"
#include "../log/log.h"
namespace dxvk {
void parseUserConfigLine(Config& config, std::string line);
const static std::unordered_map<std::string, Config> g_appDefaults = {{
{ "Dishonored2.exe", {{
{ "d3d11.allowMapFlagNoWait", "True" }
}} },
{ "F1_2015.exe", {{
{ "d3d11.fakeStreamOutSupport", "True" },
}} },
{ "FarCry5.exe", {{
{ "d3d11.allowMapFlagNoWait", "True" }
}} },
{ "Frostpunk.exe", {{
{ "dxgi.deferSurfaceCreation", "True" },
}} },
{ "Overwatch.exe", {{
{ "d3d11.fakeStreamOutSupport", "True" },
}} },
{ "Wow.exe", {{
{ "dxgi.fakeDx10Support", "True" },
}} },
{ "ffxv_s.exe", {{
{ "d3d11.fakeStreamOutSupport", "True" },
}} },
{ "mafia3.exe", {{
{ "d3d11.fakeStreamOutSupport", "True" },
}} },
}};
Config getAppConfig(const std::string& appName) {
auto appConfig = g_appDefaults.find(appName);
if (appConfig != g_appDefaults.end())
return appConfig->second;
return Config();
}
Config getUserConfig() {
Config config;
// Load either $DXVK_CONFIG_FILE or $PWD/dxvk.conf
std::string filePath = env::getEnvVar(L"DXVK_CONFIG_FILE");
if (filePath == "")
filePath = "dxvk.conf";
// Parse the file line by line
std::ifstream stream(filePath);
std::string line;
while (std::getline(stream, line))
parseUserConfigLine(config, line);
return config;
}
bool isWhitespace(char ch) {
return ch == ' ' || ch == '\x9' || ch == '\r';
}
bool isValidKeyChar(char ch) {
return (ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= 'a' && ch <= 'z')
|| (ch == '.' || ch == '_');
}
size_t skipWhitespace(const std::string& line, size_t n) {
while (n < line.size() && isWhitespace(line[n]))
n += 1;
return n;
}
void parseUserConfigLine(Config& config, std::string line) {
std::stringstream key;
std::stringstream value;
// Extract the key
size_t n = skipWhitespace(line, 0);
while (n < line.size() && isValidKeyChar(line[n]))
key << line[n++];
// Check whether the next char is a '='
n = skipWhitespace(line, n);
if (n >= line.size() || line[n] != '=')
return;
// Extract the value
n = skipWhitespace(line, n + 1);
while (n < line.size() && !isWhitespace(line[n]))
value << line[n++];
config.setOption(key.str(), value.str());
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "../util_env.h"
#include "config.h"
namespace dxvk {
/**
* \brief Retrieves application defaults
*
* Some apps have options enabled by default
* in order to improve compatibility and/or
* performance.
* \param [in] appName Application name
* \returns Default configuration for the app
*/
Config getAppConfig(const std::string& appName);
/**
* \brief Retrieves user configuration
*
* Opens and parses the file \c dxvk.conf if it
* exists, or whatever file name is specified in
* the environment variable \c DXVK_CONFIG_FILE.
* \returns User configuration
*/
Config getUserConfig();
}

View File

@ -4,6 +4,9 @@ util_src = files([
'com/com_guid.cpp',
'com/com_private_data.cpp',
'config/config.cpp',
'config/config_user.cpp',
'log/log.cpp',
'log/log_debug.cpp',