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

Revision 9475, 36.4 kB (checked in by robert, 6 years ago)

From Andy Skinner, fixes for Solaris build

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