1
0
Fork 0
mirror of https://github.com/HamletDuFromage/sigpatches-updater.git synced 2024-09-19 21:43:50 +01:00
sigpatches-updater/source/download.cpp
2020-09-12 18:12:07 +02:00

201 lines
5.6 KiB
C++

#include "download.hpp"
#include "utils.hpp"
#include <algorithm>
#define API_AGENT "HamletDuFromage"
#define _1MiB 0x100000
typedef struct
{
char *memory;
size_t size;
} MemoryStruct_t;
typedef struct
{
u_int8_t *data;
size_t data_size;
u_int64_t offset;
FILE *out;
} ntwrk_struct_t;
static size_t WriteMemoryCallback(void *contents, size_t size, size_t num_files, void *userp)
{
ntwrk_struct_t *data_struct = (ntwrk_struct_t *)userp;
size_t realsize = size * num_files;
if (realsize + data_struct->offset >= data_struct->data_size)
{
fwrite(data_struct->data, data_struct->offset, 1, data_struct->out);
data_struct->offset = 0;
}
memcpy(&data_struct->data[data_struct->offset], contents, realsize);
data_struct->offset += realsize;
data_struct->data[data_struct->offset] = 0;
return realsize;
}
int download_progress(void *p, double dltotal, double dlnow, double ultotal, double ulnow)
{
if (dltotal <= 0.0) return 0;
struct timeval tv = {0};
gettimeofday(&tv, NULL);
int counter = round(tv.tv_usec / 100000);
if (counter == 0 || counter == 2 || counter == 4 || counter == 6 || counter == 8)
{
printf("*** DOWNLOADING: %.2fMB of %.2fMB ***\r", dlnow / _1MiB, dltotal / _1MiB);
consoleUpdate(NULL);
}
return 0;
}
bool downloadFile(const char *url, const char *output, int api)
{
CURL *curl = curl_easy_init();
if (curl)
{
FILE *fp = fopen(output, "wb");
if (fp)
{
printf("\n");
ntwrk_struct_t chunk = {0};
chunk.data = static_cast<u_int8_t *>(malloc(_1MiB));
chunk.data_size = _1MiB;
chunk.out = fp;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, API_AGENT);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
// write calls
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
if (api == OFF)
{
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, download_progress);
}
// execute curl, save result
CURLcode res = curl_easy_perform(curl);
// write from mem to file
if (chunk.offset)
fwrite(chunk.data, 1, chunk.offset, fp);
// clean
curl_easy_cleanup(curl);
free(chunk.data);
fclose(chunk.out);
if (res == CURLE_OK)
{
std::cout << std::endl;
consoleUpdate(NULL);
return true;
}
}
}
consoleUpdate(NULL);
return false;
}
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback2(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = static_cast<char *>(realloc(mem->memory, mem->size + realsize + 1));
if(ptr == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
std::tuple<std::vector<std::string>, std::vector<std::string>> fetchLinks(const char *url){
CURL *curl_handle;
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = static_cast<char *>(malloc(1)); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback2);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, API_AGENT);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
/* get it! */
res = curl_easy_perform(curl_handle);
std::tuple <std::vector<std::string>, std::vector<std::string>> links;
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() for page fetching failed: %s\n",
curl_easy_strerror(res));
}
else {
std::string s = std::string(chunk.memory);
//<a href=.*?> links
//>(?:(?!>).)*?</a> titles
auto titles = htmlProcess(s, std::regex(">(?:(?!>).)*?</a>"));
std::transform(titles.begin(), titles.end(), titles.begin(),
[](std::string s) -> std::string {return s.substr(1, s.size() - 1 - 4);});
auto targets = htmlProcess(s, std::regex("<a href=.*?>"));
std::transform(targets.begin(), targets.end(), targets.begin(),
[](std::string s) -> std::string {return s.substr(8, s.size() - 8 - 2);});
links = std::make_tuple(titles, targets);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return links;
}