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