1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file script_admin.cpp Implementation of ScriptAdmin. */
9 
10 #include "../../stdafx.h"
11 #include "script_admin.hpp"
12 #include "script_log.hpp"
13 #include "../../network/network_admin.h"
14 #include "../script_instance.hpp"
15 #include "../../string_func.h"
16 
17 #include "../../safeguards.h"
18 
MakeJSON(HSQUIRRELVM vm,SQInteger index,int max_depth,std::string & data)19 /* static */ bool ScriptAdmin::MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data)
20 {
21 	if (max_depth == 0) {
22 		ScriptLog::Error("Send parameters can only be nested to 25 deep. No data sent."); // SQUIRREL_MAX_DEPTH = 25
23 		return false;
24 	}
25 
26 	switch (sq_gettype(vm, index)) {
27 		case OT_INTEGER: {
28 			SQInteger res;
29 			sq_getinteger(vm, index, &res);
30 
31 			char buf[10];
32 			seprintf(buf, lastof(buf), "%d", (int32)res);
33 			data = buf;
34 			return true;
35 		}
36 
37 		case OT_STRING: {
38 			const SQChar *buf;
39 			sq_getstring(vm, index, &buf);
40 
41 			size_t len = strlen(buf) + 1;
42 			if (len >= 255) {
43 				ScriptLog::Error("Maximum string length is 254 chars. No data sent.");
44 				return false;
45 			}
46 
47 			data = std::string("\"") + buf + "\"";
48 			return true;
49 		}
50 
51 		case OT_ARRAY: {
52 			data = "[ ";
53 
54 			bool first = true;
55 			sq_pushnull(vm);
56 			while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
57 				if (!first) data += ", ";
58 				if (first) first = false;
59 
60 				std::string tmp;
61 
62 				bool res = MakeJSON(vm, -1, max_depth - 1, tmp);
63 				sq_pop(vm, 2);
64 				if (!res) {
65 					sq_pop(vm, 1);
66 					return false;
67 				}
68 				data += tmp;
69 			}
70 			sq_pop(vm, 1);
71 			data += " ]";
72 			return true;
73 		}
74 
75 		case OT_TABLE: {
76 			data = "{ ";
77 
78 			bool first = true;
79 			sq_pushnull(vm);
80 			while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
81 				if (!first) data += ", ";
82 				if (first) first = false;
83 
84 				std::string key;
85 				std::string value;
86 
87 				/* Store the key + value */
88 				bool res = MakeJSON(vm, -2, max_depth - 1, key) && MakeJSON(vm, -1, max_depth - 1, value);
89 				sq_pop(vm, 2);
90 				if (!res) {
91 					sq_pop(vm, 1);
92 					return false;
93 				}
94 				data += key + ": " + value;
95 			}
96 			sq_pop(vm, 1);
97 			data += " }";
98 			return true;
99 		}
100 
101 		case OT_BOOL: {
102 			SQBool res;
103 			sq_getbool(vm, index, &res);
104 
105 			if (res) {
106 				data = "true";
107 				return true;
108 			}
109 
110 			data = "false";
111 			return true;
112 		}
113 
114 		case OT_NULL: {
115 			data = "null";
116 			return true;
117 		}
118 
119 		default:
120 			ScriptLog::Error("You tried to send an unsupported type. No data sent.");
121 			return false;
122 	}
123 }
124 
Send(HSQUIRRELVM vm)125 /* static */ SQInteger ScriptAdmin::Send(HSQUIRRELVM vm)
126 {
127 	if (sq_gettop(vm) - 1 != 1) return sq_throwerror(vm, "wrong number of parameters");
128 
129 	if (sq_gettype(vm, 2) != OT_TABLE) {
130 		return sq_throwerror(vm, "ScriptAdmin::Send requires a table as first parameter. No data sent.");
131 	}
132 
133 	std::string json;
134 	ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json);
135 
136 	if (json.length() > NETWORK_GAMESCRIPT_JSON_LENGTH) {
137 		ScriptLog::Error("You are trying to send a table that is too large to the AdminPort. No data sent.");
138 		sq_pushinteger(vm, 0);
139 		return 1;
140 	}
141 
142 	NetworkAdminGameScript(json);
143 
144 	sq_pushinteger(vm, 1);
145 	return 1;
146 }
147