Reputation: 806
I would like to decode a string of a large file in c++.
The size of the chain is: 1827500 characters and the file is: 1370626 bytes
My problem is that the decoding function does not work. The decoded file is different from the original file.
Below are two ways I've tried
First :
char *base64_decode(const std::string &input, long *size)
{
BIO *p_bio_mem = nullptr;
BIO *p_bio_b64 = nullptr;
char *retrnvalue;
p_bio_b64 = BIO_new(BIO_f_base64());
if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); }
BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines
p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length());
if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); }
BIO_push(p_bio_b64, p_bio_mem);
// read result from chain
// read sequence (reverse to write): buf <<-- p_bio_b64 <<-- p_bio_mem
std::vector<char> buf((input.size() * 3 / 4) + 1);
std::string result;
for (;;)
{
auto nread = BIO_read(p_bio_b64, buf.data(), buf.size());
if (nread < 0) { return NULL; //fail}
if (nread == 0) { break; } // eof
result.append(buf.data(), nread);
}
BIO_free_all(p_bio_b64);
*size = buf.size();
retrnvalue = new char[*size];
memcpy(retrnvalue, buf.data(), *size);
return retrnvalue;
}
Second:
Code from here : How do I base64 encode (decode) in C?
Some end of lines are different:
But not the entire file:
Can you tell me why? and / or tell me another way to encode a file for easy transfert ?
I have this in input : drive.google.com/file/d/0B1i4Ez8N86wFblJnaFF6YVNVTWs/view
And i want this in output : drive.google.com/file/d/0B1i4Ez8N86wFdl9OUE5UMFB3R28/view
(sorry i can't put more than 2 links)
PS: When i decode with "certutil -decode" in batch, it works without problems.
SOLVED : Problem solved, the problem was fwrite . Fix with ofstream write function
Upvotes: 1
Views: 1534
Reputation: 806
SOLVED : Problem solved, the problem was fwrite . Fix with ofstream write function
Upvotes: 1
Reputation: 30494
Your code to read the base64-ed data is pretty messed up:
std::vector<char> buf((input.size() * 3 / 4) + 1);
std::string result;
for (;;)
{
auto nread = BIO_read(p_bio_b64, buf.data(), buf.size());
if (nread < 0) { return NULL; } //fail
if (nread == 0) { break; } // eof
result.append(buf.data(), nread);
}
BIO_free_all(p_bio_b64);
*size = buf.size();
retrnvalue = new char[*size];
memcpy(retrnvalue, buf.data(), *size);
return retrnvalue;
You read your data into a string called result
, but you never do anything with it. Then you copy the contents of your scratch buffer into your output buffer. You could also do away with your size
pointer, and just return a std::string
instead of a raw char*
.
Another possible issue is the line
BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines
If your input does contain newlines, then that line will cause problems. If you want to work with input that may or may not contain newlines, you'll need to make that line conditional:
if (input.find('\n') == std::string::npos) {
BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines
}
All together, that would look something like this:
std::string base64_decode(const std::string &input)
{
BIO *p_bio_mem = nullptr;
BIO *p_bio_b64 = nullptr;
p_bio_b64 = BIO_new(BIO_f_base64());
if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); }
if (input.find('\n') == std::string::npos) {
BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines
}
p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length());
if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); }
BIO_push(p_bio_b64, p_bio_mem);
std::stringstream result;
std::vector<char> buf(1024);
while (auto nread = BIO_read(p_bio_b64, buf.data(), buf.size()))
{
if (nread < 0) { throw std::runtime_error("OMGZ"); } //fail
result.write(buf.data(), nread);
}
BIO_free_all(p_bio_b64);
return result.str();
}
You'll also probably want to add some error handling to clean up your BIO
instances in case of error (like in the answer you linked to), but that isn't what's causing the wrong result.
Upvotes: 1