1 /////////////////////////////////////////
2 //
3 //   OpenLieroX
4 //
5 //   Auxiliary Software class library
6 //
7 //   based on the work of JasonB
8 //   enhanced by Dark Charlie and Albert Zeyer
9 //
10 //   code under LGPL
11 //
12 /////////////////////////////////////////
13 
14 
15 // Config file handler
16 // Created 30/9/01
17 // By Jason Boettcher
18 
19 
20 #include <map>
21 #include <string>
22 #include "LieroX.h"
23 #include "ConfigHandler.h"
24 #include "FindFile.h"
25 #include "StringUtils.h"
26 #include "MathLib.h"
27 
28 
29 
30 typedef std::map<std::string, int, stringcaseless> KeywordMap;
31 static KeywordMap Keywords;
32 
33 
34 // Internal
35 static bool	GetString(const std::string& filename, const std::string& section, const std::string& key, std::string& string, bool abs_fn = false);
36 
37 
38 ///////////////////
39 // Add a keyword to the list
AddKeyword(const std::string & key,int value)40 bool AddKeyword(const std::string& key, int value)
41 {
42 	Keywords[key] = value;
43 
44 	return true;
45 }
46 
47 
48 
49 ///////////////////
50 // Read a keyword from a file
ReadKeyword(const std::string & filename,const std::string & section,const std::string & key,int * value,int defaultv)51 bool ReadKeyword(const std::string& filename, const std::string& section, const std::string& key, int *value, int defaultv)
52 {
53 	std::string string;
54 
55 	*value = defaultv;
56 
57 	if(!GetString(filename,section,key,string))
58 		return false;
59 
60 	// Try and find a keyword with matching keys
61 	KeywordMap::iterator f = Keywords.find(string);
62 	if(f != Keywords.end()) {
63 		//notes << filename << ":" << section << "." << key << ": " << f->first << "(" << string << ") = " << f->second << endl;
64 		*value = f->second;
65 		return true;
66 	}
67 
68 	warnings << filename << ":" << section << "." << key << ": '" << string << "' is an unknown keyword" << endl;
69 
70 	return false;
71 }
72 
73 ///////////////////
74 // Read a keyword from a file (bool version)
ReadKeyword(const std::string & filename,const std::string & section,const std::string & key,bool * value,bool defaultv)75 bool ReadKeyword(const std::string& filename, const std::string& section, const std::string& key, bool *value, bool defaultv)
76 {
77 	int v = defaultv ? 1 : 0;
78 	bool ret = ReadKeyword(filename, section, key, &v, defaultv ? 1 : 0);
79 	*value = v != 0;
80 	return ret;
81 }
82 
83 ///////////////////
84 // Read bit flags specified by keywords from a file
ReadKeywordList(const std::string & filename,const std::string & section,const std::string & key,int * value,int defaultv)85 bool ReadKeywordList(const std::string& filename, const std::string& section, const std::string& key, int *value, int defaultv)
86 {
87 	std::string string;
88 
89 	*value = defaultv;
90 
91 	if(!GetString(filename,section,key,string))
92 		return false;
93 
94 	std::vector<std::string> split = explode(string, ",");
95 	for (std::vector<std::string>::iterator it = split.begin(); it != split.end(); it++)  {
96 		TrimSpaces(*it);
97 		KeywordMap::iterator key = Keywords.find(*it);
98 		if (key != Keywords.end())
99 			*value |= key->second;
100 	}
101 
102 	return true;
103 }
104 
105 
106 ///////////////////
107 // Read an interger from a file
ReadInteger(const std::string & filename,const std::string & section,const std::string & key,int * value,int defaultv)108 bool ReadInteger(const std::string& filename, const std::string& section, const std::string& key, int *value, int defaultv)
109 {
110 	std::string string;
111 
112 	*value = defaultv;
113 
114 	if(!GetString(filename,section,key,string))
115 		return false;
116 
117 	*value = from_string<int>(string);
118 
119 	return true;
120 }
121 
122 
123 ///////////////////
124 // Read a string from a file
ReadString(const std::string & filename,const std::string & section,const std::string & key,std::string & value,std::string defaultv,bool abs_fn)125 bool ReadString(const std::string& filename, const std::string& section, const std::string& key, std::string& value, std::string defaultv, bool abs_fn)
126 {
127 	value = defaultv;
128 
129 	return GetString(filename,section,key,value, abs_fn);
130 
131 	/*int result = GetString(filename,section,key,value);
132 
133 	if (strlen(value) <= 0)
134 		strcpy(value,defaultv);
135 
136 	return result;*/
137 }
138 
139 
140 
141 ///////////////////
142 // Read a float from a file
ReadFloat(const std::string & filename,const std::string & section,const std::string & key,float * value,float defaultv)143 bool ReadFloat(const std::string& filename, const std::string& section, const std::string& key, float *value, float defaultv)
144 {
145 	std::string string;
146 
147 	*value = defaultv;
148 
149 	if(!GetString(filename,section,key,string))
150 		return false;
151 
152 	*value = (float)atof(string);
153 
154 	return true;
155 }
156 
157 
158 
ReadColour(const std::string & filename,const std::string & section,const std::string & key,Color & value,const Color & defaultv)159 bool ReadColour(const std::string& filename, const std::string& section, const std::string& key, Color& value, const Color& defaultv) {
160 	std::string string;
161 
162 	value = defaultv;
163 
164 	if(!GetString(filename,section,key,string))
165 		return false;
166 
167 	value = StrToCol(string);
168 
169 	return true;
170 }
171 
172 //////////////////
173 // Reads an array of integers
ReadIntArray(const std::string & filename,const std::string & section,const std::string & key,int * array,int num_items)174 bool ReadIntArray(const std::string& filename, const std::string& section, const std::string& key, int *array, int num_items)
175 {
176 	std::string string;
177 
178 	if (!GetString(filename,section,key,string))
179 		return false;
180 
181 	std::vector<std::string> arr = explode(string,",");
182 	for (int i=0; i<MIN(num_items,(int)arr.size()); i++)
183 		array[i] = from_string<int>(arr[i]);
184 
185 	return num_items == (int)arr.size();
186 }
187 
188 
189 
190 ///////////////////
191 // Read a string
GetString(const std::string & filename,const std::string & section,const std::string & key,std::string & string,bool abs_fn)192 static bool GetString(const std::string& filename, const std::string& section, const std::string& key, std::string& string, bool abs_fn)
193 {
194 	FILE	*config = NULL;
195 	std::string	Line;
196 	std::string	tmpLine;
197 	std::string	curSection;
198 	std::string	temp;
199 	std::string	curKey;
200 	size_t	chardest = 0;
201 	int		Position;
202 	bool	found = false;
203 
204 	if(filename == "")
205 		return false;
206 
207 	if(abs_fn) {
208 		config = fopen(Utf8ToSystemNative(filename).c_str(), "rt");
209 	} else
210 		config = OpenGameFile(filename,"rt");
211 	if(!config)
212 		return false;
213 
214 	//string="";
215 	curSection="";
216 	temp="";
217 	curKey="";
218 
219 	// Check for UTF-8 encoded file and skip the UTF-8 mark if it is
220 	uchar utf8mark[3];
221 	if(fread(utf8mark, sizeof(utf8mark)/sizeof(uchar), 1, config) == 0) {
222 		fclose(config);
223 		return false;
224 	}
225 	if (utf8mark[0] != 0xEF || utf8mark[1] != 0xBB || utf8mark[2] != 0xBF)
226 		fseek(config, 0, SEEK_SET); // Not a UTF-8 file, jump back to the beginning
227 
228 
229 	while(!feof(config) && !ferror(config))
230 	{
231 		// Parse the lines
232 		Line = ReadUntil(config, '\n');
233 		TrimSpaces(Line);
234 
235 		///////////////////
236 		// Comment, Ignore
237 		if(Line.size() == 0 || Line[0] == '#')
238 			continue;
239 
240 		////////////
241 		// Sections
242 		if(Line[0] == '[' && Line[Line.size()-1] == ']')
243 		{
244 			curSection = Line.substr(1);
245 			curSection.erase(curSection.size()-1);
246 			continue;
247 		}
248 
249 		////////
250 		// Keys
251 		chardest = Line.find('=');
252 		if(chardest != std::string::npos)
253 		{
254 			// Key
255 			Position = (int)chardest;
256 			tmpLine = Line;
257 			tmpLine.erase(Position);
258 			TrimSpaces(tmpLine);
259 			curKey = tmpLine;
260 
261 			// Check if this is the key were looking for under the section were looking for
262 			if(stringcasecmp(curKey,key) == 0 && stringcasecmp(curSection,section) == 0)
263 			{
264 				// Get the value
265 				tmpLine = Line.substr(Position+1);
266 				TrimSpaces(tmpLine);
267 				string = tmpLine;
268 				found = true;
269 				break;
270 			}
271 			continue;
272 		}
273 	}
274 
275 	fclose(config);
276 
277 	return found;
278 }
279 
280 
281