1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "squirrel/serialize.hpp"
18
19#include <iostream>
20#include <sexp/value.hpp>
21#include <sexp/util.hpp>
22
23#include "squirrel/squirrel_error.hpp"
24#include "util/log.hpp"
25#include "util/reader_mapping.hpp"
26#include "util/writer.hpp"
27
28void load_squirrel_table(HSQUIRRELVM vm, SQInteger table_idx, const ReaderMapping& mapping)
29{
30 if (table_idx < 0)
31 table_idx -= 2;
32
33 auto const& arr = mapping.get_sexp().as_array();
34 for (size_t i = 1; i < arr.size(); ++i)
35 {
36 auto const& pair = arr[i].as_array();
37
38 // Ignore key value pairs with invalid length
39 if (pair.size() < 2)
40 {
41 log_debug << "Found key/value pair with invalid length. Ignoring." << std::endl;
42 continue;
43 }
44
45 const std::string& key = pair[0].as_string();
46 auto const& value = pair[1];
47
48 // ignore empty / null values
49 if (value.is_nil())
50 {
51 log_debug << "Found null value for key " << key << ". Ignoring." << std::endl;
52 continue;
53 }
54 // push the key
55 sq_pushstring(vm, key.c_str(), key.size());
56
57 // push the value
58 switch (value.get_type()) {
59 case sexp::Value::Type::ARRAY:
60 sq_newtable(vm);
61 load_squirrel_table(vm, sq_gettop(vm), ReaderMapping(mapping.get_doc(), arr[i]));
62 break;
63 case sexp::Value::Type::INTEGER:
64 sq_pushinteger(vm, value.as_int());
65 break;
66 case sexp::Value::Type::REAL:
67 sq_pushfloat(vm, value.as_float());
68 break;
69 case sexp::Value::Type::STRING:
70 sq_pushstring(vm, value.as_string().c_str(), -1);
71 break;
72 case sexp::Value::Type::BOOLEAN:
73 sq_pushbool(vm, value.as_bool() ? SQTrue : SQFalse);
74 break;
75 case sexp::Value::Type::SYMBOL:
76 log_fatal << "Unexpected symbol in file: " << value.as_string() << std::endl;
77 sq_pushnull(vm);
78 break;
79 default:
80 assert(false);
81 break;
82 }
83
84 if (SQ_FAILED(sq_createslot(vm, table_idx)))
85 throw SquirrelError(vm, "Couldn't create new index");
86 }
87}
88
89void save_squirrel_table(HSQUIRRELVM vm, SQInteger table_idx, Writer& writer)
90{
91 // offset because of sq_pushnull
92 if (table_idx < 0)
93 table_idx -= 1;
94
95 //iterator table
96 sq_pushnull(vm);
97 while (SQ_SUCCEEDED(sq_next(vm, table_idx))) {
98 if (sq_gettype(vm, -2) != OT_STRING) {
99 std::cerr << "Table contains non-string key\n";
100 continue;
101 }
102 const SQChar* key;
103 sq_getstring(vm, -2, &key);
104
105 switch (sq_gettype(vm, -1)) {
106 case OT_INTEGER: {
107 SQInteger val;
108 sq_getinteger(vm, -1, &val);
109 writer.write(key, static_cast<int> (val));
110 break;
111 }
112 case OT_FLOAT: {
113 SQFloat val;
114 sq_getfloat(vm, -1, &val);
115 writer.write(key, static_cast<float> (val));
116 break;
117 }
118 case OT_BOOL: {
119 SQBool val;
120 if (SQ_SUCCEEDED(sq_getbool(vm, -1, &val)))
121 writer.write(key, val == SQTrue);
122 break;
123 }
124 case OT_STRING: {
125 const SQChar* str;
126 sq_getstring(vm, -1, &str);
127 writer.write(key, reinterpret_cast<const char*> (str));
128 break;
129 }
130 case OT_TABLE: {
131 writer.start_list(key, true);
132 save_squirrel_table(vm, -1, writer);
133 writer.end_list(key);
134 break;
135 }
136 case OT_CLOSURE:
137 break; // ignore
138 case OT_NATIVECLOSURE:
139 break;
140 default:
141 std::cerr << "Can't serialize key '" << key << "' in table.\n";
142 break;
143 }
144 sq_pop(vm, 2);
145 }
146 sq_pop(vm, 1);
147}
148
149/* EOF */
150