/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ // FileUtil_Mac asses that defined(TARGET_API_MAC_CARBON) is valid. #include #include #include #include #include #include #include #include #include #include using namespace osg; using namespace osgDB; using namespace std; // follows is definition of strdup for compatibility under mac, // However, I'd prefer to migrate all the findFindInPath tools to use // std::string's and then be able to remove the following definition. // My objective is to minimize the number of platform #ifdef's as they // are source of potential bugs and developer confusion. #define FILEUTILS_MAX_PATH_LENGTH 2048 char *PathDelimitor = " "; static const char *s_default_file_path = ":"; static const char *s_default_dso_path = ":"; static char *s_filePath = ":"; static bool s_filePathInitialized = false; // MACOS utilities /** MAC Carbon only : get an FSSpec for the named file system object (file or folder) contained within the specified folder ridiculous that this kind of thing doesn't seem to be built into carbon. or manybe I'm just not finding it ? give me back my cocoa. TODO : we should probably do a version of this routine that searches subfolders too */ static OSErr getObjectContainedInFolder(const std::string& objectName,FSSpecPtr containingFolder,FSSpecPtr theFSSpecPtr) { FSRef theObjectRef; FSRef containingFolderRef; CFStringRef unicodeObjectName; OSErr errCode; UniChar objectNameChars[ 255 ]; CFIndex nameLength; errCode=FSpMakeFSRef(containingFolder,&containingFolderRef); // make FSREf to containing folder if(errCode==noErr) { unicodeObjectName=CFStringCreateWithCString (NULL,objectName.c_str(),kCFStringEncodingASCII); nameLength=CFStringGetLength( unicodeObjectName ); CFStringGetCharacters( unicodeObjectName, CFRangeMake( 0, nameLength ), &objectNameChars[0] ); errCode=FSMakeFSRefUnicode (&containingFolderRef,nameLength,objectNameChars,CFStringGetSystemEncoding(),&theObjectRef); CFRelease(unicodeObjectName); if(errCode==noErr) {// the object exists, so we just have to make an FSSpec from the FSRef. return FSGetCatalogInfo (&theObjectRef, kFSCatInfoNone, NULL,NULL,theFSSpecPtr,NULL); } } return errCode; } /** MAC Carbon only : get an FSSpec for the named file system object (file or folder) contained within the specified folder this just makes an FSSpec and calls the getObjectContainedInFolder */ static OSErr getObjectContainedInFolder(const std::string& objectName,SInt16 containingFolderVolRef, SInt32 containingFolderDirID,FSSpecPtr theFSSpecPtr) { FSSpec container; OSErr errCode; errCode=FSMakeFSSpec(containingFolderVolRef,containingFolderDirID,(ConstStr255Param)"",&container); if(errCode==noErr) { errCode=getObjectContainedInFolder(objectName,&container,theFSSpecPtr); } return errCode; } /** MAC Carbon only : get an FSSpec for the current application package. this is mostly useful for finding the Plug-ins directory if the application chooses to store plugins in a folder next to the application in the "old fashioned" way. This code directly taken from Apple technote TN2015 (locating application support files under OSX) TODO - this currently only supports applications that are built as a bundle, not simple unix style exectutables. The technote above describes how to support this situation and we should probably add support for that at some point. But I need to sleep now. */ static OSErr getApplicationFSSpec(FSSpecPtr theFSSpecPtr) { OSErr err = fnfErr; CFBundleRef myAppsBundle = CFBundleGetMainBundle(); if (myAppsBundle == NULL) return err; CFURLRef myBundleURL = CFBundleCopyBundleURL(myAppsBundle); if (myBundleURL == NULL) return err; FSRef myBundleRef; Boolean ok = CFURLGetFSRef(myBundleURL, &myBundleRef); CFRelease(myBundleURL); if (!ok) return err; return FSGetCatalogInfo(&myBundleRef, kFSCatInfoNone, NULL, NULL, theFSSpecPtr, NULL); } /** MAC Carbon only : returns an FSSpec for the folder containing the specified file system object */ static OSErr getParentFolder(FSSpecPtr theFSSpec, FSSpecPtr theParentSpec) { FSRef theSubjectRef; FSRef theParentRef; OSErr theErr; theErr=FSpMakeFSRef(theFSSpec,&theSubjectRef); if(theErr==noErr) { theErr=FSGetCatalogInfo(&theSubjectRef, kFSCatInfoNone, NULL, NULL, NULL, &theParentRef); if(theErr==noErr) { theErr=FSGetCatalogInfo(&theParentRef, kFSCatInfoNone, NULL, NULL, theParentSpec, NULL); } } return theErr; } /** MAC Carbon only : get an FSSpec for the folder containing the current application package. this is mostly useful for finding the Plug-ins directory if the application chooses to store plugins in a folder next to the application in the "old fashioned" way. */ static OSErr getApplicationParentFolderFSSpec(FSSpecPtr theFolder) { FSSpec theApp; OSErr theErr; theErr=getApplicationFSSpec(&theApp); if(theErr==noErr) { theErr=getParentFolder(&theApp,theFolder); } return theErr; } /** MAC Carbon only : get an FSSpect for a sub folder of the parent folder of the current application. this is mostly useful for finding things like "plug-in" directories. Note that the proper place to put this kind of thing is now supposed to be the "Application Support" folder. */ static OSErr getApplicationPeerFolderFSSpec(const std::string& folderName,FSSpecPtr theFSSpecPtr) { FSSpec applicationFolder; OSErr errCode; errCode=getApplicationParentFolderFSSpec(&applicationFolder); if(errCode==noErr) { return getObjectContainedInFolder(folderName,&applicationFolder,theFSSpecPtr); } return errCode; // file not found error } /** MAC carbon only : returns the posix style path to a file specified in an FSSpec returns NULL if the file object pointed to by the FSSpec doesn't exist */ static char * pathFromFSSpec(FSSpecPtr theFSSpec) { FSRef theObjectRef; char pathTmp[1024]; char *path=NULL; CFURLRef theObjectURL; OSErr errCode; errCode=FSpMakeFSRef(theFSSpec,&theObjectRef); if(errCode==noErr) { theObjectURL=CFURLCreateFromFSRef(NULL,&theObjectRef); if(theObjectURL!=NULL) { CFStringRef thePath=CFURLCopyFileSystemPath(theObjectURL,kCFURLPOSIXPathStyle); // maybe should be HFS style on OS9 ? CFStringGetCString(thePath,pathTmp,1024,kCFStringEncodingASCII); path=strdup( pathTmp ); CFRelease(theObjectURL);CFRelease(thePath); } } return path; } /** MAC Carbon only : checks for the existance of a file (replaces unix access() for OS8/9 platform) */ static bool checkFileExists(const char *filePath) { CFURLRef fileURL; FSRef fileRef; bool fileExists; //if(gestalt(gestaltFSAttr)==noErr) //{ // if(gestaltReply & gestaltFSUsesPOSIXPathsForConversion) //CFURLCreateWithFileSystemPath(ilePath, kCFURLPOSIXPathStyle, Boolean isDirectory); // FSPathMakeRef is only implemented on OSX, so can't use that. fileURL=CFURLCreateFromFileSystemRepresentation(NULL,(const UInt8 *)filePath,strlen(filePath),false); // hopefully this isolates us from dealing with what form the path is in - i think it should assume the native path format for the platfrom we're running on. fileExists=CFURLGetFSRef(fileURL,&fileRef); CFRelease(fileURL); return fileExists; } /** MAC carbon only : returns the file path of a CFURLRef as a C string. you're responsible for disposing of the string when you're done */ static char *pathFromCFURL(CFURLRef theURL) { UInt8 pathTmp[1024]; // temporary buffer for path char *path=NULL; if(theURL!=NULL) { CFURLGetFileSystemRepresentation(theURL,false,pathTmp,1024); // TODO this can fail somehow - not sure what to do if it does path=strdup( (char*)pathTmp ); } return path; // phew } /** MAC carbon only : searches the given bundle for a named resource and returns the path to it if it exists, otherwise NULL */ static char *getPathOfResourceInBundle(const std::string& resourceName,CFBundleRef theBundle) { CFStringRef fileNameString=CFStringCreateWithCString (NULL,resourceName.c_str(),kCFStringEncodingASCII); CFURLRef fileURL=CFBundleCopyResourceURL( theBundle, fileNameString, NULL, NULL); // look for a resource with the specified name CFRelease(fileNameString); if(fileURL!=NULL) { notify( DEBUG_INFO ) << "found file:" << resourceName << " as a bundle resource" << endl; char *thePath=pathFromCFURL(fileURL); CFRelease(fileURL); return thePath; } return NULL; } /** MAC carbon only : returns the path to a resource in the Application bundle as a string returns NULL if the resource doesn't exist */ static char *getPathOfApplicationResource(const std::string& resourceName) { CFBundleRef theSearchBundle=CFBundleGetMainBundle(); char *thePath=getPathOfResourceInBundle(resourceName,theSearchBundle); return thePath; } // end mac utilites void osgDB::initFilePath( void ) { char *ptr; if( (ptr = getenv( "OSG_FILE_PATH" )) ) { notify(DEBUG_INFO) << "osgDB::Init("<