I've written this class that downloads an images, the URLs for which are read from a local .txt file. I'm keen to make sure my code is safe and efficient.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include<cassert>
#include <algorithm>
#include <numeric>
#include <functional>
#include <curl/curl.h>
class DownloadTesting
{
private:
CURL *curl;
FILE *file;
CURLcode response;
char outfilename[FILENAME_MAX];
int count {0};
std::vector<char*> URLS; //Stores the urls
auto DownloadImage(const char *url) -> void;
auto Convert(const std::string &s) -> char*;
auto ReadDataStore() -> void;
static auto WriteData(void *ptr, size_t size, size_t nmemb, FILE *stream) -> size_t;
public:
DownloadTesting();
~DownloadTesting();
auto Interface() -> void;
};
DownloadTesting::DownloadTesting(){};
DownloadTesting::~DownloadTesting()
{
if(!URLS.empty()) //Delete raw pointers
{
std::for_each(URLS.begin(),URLS.end(),[](char* url){delete url;});
}
}
auto DownloadTesting::WriteData(void *ptr, size_t size, size_t nmemb, FILE *stream) -> size_t //Write data into file
{
size_t written {fwrite(ptr, size, nmemb, stream)};
return written;
}
auto DownloadTesting::Convert(const std::string &s) -> char* //Convert url from std::string to raw char pointer
{
char *pc {new char[s.size()+1]};
std::strcpy(pc,s.c_str());
return pc;
}
auto DownloadTesting::ReadDataStore() -> void
{
std::vector<std::string> storage_vector;
std::string storage_string;
std::ifstream storage_file {"./imagestore/urlstore.txt"};
if(storage_file.is_open()) //Open local file
{
while(getline (storage_file,storage_string)) //Read each line
{
storage_vector.push_back(storage_string); //Storage each line in vector
}
storage_file.close();
}
std::transform(storage_vector.begin(), storage_vector.end(), std::back_inserter(URLS), [this](const std::string url){return this->Convert(url);}); //Perform conversion function on each url
}
auto DownloadTesting::DownloadImage(const char *url) -> void
{
count++; //Use a counter to name each downloaded file
std::string name {std::to_string(count)}; //Convert int to string
strcpy(outfilename, name.c_str()); //Convert std::string to [char]
curl = curl_easy_init(); //Initialise curl
if(curl)
{
file = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &DownloadTesting::WriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
response = curl_easy_perform(curl);
curl_easy_cleanup(curl); //Clean up curl
fclose(file); //Close file
}
}
auto DownloadTesting::Interface() -> void
{
this -> ReadDataStore(); //Read in the data
assert(!URLS.empty()); //Ensure data is not empty
std::for_each(URLS.begin(),URLS.end(), [this](const char* url){return this -> DownloadImage(url);}); //Perform download for each url
}
int main()
{
DownloadTesting DTO;
DTO.Interface();
}