aboutsummaryrefslogtreecommitdiff
path: root/libs/game_gamebryo/src/gamebryo/vdf_parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/game_gamebryo/src/gamebryo/vdf_parser.h')
-rw-r--r--libs/game_gamebryo/src/gamebryo/vdf_parser.h739
1 files changed, 739 insertions, 0 deletions
diff --git a/libs/game_gamebryo/src/gamebryo/vdf_parser.h b/libs/game_gamebryo/src/gamebryo/vdf_parser.h
new file mode 100644
index 0000000..32d4d27
--- /dev/null
+++ b/libs/game_gamebryo/src/gamebryo/vdf_parser.h
@@ -0,0 +1,739 @@
+// MIT License
+//
+// Copyright(c) 2016 Matthias Moeller
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#ifndef __TYTI_STEAM_VDF_PARSER_H__
+#define __TYTI_STEAM_VDF_PARSER_H__
+
+#include <algorithm>
+#include <fstream>
+#include <functional>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <exception>
+#include <system_error>
+
+// for wstring support
+#include <locale>
+#include <string>
+
+// internal
+#include <stack>
+
+// VS < 2015 has only partial C++11 support
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#ifndef CONSTEXPR
+#define CONSTEXPR
+#endif
+
+#ifndef NOEXCEPT
+#define NOEXCEPT
+#endif
+#else
+#ifndef CONSTEXPR
+#define CONSTEXPR constexpr
+#define TYTI_UNDEF_CONSTEXPR
+#endif
+
+#ifndef NOEXCEPT
+#define NOEXCEPT noexcept
+#define TYTI_UNDEF_NOEXCEPT
+#endif
+
+#endif
+
+namespace tyti
+{
+namespace vdf
+{
+ namespace detail
+ {
+ ///////////////////////////////////////////////////////////////////////////
+ // Helper functions selecting the right encoding (char/wchar_T)
+ ///////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ struct literal_macro_help
+ {
+ static CONSTEXPR const char* result(const char* c, const wchar_t*) NOEXCEPT
+ {
+ return c;
+ }
+ static CONSTEXPR const char result(const char c, const wchar_t) NOEXCEPT
+ {
+ return c;
+ }
+ };
+
+ template <>
+ struct literal_macro_help<wchar_t>
+ {
+ static CONSTEXPR const wchar_t* result(const char*, const wchar_t* wc) NOEXCEPT
+ {
+ return wc;
+ }
+ static CONSTEXPR const wchar_t result(const char, const wchar_t wc) NOEXCEPT
+ {
+ return wc;
+ }
+ };
+#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text)
+
+ inline std::string string_converter(const std::string& w) NOEXCEPT
+ {
+ return w;
+ }
+
+ // utility wrapper to adapt locale-bound facets for wstring/wbuffer convert
+ // from cppreference
+ template <class Facet>
+ struct deletable_facet : Facet
+ {
+ template <class... Args>
+ deletable_facet(Args&&... args) : Facet(std::forward<Args>(args)...)
+ {}
+ ~deletable_facet() {}
+ };
+
+ inline std::string string_converter(const std::wstring& w) // todo: use us-locale
+ {
+ std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>>
+ conv1;
+ return conv1.to_bytes(w);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Writer helper functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ template <typename charT>
+ class tabs
+ {
+ const size_t t;
+
+ public:
+ explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {}
+ std::basic_string<charT> print() const
+ {
+ return std::basic_string<charT>(t, TYTI_L(charT, '\t'));
+ }
+ inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT { return tabs(t + i); }
+ };
+
+ template <typename oStreamT>
+ oStreamT& operator<<(oStreamT& s, const tabs<typename oStreamT::char_type> t)
+ {
+ s << t.print();
+ return s;
+ }
+ } // end namespace detail
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Interface
+ ///////////////////////////////////////////////////////////////////////////
+
+ /// custom objects and their corresponding write functions
+
+ /// basic object node. Every object has a name and can contains attributes saved as
+ /// key_value pairs or childrens
+ template <typename CharT>
+ struct basic_object
+ {
+ typedef CharT char_type;
+ std::basic_string<char_type> name;
+ std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type>>
+ attribs;
+ std::unordered_map<std::basic_string<char_type>,
+ std::shared_ptr<basic_object<char_type>>>
+ childs;
+
+ void add_attribute(std::basic_string<char_type> key,
+ std::basic_string<char_type> value)
+ {
+ attribs.emplace(std::move(key), std::move(value));
+ }
+ void add_child(std::unique_ptr<basic_object<char_type>> child)
+ {
+ std::shared_ptr<basic_object<char_type>> obj{child.release()};
+ childs.emplace(obj->name, obj);
+ }
+ void set_name(std::basic_string<char_type> n) { name = std::move(n); }
+ };
+
+ template <typename CharT>
+ struct basic_multikey_object
+ {
+ typedef CharT char_type;
+ std::basic_string<char_type> name;
+ std::unordered_multimap<std::basic_string<char_type>, std::basic_string<char_type>>
+ attribs;
+ std::unordered_multimap<std::basic_string<char_type>,
+ std::shared_ptr<basic_multikey_object<char_type>>>
+ childs;
+
+ void add_attribute(std::basic_string<char_type> key,
+ std::basic_string<char_type> value)
+ {
+ attribs.emplace(std::move(key), std::move(value));
+ }
+ void add_child(std::unique_ptr<basic_multikey_object<char_type>> child)
+ {
+ std::shared_ptr<basic_multikey_object<char_type>> obj{child.release()};
+ childs.emplace(obj->name, obj);
+ }
+ void set_name(std::basic_string<char_type> n) { name = std::move(n); }
+ };
+
+ typedef basic_object<char> object;
+ typedef basic_object<wchar_t> wobject;
+ typedef basic_multikey_object<char> multikey_object;
+ typedef basic_multikey_object<wchar_t> wmultikey_object;
+
+ struct Options
+ {
+ bool strip_escape_symbols;
+ bool ignore_all_platform_conditionals;
+ bool ignore_includes;
+
+ Options()
+ : strip_escape_symbols(true), ignore_all_platform_conditionals(false),
+ ignore_includes(false)
+ {}
+ };
+
+ // forward decls
+ // forward decl
+ template <typename OutputT, typename iStreamT>
+ OutputT read(iStreamT& inStream, const Options& opt = Options{});
+
+ /** \brief writes given object tree in vdf format to given stream.
+ Output is prettyfied, using tabs
+ */
+ template <typename oStreamT, typename T>
+ void write(oStreamT& s, const T& r,
+ const detail::tabs<typename oStreamT::char_type> tab =
+ detail::tabs<typename oStreamT::char_type>(0))
+ {
+ typedef typename oStreamT::char_type charT;
+ using namespace detail;
+ s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab
+ << TYTI_L(charT, "{\n");
+ for (const auto& i : r.attribs)
+ s << tab + 1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"")
+ << i.second << TYTI_L(charT, "\"\n");
+ for (const auto& i : r.childs)
+ if (i.second)
+ write(s, *i.second, tab + 1);
+ s << tab << TYTI_L(charT, "}\n");
+ }
+
+ namespace detail
+ {
+ template <typename iStreamT>
+ std::basic_string<typename iStreamT::char_type> read_file(iStreamT& inStream)
+ {
+ // cache the file
+ typedef typename iStreamT::char_type charT;
+ std::basic_string<charT> str;
+ inStream.seekg(0, std::ios::end);
+ str.resize(static_cast<size_t>(inStream.tellg()));
+ if (str.empty())
+ return str;
+
+ inStream.seekg(0, std::ios::beg);
+ inStream.read(&str[0], str.size());
+ return str;
+ }
+
+ /** \brief Read VDF formatted sequences defined by the range [first, last).
+ If the file is mailformatted, parser will try to read it until it can.
+ @param first begin iterator
+ @param end end iterator
+ @param exclude_files list of files which cant be included anymore.
+ prevents circular includes
+
+ can thow:
+ - "std::runtime_error" if a parsing error occured
+ - "std::bad_alloc" if not enough memory coup be allocated
+ */
+ template <typename OutputT, typename IterT>
+ std::vector<std::unique_ptr<OutputT>>
+ read_internal(IterT first, const IterT last,
+ std::unordered_set<std::basic_string<
+ typename std::iterator_traits<IterT>::value_type>>& exclude_files,
+ const Options& opt)
+ {
+ static_assert(std::is_default_constructible<OutputT>::value,
+ "Output Type must be default constructible (provide constructor "
+ "without arguments)");
+ static_assert(std::is_move_constructible<OutputT>::value,
+ "Output Type must be move constructible");
+
+ typedef typename std::iterator_traits<IterT>::value_type charT;
+
+ const std::basic_string<charT> comment_end_str = TYTI_L(charT, "*/");
+ const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t");
+
+#ifdef WIN32
+ std::function<bool(const std::basic_string<charT>&)> is_platform_str =
+ [](const std::basic_string<charT>& in) {
+ return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS");
+ };
+#elif __APPLE__
+ // WIN32 stands for pc in general
+ std::function<bool(const std::basic_string<charT>&)> is_platform_str =
+ [](const std::basic_string<charT>& in) {
+ return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") ||
+ in == TYTI_L(charT, "$OSX");
+ };
+
+#elif __linux__
+ // WIN32 stands for pc in general
+ std::function<bool(const std::basic_string<charT>&)> is_platform_str =
+ [](const std::basic_string<charT>& in) {
+ return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") ||
+ in == TYTI_L(charT, "$LINUX");
+ };
+#else
+ std::function<bool(const std::basic_string<charT>&)> is_platform_str =
+ [](const std::basic_string<charT>& in) {
+ return false;
+ };
+#endif
+
+ if (opt.ignore_all_platform_conditionals)
+ is_platform_str = [](const std::basic_string<charT>&) {
+ return false;
+ };
+
+ // function for skipping a comment block
+ // iter: iterator poition to the position after a '/'
+ auto skip_comments = [&comment_end_str](IterT iter, const IterT& last) -> IterT {
+ ++iter;
+ if (iter != last) {
+ if (*iter == TYTI_L(charT, '/')) {
+ // line comment, skip whole line
+ iter = std::find(iter + 1, last, TYTI_L(charT, '\n'));
+ }
+
+ if (*iter == '*') {
+ // block comment, skip until next occurance of "*\"
+ iter = std::search(iter + 1, last, std::begin(comment_end_str),
+ std::end(comment_end_str));
+ iter += 2;
+ }
+ }
+ return iter;
+ };
+
+ auto end_quote = [](IterT iter, const IterT& last) -> IterT {
+ const auto begin = iter;
+ auto last_esc = iter;
+ do {
+ ++iter;
+ iter = std::find(iter, last, TYTI_L(charT, '\"'));
+ if (iter == last)
+ break;
+
+ last_esc = std::prev(iter);
+ while (last_esc != begin && *last_esc == '\\')
+ --last_esc;
+ } while (!(std::distance(last_esc, iter) % 2));
+ if (iter == last)
+ throw std::runtime_error{"quote was opened but not closed."};
+ return iter;
+ };
+
+ auto end_word = [&whitespaces](IterT iter, const IterT& last) -> IterT {
+ const auto begin = iter;
+ auto last_esc = iter;
+ do {
+ ++iter;
+ iter = std::find_first_of(iter, last, std::begin(whitespaces),
+ std::end(whitespaces));
+ if (iter == last)
+ break;
+
+ last_esc = std::prev(iter);
+ while (last_esc != begin && *last_esc == '\\')
+ --last_esc;
+ } while (!(std::distance(last_esc, iter) % 2));
+ // if (iter == last)
+ // throw std::runtime_error{ "word wasnt properly ended" };
+ return iter;
+ };
+
+ auto skip_whitespaces = [&whitespaces](IterT iter, const IterT& last) -> IterT {
+ iter = std::find_if_not(iter, last, [&whitespaces](charT c) {
+ // return true if whitespace
+ return std::any_of(std::begin(whitespaces), std::end(whitespaces),
+ [c](charT pc) {
+ return pc == c;
+ });
+ });
+ return iter;
+ };
+
+ std::function<void(std::basic_string<charT>&)> strip_escape_symbols =
+ [](std::basic_string<charT>& s) {
+ auto quote_searcher = [&s](size_t pos) {
+ return s.find(TYTI_L(charT, "\\\""), pos);
+ };
+ auto p = quote_searcher(0);
+ while (p != s.npos) {
+ s.replace(p, 2, TYTI_L(charT, "\""));
+ p = quote_searcher(p);
+ }
+ auto searcher = [&s](size_t pos) {
+ return s.find(TYTI_L(charT, "\\\\"), pos);
+ };
+ p = searcher(0);
+ while (p != s.npos) {
+ s.replace(p, 2, TYTI_L(charT, "\\"));
+ p = searcher(p);
+ }
+ };
+
+ if (!opt.strip_escape_symbols)
+ strip_escape_symbols = [](std::basic_string<charT>&) {};
+
+ auto conditional_fullfilled = [&skip_whitespaces,
+ &is_platform_str](IterT& iter, const IterT& last) {
+ iter = skip_whitespaces(iter, last);
+ if (*iter == '[') {
+ ++iter;
+ const auto end = std::find(iter, last, ']');
+ const bool negate = *iter == '!';
+ if (negate)
+ ++iter;
+ auto conditional = std::basic_string<charT>(iter, end);
+
+ const bool is_platform = is_platform_str(conditional);
+ iter = end + 1;
+
+ return static_cast<bool>(is_platform ^ negate);
+ }
+ return true;
+ };
+
+ // read header
+ // first, quoted name
+ std::unique_ptr<OutputT> curObj = nullptr;
+ std::vector<std::unique_ptr<OutputT>> roots;
+ std::stack<std::unique_ptr<OutputT>> lvls;
+ auto curIter = first;
+
+ while (curIter != last && *curIter != '\0') {
+ // find first starting attrib/child, or ending
+ curIter = skip_whitespaces(curIter, last);
+ if (curIter == last || *curIter == '\0')
+ break;
+ if (*curIter == TYTI_L(charT, '/')) {
+ curIter = skip_comments(curIter, last);
+ } else if (*curIter != TYTI_L(charT, '}')) {
+
+ // get key
+ const auto keyEnd = (*curIter == TYTI_L(charT, '\"'))
+ ? end_quote(curIter, last)
+ : end_word(curIter, last);
+ if (*curIter == TYTI_L(charT, '\"'))
+ ++curIter;
+ std::basic_string<charT> key(curIter, keyEnd);
+ strip_escape_symbols(key);
+ curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0);
+
+ curIter = skip_whitespaces(curIter, last);
+
+ auto conditional = conditional_fullfilled(curIter, last);
+ if (!conditional)
+ continue;
+
+ while (*curIter == TYTI_L(charT, '/')) {
+
+ curIter = skip_comments(curIter, last);
+ if (curIter == last || *curIter == '}')
+ throw std::runtime_error{"key declared, but no value"};
+ curIter = skip_whitespaces(curIter, last);
+ if (curIter == last || *curIter == '}')
+ throw std::runtime_error{"key declared, but no value"};
+ }
+ // get value
+ if (*curIter != '{') {
+ const auto valueEnd = (*curIter == TYTI_L(charT, '\"'))
+ ? end_quote(curIter, last)
+ : end_word(curIter, last);
+ if (*curIter == TYTI_L(charT, '\"'))
+ ++curIter;
+
+ auto value = std::basic_string<charT>(curIter, valueEnd);
+ strip_escape_symbols(value);
+ curIter = valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0);
+
+ auto conditional = conditional_fullfilled(curIter, last);
+ if (!conditional)
+ continue;
+
+ // process value
+ if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base")) {
+ if (curObj) {
+ curObj->add_attribute(std::move(key), std::move(value));
+ } else {
+ throw std::runtime_error{"unexpected key without object"};
+ }
+ } else {
+ if (!opt.ignore_includes &&
+ exclude_files.find(value) == exclude_files.end()) {
+ exclude_files.insert(value);
+ std::basic_ifstream<charT> i(detail::string_converter(value));
+ auto str = read_file(i);
+ auto file_objs =
+ read_internal<OutputT>(str.begin(), str.end(), exclude_files, opt);
+ for (auto& n : file_objs) {
+ if (curObj)
+ curObj->add_child(std::move(n));
+ else
+ roots.push_back(std::move(n));
+ }
+ exclude_files.erase(value);
+ }
+ }
+ } else if (*curIter == '{') {
+ if (curObj)
+ lvls.push(std::move(curObj));
+ curObj = std::make_unique<OutputT>();
+ curObj->set_name(std::move(key));
+ ++curIter;
+ }
+ }
+ // end of new object
+ else if (curObj && *curIter == TYTI_L(charT, '}')) {
+ if (!lvls.empty()) {
+ // get object before
+ std::unique_ptr<OutputT> prev{std::move(lvls.top())};
+ lvls.pop();
+
+ // add finished obj to obj before and release it from processing
+ prev->add_child(std::move(curObj));
+ curObj = std::move(prev);
+ } else {
+ roots.push_back(std::move(curObj));
+ curObj.reset();
+ }
+ ++curIter;
+ } else {
+ throw std::runtime_error{"unexpected '}'"};
+ }
+ }
+ if (curObj != nullptr || !lvls.empty()) {
+ throw std::runtime_error{"object is not closed with '}'"};
+ }
+
+ return roots;
+ }
+
+ } // namespace detail
+
+ /** \brief Read VDF formatted sequences defined by the range [first, last).
+ If the file is mailformatted, parser will try to read it until it can.
+ @param first begin iterator
+ @param end end iterator
+
+ can thow:
+ - "std::runtime_error" if a parsing error occured
+ - "std::bad_alloc" if not enough memory coup be allocated
+ */
+ template <typename OutputT, typename IterT>
+ OutputT read(IterT first, const IterT last, const Options& opt = Options{})
+ {
+ auto exclude_files = std::unordered_set<
+ std::basic_string<typename std::iterator_traits<IterT>::value_type>>{};
+ auto roots = detail::read_internal<OutputT>(first, last, exclude_files, opt);
+
+ OutputT result;
+ if (roots.size() > 1) {
+ for (auto& i : roots)
+ result.add_child(std::move(i));
+ } else if (roots.size() == 1)
+ result = std::move(*roots[0]);
+
+ return result;
+ }
+
+ /** \brief Read VDF formatted sequences defined by the range [first, last).
+ If the file is mailformatted, parser will try to read it until it can.
+ @param first begin iterator
+ @param end end iterator
+ @param ec output bool. 0 if ok, otherwise, holds an system error code
+
+ Possible error codes:
+ std::errc::protocol_error: file is mailformatted
+ std::errc::not_enough_memory: not enough space
+ std::errc::invalid_argument: iterators throws e.g. out of range
+ */
+ template <typename OutputT, typename IterT>
+ OutputT read(IterT first, IterT last, std::error_code& ec,
+ const Options& opt = Options{}) NOEXCEPT
+
+ {
+ ec.clear();
+ OutputT r{};
+ try {
+ r = read<OutputT>(first, last, opt);
+ } catch (std::runtime_error&) {
+ ec = std::make_error_code(std::errc::protocol_error);
+ } catch (std::bad_alloc&) {
+ ec = std::make_error_code(std::errc::not_enough_memory);
+ } catch (...) {
+ ec = std::make_error_code(std::errc::invalid_argument);
+ }
+ return r;
+ }
+
+ /** \brief Read VDF formatted sequences defined by the range [first, last).
+ If the file is mailformatted, parser will try to read it until it can.
+ @param first begin iterator
+ @param end end iterator
+ @param ok output bool. true, if parser successed, false, if parser failed
+ */
+ template <typename OutputT, typename IterT>
+ OutputT read(IterT first, const IterT last, bool* ok,
+ const Options& opt = Options{}) NOEXCEPT
+ {
+ std::error_code ec;
+ auto r = read<OutputT>(first, last, ec, opt);
+ if (ok)
+ *ok = !ec;
+ return r;
+ }
+
+ template <typename IterT>
+ inline auto read(IterT first, const IterT last, bool* ok,
+ const Options& opt = Options{}) NOEXCEPT
+ ->basic_object<typename std::iterator_traits<IterT>::value_type>
+ {
+ return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
+ first, last, ok, opt);
+ }
+
+ template <typename IterT>
+ inline auto read(IterT first, IterT last, std::error_code& ec,
+ const Options& opt = Options{}) NOEXCEPT
+ ->basic_object<typename std::iterator_traits<IterT>::value_type>
+ {
+ return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
+ first, last, ec, opt);
+ }
+
+ template <typename IterT>
+ inline auto read(IterT first, const IterT last, const Options& opt = Options{})
+ -> basic_object<typename std::iterator_traits<IterT>::value_type>
+ {
+ return read<basic_object<typename std::iterator_traits<IterT>::value_type>>(
+ first, last, opt);
+ }
+
+ /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
+ formatted data. throws "std::bad_alloc" if file buffer could not be allocated
+ */
+ template <typename OutputT, typename iStreamT>
+ OutputT read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
+ {
+ // cache the file
+ typedef typename iStreamT::char_type charT;
+ std::basic_string<charT> str = detail::read_file(inStream);
+
+ // parse it
+ return read<OutputT>(str.begin(), str.end(), ec, opt);
+ }
+
+ template <typename iStreamT>
+ inline basic_object<typename iStreamT::char_type>
+ read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{})
+ {
+ return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt);
+ }
+
+ /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
+ formatted data. throws "std::bad_alloc" if file buffer could not be allocated ok ==
+ false, if a parsing error occured
+ */
+ template <typename OutputT, typename iStreamT>
+ OutputT read(iStreamT& inStream, bool* ok, const Options& opt = Options{})
+ {
+ std::error_code ec;
+ const auto r = read<OutputT>(inStream, ec, opt);
+ if (ok)
+ *ok = !ec;
+ return r;
+ }
+
+ template <typename iStreamT>
+ inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok,
+ const Options& opt = Options{})
+ {
+ return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt);
+ }
+
+ /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf
+ formatted data. throws "std::bad_alloc" if file buffer could not be allocated
+ throws "std::runtime_error" if a parsing error occured
+ */
+ template <typename OutputT, typename iStreamT>
+ OutputT read(iStreamT& inStream, const Options& opt)
+ {
+
+ // cache the file
+ typedef typename iStreamT::char_type charT;
+ std::basic_string<charT> str = detail::read_file(inStream);
+ // parse it
+ return read<OutputT>(str.begin(), str.end(), opt);
+ }
+
+ template <typename iStreamT>
+ inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream,
+ const Options& opt = Options{})
+ {
+ return read<basic_object<typename iStreamT::char_type>>(inStream, opt);
+ }
+
+} // namespace vdf
+} // namespace tyti
+#ifndef TYTI_NO_L_UNDEF
+#undef TYTI_L
+#endif
+
+#ifdef TYTI_UNDEF_CONSTEXPR
+#undef CONSTEXPR
+#undef TYTI_NO_L_UNDEF
+#endif
+
+#ifdef TYTI_UNDEF_NOTHROW
+#undef NOTHROW
+#undef TYTI_UNDEF_NOTHROW
+#endif
+
+#endif //__TYTI_STEAM_VDF_PARSER_H__