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 &sub;
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 &prop;
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