1/*
2 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "luavaluecasts.h"
24#include "luainterface.h"
25#include <framework/otml/otmlnode.h>
26
27// bool
28int push_luavalue(bool b)
29{
30 g_lua.pushBoolean(b);
31 return 1;
32}
33
34bool luavalue_cast(int index, bool& b)
35{
36 b = g_lua.toBoolean(index);
37 return true;
38}
39
40// int
41int push_luavalue(int i)
42{
43 g_lua.pushInteger(i);
44 return 1;
45}
46
47bool luavalue_cast(int index, int& i)
48{
49 i = g_lua.toInteger(index);
50 if(i == 0 && !g_lua.isNumber(index) && !g_lua.isNil())
51 return false;
52 return true;
53}
54
55// double
56int push_luavalue(double d)
57{
58 g_lua.pushNumber(d);
59 return 1;
60}
61
62bool luavalue_cast(int index, double& d)
63{
64 d = g_lua.toNumber(index);
65 if(d == 0 && !g_lua.isNumber(index) && !g_lua.isNil())
66 return false;
67 return true;
68}
69
70// string
71int push_luavalue(const char* cstr)
72{
73 g_lua.pushCString(cstr);
74 return 1;
75}
76
77int push_luavalue(const std::string& str)
78{
79 g_lua.pushString(str);
80 return 1;
81}
82
83bool luavalue_cast(int index, std::string& str)
84{
85 str = g_lua.toString(index);
86 return true;
87}
88
89// lua cpp function
90int push_luavalue(const LuaCppFunction& func)
91{
92 g_lua.pushCppFunction(func);
93 return 1;
94}
95
96// color
97int push_luavalue(const Color& color)
98{
99 g_lua.createTable(0, 4);
100 g_lua.pushInteger(color.r());
101 g_lua.setField("r");
102 g_lua.pushInteger(color.g());
103 g_lua.setField("g");
104 g_lua.pushInteger(color.b());
105 g_lua.setField("b");
106 g_lua.pushInteger(color.a());
107 g_lua.setField("a");
108 return 1;
109}
110
111bool luavalue_cast(int index, Color& color)
112{
113 if(g_lua.isTable(index)) {
114 g_lua.getField("r", index);
115 color.setRed((int)g_lua.popInteger());
116 g_lua.getField("g", index);
117 color.setGreen((int)g_lua.popInteger());
118 g_lua.getField("b", index);
119 color.setBlue((int)g_lua.popInteger());
120 g_lua.getField("a", index);
121 color.setAlpha((int)g_lua.popInteger());
122 return true;
123 } else if(g_lua.isString()) {
124 return stdext::cast(g_lua.toString(index), color);
125 } else if(g_lua.isNil()) {
126 color = Color::white;
127 return true;
128 }
129 return false;
130}
131
132// rect
133int push_luavalue(const Rect& rect)
134{
135 g_lua.createTable(0, 4);
136 g_lua.pushInteger(rect.x());
137 g_lua.setField("x");
138 g_lua.pushInteger(rect.y());
139 g_lua.setField("y");
140 g_lua.pushInteger(rect.width());
141 g_lua.setField("width");
142 g_lua.pushInteger(rect.height());
143 g_lua.setField("height");
144 return 1;
145}
146
147bool luavalue_cast(int index, Rect& rect)
148{
149 if(g_lua.isTable(index)) {
150 g_lua.getField("x", index);
151 rect.setX(g_lua.popInteger());
152 g_lua.getField("y", index);
153 rect.setY(g_lua.popInteger());
154 g_lua.getField("width", index);
155 rect.setWidth(g_lua.popInteger());
156 g_lua.getField("height", index);
157 rect.setHeight(g_lua.popInteger());
158 return true;
159 } else if(g_lua.isString()) {
160 return stdext::cast(g_lua.toString(index), rect);
161 } else if(g_lua.isNil()) {
162 rect = Rect();
163 return true;
164 }
165 return false;
166}
167
168// point
169int push_luavalue(const Point& point)
170{
171 g_lua.createTable(0, 2);
172 g_lua.pushInteger(point.x);
173 g_lua.setField("x");
174 g_lua.pushInteger(point.y);
175 g_lua.setField("y");
176 return 1;
177}
178
179bool luavalue_cast(int index, Point& point)
180{
181 if(g_lua.isTable(index)) {
182 g_lua.getField("x", index);
183 point.x = g_lua.popInteger();
184 g_lua.getField("y", index);
185 point.y = g_lua.popInteger();
186 return true;
187 } else if(g_lua.isString()) {
188 return stdext::cast(g_lua.toString(index), point);
189 } else if(g_lua.isNil()) {
190 point = Point();
191 return true;
192 }
193 return false;
194}
195
196// size
197int push_luavalue(const Size& size)
198{
199 g_lua.createTable(0, 2);
200 g_lua.pushInteger(size.width());
201 g_lua.setField("width");
202 g_lua.pushInteger(size.height());
203 g_lua.setField("height");
204 return 1;
205}
206
207bool luavalue_cast(int index, Size& size)
208{
209 if(g_lua.isTable(index)) {
210 g_lua.getField("width", index);
211 size.setWidth(g_lua.popInteger());
212 g_lua.getField("height", index);
213 size.setHeight(g_lua.popInteger());
214 return true;
215 } else if(g_lua.isString()) {
216 return stdext::cast(g_lua.toString(index), size);
217 } else if(g_lua.isNil()) {
218 size = Size();
219 return true;
220 }
221 return false;
222}
223
224// otml nodes
225void push_otml_subnode_luavalue(const OTMLNodePtr& node)
226{
227 if(node->hasValue()) {
228 union {
229 bool b;
230 double d;
231 long l;
232 };
233 std::string value = node->rawValue();
234 if(stdext::cast(value, b))
235 g_lua.pushBoolean(b);
236 else if(stdext::cast(value, l))
237 g_lua.pushInteger(l);
238 else if(stdext::cast(value, d))
239 g_lua.pushNumber(d);
240 else
241 g_lua.pushString(value);
242 } else if(node->hasChildren()) {
243 g_lua.newTable();
244 bool pushedChild = false;
245 int currentIndex = 1;
246 for(const OTMLNodePtr& cnode : node->children()) {
247 push_otml_subnode_luavalue(cnode);
248 if(!g_lua.isNil()) {
249 if(cnode->isUnique()) {
250 g_lua.pushString(cnode->tag());
251 g_lua.insert(-2);
252 g_lua.rawSet();
253 } else
254 g_lua.rawSeti(currentIndex++);
255 pushedChild = true;
256 } else
257 g_lua.pop();
258 }
259 if(!pushedChild) {
260 g_lua.pop();
261 g_lua.pushNil();
262 }
263 } else
264 g_lua.pushNil();
265}
266
267int push_luavalue(const OTMLNodePtr& node)
268{
269 if(node) {
270 g_lua.newTable();
271 int currentIndex = 1;
272 for(const OTMLNodePtr& cnode : node->children()) {
273 push_otml_subnode_luavalue(cnode);
274 if(cnode->isUnique() && !cnode->tag().empty()) {
275 g_lua.setField(cnode->tag());
276 } else
277 g_lua.rawSeti(currentIndex++);
278 }
279 } else
280 g_lua.pushNil();
281 return 1;
282}
283
284bool luavalue_cast(int index, OTMLNodePtr& node)
285{
286 node = OTMLNode::create();
287 node->setUnique(true);
288 if(g_lua.isTable(index)) {
289 g_lua.pushNil();
290 while(g_lua.next(index < 0 ? index-1 : index)) {
291 std::string cnodeName;
292 if(g_lua.isString(-2)) {
293 g_lua.pushValue(-2);
294 cnodeName = g_lua.toString();
295 g_lua.pop();
296 } else
297 VALIDATE(g_lua.isNumber());
298 if(g_lua.isTable()) {
299 OTMLNodePtr cnode;
300 if(luavalue_cast(-1, cnode)) {
301 if(cnodeName.empty())
302 cnode->setUnique(false);
303 else
304 cnode->setTag(cnodeName);
305 node->addChild(cnode);
306 }
307 } else {
308 std::string value;
309 if(g_lua.isBoolean())
310 value = stdext::unsafe_cast<std::string>(g_lua.toBoolean());
311 else
312 value = g_lua.toString();
313 if(cnodeName.empty())
314 node->writeIn(value);
315 else
316 node->writeAt(cnodeName, value);
317 }
318 g_lua.pop();
319 }
320 return true;
321 }
322 return false;
323}
324
325// object ptr
326bool luavalue_cast(int index, LuaObjectPtr& obj) {
327 if(g_lua.isUserdata(index)) {
328 obj = g_lua.toObject(index);
329 return true;
330 } else if(g_lua.isNil(index)) {
331 obj = nullptr;
332 return true;
333 }
334 return false;
335}
336