2

I've tried the following code with both normal ifstreams and the current boost:iostream I'm using, both have the same result.

It is intended to load a file from physfs into memory then pass it to a handler to process (eg Image, audio or data). Currently when c_str is called it only returns a small part of the file.

 PhysFS::FileStream file("Resources/test.png" , PhysFS::OM_READ); if(file.is_open()) { String* theFile; theFile = new String((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); String::iterator it; for ( it=theFile->begin() ; it < theFile->end(); it++ ) { std::cout << *it; } // Outputs the entire file std::cout << theFile->c_str(); // Outputs only the first few lines } 

The iterator loop outputs the entire png file as expected, but the c_str call only returns the first few characters (\211PNG).

I've been trying variations of this code for quite some time with no success. Any ideas?

3 Answers 3

15

I imagine that the next character is a null (ASCII 0) byte. c_str() simply gives you a *char, therefore your write to stdout is interpreted as a class C string which ends at the first null byte.

If you really need a C-like interface to this string, the main thing is that theFile->c_str() points to your data and theFile.length gives you the number of characters in the string. So you might want to do something like this:

char *c_value = theFile->c_str() for (int i = 0; i < theFile.length; i++) { cout << c_value[i]; } 

The real solution depends on why you are converting to a char * in the first place. If you are calling a legacy function that only accepts char *, there is likely also a length argument to that legacy function.

Sign up to request clarification or add additional context in comments.

5 Comments

How would I go about fixing that? I don't have much experience with C style strings
I'm using a library which needs a c string input.
I updated my answer. Simie, you want to check that library function to see if it accepts a string-length argument. If it doesn't, that library function might simply be unable to process a string with an embedded null character.
You made it to my blog today too. :-) blog.criticalresults.com/2009/10/12/strings-and-pointers
If you're using a (const char*, length) pair, don't use .c_str() but .data(). .c_str() adds an extra \0, possibly copying the string in the process.
2

One of the bytes is probably 0. That means end of string to cout when passing a char* (which c_str is)

Comments

2

I would consider using std::vector<unsigned char> instead of std::string for this. It is a lot easier to deal with binary data in a vector. You can reference the underlying pointer using &vec[0] if you need access to a C-style array. I would also make sure that your file abstraction use std::ios_base::binary for the file mode under the hood as well.

4 Comments

As far as I can tell there is no option in PhysFS to open a file in binary mode. The lack of proper examples on how to use PhysFS is why I thought that it was a problem with me reading the file into memory instead of the display problems. :-(
Yeah, I was going to say that too: don't read the whole file into memory. Unless, I guess, you're quite certain it will be very small.
@Simie: I'm guessing that you are not allowed to use std::ifstream instead? or does PhysFS do something more than read a file.
I'm using PhysFS for the archive support, multi-directory search paths @catfood: I wasn't aware there was a way to stream textures? How else would you do it?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.