]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/common/c_converter.cpp
Make sure relevant std::stringstreams are set to binary
[dragonfireclient.git] / src / script / common / c_converter.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 extern "C" {
21 #include "lua.h"
22 #include "lauxlib.h"
23 }
24
25 #include "util/numeric.h"
26 #include "util/serialize.h"
27 #include "util/string.h"
28 #include "common/c_converter.h"
29 #include "common/c_internal.h"
30 #include "constants.h"
31 #include <set>
32
33
34 #define CHECK_TYPE(index, name, type) { \
35                 int t = lua_type(L, (index)); \
36                 if (t != (type)) { \
37                         throw LuaError(std::string("Invalid ") + (name) + \
38                                 " (expected " + lua_typename(L, (type)) + \
39                                 " got " + lua_typename(L, t) + ")."); \
40                 } \
41         }
42 #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
43 #define CHECK_FLOAT_RANGE(value, name) \
44 if (value < F1000_MIN || value > F1000_MAX) { \
45         std::ostringstream error_text; \
46         error_text << "Invalid float vector dimension range '" name "' " << \
47         "(expected " << F1000_MIN << " < " name " < " << F1000_MAX << \
48         " got " << value << ")." << std::endl; \
49         throw LuaError(error_text.str()); \
50 }
51 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
52
53
54 /**
55  * A helper which sets (if available) the vector metatable from builtin as metatable
56  * for the table on top of the stack
57  */
58 static void set_vector_metatable(lua_State *L)
59 {
60         // get vector.metatable
61         lua_getglobal(L, "vector");
62         if (!lua_istable(L, -1)) {
63                 // there is no global vector table
64                 lua_pop(L, 1);
65                 errorstream << "set_vector_metatable in c_converter.cpp: " <<
66                                 "missing global vector table" << std::endl;
67                 return;
68         }
69         lua_getfield(L, -1, "metatable");
70         // set the metatable
71         lua_setmetatable(L, -3);
72         // pop vector global
73         lua_pop(L, 1);
74 }
75
76
77 void push_float_string(lua_State *L, float value)
78 {
79         auto str = ftos(value);
80         lua_pushstring(L, str.c_str());
81 }
82
83 void push_v3f(lua_State *L, v3f p)
84 {
85         lua_createtable(L, 0, 3);
86         lua_pushnumber(L, p.X);
87         lua_setfield(L, -2, "x");
88         lua_pushnumber(L, p.Y);
89         lua_setfield(L, -2, "y");
90         lua_pushnumber(L, p.Z);
91         lua_setfield(L, -2, "z");
92         set_vector_metatable(L);
93 }
94
95 void push_v2f(lua_State *L, v2f p)
96 {
97         lua_createtable(L, 0, 2);
98         lua_pushnumber(L, p.X);
99         lua_setfield(L, -2, "x");
100         lua_pushnumber(L, p.Y);
101         lua_setfield(L, -2, "y");
102 }
103
104 void push_v3_float_string(lua_State *L, v3f p)
105 {
106         lua_createtable(L, 0, 3);
107         push_float_string(L, p.X);
108         lua_setfield(L, -2, "x");
109         push_float_string(L, p.Y);
110         lua_setfield(L, -2, "y");
111         push_float_string(L, p.Z);
112         lua_setfield(L, -2, "z");
113 }
114
115 void push_v2_float_string(lua_State *L, v2f p)
116 {
117         lua_createtable(L, 0, 2);
118         push_float_string(L, p.X);
119         lua_setfield(L, -2, "x");
120         push_float_string(L, p.Y);
121         lua_setfield(L, -2, "y");
122 }
123
124 v2s16 read_v2s16(lua_State *L, int index)
125 {
126         v2s16 p;
127         CHECK_POS_TAB(index);
128         lua_getfield(L, index, "x");
129         p.X = lua_tonumber(L, -1);
130         lua_pop(L, 1);
131         lua_getfield(L, index, "y");
132         p.Y = lua_tonumber(L, -1);
133         lua_pop(L, 1);
134         return p;
135 }
136
137 void push_v2s16(lua_State *L, v2s16 p)
138 {
139         lua_createtable(L, 0, 2);
140         lua_pushinteger(L, p.X);
141         lua_setfield(L, -2, "x");
142         lua_pushinteger(L, p.Y);
143         lua_setfield(L, -2, "y");
144 }
145
146 void push_v2s32(lua_State *L, v2s32 p)
147 {
148         lua_createtable(L, 0, 2);
149         lua_pushinteger(L, p.X);
150         lua_setfield(L, -2, "x");
151         lua_pushinteger(L, p.Y);
152         lua_setfield(L, -2, "y");
153 }
154
155 v2s32 read_v2s32(lua_State *L, int index)
156 {
157         v2s32 p;
158         CHECK_POS_TAB(index);
159         lua_getfield(L, index, "x");
160         p.X = lua_tonumber(L, -1);
161         lua_pop(L, 1);
162         lua_getfield(L, index, "y");
163         p.Y = lua_tonumber(L, -1);
164         lua_pop(L, 1);
165         return p;
166 }
167
168 v2f read_v2f(lua_State *L, int index)
169 {
170         v2f p;
171         CHECK_POS_TAB(index);
172         lua_getfield(L, index, "x");
173         p.X = lua_tonumber(L, -1);
174         lua_pop(L, 1);
175         lua_getfield(L, index, "y");
176         p.Y = lua_tonumber(L, -1);
177         lua_pop(L, 1);
178         return p;
179 }
180
181 v2f check_v2f(lua_State *L, int index)
182 {
183         v2f p;
184         CHECK_POS_TAB(index);
185         lua_getfield(L, index, "x");
186         CHECK_POS_COORD("x");
187         p.X = lua_tonumber(L, -1);
188         lua_pop(L, 1);
189         lua_getfield(L, index, "y");
190         CHECK_POS_COORD("y");
191         p.Y = lua_tonumber(L, -1);
192         lua_pop(L, 1);
193         return p;
194 }
195
196 v3f read_v3f(lua_State *L, int index)
197 {
198         v3f pos;
199         CHECK_POS_TAB(index);
200         lua_getfield(L, index, "x");
201         pos.X = lua_tonumber(L, -1);
202         lua_pop(L, 1);
203         lua_getfield(L, index, "y");
204         pos.Y = lua_tonumber(L, -1);
205         lua_pop(L, 1);
206         lua_getfield(L, index, "z");
207         pos.Z = lua_tonumber(L, -1);
208         lua_pop(L, 1);
209         return pos;
210 }
211
212 v3f check_v3f(lua_State *L, int index)
213 {
214         v3f pos;
215         CHECK_POS_TAB(index);
216         lua_getfield(L, index, "x");
217         CHECK_POS_COORD("x");
218         pos.X = lua_tonumber(L, -1);
219         CHECK_FLOAT_RANGE(pos.X, "x")
220         lua_pop(L, 1);
221         lua_getfield(L, index, "y");
222         CHECK_POS_COORD("y");
223         pos.Y = lua_tonumber(L, -1);
224         CHECK_FLOAT_RANGE(pos.Y, "y")
225         lua_pop(L, 1);
226         lua_getfield(L, index, "z");
227         CHECK_POS_COORD("z");
228         pos.Z = lua_tonumber(L, -1);
229         CHECK_FLOAT_RANGE(pos.Z, "z")
230         lua_pop(L, 1);
231         return pos;
232 }
233
234 v3d read_v3d(lua_State *L, int index)
235 {
236         v3d pos;
237         CHECK_POS_TAB(index);
238         lua_getfield(L, index, "x");
239         pos.X = lua_tonumber(L, -1);
240         lua_pop(L, 1);
241         lua_getfield(L, index, "y");
242         pos.Y = lua_tonumber(L, -1);
243         lua_pop(L, 1);
244         lua_getfield(L, index, "z");
245         pos.Z = lua_tonumber(L, -1);
246         lua_pop(L, 1);
247         return pos;
248 }
249
250 v3d check_v3d(lua_State *L, int index)
251 {
252         v3d pos;
253         CHECK_POS_TAB(index);
254         lua_getfield(L, index, "x");
255         CHECK_POS_COORD("x");
256         pos.X = lua_tonumber(L, -1);
257         CHECK_FLOAT_RANGE(pos.X, "x")
258         lua_pop(L, 1);
259         lua_getfield(L, index, "y");
260         CHECK_POS_COORD("y");
261         pos.Y = lua_tonumber(L, -1);
262         CHECK_FLOAT_RANGE(pos.Y, "y")
263         lua_pop(L, 1);
264         lua_getfield(L, index, "z");
265         CHECK_POS_COORD("z");
266         pos.Z = lua_tonumber(L, -1);
267         CHECK_FLOAT_RANGE(pos.Z, "z")
268         lua_pop(L, 1);
269         return pos;
270 }
271
272 void push_ARGB8(lua_State *L, video::SColor color)
273 {
274         lua_createtable(L, 0, 4);
275         lua_pushinteger(L, color.getAlpha());
276         lua_setfield(L, -2, "a");
277         lua_pushinteger(L, color.getRed());
278         lua_setfield(L, -2, "r");
279         lua_pushinteger(L, color.getGreen());
280         lua_setfield(L, -2, "g");
281         lua_pushinteger(L, color.getBlue());
282         lua_setfield(L, -2, "b");
283 }
284
285 void pushFloatPos(lua_State *L, v3f p)
286 {
287         p /= BS;
288         push_v3f(L, p);
289 }
290
291 v3f checkFloatPos(lua_State *L, int index)
292 {
293         return check_v3f(L, index) * BS;
294 }
295
296 void push_v3s16(lua_State *L, v3s16 p)
297 {
298         lua_createtable(L, 0, 3);
299         lua_pushinteger(L, p.X);
300         lua_setfield(L, -2, "x");
301         lua_pushinteger(L, p.Y);
302         lua_setfield(L, -2, "y");
303         lua_pushinteger(L, p.Z);
304         lua_setfield(L, -2, "z");
305         set_vector_metatable(L);
306 }
307
308 v3s16 read_v3s16(lua_State *L, int index)
309 {
310         // Correct rounding at <0
311         v3d pf = read_v3d(L, index);
312         return doubleToInt(pf, 1.0);
313 }
314
315 v3s16 check_v3s16(lua_State *L, int index)
316 {
317         // Correct rounding at <0
318         v3d pf = check_v3d(L, index);
319         return doubleToInt(pf, 1.0);
320 }
321
322 bool read_color(lua_State *L, int index, video::SColor *color)
323 {
324         if (lua_istable(L, index)) {
325                 *color = read_ARGB8(L, index);
326         } else if (lua_isnumber(L, index)) {
327                 color->set(lua_tonumber(L, index));
328         } else if (lua_isstring(L, index)) {
329                 video::SColor parsed_color;
330                 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
331                         return false;
332
333                 *color = parsed_color;
334         } else {
335                 return false;
336         }
337
338         return true;
339 }
340
341 video::SColor read_ARGB8(lua_State *L, int index)
342 {
343         video::SColor color(0);
344         CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
345         lua_getfield(L, index, "a");
346         color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
347         lua_pop(L, 1);
348         lua_getfield(L, index, "r");
349         color.setRed(lua_tonumber(L, -1));
350         lua_pop(L, 1);
351         lua_getfield(L, index, "g");
352         color.setGreen(lua_tonumber(L, -1));
353         lua_pop(L, 1);
354         lua_getfield(L, index, "b");
355         color.setBlue(lua_tonumber(L, -1));
356         lua_pop(L, 1);
357         return color;
358 }
359
360 bool is_color_table(lua_State *L, int index)
361 {
362         // Check whole table in case of missing ColorSpec keys:
363         // This check does not remove the checked value from the stack.
364         // Only update the value if we know we have a valid ColorSpec key pair.
365         if (!lua_istable(L, index))
366                 return false;
367
368         bool is_color_table = false;
369         lua_getfield(L, index, "r");
370         if (!is_color_table)
371                 is_color_table = lua_isnumber(L, -1);
372         lua_getfield(L, index, "g");
373         if (!is_color_table)
374                 is_color_table = lua_isnumber(L, -1);
375         lua_getfield(L, index, "b");
376         if (!is_color_table)
377                 is_color_table = lua_isnumber(L, -1);
378         lua_pop(L, 3); // b, g, r values
379         return is_color_table;
380 }
381
382 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
383 {
384         aabb3f box;
385         if(lua_istable(L, index)){
386                 lua_rawgeti(L, index, 1);
387                 box.MinEdge.X = lua_tonumber(L, -1) * scale;
388                 lua_pop(L, 1);
389                 lua_rawgeti(L, index, 2);
390                 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
391                 lua_pop(L, 1);
392                 lua_rawgeti(L, index, 3);
393                 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
394                 lua_pop(L, 1);
395                 lua_rawgeti(L, index, 4);
396                 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
397                 lua_pop(L, 1);
398                 lua_rawgeti(L, index, 5);
399                 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
400                 lua_pop(L, 1);
401                 lua_rawgeti(L, index, 6);
402                 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
403                 lua_pop(L, 1);
404         }
405         box.repair();
406         return box;
407 }
408
409 void push_aabb3f(lua_State *L, aabb3f box)
410 {
411         lua_createtable(L, 6, 0);
412         lua_pushnumber(L, box.MinEdge.X);
413         lua_rawseti(L, -2, 1);
414         lua_pushnumber(L, box.MinEdge.Y);
415         lua_rawseti(L, -2, 2);
416         lua_pushnumber(L, box.MinEdge.Z);
417         lua_rawseti(L, -2, 3);
418         lua_pushnumber(L, box.MaxEdge.X);
419         lua_rawseti(L, -2, 4);
420         lua_pushnumber(L, box.MaxEdge.Y);
421         lua_rawseti(L, -2, 5);
422         lua_pushnumber(L, box.MaxEdge.Z);
423         lua_rawseti(L, -2, 6);
424 }
425
426 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
427 {
428         std::vector<aabb3f> boxes;
429         if(lua_istable(L, index)){
430                 int n = lua_objlen(L, index);
431                 // Check if it's a single box or a list of boxes
432                 bool possibly_single_box = (n == 6);
433                 for(int i = 1; i <= n && possibly_single_box; i++){
434                         lua_rawgeti(L, index, i);
435                         if(!lua_isnumber(L, -1))
436                                 possibly_single_box = false;
437                         lua_pop(L, 1);
438                 }
439                 if(possibly_single_box){
440                         // Read a single box
441                         boxes.push_back(read_aabb3f(L, index, scale));
442                 } else {
443                         // Read a list of boxes
444                         for(int i = 1; i <= n; i++){
445                                 lua_rawgeti(L, index, i);
446                                 boxes.push_back(read_aabb3f(L, -1, scale));
447                                 lua_pop(L, 1);
448                         }
449                 }
450         }
451         return boxes;
452 }
453
454 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
455 {
456         if (index < 0)
457                 index = lua_gettop(L) + 1 + index;
458
459         size_t num_strings = 0;
460
461         if (lua_istable(L, index)) {
462                 lua_pushnil(L);
463                 while (lua_next(L, index)) {
464                         if (lua_isstring(L, -1)) {
465                                 result->push_back(lua_tostring(L, -1));
466                                 num_strings++;
467                         }
468                         lua_pop(L, 1);
469                 }
470         } else if (lua_isstring(L, index)) {
471                 result->push_back(lua_tostring(L, index));
472                 num_strings++;
473         }
474
475         return num_strings;
476 }
477
478 /*
479         Table field getters
480 */
481
482 #if defined(__MINGW32__) && !defined(__MINGW64__)
483 /* MinGW 32-bit somehow crashes in the std::set destructor when this
484  * variable is thread-local, so just don't do that. */
485 static std::set<u64> warned_msgs;
486 #endif
487
488 bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname)
489 {
490 #if !defined(__MINGW32__) || defined(__MINGW64__)
491         thread_local std::set<u64> warned_msgs;
492 #endif
493
494         int t = lua_type(L, index);
495         if (t == LUA_TNIL)
496                 return false;
497
498         if (t == type)
499                 return true;
500
501         // Check coercion types
502         if (type == LUA_TNUMBER) {
503                 if (lua_isnumber(L, index))
504                         return true;
505         } else if (type == LUA_TSTRING) {
506                 if (lua_isstring(L, index))
507                         return true;
508         }
509
510         // Types mismatch. Log unique line.
511         std::string backtrace = std::string("Invalid field ") + fieldname +
512                 " (expected " + lua_typename(L, type) +
513                 " got " + lua_typename(L, t) + ").\n" + script_get_backtrace(L);
514
515         u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE);
516         if (warned_msgs.find(hash) == warned_msgs.end()) {
517                 errorstream << backtrace << std::endl;
518                 warned_msgs.insert(hash);
519         }
520
521         return false;
522 }
523
524 bool getstringfield(lua_State *L, int table,
525                 const char *fieldname, std::string &result)
526 {
527         lua_getfield(L, table, fieldname);
528         bool got = false;
529
530         if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) {
531                 size_t len = 0;
532                 const char *ptr = lua_tolstring(L, -1, &len);
533                 if (ptr) {
534                         result.assign(ptr, len);
535                         got = true;
536                 }
537         }
538         lua_pop(L, 1);
539         return got;
540 }
541
542 bool getfloatfield(lua_State *L, int table,
543                 const char *fieldname, float &result)
544 {
545         lua_getfield(L, table, fieldname);
546         bool got = false;
547
548         if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) {
549                 result = lua_tonumber(L, -1);
550                 got = true;
551         }
552         lua_pop(L, 1);
553         return got;
554 }
555
556 bool getboolfield(lua_State *L, int table,
557                 const char *fieldname, bool &result)
558 {
559         lua_getfield(L, table, fieldname);
560         bool got = false;
561
562         if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){
563                 result = lua_toboolean(L, -1);
564                 got = true;
565         }
566         lua_pop(L, 1);
567         return got;
568 }
569
570 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
571                 std::vector<std::string> *result)
572 {
573         lua_getfield(L, table, fieldname);
574
575         size_t num_strings_read = read_stringlist(L, -1, result);
576
577         lua_pop(L, 1);
578         return num_strings_read;
579 }
580
581 std::string getstringfield_default(lua_State *L, int table,
582                 const char *fieldname, const std::string &default_)
583 {
584         std::string result = default_;
585         getstringfield(L, table, fieldname, result);
586         return result;
587 }
588
589 int getintfield_default(lua_State *L, int table,
590                 const char *fieldname, int default_)
591 {
592         int result = default_;
593         getintfield(L, table, fieldname, result);
594         return result;
595 }
596
597 float getfloatfield_default(lua_State *L, int table,
598                 const char *fieldname, float default_)
599 {
600         float result = default_;
601         getfloatfield(L, table, fieldname, result);
602         return result;
603 }
604
605 bool getboolfield_default(lua_State *L, int table,
606                 const char *fieldname, bool default_)
607 {
608         bool result = default_;
609         getboolfield(L, table, fieldname, result);
610         return result;
611 }
612
613 v3s16 getv3s16field_default(lua_State *L, int table,
614                 const char *fieldname, v3s16 default_)
615 {
616         getv3intfield(L, table, fieldname, default_);
617         return default_;
618 }
619
620 void setstringfield(lua_State *L, int table,
621                 const char *fieldname, const std::string &value)
622 {
623         lua_pushlstring(L, value.c_str(), value.length());
624         if(table < 0)
625                 table -= 1;
626         lua_setfield(L, table, fieldname);
627 }
628
629 void setintfield(lua_State *L, int table,
630                 const char *fieldname, int value)
631 {
632         lua_pushinteger(L, value);
633         if(table < 0)
634                 table -= 1;
635         lua_setfield(L, table, fieldname);
636 }
637
638 void setfloatfield(lua_State *L, int table,
639                 const char *fieldname, float value)
640 {
641         lua_pushnumber(L, value);
642         if(table < 0)
643                 table -= 1;
644         lua_setfield(L, table, fieldname);
645 }
646
647 void setboolfield(lua_State *L, int table,
648                 const char *fieldname, bool value)
649 {
650         lua_pushboolean(L, value);
651         if(table < 0)
652                 table -= 1;
653         lua_setfield(L, table, fieldname);
654 }
655
656
657 ////
658 //// Array table slices
659 ////
660
661 size_t write_array_slice_float(
662         lua_State *L,
663         int table_index,
664         float *data,
665         v3u16 data_size,
666         v3u16 slice_offset,
667         v3u16 slice_size)
668 {
669         v3u16 pmin, pmax(data_size);
670
671         if (slice_offset.X > 0) {
672                 slice_offset.X--;
673                 pmin.X = slice_offset.X;
674                 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
675         }
676
677         if (slice_offset.Y > 0) {
678                 slice_offset.Y--;
679                 pmin.Y = slice_offset.Y;
680                 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
681         }
682
683         if (slice_offset.Z > 0) {
684                 slice_offset.Z--;
685                 pmin.Z = slice_offset.Z;
686                 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
687         }
688
689         const u32 ystride = data_size.X;
690         const u32 zstride = data_size.X * data_size.Y;
691
692         u32 elem_index = 1;
693         for (u32 z = pmin.Z; z != pmax.Z; z++)
694         for (u32 y = pmin.Y; y != pmax.Y; y++)
695         for (u32 x = pmin.X; x != pmax.X; x++) {
696                 u32 i = z * zstride + y * ystride + x;
697                 lua_pushnumber(L, data[i]);
698                 lua_rawseti(L, table_index, elem_index);
699                 elem_index++;
700         }
701
702         return elem_index - 1;
703 }