-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetch.hpp
146 lines (117 loc) · 3.69 KB
/
fetch.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// ---------------------------------------------------------------------------
// This software is in the public domain, furnished "as is", without technical
// support, and with no warranty, express or implied, as to its usefulness for
// any purpose.
//
// FETCH.HPP
// Fetch class is used to download a range of tiles from a tileserver
//
// Author: Thomas Brüggemann
// ---------------------------------------------------------------------------
#ifndef FETCH_HPP
#define FETCH_HPP
#include <curl/curl.h>
#include <curl/easy.h>
#include <curl/curlbuild.h>
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include "patches.hpp"
size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream)
{
std::string data((const char*) ptr, (size_t) size * nmemb);
*((std::stringstream*) stream) << data;
return size * nmemb;
}
class Fetch
{
private:
void* curl;
inline bool replace(std::string& str, const std::string& from, const std::string& to);
public:
Fetch();
~Fetch();
inline std::string fromUrl(std::string url, int zoom, int x, int y);
inline bool saveFromUrl(std::string url, int zoom, int x, int y, std::string fileName);
};
// CONSTRUCTOR
Fetch::Fetch()
{
curl = curl_easy_init();
};
// DESTRUCTOR
Fetch::~Fetch()
{
curl_easy_cleanup(curl);
};
// REPLACE
// replaces the first occurancy of a string with another string
inline bool Fetch::replace(std::string& str, const std::string& from, const std::string& to)
{
size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
{
return false;
}
str.replace(start_pos, from.length(), to);
return true;
};
// FROM URL
// url would be something like 'http://a.tile.osm.org/{z}/{x}/{y}.png'
inline std::string Fetch::fromUrl(std::string url, int zoom, int x, int y)
{
// replace the zoom, x and y parameters to the url
this->replace(url, "{z}", patches::to_string(zoom));
this->replace(url, "{x}", patches::to_string(x));
this->replace(url, "{y}", patches::to_string(y));
std::cout << "Download " << url << " ... ";
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// example.com is redirected, so we tell libcurl to follow redirection
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); // prevent "longjmp causes uninitialized stack frame" bug
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);
std::stringstream out;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
// perform the request, res will get the return code
CURLcode res = curl_easy_perform(curl);
// check for errors
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
// return the resulting content
std::string result(out.str());
return result;
};
// SAVE FROM URL
// fetches the content from url and saves it to a file on disk
inline bool Fetch::saveFromUrl(std::string url, int zoom, int x, int y, std::string fileName)
{
// replace the zoom, x and y parameters to the filename
this->replace(fileName, "{z}", patches::to_string(zoom));
this->replace(fileName, "{x}", patches::to_string(x));
this->replace(fileName, "{y}", patches::to_string(y));
// check if file exists
std::ifstream checkfile(fileName);
if(checkfile.good()) return true;
// fetch the content form url
std::string content = this->fromUrl(url, zoom, x, y);
// write to file
std::ofstream os(fileName.c_str());
if(!os)
{
return false;
}
os << content;
os.close();
std::cout << "done" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
return true;
};
#endif