Reputation: 153
For days I have been trying to read an entire PNG into a string, so I can upload it to a server via winsock2, it appears to stop reading the file after a few characters or a some sort of line break, is there any particular reason and a way of solving it.
I have tried many many solutions and this is now starting to drive me insane. The current code I am using is as follows
std::ifstream in ("some.png", ios::in|ios::binary|ios::ate );
std::string contents;
if (in)
{
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
in.close();
length = contents.size();
}
I have no idea what the problem could be, as I am relatively new to c++, I have trolled through google for days with no working solution.
Please help
UPDATE code posting to the server
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return;
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0)
throw;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_port = htons(80);
LPHOSTENT host = gethostbyname("127.0.0.1");
if (!host)
throw;
service.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
if (connect(fd, (SOCKADDR *)&service, sizeof(service)) < 0)
throw;
int length ;
std::ifstream in (CCFileUtils::fullPathFromRelativePath("back.png"), ios::in|ios::binary|ios::ate );
std::string contents;
if (in){
in.seekg(0, in.end);
contents.resize(in.tellg());
in.seekg(0, in.beg);
in.read(&contents[0], contents.size());
in.close();
length = contents.size();
}else
std::string str =
"POST /index.php HTTP/1.1\r\n"
"Host: metapps.co.uk\r\n"
"Accept: */*\r\n";
char buffer1 [50];
str.append( "Content-Length: 121\r\n" );
str.append( "\r\n" );
str.append( "Content-Disposition: form-data; name=\"tmp\";filename=\"photo.png\"\r\n" );
str.append( "Content-Type: image/dds\r\n" );
sprintf (buffer1, "Content-Length: %d\r\n", length);
str.append( buffer1 );
str.append( contents );
str.append( "\r\n\x01A\r\n" );
// send str ...
send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
char ret[1024];
recv(fd,ret,strlen(ret),0);
closesocket(fd);
WSACleanup();
}
Update 2
Its something to do with the Null terminator string and the append method
If I do
str.append( "he\0llo" );
The server will only show "he"
If I do
str.append( "hello" );
I get hello, hopefully this info, can lead to a solution
Upvotes: 2
Views: 986
Reputation: 153
I solved it!
The header Content-length I was sending were a fixed length of 121
str.append( "Content-Length: 121\r\n" );
So the server was therefore truncating the message body to this length, I had no idea the server took this value so seriously, if it were too big it would also throw a 500 error.
Sending the correct length for the message body fixed it.
I also separated the headers from the message body and used a
std::vector<char>
to store the message body as per @youdontneedtothankme
Thanks for all replies and comments, helped me get to the bottom of the issue after one long week of frustration, my life can now move on lol :)
Stackoverflow FTW!
Upvotes: 0
Reputation: 392999
One way[1]:
std::ifstream in("some.png", ios::binary);
std::vector<unsigned char> contents(std::istreambuf_iterator<char>(in), {});
Another
std::ostringstream oss;
oss << in.rdbuf();
std::string contents = iss.str();
As others have noted, it's usually not necessary to have the full contents in memory at a single time, though. It leads to problems with scalability. Avoid it if at all possible.
[1] If your compiler is standards challenged, break it up:
std::istreambuf_iterator<char> f(in), l;
std::vector<unsigned char> contents(f, l);
Upvotes: 1
Reputation: 672
You are using &contents[0]
to get the address of the internal buffer used by the string. As far as I know, this buffer is not guaranteed to be sequentiental, or even have the right size before you call .c_str(), so you just can't pass the address around.
Use std::vector<char>
or std::array<char, n>
for raw binary data. They are allways guaranteed to have sequential buffers.
Oh, and by the way, there is no need to read the whole file into one big buffer. Just read and write it piecewise.
Upvotes: 0
Reputation: 66922
send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
char ret[1024];
strlen( str.c_str() ) +1
will tell you the position of the first 0 byte in the output, and is NOT the length of the string. The length of the string is best optained via str.size()
instead.
Also, as WhosCraig mentioned, you're calling strlen(ret)
where ret
is uninitialized. Instead, use
std::array<char, 1024> ret;
recv(fd,ret,ret.size(),0);
or potentially something more dynamic.
Upvotes: 3