3

I've got a class project to make a webserver in c++. Everything's been going OK until I got to the point where I needed to host images or pdfs, at which point the files were corrupted. Doing some more digging, I realized that all the corrupted images had null characters before the end.

That brings me to my question. I have a char* which I've read these files to, and I know the length of the file. I'm pretty positive that the entire file is being read in (code below), but I don't know how to print it out or send it. How can I tell C++ that I want to send the first X characters following the char*? (I'm sure the answer is somewhere here or on the web, I just can't seem to phrase my question in the right way to find the answer)

ifstream myfile (path.c_str() , ios::in|ios::binary|ios::ate);
ifstream::pos_type size = myfile.tellg();
cout << size << endl;
fileSize = (int) size;
fileToReturn = new char [size];
myfile.seekg (0, ios::beg);
myfile.read (fileToReturn, size);
myfile.close();

cout << "file read\n"<< fileToReturn << endl;

For a plain text file, this would output fine. For the PDF, it only prints the first part of the file (the part before the first null character). How do I get it to print out the whole file?

EDIT: To clarify, my end goal is to send this over the web, not re-save the file.

// reply is string with all my headers and everything set.
// fileToReturn is my char*, and fileSize is the int with how long it should be  
char* totalReply = new char [reply.length() + fileSize+1];
strcpy(totalReply, reply.c_str());
strcat(totalReply, fileToReturn);
send(client, totalReply, reply.length() + fileSize, 0);
Dr. Cyanide
  • 520
  • 1
  • 7
  • 21
  • 1
    If your data isn't "strings", why are you using strcpy, etc... use memcpy to prepare the buffer to be sent. – João Augusto Oct 26 '12 at 10:16
  • 1
    Looks like you are not quite sure what a "C string" is. It an array of 8-bit ASCII characters, ending at first \0 character. The byte array itself can be longer (for functions which take array length), but string functions *only* consider the part up to first \0 (even if array is actually shorter, in which case you get buffer overrun). – hyde Oct 26 '12 at 10:28
  • I originally started out using strings, which worked OK until I got to moving binary files, then I guess I forgot to change some things over. – Dr. Cyanide Oct 26 '12 at 10:31

2 Answers2

1

The issue is that ostream& operator<< (ostream& out, const char* s ); expects s to be a null-terminated ASCII string. So it stops as soon as it encounters a NUL character. If you really want to write all data to the console, use `ostream& write ( const char* s , streamsize n ), like this:

cout.write(fileToReturn, size);

The issue is the same for strcat: it stops after the first NUL character. So concatenate using memcpy:

memcpy(totalReply, reply.c_str(), reply.size()+1);
memcpy(totalReply+reply.size()+1, fileToReturn, fileSize )

But you tagged this question as C++, so why not do it like this:

ifstream myfile (path.c_str() , ios::in|ios::binary|ios::ate);
vector<char> totalReply;
totalReply.insert(buffer.end(), reply.begin(), reply.end());
// need a NUL character here?: totalReply.push_back('\0');
totalReply.insert(buffer.end(), istream_iterator(myfile), istream_iterator());
send(client, &totalReply[0], totalReply.size(), 0);
Daniel Gehriger
  • 7,339
  • 2
  • 34
  • 55
  • My ultimate problem is that I need to send this as a message over the web, I'm not writing it to a file. – Dr. Cyanide Oct 26 '12 at 10:07
  • Well - either the API you are using to "send this as a message over the web" exposes a stream interface and accepts receiving what is basically binary data; or it doesn't. In that case, you need to encode your data (base64, XML) on your side, and decode it on the receiving side. – Daniel Gehriger Oct 26 '12 at 10:09
  • Added the code that I'm using to send everything. It might also be a problem with the strcat – Dr. Cyanide Oct 26 '12 at 10:12
  • Same issue with `strcat`. Don't use any of the `str*` functions, but the `mem*` equivalents for binary data. – Daniel Gehriger Oct 26 '12 at 10:13
  • The syntax for the strcat is off (can only accept 2 parameters), but I think this is the right direction – Dr. Cyanide Oct 26 '12 at 10:21
  • Used the memcpy and that seems to have fixed the issue with the PDF. The images are looking better too, but still corrupted (but I'll need more time to debug that one). Thanks for your help! – Dr. Cyanide Oct 26 '12 at 10:30
  • My pleasure. Yes, images always look a bit better with `memcpy` ;-) – Daniel Gehriger Oct 26 '12 at 10:31
0

you fail to mention how you open the file, make sure you have opened in binary mode otherwise seek et all will not work properly with new line characters.

i.e. myfile.open( "yourfile", ios::binary|ios::in )

AndersK
  • 35,813
  • 6
  • 60
  • 86