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

Revision 13041, 41.4 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

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