The open source OpenXR runtime
at mr/scanout-values 824 lines 27 kB view raw
1// MIT License 2// 3// Copyright(c) 2016 Matthias Moeller 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files(the "Software"), to deal 7// in the Software without restriction, including without limitation the rights 8// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 9// copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions : 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21// SOFTWARE. 22 23#ifndef __TYTI_STEAM_VDF_PARSER_H__ 24#define __TYTI_STEAM_VDF_PARSER_H__ 25 26#include <algorithm> 27#include <fstream> 28#include <functional> 29#include <iterator> 30#include <map> 31#include <memory> 32#include <unordered_map> 33#include <unordered_set> 34#include <utility> 35#include <vector> 36 37#include <exception> 38#include <system_error> 39 40// for wstring support 41#include <locale> 42#include <string> 43 44// internal 45#include <stack> 46 47// VS < 2015 has only partial C++11 support 48#if defined(_MSC_VER) && _MSC_VER < 1900 49#ifndef CONSTEXPR 50#define CONSTEXPR 51#endif 52 53#ifndef NOEXCEPT 54#define NOEXCEPT 55#endif 56#else 57#ifndef CONSTEXPR 58#define CONSTEXPR constexpr 59#define TYTI_UNDEF_CONSTEXPR 60#endif 61 62#ifndef NOEXCEPT 63#define NOEXCEPT noexcept 64#define TYTI_UNDEF_NOEXCEPT 65#endif 66 67#endif 68 69namespace tyti 70{ 71namespace vdf 72{ 73namespace detail 74{ 75/////////////////////////////////////////////////////////////////////////// 76// Helper functions selecting the right encoding (char/wchar_T) 77/////////////////////////////////////////////////////////////////////////// 78 79template <typename T> struct literal_macro_help 80{ 81 static CONSTEXPR const char *result(const char *c, const wchar_t *) NOEXCEPT 82 { 83 return c; 84 } 85 static CONSTEXPR const char result(const char c, const wchar_t) NOEXCEPT 86 { 87 return c; 88 } 89}; 90 91template <> struct literal_macro_help<wchar_t> 92{ 93 static CONSTEXPR const wchar_t *result(const char *, 94 const wchar_t *wc) NOEXCEPT 95 { 96 return wc; 97 } 98 static CONSTEXPR const wchar_t result(const char, const wchar_t wc) NOEXCEPT 99 { 100 return wc; 101 } 102}; 103#define TYTI_L(type, text) \ 104 vdf::detail::literal_macro_help<type>::result(text, L##text) 105 106inline std::string string_converter(const std::string &w) NOEXCEPT { return w; } 107 108// utility wrapper to adapt locale-bound facets for wstring/wbuffer convert 109// from cppreference 110template <class Facet> struct deletable_facet : Facet 111{ 112 template <class... Args> 113 deletable_facet(Args &&...args) : Facet(std::forward<Args>(args)...) 114 { 115 } 116 ~deletable_facet() {} 117}; 118 119inline std::string 120string_converter(const std::wstring &w) // todo: use us-locale 121{ 122 std::wstring_convert< 123 deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> 124 conv1; 125 return conv1.to_bytes(w); 126} 127 128/////////////////////////////////////////////////////////////////////////// 129// Writer helper functions 130/////////////////////////////////////////////////////////////////////////// 131 132template <typename charT> class tabs 133{ 134 const size_t t; 135 136 public: 137 explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {} 138 std::basic_string<charT> print() const 139 { 140 return std::basic_string<charT>(t, TYTI_L(charT, '\t')); 141 } 142 inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT 143 { 144 return tabs(t + i); 145 } 146}; 147 148template <typename oStreamT> 149oStreamT &operator<<(oStreamT &s, const tabs<typename oStreamT::char_type> t) 150{ 151 s << t.print(); 152 return s; 153} 154} // end namespace detail 155 156/////////////////////////////////////////////////////////////////////////// 157// Interface 158/////////////////////////////////////////////////////////////////////////// 159 160/// custom objects and their corresponding write functions 161 162/// basic object node. Every object has a name and can contains attributes saved 163/// as key_value pairs or childrens 164template <typename CharT> struct basic_object 165{ 166 typedef CharT char_type; 167 std::basic_string<char_type> name; 168 std::unordered_map<std::basic_string<char_type>, 169 std::basic_string<char_type>> 170 attribs; 171 std::unordered_map<std::basic_string<char_type>, 172 std::shared_ptr<basic_object<char_type>>> 173 childs; 174 175 void add_attribute(std::basic_string<char_type> key, 176 std::basic_string<char_type> value) 177 { 178 attribs.emplace(std::move(key), std::move(value)); 179 } 180 void add_child(std::unique_ptr<basic_object<char_type>> child) 181 { 182 std::shared_ptr<basic_object<char_type>> obj{child.release()}; 183 childs.emplace(obj->name, obj); 184 } 185 void set_name(std::basic_string<char_type> n) { name = std::move(n); } 186}; 187 188template <typename CharT> struct basic_multikey_object 189{ 190 typedef CharT char_type; 191 std::basic_string<char_type> name; 192 std::unordered_multimap<std::basic_string<char_type>, 193 std::basic_string<char_type>> 194 attribs; 195 std::unordered_multimap<std::basic_string<char_type>, 196 std::shared_ptr<basic_multikey_object<char_type>>> 197 childs; 198 199 void add_attribute(std::basic_string<char_type> key, 200 std::basic_string<char_type> value) 201 { 202 attribs.emplace(std::move(key), std::move(value)); 203 } 204 void add_child(std::unique_ptr<basic_multikey_object<char_type>> child) 205 { 206 std::shared_ptr<basic_multikey_object<char_type>> obj{child.release()}; 207 childs.emplace(obj->name, obj); 208 } 209 void set_name(std::basic_string<char_type> n) { name = std::move(n); } 210}; 211 212typedef basic_object<char> object; 213typedef basic_object<wchar_t> wobject; 214typedef basic_multikey_object<char> multikey_object; 215typedef basic_multikey_object<wchar_t> wmultikey_object; 216 217struct Options 218{ 219 bool strip_escape_symbols; 220 bool ignore_all_platform_conditionals; 221 bool ignore_includes; 222 223 Options() 224 : strip_escape_symbols(true), ignore_all_platform_conditionals(false), 225 ignore_includes(false) 226 { 227 } 228}; 229 230// forward decls 231// forward decl 232template <typename OutputT, typename iStreamT> 233OutputT read(iStreamT &inStream, const Options &opt = Options{}); 234 235/** \brief writes given object tree in vdf format to given stream. 236Output is prettyfied, using tabs 237*/ 238template <typename oStreamT, typename T> 239void write(oStreamT &s, const T &r, 240 const detail::tabs<typename oStreamT::char_type> tab = 241 detail::tabs<typename oStreamT::char_type>(0)) 242{ 243 typedef typename oStreamT::char_type charT; 244 using namespace detail; 245 s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab 246 << TYTI_L(charT, "{\n"); 247 for (const auto &i : r.attribs) 248 s << tab + 1 << TYTI_L(charT, '"') << i.first 249 << TYTI_L(charT, "\"\t\t\"") << i.second << TYTI_L(charT, "\"\n"); 250 for (const auto &i : r.childs) 251 if (i.second) 252 write(s, *i.second, tab + 1); 253 s << tab << TYTI_L(charT, "}\n"); 254} 255 256namespace detail 257{ 258template <typename iStreamT> 259std::basic_string<typename iStreamT::char_type> read_file(iStreamT &inStream) 260{ 261 // cache the file 262 typedef typename iStreamT::char_type charT; 263 std::basic_string<charT> str; 264 inStream.seekg(0, std::ios::end); 265 str.resize(static_cast<size_t>(inStream.tellg())); 266 if (str.empty()) 267 return str; 268 269 inStream.seekg(0, std::ios::beg); 270 inStream.read(&str[0], str.size()); 271 return str; 272} 273 274/** \brief Read VDF formatted sequences defined by the range [first, last). 275If the file is mailformatted, parser will try to read it until it can. 276@param first begin iterator 277@param end end iterator 278@param exclude_files list of files which cant be included anymore. 279 prevents circular includes 280 281can thow: 282 - "std::runtime_error" if a parsing error occured 283 - "std::bad_alloc" if not enough memory coup be allocated 284*/ 285template <typename OutputT, typename IterT> 286std::vector<std::unique_ptr<OutputT>> read_internal( 287 IterT first, const IterT last, 288 std::unordered_set< 289 std::basic_string<typename std::iterator_traits<IterT>::value_type>> 290 &exclude_files, 291 const Options &opt) 292{ 293 static_assert(std::is_default_constructible<OutputT>::value, 294 "Output Type must be default constructible (provide " 295 "constructor without arguments)"); 296 static_assert(std::is_move_constructible<OutputT>::value, 297 "Output Type must be move constructible"); 298 299 typedef typename std::iterator_traits<IterT>::value_type charT; 300 301 const std::basic_string<charT> comment_end_str = TYTI_L(charT, "*/"); 302 const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t"); 303 304#ifdef WIN32 305 std::function<bool(const std::basic_string<charT> &)> is_platform_str = 306 [](const std::basic_string<charT> &in) 307 { 308 return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS"); 309 }; 310#elif __APPLE__ 311 // WIN32 stands for pc in general 312 std::function<bool(const std::basic_string<charT> &)> is_platform_str = 313 [](const std::basic_string<charT> &in) 314 { 315 return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || 316 in == TYTI_L(charT, "$OSX"); 317 }; 318 319#elif __linux__ 320 // WIN32 stands for pc in general 321 std::function<bool(const std::basic_string<charT> &)> is_platform_str = 322 [](const std::basic_string<charT> &in) 323 { 324 return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || 325 in == TYTI_L(charT, "$LINUX"); 326 }; 327#else 328 std::function<bool(const std::basic_string<charT> &)> is_platform_str = 329 [](const std::basic_string<charT> &in) { return false; }; 330#endif 331 332 if (opt.ignore_all_platform_conditionals) 333 is_platform_str = [](const std::basic_string<charT> &) 334 { return false; }; 335 336 // function for skipping a comment block 337 // iter: iterator poition to the position after a '/' 338 auto skip_comments = [&comment_end_str](IterT iter, 339 const IterT &last) -> IterT 340 { 341 ++iter; 342 if (iter == last) 343 return last; 344 345 if (*iter == TYTI_L(charT, '/')) 346 { 347 // line comment, skip whole line 348 iter = std::find(iter + 1, last, TYTI_L(charT, '\n')); 349 if (iter == last) 350 return last; 351 } 352 353 if (*iter == '*') 354 { 355 // block comment, skip until next occurance of "*\" 356 iter = std::search(iter + 1, last, std::begin(comment_end_str), 357 std::end(comment_end_str)); 358 if (std::distance(iter, last) <= 2) 359 return last; 360 iter += 2; 361 } 362 363 return iter; 364 }; 365 366 auto end_quote = [](IterT iter, const IterT &last) -> IterT 367 { 368 const auto begin = iter; 369 auto last_esc = iter; 370 if (iter == last) 371 throw std::runtime_error{"quote was opened but not closed."}; 372 do 373 { 374 ++iter; 375 iter = std::find(iter, last, TYTI_L(charT, '\"')); 376 if (iter == last) 377 break; 378 379 last_esc = std::prev(iter); 380 while (last_esc != begin && *last_esc == '\\') 381 --last_esc; 382 } while (!(std::distance(last_esc, iter) % 2) && iter != last); 383 if (iter == last) 384 throw std::runtime_error{"quote was opened but not closed."}; 385 return iter; 386 }; 387 388 auto end_word = [&whitespaces](IterT iter, const IterT &last) -> IterT 389 { 390 const auto begin = iter; 391 auto last_esc = iter; 392 if (iter == last) 393 throw std::runtime_error{"quote was opened but not closed."}; 394 do 395 { 396 ++iter; 397 iter = std::find_first_of(iter, last, std::begin(whitespaces), 398 std::end(whitespaces)); 399 if (iter == last) 400 break; 401 402 last_esc = std::prev(iter); 403 while (last_esc != begin && *last_esc == '\\') 404 --last_esc; 405 } while (!(std::distance(last_esc, iter) % 2) && iter != last); 406 if (iter == last) 407 throw std::runtime_error{"word wasnt properly ended"}; 408 return iter; 409 }; 410 411 auto skip_whitespaces = [&whitespaces](IterT iter, 412 const IterT &last) -> IterT 413 { 414 if (iter == last) 415 return iter; 416 iter = std::find_if_not(iter, last, 417 [&whitespaces](charT c) 418 { 419 // return true if whitespace 420 return std::any_of(std::begin(whitespaces), 421 std::end(whitespaces), 422 [c](charT pc) 423 { return pc == c; }); 424 }); 425 return iter; 426 }; 427 428 std::function<void(std::basic_string<charT> &)> strip_escape_symbols = 429 [](std::basic_string<charT> &s) 430 { 431 auto quote_searcher = [&s](size_t pos) 432 { return s.find(TYTI_L(charT, "\\\""), pos); }; 433 auto p = quote_searcher(0); 434 while (p != s.npos) 435 { 436 s.replace(p, 2, TYTI_L(charT, "\"")); 437 p = quote_searcher(p); 438 } 439 auto searcher = [&s](size_t pos) 440 { return s.find(TYTI_L(charT, "\\\\"), pos); }; 441 p = searcher(0); 442 while (p != s.npos) 443 { 444 s.replace(p, 2, TYTI_L(charT, "\\")); 445 p = searcher(p); 446 } 447 }; 448 449 if (!opt.strip_escape_symbols) 450 strip_escape_symbols = [](std::basic_string<charT> &) {}; 451 452 auto conditional_fullfilled = 453 [&skip_whitespaces, &is_platform_str](IterT &iter, const IterT &last) 454 { 455 iter = skip_whitespaces(iter, last); 456 if (iter == last) 457 return true; 458 if (*iter == '[') 459 { 460 ++iter; 461 if (iter == last) 462 throw std::runtime_error("conditional not closed"); 463 const auto end = std::find(iter, last, ']'); 464 if (end == last) 465 throw std::runtime_error("conditional not closed"); 466 const bool negate = *iter == '!'; 467 if (negate) 468 ++iter; 469 auto conditional = std::basic_string<charT>(iter, end); 470 471 const bool is_platform = is_platform_str(conditional); 472 iter = end + 1; 473 474 return static_cast<bool>(is_platform ^ negate); 475 } 476 return true; 477 }; 478 479 // read header 480 // first, quoted name 481 std::unique_ptr<OutputT> curObj = nullptr; 482 std::vector<std::unique_ptr<OutputT>> roots; 483 std::stack<std::unique_ptr<OutputT>> lvls; 484 auto curIter = first; 485 486 while (curIter != last && *curIter != '\0') 487 { 488 // find first starting attrib/child, or ending 489 curIter = skip_whitespaces(curIter, last); 490 if (curIter == last || *curIter == '\0') 491 break; 492 if (*curIter == TYTI_L(charT, '/')) 493 { 494 curIter = skip_comments(curIter, last); 495 if (curIter == last || *curIter == '\0') 496 throw std::runtime_error("Unexpected eof"); 497 } 498 else if (*curIter != TYTI_L(charT, '}')) 499 { 500 // get key 501 const auto keyEnd = (*curIter == TYTI_L(charT, '\"')) 502 ? end_quote(curIter, last) 503 : end_word(curIter, last); 504 if (*curIter == TYTI_L(charT, '\"')) 505 ++curIter; 506 std::basic_string<charT> key(curIter, keyEnd); 507 strip_escape_symbols(key); 508 curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0); 509 if (curIter == last) 510 throw std::runtime_error{"key opened, but never closed"}; 511 512 curIter = skip_whitespaces(curIter, last); 513 514 auto conditional = conditional_fullfilled(curIter, last); 515 if (!conditional) 516 continue; 517 if (curIter == last) 518 throw std::runtime_error{"key declared, but no value"}; 519 520 while (*curIter == TYTI_L(charT, '/')) 521 { 522 523 curIter = skip_comments(curIter, last); 524 if (curIter == last || *curIter == '}') 525 throw std::runtime_error{"key declared, but no value"}; 526 curIter = skip_whitespaces(curIter, last); 527 if (curIter == last || *curIter == '}') 528 throw std::runtime_error{"key declared, but no value"}; 529 } 530 // get value 531 if (*curIter != '{') 532 { 533 if (curIter == last) 534 throw std::runtime_error{"key declared, but no value"}; 535 const auto valueEnd = (*curIter == TYTI_L(charT, '\"')) 536 ? end_quote(curIter, last) 537 : end_word(curIter, last); 538 if (valueEnd == last) 539 throw std::runtime_error("No closed word"); 540 if (*curIter == TYTI_L(charT, '\"')) 541 ++curIter; 542 if (curIter == last) 543 throw std::runtime_error("No closed word"); 544 545 auto value = std::basic_string<charT>(curIter, valueEnd); 546 strip_escape_symbols(value); 547 curIter = 548 valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0); 549 550 auto conditional = conditional_fullfilled(curIter, last); 551 if (!conditional) 552 continue; 553 554 // process value 555 if (key != TYTI_L(charT, "#include") && 556 key != TYTI_L(charT, "#base")) 557 { 558 if (curObj) 559 { 560 curObj->add_attribute(std::move(key), std::move(value)); 561 } 562 else 563 { 564 throw std::runtime_error{ 565 "unexpected key without object"}; 566 } 567 } 568 else 569 { 570 if (!opt.ignore_includes && 571 exclude_files.find(value) == exclude_files.end()) 572 { 573 exclude_files.insert(value); 574 std::basic_ifstream<charT> i( 575 detail::string_converter(value)); 576 auto str = read_file(i); 577 auto file_objs = read_internal<OutputT>( 578 str.begin(), str.end(), exclude_files, opt); 579 for (auto &n : file_objs) 580 { 581 if (curObj) 582 curObj->add_child(std::move(n)); 583 else 584 roots.push_back(std::move(n)); 585 } 586 exclude_files.erase(value); 587 } 588 } 589 } 590 else if (*curIter == '{') 591 { 592 if (curObj) 593 lvls.push(std::move(curObj)); 594 curObj = std::make_unique<OutputT>(); 595 curObj->set_name(std::move(key)); 596 ++curIter; 597 } 598 } 599 // end of new object 600 else if (curObj && *curIter == TYTI_L(charT, '}')) 601 { 602 if (!lvls.empty()) 603 { 604 // get object before 605 std::unique_ptr<OutputT> prev{std::move(lvls.top())}; 606 lvls.pop(); 607 608 // add finished obj to obj before and release it from processing 609 prev->add_child(std::move(curObj)); 610 curObj = std::move(prev); 611 } 612 else 613 { 614 roots.push_back(std::move(curObj)); 615 curObj.reset(); 616 } 617 ++curIter; 618 } 619 else 620 { 621 throw std::runtime_error{"unexpected '}'"}; 622 } 623 } 624 if (curObj != nullptr || !lvls.empty()) 625 { 626 throw std::runtime_error{"object is not closed with '}'"}; 627 } 628 629 return roots; 630} 631 632} // namespace detail 633 634/** \brief Read VDF formatted sequences defined by the range [first, last). 635If the file is mailformatted, parser will try to read it until it can. 636@param first begin iterator 637@param end end iterator 638 639can thow: 640 - "std::runtime_error" if a parsing error occured 641 - "std::bad_alloc" if not enough memory coup be allocated 642*/ 643template <typename OutputT, typename IterT> 644OutputT read(IterT first, const IterT last, const Options &opt = Options{}) 645{ 646 auto exclude_files = std::unordered_set< 647 std::basic_string<typename std::iterator_traits<IterT>::value_type>>{}; 648 auto roots = 649 detail::read_internal<OutputT>(first, last, exclude_files, opt); 650 651 OutputT result; 652 if (roots.size() > 1) 653 { 654 for (auto &i : roots) 655 result.add_child(std::move(i)); 656 } 657 else if (roots.size() == 1) 658 result = std::move(*roots[0]); 659 660 return result; 661} 662 663/** \brief Read VDF formatted sequences defined by the range [first, last). 664If the file is mailformatted, parser will try to read it until it can. 665@param first begin iterator 666@param end end iterator 667@param ec output bool. 0 if ok, otherwise, holds an system error code 668 669Possible error codes: 670std::errc::protocol_error: file is mailformatted 671std::errc::not_enough_memory: not enough space 672std::errc::invalid_argument: iterators throws e.g. out of range 673*/ 674template <typename OutputT, typename IterT> 675OutputT read(IterT first, IterT last, std::error_code &ec, 676 const Options &opt = Options{}) NOEXCEPT 677 678{ 679 ec.clear(); 680 OutputT r{}; 681 try 682 { 683 r = read<OutputT>(first, last, opt); 684 } 685 catch (std::runtime_error &) 686 { 687 ec = std::make_error_code(std::errc::protocol_error); 688 } 689 catch (std::bad_alloc &) 690 { 691 ec = std::make_error_code(std::errc::not_enough_memory); 692 } 693 catch (...) 694 { 695 ec = std::make_error_code(std::errc::invalid_argument); 696 } 697 return r; 698} 699 700/** \brief Read VDF formatted sequences defined by the range [first, last). 701If the file is mailformatted, parser will try to read it until it can. 702@param first begin iterator 703@param end end iterator 704@param ok output bool. true, if parser successed, false, if parser failed 705*/ 706template <typename OutputT, typename IterT> 707OutputT read(IterT first, const IterT last, bool *ok, 708 const Options &opt = Options{}) NOEXCEPT 709{ 710 std::error_code ec; 711 auto r = read<OutputT>(first, last, ec, opt); 712 if (ok) 713 *ok = !ec; 714 return r; 715} 716 717template <typename IterT> 718inline auto read(IterT first, const IterT last, bool *ok, 719 const Options &opt = Options{}) NOEXCEPT 720 ->basic_object<typename std::iterator_traits<IterT>::value_type> 721{ 722 return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( 723 first, last, ok, opt); 724} 725 726template <typename IterT> 727inline auto read(IterT first, IterT last, std::error_code &ec, 728 const Options &opt = Options{}) NOEXCEPT 729 ->basic_object<typename std::iterator_traits<IterT>::value_type> 730{ 731 return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( 732 first, last, ec, opt); 733} 734 735template <typename IterT> 736inline auto read(IterT first, const IterT last, const Options &opt = Options{}) 737 -> basic_object<typename std::iterator_traits<IterT>::value_type> 738{ 739 return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( 740 first, last, opt); 741} 742 743/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf 744 formatted data. throws "std::bad_alloc" if file buffer could not be allocated 745*/ 746template <typename OutputT, typename iStreamT> 747OutputT read(iStreamT &inStream, std::error_code &ec, 748 const Options &opt = Options{}) 749{ 750 // cache the file 751 typedef typename iStreamT::char_type charT; 752 std::basic_string<charT> str = detail::read_file(inStream); 753 754 // parse it 755 return read<OutputT>(str.begin(), str.end(), ec, opt); 756} 757 758template <typename iStreamT> 759inline basic_object<typename iStreamT::char_type> 760read(iStreamT &inStream, std::error_code &ec, const Options &opt = Options{}) 761{ 762 return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt); 763} 764 765/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf 766 formatted data. throws "std::bad_alloc" if file buffer could not be allocated 767 ok == false, if a parsing error occured 768*/ 769template <typename OutputT, typename iStreamT> 770OutputT read(iStreamT &inStream, bool *ok, const Options &opt = Options{}) 771{ 772 std::error_code ec; 773 const auto r = read<OutputT>(inStream, ec, opt); 774 if (ok) 775 *ok = !ec; 776 return r; 777} 778 779template <typename iStreamT> 780inline basic_object<typename iStreamT::char_type> 781read(iStreamT &inStream, bool *ok, const Options &opt = Options{}) 782{ 783 return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt); 784} 785 786/** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf 787 formatted data. throws "std::bad_alloc" if file buffer could not be allocated 788 throws "std::runtime_error" if a parsing error occured 789*/ 790template <typename OutputT, typename iStreamT> 791OutputT read(iStreamT &inStream, const Options &opt) 792{ 793 794 // cache the file 795 typedef typename iStreamT::char_type charT; 796 std::basic_string<charT> str = detail::read_file(inStream); 797 // parse it 798 return read<OutputT>(str.begin(), str.end(), opt); 799} 800 801template <typename iStreamT> 802inline basic_object<typename iStreamT::char_type> 803read(iStreamT &inStream, const Options &opt = Options{}) 804{ 805 return read<basic_object<typename iStreamT::char_type>>(inStream, opt); 806} 807 808} // namespace vdf 809} // namespace tyti 810#ifndef TYTI_NO_L_UNDEF 811#undef TYTI_L 812#endif 813 814#ifdef TYTI_UNDEF_CONSTEXPR 815#undef CONSTEXPR 816#undef TYTI_NO_L_UNDEF 817#endif 818 819#ifdef TYTI_UNDEF_NOTHROW 820#undef NOTHROW 821#undef TYTI_UNDEF_NOTHROW 822#endif 823 824#endif //__TYTI_STEAM_VDF_PARSER_H__