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