Reputation: 500
I'm working on some multiplatform C++ code. Hence the requirement to use fopen, fgetpos, etc. The following was working earlier on iOS and with my update to the latest version it stopped working.
I have a couple of text files Shader.vsh and Shader.fsh in a Shaders folder that is getting copied over to the bundle. In order to open the file, I do the following..
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef cfstrFilename = CFSTRFromConstCharPtr( "Shader" );
CFStringRef cfstrFileType = CFSTRFromConstCharPtr( "vsh" );
CFStringRef cfstrSubDir = CFSTRFromConstCharPtr( "Shaders" );
CFURLRef resourcesURL = CFBundleCopyResourceURL( mainBundle, cfstrFilename, cfstrFileType, cfstrSubDir );
CFStringRef str = CFURLCopyFileSystemPath( resourcesURL, kCFURLPOSIXPathStyle );
CFRelease( resourcesURL );
char path[ PATH_MAX ];
CFStringGetCString( str, path, FILENAME_MAX, kCFStringEncodingASCII );
CFRelease( str );
FILE* fp = fopen( path, "rb" );
At this point, fp is Non NULL. So I assume it succeeded. Later, when I try to do
fpos_t pos;
int result = fgetpos( fp, &fpos_t );
result = -1 and errno = 0x2, which I believe is file not found.
As I mentioned earlier, this used to work on a previous version at some point. I started working on this again and in the process updated to the latest XCode, etc and things stopped working.
The path for the file that I pass into fopen turns out to be /Users/shammi/Library/Application Support/iPhone Simulator/6.1/Applications/9132490F-71AC-4C61-A584-E8F6C5B261FF/TestApp.app/Shaders/Shader.vsh I'm able to see and open that file in finder/console and confirmed that its valid.
What am I doing wrong? Is there another alternative that allows me to use portable IO functions?
Upvotes: 0
Views: 122
Reputation: 500
Found the problem. What I failed to mention here is what happens between the 2 sections of code above. Prior to this, I used to have my own ref counting solution and I recently changed to using shared_ptr. My own ref counting solution allowed for implicit casts. With shared_ptr, you can't do that. So here is the exact code...
std::shared_ptr< BinaryStream > BundleNamespace::OpenStream( const char* _szPath,
BinaryStream::Mode _eMode )
{
std::shared_ptr< BinaryStream > pStream = __super::OpenStream( _szPath, _eMode );
if ( !pStream )
{
std::string strDir;
std::string strFile;
std::string strExt;
SplitPath( _szPath, strDir, strFile, strExt );
std::string strFullPath = GetResourcePathFor( strFile.c_str(), strExt.c_str(), strDir.c_str() );
FILE* fp = fopen( strFullPath.c_str(), _eMode == BinaryStream::Mode_Read ? "r" : "w+b" );
pStream = std::make_shared<FileStream>( fp, _eMode );
}
return pStream;
}
The problem here is with
pStream = std::make_shared<FileStream>( fp, _eMode );
My FileStream's destructor calls fclose(m_pFile). The fix here is to change it to..
pStream = std::static_pointer_cast< BinaryStream >( std::make_shared<FileStream>( fp, _eMode ) );`
Also, using perror() proved to be more useful compared to trying to decipher errno.
Upvotes: 0