1 /*
2 script/lua_api/l_util.cpp
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5 
6 /*
7 This file is part of Freeminer.
8 
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Freeminer  is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Freeminer.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "lua_api/l_util.h"
24 #include "lua_api/l_internal.h"
25 #include "common/c_converter.h"
26 #include "common/c_content.h"
27 #include "cpp_api/s_async.h"
28 #include "serialization.h"
29 #include "json/json.h"
30 #include "debug.h"
31 #include "porting.h"
32 #include "log.h"
33 #include "tool.h"
34 #include "filesys.h"
35 #include "settings.h"
36 #include "main.h"  //required for g_settings, g_settings_path
37 
38 // debug(...)
39 // Writes a line to dstream
l_debug(lua_State * L)40 int ModApiUtil::l_debug(lua_State *L)
41 {
42 	NO_MAP_LOCK_REQUIRED;
43 	// Handle multiple parameters to behave like standard lua print()
44 	int n = lua_gettop(L);
45 	lua_getglobal(L, "tostring");
46 	for (int i = 1; i <= n; i++) {
47 		/*
48 			Call tostring(i-th argument).
49 			This is what print() does, and it behaves a bit
50 			differently from directly calling lua_tostring.
51 		*/
52 		lua_pushvalue(L, -1);  /* function to be called */
53 		lua_pushvalue(L, i);   /* value to print */
54 		lua_call(L, 1, 1);
55 		size_t len;
56 		const char *s = lua_tolstring(L, -1, &len);
57 		if (i > 1)
58 			dstream << "\t";
59 		if (s)
60 			dstream << std::string(s, len);
61 		lua_pop(L, 1);
62 	}
63 	dstream << std::endl;
64 	return 0;
65 }
66 
67 // log([level,] text)
68 // Writes a line to the logger.
69 // The one-argument version logs to infostream.
70 // The two-argument version accept a log level: error, action, info, or verbose.
l_log(lua_State * L)71 int ModApiUtil::l_log(lua_State *L)
72 {
73 	NO_MAP_LOCK_REQUIRED;
74 	std::string text;
75 	LogMessageLevel level = LMT_INFO;
76 	if (lua_isnone(L, 2)) {
77 		text = lua_tostring(L, 1);
78 	}
79 	else {
80 		std::string levelname = luaL_checkstring(L, 1);
81 		text = luaL_checkstring(L, 2);
82 		if(levelname == "error")
83 			level = LMT_ERROR;
84 		else if(levelname == "action")
85 			level = LMT_ACTION;
86 		else if(levelname == "verbose")
87 			level = LMT_VERBOSE;
88 		else if (levelname == "deprecated") {
89 			log_deprecated(L,text);
90 			return 0;
91 		}
92 
93 	}
94 	log_printline(level, text);
95 	return 0;
96 }
97 
98 // setting_set(name, value)
l_setting_set(lua_State * L)99 int ModApiUtil::l_setting_set(lua_State *L)
100 {
101 	NO_MAP_LOCK_REQUIRED;
102 	const char *name = luaL_checkstring(L, 1);
103 	const char *value = luaL_checkstring(L, 2);
104 	g_settings->set(name, value);
105 	return 0;
106 }
107 
108 // setting_get(name)
l_setting_get(lua_State * L)109 int ModApiUtil::l_setting_get(lua_State *L)
110 {
111 	NO_MAP_LOCK_REQUIRED;
112 	const char *name = luaL_checkstring(L, 1);
113 	try{
114 		std::string value = g_settings->get(name);
115 		lua_pushstring(L, value.c_str());
116 	} catch(SettingNotFoundException &e){
117 		lua_pushnil(L);
118 	}
119 	return 1;
120 }
121 
122 // setting_setbool(name)
l_setting_setbool(lua_State * L)123 int ModApiUtil::l_setting_setbool(lua_State *L)
124 {
125 	NO_MAP_LOCK_REQUIRED;
126 	const char *name = luaL_checkstring(L, 1);
127 	bool value = lua_toboolean(L, 2);
128 	g_settings->setBool(name, value);
129 	return 0;
130 }
131 
132 // setting_getbool(name)
l_setting_getbool(lua_State * L)133 int ModApiUtil::l_setting_getbool(lua_State *L)
134 {
135 	NO_MAP_LOCK_REQUIRED;
136 	const char *name = luaL_checkstring(L, 1);
137 	try{
138 		bool value = g_settings->getBool(name);
139 		lua_pushboolean(L, value);
140 	} catch(SettingNotFoundException &e){
141 		lua_pushnil(L);
142 	}
143 	return 1;
144 }
145 
146 // setting_save()
l_setting_save(lua_State * L)147 int ModApiUtil::l_setting_save(lua_State *L)
148 {
149 	NO_MAP_LOCK_REQUIRED;
150 	if(g_settings_path != "")
151 		g_settings->updateConfigFile(g_settings_path.c_str());
152 	return 0;
153 }
154 
155 // parse_json(str[, nullvalue])
l_parse_json(lua_State * L)156 int ModApiUtil::l_parse_json(lua_State *L)
157 {
158 	NO_MAP_LOCK_REQUIRED;
159 
160 	const char *jsonstr = luaL_checkstring(L, 1);
161 
162 	// Use passed nullvalue or default to nil
163 	int nullindex = 2;
164 	if (lua_isnone(L, nullindex)) {
165 		lua_pushnil(L);
166 		nullindex = lua_gettop(L);
167 	}
168 
169 	Json::Value root;
170 
171 	{
172 		Json::Reader reader;
173 		std::istringstream stream(jsonstr);
174 
175 		if (!reader.parse(stream, root)) {
176 			errorstream << "Failed to parse json data "
177 				<< reader.getFormattedErrorMessages();
178 			errorstream << "data: \"" << jsonstr << "\""
179 				<< std::endl;
180 			lua_pushnil(L);
181 			return 1;
182 		}
183 	}
184 
185 	if (!push_json_value(L, root, nullindex)) {
186 		errorstream << "Failed to parse json data, "
187 			<< "depth exceeds lua stack limit" << std::endl;
188 		errorstream << "data: \"" << jsonstr << "\"" << std::endl;
189 		lua_pushnil(L);
190 	}
191 	return 1;
192 }
193 
194 // write_json(data[, styled]) -> string or nil and error message
l_write_json(lua_State * L)195 int ModApiUtil::l_write_json(lua_State *L)
196 {
197 	NO_MAP_LOCK_REQUIRED;
198 
199 	bool styled = false;
200 	if (!lua_isnone(L, 2)) {
201 		styled = lua_toboolean(L, 2);
202 		lua_pop(L, 1);
203 	}
204 
205 	Json::Value root;
206 	try {
207 		read_json_value(L, root, 1);
208 	} catch (SerializationError &e) {
209 		lua_pushnil(L);
210 		lua_pushstring(L, e.what());
211 		return 2;
212 	}
213 
214 	std::string out;
215 	if (styled) {
216 		Json::StyledWriter writer;
217 		out = writer.write(root);
218 	} else {
219 		Json::FastWriter writer;
220 		out = writer.write(root);
221 	}
222 	lua_pushlstring(L, out.c_str(), out.size());
223 	return 1;
224 }
225 
226 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
l_get_dig_params(lua_State * L)227 int ModApiUtil::l_get_dig_params(lua_State *L)
228 {
229 	NO_MAP_LOCK_REQUIRED;
230 	std::map<std::string, int> groups;
231 	read_groups(L, 1, groups);
232 	ToolCapabilities tp = read_tool_capabilities(L, 2);
233 	if(lua_isnoneornil(L, 3))
234 		push_dig_params(L, getDigParams(groups, &tp));
235 	else
236 		push_dig_params(L, getDigParams(groups, &tp,
237 					luaL_checknumber(L, 3)));
238 	return 1;
239 }
240 
241 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
l_get_hit_params(lua_State * L)242 int ModApiUtil::l_get_hit_params(lua_State *L)
243 {
244 	NO_MAP_LOCK_REQUIRED;
245 	std::map<std::string, int> groups;
246 	read_groups(L, 1, groups);
247 	ToolCapabilities tp = read_tool_capabilities(L, 2);
248 	if(lua_isnoneornil(L, 3))
249 		push_hit_params(L, getHitParams(groups, &tp));
250 	else
251 		push_hit_params(L, getHitParams(groups, &tp,
252 					luaL_checknumber(L, 3)));
253 	return 1;
254 }
255 
256 // get_password_hash(name, raw_password)
l_get_password_hash(lua_State * L)257 int ModApiUtil::l_get_password_hash(lua_State *L)
258 {
259 	NO_MAP_LOCK_REQUIRED;
260 	std::string name = luaL_checkstring(L, 1);
261 	std::string raw_password = luaL_checkstring(L, 2);
262 	std::string hash = translatePassword(name,
263 			narrow_to_wide(raw_password));
264 	lua_pushstring(L, hash.c_str());
265 	return 1;
266 }
267 
268 // is_yes(arg)
l_is_yes(lua_State * L)269 int ModApiUtil::l_is_yes(lua_State *L)
270 {
271 	NO_MAP_LOCK_REQUIRED;
272 
273 	lua_getglobal(L, "tostring"); // function to be called
274 	lua_pushvalue(L, 1); // 1st argument
275 	lua_call(L, 1, 1); // execute function
276 	std::string str(lua_tostring(L, -1)); // get result
277 	lua_pop(L, 1);
278 
279 	bool yes = is_yes(str);
280 	lua_pushboolean(L, yes);
281 	return 1;
282 }
283 
l_get_builtin_path(lua_State * L)284 int ModApiUtil::l_get_builtin_path(lua_State *L)
285 {
286 	std::string path = porting::path_share + DIR_DELIM + "builtin";
287 	lua_pushstring(L, path.c_str());
288 	return 1;
289 }
290 
291 // compress(data, method, level)
l_compress(lua_State * L)292 int ModApiUtil::l_compress(lua_State *L)
293 {
294 	size_t size;
295 	const char *data = luaL_checklstring(L, 1, &size);
296 
297 	int level = -1;
298 	if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
299 		level = luaL_checknumber(L, 3);
300 
301 	std::ostringstream os;
302 	compressZlib(std::string(data, size), os, level);
303 
304 	std::string out = os.str();
305 
306 	lua_pushlstring(L, out.data(), out.size());
307 	return 1;
308 }
309 
310 // decompress(data, method)
l_decompress(lua_State * L)311 int ModApiUtil::l_decompress(lua_State *L)
312 {
313 	size_t size;
314 	const char * data = luaL_checklstring(L, 1, &size);
315 
316 	std::istringstream is(std::string(data, size));
317 	std::ostringstream os;
318 	decompressZlib(is, os);
319 
320 	std::string out = os.str();
321 
322 	lua_pushlstring(L, out.data(), out.size());
323 	return 1;
324 }
325 
Initialize(lua_State * L,int top)326 void ModApiUtil::Initialize(lua_State *L, int top)
327 {
328 	API_FCT(debug);
329 	API_FCT(log);
330 
331 	API_FCT(setting_set);
332 	API_FCT(setting_get);
333 	API_FCT(setting_setbool);
334 	API_FCT(setting_getbool);
335 	API_FCT(setting_save);
336 
337 	API_FCT(parse_json);
338 	API_FCT(write_json);
339 
340 	API_FCT(get_dig_params);
341 	API_FCT(get_hit_params);
342 
343 	API_FCT(get_password_hash);
344 
345 	API_FCT(is_yes);
346 
347 	API_FCT(get_builtin_path);
348 
349 	API_FCT(compress);
350 	API_FCT(decompress);
351 }
352 
InitializeAsync(AsyncEngine & engine)353 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
354 {
355 	ASYNC_API_FCT(debug);
356 	ASYNC_API_FCT(log);
357 
358 	//ASYNC_API_FCT(setting_set);
359 	ASYNC_API_FCT(setting_get);
360 	//ASYNC_API_FCT(setting_setbool);
361 	ASYNC_API_FCT(setting_getbool);
362 	//ASYNC_API_FCT(setting_save);
363 
364 	ASYNC_API_FCT(parse_json);
365 	ASYNC_API_FCT(write_json);
366 
367 	ASYNC_API_FCT(is_yes);
368 
369 	ASYNC_API_FCT(get_builtin_path);
370 
371 	ASYNC_API_FCT(compress);
372 	ASYNC_API_FCT(decompress);
373 }
374 
375