Fix invalid use of pointer to temporary object in json2lua conversion
[oweals/minetest.git] / src / convert_json.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 #include <vector>
21 #include <iostream>
22 #include <sstream>
23
24 #include "convert_json.h"
25 #include "mods.h"
26 #include "config.h"
27 #include "log.h"
28 #include "main.h" // for g_settings
29 #include "settings.h"
30
31 #if USE_CURL
32 #include <curl/curl.h>
33
34 static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
35 {
36     ((std::string*)userp)->append((char*)contents, size * nmemb);
37     return size * nmemb;
38 }
39
40 #endif
41
42 Json::Value                 fetchJsonValue(const std::string url,
43                                                                                                         struct curl_slist *chunk) {
44 #if USE_CURL
45         std::string liststring;
46         CURL *curl;
47
48         curl = curl_easy_init();
49         if (curl)
50         {
51                 CURLcode res;
52
53                 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
54                 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
55                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
56                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
57                 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, g_settings->getS32("curl_timeout"));
58                 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, g_settings->getS32("curl_timeout"));
59
60                 if (chunk != 0)
61                         curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
62
63                 res = curl_easy_perform(curl);
64                 if (res != CURLE_OK)
65                         errorstream<<"Jsonreader: "<< url <<" not found (" << curl_easy_strerror(res) << ")" <<std::endl;
66                 curl_easy_cleanup(curl);
67         }
68
69         Json::Value root;
70         Json::Reader reader;
71         std::istringstream stream(liststring);
72         if (!liststring.size()) {
73                 return Json::Value();
74         }
75
76         if (!reader.parse( stream, root ) )
77         {
78                 errorstream << "URL: " << url << std::endl;
79                 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
80                 errorstream << "data: \"" << liststring << "\"" << std::endl;
81                 return Json::Value();
82         }
83
84         if (root.isArray()) {
85                 return root;
86         }
87         if ((root["list"].isArray())) {
88                 return root["list"];
89         }
90         else {
91                 return root;
92         }
93 #endif
94         return Json::Value();
95 }
96
97 std::vector<ModStoreMod>    readModStoreList(Json::Value& modlist) {
98         std::vector<ModStoreMod> retval;
99
100         if (modlist.isArray()) {
101                 for (unsigned int i = 0; i < modlist.size(); i++)
102                 {
103                         ModStoreMod toadd;
104                         toadd.valid = true;
105
106                         //id
107                         if (modlist[i]["id"].asString().size()) {
108                                 std::string id_raw = modlist[i]["id"].asString();
109                                 char* endptr = 0;
110                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
111
112                                 if ((id_raw != "") && (*endptr == 0)) {
113                                         toadd.id = numbervalue;
114                                 }
115                                 else {
116                                         errorstream << "readModStoreList: missing id" << std::endl;
117                                         toadd.valid = false;
118                                 }
119                         }
120                         else {
121                                 errorstream << "readModStoreList: missing id" << std::endl;
122                                 toadd.valid = false;
123                         }
124
125                         //title
126                         if (modlist[i]["title"].asString().size()) {
127                                 toadd.title = modlist[i]["title"].asString();
128                         }
129                         else {
130                                 errorstream << "readModStoreList: missing title" << std::endl;
131                                 toadd.valid = false;
132                         }
133
134                         //basename
135                         if (modlist[i]["basename"].asString().size()) {
136                                 toadd.basename = modlist[i]["basename"].asString();
137                         }
138                         else {
139                                 errorstream << "readModStoreList: missing basename" << std::endl;
140                                 toadd.valid = false;
141                         }
142
143                         //author
144
145                         //rating
146
147                         //version
148
149                         if (toadd.valid) {
150                                 retval.push_back(toadd);
151                         }
152                 }
153         }
154         return retval;
155 }
156
157 ModStoreModDetails          readModStoreModDetails(Json::Value& details) {
158
159         ModStoreModDetails retval;
160
161         retval.valid = true;
162
163         //version set
164         if (details["version_set"].isArray()) {
165                 for (unsigned int i = 0; i < details["version_set"].size(); i++)
166                 {
167                         ModStoreVersionEntry toadd;
168
169                         if (details["version_set"][i]["id"].asString().size()) {
170                                 std::string id_raw = details["version_set"][i]["id"].asString();
171                                 char* endptr = 0;
172                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
173
174                                 if ((id_raw != "") && (*endptr == 0)) {
175                                         toadd.id = numbervalue;
176                                 }
177                         }
178                         else {
179                                 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
180                                 retval.valid = false;
181                         }
182
183                         //date
184                         if (details["version_set"][i]["date"].asString().size()) {
185                                 toadd.date = details["version_set"][i]["date"].asString();
186                         }
187
188                         //file
189                         if (details["version_set"][i]["file"].asString().size()) {
190                                 toadd.file = details["version_set"][i]["file"].asString();
191                         }
192                         else {
193                                 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
194                                 retval.valid = false;
195                         }
196
197                         //approved
198
199                         //mtversion
200
201                         if( retval.valid ) {
202                                 retval.versions.push_back(toadd);
203                         }
204                         else {
205                                 break;
206                         }
207                 }
208         }
209
210         if (retval.versions.size() < 1) {
211                 errorstream << "readModStoreModDetails: not a single version specified!" << std::endl;
212                 retval.valid = false;
213         }
214
215         //categories
216         if (details["categories"].isObject()) {
217                 for (unsigned int i = 0; i < details["categories"].size(); i++) {
218                         ModStoreCategoryInfo toadd;
219
220                         if (details["categories"][i]["id"].asString().size()) {
221
222                                 std::string id_raw = details["categories"][i]["id"].asString();
223                                 char* endptr = 0;
224                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
225
226                                 if ((id_raw != "") && (*endptr == 0)) {
227                                         toadd.id = numbervalue;
228                                 }
229                         }
230                         else {
231                                 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
232                                 retval.valid = false;
233                         }
234                         if (details["categories"][i]["title"].asString().size()) {
235                                 toadd.name = details["categories"][i]["title"].asString();
236                         }
237                         else {
238                                 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
239                                 retval.valid = false;
240                         }
241
242                         if( retval.valid ) {
243                                 retval.categories.push_back(toadd);
244                         }
245                         else {
246                                 break;
247                         }
248                 }
249         }
250
251         //author
252         if (details["author"].isObject()) {
253                 if (details["author"]["id"].asString().size()) {
254
255                         std::string id_raw = details["author"]["id"].asString();
256                         char* endptr = 0;
257                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
258
259                         if ((id_raw != "") && (*endptr == 0)) {
260                                 retval.author.id = numbervalue;
261                         }
262                         else {
263                                 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
264                                 retval.valid = false;
265                         }
266                 }
267                 else {
268                         errorstream << "readModStoreModDetails: missing author id" << std::endl;
269                         retval.valid = false;
270                 }
271
272                 if (details["author"]["username"].asString().size()) {
273                         retval.author.username = details["author"]["username"].asString();
274                 }
275                 else {
276                         errorstream << "readModStoreModDetails: missing author username" << std::endl;
277                         retval.valid = false;
278                 }
279         }
280         else {
281                 errorstream << "readModStoreModDetails: missing author" << std::endl;
282                 retval.valid = false;
283         }
284
285         //license
286         if (details["license"].isObject()) {
287                 if (details["license"]["id"].asString().size()) {
288
289                         std::string id_raw = details["license"]["id"].asString();
290                         char* endptr = 0;
291                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
292
293                         if ((id_raw != "") && (*endptr == 0)) {
294                                 retval.license.id = numbervalue;
295                         }
296                 }
297                 else {
298                         errorstream << "readModStoreModDetails: missing license id" << std::endl;
299                         retval.valid = false;
300                 }
301
302                 if (details["license"]["short"].asString().size()) {
303                         retval.license.shortinfo = details["license"]["short"].asString();
304                 }
305                 else {
306                         errorstream << "readModStoreModDetails: missing license short" << std::endl;
307                         retval.valid = false;
308                 }
309
310                 if (details["license"]["link"].asString().size()) {
311                         retval.license.url = details["license"]["link"].asString();
312                 }
313
314         }
315
316         //titlepic
317         if (details["titlepic"].isObject()) {
318                 if (details["titlepic"]["id"].asString().size()) {
319
320                         std::string id_raw = details["titlepic"]["id"].asString();
321                         char* endptr = 0;
322                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
323
324                         if ((id_raw != "") && (*endptr == 0)) {
325                                 retval.titlepic.id = numbervalue;
326                         }
327                 }
328
329                 if (details["titlepic"]["file"].asString().size()) {
330                         retval.titlepic.file = details["titlepic"]["file"].asString();
331                 }
332
333                 if (details["titlepic"]["desc"].asString().size()) {
334                         retval.titlepic.description = details["titlepic"]["desc"].asString();
335                 }
336
337                 if (details["titlepic"]["mod"].asString().size()) {
338
339                         std::string mod_raw = details["titlepic"]["mod"].asString();
340                         char* endptr = 0;
341                         int numbervalue = strtol(mod_raw.c_str(),&endptr,10);
342
343                         if ((mod_raw != "") && (*endptr == 0)) {
344                                 retval.titlepic.mod = numbervalue;
345                         }
346                 }
347         }
348
349         //id
350         if (details["id"].asString().size()) {
351
352                 std::string id_raw = details["id"].asString();
353                 char* endptr = 0;
354                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
355
356                 if ((id_raw != "") && (*endptr == 0)) {
357                         retval.id = numbervalue;
358                 }
359         }
360         else {
361                 errorstream << "readModStoreModDetails: missing id" << std::endl;
362                 retval.valid = false;
363         }
364
365         //title
366         if (details["title"].asString().size()) {
367                 retval.title = details["title"].asString();
368         }
369         else {
370                 errorstream << "readModStoreModDetails: missing title" << std::endl;
371                 retval.valid = false;
372         }
373
374         //basename
375         if (details["basename"].asString().size()) {
376                 retval.basename = details["basename"].asString();
377         }
378         else {
379                 errorstream << "readModStoreModDetails: missing basename" << std::endl;
380                 retval.valid = false;
381         }
382
383         //description
384         if (details["desc"].asString().size()) {
385                 retval.description = details["desc"].asString();
386         }
387
388         //repository
389         if (details["replink"].asString().size()) {
390                 retval.repository = details["replink"].asString();
391         }
392
393         //value
394         if (details["rating"].asString().size()) {
395
396                 std::string id_raw = details["rating"].asString();
397                 char* endptr = 0;
398                 float numbervalue = strtof(id_raw.c_str(),&endptr);
399
400                 if ((id_raw != "") && (*endptr == 0)) {
401                         retval.rating = numbervalue;
402                 }
403         }
404         else {
405                 retval.rating = 0.0;
406         }
407
408         //depends
409         if (details["depends"].isArray()) {
410                 //TODO
411         }
412
413         //softdepends
414         if (details["softdep"].isArray()) {
415                 //TODO
416         }
417
418         //screenshot url
419         if (details["screenshot_url"].asString().size()) {
420                 retval.screenshot_url = details["screenshot_url"].asString();
421         }
422
423         return retval;
424 }