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

Revision 13041, 57.5 kB (checked in by robert, 3 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#include <stdio.h>
15#include <string.h>
16
17#include <osg/Notify>
18#include <osg/Object>
19#include <osg/Image>
20#include <osg/Shader>
21#include <osg/Node>
22#include <osg/Group>
23#include <osg/Geode>
24#include <osg/ApplicationUsage>
25#include <osg/Version>
26#include <osg/Timer>
27
28#include <osgDB/Registry>
29#include <osgDB/FileUtils>
30#include <osgDB/FileNameUtils>
31#include <osgDB/fstream>
32#include <osgDB/Archive>
33
34#include <algorithm>
35#include <set>
36#include <memory>
37
38#include <stdlib.h>
39
40#if defined(__sgi)
41    #include <ctype.h>
42#elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__)
43    #include <cctype>
44    using std::tolower;
45#endif
46
47#ifdef OSG_LIBRARY_POSTFIX
48    #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_LIBRARY_POSTFIX)
49#else
50    #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ""
51#endif
52
53using namespace osg;
54using namespace osgDB;
55
56#if !defined(WIN32) || defined(__CYGWIN__)
57static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[:path]..","Paths for locating datafiles");
58static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[:path]..","Paths for locating libraries/ plugins");
59#else
60static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[;path]..","Paths for locating datafiles");
61static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[;path]..","Paths for locating libraries/ plugins");
62#endif
63
64static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry.");
65
66
67// from MimeTypes.cpp
68extern const char* builtinMimeTypeExtMappings[];
69
70
71class Registry::AvailableReaderWriterIterator
72{
73public:
74    AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex):
75        _rwList(rwList),
76        _pluginMutex(pluginMutex) {}
77
78
79    ReaderWriter& operator * () { return *get(); }
80    ReaderWriter* operator -> () { return get(); }
81
82    bool valid() { return get()!=0; }
83
84    void operator ++()
85    {
86        _rwUsed.insert(get());
87    }
88
89
90protected:
91
92    AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; }
93
94    Registry::ReaderWriterList&     _rwList;
95    OpenThreads::ReentrantMutex&    _pluginMutex;
96
97    std::set<ReaderWriter*>         _rwUsed;
98
99    ReaderWriter* get()
100    {
101        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
102        Registry::ReaderWriterList::iterator itr=_rwList.begin();
103        for(;itr!=_rwList.end();++itr)
104        {
105            if (_rwUsed.find(itr->get())==_rwUsed.end())
106            {
107                return itr->get();
108            }
109        }
110        return 0;
111    }
112
113};
114
115class Registry::AvailableArchiveIterator
116{
117public:
118    AvailableArchiveIterator(Registry::ArchiveCache& archives, OpenThreads::ReentrantMutex& mutex):
119        _archives(archives),
120        _mutex(mutex) {}
121
122
123    Archive& operator * () { return *get(); }
124    Archive* operator -> () { return get(); }
125
126    bool valid() { return get()!=0; }
127
128    void operator ++()
129    {
130        _archivesUsed.insert(get());
131    }
132
133
134protected:
135
136    AvailableArchiveIterator& operator = (const AvailableArchiveIterator&) { return *this; }
137
138    Registry::ArchiveCache&         _archives;
139    OpenThreads::ReentrantMutex&    _mutex;
140
141    std::set<Archive*>              _archivesUsed;
142
143    Archive* get()
144    {
145        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
146        Registry::ArchiveCache::iterator itr=_archives.begin();
147        for(;itr!=_archives.end();++itr)
148        {
149            if (_archivesUsed.find(itr->second.get())==_archivesUsed.end())
150            {
151                return itr->second.get();
152            }
153        }
154        return 0;
155    }
156
157};
158
159#if 0
160    // temporary test of autoregistering, not compiled by default.
161    enum Methods
162    {
163        SET_1,
164        SET_2,
165        END
166    };
167
168
169    typedef std::pair<Methods,std::string> MethodPair;
170
171    class Proxy
172    {
173    public:
174        Proxy(MethodPair* methods)
175        {
176            std::cout<<"methods "<<methods<<std::endl;
177            for(int i=0;methods[i].first!=END;++i)
178            {
179                std::cout<<"\t"<<methods[i].first<<"\t"<<methods[i].second<<std::endl;
180            }
181        }
182    };
183
184
185    static MethodPair methods[] =
186    {
187        MethodPair(SET_1,"SET_1"),
188        MethodPair(SET_2,"SET_2"),
189        MethodPair(END,"")
190    };
191
192    Proxy myproxy(methods);
193
194#endif
195
196void PrintFilePathList(std::ostream& stream,const FilePathList& filepath)
197{
198    for(FilePathList::const_iterator itr=filepath.begin();
199        itr!=filepath.end();
200        ++itr)
201    {
202        stream << "    "<< *itr<<std::endl;
203    }
204}
205
206Registry* Registry::instance(bool erase)
207{
208    static ref_ptr<Registry> s_registry = new Registry;
209    if (erase)
210    {
211        s_registry->destruct();
212        s_registry = 0;
213    }
214    return s_registry.get(); // will return NULL on erase
215}
216
217
218// definition of the Registry
219Registry::Registry()
220{
221    // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify().
222    // OSG_INFO << "Constructing osg::Registry"<<std::endl;
223
224    _buildKdTreesHint = Options::NO_PREFERENCE;
225    _kdTreeBuilder = new osg::KdTreeBuilder;
226
227    const char* kdtree_str = getenv("OSG_BUILD_KDTREES");
228    if (kdtree_str)
229    {
230        bool switchOff = (strcmp(kdtree_str, "off")==0 || strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 );
231        if (switchOff) _buildKdTreesHint = Options::DO_NOT_BUILD_KDTREES;
232        else _buildKdTreesHint = Options::BUILD_KDTREES;
233    }
234
235    const char* ptr=0;
236
237    _expiryDelay = 10.0;
238    if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0)
239    {
240        _expiryDelay = osg::asciiToDouble(ptr);
241        OSG_INFO<<"Registry : Expiry delay = "<<_expiryDelay<<std::endl;
242    }
243
244    const char* fileCachePath = getenv("OSG_FILE_CACHE");
245    if (fileCachePath)
246    {
247        _fileCache = new FileCache(fileCachePath);
248    }
249
250    _createNodeFromImage = false;
251    _openingLibrary = false;
252
253    // add default osga archive extension
254    _archiveExtList.push_back("osga");
255    _archiveExtList.push_back("zip");
256
257    initFilePathLists();
258
259
260
261    // register file extension alias.
262    const char* flt_str = getenv("OSG_OPEN_FLIGHT_PLUGIN");
263    if (flt_str)
264    {
265        if (strcmp(flt_str, "new")==0)
266        {
267            addFileExtensionAlias("flt", "OpenFlight");
268        }
269    }
270    else
271    {
272    #ifndef COMPILE_WITH_OLD_OPENFLIGHT_PLUGIN_AS_DEFAULT
273        addFileExtensionAlias("flt", "OpenFlight");
274    #endif
275    }
276
277    addFileExtensionAlias("osgs", "osg");
278    addFileExtensionAlias("osgt", "osg");
279    addFileExtensionAlias("osgb", "osg");
280    addFileExtensionAlias("osgx", "osg");
281
282    addFileExtensionAlias("shadow""osgshadow");
283    addFileExtensionAlias("terrain", "osgterrain");
284    addFileExtensionAlias("view""osgviewer");
285
286    addFileExtensionAlias("sgi""rgb");
287    addFileExtensionAlias("rgba", "rgb");
288    addFileExtensionAlias("int""rgb");
289    addFileExtensionAlias("inta", "rgb");
290    addFileExtensionAlias("bw",   "rgb");
291
292    addFileExtensionAlias("ivz""gz");
293    addFileExtensionAlias("ozg""gz");
294
295    addFileExtensionAlias("mag""dicom");
296    addFileExtensionAlias("ph",   "dicom");
297    addFileExtensionAlias("ima""dicom");
298    addFileExtensionAlias("dcm""dicom");
299    addFileExtensionAlias("dic""dicom");
300
301    addFileExtensionAlias("gl",   "glsl");
302    addFileExtensionAlias("vert", "glsl");
303    addFileExtensionAlias("frag", "glsl");
304    addFileExtensionAlias("geom", "glsl");
305
306
307#if defined(DARWIN_IMAGEIO)
308    addFileExtensionAlias("jpg""imageio");
309    addFileExtensionAlias("jpe""imageio");
310    addFileExtensionAlias("jpeg", "imageio");
311    addFileExtensionAlias("tif""imageio");
312    addFileExtensionAlias("tiff", "imageio");
313    addFileExtensionAlias("gif""imageio");
314    addFileExtensionAlias("png""imageio");
315    addFileExtensionAlias("psd""imageio");
316    addFileExtensionAlias("tga""imageio");
317
318#endif
319
320#if defined(DARWIN_QTKIT)
321    addFileExtensionAlias("mov""QTKit");
322    addFileExtensionAlias("mp4""QTKit");
323    addFileExtensionAlias("mov""QTKit");
324    addFileExtensionAlias("mpg""QTKit");
325    addFileExtensionAlias("mpeg""QTKit");
326    addFileExtensionAlias("mpv""QTKit");
327    addFileExtensionAlias("m4v""QTKit");
328    addFileExtensionAlias("3gp""QTKit");
329    addFileExtensionAlias("live", "QTKit");
330    // Requires Perian
331    addFileExtensionAlias("avi""QTKit");
332    addFileExtensionAlias("xvid""QTKit");
333    // Requires Flip4Mac
334    addFileExtensionAlias("wmv""QTKit");
335#endif
336
337#if defined(DARWIN_QUICKTIME)
338
339    addFileExtensionAlias("jpg""qt");
340    addFileExtensionAlias("jpe""qt");
341    addFileExtensionAlias("jpeg", "qt");
342    addFileExtensionAlias("tif""qt");
343    addFileExtensionAlias("tiff", "qt");
344    addFileExtensionAlias("gif""qt");
345    addFileExtensionAlias("png""qt");
346    addFileExtensionAlias("psd""qt");
347    addFileExtensionAlias("tga""qt");
348    addFileExtensionAlias("flv""qt");
349    addFileExtensionAlias("dv",   "qt");
350    #if !defined(DARWIN_QTKIT)
351
352        addFileExtensionAlias("mov""qt");
353        addFileExtensionAlias("avi""qt");
354        addFileExtensionAlias("mpg""qt");
355        addFileExtensionAlias("mpv""qt");
356        addFileExtensionAlias("mp4""qt");
357        addFileExtensionAlias("m4v""qt");
358        addFileExtensionAlias("3gp""qt");
359        // Add QuickTime live support for OSX
360        addFileExtensionAlias("live", "qt");
361    #endif
362#else
363    addFileExtensionAlias("jpg""jpeg");
364    addFileExtensionAlias("jpe""jpeg");
365    addFileExtensionAlias("tif""tiff");
366
367    // really need to decide this at runtime...
368    #if defined(USE_XINE)
369
370        addFileExtensionAlias("mov""xine");
371        addFileExtensionAlias("mpg""xine");
372        addFileExtensionAlias("ogv""xine");
373        addFileExtensionAlias("mpv""xine");
374        addFileExtensionAlias("dv",   "xine");
375        addFileExtensionAlias("avi""xine");
376        addFileExtensionAlias("wmv""xine");
377        addFileExtensionAlias("flv""xine");
378    #endif
379
380    // support QuickTime for Windows
381    // Logic error here. It is possible for Apple to not define Quicktime and end up in
382    // this Quicktime for Windows block. So add an extra check to avoid QTKit clashes.
383    #if defined(USE_QUICKTIME) && !defined(DARWIN_QTKIT)
384
385        addFileExtensionAlias("mov""qt");
386        addFileExtensionAlias("live", "qt");
387        addFileExtensionAlias("mpg""qt");
388        addFileExtensionAlias("avi""qt");
389    #endif
390#endif
391
392    // remove geo to lwo alias as the new Carbon Graphics GEO format
393    // also uses the .geo. It is still possible to load light wave .geo
394    // files via loading the lwo plugin explicitly and then doing a readNodeFile.
395    //addFileExtensionAlias("geo",  "lwo");
396    addFileExtensionAlias("lw",   "lwo");
397
398    #if defined(USE_VRML)
399        addFileExtensionAlias("wrl",   "vrml");
400    #elif defined(USE_INVENTOR)
401        addFileExtensionAlias("wrl",   "iv");
402    #endif
403
404    // add alias for the text/freetype plugin.
405    addFileExtensionAlias("ttf",    "freetype");  // true type
406    addFileExtensionAlias("ttc",    "freetype");  // true type
407    addFileExtensionAlias("cid",    "freetype");  // Postscript CID-Fonts
408    addFileExtensionAlias("cff",    "freetype");  // OpenType
409    addFileExtensionAlias("cef",    "freetype");  // OpenType
410    addFileExtensionAlias("fon",    "freetype");  // Windows bitmap fonts
411    addFileExtensionAlias("fnt",    "freetype");  // Windows bitmap fonts
412    addFileExtensionAlias("text3d", "freetype"); // use 3D Font instead of 2D Font
413
414    // wont't add type1 and type2 until resolve extension collision with Performer binary and ascii files.
415    // addFileExtensionAlias("pfb",   "freetype");  // type1 binary
416    // addFileExtensionAlias("pfa",   "freetype");  // type2 ascii
417
418
419    // portable bitmap, greyscale and colour/pixmap image formats
420    addFileExtensionAlias("pbm", "pnm");
421    addFileExtensionAlias("pgm", "pnm");
422    addFileExtensionAlias("ppm", "pnm");
423
424
425    // add revision file mappings
426    addFileExtensionAlias("added",    "revisions");
427    addFileExtensionAlias("removed""revisions");
428    addFileExtensionAlias("modified", "revisions");
429
430
431
432
433    // add built-in mime-type extension mappings
434    for( int i=0; ; i+=2 )
435    {
436        std::string mimeType = builtinMimeTypeExtMappings[i];
437        if ( mimeType.length() == 0 )
438            break;
439        addMimeTypeExtensionMapping( mimeType, builtinMimeTypeExtMappings[i+1] );
440    }
441
442    // register server protocols, so the curl can handle it, if necessary
443    registerProtocol("http");
444    registerProtocol("https");
445    registerProtocol("ftp");
446    registerProtocol("ftps");
447
448    _objectWrapperManager = new ObjectWrapperManager;
449    _deprecatedDotOsgWrapperManager = new DeprecatedDotOsgWrapperManager;
450}
451
452
453Registry::~Registry()
454{
455    destruct();
456}
457
458void Registry::destruct()
459{
460    // OSG_NOTICE<<"Registry::destruct()"<<std::endl;
461
462    // clean up the SharedStateManager
463    _sharedStateManager = 0;
464
465
466    // clean up the FileCache
467    _fileCache = 0;
468
469
470    // object cache clear needed here to prevent crash in unref() of
471    // the objects it contains when running the TXP plugin.
472    // Not sure why, but perhaps there is is something in a TXP plugin
473    // which deletes the data before its ref count hits zero, perhaps
474    // even some issue with objects be allocated by a plugin that is
475    // maintained after that plugin is deleted...  Robert Osfield, Jan 2004.
476    clearObjectCache();
477    clearArchiveCache();
478
479
480    // unload all the plugin before we finally destruct.
481    closeAllLibraries();
482}
483
484#include <iostream>
485
486void Registry::initDataFilePathList()
487{
488    FilePathList filepath;
489    //
490    // set up data file paths
491    //
492    char *ptr;
493
494    if( (ptr = getenv( "OSG_FILE_PATH" )) )
495    {
496        //OSG_NOTIFY(DEBUG_INFO) << "OSG_FILE_PATH("<<ptr<<")"<<std::endl;
497        convertStringPathIntoFilePathList(ptr, filepath);
498    }
499    else if( (ptr = getenv( "OSGFILEPATH" )) )
500    {
501        //OSG_NOTIFY(DEBUG_INFO) << "OSGFILEPATH("<<ptr<<")"<<std::endl;
502        convertStringPathIntoFilePathList(ptr, filepath);
503    }
504
505    osgDB::appendPlatformSpecificResourceFilePaths(filepath);
506    setDataFilePathList(filepath);
507
508}
509
510void Registry::setDataFilePathList(const std::string& paths)
511{
512    _dataFilePath.clear();
513    convertStringPathIntoFilePathList(paths,_dataFilePath);
514}
515
516void Registry::setLibraryFilePathList(const std::string& paths) { _libraryFilePath.clear(); convertStringPathIntoFilePathList(paths,_libraryFilePath); }
517
518
519
520void Registry::initLibraryFilePathList()
521{
522    //
523    // set up library paths
524    //
525    char* ptr;
526    if( (ptr = getenv( "OSG_LIBRARY_PATH")) )
527    {
528        //OSG_NOTIFY(DEBUG_INFO) << "OSG_LIBRARY_PATH("<<ptr<<")"<<std::endl;
529        setLibraryFilePathList(ptr);
530    }
531    else if( (ptr = getenv( "OSG_LD_LIBRARY_PATH")) )
532    {
533        //OSG_NOTIFY(DEBUG_INFO) << "OSG_LD_LIBRARY_PATH("<<ptr<<")"<<std::endl;
534        setLibraryFilePathList(ptr);
535    }
536
537    appendPlatformSpecificLibraryFilePaths(_libraryFilePath);
538
539}
540
541
542void Registry::readCommandLine(osg::ArgumentParser& arguments)
543{
544    // report the usage options.
545    if (arguments.getApplicationUsage())
546    {
547        arguments.getApplicationUsage()->addCommandLineOption("-l <library>","Load the plugin");
548        arguments.getApplicationUsage()->addCommandLineOption("-e <extension>","Load the plugin associated with handling files with specified extension");
549        arguments.getApplicationUsage()->addCommandLineOption("-O <option_string>","Provide an option string to reader/writers used to load databases");
550    }
551
552    std::string value;
553    while(arguments.read("-l",value))
554    {
555        loadLibrary(value);
556    }
557
558    while(arguments.read("-e",value))
559    {
560        std::string libName = createLibraryNameForExtension(value);
561        loadLibrary(libName);
562    }
563
564    while(arguments.read("-O",value))
565    {
566        setOptions(new Options(value));
567    }
568}
569
570void Registry::addReaderWriter(ReaderWriter* rw)
571{
572    if (rw==0L) return;
573
574    // OSG_NOTIFY(INFO) << "osg::Registry::addReaderWriter("<<rw->className()<<")"<< std::endl;
575
576    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
577
578    _rwList.push_back(rw);
579
580}
581
582
583void Registry::removeReaderWriter(ReaderWriter* rw)
584{
585    if (rw==0L) return;
586
587//    OSG_NOTIFY(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl;
588
589    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
590
591    ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw);
592    if (rwitr!=_rwList.end())
593    {
594        _rwList.erase(rwitr);
595    }
596
597}
598
599ImageProcessor* Registry::getImageProcessor()
600{
601    {
602        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
603        if (!_ipList.empty())
604        {
605            return _ipList.front().get();
606        }
607    }
608    return getImageProcessorForExtension("nvtt");
609}
610
611ImageProcessor* Registry::getImageProcessorForExtension(const std::string& ext)
612{
613    {
614        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
615        if (!_ipList.empty())
616        {
617            return _ipList.front().get();
618        }
619    }
620
621    std::string libraryName = createLibraryNameForExtension(ext);
622    OSG_NOTICE << "Now checking for plug-in "<<libraryName<< std::endl;
623    if (loadLibrary(libraryName)==LOADED)
624    {
625        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
626        if (!_ipList.empty())
627        {
628            OSG_NOTICE << "Loaded plug-in "<<libraryName<<" and located ImageProcessor"<< std::endl;
629            return _ipList.front().get();
630        }
631    }
632    return 0;
633}
634
635void Registry::addImageProcessor(ImageProcessor* ip)
636{
637    if (ip==0L) return;
638
639    OSG_NOTIFY(NOTICE) << "osg::Registry::addImageProcessor("<<ip->className()<<")"<< std::endl;
640
641    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
642
643    _ipList.push_back(ip);
644
645}
646
647
648void Registry::removeImageProcessor(ImageProcessor* ip)
649{
650    if (ip==0L) return;
651
652    OSG_NOTIFY(NOTICE) << "osg::Registry::removeImageProcessor();"<< std::endl;
653
654    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
655
656    ImageProcessorList::iterator ipitr = std::find(_ipList.begin(),_ipList.end(),ip);
657    if (ipitr!=_ipList.end())
658    {
659        _ipList.erase(ipitr);
660    }
661
662}
663
664
665void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
666{
667    _extAliasMap[mapExt] = toExt;
668}
669
670void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt)
671{
672    _mimeTypeExtMap[fromMimeType] = toExt;
673}
674
675bool Registry::readPluginAliasConfigurationFile( const std::string& file )
676{
677    std::string fileName = osgDB::findDataFile( file );
678    if (fileName.empty())
679    {
680        OSG_NOTIFY( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl;
681        return false;
682    }
683
684    osgDB::ifstream ifs;
685    ifs.open( fileName.c_str() );
686    if (!ifs.good())
687    {
688        OSG_NOTIFY( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl;
689        return false;
690    }
691
692    int lineNum( 0 );
693    while (ifs.good())
694    {
695        std::string raw;
696        ++lineNum;
697        std::getline( ifs, raw );
698        std::string ln = trim( raw );
699        if (ln.empty()) continue;
700        if (ln[0] == '#') continue;
701
702        std::string::size_type spIdx = ln.find_first_of( " \t" );
703        if (spIdx == ln.npos)
704        {
705            // mapExt and toExt must be on the same line, separated by a space.
706            OSG_NOTIFY( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl;
707            continue;
708        }
709
710        const std::string mapExt = trim( ln.substr( 0, spIdx ) );
711        const std::string toExt = trim( ln.substr( spIdx+1 ) );
712        addFileExtensionAlias( mapExt, toExt );
713    }
714    return true;
715}
716
717std::string Registry::trim( const std::string& str )
718{
719    if (!str.size()) return str;
720    std::string::size_type first = str.find_first_not_of( " \t" );
721    std::string::size_type last = str.find_last_not_of( "  \t\r\n" );
722    if ((first==str.npos) || (last==str.npos)) return std::string( "" );
723    return str.substr( first, last-first+1 );
724}
725
726
727std::string Registry::createLibraryNameForFile(const std::string& fileName)
728{
729    return createLibraryNameForExtension(getFileExtension(fileName));
730}
731
732std::string Registry::createLibraryNameForExtension(const std::string& ext)
733{
734    std::string lowercase_ext;
735    for(std::string::const_iterator sitr=ext.begin();
736        sitr!=ext.end();
737        ++sitr)
738    {
739        lowercase_ext.push_back(tolower(*sitr));
740    }
741
742    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
743    if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);
744
745#if defined(OSG_JAVA_BUILD)
746    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
747#else
748    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
749#endif
750
751#if defined(__CYGWIN__)
752    return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
753#elif defined(__MINGW32__)
754    return prepend+"mingw_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
755#elif defined(WIN32)
756    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
757#elif macintosh
758    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES;
759#else
760    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+ADDQUOTES(OSG_PLUGIN_EXTENSION);
761#endif
762
763}
764
765std::string Registry::createLibraryNameForNodeKit(const std::string& name)
766{
767#if defined(__CYGWIN__)
768    return "cyg"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
769#elif defined(__MINGW32__)
770    return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
771#elif defined(WIN32)
772    return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
773#elif macintosh
774    return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES;
775#else
776    return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES + ADDQUOTES(OSG_PLUGIN_EXTENSION);
777#endif
778}
779
780Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
781{
782    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
783
784    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
785    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
786
787    _openingLibrary=true;
788
789    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
790    _openingLibrary=false;
791
792    if (dl)
793    {
794        _dlList.push_back(dl);
795        return LOADED;
796    }
797    return NOT_LOADED;
798}
799
800
801bool Registry::closeLibrary(const std::string& fileName)
802{
803    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
804    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
805    if (ditr!=_dlList.end())
806    {
807        _dlList.erase(ditr);
808        return true;
809    }
810    return false;
811}
812
813void Registry::closeAllLibraries()
814{
815    // OSG_NOTICE<<"Registry::closeAllLibraries()"<<std::endl;
816    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
817    _dlList.clear();
818}
819
820Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
821{
822    DynamicLibraryList::iterator ditr = _dlList.begin();
823    for(;ditr!=_dlList.end();++ditr)
824    {
825        if ((*ditr)->getName()==fileName) return ditr;
826    }
827    return _dlList.end();
828}
829
830DynamicLibrary* Registry::getLibrary(const std::string& fileName)
831{
832    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
833    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
834    if (ditr!=_dlList.end()) return ditr->get();
835    else return NULL;
836}
837
838ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
839{
840    // record the existing reader writer.
841    std::set<ReaderWriter*> rwOriginal;
842
843    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
844
845    // first attemt one of the installed loaders
846    for(ReaderWriterList::iterator itr=_rwList.begin();
847        itr!=_rwList.end();
848        ++itr)
849    {
850        rwOriginal.insert(itr->get());
851        if((*itr)->acceptsExtension(ext)) return (*itr).get();
852    }
853
854    // now look for a plug-in to load the file.
855    std::string libraryName = createLibraryNameForExtension(ext);
856    OSG_NOTIFY(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
857    if (loadLibrary(libraryName)==LOADED)
858    {
859        for(ReaderWriterList::iterator itr=_rwList.begin();
860            itr!=_rwList.end();
861            ++itr)
862        {
863            if (rwOriginal.find(itr->get())==rwOriginal.end())
864            {
865                if((*itr)->acceptsExtension(ext)) return (*itr).get();
866            }
867        }
868    }
869
870    return NULL;
871
872}
873
874ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType)
875{
876    MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType );
877    return i != _mimeTypeExtMap.end()?
878        getReaderWriterForExtension( i->second ) :
879        NULL;
880}
881
882#if 0
883struct concrete_wrapper: basic_type_wrapper
884{
885    virtual ~concrete_wrapper() {}
886    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
887    bool matches(const osg::Object *proto) const
888    {
889        return myobj_->isSameKindAs(proto);
890    }
891    const osg::Object *myobj_;
892};
893#endif
894
895
896
897struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
898{
899    ReadObjectFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
900
901    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }
902    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
903    virtual bool isValid(osg::Object* object) const { return object!=0;  }
904
905    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadObjectFunctor(filename, options); }
906};
907
908struct Registry::ReadImageFunctor : public Registry::ReadFunctor
909{
910    ReadImageFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
911
912    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }
913    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
914    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
915
916    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadImageFunctor(filename, options); }
917};
918
919struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
920{
921    ReadHeightFieldFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
922
923    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }
924    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
925    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
926
927    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadHeightFieldFunctor(filename, options); }
928};
929
930struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
931{
932    ReadNodeFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
933
934    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }
935    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
936    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
937
938    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadNodeFunctor(filename, options); }
939};
940
941struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
942{
943    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options):
944        ReadFunctor(filename,options),
945        _status(status),
946        _indexBlockSizeHint(indexBlockSizeHint) {}
947
948    ReaderWriter::ArchiveStatus _status;
949    unsigned int _indexBlockSizeHint;
950
951    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
952    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
953    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
954
955    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadArchiveFunctor(filename, _status, _indexBlockSizeHint, options); }
956};
957
958struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
959{
960    ReadShaderFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
961
962    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }
963    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
964    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
965
966    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadShaderFunctor(filename, options); }
967};
968
969void Registry::addArchiveExtension(const std::string ext)
970{
971    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
972        aitr!=_archiveExtList.end();
973        ++aitr)
974    {
975        if ( (*aitr) == ext)   // extension already in archive extension list
976            return;
977    }
978    _archiveExtList.push_back(ext);
979}
980
981std::string Registry::findDataFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
982{
983    if (filename.empty()) return filename;
984
985    // if data file contains a server address then we can't find it in local directories so return empty string.
986    if (containsServerAddress(filename)) return std::string();
987
988    bool absolutePath = osgDB::isAbsolutePath(filename);
989
990    if (absolutePath && fileExists(filename))
991    {
992        OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
993        return filename;
994    }
995
996    std::string fileFound;
997    bool pathsContainsCurrentWorkingDirectory = false;
998
999    if (options && !options->getDatabasePathList().empty())
1000    {
1001        fileFound = findFileInPath(filename, options->getDatabasePathList(), caseSensitivity);
1002        if (!fileFound.empty()) return fileFound;
1003
1004        if (osgDB::containsCurrentWorkingDirectoryReference(options->getDatabasePathList()))
1005        {
1006            pathsContainsCurrentWorkingDirectory = true;
1007        }
1008
1009    }
1010
1011    const FilePathList& filepaths = Registry::instance()->getDataFilePathList();
1012    if (!filepaths.empty())
1013    {
1014        fileFound = findFileInPath(filename, filepaths, caseSensitivity);
1015        if (!fileFound.empty()) return fileFound;
1016
1017        if (!pathsContainsCurrentWorkingDirectory && osgDB::containsCurrentWorkingDirectoryReference(filepaths))
1018        {
1019            pathsContainsCurrentWorkingDirectory = true;
1020        }
1021    }
1022
1023    if (!absolutePath && !pathsContainsCurrentWorkingDirectory)
1024    {
1025        // check current working directory
1026        if (fileExists(filename))
1027        {
1028            return filename;
1029        }
1030    }
1031
1032
1033    // if a directory is included in the filename, get just the (simple) filename itself and try that
1034    std::string simpleFileName = getSimpleFileName(filename);
1035    if (simpleFileName!=filename)
1036    {
1037
1038        if(fileExists(simpleFileName))
1039        {
1040            OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1041            return simpleFileName;
1042        }
1043
1044        if (options && !options->getDatabasePathList().empty())
1045        {
1046            fileFound = findFileInPath(simpleFileName, options->getDatabasePathList(), caseSensitivity);
1047            if (!fileFound.empty()) return fileFound;
1048        }
1049
1050        if (!filepaths.empty())
1051        {
1052            fileFound = findFileInPath(simpleFileName, filepaths,caseSensitivity);
1053            if (!fileFound.empty()) return fileFound;
1054        }
1055
1056    }
1057
1058    // return empty string.
1059    return std::string();
1060}
1061
1062std::string Registry::findLibraryFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
1063{
1064    if (filename.empty())
1065        return filename;
1066
1067    const FilePathList& filepath = Registry::instance()->getLibraryFilePathList();
1068
1069    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
1070    if (!fileFound.empty())
1071        return fileFound;
1072
1073    if(fileExists(filename))
1074    {
1075        OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1076        return filename;
1077    }
1078
1079    // if a directory is included in the filename, get just the (simple) filename itself and try that
1080    std::string simpleFileName = getSimpleFileName(filename);
1081    if (simpleFileName!=filename)
1082    {
1083        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
1084        if (!fileFound.empty()) return fileFound;
1085    }
1086
1087    // failed return empty string.
1088    return std::string();
1089}
1090
1091
1092
1093ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1094{
1095    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1096        aitr!=_archiveExtList.end();
1097        ++aitr)
1098    {
1099        std::string archiveExtension = "." + (*aitr);
1100
1101        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1102        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1103        if (positionArchive!=std::string::npos)
1104        {
1105            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1106            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1107            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1108            OSG_INFO<<"Contains archive : "<<readFunctor._filename<<std::endl;
1109            OSG_INFO<<"         archive : "<<archiveName<<std::endl;
1110            OSG_INFO<<"         filename : "<<fileName<<std::endl;
1111
1112            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1113
1114            if (!result.validArchive()) return result;
1115
1116            osgDB::Archive* archive = result.getArchive();
1117
1118            //if valid options were passed through the read functor clone them
1119            //otherwise make new options
1120            osg::ref_ptr<osgDB::ReaderWriter::Options> options = readFunctor._options ?
1121                readFunctor._options->cloneOptions() :
1122                new osgDB::ReaderWriter::Options;
1123
1124            options->setDatabasePath(archiveName);
1125
1126            std::auto_ptr<ReadFunctor> rf(readFunctor.cloneType(fileName, options.get()));
1127
1128            result = rf->doRead(*archive);
1129
1130            if (rf->isValid(result))
1131            {
1132                OSG_INFO<<"Read object from archive"<<std::endl;
1133                return result;
1134            }
1135            OSG_INFO<<"Failed to read object from archive"<<std::endl;
1136        }
1137    }
1138
1139    // record the errors reported by readerwriters.
1140    typedef std::vector<ReaderWriter::ReadResult> Results;
1141    Results results;
1142
1143    // first attempt to load the file from existing ReaderWriter's
1144    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1145    for(;itr.valid();++itr)
1146    {
1147        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1148        if (readFunctor.isValid(rr)) return rr;
1149        else results.push_back(rr);
1150    }
1151
1152    // check loaded archives.
1153    AvailableArchiveIterator aaitr(_archiveCache, _archiveCacheMutex);
1154    for(;aaitr.valid();++aaitr)
1155    {
1156        ReaderWriter::ReadResult rr = readFunctor.doRead(*aaitr);
1157        if (readFunctor.isValid(rr)) return rr;
1158        else
1159        {
1160            // don't pass on FILE_NOT_FOUND results as we don't want to prevent non archive plugins that haven't been
1161            // loaded yet from getting a chance to test for the presence of the file.
1162            if (rr.status()!=ReaderWriter::ReadResult::FILE_NOT_FOUND) results.push_back(rr);
1163        }
1164    }
1165
1166
1167    if (!results.empty())
1168    {
1169        unsigned int num_FILE_NOT_HANDLED = 0;
1170        unsigned int num_FILE_NOT_FOUND = 0;
1171        unsigned int num_ERROR_IN_READING_FILE = 0;
1172
1173        Results::iterator ritr;
1174        for(ritr=results.begin();
1175            ritr!=results.end();
1176            ++ritr)
1177        {
1178            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1179            else if (ritr->status()==ReaderWriter::ReadResult::NOT_IMPLEMENTED) ++num_FILE_NOT_HANDLED;//Freetype and others
1180            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1181            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1182        }
1183
1184        if (num_FILE_NOT_HANDLED!=results.size())
1185        {
1186            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1187            {
1188                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1189                {
1190                    // OSG_NOTICE<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1191                    return *ritr;
1192                }
1193            }
1194
1195            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1196            if (!osgDB::containsServerAddress(readFunctor._filename))
1197            {
1198                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1199                {
1200                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1201                    {
1202                        //OSG_NOTICE<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1203                        return *ritr;
1204                    }
1205                }
1206            }
1207        }
1208    }
1209
1210    results.clear();
1211
1212    // now look for a plug-in to load the file.
1213    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1214    if (loadLibrary(libraryName)!=NOT_LOADED)
1215    {
1216        for(;itr.valid();++itr)
1217        {
1218            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1219            if (readFunctor.isValid(rr)) return rr;
1220            else results.push_back(rr);
1221        }
1222    }
1223
1224    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1225    //to download the file and use the stream reading functionality of the plugins to load the file
1226    if (containsServerAddress(readFunctor._filename))
1227    {
1228        ReaderWriter* rw = getReaderWriterForExtension("curl");
1229        if (rw)
1230        {
1231            return readFunctor.doRead(*rw);
1232        }
1233        else
1234        {
1235            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1236        }
1237    }
1238
1239    if (!results.empty())
1240    {
1241        unsigned int num_FILE_NOT_HANDLED = 0;
1242        unsigned int num_FILE_NOT_FOUND = 0;
1243        unsigned int num_ERROR_IN_READING_FILE = 0;
1244
1245        Results::iterator ritr;
1246        for(ritr=results.begin();
1247            ritr!=results.end();
1248            ++ritr)
1249        {
1250            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1251            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1252            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1253        }
1254
1255        if (num_FILE_NOT_HANDLED!=results.size())
1256        {
1257            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1258            {
1259                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1260                {
1261                    // OSG_NOTICE<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1262                    return *ritr;
1263                }
1264            }
1265
1266            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1267            {
1268                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1269                {
1270                    // OSG_NOTICE<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1271                    return *ritr;
1272                }
1273            }
1274        }
1275    }
1276    else
1277    {
1278        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1279    }
1280
1281    return results.front();
1282}
1283
1284ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint)
1285{
1286    std::string file(readFunctor._filename);
1287
1288    bool useObjectCache=false;
1289    //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
1290    if (cacheHint!=Options::CACHE_ARCHIVES)
1291    {
1292        const Options* options=readFunctor._options;
1293        useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
1294    }
1295    if (useObjectCache)
1296    {
1297        // search for entry in the object cache.
1298        {
1299            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1300            ObjectCache::iterator oitr=_objectCache.find(file);
1301            if (oitr!=_objectCache.end())
1302            {
1303                OSG_NOTIFY(INFO)<<"returning cached instanced of "<<file<<std::endl;
1304                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1305                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1306            }
1307        }
1308
1309        ReaderWriter::ReadResult rr = read(readFunctor);
1310        if (rr.validObject())
1311        {
1312            // update cache with new entry.
1313            OSG_NOTIFY(INFO)<<"Adding to object cache "<<file<<std::endl;
1314            addEntryToObjectCache(file,rr.getObject());
1315        }
1316        else
1317        {
1318            OSG_NOTIFY(INFO)<<"No valid object found for "<<file<<std::endl;
1319        }
1320
1321        return rr;
1322
1323    }
1324    else
1325    {
1326        ReaderWriter::ReadResult rr = read(readFunctor);
1327        return rr;
1328    }
1329}
1330
1331
1332ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options)
1333{
1334    osg::ref_ptr<osgDB::Archive> archive = getRefFromArchiveCache(fileName);
1335    if (archive.valid()) return archive.get();
1336
1337    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),Options::CACHE_ARCHIVES);
1338
1339    // default to using caching archive if no options structure provided, but if options are provided use archives
1340    // only if supplied.
1341    if (result.validArchive() &&
1342        (!options || (options->getObjectCacheHint() & Options::CACHE_ARCHIVES)) )
1343    {
1344        addToArchiveCache(fileName,result.getArchive());
1345    }
1346    return result;
1347}
1348
1349
1350ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const Options* options)
1351{
1352    return readImplementation(ReadObjectFunctor(fileName, options),Options::CACHE_OBJECTS);
1353}
1354
1355ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const Options* options)
1356{
1357    // record the errors reported by readerwriters.
1358    typedef std::vector<ReaderWriter::WriteResult> Results;
1359    Results results;
1360
1361    // first attempt to load the file from existing ReaderWriter's
1362    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1363    for(;itr.valid();++itr)
1364    {
1365        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1366        if (rr.success()) return rr;
1367        else results.push_back(rr);
1368    }
1369
1370    // now look for a plug-in to save the file.
1371    std::string libraryName = createLibraryNameForFile(fileName);
1372    if (loadLibrary(libraryName)==LOADED)
1373    {
1374        for(;itr.valid();++itr)
1375        {
1376            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1377            if (rr.success()) return rr;
1378            else results.push_back(rr);
1379        }
1380    }
1381
1382    if (results.empty())
1383    {
1384        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1385    }
1386
1387    if (results.front().message().empty())
1388    {
1389        switch(results.front().status())
1390        {
1391            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1392            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1393            default: break;
1394        }
1395    }
1396
1397    return results.front();
1398}
1399
1400
1401
1402ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const Options* options)
1403{
1404    return readImplementation(ReadImageFunctor(fileName, options),Options::CACHE_IMAGES);
1405}
1406
1407ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const Options* options)
1408{
1409    // record the errors reported by readerwriters.
1410    typedef std::vector<ReaderWriter::WriteResult> Results;
1411    Results results;
1412
1413    // first attempt to load the file from existing ReaderWriter's
1414    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1415    for(;itr.valid();++itr)
1416    {
1417        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1418        if (rr.success()) return rr;
1419        else results.push_back(rr);
1420    }
1421
1422    results.clear();
1423
1424    // now look for a plug-in to save the file.
1425    std::string libraryName = createLibraryNameForFile(fileName);
1426    if (loadLibrary(libraryName)==LOADED)
1427    {
1428        for(;itr.valid();++itr)
1429        {
1430            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1431            if (rr.success()) return rr;
1432            else results.push_back(rr);
1433        }
1434    }
1435
1436    if (results.empty())
1437    {
1438        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1439    }
1440
1441    if (results.front().message().empty())
1442    {
1443        switch(results.front().status())
1444        {
1445            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1446            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1447            default: break;
1448        }
1449    }
1450
1451    return results.front();
1452}
1453
1454
1455ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const Options* options)
1456{
1457    return readImplementation(ReadHeightFieldFunctor(fileName, options),Options::CACHE_HEIGHTFIELDS);
1458}
1459
1460ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const Options* options)
1461{
1462    // record the errors reported by readerwriters.
1463    typedef std::vector<ReaderWriter::WriteResult> Results;
1464    Results results;
1465
1466    // first attempt to load the file from existing ReaderWriter's
1467    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1468    for(;itr.valid();++itr)
1469    {
1470        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1471        if (rr.success()) return rr;
1472        else results.push_back(rr);
1473    }
1474
1475    results.clear();
1476
1477    // now look for a plug-in to save the file.
1478    std::string libraryName = createLibraryNameForFile(fileName);
1479    if (loadLibrary(libraryName)==LOADED)
1480    {
1481        for(;itr.valid();++itr)
1482        {
1483            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1484            if (rr.success()) return rr;
1485            else results.push_back(rr);
1486        }
1487    }
1488
1489    if (results.empty())
1490    {
1491        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1492    }
1493
1494    if (results.front().message().empty())
1495    {
1496        switch(results.front().status())
1497        {
1498            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1499            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1500            default: break;
1501        }
1502    }
1503
1504    return results.front();
1505}
1506
1507
1508ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options)
1509{
1510#if 0
1511
1512    osg::Timer_t startTick = osg::Timer::instance()->tick();
1513    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1514    osg::Timer_t endTick = osg::Timer::instance()->tick();
1515    OSG_NOTICE<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1516    return result;
1517
1518#else
1519
1520    return readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1521
1522#endif
1523}
1524
1525ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const Options* options)
1526{
1527    // record the errors reported by readerwriters.
1528    typedef std::vector<ReaderWriter::WriteResult> Results;
1529    Results results;
1530
1531    // first attempt to write the file from existing ReaderWriter's
1532    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1533    for(;itr.valid();++itr)
1534    {
1535        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1536        if (rr.success()) return rr;
1537        else results.push_back(rr);
1538    }
1539
1540    results.clear();
1541
1542    // now look for a plug-in to save the file.
1543    std::string libraryName = createLibraryNameForFile(fileName);
1544
1545
1546    if (loadLibrary(libraryName)==LOADED)
1547    {
1548        for(;itr.valid();++itr)
1549        {
1550            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1551
1552            if (rr.success()) return rr;
1553            else results.push_back(rr);
1554        }
1555    }
1556
1557    if (results.empty())
1558    {
1559        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
1560    }
1561
1562    if (results.front().message().empty())
1563    {
1564        switch(results.front().status())
1565        {
1566            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1567            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1568            default: break;
1569        }
1570    }
1571
1572    return results.front();
1573}
1574
1575ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const Options* options)
1576{
1577    return readImplementation(ReadShaderFunctor(fileName, options),Options::CACHE_SHADERS);
1578}
1579
1580ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const Options* options)
1581{
1582    // record the errors reported by readerwriters.
1583    typedef std::vector<ReaderWriter::WriteResult> Results;
1584    Results results;
1585
1586    // first attempt to load the file from existing ReaderWriter's
1587    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1588    for(;itr.valid();++itr)
1589    {
1590        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1591        if (rr.success()) return rr;
1592        else results.push_back(rr);
1593    }
1594
1595    results.clear();
1596
1597    // now look for a plug-in to save the file.
1598    std::string libraryName = createLibraryNameForFile(fileName);
1599    if (loadLibrary(libraryName)==LOADED)
1600    {
1601        for(;itr.valid();++itr)
1602        {
1603            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1604            if (rr.success()) return rr;
1605            else results.push_back(rr);
1606        }
1607    }
1608
1609    if (results.empty())
1610    {
1611        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
1612    }
1613
1614    if (results.front().message().empty())
1615    {
1616        switch(results.front().status())
1617        {
1618            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1619            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1620            default: break;
1621        }
1622    }
1623
1624    return results.front();
1625}
1626
1627void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
1628{
1629    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1630    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
1631}
1632
1633osg::Object* Registry::getFromObjectCache(const std::string& fileName)
1634{
1635    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1636    ObjectCache::iterator itr = _objectCache.find(fileName);
1637    if (itr!=_objectCache.end()) return itr->second.first.get();
1638    else return 0;
1639}
1640
1641osg::ref_ptr<osg::Object> Registry::getRefFromObjectCache(const std::string& fileName)
1642{
1643    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1644    ObjectCache::iterator itr = _objectCache.find(fileName);
1645    if (itr!=_objectCache.end()) return itr->second.first;
1646    else return 0;
1647}
1648
1649void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp)
1650{
1651    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1652
1653    // look for objects with external references and update their time stamp.
1654    for(ObjectCache::iterator itr=_objectCache.begin();
1655        itr!=_objectCache.end();
1656        ++itr)
1657    {
1658        // if ref count is greater the 1 the object has an external reference.
1659        if (itr->second.first->referenceCount()>1)
1660        {
1661            // so update it time stamp.
1662            itr->second.second = frameStamp.getReferenceTime();
1663        }
1664    }
1665}
1666
1667void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp)
1668{
1669    double expiryTime = frameStamp.getReferenceTime() - _expiryDelay;
1670
1671    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1672
1673    // Remove expired entries from object cache
1674    ObjectCache::iterator oitr = _objectCache.begin();
1675    while(oitr != _objectCache.end())
1676    {
1677        if (oitr->second.second<=expiryTime)
1678        {
1679            _objectCache.erase(oitr++);
1680        }
1681        else
1682        {
1683            ++oitr;
1684        }
1685    }
1686}
1687
1688void Registry::removeFromObjectCache(const std::string& fileName)
1689{
1690    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1691    ObjectCache::iterator itr = _objectCache.find(fileName);
1692    if (itr!=_objectCache.end()) _objectCache.erase(itr);
1693}
1694
1695void Registry::clearObjectCache()
1696{
1697    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1698    _objectCache.clear();
1699}
1700
1701void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
1702{
1703    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1704    _archiveCache[fileName] = archive;
1705}
1706
1707/** Remove archive from cache.*/
1708void Registry::removeFromArchiveCache(const std::string& fileName)
1709{
1710    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1711    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1712    if (itr!=_archiveCache.end())
1713    {
1714        _archiveCache.erase(itr);
1715    }
1716}
1717
1718osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
1719{
1720    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1721    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1722    if (itr!=_archiveCache.end()) return itr->second.get();
1723    else return 0;
1724}
1725
1726osg::ref_ptr<osgDB::Archive> Registry::getRefFromArchiveCache(const std::string& fileName)
1727{
1728    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1729    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1730    if (itr!=_archiveCache.end()) return itr->second;
1731    else return 0;
1732}
1733
1734void Registry::clearArchiveCache()
1735{
1736    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1737    _archiveCache.clear();
1738}
1739
1740void Registry::releaseGLObjects(osg::State* state)
1741{
1742    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1743
1744    for(ObjectCache::iterator itr = _objectCache.begin();
1745        itr != _objectCache.end();
1746        ++itr)
1747    {
1748        osg::Object* object = itr->second.first.get();
1749        object->releaseGLObjects(state);
1750    }
1751
1752    if (_sharedStateManager.valid())
1753    {
1754      _sharedStateManager->releaseGLObjects( state );
1755    }
1756}
1757
1758SharedStateManager* Registry::getOrCreateSharedStateManager()
1759{
1760    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
1761
1762    return _sharedStateManager.get();
1763}
1764
1765
1766void Registry::registerProtocol(const std::string& protocol)
1767{
1768    _registeredProtocols.insert( convertToLowerCase(protocol) );
1769}
1770
1771bool Registry::isProtocolRegistered(const std::string& protocol)
1772{
1773    return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end());
1774}
Note: See TracBrowser for help on using the browser.