Updated copyright header
[supertux.git] / src / addon / downloader.cpp
1 //  SuperTux
2 //  Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
3 //                2014 Ingo Ruhnke <grumbel@gmail.com>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 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 General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "addon/downloader.hpp"
19
20 #include <curl/curl.h>
21 #include <curl/easy.h>
22 #include <physfs.h>
23 #include <memory>
24 #include <stdexcept>
25
26 #include "util/log.hpp"
27 #include "version.h"
28
29 namespace {
30
31 size_t my_curl_string_append(void* ptr, size_t size, size_t nmemb, void* userdata)
32 {
33   std::string& s = *static_cast<std::string*>(userdata);
34   std::string buf(static_cast<char*>(ptr), size * nmemb);
35   s += buf;
36   log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
37   return size * nmemb;
38 }
39
40 size_t my_curl_physfs_write(void* ptr, size_t size, size_t nmemb, void* userdata)
41 {
42   PHYSFS_file* f = static_cast<PHYSFS_file*>(userdata);
43   PHYSFS_sint64 written = PHYSFS_write(f, ptr, size, nmemb);
44   log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
45   return size * written;
46 }
47
48 } // namespace
49
50 Downloader::Downloader()
51 {
52   curl_global_init(CURL_GLOBAL_ALL);
53 }
54
55 Downloader::~Downloader()
56 {
57   curl_global_cleanup();
58 }
59
60 void
61 Downloader::download(const std::string& url,
62                      size_t (*write_func)(void* ptr, size_t size, size_t nmemb, void* userdata),
63                      void* userdata)
64 {
65   log_info << "Downloading " << url << std::endl;
66
67   char error_buffer[CURL_ERROR_SIZE+1];
68
69   CURL* curl_handle = curl_easy_init();
70   curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
71   curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
72   curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_func);
73   curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, userdata);
74   curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
75   curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
76   curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
77   curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
78   curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
79   CURLcode result = curl_easy_perform(curl_handle);
80   curl_easy_cleanup(curl_handle);
81
82   if (result != CURLE_OK)
83   {
84     std::string why = error_buffer[0] ? error_buffer : "unhandled error";
85     throw std::runtime_error(url + ": download failed: " + why);
86   }
87 }
88
89 std::string
90 Downloader::download(const std::string& url)
91 {
92   std::string result;
93   download(url, my_curl_string_append, &result);
94   return result;
95 }
96
97 void
98 Downloader::download(const std::string& url, const std::string& filename)
99 {
100   std::unique_ptr<PHYSFS_file, int(*)(PHYSFS_File*)> fout(PHYSFS_openWrite(filename.c_str()),
101                                                           PHYSFS_close);
102   download(url, my_curl_physfs_write, fout.get());
103 }
104
105 /* EOF */