1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "System/Info.h"
4 
5 #include "System/Util.h"
6 #include "System/Exceptions.h"
7 #include "System/Log/ILog.h"
8 #include "Lua/LuaParser.h"
9 
10 #include <assert.h>
11 
12 static const char* InfoItem_badKeyChars = " =;\r\n\t";
13 
info_getValueAsString(const InfoItem * infoItem)14 std::string info_getValueAsString(const InfoItem* infoItem) {
15 
16 	assert(infoItem != NULL);
17 
18 	std::string stringValue = "";
19 
20 	switch (infoItem->valueType) {
21 		case INFO_VALUE_TYPE_STRING: {
22 			stringValue = infoItem->valueTypeString;
23 		} break;
24 		case INFO_VALUE_TYPE_INTEGER: {
25 			stringValue = IntToString(infoItem->value.typeInteger);
26 		} break;
27 		case INFO_VALUE_TYPE_FLOAT: {
28 			stringValue = FloatToString(infoItem->value.typeFloat);
29 		} break;
30 		case INFO_VALUE_TYPE_BOOL: {
31 			stringValue = IntToString((int) infoItem->value.typeBool);
32 		} break;
33 	}
34 
35 	return stringValue;
36 }
37 
info_convertToStringValue(InfoItem * infoItem)38 void info_convertToStringValue(InfoItem* infoItem) {
39 
40 	assert(infoItem != NULL);
41 
42 	infoItem->valueTypeString = info_getValueAsString(infoItem);
43 	infoItem->valueType = INFO_VALUE_TYPE_STRING;
44 }
45 
info_convertTypeToString(InfoValueType infoValueType)46 const char* info_convertTypeToString(InfoValueType infoValueType) {
47 
48 	const char* typeString = NULL;
49 
50 	switch (infoValueType) {
51 		case INFO_VALUE_TYPE_STRING: {
52 			typeString = "string";
53 		} break;
54 		case INFO_VALUE_TYPE_INTEGER: {
55 			typeString = "integer";
56 		} break;
57 		case INFO_VALUE_TYPE_FLOAT: {
58 			typeString = "float";
59 		} break;
60 		case INFO_VALUE_TYPE_BOOL: {
61 			typeString = "bool";
62 		} break;
63 	}
64 
65 	return typeString;
66 }
67 
info_parseInfoItem(const LuaTable & root,int index,InfoItem & inf,std::set<string> & infoSet)68 static bool info_parseInfoItem(const LuaTable& root, int index, InfoItem& inf,
69 		std::set<string>& infoSet)
70 {
71 	const LuaTable& infsTbl = root.SubTable(index);
72 	if (!infsTbl.IsValid()) {
73 		LOG_L(L_WARNING, "parseInfoItem: subtable %d invalid", index);
74 		return false;
75 	}
76 
77 	// common info properties
78 	inf.key = infsTbl.GetString("key", "");
79 	if (inf.key.empty()
80 			|| (inf.key.find_first_of(InfoItem_badKeyChars) != string::npos)) {
81 		LOG_L(L_WARNING,
82 				"parseInfoItem: empty key or key contains bad characters");
83 		return false;
84 	}
85 	std::string lowerKey = StringToLower(inf.key);
86 	if (infoSet.find(inf.key) != infoSet.end()) {
87 		LOG_L(L_WARNING, "parseInfoItem: key toLowerCase(%s) exists already",
88 				inf.key.c_str());
89 		return false;
90 	}
91 	// TODO add support for info value types other then string
92 	inf.valueType = INFO_VALUE_TYPE_STRING;
93 	inf.valueTypeString = infsTbl.GetString("value", "");
94 	if (inf.valueTypeString.empty()) {
95 		LOG_L(L_WARNING, "parseInfoItem: %s: empty value", inf.key.c_str());
96 		return false;
97 	}
98 	inf.desc = infsTbl.GetString("desc", "");
99 
100 	infoSet.insert(lowerKey);
101 
102 	return true;
103 }
104 
105 
info_parseInfo(std::vector<InfoItem> & info,const std::string & fileName,const std::string & fileModes,const std::string & accessModes,std::set<std::string> * infoSet)106 void info_parseInfo(
107 		std::vector<InfoItem>& info,
108 		const std::string& fileName,
109 		const std::string& fileModes,
110 		const std::string& accessModes,
111 		std::set<std::string>* infoSet)
112 {
113 	LuaParser luaParser(fileName, fileModes, accessModes);
114 
115 	if (!luaParser.Execute()) {
116 		throw content_error("luaParser.Execute() failed: "
117 				+ luaParser.GetErrorLog());
118 	}
119 
120 	const LuaTable root = luaParser.GetRoot();
121 	if (!root.IsValid()) {
122 		throw content_error("root table invalid");
123 	}
124 
125 	std::set<std::string>* myInfoSet = NULL;
126 	if (infoSet == NULL) {
127 		myInfoSet = new std::set<std::string>();
128 	} else {
129 		myInfoSet = infoSet;
130 	}
131 	for (int index = 1; root.KeyExists(index); index++) {
132 		InfoItem inf;
133 		if (info_parseInfoItem(root, index, inf, *myInfoSet)) {
134 			info.push_back(inf);
135 		}
136 	}
137 	if (infoSet == NULL) {
138 		delete myInfoSet;
139 		myInfoSet = NULL;
140 	}
141 }
142 
info_parseInfo(const std::string & fileName,const std::string & fileModes,const std::string & accessModes,std::set<std::string> * infoSet)143 std::vector<InfoItem> info_parseInfo(
144 		const std::string& fileName,
145 		const std::string& fileModes,
146 		const std::string& accessModes,
147 		std::set<std::string>* infoSet)
148 {
149 	std::vector<InfoItem> info;
150 
151 	info_parseInfo(info, fileName, fileModes, accessModes, infoSet);
152 
153 	return info;
154 }
155