Shammi
Shammi

Reputation: 500

fgetpos failing in iOS 6.1 simulator when opening files in bundles

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

Answers (1)

Shammi
Shammi

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

Related Questions