I'm getting a response from a server using boost::asio. The result is stored in a std::string.
I want to convert this std::string into a .png image and write it to file.
I'm having awful trouble with this. Here is my code:
CURL *curl;
CURLcode res;
std::string errorBuffer[CURL_ERROR_SIZE];
std::string url="http://www.google.ie/images/srpr/logo3w.png";
std::string response="";
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res=curl_easy_perform(curl);
curl_easy_cleanup(curl);
response now stored in response
write_to_binary_file(response.data());
, where write_to_binary_file is:
void write_to_binary_file(std::string p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.close();
std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,sizeof(p_Data));
file.close();
}
Now if I do an octal dump on the file written by my C++ program, it's totally different to the octal dump I get when I download the file from the URL directly.
Updated write_to_binary_file
int write_to_binary_file(const char* p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.write(c_str(),sizeof(ring));
//binary_file.close();
/*std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,len);
file.close();*/
FILE *fp;
size_t count;
const char *str = p_Data;
fp = fopen("img.png", "w");
if(fp == NULL) {
perror("failed to open img.png");
return EXIT_FAILURE;
}
count = fwrite(str, 1, strlen(str), fp);
printf("Wrote %zu bytes. fclose(fp) %s.\n", count, fclose(fp) == 0 ? "succeeded" : "failed");
return EXIT_SUCCESS;
}
Call using int x=write_to_binary_file(response.c_str());
Still won't work for me ;(
You might want to consider using SFML for such a task, given it deals with HTTP and greatly simplifies the task. I've personally used it download .GIF images from a website.
To address your question (I am admittedly not familiar with boost::asio), the things you will want to consider is:
Don't do sizeof(std::string). Std::string has a .size() method. So response.size(); is applicable here.
Don't use strlen(), sizeof() or any method that uses a null-terminated sentinel value when dealing with raw data from a website, as a null-value can occur anywhere in the raw data stream (it isn't like text). Use std::string's .size() method.
Given it's raw data, write in binary mode! Text mode will terminate on the ctrl+z signal within a file on windows. IE it'd likely not fully write the file.
Base64 doesn't always apply. Chances are this is automated anyway.
Consider extracting the filename from the supplied URL itself.
Assuming response is acceptable, this is the code you want:
Right, this is why
reinterpret_cast
is poor in many scenarios: it promotes guesscoding.This is when you've thrown away your reference materials and just assumed that you need to pass a pointer to an
std::string
somewhere, and decided that the compiler's error messages were wrong. So, you usedreinterpret_cast
to "shut it up", and now you're wondering why nothing's working properly.Presumably somebody has told you to "use
std::string
" instead of char arrays, and you've just swapped the type names rather than doing any research into what the actual difference is.std::string
is an object with various internal members, and which usually stores its actual string data indirectly (dynamically, or what you may inaccurately and misleadingly refer to as "on the heap"); in fact, it's completely abstracted away from you as to just how it stores its data. Either way, it's not just achar
array.Use the API that it provides to obtain a pointer to a
char
array, with eitherstd::string::data()
or possiblystd::string::c_str()
... and stop guesscoding.Also, I doubt that this compiles:
And you probably wanted to construct a
std::string
with a certain length:Strings are objects, not raw arrays!
My first guess would be that "reinterpret_cast(&p_Data)" is messing up your data. Why do you cast it in this way? p_Data.data() or p_Data.c_str() are probably what you want.
look what is the contents of your responce string. probably you should decode it by base64 decoder before writing into file