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