From 7e0962c5ea0f7cf5ebb24cb1dd63f88d940935e7 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 01:09:34 +0100
Subject: [PATCH 01/14] Make # only start a comment in openmw.cfg if it starts
 a line and introduct compilation errors

---
 apps/openmw/main.cpp                      |  13 +--
 components/fallback/validate.hpp          |   4 +-
 components/files/configurationmanager.cpp | 114 +++++++++++++++++++++-
 components/files/configurationmanager.hpp |  43 ++++++++
 4 files changed, 165 insertions(+), 9 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index a4bf1fe5b..e4a918271 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-    typedef std::vector<std::string> StringsVector;
+	typedef Files::EscapeHashString string;
+    typedef std::vector<string> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
 
@@ -79,13 +80,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
             ->multitoken()->composing(), "set data directories (later directories have higher priority)")
 
-        ("data-local", bpo::value<std::string>()->default_value(""),
+        ("data-local", bpo::value<string>()->default_value(""),
             "set local data directory (highest priority)")
 
         ("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
-        ("resources", bpo::value<std::string>()->default_value("resources"),
+        ("resources", bpo::value<string>()->default_value("resources"),
             "set resources directory")
 
         ("start", bpo::value<std::string>()->default_value(""),
@@ -109,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-console", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "enable console-only script functionality")
 
-        ("script-run", bpo::value<std::string>()->default_value(""),
+        ("script-run", bpo::value<string>()->default_value(""),
             "select a file containing a list of console commands that is executed on startup")
 
         ("script-warn", bpo::value<int>()->implicit_value (1)
@@ -125,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
             ->default_value(true), "enable script blacklisting")
 
-        ("load-savegame", bpo::value<std::string>()->default_value(""),
+        ("load-savegame", bpo::value<string>()->default_value(""),
             "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
 
         ("skip-menu", bpo::value<bool>()->implicit_value(true)
@@ -137,7 +138,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("fs-strict", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "strict file system handling (no case folding)")
 
-        ( "encoding", bpo::value<std::string>()->
+        ( "encoding", bpo::value<string>()->
             default_value("win1252"),
             "Character encoding used in OpenMW game messages:\n"
             "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 3b6398d6a..531711544 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -3,6 +3,8 @@
 
 #include <boost/program_options.hpp>
 
+#include <components\files\configurationmanager.hpp>
+
 // Parses and validates a fallback map from boost program_options.
 // Note: for boost to pick up the validate function, you need to pull in the namespace e.g.
 // by using namespace Fallback;
@@ -11,7 +13,7 @@ namespace Fallback
 {
 
     struct FallbackMap {
-        std::map<std::string,std::string> mMap;
+        std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
     };
 
     void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 5ac3dd695..c50303d97 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -3,9 +3,11 @@
 #include <string>
 #include <iostream>
 #include <algorithm>
+#include <ctype.h>
 
 #include <boost/bind.hpp>
 #include <boost/algorithm/string/erase.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/filesystem/fstream.hpp>
 
 /**
@@ -139,8 +141,11 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
         if (!mSilent)
             std::cout << "Loading config file: " << cfgFile.string() << "... ";
 
-        boost::filesystem::ifstream configFileStream(cfgFile);
-        if (configFileStream.is_open())
+        boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile);
+		boost::iostreams::filtering_istream configFileStream;
+		configFileStream.push(escape_hash_filter());
+		configFileStream.push(configFileStreamUnfiltered);
+        if (configFileStreamUnfiltered.is_open())
         {
             boost::program_options::store(boost::program_options::parse_config_file(
                 configFileStream, description, true), variables);
@@ -159,6 +164,111 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
     return false;
 }
 
+escape_hash_filter::escape_hash_filter() : mNext()
+{
+}
+
+escape_hash_filter::~escape_hash_filter()
+{
+}
+
+template <typename Source>
+int escape_hash_filter::get(Source & src)
+{
+	if (mNext.empty())
+	{
+		int character = boost::iostreams::get(src);
+		bool record = true;
+		if (character == boost::iostreams::WOULD_BLOCK)
+		{
+			mNext.push(character);
+			record = false;
+		}
+		else if (character == EOF)
+		{
+			seenNonWhitespace = false;
+			finishLine = false;
+			mNext.push(character);
+		}
+		else if (character == '\n')
+		{
+			seenNonWhitespace = false;
+			finishLine = false;
+			mNext.push(character);
+		}
+		else if (finishLine)
+		{
+			mNext.push(character);
+		}
+		else if (character == '#')
+		{
+			if (seenNonWhitespace)
+			{
+				mNext.push(sEscape);
+				mNext.push(sHashIdentifier);
+			}
+			else
+			{
+				//it's fine being interpreted by Boost as a comment, and so is anything afterwards
+				mNext.push(character);
+				finishLine = true;
+			}
+		}
+		else if (mPrevious == sEscape)
+		{
+			mNext.push(sEscape);
+			mNext.push(sEscapeIdentifier);
+		}
+		else
+		{
+			mNext.push(character);
+		}
+		if (!seenNonWhitespace && !isspace(character))
+			seenNonWhitespace = true;
+		if (record)
+			mPrevious = character;
+	}
+	int retval = mNext.front();
+	mNext.pop();
+	return retval;
+}
+
+std::string EscapeHashString::processString(const std::string & str)
+{
+	std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
+	boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1));
+	return temp;
+}
+
+EscapeHashString::EscapeHashString()
+{
+}
+
+EscapeHashString::EscapeHashString(const std::string & str) : std::string(EscapeHashString::processString(str))
+{
+}
+
+EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : std::string(EscapeHashString::processString(str), pos, len)
+{
+}
+
+EscapeHashString::EscapeHashString(const char * s) : std::string(EscapeHashString::processString(std::string(s)))
+{
+}
+
+EscapeHashString::EscapeHashString(const char * s, size_t n) : std::string(EscapeHashString::processString(std::string(s)), 0, n)
+{
+}
+
+EscapeHashString::EscapeHashString(size_t n, char c) : std::string(n, c)
+{
+}
+
+template <class InputIterator>
+EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last)))
+{
+}
+
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
 {
     return mFixedPath.getGlobalConfigPath();
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index c05dbbb45..7ef7d6fae 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -2,8 +2,10 @@
 #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
 
 #include <map>
+#include <queue>
 
 #include <boost/program_options.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
 
 #include <components/files/fixedpath.hpp>
 #include <components/files/collections.hpp>
@@ -63,6 +65,47 @@ struct ConfigurationManager
         bool mSilent;
 };
 
+
+/**
+ * \struct escape_hash_filter
+ */
+struct escape_hash_filter : public boost::iostreams::input_filter
+{
+	static const int sEscape = '@';
+	static const int sHashIdentifier = 'h';
+	static const int sEscapeIdentifier = 'a';
+
+	escape_hash_filter();
+	virtual ~escape_hash_filter();
+
+	template <typename Source> int get(Source & src);
+
+	private:
+		std::queue<int> mNext;
+		int mPrevious;
+
+		bool seenNonWhitespace = false;
+		bool finishLine = false;
+};
+
+/**
+ * \class EscapeHashString
+ */
+class EscapeHashString : public std::string
+{
+	public:
+		static std::string processString(const std::string & str);
+
+		EscapeHashString();
+		EscapeHashString(const std::string & str);
+		EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
+		EscapeHashString(const char * s);
+		EscapeHashString(const char * s, size_t n);
+		EscapeHashString(size_t n, char c);
+		template <class InputIterator>
+		EscapeHashString(InputIterator first, InputIterator last);
+};
+
 } /* namespace Cfg */
 
 #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */

From e17e354e8438b8ee3d0a0d5785f8201b69dd4136 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 01:09:34 +0100
Subject: [PATCH 02/14] Make # only start a comment in openmw.cfg if it starts
 a line and introduct compilation errors

---
 apps/openmw/main.cpp                      |  13 +--
 components/fallback/validate.hpp          |   4 +-
 components/files/configurationmanager.cpp | 114 +++++++++++++++++++++-
 components/files/configurationmanager.hpp |  43 ++++++++
 4 files changed, 165 insertions(+), 9 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index a4bf1fe5b..e4a918271 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-    typedef std::vector<std::string> StringsVector;
+	typedef Files::EscapeHashString string;
+    typedef std::vector<string> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
 
@@ -79,13 +80,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
             ->multitoken()->composing(), "set data directories (later directories have higher priority)")
 
-        ("data-local", bpo::value<std::string>()->default_value(""),
+        ("data-local", bpo::value<string>()->default_value(""),
             "set local data directory (highest priority)")
 
         ("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
-        ("resources", bpo::value<std::string>()->default_value("resources"),
+        ("resources", bpo::value<string>()->default_value("resources"),
             "set resources directory")
 
         ("start", bpo::value<std::string>()->default_value(""),
@@ -109,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-console", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "enable console-only script functionality")
 
-        ("script-run", bpo::value<std::string>()->default_value(""),
+        ("script-run", bpo::value<string>()->default_value(""),
             "select a file containing a list of console commands that is executed on startup")
 
         ("script-warn", bpo::value<int>()->implicit_value (1)
@@ -125,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
             ->default_value(true), "enable script blacklisting")
 
-        ("load-savegame", bpo::value<std::string>()->default_value(""),
+        ("load-savegame", bpo::value<string>()->default_value(""),
             "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
 
         ("skip-menu", bpo::value<bool>()->implicit_value(true)
@@ -137,7 +138,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("fs-strict", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "strict file system handling (no case folding)")
 
-        ( "encoding", bpo::value<std::string>()->
+        ( "encoding", bpo::value<string>()->
             default_value("win1252"),
             "Character encoding used in OpenMW game messages:\n"
             "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 3b6398d6a..531711544 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -3,6 +3,8 @@
 
 #include <boost/program_options.hpp>
 
+#include <components\files\configurationmanager.hpp>
+
 // Parses and validates a fallback map from boost program_options.
 // Note: for boost to pick up the validate function, you need to pull in the namespace e.g.
 // by using namespace Fallback;
@@ -11,7 +13,7 @@ namespace Fallback
 {
 
     struct FallbackMap {
-        std::map<std::string,std::string> mMap;
+        std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
     };
 
     void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 5ac3dd695..c50303d97 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -3,9 +3,11 @@
 #include <string>
 #include <iostream>
 #include <algorithm>
+#include <ctype.h>
 
 #include <boost/bind.hpp>
 #include <boost/algorithm/string/erase.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/filesystem/fstream.hpp>
 
 /**
@@ -139,8 +141,11 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
         if (!mSilent)
             std::cout << "Loading config file: " << cfgFile.string() << "... ";
 
-        boost::filesystem::ifstream configFileStream(cfgFile);
-        if (configFileStream.is_open())
+        boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile);
+		boost::iostreams::filtering_istream configFileStream;
+		configFileStream.push(escape_hash_filter());
+		configFileStream.push(configFileStreamUnfiltered);
+        if (configFileStreamUnfiltered.is_open())
         {
             boost::program_options::store(boost::program_options::parse_config_file(
                 configFileStream, description, true), variables);
@@ -159,6 +164,111 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
     return false;
 }
 
+escape_hash_filter::escape_hash_filter() : mNext()
+{
+}
+
+escape_hash_filter::~escape_hash_filter()
+{
+}
+
+template <typename Source>
+int escape_hash_filter::get(Source & src)
+{
+	if (mNext.empty())
+	{
+		int character = boost::iostreams::get(src);
+		bool record = true;
+		if (character == boost::iostreams::WOULD_BLOCK)
+		{
+			mNext.push(character);
+			record = false;
+		}
+		else if (character == EOF)
+		{
+			seenNonWhitespace = false;
+			finishLine = false;
+			mNext.push(character);
+		}
+		else if (character == '\n')
+		{
+			seenNonWhitespace = false;
+			finishLine = false;
+			mNext.push(character);
+		}
+		else if (finishLine)
+		{
+			mNext.push(character);
+		}
+		else if (character == '#')
+		{
+			if (seenNonWhitespace)
+			{
+				mNext.push(sEscape);
+				mNext.push(sHashIdentifier);
+			}
+			else
+			{
+				//it's fine being interpreted by Boost as a comment, and so is anything afterwards
+				mNext.push(character);
+				finishLine = true;
+			}
+		}
+		else if (mPrevious == sEscape)
+		{
+			mNext.push(sEscape);
+			mNext.push(sEscapeIdentifier);
+		}
+		else
+		{
+			mNext.push(character);
+		}
+		if (!seenNonWhitespace && !isspace(character))
+			seenNonWhitespace = true;
+		if (record)
+			mPrevious = character;
+	}
+	int retval = mNext.front();
+	mNext.pop();
+	return retval;
+}
+
+std::string EscapeHashString::processString(const std::string & str)
+{
+	std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
+	boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1));
+	return temp;
+}
+
+EscapeHashString::EscapeHashString()
+{
+}
+
+EscapeHashString::EscapeHashString(const std::string & str) : std::string(EscapeHashString::processString(str))
+{
+}
+
+EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : std::string(EscapeHashString::processString(str), pos, len)
+{
+}
+
+EscapeHashString::EscapeHashString(const char * s) : std::string(EscapeHashString::processString(std::string(s)))
+{
+}
+
+EscapeHashString::EscapeHashString(const char * s, size_t n) : std::string(EscapeHashString::processString(std::string(s)), 0, n)
+{
+}
+
+EscapeHashString::EscapeHashString(size_t n, char c) : std::string(n, c)
+{
+}
+
+template <class InputIterator>
+EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last)))
+{
+}
+
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
 {
     return mFixedPath.getGlobalConfigPath();
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index c05dbbb45..7ef7d6fae 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -2,8 +2,10 @@
 #define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
 
 #include <map>
+#include <queue>
 
 #include <boost/program_options.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
 
 #include <components/files/fixedpath.hpp>
 #include <components/files/collections.hpp>
@@ -63,6 +65,47 @@ struct ConfigurationManager
         bool mSilent;
 };
 
+
+/**
+ * \struct escape_hash_filter
+ */
+struct escape_hash_filter : public boost::iostreams::input_filter
+{
+	static const int sEscape = '@';
+	static const int sHashIdentifier = 'h';
+	static const int sEscapeIdentifier = 'a';
+
+	escape_hash_filter();
+	virtual ~escape_hash_filter();
+
+	template <typename Source> int get(Source & src);
+
+	private:
+		std::queue<int> mNext;
+		int mPrevious;
+
+		bool seenNonWhitespace = false;
+		bool finishLine = false;
+};
+
+/**
+ * \class EscapeHashString
+ */
+class EscapeHashString : public std::string
+{
+	public:
+		static std::string processString(const std::string & str);
+
+		EscapeHashString();
+		EscapeHashString(const std::string & str);
+		EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
+		EscapeHashString(const char * s);
+		EscapeHashString(const char * s, size_t n);
+		EscapeHashString(size_t n, char c);
+		template <class InputIterator>
+		EscapeHashString(InputIterator first, InputIterator last);
+};
+
 } /* namespace Cfg */
 
 #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */

From c1ffc9e7769c4ed7a33804e59a51e97016e47dfd Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 01:59:16 +0100
Subject: [PATCH 03/14] Remove a compilation error and set up framework to
 remove the others

---
 apps/openmw/main.cpp                      |  2 +-
 components/files/configurationmanager.cpp | 16 ++++++++++++++++
 components/files/configurationmanager.hpp |  3 +++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index e4a918271..cd45ddcf5 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -242,7 +242,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setScriptConsoleMode (variables["script-console"].as<bool>());
     engine.setStartupScript (variables["script-run"].as<std::string>());
     engine.setWarningsMode (variables["script-warn"].as<int>());
-    engine.setScriptBlacklist (variables["script-blacklist"].as<StringsVector>());
+    engine.setScriptBlacklist (string::toStdStringVector(variables["script-blacklist"].as<StringsVector>()));
     engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
     engine.setSaveGameFile (variables["load-savegame"].as<std::string>());
 
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index c50303d97..c7ac976d6 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -240,6 +240,17 @@ std::string EscapeHashString::processString(const std::string & str)
 	return temp;
 }
 
+
+std::vector<std::string> EscapeHashString::toStdStringVector(const std::vector<EscapeHashString> & vec)
+{
+	std::vector<std::string> temp = std::vector<std::string>();
+	for (std::vector<EscapeHashString>::const_iterator it = vec.begin(); it != vec.end(); ++it)
+	{
+		temp.push_back(it->toStdString());
+	}
+	return temp;
+}
+
 EscapeHashString::EscapeHashString()
 {
 }
@@ -269,6 +280,11 @@ EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : st
 {
 }
 
+std::string EscapeHashString::toStdString() const
+{
+	return std::string(* this);
+}
+
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
 {
     return mFixedPath.getGlobalConfigPath();
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 7ef7d6fae..47ecc9eb2 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -95,6 +95,7 @@ class EscapeHashString : public std::string
 {
 	public:
 		static std::string processString(const std::string & str);
+		static std::vector<std::string> toStdStringVector(const std::vector<EscapeHashString> & vec);
 
 		EscapeHashString();
 		EscapeHashString(const std::string & str);
@@ -104,6 +105,8 @@ class EscapeHashString : public std::string
 		EscapeHashString(size_t n, char c);
 		template <class InputIterator>
 		EscapeHashString(InputIterator first, InputIterator last);
+
+		std::string toStdString() const;
 };
 
 } /* namespace Cfg */

From 2a9b12bb3fb844f30aba7d9fada0170e3b86c1c9 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 14:15:35 +0100
Subject: [PATCH 04/14] Fix an issue preventing compilation, revealing another
 that doesn't make much sense.

---
 apps/openmw/main.cpp             |  4 ++--
 components/fallback/validate.hpp | 15 ++++++++++++++-
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index cd45ddcf5..9be1e8a7f 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -145,7 +145,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
             "\n\twin1252 - Western European (Latin) alphabet, used by default")
 
-        ("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
+			("fallback", bpo::value<EscapeFallbackMap>()->default_value(EscapeFallbackMap(), "")
             ->multitoken()->composing(), "fallback values")
 
         ("no-grab", "Don't grab mouse cursor")
@@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     // other settings
     engine.setSoundUsage(!variables["no-sound"].as<bool>());
-    engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
+	engine.setFallbackValues(variables["fallback"].as<EscapeFallbackMap>().toFallbackMap().mMap);
     engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
     engine.enableFontExport(variables["export-fonts"].as<bool>());
 
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 531711544..c41ff6b96 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -13,9 +13,22 @@ namespace Fallback
 {
 
     struct FallbackMap {
-        std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
+        std::map<std::string, std::string> mMap;
     };
 
+	struct EscapeFallbackMap : FallbackMap 
+	{
+		std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
+
+		FallbackMap toFallbackMap() const
+		{
+			FallbackMap temp = FallbackMap();
+			for (std::map<Files::EscapeHashString, Files::EscapeHashString>::const_iterator it = mMap.begin(); it != mMap.end(); ++it)
+				temp.mMap[it->first.toStdString()] = it->second.toStdString();
+			return temp;
+		}
+	};
+
     void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
     {
         if(v.empty())

From 7697406467d19bf39c568c35be2cc5293e082d35 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 14:39:38 +0100
Subject: [PATCH 05/14] Partially fix '2 overloads have similar conversions'
 compilation error

---
 components/fallback/validate.hpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index c41ff6b96..4df7da6e7 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -58,6 +58,10 @@ namespace Fallback
         }
     }
 
+	void validate(boost::any &v, std::vector<std::string> const &tokens, EscapeFallbackMap* eFM, int a)
+	{
+		validate(v, tokens, (FallbackMap *)eFM, a);
+	}
 }
 
 #endif

From fbe6dc97043bf2bfd52c4e44096b5bd967b40fa5 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 21:33:36 +0100
Subject: [PATCH 06/14] Change compilation error to runtime exception and
 decide that inheriting from std::string may have been a bad idea in C++

---
 apps/openmw/main.cpp                      | 17 +++---
 components/fallback/validate.hpp          | 65 +++++++++++++----------
 components/files/configurationmanager.cpp |  6 +++
 components/files/configurationmanager.hpp |  1 +
 4 files changed, 52 insertions(+), 37 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index 9be1e8a7f..645316f9c 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,8 +69,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-	typedef Files::EscapeHashString string;
-    typedef std::vector<string> StringsVector;
+	typedef std::vector<Files::EscapeHashString> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
 
@@ -80,16 +79,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
             ->multitoken()->composing(), "set data directories (later directories have higher priority)")
 
-        ("data-local", bpo::value<string>()->default_value(""),
+			("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set local data directory (highest priority)")
 
         ("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
-        ("resources", bpo::value<string>()->default_value("resources"),
+			("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
             "set resources directory")
 
-        ("start", bpo::value<std::string>()->default_value(""),
+			("start", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set initial cell")
 
         ("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
@@ -110,7 +109,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-console", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "enable console-only script functionality")
 
-        ("script-run", bpo::value<string>()->default_value(""),
+			("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
             "select a file containing a list of console commands that is executed on startup")
 
         ("script-warn", bpo::value<int>()->implicit_value (1)
@@ -126,7 +125,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
             ->default_value(true), "enable script blacklisting")
 
-        ("load-savegame", bpo::value<string>()->default_value(""),
+			("load-savegame", bpo::value<Files::EscapeHashString>()->default_value(""),
             "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
 
         ("skip-menu", bpo::value<bool>()->implicit_value(true)
@@ -138,7 +137,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("fs-strict", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "strict file system handling (no case folding)")
 
-        ( "encoding", bpo::value<string>()->
+			("encoding", bpo::value<Files::EscapeHashString>()->
             default_value("win1252"),
             "Character encoding used in OpenMW game messages:\n"
             "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
@@ -242,7 +241,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setScriptConsoleMode (variables["script-console"].as<bool>());
     engine.setStartupScript (variables["script-run"].as<std::string>());
     engine.setWarningsMode (variables["script-warn"].as<int>());
-    engine.setScriptBlacklist (string::toStdStringVector(variables["script-blacklist"].as<StringsVector>()));
+    engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as<StringsVector>()));
     engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
     engine.setSaveGameFile (variables["load-savegame"].as<std::string>());
 
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 4df7da6e7..4c4897c27 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -12,11 +12,11 @@
 namespace Fallback
 {
 
-    struct FallbackMap {
-        std::map<std::string, std::string> mMap;
-    };
+	struct FallbackMap {
+		std::map<std::string, std::string> mMap;
+	};
 
-	struct EscapeFallbackMap : FallbackMap 
+	struct EscapeFallbackMap : FallbackMap
 	{
 		std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
 
@@ -29,34 +29,34 @@ namespace Fallback
 		}
 	};
 
-    void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
-    {
-        if(v.empty())
-        {
-            v = boost::any(FallbackMap());
-        }
+	void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
+	{
+		if (v.empty())
+		{
+			v = boost::any(FallbackMap());
+		}
 
-        FallbackMap *map = boost::any_cast<FallbackMap>(&v);
+		FallbackMap *map = boost::any_cast<FallbackMap>(&v);
 
-        for(std::vector<std::string>::const_iterator it=tokens.begin(); it != tokens.end(); ++it)
-        {
-            int sep = it->find(",");
-            if(sep < 1 || sep == (int)it->length()-1)
-    #if (BOOST_VERSION < 104200)
-                throw boost::program_options::validation_error("invalid value");
-    #else
-                throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
-    #endif
+		for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
+		{
+			int sep = it->find(",");
+			if (sep < 1 || sep == (int)it->length() - 1)
+#if (BOOST_VERSION < 104200)
+				throw boost::program_options::validation_error("invalid value");
+#else
+				throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
+#endif
 
-            std::string key(it->substr(0,sep));
-            std::string value(it->substr(sep+1));
+			std::string key(it->substr(0, sep));
+			std::string value(it->substr(sep + 1));
 
-            if(map->mMap.find(key) == map->mMap.end())
-            {
-                map->mMap.insert(std::make_pair (key,value));
-            }
-        }
-    }
+			if (map->mMap.find(key) == map->mMap.end())
+			{
+				map->mMap.insert(std::make_pair(key, value));
+			}
+		}
+	}
 
 	void validate(boost::any &v, std::vector<std::string> const &tokens, EscapeFallbackMap* eFM, int a)
 	{
@@ -64,4 +64,13 @@ namespace Fallback
 	}
 }
 
+namespace Files {
+	void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
+	{
+		std::string * temp = eHS->toStdStringPtr();
+		boost::program_options::validate(v, tokens, temp, a);
+		delete temp;
+	}
+}
+
 #endif
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index c7ac976d6..78e49e23d 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -285,6 +285,12 @@ std::string EscapeHashString::toStdString() const
 	return std::string(* this);
 }
 
+std::string * EscapeHashString::toStdStringPtr() const
+{
+	std::string * ret = new std::string(*this);
+	return ret;
+}
+
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
 {
     return mFixedPath.getGlobalConfigPath();
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 47ecc9eb2..0d3517d48 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -107,6 +107,7 @@ class EscapeHashString : public std::string
 		EscapeHashString(InputIterator first, InputIterator last);
 
 		std::string toStdString() const;
+		std::string * toStdStringPtr() const;
 };
 
 } /* namespace Cfg */

From 195dd277804701438a82875a5829c61d27857976 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 22:05:38 +0100
Subject: [PATCH 07/14] Resolve obvious runtime error revealing more subtle one

---
 apps/openmw/main.cpp                      | 31 ++++++++++++-----------
 components/fallback/validate.hpp          | 11 +++++---
 components/files/configurationmanager.cpp | 19 +++++++-------
 components/files/configurationmanager.hpp |  2 ++
 4 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index 645316f9c..d63d1f60c 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,7 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-	typedef std::vector<Files::EscapeHashString> StringsVector;
+	typedef std::vector<Files::EscapeHashString> EscapeStringsVector;
+	typedef std::vector<std::string> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
 
@@ -82,7 +83,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 			("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set local data directory (highest priority)")
 
-        ("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
+        ("fallback-archive", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
 			("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
@@ -91,7 +92,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 			("start", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set initial cell")
 
-        ("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
+        ("content", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "")
             ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
 
         ("no-sound", bpo::value<bool>()->implicit_value(true)
@@ -119,7 +120,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             "\t1 - show warning but consider script as correctly compiled anyway\n"
             "\t2 - treat warnings as errors")
 
-        ("script-blacklist", bpo::value<StringsVector>()->default_value(StringsVector(), "")
+        ("script-blacklist", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "")
             ->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)")
 
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
@@ -173,20 +174,20 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     {
         cfgMgr.readConfiguration(variables, desc, true);
 
-        Version::Version v = Version::getOpenmwVersion(variables["resources"].as<std::string>());
+        Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
         std::cout << v.describe() << std::endl;
         return false;
     }
 
     cfgMgr.readConfiguration(variables, desc);
 
-    Version::Version v = Version::getOpenmwVersion(variables["resources"].as<std::string>());
+    Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
     std::cout << v.describe() << std::endl;
 
     engine.setGrabMouse(!variables.count("no-grab"));
 
     // Font encoding settings
-    std::string encoding(variables["encoding"].as<std::string>());
+    std::string encoding(variables["encoding"].as<Files::EscapeHashString>().toStdString());
     std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl;
     engine.setEncoding(ToUTF8::calculateEncoding(encoding));
 
@@ -195,7 +196,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
 
-    std::string local(variables["data-local"].as<std::string>());
+    std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
     if (!local.empty())
     {
         dataDirs.push_back(Files::PathContainer::value_type(local));
@@ -206,15 +207,15 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setDataDirs(dataDirs);
 
     // fallback archives
-    StringsVector archives = variables["fallback-archive"].as<StringsVector>();
+    StringsVector archives = Files::EscapeHashString::toStdStringVector(variables["fallback-archive"].as<EscapeStringsVector>());
     for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); ++it)
     {
         engine.addArchive(*it);
     }
 
-    engine.setResourceDir(variables["resources"].as<std::string>());
+    engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString());
 
-    StringsVector content = variables["content"].as<StringsVector>();
+	StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as<EscapeStringsVector>());
     if (content.empty())
     {
       std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
@@ -229,7 +230,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     }
 
     // startup-settings
-    engine.setCell(variables["start"].as<std::string>());
+    engine.setCell(variables["start"].as<Files::EscapeHashString>().toStdString());
     engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
     if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
         std::cerr << "new-game used without skip-menu -> ignoring it" << std::endl;
@@ -239,11 +240,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>());
     engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
     engine.setScriptConsoleMode (variables["script-console"].as<bool>());
-    engine.setStartupScript (variables["script-run"].as<std::string>());
+    engine.setStartupScript (variables["script-run"].as<Files::EscapeHashString>().toStdString());
     engine.setWarningsMode (variables["script-warn"].as<int>());
-    engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as<StringsVector>()));
+    engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as<EscapeStringsVector>()));
     engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
-    engine.setSaveGameFile (variables["load-savegame"].as<std::string>());
+    engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapeHashString>().toStdString());
 
     // other settings
     engine.setSoundUsage(!variables["no-sound"].as<bool>());
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 4c4897c27..7683a1297 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -67,9 +67,14 @@ namespace Fallback
 namespace Files {
 	void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
 	{
-		std::string * temp = eHS->toStdStringPtr();
-		boost::program_options::validate(v, tokens, temp, a);
-		delete temp;
+		if (eHS == NULL)
+			boost::program_options::validate(v, tokens, (std::string *) NULL, a);
+		else
+		{
+			std::string * temp = eHS->toStdStringPtr();
+			boost::program_options::validate(v, tokens, temp, a);
+			delete temp;
+		}
 	}
 }
 
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 78e49e23d..d8543738d 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -251,44 +251,43 @@ std::vector<std::string> EscapeHashString::toStdStringVector(const std::vector<E
 	return temp;
 }
 
-EscapeHashString::EscapeHashString()
+EscapeHashString::EscapeHashString() : mData()
 {
 }
 
-EscapeHashString::EscapeHashString(const std::string & str) : std::string(EscapeHashString::processString(str))
+EscapeHashString::EscapeHashString(const std::string & str) : mData(EscapeHashString::processString(str))
 {
 }
 
-EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : std::string(EscapeHashString::processString(str), pos, len)
+EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : mData(EscapeHashString::processString(str), pos, len)
 {
 }
 
-EscapeHashString::EscapeHashString(const char * s) : std::string(EscapeHashString::processString(std::string(s)))
+EscapeHashString::EscapeHashString(const char * s) : mData(EscapeHashString::processString(std::string(s)))
 {
 }
 
-EscapeHashString::EscapeHashString(const char * s, size_t n) : std::string(EscapeHashString::processString(std::string(s)), 0, n)
+EscapeHashString::EscapeHashString(const char * s, size_t n) : mData(EscapeHashString::processString(std::string(s)), 0, n)
 {
 }
 
-EscapeHashString::EscapeHashString(size_t n, char c) : std::string(n, c)
+EscapeHashString::EscapeHashString(size_t n, char c) : mData(n, c)
 {
 }
 
 template <class InputIterator>
-EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : std::string(EscapeHashString::processString(std::string(first, last)))
+EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last)))
 {
 }
 
 std::string EscapeHashString::toStdString() const
 {
-	return std::string(* this);
+	return std::string(mData);
 }
 
 std::string * EscapeHashString::toStdStringPtr() const
 {
-	std::string * ret = new std::string(*this);
-	return ret;
+	return new std::string(mData);
 }
 
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 0d3517d48..e6257eec4 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -93,6 +93,8 @@ struct escape_hash_filter : public boost::iostreams::input_filter
  */
 class EscapeHashString : public std::string
 {
+	private:
+		std::string mData;
 	public:
 		static std::string processString(const std::string & str);
 		static std::vector<std::string> toStdStringVector(const std::vector<EscapeHashString> & vec);

From 1a0642f1dbcbcfdc341989f2ec7e81aedee86f3f Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Mon, 11 Jul 2016 22:33:15 +0100
Subject: [PATCH 08/14] Make it work by realising that what
 boost::program_options calls validation is what any sane person would regard
 as parsing

---
 apps/openmw/main.cpp             |  4 ++--
 components/fallback/validate.hpp | 39 ++++++++------------------------
 2 files changed, 11 insertions(+), 32 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index d63d1f60c..e57ff867c 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -145,7 +145,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
             "\n\twin1252 - Western European (Latin) alphabet, used by default")
 
-			("fallback", bpo::value<EscapeFallbackMap>()->default_value(EscapeFallbackMap(), "")
+			("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
             ->multitoken()->composing(), "fallback values")
 
         ("no-grab", "Don't grab mouse cursor")
@@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     // other settings
     engine.setSoundUsage(!variables["no-sound"].as<bool>());
-	engine.setFallbackValues(variables["fallback"].as<EscapeFallbackMap>().toFallbackMap().mMap);
+	engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
     engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
     engine.enableFontExport(variables["export-fonts"].as<bool>());
 
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 7683a1297..605b64702 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -16,19 +16,6 @@ namespace Fallback
 		std::map<std::string, std::string> mMap;
 	};
 
-	struct EscapeFallbackMap : FallbackMap
-	{
-		std::map<Files::EscapeHashString, Files::EscapeHashString> mMap;
-
-		FallbackMap toFallbackMap() const
-		{
-			FallbackMap temp = FallbackMap();
-			for (std::map<Files::EscapeHashString, Files::EscapeHashString>::const_iterator it = mMap.begin(); it != mMap.end(); ++it)
-				temp.mMap[it->first.toStdString()] = it->second.toStdString();
-			return temp;
-		}
-	};
-
 	void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
 	{
 		if (v.empty())
@@ -40,16 +27,17 @@ namespace Fallback
 
 		for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
 		{
-			int sep = it->find(",");
-			if (sep < 1 || sep == (int)it->length() - 1)
+			std::string temp = Files::EscapeHashString::processString(*it);
+			int sep = temp.find(",");
+			if (sep < 1 || sep == (int)temp.length() - 1)
 #if (BOOST_VERSION < 104200)
 				throw boost::program_options::validation_error("invalid value");
 #else
 				throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
 #endif
 
-			std::string key(it->substr(0, sep));
-			std::string value(it->substr(sep + 1));
+			std::string key(temp.substr(0, sep));
+			std::string value(temp.substr(sep + 1));
 
 			if (map->mMap.find(key) == map->mMap.end())
 			{
@@ -57,24 +45,15 @@ namespace Fallback
 			}
 		}
 	}
-
-	void validate(boost::any &v, std::vector<std::string> const &tokens, EscapeFallbackMap* eFM, int a)
-	{
-		validate(v, tokens, (FallbackMap *)eFM, a);
-	}
 }
 
 namespace Files {
 	void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
 	{
-		if (eHS == NULL)
-			boost::program_options::validate(v, tokens, (std::string *) NULL, a);
-		else
-		{
-			std::string * temp = eHS->toStdStringPtr();
-			boost::program_options::validate(v, tokens, temp, a);
-			delete temp;
-		}
+		boost::program_options::validators::check_first_occurrence(v);
+		
+		if (v.empty())
+			v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
 	}
 }
 

From 5121e77a95667aafc82665ad8d8cb390153058bf Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Tue, 12 Jul 2016 00:00:29 +0100
Subject: [PATCH 09/14] Remove the cause of a warning which upset Travis (but
 not the thing that made the Travis build fail, as I have no idea why it
 wouldn't work or how to fix it

---
 components/files/configurationmanager.cpp | 20 ++++++++++----------
 components/files/configurationmanager.hpp |  4 ++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index d8543738d..951c444a5 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -164,7 +164,7 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
     return false;
 }
 
-escape_hash_filter::escape_hash_filter() : mNext()
+escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false)
 {
 }
 
@@ -186,23 +186,23 @@ int escape_hash_filter::get(Source & src)
 		}
 		else if (character == EOF)
 		{
-			seenNonWhitespace = false;
-			finishLine = false;
+			mSeenNonWhitespace = false;
+			mFinishLine = false;
 			mNext.push(character);
 		}
 		else if (character == '\n')
 		{
-			seenNonWhitespace = false;
-			finishLine = false;
+			mSeenNonWhitespace = false;
+			mFinishLine = false;
 			mNext.push(character);
 		}
-		else if (finishLine)
+		else if (mFinishLine)
 		{
 			mNext.push(character);
 		}
 		else if (character == '#')
 		{
-			if (seenNonWhitespace)
+			if (mSeenNonWhitespace)
 			{
 				mNext.push(sEscape);
 				mNext.push(sHashIdentifier);
@@ -211,7 +211,7 @@ int escape_hash_filter::get(Source & src)
 			{
 				//it's fine being interpreted by Boost as a comment, and so is anything afterwards
 				mNext.push(character);
-				finishLine = true;
+				mFinishLine = true;
 			}
 		}
 		else if (mPrevious == sEscape)
@@ -223,8 +223,8 @@ int escape_hash_filter::get(Source & src)
 		{
 			mNext.push(character);
 		}
-		if (!seenNonWhitespace && !isspace(character))
-			seenNonWhitespace = true;
+		if (!mSeenNonWhitespace && !isspace(character))
+			mSeenNonWhitespace = true;
 		if (record)
 			mPrevious = character;
 	}
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index e6257eec4..20d5c62ec 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -84,8 +84,8 @@ struct escape_hash_filter : public boost::iostreams::input_filter
 		std::queue<int> mNext;
 		int mPrevious;
 
-		bool seenNonWhitespace = false;
-		bool finishLine = false;
+		bool mSeenNonWhitespace;
+		bool mFinishLine;
 };
 
 /**

From 7475d90693a7344735d744c66a993d51842a7244 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Tue, 12 Jul 2016 00:14:19 +0100
Subject: [PATCH 10/14] Fix dodgy include by changing backslashes to
 forwardslashes

---
 components/fallback/validate.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index 605b64702..fe545ce4b 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -3,7 +3,7 @@
 
 #include <boost/program_options.hpp>
 
-#include <components\files\configurationmanager.hpp>
+#include <components/files/configurationmanager.hpp>
 
 // Parses and validates a fallback map from boost program_options.
 // Note: for boost to pick up the validate function, you need to pull in the namespace e.g.

From 08df463c949fc1f1d51b51f61f00a5cd0e626e71 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Tue, 12 Jul 2016 00:37:08 +0100
Subject: [PATCH 11/14] Separate declaration and definition of some static
 members to hopefully calm Travis down.

---
 components/files/configurationmanager.cpp | 4 ++++
 components/files/configurationmanager.hpp | 6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 951c444a5..46775a7fb 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -164,6 +164,10 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
     return false;
 }
 
+const int escape_hash_filter::sEscape = '@';
+const int escape_hash_filter::sEscapeIdentifier = 'a';
+const int escape_hash_filter::sHashIdentifier = 'h';
+
 escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false)
 {
 }
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 20d5c62ec..6e1cfbdb1 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -71,9 +71,9 @@ struct ConfigurationManager
  */
 struct escape_hash_filter : public boost::iostreams::input_filter
 {
-	static const int sEscape = '@';
-	static const int sHashIdentifier = 'h';
-	static const int sEscapeIdentifier = 'a';
+	static const int sEscape;
+	static const int sHashIdentifier;
+	static const int sEscapeIdentifier;
 
 	escape_hash_filter();
 	virtual ~escape_hash_filter();

From e6f78ae5b74272aa8e10dc0b803c60138de15978 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Tue, 12 Jul 2016 01:06:57 +0100
Subject: [PATCH 12/14] Switch indentation to spaces to remain consistent with
 the rest of the project

---
 apps/openmw/main.cpp                      |  22 ++--
 components/fallback/validate.hpp          |  64 +++++-----
 components/files/configurationmanager.cpp | 140 +++++++++++-----------
 components/files/configurationmanager.hpp |  52 ++++----
 4 files changed, 139 insertions(+), 139 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index e57ff867c..e96b6e595 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,8 +69,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-	typedef std::vector<Files::EscapeHashString> EscapeStringsVector;
-	typedef std::vector<std::string> StringsVector;
+    typedef std::vector<Files::EscapeHashString> EscapeStringsVector;
+    typedef std::vector<std::string> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
 
@@ -80,16 +80,16 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
             ->multitoken()->composing(), "set data directories (later directories have higher priority)")
 
-			("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
+            ("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set local data directory (highest priority)")
 
         ("fallback-archive", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
-			("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
+            ("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
             "set resources directory")
 
-			("start", bpo::value<Files::EscapeHashString>()->default_value(""),
+            ("start", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set initial cell")
 
         ("content", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "")
@@ -110,7 +110,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-console", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "enable console-only script functionality")
 
-			("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
+            ("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
             "select a file containing a list of console commands that is executed on startup")
 
         ("script-warn", bpo::value<int>()->implicit_value (1)
@@ -126,7 +126,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
             ->default_value(true), "enable script blacklisting")
 
-			("load-savegame", bpo::value<Files::EscapeHashString>()->default_value(""),
+            ("load-savegame", bpo::value<Files::EscapeHashString>()->default_value(""),
             "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
 
         ("skip-menu", bpo::value<bool>()->implicit_value(true)
@@ -138,14 +138,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         ("fs-strict", bpo::value<bool>()->implicit_value(true)
             ->default_value(false), "strict file system handling (no case folding)")
 
-			("encoding", bpo::value<Files::EscapeHashString>()->
+            ("encoding", bpo::value<Files::EscapeHashString>()->
             default_value("win1252"),
             "Character encoding used in OpenMW game messages:\n"
             "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
             "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
             "\n\twin1252 - Western European (Latin) alphabet, used by default")
 
-			("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
+            ("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
             ->multitoken()->composing(), "fallback values")
 
         ("no-grab", "Don't grab mouse cursor")
@@ -215,7 +215,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString());
 
-	StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as<EscapeStringsVector>());
+    StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as<EscapeStringsVector>());
     if (content.empty())
     {
       std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
@@ -248,7 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     // other settings
     engine.setSoundUsage(!variables["no-sound"].as<bool>());
-	engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
+    engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
     engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
     engine.enableFontExport(variables["export-fonts"].as<bool>());
 
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index fe545ce4b..e609297ae 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -12,49 +12,49 @@
 namespace Fallback
 {
 
-	struct FallbackMap {
-		std::map<std::string, std::string> mMap;
-	};
+    struct FallbackMap {
+        std::map<std::string, std::string> mMap;
+    };
 
-	void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
-	{
-		if (v.empty())
-		{
-			v = boost::any(FallbackMap());
-		}
+    void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap*, int)
+    {
+        if (v.empty())
+        {
+            v = boost::any(FallbackMap());
+        }
 
-		FallbackMap *map = boost::any_cast<FallbackMap>(&v);
+        FallbackMap *map = boost::any_cast<FallbackMap>(&v);
 
-		for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
-		{
-			std::string temp = Files::EscapeHashString::processString(*it);
-			int sep = temp.find(",");
-			if (sep < 1 || sep == (int)temp.length() - 1)
+        for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
+        {
+            std::string temp = Files::EscapeHashString::processString(*it);
+            int sep = temp.find(",");
+            if (sep < 1 || sep == (int)temp.length() - 1)
 #if (BOOST_VERSION < 104200)
-				throw boost::program_options::validation_error("invalid value");
+                throw boost::program_options::validation_error("invalid value");
 #else
-				throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
+                throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value);
 #endif
 
-			std::string key(temp.substr(0, sep));
-			std::string value(temp.substr(sep + 1));
+            std::string key(temp.substr(0, sep));
+            std::string value(temp.substr(sep + 1));
 
-			if (map->mMap.find(key) == map->mMap.end())
-			{
-				map->mMap.insert(std::make_pair(key, value));
-			}
-		}
-	}
+            if (map->mMap.find(key) == map->mMap.end())
+            {
+                map->mMap.insert(std::make_pair(key, value));
+            }
+        }
+    }
 }
 
 namespace Files {
-	void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
-	{
-		boost::program_options::validators::check_first_occurrence(v);
-		
-		if (v.empty())
-			v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
-	}
+    void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
+    {
+        boost::program_options::validators::check_first_occurrence(v);
+        
+        if (v.empty())
+            v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
+    }
 }
 
 #endif
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 46775a7fb..511dbe411 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -142,9 +142,9 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
             std::cout << "Loading config file: " << cfgFile.string() << "... ";
 
         boost::filesystem::ifstream configFileStreamUnfiltered(cfgFile);
-		boost::iostreams::filtering_istream configFileStream;
-		configFileStream.push(escape_hash_filter());
-		configFileStream.push(configFileStreamUnfiltered);
+        boost::iostreams::filtering_istream configFileStream;
+        configFileStream.push(escape_hash_filter());
+        configFileStream.push(configFileStreamUnfiltered);
         if (configFileStreamUnfiltered.is_open())
         {
             boost::program_options::store(boost::program_options::parse_config_file(
@@ -179,80 +179,80 @@ escape_hash_filter::~escape_hash_filter()
 template <typename Source>
 int escape_hash_filter::get(Source & src)
 {
-	if (mNext.empty())
-	{
-		int character = boost::iostreams::get(src);
-		bool record = true;
-		if (character == boost::iostreams::WOULD_BLOCK)
-		{
-			mNext.push(character);
-			record = false;
-		}
-		else if (character == EOF)
-		{
-			mSeenNonWhitespace = false;
-			mFinishLine = false;
-			mNext.push(character);
-		}
-		else if (character == '\n')
-		{
-			mSeenNonWhitespace = false;
-			mFinishLine = false;
-			mNext.push(character);
-		}
-		else if (mFinishLine)
-		{
-			mNext.push(character);
-		}
-		else if (character == '#')
-		{
-			if (mSeenNonWhitespace)
-			{
-				mNext.push(sEscape);
-				mNext.push(sHashIdentifier);
-			}
-			else
-			{
-				//it's fine being interpreted by Boost as a comment, and so is anything afterwards
-				mNext.push(character);
-				mFinishLine = true;
-			}
-		}
-		else if (mPrevious == sEscape)
-		{
-			mNext.push(sEscape);
-			mNext.push(sEscapeIdentifier);
-		}
-		else
-		{
-			mNext.push(character);
-		}
-		if (!mSeenNonWhitespace && !isspace(character))
-			mSeenNonWhitespace = true;
-		if (record)
-			mPrevious = character;
-	}
-	int retval = mNext.front();
-	mNext.pop();
-	return retval;
+    if (mNext.empty())
+    {
+        int character = boost::iostreams::get(src);
+        bool record = true;
+        if (character == boost::iostreams::WOULD_BLOCK)
+        {
+            mNext.push(character);
+            record = false;
+        }
+        else if (character == EOF)
+        {
+            mSeenNonWhitespace = false;
+            mFinishLine = false;
+            mNext.push(character);
+        }
+        else if (character == '\n')
+        {
+            mSeenNonWhitespace = false;
+            mFinishLine = false;
+            mNext.push(character);
+        }
+        else if (mFinishLine)
+        {
+            mNext.push(character);
+        }
+        else if (character == '#')
+        {
+            if (mSeenNonWhitespace)
+            {
+                mNext.push(sEscape);
+                mNext.push(sHashIdentifier);
+            }
+            else
+            {
+                //it's fine being interpreted by Boost as a comment, and so is anything afterwards
+                mNext.push(character);
+                mFinishLine = true;
+            }
+        }
+        else if (mPrevious == sEscape)
+        {
+            mNext.push(sEscape);
+            mNext.push(sEscapeIdentifier);
+        }
+        else
+        {
+            mNext.push(character);
+        }
+        if (!mSeenNonWhitespace && !isspace(character))
+            mSeenNonWhitespace = true;
+        if (record)
+            mPrevious = character;
+    }
+    int retval = mNext.front();
+    mNext.pop();
+    return retval;
 }
 
 std::string EscapeHashString::processString(const std::string & str)
 {
-	std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
-	boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1));
-	return temp;
+    std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
+    boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1));
+    return temp;
 }
 
 
 std::vector<std::string> EscapeHashString::toStdStringVector(const std::vector<EscapeHashString> & vec)
 {
-	std::vector<std::string> temp = std::vector<std::string>();
-	for (std::vector<EscapeHashString>::const_iterator it = vec.begin(); it != vec.end(); ++it)
-	{
-		temp.push_back(it->toStdString());
-	}
-	return temp;
+    std::vector<std::string> temp = std::vector<std::string>();
+    for (std::vector<EscapeHashString>::const_iterator it = vec.begin(); it != vec.end(); ++it)
+    {
+        temp.push_back(it->toStdString());
+    }
+    return temp;
 }
 
 EscapeHashString::EscapeHashString() : mData()
@@ -286,12 +286,12 @@ EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mD
 
 std::string EscapeHashString::toStdString() const
 {
-	return std::string(mData);
+    return std::string(mData);
 }
 
 std::string * EscapeHashString::toStdStringPtr() const
 {
-	return new std::string(mData);
+    return new std::string(mData);
 }
 
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 6e1cfbdb1..5138b3ca7 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -71,21 +71,21 @@ struct ConfigurationManager
  */
 struct escape_hash_filter : public boost::iostreams::input_filter
 {
-	static const int sEscape;
-	static const int sHashIdentifier;
-	static const int sEscapeIdentifier;
+    static const int sEscape;
+    static const int sHashIdentifier;
+    static const int sEscapeIdentifier;
 
-	escape_hash_filter();
-	virtual ~escape_hash_filter();
+    escape_hash_filter();
+    virtual ~escape_hash_filter();
 
-	template <typename Source> int get(Source & src);
+    template <typename Source> int get(Source & src);
 
-	private:
-		std::queue<int> mNext;
-		int mPrevious;
+    private:
+        std::queue<int> mNext;
+        int mPrevious;
 
-		bool mSeenNonWhitespace;
-		bool mFinishLine;
+        bool mSeenNonWhitespace;
+        bool mFinishLine;
 };
 
 /**
@@ -93,23 +93,23 @@ struct escape_hash_filter : public boost::iostreams::input_filter
  */
 class EscapeHashString : public std::string
 {
-	private:
-		std::string mData;
-	public:
-		static std::string processString(const std::string & str);
-		static std::vector<std::string> toStdStringVector(const std::vector<EscapeHashString> & vec);
+    private:
+        std::string mData;
+    public:
+        static std::string processString(const std::string & str);
+        static std::vector<std::string> toStdStringVector(const std::vector<EscapeHashString> & vec);
 
-		EscapeHashString();
-		EscapeHashString(const std::string & str);
-		EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
-		EscapeHashString(const char * s);
-		EscapeHashString(const char * s, size_t n);
-		EscapeHashString(size_t n, char c);
-		template <class InputIterator>
-		EscapeHashString(InputIterator first, InputIterator last);
+        EscapeHashString();
+        EscapeHashString(const std::string & str);
+        EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
+        EscapeHashString(const char * s);
+        EscapeHashString(const char * s, size_t n);
+        EscapeHashString(size_t n, char c);
+        template <class InputIterator>
+        EscapeHashString(InputIterator first, InputIterator last);
 
-		std::string toStdString() const;
-		std::string * toStdStringPtr() const;
+        std::string toStdString() const;
+        std::string * toStdStringPtr() const;
 };
 
 } /* namespace Cfg */

From f1b5ad580427cb7ab9812b8664009e375e21e921 Mon Sep 17 00:00:00 2001
From: AnyOldName3 <krizdjali+github@gmail.com>
Date: Tue, 12 Jul 2016 17:09:57 +0100
Subject: [PATCH 13/14] Remove unused unsafe function and properly remove
 inheritance from std::string, providing implementations of missing stream
 operators preventing boost reading and writing to escape strings.

---
 apps/openmw/main.cpp                      | 13 ++++---
 components/fallback/validate.hpp          | 11 ++++++
 components/files/configurationmanager.cpp | 42 ++++++++++++++++-------
 components/files/configurationmanager.hpp | 18 ++++++++--
 4 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index e96b6e595..f54905a2c 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -69,7 +69,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 {
     // Create a local alias for brevity
     namespace bpo = boost::program_options;
-    typedef std::vector<Files::EscapeHashString> EscapeStringsVector;
     typedef std::vector<std::string> StringsVector;
 
     bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
@@ -83,7 +82,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             ("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set local data directory (highest priority)")
 
-        ("fallback-archive", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "fallback-archive")
+        ("fallback-archive", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "fallback-archive")
             ->multitoken(), "set fallback BSA archives (later archives have higher priority)")
 
             ("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
@@ -92,7 +91,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             ("start", bpo::value<Files::EscapeHashString>()->default_value(""),
             "set initial cell")
 
-        ("content", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "")
+        ("content", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
             ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
 
         ("no-sound", bpo::value<bool>()->implicit_value(true)
@@ -120,7 +119,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
             "\t1 - show warning but consider script as correctly compiled anyway\n"
             "\t2 - treat warnings as errors")
 
-        ("script-blacklist", bpo::value<EscapeStringsVector>()->default_value(EscapeStringsVector(), "")
+        ("script-blacklist", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
             ->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)")
 
         ("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
@@ -207,7 +206,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setDataDirs(dataDirs);
 
     // fallback archives
-    StringsVector archives = Files::EscapeHashString::toStdStringVector(variables["fallback-archive"].as<EscapeStringsVector>());
+    StringsVector archives = variables["fallback-archive"].as<Files::EscapeStringVector>().toStdStringVector();
     for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); ++it)
     {
         engine.addArchive(*it);
@@ -215,7 +214,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString());
 
-    StringsVector content = Files::EscapeHashString::toStdStringVector(variables["content"].as<EscapeStringsVector>());
+    StringsVector content = variables["content"].as<Files::EscapeStringVector>().toStdStringVector();
     if (content.empty())
     {
       std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
@@ -242,7 +241,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
     engine.setScriptConsoleMode (variables["script-console"].as<bool>());
     engine.setStartupScript (variables["script-run"].as<Files::EscapeHashString>().toStdString());
     engine.setWarningsMode (variables["script-warn"].as<int>());
-    engine.setScriptBlacklist (Files::EscapeHashString::toStdStringVector(variables["script-blacklist"].as<EscapeStringsVector>()));
+    engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
     engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
     engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapeHashString>().toStdString());
 
diff --git a/components/fallback/validate.hpp b/components/fallback/validate.hpp
index e609297ae..d82ef5770 100644
--- a/components/fallback/validate.hpp
+++ b/components/fallback/validate.hpp
@@ -55,6 +55,17 @@ namespace Files {
         if (v.empty())
             v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
     }
+
+    void validate(boost::any &v, const std::vector<std::string> &tokens, EscapeStringVector *, int)
+    {
+        if (v.empty())
+            v = boost::any(EscapeStringVector());
+
+        EscapeStringVector * eSV = boost::any_cast<EscapeStringVector>(&v);
+
+        for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
+            eSV->mVector.push_back(EscapeHashString(*it));
+    }
 }
 
 #endif
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 511dbe411..3a7f57949 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -244,17 +244,6 @@ std::string EscapeHashString::processString(const std::string & str)
     return temp;
 }
 
-
-std::vector<std::string> EscapeHashString::toStdStringVector(const std::vector<EscapeHashString> & vec)
-{
-    std::vector<std::string> temp = std::vector<std::string>();
-    for (std::vector<EscapeHashString>::const_iterator it = vec.begin(); it != vec.end(); ++it)
-    {
-        temp.push_back(it->toStdString());
-    }
-    return temp;
-}
-
 EscapeHashString::EscapeHashString() : mData()
 {
 }
@@ -289,9 +278,36 @@ std::string EscapeHashString::toStdString() const
     return std::string(mData);
 }
 
-std::string * EscapeHashString::toStdStringPtr() const
+std::istream & operator>> (std::istream & is, EscapeHashString & eHS)
 {
-    return new std::string(mData);
+    std::string temp;
+    is >> temp;
+    eHS = EscapeHashString(temp);
+    return is;
+}
+
+std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS)
+{
+    os << eHS.mData;
+    return os;
+}
+
+EscapeStringVector::EscapeStringVector() : mVector()
+{
+}
+
+EscapeStringVector::~EscapeStringVector()
+{
+}
+
+std::vector<std::string> EscapeStringVector::toStdStringVector() const
+{
+    std::vector<std::string> temp = std::vector<std::string>();
+    for (std::vector<EscapeHashString>::const_iterator it = mVector.begin(); it != mVector.end(); ++it)
+    {
+        temp.push_back(it->toStdString());
+    }
+    return temp;
 }
 
 const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 5138b3ca7..3ce995983 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -91,13 +91,12 @@ struct escape_hash_filter : public boost::iostreams::input_filter
 /**
  * \class EscapeHashString
  */
-class EscapeHashString : public std::string
+class EscapeHashString
 {
     private:
         std::string mData;
     public:
         static std::string processString(const std::string & str);
-        static std::vector<std::string> toStdStringVector(const std::vector<EscapeHashString> & vec);
 
         EscapeHashString();
         EscapeHashString(const std::string & str);
@@ -109,7 +108,20 @@ class EscapeHashString : public std::string
         EscapeHashString(InputIterator first, InputIterator last);
 
         std::string toStdString() const;
-        std::string * toStdStringPtr() const;
+
+        friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS);
+};
+
+std::istream & operator>> (std::istream & is, EscapeHashString & eHS);
+
+struct EscapeStringVector
+{
+    std::vector<Files::EscapeHashString> mVector;
+
+    EscapeStringVector();
+    virtual ~EscapeStringVector();
+
+    std::vector<std::string> toStdStringVector() const;
 };
 
 } /* namespace Cfg */

From 4ac5174d899f03eff4449f7d8d74e2f0e2b9a8ca Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Tue, 19 Jul 2016 16:29:26 +0200
Subject: [PATCH 14/14] updated credits file

---
 AUTHORS.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/AUTHORS.md b/AUTHORS.md
index b97642aba..60e969cdc 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -22,6 +22,7 @@ Programmers
     Alexander Nadeau (wareya)
     Alexander Olofsson (Ace)
     Allofich
+    AnyOldName3
     Austin Salgat (Salgat)
     Artem Kotsynyak (greye)
     artemutin