root/OpenSceneGraph/trunk/src/osgDB/FileUtils.cpp @ 10171

Revision 10171, 36.3 kB (checked in by robert, 6 years ago)

Refactored the Registry::ReadFileCallback?, WriteFileCallback? and ReaderWriter::Options to they are now defined in their own header and in the osgDB namespace.

Introduced a new FindFileCallback? to Registry to compliement the existing ReadFileCallback? and WriteFileCallback?.

Added support for assign Find, Read and WriteFileCallbacks? to osdDB::Options to enable plugins/applications to override the callbacks just for that
read/write call and any nested file operations

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[5328]1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
[1529]2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
[773]13
[9124]14// currently this impl is for _all_ platforms, except as defined.
[909]15// the mac version will change soon to reflect the path scheme under osx, but
16// for now, the above include is commented out, and the below code takes precedence.
[773]17
18#if defined(WIN32) && !defined(__CYGWIN__)
[8076]19    #include <io.h>
[9991]20    #define WINBASE_DECLARE_GET_MODULE_HANDLE_EX
[8076]21    #include <windows.h>
22    #include <winbase.h>
[2991]23    #include <sys/types.h>
24    #include <sys/stat.h>
[3367]25    #include <direct.h> // for _mkdir
[3465]26   
[3367]27    #define mkdir(x,y) _mkdir((x))
[3467]28    #define stat64 _stati64
[3367]29
[773]30    // set up for windows so acts just like unix access().
[9201]31#ifndef F_OK
[773]32    #define F_OK 4
[9201]33#endif
[3367]34
[909]35#else // unix
[3483]36
[5456]37#if defined( __APPLE__ )
38    // I'm not sure how we would handle this in raw Darwin
39    // without the AvailablilityMacros.
40    #include <AvailabilityMacros.h>
41    // 10.5 defines stat64 so we can't use this #define
42    // By default, MAC_OS_X_VERSION_MAX_ALLOWED is set to the latest
43    // system the headers know about. So I will use this as the control
44    // variable. (MIN_ALLOWED is set low by default so it is
45    // unhelpful in this case.)
46    // Unfortunately, we can't use the label MAC_OS_X_VERSION_10_4
47    // for older OS's like Jaguar, Panther since they are not defined,
48    // so I am going to hardcode the number.
49    #if (MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
50        #define stat64 stat
51    #endif
[7496]52#elif defined(__CYGWIN__) || defined(__FreeBSD__) || (defined(__hpux) && !defined(_LARGEFILE64_SOURCE))
[3483]53    #define stat64 stat
54#endif
55
[9475]56    #include <stdlib.h>
[773]57    #include <unistd.h>
[2971]58    #include <sys/types.h>
59    #include <sys/stat.h>
[8]60#endif
[773]61
[3367]62    // set up _S_ISDIR()
63#if !defined(S_ISDIR)
64if defined( _S_IFDIR) && !defined( __S_IFDIR)
65#    define __S_IFDIR _S_IFDIR
66endif
67define S_ISDIR(mode)    (mode&__S_IFDIR)
68#endif
69
[9124]70#include <osg/Config>
71#include <osgDB/ConvertUTF>
[775]72#include <osg/Notify>
73
74#include <osgDB/FileUtils>
75#include <osgDB/FileNameUtils>
76#include <osgDB/Registry>
77
[3367]78#include <errno.h>
[9343]79#include <string.h>
80
[3367]81#include <stack>
[775]82
[9124]83namespace osgDB
84{
85#ifdef OSG_USE_UTF8_FILENAME
86#define OSGDB_STRING_TO_FILENAME(s) osgDB::convertUTF8toUTF16(s)
87#define OSGDB_FILENAME_TO_STRING(s) osgDB::convertUTF16toUTF8(s)
88#define OSGDB_FILENAME_TEXT(x) L ## x
89#define OSGDB_WINDOWS_FUNCT(x) x ## W
[10129]90#define OSGDB_WINDOWS_FUNCT_STRING(x) #x "W"
[9124]91typedef wchar_t filenamechar;
92typedef std::wstring filenamestring;
93#else
94#define OSGDB_STRING_TO_FILENAME(s) s
95#define OSGDB_FILENAME_TO_STRING(s) s
96#define OSGDB_FILENAME_TEXT(x) x
97#define OSGDB_WINDOWS_FUNCT(x) x ## A
[9991]98#define OSGDB_WINDOWS_FUNCT_STRING(x) #x "A"
[9124]99typedef char filenamechar;
100typedef std::string filenamestring;
101#endif
102}
[6705]103
[9124]104FILE* osgDB::fopen(const char* filename, const char* mode)
105{
106#ifdef OSG_USE_UTF8_FILENAME
107    return ::_wfopen(convertUTF8toUTF16(filename).c_str(), convertUTF8toUTF16(mode).c_str());
108#else
109    return ::fopen(filename, mode);
110#endif
111}
[6705]112
[3367]113bool osgDB::makeDirectory( const std::string &path )
114{
115    if (path.empty())
116    {
117        osg::notify(osg::DEBUG_INFO) << "osgDB::makeDirectory(): cannot create an empty directory" << std::endl;
118        return false;
119    }
120   
[3464]121    struct stat64 stbuf;
[9124]122#ifdef OSG_USE_UTF8_FILENAME
123    if( _wstat64( OSGDB_STRING_TO_FILENAME(path).c_str(), &stbuf ) == 0 )
124#else
[3464]125    if( stat64( path.c_str(), &stbuf ) == 0 )
[9124]126#endif
[3367]127    {
128        if( S_ISDIR(stbuf.st_mode))
129            return true;
130        else
131        {
132            osg::notify(osg::DEBUG_INFO) << "osgDB::makeDirectory(): "  <<
133                    path << " already exists and is not a directory!" << std::endl;
134            return false;
135        }
136    }
137
138    std::string dir = path;
139    std::stack<std::string> paths;
140    while( true )
141    {
142        if( dir.empty() )
143            break;
144 
[9124]145#ifdef OSG_USE_UTF8_FILENAME
146        if( _wstat64( OSGDB_STRING_TO_FILENAME(dir).c_str(), &stbuf ) < 0 )
147#else
[3464]148        if( stat64( dir.c_str(), &stbuf ) < 0 )
[9124]149#endif
[3367]150        {
151            switch( errno )
152            {
153                case ENOENT:
154                case ENOTDIR:
155                    paths.push( dir );
156                    break;
157 
158                default:
[3659]159                    osg::notify(osg::DEBUG_INFO) << "osgDB::makeDirectory(): "  << strerror(errno) << std::endl;
[3367]160                    return false;
161            }
162        }
163        dir = getFilePath(std::string(dir));
164    }
165
166    while( !paths.empty() )
167    {
168        std::string dir = paths.top();
169 
[5161]170        #if defined(WIN32)
171            //catch drive name
172            if (dir.size() == 2 && dir.c_str()[1] == ':') {
173                paths.pop();
174                continue;
175            }
176        #endif
177
[9124]178#ifdef OSG_USE_UTF8_FILENAME
179        if ( _wmkdir(OSGDB_STRING_TO_FILENAME(dir).c_str())< 0 )
180#else
[3367]181        if( mkdir( dir.c_str(), 0755 )< 0 )
[9124]182#endif
[3367]183        {
[3659]184            osg::notify(osg::DEBUG_INFO) << "osgDB::makeDirectory(): "  << strerror(errno) << std::endl;
[3367]185            return false;
186        }
187        paths.pop();
188    }
189    return true;
190}
191
192bool osgDB::makeDirectoryForFile( const std::string &path )
193{
194    return makeDirectory( getFilePath( path ));
195}
196
[3330]197void osgDB::convertStringPathIntoFilePathList(const std::string& paths,FilePathList& filepath)
198{
199#if defined(WIN32) && !defined(__CYGWIN__)
200    char delimitor = ';';
201#else
202    char delimitor = ':';
203#endif
204
205    if (!paths.empty())
206    {
207        std::string::size_type start = 0;
208        std::string::size_type end;
209        while ((end = paths.find_first_of(delimitor,start))!=std::string::npos)
210        {
211            filepath.push_back(std::string(paths,start,end-start));
212            start = end+1;
213        }
214
[7276]215        std::string lastPath(paths,start,std::string::npos);
216        if (!lastPath.empty())
217            filepath.push_back(lastPath);
[3330]218    }
219 
220}
221
[773]222bool osgDB::fileExists(const std::string& filename)
223{
[9124]224#ifdef OSG_USE_UTF8_FILENAME
225    return _waccess( OSGDB_STRING_TO_FILENAME(filename).c_str(), F_OK ) == 0;
226#else
[773]227    return access( filename.c_str(), F_OK ) == 0;
[9124]228#endif
[773]229}
230
[2971]231osgDB::FileType osgDB::fileType(const std::string& filename)
232{
[3464]233    struct stat64 fileStat;
[9124]234#ifdef OSG_USE_UTF8_FILENAME
235    if ( _wstat64(OSGDB_STRING_TO_FILENAME(filename).c_str(), &fileStat) != 0 )
236#else
237    if ( stat64(filename.c_str(), &fileStat) != 0 )
238#endif
[2971]239    {
240        return FILE_NOT_FOUND;
[2991]241    } // end if
[2992]242
243    if ( fileStat.st_mode & S_IFDIR )
[2991]244        return DIRECTORY;
[2992]245    else if ( fileStat.st_mode & S_IFREG )
[2971]246        return REGULAR_FILE;
[2992]247
[2991]248    return FILE_NOT_FOUND;
[2971]249}
250
[2444]251std::string osgDB::findFileInPath(const std::string& filename, const FilePathList& filepath,CaseSensitivity caseSensitivity)
[773]252{
[2420]253    if (filename.empty())
254        return filename;
[773]255
[3833]256    if (!isFileNameNativeStyle(filename))
257        return findFileInPath(convertFileNameToNativeStyle(filename), filepath, caseSensitivity);
[773]258
[3833]259
[773]260    for(FilePathList::const_iterator itr=filepath.begin();
261        itr!=filepath.end();
262        ++itr)
263    {
[3691]264        osg::notify(osg::DEBUG_INFO) << "itr='" <<*itr<< "'\n";
[6005]265        std::string path = itr->empty() ? filename : concatPaths(*itr, filename);
266       
267        path = getRealPath(path);
268
[773]269        osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : trying " << path << " ...\n";
[2420]270        if(fileExists(path))
271        {
272            osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : USING " << path << "\n";
273            return path;
274        }
[2444]275#ifndef WIN32 
276// windows already case insensitive so no need to retry..
277        else if (caseSensitivity==CASE_INSENSITIVE)
278        {
279            std::string foundfile = findFileInDirectory(filename,*itr,CASE_INSENSITIVE);
280            if (!foundfile.empty()) return foundfile;
281        }
282#endif
283           
[773]284    }
285
286    return std::string();
287}
288
[3691]289
[2444]290std::string osgDB::findDataFile(const std::string& filename,CaseSensitivity caseSensitivity)
[773]291{
[10171]292    return findDataFile(filename,static_cast<Options*>(0),caseSensitivity);
[3689]293}
294
[10171]295OSGDB_EXPORT std::string osgDB::findDataFile(const std::string& filename,const Options* options, CaseSensitivity caseSensitivity)
[3689]296{
[10171]297    return Registry::instance()->findDataFile(filename, options, caseSensitivity);
[773]298}
299
[2444]300std::string osgDB::findLibraryFile(const std::string& filename,CaseSensitivity caseSensitivity)
[773]301{
[10171]302    return Registry::instance()->findLibraryFile(filename, osgDB::Registry::instance()->getOptions(), caseSensitivity);
[773]303}
304
[2444]305std::string osgDB::findFileInDirectory(const std::string& fileName,const std::string& dirName,CaseSensitivity caseSensitivity)
[773]306{
307    bool needFollowingBackslash = false;
308    bool needDirectoryName = true;
309    osgDB::DirectoryContents dc;
310
[9425]311    std::string realDirName = dirName;
312    std::string realFileName = fileName;
313
314    // Skip case-insensitive recursion if on Windows
315    #ifdef WIN32
316        bool win32 = true;
317    #else
318        bool win32 = false;
319    #endif
320   
321    // If the fileName contains extra path information, make that part of the
322    // directory name instead
323    if (fileName != getSimpleFileName(fileName))
[773]324    {
[9425]325        // See if we need to add a slash between the directory and file
326        if (realDirName.empty())
327        {
328            realDirName = getFilePath(fileName);
329        }
330        else if (realDirName=="." || realDirName=="./" || realDirName==".\\")
331        {
332            realDirName = "./" + getFilePath(fileName);
333        }
334        else
335        {
336            char lastChar = dirName[dirName.size()-1];
337            if ((lastChar == '/') || (lastChar == '\\'))
338                realDirName = dirName + getFilePath(fileName);
339            else
340                realDirName = dirName + "/" + getFilePath(fileName);
341        }
342
343        // Simplify the file name
344        realFileName = getSimpleFileName(fileName);
345    }
346
347    osg::notify(osg::DEBUG_INFO) << "findFileInDirectory() : looking for " << realFileName << " in " << realDirName << "...\n";
348
349    if (realDirName.empty())
350    {
[773]351        dc = osgDB::getDirectoryContents(".");
352        needFollowingBackslash = false;
353        needDirectoryName = false;
354    }
[9425]355    else if (realDirName=="." || realDirName=="./" || realDirName==".\\")
[773]356    {
357        dc = osgDB::getDirectoryContents(".");
358        needFollowingBackslash = false;
359        needDirectoryName = false;
360    }
[9425]361    else if (realDirName=="/")
[773]362    {
[9425]363        dc = osgDB::getDirectoryContents("/");
364        needFollowingBackslash = false;
[773]365        needDirectoryName = true;
366    }
[9425]367    else
368    {
369        // See if we're working in case insensitive mode, and that we're not
370        // using Windows (the recursive search is not needed in these
371        // cases)
372        if ((caseSensitivity == CASE_INSENSITIVE) && (!win32))
373        {
374            // Split the last path element from the directory name
375            std::string parentPath = getFilePath(realDirName);
376            std::string lastElement = getSimpleFileName(realDirName);
[773]377
[9425]378            // See if we're already at the top level of the filesystem
379            if ((parentPath.empty()) && (!lastElement.empty()))
380            {
381                // Search for the first path element (ignoring case) in
382                // the top-level directory
383                realDirName = findFileInDirectory(lastElement, "/",
384                                                  CASE_INSENSITIVE);
385     
386                dc = osgDB::getDirectoryContents(realDirName);
387                needFollowingBackslash = true;
388                needDirectoryName = true;
389            }
390            else
391            {
392                // Recursively search for the last path element (ignoring case)
393                // in the parent path
394                realDirName = findFileInDirectory(lastElement, parentPath,
395                                                  CASE_INSENSITIVE);
396     
397                dc = osgDB::getDirectoryContents(realDirName);
398                char lastChar = realDirName[realDirName.size()-1];
399                if (lastChar=='/') needFollowingBackslash = false;
400                else if (lastChar=='\\') needFollowingBackslash = false;
401                else needFollowingBackslash = true;
402                needDirectoryName = true;
403            }
404        }
405        else
406        {
407            // No need for recursive search if we're doing an exact comparison
408            dc = osgDB::getDirectoryContents(realDirName);
409            char lastChar = realDirName[realDirName.size()-1];
410            if (lastChar=='/') needFollowingBackslash = false;
411            else if (lastChar=='\\') needFollowingBackslash = false;
412            else needFollowingBackslash = true;
413            needDirectoryName = true;
414        }
415    }
416
[773]417    for(osgDB::DirectoryContents::iterator itr=dc.begin();
418        itr!=dc.end();
419        ++itr)
420    {
[9425]421        if ((caseSensitivity==CASE_INSENSITIVE && osgDB::equalCaseInsensitive(realFileName,*itr)) ||
422            (realFileName==*itr))
[773]423        {
424            if (!needDirectoryName) return *itr;
[9425]425            else if (needFollowingBackslash) return realDirName+'/'+*itr;
426            else return realDirName+*itr;
[773]427        }
428    }
429    return "";
430}
431
[8901]432static void appendInstallationLibraryFilePaths(osgDB::FilePathList& filepath)
433{
434#ifdef OSG_DEFAULT_LIBRARY_PATH
[8911]435
[8901]436    // Append the install prefix path to the library search path if configured
[8911]437    filepath.push_back(ADDQUOTES(OSG_DEFAULT_LIBRARY_PATH));
[8901]438#endif
439}
440
[796]441#if defined(WIN32) && !defined(__CYGWIN__)
[773]442    #include <io.h>
443    #include <direct.h>
444
445    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
446    {
447        osgDB::DirectoryContents contents;
448
[9124]449        OSGDB_WINDOWS_FUNCT(WIN32_FIND_DATA) data;
450        HANDLE handle = OSGDB_WINDOWS_FUNCT(FindFirstFile)((OSGDB_STRING_TO_FILENAME(dirName) + OSGDB_FILENAME_TEXT("\\*")).c_str(), &data);
[773]451        if (handle != INVALID_HANDLE_VALUE)
452        {
453            do
454            {
[9124]455                contents.push_back(OSGDB_FILENAME_TO_STRING(data.cFileName));
[773]456            }
[9124]457            while (OSGDB_WINDOWS_FUNCT(FindNextFile)(handle, &data) != 0);
[773]458
459            FindClose(handle);
460        }
461        return contents;
462    }
463
464#else
465
466    #include <dirent.h>
467    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
468    {
469        osgDB::DirectoryContents contents;
470
471        DIR *handle = opendir(dirName.c_str());
472        if (handle)
473        {
474            dirent *rc;
475            while((rc = readdir(handle))!=NULL)
476            {
477                contents.push_back(rc->d_name);
478            }
479            closedir(handle);
480        }
481
482        return contents;
483    }
484
485#endif // unix getDirectoryContexts
486
[3330]487
488/////////////////////////////////////////////////////////////////////////////////////////////////
489//
490// Implementation of appendPlatformSpecificLibraryFilePaths(..)
491//
492#ifdef __sgi
493
494    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
495    {
496        convertStringPathIntoFilePathList("/usr/lib32/:/usr/local/lib32/",filepath);
497
498        // bloody mess see rld(1) man page
[3336]499        char* ptr;
500
[3330]501        #if (_MIPS_SIM == _MIPS_SIM_ABI32)
502        if( (ptr = getenv( "LD_LIBRARY_PATH" )))
503        {
504            convertStringPathIntoFilePathList(ptr,filepath);
505        }
506
507        #elif (_MIPS_SIM == _MIPS_SIM_NABI32)
508
509        if( !(ptr = getenv( "LD_LIBRARYN32_PATH" )))
510            ptr = getenv( "LD_LIBRARY_PATH" );
511
512        if( ptr )
513        {
514            convertStringPathIntoFilePathList(ptr,filepath);
515        }
516
517        #elif (_MIPS_SIM == _MIPS_SIM_ABI64)
518
519        if( !(ptr = getenv( "LD_LIBRARY64_PATH" )))
520            ptr = getenv( "LD_LIBRARY_PATH" );
521
522        if( ptr )
523        {
524            convertStringPathIntoFilePathList(ptr,filepath);
525        }
526        #endif
[8901]527
528        appendInstallationLibraryFilePaths(filepath);
[3330]529    }
530
531
532#elif defined(__CYGWIN__)
533
534    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
535    {
536        char* ptr;
537        if ((ptr = getenv( "PATH" )))
538        {
539            convertStringPathIntoFilePathList(ptr,filepath);
540        }
541
[8901]542        appendInstallationLibraryFilePaths(filepath);
543
[3330]544        convertStringPathIntoFilePathList("/usr/bin/:/usr/local/bin/",filepath);
545    }
546   
547#elif defined(WIN32)
548
549    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
550    {
[7276]551        // See http://msdn2.microsoft.com/en-us/library/ms682586.aspx
552
553        // Safe DLL search mode changes the DLL search order to search for
[7298]554        // DLLs in the current directory after the system directories, instead
555        // of right after the application's directory. According to the article
556        // linked above, on Windows XP and Windows 2000, Safe DLL search mode
557        // is disabled by default. However, it is a good idea to enable it. We
558        // will search as if it was enabled.
[7276]559
560        // So if SafeDllSearchMode is enabled, the search order is as follows:
561
562        //   1. The directory from which the application loaded.
563        DWORD retval = 0;
564        const DWORD size = MAX_PATH;
[9124]565        filenamechar path[size];
566        retval = OSGDB_WINDOWS_FUNCT(GetModuleFileName)(NULL, path, size);
[7276]567        if (retval != 0 && retval < size)
568        {
[9124]569            filenamestring pathstr(path);
570            filenamestring executableDir(pathstr, 0,
571                                      pathstr.find_last_of(OSGDB_FILENAME_TEXT("\\/")));
572            convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(executableDir), filepath);
[7276]573        }
574        else
575        {
576            osg::notify(osg::WARN) << "Could not get application directory "
577                "using Win32 API. It will not be searched." << std::endl;
578        }
579
[9991]580        //   2. The directory that the dll that contains this function is in.
581        // For static builds, this will be the executable directory.
582
[10024]583        #if defined(_MSC_VER)
584            // Requires use of the GetModuleHandleEx() function which is available only on Windows XP or higher.
585            // In order to allow execution on older versions, we load the function dynamically from the library and
586            // use it only if it's available.
587            OSGDB_WINDOWS_FUNCT(PGET_MODULE_HANDLE_EX) pGetModuleHandleEx = reinterpret_cast<OSGDB_WINDOWS_FUNCT(PGET_MODULE_HANDLE_EX)>
588                (GetProcAddress( GetModuleHandleA("kernel32.dll"), OSGDB_WINDOWS_FUNCT_STRING(GetModuleHandleEx)));
589            if( pGetModuleHandleEx )
590            {
591                HMODULE thisModule = 0;
[10129]592                static filenamechar static_variable = 0;    // Variable that is located in DLL address space.
[9991]593
[10024]594                if( pGetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, &static_variable, &thisModule) )
[9991]595                {
[10024]596                    retval = OSGDB_WINDOWS_FUNCT(GetModuleFileName)(thisModule, path, size);
597                    if (retval != 0 && retval < size)
598                    {
599                        filenamestring pathstr(path);
600                        filenamestring dllDir(pathstr, 0,
601                                                pathstr.find_last_of(OSGDB_FILENAME_TEXT("\\/")));
602                        convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(dllDir), filepath);
603                    }
604                    else
605                    {
606                        osg::notify(osg::WARN) << "Could not get dll directory "
607                            "using Win32 API. It will not be searched." << std::endl;
608                    }
[9991]609                }
610                else
611                {
[10024]612                    osg::notify(osg::WARN) << "Could not get dll module handle "
613                        "using Win32 API. Dll directory will not be searched." << std::endl;
[9991]614                }
615            }
[10024]616        #endif
[9991]617
618        //   3. The system directory. Use the GetSystemDirectory function to
[7276]619        //      get the path of this directory.
[9124]620        filenamechar systemDir[(UINT)size];
621        retval = OSGDB_WINDOWS_FUNCT(GetSystemDirectory)(systemDir, (UINT)size);
622
[7276]623        if (retval != 0 && retval < size)
624        {
[9124]625            convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(systemDir),
[7276]626                                              filepath);
627        }
628        else
629        {
630            osg::notify(osg::WARN) << "Could not get system directory using "
631                "Win32 API, using default directory." << std::endl;
632            convertStringPathIntoFilePathList("C:\\Windows\\System32",
633                                              filepath);
634        }
635
[9991]636        //   4. The 16-bit system directory. There is no function that obtains
[7276]637        //      the path of this directory, but it is searched.
[9991]638        //   5. The Windows directory. Use the GetWindowsDirectory function to
[7276]639        //      get the path of this directory.
[9124]640        filenamechar windowsDir[(UINT)size];
641        retval = OSGDB_WINDOWS_FUNCT(GetWindowsDirectory)(windowsDir, (UINT)size);
[7276]642        if (retval != 0 && retval < size)
643        {
[9124]644            convertStringPathIntoFilePathList(std::string(OSGDB_FILENAME_TO_STRING(windowsDir)) +
[7276]645                                              "\\System", filepath);
[9124]646            convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(windowsDir),
[7276]647                                              filepath);
648        }
649        else
650        {
651            osg::notify(osg::WARN) << "Could not get Windows directory using "
652                "Win32 API, using default directory." << std::endl;
653            convertStringPathIntoFilePathList("C:\\Windows", filepath);
654            convertStringPathIntoFilePathList("C:\\Windows\\System", filepath);
655        }
656
657
[9991]658        //   6. The current directory.
[7276]659        convertStringPathIntoFilePathList(".", filepath);
660
[9991]661        //   7. The directories that are listed in the PATH environment
[7276]662        //      variable. Note that this does not include the per-application
663        //      path specified by the App Paths registry key.
[9124]664        filenamechar* ptr;
665#ifdef OSG_USE_UTF8_FILENAME
[9459]666        if ((ptr = _wgetenv(OSGDB_FILENAME_TEXT("PATH"))))
[9124]667#else
[9459]668        if ((ptr = getenv("PATH")))
[9124]669#endif
[3330]670        {
[7276]671            // Note that on any sane Windows system, some of the paths above
672            // will also be on the PATH (the values gotten in systemDir and
673            // windowsDir), but the DLL search goes sequentially and stops
674            // when a DLL is found, so I see no point in removing duplicates.
[9124]675            convertStringPathIntoFilePathList(OSGDB_FILENAME_TO_STRING(ptr), filepath);
[3330]676        }
[8901]677
678        appendInstallationLibraryFilePaths(filepath);
[3330]679    }
680   
681#elif defined(__APPLE__)
682
[3333]683    // #define COMPILE_COCOA_VERSION
[3372]684    #define COMPILE_CARBON_VERSION
[4420]685    // WARNING: Cocoa version is currently untested.
686    #ifdef COMPILE_COCOA_VERSION
687        #include <Foundation/Foundation.h>
688    #endif
689    #ifdef COMPILE_CARBON_VERSION
690        #include <CoreServices/CoreServices.h>
691        #include <CoreFoundation/CoreFoundation.h>
692        #include <Carbon/Carbon.h>
693    #endif
694    #include <iostream>
[3333]695   
[4420]696    // These functions are local to FileUtils.cpp and not exposed to the API
697    // returns the path string except for numToShorten directories stripped off the end
698    std::string GetShortenedPath(std::string path, int numToShorten)
699    {
700        unsigned int i = path.length() - 1;
701        if(path[i] == '/') i--;
702        while(i > 1 && numToShorten)
703        {
704            if(path[i] == '/')
705                numToShorten--;
706            i--;
707        }
708        return path.substr(0,i + 1);
709    }
[3333]710
[4420]711    // returns an absolute (POSIX on MacOS X) path from a CFURLRef
712    std::string GetPathFromCFURLRef(CFURLRef urlRef)
713    {
714        char buffer[1024];
715        std::string path;
716        if(CFURLGetFileSystemRepresentation(urlRef, true, (UInt8*)buffer, 1024))
717            path = std::string(buffer);
718        return path;
719    }
720
721    // returns the absolute path to the main bundle
722    std::string GetApplicationBundlePath(CFBundleRef mainBundle)
723    {
724        std::string path;
725        CFURLRef urlRef = CFBundleCopyBundleURL(mainBundle);
726        if(urlRef)
[4990]727        {
[4420]728            path = GetPathFromCFURLRef(urlRef);
[4990]729            CFRelease(urlRef); // docs say we are responsible for releasing CFURLRef
730        }
[4420]731        return path;
732       
733    }
734
735    std::string GetApplicationParentPath(CFBundleRef mainBundle)
736    {
737        return GetShortenedPath(GetApplicationBundlePath(mainBundle), 1);
738    }
739
740    std::string GetApplicationPluginsPath(CFBundleRef mainBundle)
741    {
742        std::string path;
743        CFURLRef urlRef = CFBundleCopyBuiltInPlugInsURL(mainBundle);
744        if(urlRef)
[4990]745        {
[4420]746            path = GetPathFromCFURLRef(urlRef);
[4990]747            CFRelease(urlRef);
748        }
[4420]749        return path;
750       
751    }
752
753    std::string GetApplicationResourcesPath(CFBundleRef mainBundle)
754    {
755        std::string path;
756        CFURLRef urlRef = CFBundleCopyResourcesDirectoryURL(mainBundle);
757        if(urlRef)
[4990]758        {
[4420]759            path = GetPathFromCFURLRef(urlRef);
[4990]760            CFRelease(urlRef);
761        }
[4420]762        return path;
763    }
764
[3330]765    // The Cocoa version is about 10 lines of code.
766    // The Carbon version is noticably longer.
767    // Unfortunately, the Cocoa version requires -lobjc to be
768    // linked in when creating an executable.
769    // Rumor is that this will be done autmatically in gcc 3.5/Tiger,
770    // but for now, this will cause a lot of headaches for people
771    // who aren't familiar with this concept, so the Carbon version
772    // is preferable.
773    // But for the curious, both implementations are here.
774    // Note that if the Cocoa version is used, the file should be
775    // renamed to use the .mm extension to denote Objective-C++.
776    // And of course, you will need to link against Cocoa
[5456]777    // Update: There is a bug in the Cocoa version. Advanced users can remap
778    // their systems so these paths go somewhere else. The Carbon calls
779    // will catch this, but the hardcoded Cocoa code below will not.
[3330]780
[3333]781    #ifdef COMPILE_COCOA_VERSION
[3330]782    // OS X has preferred locations for where PlugIns should be located.
783    // This function will set this as the order to search:
784    // YourProgram.app/Contents/PlugIns
785    // ~/Library/Application Support/OpenSceneGraph/PlugIns
786    // /Library/Application Support/OpenSceneGraph/PlugIns
787    // /Network/Library/Application Support/OpenSceneGraph/PlugIns
788    //
789    // As a side effect of this function, if the application is not a
790    // bundle, the first place searched becomes
791    // YourProgram/PlugIns
792    //
793    // In principle, these other directories should be searched:
794    // ~/Library/Application Support/YourProgram/PlugIns
795    // /Library/Application Support/YourProgram/PlugIns
796    // /Network/Library/Application Support/TheProgram/PlugIns
797    // But I'm not going to worry about it for now because the
798    // bundle's PlugIns directory is supposed to be the preferred
799    // place for this anyway.
800    //
801    // Another directory that might be worth considering is
802    // the directory the program resides in,
803    // but I'm worried about multiplatform distribution.
804    // Because .so is used by other platforms like Linux, we
805    // could end up loading the wrong binary.
806    // I'm not sure how robust the current code is for this case.
807    // Assuming the program doesn't crash, will OSG move on to the
808    // next search directory, or just give up?
809    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
810    {
811        char* ptr;
812        if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) )
813        {
814            convertStringPathIntoFilePathList(ptr, filepath);
815        }
816
[8901]817        appendInstallationLibraryFilePaths(filepath);
818
[3330]819        // Since this is currently the only Objective-C code in the
820        // library, we need an autoreleasepool for obj-c memory management.
821        // If more Obj-C is added, we might move this pool to another
822        // location so it can be shared. Pools seem to be stackable,
823        // so I don't think there will be a problem if multiple pools
824        // exist at a time.
825        NSAutoreleasePool* mypool = [[NSAutoreleasePool alloc] init];
826
827        NSString* myBundlePlugInPath;
828        NSString* userSupportDir;
829
830        // This will grab the "official" bundle plug in path.
831        // It will be YourProgram.app/Contents/PlugIns (for App bundles)
832        // or YourProgram/PlugIns (for Unix executables)
833        myBundlePlugInPath = [[NSBundle mainBundle] builtInPlugInsPath];
834
835        // Now setup the other search paths
836        // Cocoa has a nice method for tilde expansion.
837        // There's probably a better way of getting this directory, but I
838        // can't find the call.
839        userSupportDir = [@"~/Library/Application Support/OpenSceneGraph/PlugIns" stringByExpandingTildeInPath];
840
841        // Can setup the remaining directories directly in C++
842
843        // Since Obj-C and C++ objects don't understand each other,
844        // the Obj-C strings must be converted down to C strings so
845        // C++ can make them into C++ strings.
846        filepath.push_back( [myBundlePlugInPath UTF8String] );
847        filepath.push_back( [userSupportDir UTF8String] );
848
849        filepath.push_back( "/Library/Application Support/OpenSceneGraph/PlugIns" );
850        filepath.push_back( "/Network/Library/Application Support/OpenSceneGraph/PlugIns" );
851
852        // Clean up the autorelease pool
853        [mypool release];
854    }
855
[3333]856    #elif defined(COMPILE_CARBON_VERSION)
[3330]857
858    // OS X has preferred locations for where PlugIns should be located.
859    // This function will set this as the order to search:
860    // YourProgram.app/Contents/PlugIns
861    // ~/Library/Application Support/OpenSceneGraph/PlugIns
862    // /Library/Application Support/OpenSceneGraph/PlugIns
863    // /Network/Library/Application Support/OpenSceneGraph/PlugIns
864    //
865    // In principle, these other directories should be searched:
866    // ~/Library/Application Support/YourProgram/PlugIns
867    // /Library/Application Support/YourProgram/PlugIns
868    // /Network/Library/Application Support/TheProgram/PlugIns
869    // But I'm not going to worry about it for now because the
870    // bundle's PlugIns directory is supposed to be the preferred
871    // place for this anyway.
872    //
873    // Another directory that might be worth considering is
874    // the directory the program resides in,
875    // but I'm worried about multiplatform distribution.
876    // Because .so is used by other platforms like Linux, we
877    // could end up loading the wrong binary.
878    // I'm not sure how robust the current code is for this case.
879    // Assuming the program doesn't crash, will OSG move on to the
880    // next search directory, or just give up?
881    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
882    {
883        char* ptr;
884        if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) )
885        {
886            convertStringPathIntoFilePathList(ptr, filepath);
887        }
888
[8901]889        appendInstallationLibraryFilePaths(filepath);
890
[3330]891        const std::string OSG_PLUGIN_PATH("/OpenSceneGraph/PlugIns");
892        CFURLRef  url;
893        CFBundleRef myBundle;
894        FSRef     f;
[4327]895        OSErr    errCode;
[3330]896
897        // Start with the the Bundle PlugIns directory.
898
[4420]899        // Get the main bundle first. No need to retain or release it since
900        //  we are not keeping a reference
[3330]901        myBundle = CFBundleGetMainBundle();
[4420]902       
[3330]903        if(myBundle != NULL)
904        {
[4420]905            // CFBundleGetMainBundle will return a bundle ref even if
906            //  the application isn't part of a bundle, so we need to check
907            //  if the path to the bundle ends in ".app" to see if it is a
908            //  proper application bundle. If it is, the plugins path is added
909            std::string bundlePath = GetApplicationBundlePath(myBundle);
910            if( bundlePath.substr(bundlePath.length() - 4, 4) == std::string(".app") )
911                filepath.push_back(GetApplicationPluginsPath(myBundle));
[3330]912        }
913        else
914        {
[3331]915            osg::notify( osg::DEBUG_INFO ) << "Couldn't find the Application Bundle" << std::endl;
[3330]916        }
917
918        // Next, check the User's Application Support folder
919        errCode = FSFindFolder( kUserDomain, kApplicationSupportFolderType, kDontCreateFolder, &f );
920        if(noErr == errCode)
921        {
922            // Get the URL
923            url = CFURLCreateFromFSRef( 0, &f );
[4420]924            if(url)
[4990]925            {
[4420]926                filepath.push_back(GetPathFromCFURLRef(url) + OSG_PLUGIN_PATH);
[4990]927                CFRelease( url );
928            }
[4419]929            else
[4420]930                osg::notify( osg::DEBUG_INFO ) << "Couldn't create CFURLRef for User's application support Path" << std::endl;
931
[4419]932            url = NULL;
[3330]933        }
934        else
935        {
[3331]936            osg::notify( osg::DEBUG_INFO ) << "Couldn't find the User's Application Support Path" << std::endl;
[3330]937        }
938
939        // Next, check the Local System's Application Support Folder
940        errCode = FSFindFolder( kLocalDomain, kApplicationSupportFolderType, kDontCreateFolder, &f );
941        if(noErr == errCode)
942        {
943            // Get the URL
944            url = CFURLCreateFromFSRef( 0, &f );
[4420]945           
946            if(url)
[4990]947            {
[4420]948                filepath.push_back(GetPathFromCFURLRef(url) + OSG_PLUGIN_PATH);
[4990]949                CFRelease( url );
950            }
[4419]951            else
[4420]952                osg::notify( osg::DEBUG_INFO ) << "Couldn't create CFURLRef for local System's ApplicationSupport Path" << std::endl;
953
[4419]954            url = NULL;
[3330]955        }
956        else
957        {
[3331]958            osg::notify( osg::DEBUG_INFO ) << "Couldn't find the Local System's Application Support Path" << std::endl;
[3330]959        }
960
961        // Finally, check the Network Application Support Folder
962        // This one has a likely chance of not existing so an error
963        // may be returned. Don't panic.
964        errCode = FSFindFolder( kNetworkDomain, kApplicationSupportFolderType, kDontCreateFolder, &f );
965        if(noErr == errCode)
966        {
967            // Get the URL
968            url = CFURLCreateFromFSRef( 0, &f );
[4420]969           
970            if(url)
[4990]971            {
[4420]972                filepath.push_back(GetPathFromCFURLRef(url) + OSG_PLUGIN_PATH);
[4990]973                CFRelease( url );
974            }
[4419]975            else
[4420]976                osg::notify( osg::DEBUG_INFO ) << "Couldn't create CFURLRef for network Application Support Path" << std::endl;
977
978            url = NULL;
[3330]979        }
980        else
981        {
[4327]982        // had to comment out as it segfauls the OSX app otherwise
[3410]983            // osg::notify( osg::DEBUG_INFO ) << "Couldn't find the Network Application Support Path" << std::endl;
[3330]984        }
985    }
[3333]986    #else
987    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
988    {
989        char* ptr;
990        if ((ptr = getenv( "DYLD_LIBRARY_PATH" )) )
991        {
992            convertStringPathIntoFilePathList(ptr, filepath);
993        }
[8901]994
995        appendInstallationLibraryFilePaths(filepath);
[3333]996    }
[3330]997    #endif
998   
999#else   
1000
1001    void osgDB::appendPlatformSpecificLibraryFilePaths(FilePathList& filepath)
1002    {
1003
1004       char* ptr;
1005       if( (ptr = getenv( "LD_LIBRARY_PATH" )) )
1006        {
1007            convertStringPathIntoFilePathList(ptr,filepath);
1008        }
1009
[8901]1010        appendInstallationLibraryFilePaths(filepath);
[4327]1011
1012#if defined(__ia64__) || defined(__x86_64__)
1013        convertStringPathIntoFilePathList("/usr/lib/:/usr/lib64/:/usr/local/lib/:/usr/local/lib64/",filepath);
1014#else
[3330]1015        convertStringPathIntoFilePathList("/usr/lib/:/usr/local/lib/",filepath);
[4327]1016#endif
[3330]1017
1018    }
1019
1020#endif
1021
1022
1023
1024
[4420]1025#ifdef __APPLE__
1026    void osgDB::appendPlatformSpecificResourceFilePaths(FilePathList& filepath)
1027    {
1028        // Get the main application bundle
1029        CFBundleRef mainBundle = CFBundleGetMainBundle();
1030       
1031        if (mainBundle != NULL) {
1032            // Get the parent directory and the resources directory
1033            std::string bundlePath = GetApplicationBundlePath(mainBundle);
1034            std::string resourcesPath = GetApplicationResourcesPath(mainBundle);
1035           
1036            // check if application is really part of a .app bundle
1037            if(bundlePath.substr(bundlePath.length() - 4, 4) == std::string(".app"))
1038            {
1039                if(resourcesPath != std::string(""))
1040                    filepath.push_back( resourcesPath );
1041               
1042                std::string parentPath = GetShortenedPath(bundlePath, 1);
1043                if(parentPath != std::string(""))
1044                    filepath.push_back( parentPath );
1045            }
1046        }
1047        else
1048        {
1049            osg::notify( osg::DEBUG_INFO ) << "Couldn't find the Application Bundle." << std::endl;
1050        }
1051    }
1052#else
[4600]1053    void osgDB::appendPlatformSpecificResourceFilePaths(FilePathList& /*filepath*/)
[4420]1054    {
1055    }
1056#endif
[3330]1057
1058
1059
1060
1061
Note: See TracBrowser for help on using the browser.