1 /* 2 =========================================================================== 3 Copyright (C) 2000 - 2013, Raven Software, Inc. 4 Copyright (C) 2001 - 2013, Activision, Inc. 5 Copyright (C) 2013 - 2015, OpenJK contributors 6 7 This file is part of the OpenJK source code. 8 9 OpenJK is free software; you can redistribute it and/or modify it 10 under the terms of the GNU General Public License version 2 as 11 published by the Free Software Foundation. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, see <http://www.gnu.org/licenses/>. 20 =========================================================================== 21 */ 22 23 // Filename:- genericparser2.h 24 25 #include <vector> 26 #include <forward_list> 27 #include <array> 28 #include <cassert> 29 30 #include "qcommon/safe/gsl.h" 31 #include "qcommon/safe/memory.h" 32 #include "qcommon/safe/files.h" 33 #include "qcommon/safe/string.h" 34 35 #ifndef GENERICPARSER2_H 36 #define GENERICPARSER2_H 37 38 namespace GP2 39 { 40 template< typename T > 41 using Vector = std::vector< T, Zone::Allocator< T, TAG_GP2 > >; 42 } 43 44 class CGPProperty 45 { 46 public: 47 using Values = GP2::Vector< gsl::cstring_view >; 48 private: 49 gsl::cstring_view mKey; 50 Values mValues; 51 52 53 public: 54 55 CGPProperty( gsl::cstring_view initKey, gsl::cstring_view initValue = {} ); 56 GetName()57 const gsl::cstring_view& GetName() const { return mKey; } IsList()58 bool IsList() const NOEXCEPT 59 { 60 return mValues.size() > 1; 61 } GetTopValue()62 const gsl::cstring_view& GetTopValue() const NOEXCEPT 63 { 64 static gsl::cstring_view empty{}; 65 return mValues.empty() ? empty : mValues.front(); 66 } GetValues()67 const Values& GetValues() const NOEXCEPT 68 { 69 return mValues; 70 } 71 void AddValue( gsl::cstring_view newValue ); 72 }; 73 74 75 76 class CGPGroup 77 { 78 public: 79 /// Key-Value-Pairs 80 using Properties = GP2::Vector< CGPProperty >; 81 using SubGroups = GP2::Vector< CGPGroup >; 82 private: 83 Properties mProperties; 84 gsl::cstring_view mName = CSTRING_VIEW( "Top Level" ); 85 SubGroups mSubGroups; 86 public: 87 CGPGroup() = default; 88 CGPGroup( const gsl::cstring_view& initName ); 89 // non-copyable; but just for performance reasons, since it would incur a deep copy. 90 CGPGroup( const CGPGroup& ) = delete; 91 CGPGroup& operator=( const CGPGroup& ) = delete; 92 // movable 93 #if defined( _MSC_VER ) && _MSC_VER < 1900 94 // alas no default move constructors on VS2013. 95 // TODO DELETEME once we drop VS2013 (because fuck that). CGPGroup(CGPGroup && rhs)96 CGPGroup( CGPGroup&& rhs ) 97 : mProperties( std::move( rhs.mProperties ) ) 98 , mName( std::move( rhs.mName ) ) 99 , mSubGroups( std::move( rhs.mSubGroups ) ) 100 { 101 } 102 CGPGroup& operator=( CGPGroup&& rhs ) 103 { 104 mProperties = std::move( rhs.mProperties ); 105 mName = std::move( rhs.mName ); 106 mSubGroups = std::move( rhs.mSubGroups ); 107 return *this; 108 } 109 #else 110 CGPGroup( CGPGroup&& ) = default; 111 CGPGroup& operator=( CGPGroup&& ) = default; 112 #endif 113 GetProperties()114 const Properties& GetProperties() const NOEXCEPT 115 { 116 return mProperties; 117 } GetSubGroups()118 const SubGroups& GetSubGroups() const NOEXCEPT 119 { 120 return mSubGroups; 121 } FindSubGroup(const gsl::cstring_view & name)122 const CGPGroup* FindSubGroup( const gsl::cstring_view& name ) const NOEXCEPT 123 { 124 for( auto& sub : GetSubGroups() ) 125 { 126 if( Q::stricmp( name, sub.GetName() ) == Q::Ordering::EQ ) 127 { 128 return ⊂ 129 } 130 } 131 return nullptr; 132 } FindProperty(const gsl::cstring_view & name)133 const CGPProperty* FindProperty( const gsl::cstring_view& name ) const NOEXCEPT 134 { 135 for( auto& prop : GetProperties() ) 136 { 137 if( Q::stricmp( name, prop.GetName() ) == Q::Ordering::EQ ) 138 { 139 return ∝ 140 } 141 } 142 return nullptr; 143 } GetName()144 const gsl::cstring_view& GetName() const NOEXCEPT 145 { 146 return mName; 147 } Clear()148 void Clear() NOEXCEPT 149 { 150 // name is retained 151 mProperties.clear(); 152 mSubGroups.clear(); 153 } 154 bool Parse( gsl::cstring_view& data, const bool topLevel = true ); 155 }; 156 157 /** 158 Generic Text Parser. 159 160 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. 161 */ 162 class CGenericParser2 163 { 164 private: 165 CGPGroup mTopLevel; 166 FS::FileBuffer mFileContent; 167 168 public: 169 GetBaseParseGroup()170 const CGPGroup& GetBaseParseGroup() 171 { 172 return mTopLevel; 173 } 174 175 bool Parse( gsl::czstring filename ); 176 void Clear() NOEXCEPT; ValidFile()177 bool ValidFile() const NOEXCEPT 178 { 179 return mFileContent.valid(); 180 } 181 }; 182 183 #endif // #ifndef GENERICPARSER2_H 184 185 186 //////////////////// eof ///////////////////// 187 188