3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
24 #include "convert_json.h"
28 #include "main.h" // for g_settings
33 #include <curl/curl.h>
35 static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
37 ((std::string*)userp)->append((char*)contents, size * nmemb);
43 Json::Value fetchJsonValue(const std::string url,
44 struct curl_slist *chunk) {
46 std::string liststring;
49 curl = curl_easy_init();
54 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
55 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
56 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
57 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
58 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, g_settings->getS32("curl_timeout"));
59 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, g_settings->getS32("curl_timeout"));
60 curl_easy_setopt(curl, CURLOPT_USERAGENT, (std::string("Minetest ")+minetest_version_hash).c_str());
63 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
65 res = curl_easy_perform(curl);
67 errorstream<<"Jsonreader: "<< url <<" not found (" << curl_easy_strerror(res) << ")" <<std::endl;
68 curl_easy_cleanup(curl);
73 std::istringstream stream(liststring);
74 if (!liststring.size()) {
78 if (!reader.parse( stream, root ) )
80 errorstream << "URL: " << url << std::endl;
81 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
82 errorstream << "data: \"" << liststring << "\"" << std::endl;
89 if ((root["list"].isArray())) {
99 std::vector<ModStoreMod> readModStoreList(Json::Value& modlist) {
100 std::vector<ModStoreMod> retval;
102 if (modlist.isArray()) {
103 for (unsigned int i = 0; i < modlist.size(); i++)
109 if (modlist[i]["id"].asString().size()) {
110 std::string id_raw = modlist[i]["id"].asString();
112 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
114 if ((id_raw != "") && (*endptr == 0)) {
115 toadd.id = numbervalue;
118 errorstream << "readModStoreList: missing id" << std::endl;
123 errorstream << "readModStoreList: missing id" << std::endl;
128 if (modlist[i]["title"].asString().size()) {
129 toadd.title = modlist[i]["title"].asString();
132 errorstream << "readModStoreList: missing title" << std::endl;
137 if (modlist[i]["basename"].asString().size()) {
138 toadd.basename = modlist[i]["basename"].asString();
141 errorstream << "readModStoreList: missing basename" << std::endl;
152 retval.push_back(toadd);
159 ModStoreModDetails readModStoreModDetails(Json::Value& details) {
161 ModStoreModDetails retval;
166 if (details["version_set"].isArray()) {
167 for (unsigned int i = 0; i < details["version_set"].size(); i++)
169 ModStoreVersionEntry toadd;
171 if (details["version_set"][i]["id"].asString().size()) {
172 std::string id_raw = details["version_set"][i]["id"].asString();
174 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
176 if ((id_raw != "") && (*endptr == 0)) {
177 toadd.id = numbervalue;
181 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
182 retval.valid = false;
186 if (details["version_set"][i]["date"].asString().size()) {
187 toadd.date = details["version_set"][i]["date"].asString();
191 if (details["version_set"][i]["file"].asString().size()) {
192 toadd.file = details["version_set"][i]["file"].asString();
195 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
196 retval.valid = false;
204 retval.versions.push_back(toadd);
212 if (retval.versions.size() < 1) {
213 infostream << "readModStoreModDetails: not a single version specified!" << std::endl;
214 retval.valid = false;
218 if (details["categories"].isObject()) {
219 for (unsigned int i = 0; i < details["categories"].size(); i++) {
220 ModStoreCategoryInfo toadd;
222 if (details["categories"][i]["id"].asString().size()) {
224 std::string id_raw = details["categories"][i]["id"].asString();
226 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
228 if ((id_raw != "") && (*endptr == 0)) {
229 toadd.id = numbervalue;
233 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
234 retval.valid = false;
236 if (details["categories"][i]["title"].asString().size()) {
237 toadd.name = details["categories"][i]["title"].asString();
240 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
241 retval.valid = false;
245 retval.categories.push_back(toadd);
254 if (details["author"].isObject()) {
255 if (details["author"]["id"].asString().size()) {
257 std::string id_raw = details["author"]["id"].asString();
259 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
261 if ((id_raw != "") && (*endptr == 0)) {
262 retval.author.id = numbervalue;
265 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
266 retval.valid = false;
270 errorstream << "readModStoreModDetails: missing author id" << std::endl;
271 retval.valid = false;
274 if (details["author"]["username"].asString().size()) {
275 retval.author.username = details["author"]["username"].asString();
278 errorstream << "readModStoreModDetails: missing author username" << std::endl;
279 retval.valid = false;
283 errorstream << "readModStoreModDetails: missing author" << std::endl;
284 retval.valid = false;
288 if (details["license"].isObject()) {
289 if (details["license"]["id"].asString().size()) {
291 std::string id_raw = details["license"]["id"].asString();
293 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
295 if ((id_raw != "") && (*endptr == 0)) {
296 retval.license.id = numbervalue;
300 errorstream << "readModStoreModDetails: missing license id" << std::endl;
301 retval.valid = false;
304 if (details["license"]["short"].asString().size()) {
305 retval.license.shortinfo = details["license"]["short"].asString();
308 errorstream << "readModStoreModDetails: missing license short" << std::endl;
309 retval.valid = false;
312 if (details["license"]["link"].asString().size()) {
313 retval.license.url = details["license"]["link"].asString();
319 if (details["titlepic"].isObject()) {
320 if (details["titlepic"]["id"].asString().size()) {
322 std::string id_raw = details["titlepic"]["id"].asString();
324 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
326 if ((id_raw != "") && (*endptr == 0)) {
327 retval.titlepic.id = numbervalue;
331 if (details["titlepic"]["file"].asString().size()) {
332 retval.titlepic.file = details["titlepic"]["file"].asString();
335 if (details["titlepic"]["desc"].asString().size()) {
336 retval.titlepic.description = details["titlepic"]["desc"].asString();
339 if (details["titlepic"]["mod"].asString().size()) {
341 std::string mod_raw = details["titlepic"]["mod"].asString();
343 int numbervalue = strtol(mod_raw.c_str(),&endptr,10);
345 if ((mod_raw != "") && (*endptr == 0)) {
346 retval.titlepic.mod = numbervalue;
352 if (details["id"].asString().size()) {
354 std::string id_raw = details["id"].asString();
356 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
358 if ((id_raw != "") && (*endptr == 0)) {
359 retval.id = numbervalue;
363 errorstream << "readModStoreModDetails: missing id" << std::endl;
364 retval.valid = false;
368 if (details["title"].asString().size()) {
369 retval.title = details["title"].asString();
372 errorstream << "readModStoreModDetails: missing title" << std::endl;
373 retval.valid = false;
377 if (details["basename"].asString().size()) {
378 retval.basename = details["basename"].asString();
381 errorstream << "readModStoreModDetails: missing basename" << std::endl;
382 retval.valid = false;
386 if (details["desc"].asString().size()) {
387 retval.description = details["desc"].asString();
391 if (details["replink"].asString().size()) {
392 retval.repository = details["replink"].asString();
396 if (details["rating"].asString().size()) {
398 std::string id_raw = details["rating"].asString();
400 float numbervalue = strtof(id_raw.c_str(),&endptr);
402 if ((id_raw != "") && (*endptr == 0)) {
403 retval.rating = numbervalue;
411 if (details["depends"].isArray()) {
416 if (details["softdep"].isArray()) {
421 if (details["screenshot_url"].asString().size()) {
422 retval.screenshot_url = details["screenshot_url"].asString();