/* =========================================================================== Copyright (C) 2000 - 2013, Raven Software, Inc. Copyright (C) 2001 - 2013, Activision, Inc. Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . =========================================================================== */ // Filename:- genericparser2.h #include #include #include #include #include "qcommon/safe/gsl.h" #include "qcommon/safe/memory.h" #include "qcommon/safe/files.h" #include "qcommon/safe/string.h" #ifndef GENERICPARSER2_H #define GENERICPARSER2_H namespace GP2 { template< typename T > using Vector = std::vector< T, Zone::Allocator< T, TAG_GP2 > >; } class CGPProperty { public: using Values = GP2::Vector< gsl::cstring_view >; private: gsl::cstring_view mKey; Values mValues; public: CGPProperty( gsl::cstring_view initKey, gsl::cstring_view initValue = {} ); const gsl::cstring_view& GetName() const { return mKey; } bool IsList() const NOEXCEPT { return mValues.size() > 1; } const gsl::cstring_view& GetTopValue() const NOEXCEPT { static gsl::cstring_view empty{}; return mValues.empty() ? empty : mValues.front(); } const Values& GetValues() const NOEXCEPT { return mValues; } void AddValue( gsl::cstring_view newValue ); }; class CGPGroup { public: /// Key-Value-Pairs using Properties = GP2::Vector< CGPProperty >; using SubGroups = GP2::Vector< CGPGroup >; private: Properties mProperties; gsl::cstring_view mName = CSTRING_VIEW( "Top Level" ); SubGroups mSubGroups; public: CGPGroup() = default; CGPGroup( const gsl::cstring_view& initName ); // non-copyable; but just for performance reasons, since it would incur a deep copy. CGPGroup( const CGPGroup& ) = delete; CGPGroup& operator=( const CGPGroup& ) = delete; // movable #if defined( _MSC_VER ) && _MSC_VER < 1900 // alas no default move constructors on VS2013. // TODO DELETEME once we drop VS2013 (because fuck that). CGPGroup( CGPGroup&& rhs ) : mProperties( std::move( rhs.mProperties ) ) , mName( std::move( rhs.mName ) ) , mSubGroups( std::move( rhs.mSubGroups ) ) { } CGPGroup& operator=( CGPGroup&& rhs ) { mProperties = std::move( rhs.mProperties ); mName = std::move( rhs.mName ); mSubGroups = std::move( rhs.mSubGroups ); return *this; } #else CGPGroup( CGPGroup&& ) = default; CGPGroup& operator=( CGPGroup&& ) = default; #endif const Properties& GetProperties() const NOEXCEPT { return mProperties; } const SubGroups& GetSubGroups() const NOEXCEPT { return mSubGroups; } const CGPGroup* FindSubGroup( const gsl::cstring_view& name ) const NOEXCEPT { for( auto& sub : GetSubGroups() ) { if( Q::stricmp( name, sub.GetName() ) == Q::Ordering::EQ ) { return ⊂ } } return nullptr; } const CGPProperty* FindProperty( const gsl::cstring_view& name ) const NOEXCEPT { for( auto& prop : GetProperties() ) { if( Q::stricmp( name, prop.GetName() ) == Q::Ordering::EQ ) { return ∝ } } return nullptr; } const gsl::cstring_view& GetName() const NOEXCEPT { return mName; } void Clear() NOEXCEPT { // name is retained mProperties.clear(); mSubGroups.clear(); } bool Parse( gsl::cstring_view& data, const bool topLevel = true ); }; /** Generic Text Parser. Used to parse effect files and the dynamic music system files. Parses blocks of the form `name { \n ... \n }`; blocks can contain other blocks or properties of the form `key value`. Value can also be a list; in that case the format is `key [\n value1 \n value2\n]`. Mind the separating newlines, values are actually newline-delimited. */ class CGenericParser2 { private: CGPGroup mTopLevel; FS::FileBuffer mFileContent; public: const CGPGroup& GetBaseParseGroup() { return mTopLevel; } bool Parse( gsl::czstring filename ); void Clear() NOEXCEPT; bool ValidFile() const NOEXCEPT { return mFileContent.valid(); } }; #endif // #ifndef GENERICPARSER2_H //////////////////// eof /////////////////////