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:
parent
3359b89166
commit
5e58083c01
86
src/util/config/config.cpp
Normal file
86
src/util/config/config.cpp
Normal 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
89
src/util/config/config.h
Normal 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);
|
||||
|
||||
};
|
||||
|
||||
}
|
112
src/util/config/config_user.cpp
Normal file
112
src/util/config/config_user.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
30
src/util/config/config_user.h
Normal file
30
src/util/config/config_user.h
Normal 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();
|
||||
|
||||
}
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user