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

Revision 10024, 38.6 kB (checked in by robert, 5 years ago)

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