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

Revision 10356, 72.1 kB (checked in by robert, 8 years ago)

Added ".added", ".modified" and ".removed" alias to .revisions plugin

  • 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
37#include <stdlib.h>
38
39#if defined(__sgi)
40    #include <ctype.h>
41#elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__)
42    #include <cctype>
43    using std::tolower;
44#endif
45
46#ifdef OSG_DEBUG_POSTFIX
47    #define OSG_DEBUG_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_DEBUG_POSTFIX)
48#else
49    #define OSG_DEBUG_POSTFIX_WITH_QUOTES "d"
50#endif
51
52using namespace osg;
53using namespace osgDB;
54
55#if !defined(WIN32) || defined(__CYGWIN__)
56static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[:path]..","Paths for locating datafiles");
57static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[:path]..","Paths for locating libraries/ plugins");
58#else
59static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[;path]..","Paths for locating datafiles");
60static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[;path]..","Paths for locating libraries/ plugins");
61#endif
62
63static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry.");
64
65
66// from MimeTypes.cpp
67extern const char* builtinMimeTypeExtMappings[];
68
69
70class Registry::AvailableReaderWriterIterator
71{
72public:
73    AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex):
74        _rwList(rwList),
75        _pluginMutex(pluginMutex) {}
76
77
78    ReaderWriter& operator * () { return *get(); }
79    ReaderWriter* operator -> () { return get(); }
80   
81    bool valid() { return get()!=0; }
82   
83    void operator ++()
84    {
85        _rwUsed.insert(get());
86    }
87   
88
89protected:
90
91    AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; }
92
93    Registry::ReaderWriterList&     _rwList;
94    OpenThreads::ReentrantMutex&    _pluginMutex;
95   
96    std::set<ReaderWriter*>         _rwUsed;
97
98    ReaderWriter* get()
99    {
100        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
101        Registry::ReaderWriterList::iterator itr=_rwList.begin();
102        for(;itr!=_rwList.end();++itr)
103        {
104            if (_rwUsed.find(itr->get())==_rwUsed.end())
105            {
106                return itr->get();
107            }
108        }
109        return 0;
110    }
111
112};
113
114#if 0
115    // temporary test of autoregistering, not compiled by default.
116    enum Methods
117    {
118        SET_1,
119        SET_2,
120        END
121    };
122
123
124    typedef std::pair<Methods,std::string> MethodPair;
125
126    class Proxy
127    {
128    public:
129        Proxy(MethodPair* methods)
130        {
131            std::cout<<"methods "<<methods<<std::endl;
132            for(int i=0;methods[i].first!=END;++i)
133            {
134                std::cout<<"\t"<<methods[i].first<<"\t"<<methods[i].second<<std::endl;
135            }
136        }
137    };
138
139
140    static MethodPair methods[] =
141    {
142        MethodPair(SET_1,"SET_1"),
143        MethodPair(SET_2,"SET_2"),
144        MethodPair(END,"")
145    };
146
147    Proxy myproxy(methods);
148
149#endif
150
151void PrintFilePathList(std::ostream& stream,const FilePathList& filepath)
152{
153    for(FilePathList::const_iterator itr=filepath.begin();
154        itr!=filepath.end();
155        ++itr)
156    {
157        stream << "    "<< *itr<<std::endl;
158    }
159}
160
161Registry* Registry::instance(bool erase)
162{
163    static ref_ptr<Registry> s_registry = new Registry;
164    if (erase)
165    {   
166        s_registry->destruct();
167        s_registry = 0;
168    }
169    return s_registry.get(); // will return NULL on erase
170}
171
172
173// definition of the Registry
174Registry::Registry()
175{
176    // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify().
177    // notify(INFO) << "Constructing osg::Registry"<<std::endl;
178
179    _buildKdTreesHint = Options::NO_PREFERENCE;
180    _kdTreeBuilder = new osg::KdTreeBuilder;
181   
182    const char* kdtree_str = getenv("OSG_BUILD_KDTREES");
183    if (kdtree_str)
184    {
185        bool switchOff = (strcmp(kdtree_str, "off")==0 || strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 );
186        if (switchOff) _buildKdTreesHint = Options::DO_NOT_BUILD_KDTREES;
187        else _buildKdTreesHint = Options::BUILD_KDTREES;
188    }
189
190    const char* fileCachePath = getenv("OSG_FILE_CACHE");
191    if (fileCachePath)
192    {
193        _fileCache = new FileCache(fileCachePath);   
194    }
195
196    _createNodeFromImage = false;
197    _openingLibrary = false;
198
199    // add default osga archive extension
200    _archiveExtList.push_back("osga");
201   
202    initFilePathLists();
203
204
205
206    // register file extension alias.
207    const char* flt_str = getenv("OSG_OPEN_FLIGHT_PLUGIN");
208    if (flt_str)
209    {
210        if (strcmp(flt_str, "new")==0)
211        {
212            addFileExtensionAlias("flt", "OpenFlight");
213        }
214    }
215    else
216    {
217    #ifndef COMPILE_WITH_OLD_OPENFLIGHT_PLUGIN_AS_DEFAULT
218        addFileExtensionAlias("flt", "OpenFlight");
219    #endif
220    }
221
222    addFileExtensionAlias("osgs", "osg");
223    addFileExtensionAlias("shadow""osgShadow");
224    addFileExtensionAlias("terrain", "osgTerrain");
225    addFileExtensionAlias("view""osgViewer");
226
227    addFileExtensionAlias("sgi""rgb");
228    addFileExtensionAlias("rgba", "rgb");
229    addFileExtensionAlias("int""rgb");
230    addFileExtensionAlias("inta", "rgb");
231    addFileExtensionAlias("bw",   "rgb");
232
233    addFileExtensionAlias("ivz",   "gz");
234    addFileExtensionAlias("ozg",   "gz");
235   
236    addFileExtensionAlias("mag",   "dicom");
237    addFileExtensionAlias("ph",   "dicom");
238    addFileExtensionAlias("ima",   "dicom");
239    addFileExtensionAlias("dcm",   "dicom");
240    addFileExtensionAlias("dic",   "dicom");
241
242    addFileExtensionAlias("gl",   "glsl");
243    addFileExtensionAlias("vert",   "glsl");
244    addFileExtensionAlias("frag",   "glsl");
245
246
247#if defined(DARWIN_IMAGEIO)
248    addFileExtensionAlias("jpg""imageio");
249    addFileExtensionAlias("jpe""imageio");
250    addFileExtensionAlias("jpeg", "imageio");
251    addFileExtensionAlias("tif""imageio");
252    addFileExtensionAlias("tiff", "imageio");
253    addFileExtensionAlias("gif""imageio");
254    addFileExtensionAlias("png""imageio");
255    addFileExtensionAlias("psd""imageio");
256    addFileExtensionAlias("tga""imageio");
257#endif
258
259#if defined(DARWIN_QUICKTIME)
260    addFileExtensionAlias("jpg""qt");
261    addFileExtensionAlias("jpe""qt");
262    addFileExtensionAlias("jpeg", "qt");
263    addFileExtensionAlias("tif""qt");
264    addFileExtensionAlias("tiff", "qt");
265    addFileExtensionAlias("gif""qt");
266    addFileExtensionAlias("png""qt");
267    addFileExtensionAlias("psd""qt");
268    addFileExtensionAlias("tga""qt");
269    addFileExtensionAlias("mov""qt");
270    addFileExtensionAlias("avi""qt");
271    addFileExtensionAlias("mpg""qt");
272    addFileExtensionAlias("flv""qt");
273    addFileExtensionAlias("mpv""qt");
274    addFileExtensionAlias("dv",   "qt");
275    addFileExtensionAlias("mp4""qt");
276    addFileExtensionAlias("m4v""qt");
277    addFileExtensionAlias("3gp""qt");
278    // Add QuickTime live support for OSX
279    addFileExtensionAlias("live", "qt");
280#else
281    addFileExtensionAlias("jpg""jpeg");
282    addFileExtensionAlias("jpe""jpeg");
283    addFileExtensionAlias("tif""tiff");
284
285    // really need to decide this at runtime...
286    #if defined(USE_XINE)
287        addFileExtensionAlias("mov""xine");
288        addFileExtensionAlias("mpg""xine");
289        addFileExtensionAlias("ogv""xine");
290        addFileExtensionAlias("mpv""xine");
291        addFileExtensionAlias("dv",   "xine");
292        addFileExtensionAlias("avi""xine");
293        addFileExtensionAlias("wmv""xine");
294        addFileExtensionAlias("flv""xine");
295    #endif
296
297    // support QuickTime for Windows
298    #if defined(USE_QUICKTIME)
299        addFileExtensionAlias("mov", "qt");
300        addFileExtensionAlias("live", "qt");
301        addFileExtensionAlias("mpg", "qt");
302        addFileExtensionAlias("avi", "qt");
303    #endif
304#endif
305
306    // remove geo to lwo alias as the new Carbon Graphics GEO format
307    // also uses the .geo. It is still possible to load light wave .geo
308    // files via loading the lwo plugin explicitly and then doing a readNodeFile.
309    //addFileExtensionAlias("geo",  "lwo");
310    addFileExtensionAlias("lw",   "lwo");
311
312    #if defined(USE_VRML)
313        addFileExtensionAlias("wrl",   "vrml");   
314    #elif defined(USE_INVENTOR)
315        addFileExtensionAlias("wrl",   "iv");
316    #endif
317   
318    // add alias for the text/freetype plugin.
319    addFileExtensionAlias("ttf",   "freetype");  // true type
320    addFileExtensionAlias("ttc",   "freetype");  // true type
321    addFileExtensionAlias("cid",   "freetype");  // Postscript CID-Fonts
322    addFileExtensionAlias("cff",   "freetype");  // OpenType
323    addFileExtensionAlias("cef",   "freetype");  // OpenType
324    addFileExtensionAlias("fon",   "freetype");  // Windows bitmap fonts
325    addFileExtensionAlias("fnt",   "freetype");  // Windows bitmap fonts
326    addFileExtensionAlias("text3d", "freetype"); // use 3D Font instead of 2D Font
327
328    // wont't add type1 and type2 until resolve extension collision with Performer binary and ascii files.
329    // addFileExtensionAlias("pfb",   "freetype");  // type1 binary
330    // addFileExtensionAlias("pfa",   "freetype");  // type2 ascii
331
332
333    // portable bitmap, greyscale and colour/pixmap image formats
334    addFileExtensionAlias("pbm", "pnm");
335    addFileExtensionAlias("pgm", "pnm");
336    addFileExtensionAlias("ppm", "pnm");
337   
338
339    // add revision file mappings
340    addFileExtensionAlias("added", "revisions");
341    addFileExtensionAlias("removed", "revisions");
342    addFileExtensionAlias("modified", "revisions");
343
344
345
346
347    // add built-in mime-type extension mappings
348    for( int i=0; ; i+=2 )
349    {
350        std::string mimeType = builtinMimeTypeExtMappings[i];
351        if ( mimeType.length() == 0 )
352            break;
353        addMimeTypeExtensionMapping( mimeType, builtinMimeTypeExtMappings[i+1] );
354    }
355   
356    // register http-protocol, so the curl can handle it, if necessary
357    registerProtocol("http");
358}
359
360
361Registry::~Registry()
362{
363    destruct();
364}
365
366void Registry::destruct()
367{
368    // osg::notify(osg::NOTICE)<<"Registry::destruct()"<<std::endl;
369
370    // clean up the SharedStateManager
371    _sharedStateManager = 0;
372   
373
374    // clean up the FileCache
375    _fileCache = 0;
376   
377
378    // object cache clear needed here to prevent crash in unref() of
379    // the objects it contains when running the TXP plugin.
380    // Not sure why, but perhaps there is is something in a TXP plugin
381    // which deletes the data before its ref count hits zero, perhaps
382    // even some issue with objects be allocated by a plugin that is
383    // maintained after that plugin is deleted...  Robert Osfield, Jan 2004.
384    clearObjectCache();
385    clearArchiveCache();
386   
387
388    // unload all the plugin before we finally destruct.
389    closeAllLibraries();
390}
391
392#include <iostream>
393
394void Registry::initDataFilePathList()
395{
396    FilePathList filepath;
397    //
398    // set up data file paths
399    //
400    char *ptr;
401 
402    if( (ptr = getenv( "OSG_FILE_PATH" )) )
403    {
404        //notify(DEBUG_INFO) << "OSG_FILE_PATH("<<ptr<<")"<<std::endl;
405        convertStringPathIntoFilePathList(ptr, filepath);
406    }
407    else if( (ptr = getenv( "OSGFILEPATH" )) )
408    {
409        //notify(DEBUG_INFO) << "OSGFILEPATH("<<ptr<<")"<<std::endl;
410        convertStringPathIntoFilePathList(ptr, filepath);
411    }
412
413    osgDB::appendPlatformSpecificResourceFilePaths(filepath);
414    setDataFilePathList(filepath);
415   
416}
417
418void Registry::setDataFilePathList(const std::string& paths)
419{
420    _dataFilePath.clear();
421    convertStringPathIntoFilePathList(paths,_dataFilePath);
422}
423
424void Registry::setLibraryFilePathList(const std::string& paths) { _libraryFilePath.clear(); convertStringPathIntoFilePathList(paths,_libraryFilePath); }
425
426
427
428void Registry::initLibraryFilePathList()
429{
430    //
431    // set up library paths
432    //
433    char* ptr;
434    if( (ptr = getenv( "OSG_LIBRARY_PATH")) )
435    {
436        //notify(DEBUG_INFO) << "OSG_LIBRARY_PATH("<<ptr<<")"<<std::endl;
437        setLibraryFilePathList(ptr);
438    }
439    else if( (ptr = getenv( "OSG_LD_LIBRARY_PATH")) )
440    {
441        //notify(DEBUG_INFO) << "OSG_LD_LIBRARY_PATH("<<ptr<<")"<<std::endl;
442        setLibraryFilePathList(ptr);
443    }
444   
445    appendPlatformSpecificLibraryFilePaths(_libraryFilePath);
446
447}
448
449
450void Registry::readCommandLine(osg::ArgumentParser& arguments)
451{
452    // report the usage options.
453    if (arguments.getApplicationUsage())
454    {
455        arguments.getApplicationUsage()->addCommandLineOption("-l <library>","Load the plugin");
456        arguments.getApplicationUsage()->addCommandLineOption("-e <extension>","Load the plugin associated with handling files with specified extension");
457        arguments.getApplicationUsage()->addCommandLineOption("-O <option_string>","Provide an option string to reader/writers used to load databases");
458    }
459
460    std::string value;
461    while(arguments.read("-l",value))
462    {
463        loadLibrary(value);
464    }
465       
466    while(arguments.read("-e",value))
467    {
468        std::string libName = createLibraryNameForExtension(value);
469        loadLibrary(libName);
470    }
471
472    while(arguments.read("-O",value))
473    {
474        setOptions(new Options(value));
475    }
476}
477
478void Registry::addDotOsgWrapper(DotOsgWrapper* wrapper)
479{
480    if (wrapper==0L) return;
481
482    //notify(INFO) << "osg::Registry::addDotOsgWrapper("<<wrapper->getName()<<")"<< std::endl;
483    const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
484   
485    for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin();
486                                                  itr!=assoc.end();
487                                                  ++itr)
488    {
489        //notify(INFO) << "    ("<<*itr<<")"<< std::endl;
490    }
491
492    const std::string& name = wrapper->getName();
493    const osg::Object* proto = wrapper->getPrototype();
494
495    _objectWrapperMap[name] = wrapper;
496    if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper;
497   
498    if (proto)
499    {
500        std::string libraryName = proto->libraryName();
501        std::string compositeName = libraryName + "::" + name;
502
503        _objectWrapperMap[compositeName] = wrapper;
504        if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper;
505
506        if (dynamic_cast<const Image*>(proto))
507        {
508            _imageWrapperMap[name] = wrapper;
509            _imageWrapperMap[compositeName] = wrapper;
510        }
511        if (dynamic_cast<const Drawable*>(proto))
512        {
513              _drawableWrapperMap[name] = wrapper;
514              _drawableWrapperMap[compositeName] = wrapper;
515        }
516        if (dynamic_cast<const StateAttribute*>(proto))
517        {
518            _stateAttrWrapperMap[name] = wrapper;
519            _stateAttrWrapperMap[compositeName] = wrapper;
520        }
521        if (dynamic_cast<const Uniform*>(proto))
522        {
523            _uniformWrapperMap[name] = wrapper;
524            _uniformWrapperMap[compositeName] = wrapper;
525        }
526        if (dynamic_cast<const Node*>(proto))
527        {
528            _nodeWrapperMap[name] = wrapper;
529            _nodeWrapperMap[compositeName] = wrapper;
530        }
531        if (dynamic_cast<const Shader*>(proto))
532        {
533            _shaderWrapperMap[name] = wrapper;
534            _shaderWrapperMap[compositeName] = wrapper;
535        }
536
537
538    }
539}
540
541// need to change to delete all instances of wrapper, since we
542// now can have a wrapper entered twice with the addition of the
543// library::class composite name.
544void Registry::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper)
545{
546    typedef std::vector<DotOsgWrapperMap::iterator> EraseList;
547    EraseList eraseList;
548    for(DotOsgWrapperMap::iterator witr=wrappermap.begin();
549        witr!=wrappermap.end();
550        ++witr)
551    {
552        if (witr->second==wrapper) eraseList.push_back(witr);
553    }
554    for(EraseList::iterator eitr=eraseList.begin();
555        eitr!=eraseList.end();
556        ++eitr)
557    {
558        wrappermap.erase(*eitr);
559    }
560}
561
562void Registry::removeDotOsgWrapper(DotOsgWrapper* wrapper)
563{
564    if (wrapper==0L) return;
565
566    eraseWrapper(_objectWrapperMap,wrapper);
567    eraseWrapper(_classNameWrapperMap,wrapper);
568    eraseWrapper(_imageWrapperMap,wrapper);
569    eraseWrapper(_drawableWrapperMap,wrapper);
570    eraseWrapper(_uniformWrapperMap,wrapper);
571    eraseWrapper(_stateAttrWrapperMap,wrapper);
572    eraseWrapper(_nodeWrapperMap,wrapper);
573    eraseWrapper(_shaderWrapperMap,wrapper);
574}
575
576void Registry::addReaderWriter(ReaderWriter* rw)
577{
578    if (rw==0L) return;
579
580    // notify(INFO) << "osg::Registry::addReaderWriter("<<rw->className()<<")"<< std::endl;
581
582    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
583
584    _rwList.push_back(rw);
585
586}
587
588
589void Registry::removeReaderWriter(ReaderWriter* rw)
590{
591    if (rw==0L) return;
592
593//    notify(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl;
594
595    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
596
597    ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw);
598    if (rwitr!=_rwList.end())
599    {
600        _rwList.erase(rwitr);
601    }
602
603}
604
605
606void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
607{
608    _extAliasMap[mapExt] = toExt;
609}
610
611void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt)
612{
613    _mimeTypeExtMap[fromMimeType] = toExt;
614}
615
616bool Registry::readPluginAliasConfigurationFile( const std::string& file )
617{
618    std::string fileName = osgDB::findDataFile( file );
619    if (fileName.empty())
620    {
621        osg::notify( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl;
622        return false;
623    }
624
625    osgDB::ifstream ifs;
626    ifs.open( fileName.c_str() );
627    if (!ifs.good())
628    {
629        osg::notify( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl;
630        return false;
631    }
632
633    int lineNum( 0 );
634    while (ifs.good())
635    {
636        std::string raw;
637        ++lineNum;
638        std::getline( ifs, raw );
639        std::string ln = trim( raw );
640        if (ln.empty()) continue;
641        if (ln[0] == '#') continue;
642
643        std::string::size_type spIdx = ln.find_first_of( " \t" );
644        if (spIdx == ln.npos)
645        {
646            // mapExt and toExt must be on the same line, separated by a space.
647            osg::notify( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl;
648            continue;
649        }
650
651        const std::string mapExt = trim( ln.substr( 0, spIdx ) );
652        const std::string toExt = trim( ln.substr( spIdx+1 ) );
653        addFileExtensionAlias( mapExt, toExt );
654    }
655    return true;
656}
657
658std::string Registry::trim( const std::string& str )
659{
660    if (!str.size()) return str;
661    std::string::size_type first = str.find_first_not_of( " \t" );
662    std::string::size_type last = str.find_last_not_of( "  \t\r\n" );
663    if ((first==str.npos) || (last==str.npos)) return std::string( "" );
664    return str.substr( first, last-first+1 );
665}
666
667
668std::string Registry::createLibraryNameForFile(const std::string& fileName)
669{
670    return createLibraryNameForExtension(getFileExtension(fileName));
671}
672
673std::string Registry::createLibraryNameForExtension(const std::string& ext)
674{
675    std::string lowercase_ext;
676    for(std::string::const_iterator sitr=ext.begin();
677        sitr!=ext.end();
678        ++sitr)
679    {
680        lowercase_ext.push_back(tolower(*sitr));
681    }
682
683    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
684    if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);
685
686#if defined(OSG_JAVA_BUILD)
687    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
688#else
689    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
690#endif
691
692#if defined(__CYGWIN__)
693    #ifdef _DEBUG
694        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_DEBUG_POSTFIX_WITH_QUOTES+".dll";
695    #else
696        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+".dll";
697    #endif
698#elif defined(__MINGW32__)
699    return prepend+"mingw_"+"osgdb_"+lowercase_ext+".dll";
700#elif defined(WIN32)
701    #ifdef _DEBUG
702        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
703    #else
704        return prepend+"osgdb_"+lowercase_ext+".dll";
705    #endif
706#elif macintosh
707    #ifdef _DEBUG
708        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES;
709    #else
710        return prepend+"osgdb_"+lowercase_ext;
711    #endif
712#elif defined(__hpux__)
713    // why don't we use PLUGIN_EXT from the makefiles here?
714    return prepend+"osgdb_"+lowercase_ext+".sl";
715#else
716    #ifdef _DEBUG
717         return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES + ".so";
718    #else
719         return prepend+"osgdb_"+lowercase_ext+".so";
720    #endif
721#endif
722
723}
724
725std::string Registry::createLibraryNameForNodeKit(const std::string& name)
726{
727#if defined(__CYGWIN__)
728    return "cyg"+name+".dll";
729#elif defined(__MINGW32__)
730    return "lib"+name+".dll";
731#elif defined(WIN32)
732    #ifdef _DEBUG
733        return name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
734    #else
735        return name+".dll";
736    #endif
737#elif macintosh
738    #ifdef _DEBUG
739        return name+OSGDEBUG_POSTFIX_WITH_QUOTES;
740    #else
741        return name;
742    #endif
743#elif defined(__hpux__)
744    // why don't we use PLUGIN_EXT from the makefiles here?
745    return "lib"+name+".sl";
746#else
747    #ifdef _DEBUG
748        return "lib"+name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".so";
749    #else
750        return "lib"+name+".so";
751    #endif
752#endif
753}
754
755Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
756{
757    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
758
759    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
760    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
761
762    _openingLibrary=true;
763
764    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
765    _openingLibrary=false;
766
767    if (dl)
768    {
769        _dlList.push_back(dl);
770        return LOADED;
771    }
772    return NOT_LOADED;
773}
774
775
776bool Registry::closeLibrary(const std::string& fileName)
777{
778    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
779    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
780    if (ditr!=_dlList.end())
781    {
782        _dlList.erase(ditr);
783        return true;
784    }
785    return false;
786}
787
788void Registry::closeAllLibraries()
789{
790    // osg::notify(osg::NOTICE)<<"Registry::closeAllLibraries()"<<std::endl;
791    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
792    _dlList.clear();
793}
794
795Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
796{
797    DynamicLibraryList::iterator ditr = _dlList.begin();
798    for(;ditr!=_dlList.end();++ditr)
799    {
800        if ((*ditr)->getName()==fileName) return ditr;
801    }
802    return _dlList.end();
803}
804
805DynamicLibrary* Registry::getLibrary(const std::string& fileName)
806{
807    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
808    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
809    if (ditr!=_dlList.end()) return ditr->get();
810    else return NULL;
811}
812
813ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
814{
815    // record the existing reader writer.
816    std::set<ReaderWriter*> rwOriginal;
817
818    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
819
820    // first attemt one of the installed loaders
821    for(ReaderWriterList::iterator itr=_rwList.begin();
822        itr!=_rwList.end();
823        ++itr)
824    {
825        rwOriginal.insert(itr->get());
826        if((*itr)->acceptsExtension(ext)) return (*itr).get();
827    }
828   
829    // now look for a plug-in to load the file.
830    std::string libraryName = createLibraryNameForExtension(ext);
831    notify(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
832    if (loadLibrary(libraryName)==LOADED)
833    {
834        for(ReaderWriterList::iterator itr=_rwList.begin();
835            itr!=_rwList.end();
836            ++itr)
837        {
838            if (rwOriginal.find(itr->get())==rwOriginal.end())
839            {
840                if((*itr)->acceptsExtension(ext)) return (*itr).get();
841            }
842        }
843    }
844
845    return NULL;
846
847}
848
849ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType)
850{
851    MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType );
852    return i != _mimeTypeExtMap.end()?
853        getReaderWriterForExtension( i->second ) :
854        NULL;
855}
856
857struct concrete_wrapper: basic_type_wrapper
858{
859    virtual ~concrete_wrapper() {}
860    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
861    bool matches(const osg::Object *proto) const
862    {
863        return myobj_->isSameKindAs(proto);
864    }
865    const osg::Object *myobj_;
866};
867
868osg::Object* Registry::readObjectOfType(const osg::Object& compObj,Input& fr)
869{
870    return readObjectOfType(concrete_wrapper(&compObj), fr);
871}
872
873osg::Object* Registry::readObjectOfType(const basic_type_wrapper &btw,Input& fr)
874{
875    const char *str = fr[0].getStr();
876    if (str==NULL) return NULL;
877
878    if (fr[0].matchWord("Use"))
879    {
880        if (fr[1].isString())
881        {
882            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
883            if (obj && btw.matches(obj))
884            {
885                fr+=2;
886                return obj;
887            }
888        }
889        else return NULL;
890
891    }
892
893    std::string name = str;
894    DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name);
895    if (itr==_objectWrapperMap.end())
896    {
897        // not found so check if a library::class composite name.
898        std::string token = fr[0].getStr();
899        std::string::size_type posDoubleColon = token.rfind("::");
900        if (posDoubleColon != std::string::npos)
901        {
902            // we have a composite name so now strip off the library name
903            // are try to load it, and then retry the readObject to see
904            // if we can recognize the objects.
905            std::string libraryName = std::string(token,0,posDoubleColon);
906
907            // first try the standard nodekit library.
908            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
909            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObjectOfType(btw,fr);
910           
911            // otherwise try the osgdb_ plugin library.
912            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
913            if (loadLibrary(pluginLibraryName)==LOADED) return readObjectOfType(btw,fr);
914        }
915    }
916    else if (fr[1].isOpenBracket())
917    {
918        DotOsgWrapper* wrapper = itr->second.get();
919        const osg::Object* proto = wrapper->getPrototype();
920        if (proto==NULL)
921        {
922            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
923            return NULL;
924        }
925       
926        if (!btw.matches(proto))
927        {
928            return NULL;
929        }
930
931        // record the number of nested brackets move the input iterator
932        // over the name { tokens.
933        int entry = fr[0].getNoNestedBrackets();
934        fr+=2;
935
936        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
937        osg::Object* obj = proto->cloneType();
938
939        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
940        {
941            bool iteratorAdvanced = false;
942            if (fr[0].matchWord("UniqueID") && fr[1].isString())
943            {
944                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
945                fr += 2;
946                iteratorAdvanced = true;
947            }
948
949            // read the local data by iterating through the associate
950            // list, mapping the associate names to DotOsgWrapper's which
951            // in turn have the appropriate functions.
952            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
953                                                          aitr!=assoc.end();
954                                                          ++aitr)
955            {
956                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
957                if (mitr==_objectWrapperMap.end())
958                {
959                    // not found so check if a library::class composite name.
960                    std::string token = *aitr;
961                    std::string::size_type posDoubleColon = token.rfind("::");
962                    if (posDoubleColon != std::string::npos)
963                    {
964                        // we have a composite name so now strip off the library name
965                        // and try to load it, and then retry the find to see
966                        // if we can recognize the objects.
967                        std::string libraryName = std::string(token,0,posDoubleColon);
968
969                        // first try the standard nodekit library.
970                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
971                        if (loadLibrary(nodeKitLibraryName)==LOADED)
972                        {
973                            mitr = _objectWrapperMap.find(*aitr);
974                            if (mitr==_objectWrapperMap.end())
975                            {
976                                // otherwise try the osgdb_ plugin library.
977                                std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
978                                if (loadLibrary(pluginLibraryName)==LOADED)
979                                {
980                                    mitr = _objectWrapperMap.find(*aitr);
981                                }
982                            }
983                        }
984                    }
985                }
986
987                if (mitr!=_objectWrapperMap.end())
988                {
989                    // get the function to read the data...
990                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
991                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
992                }
993
994            }
995
996            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
997        }
998        ++fr;                        // step over trailing '}'
999       
1000        return obj;
1001       
1002    }
1003    return 0L;
1004}
1005
1006//
1007// read object from input iterator.
1008//
1009osg::Object* Registry::readObject(DotOsgWrapperMap& dowMap,Input& fr)
1010{
1011    const char *str = fr[0].getStr();
1012    if (str==NULL) return NULL;
1013
1014    std::string name = str;
1015    DotOsgWrapperMap::iterator itr = dowMap.find(name);
1016    if (itr==dowMap.end())
1017    {
1018        // not found so check if a library::class composite name.
1019        std::string token = fr[0].getStr();
1020        std::string::size_type posDoubleColon = token.rfind("::");
1021        if (posDoubleColon != std::string::npos)
1022        {
1023            // we have a composite name so now strip off the library name
1024            // are try to load it, and then retry the readObject to see
1025            // if we can recognize the objects.
1026       
1027            std::string libraryName = std::string(token,0,posDoubleColon);
1028
1029            // first try the standard nodekit library.
1030            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1031            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObject(dowMap,fr);
1032           
1033            // otherwise try the osgdb_ plugin library.
1034            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1035            if (loadLibrary(pluginLibraryName)==LOADED) return readObject(dowMap,fr);
1036        }
1037    }
1038    else if (fr[1].isOpenBracket())
1039    {
1040   
1041        DotOsgWrapper* wrapper = itr->second.get();
1042        const osg::Object* proto = wrapper->getPrototype();
1043        if (proto==NULL)
1044        {
1045            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
1046            return NULL;
1047        }
1048
1049        // record the number of nested brackets move the input iterator
1050        // over the name { tokens.
1051        int entry = fr[0].getNoNestedBrackets();
1052        fr+=2;
1053
1054        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1055        osg::Object* obj = proto->cloneType();
1056
1057        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
1058        {
1059            bool iteratorAdvanced = false;
1060            if (fr[0].matchWord("UniqueID") && fr[1].isString())
1061            {
1062                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
1063                fr += 2;
1064                iteratorAdvanced = true;
1065            }
1066
1067            // read the local data by iterating through the associate
1068            // list, mapping the associate names to DotOsgWrapper's which
1069            // in turn have the appropriate functions.
1070            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1071                                                          aitr!=assoc.end();
1072                                                          ++aitr)
1073            {
1074                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1075                if (mitr==_objectWrapperMap.end())
1076                {
1077                    // not found so check if a library::class composite name.
1078                    std::string token = *aitr;
1079                    std::string::size_type posDoubleColon = token.rfind("::");
1080                    if (posDoubleColon != std::string::npos)
1081                    {
1082
1083                        // we have a composite name so now strip off the library name
1084                        // are try to load it, and then retry the find to see
1085                        // if we can recognize the objects.
1086
1087                        std::string libraryName = std::string(token,0,posDoubleColon);
1088
1089                        // first try the standard nodekit library.
1090                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1091                        if (loadLibrary(nodeKitLibraryName)==LOADED)
1092                        {
1093                            mitr = _objectWrapperMap.find(*aitr);
1094                        }
1095
1096                        if (mitr==_objectWrapperMap.end())
1097                        {
1098                            // otherwise try the osgdb_ plugin library.
1099                            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1100                            if (loadLibrary(pluginLibraryName)==LOADED)
1101                            {
1102                                mitr = _objectWrapperMap.find(*aitr);
1103                            }
1104                        }
1105
1106                    }
1107                }
1108
1109                if (mitr!=_objectWrapperMap.end())
1110                {
1111                    // get the function to read the data...
1112                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
1113                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
1114                }
1115
1116            }
1117
1118            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
1119        }
1120        ++fr;                        // step over trailing '}'
1121       
1122        return obj;
1123       
1124    }
1125
1126    return 0L;
1127}
1128
1129//
1130// read object from input iterator.
1131//
1132Object* Registry::readObject(Input& fr)
1133{
1134    if (fr[0].matchWord("Use"))
1135    {
1136        if (fr[1].isString())
1137        {
1138            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
1139            if (obj) fr+=2;
1140            return obj;
1141        }
1142        else return NULL;
1143
1144    }
1145
1146    return readObject(_objectWrapperMap,fr);
1147}
1148
1149
1150//
1151// read image from input iterator.
1152//
1153Image* Registry::readImage(Input& fr)
1154{
1155    if (fr[0].matchWord("Use"))
1156    {
1157        if (fr[1].isString())
1158        {
1159            Image* image = dynamic_cast<Image*>(fr.getObjectForUniqueID(fr[1].getStr()));
1160            if (image) fr+=2;
1161            return image;
1162        }
1163        else return NULL;
1164
1165    }
1166
1167    osg::Object* obj = readObject(_imageWrapperMap,fr);
1168    osg::Image* image = dynamic_cast<Image*>(obj);
1169    if (image) return image;
1170    else if (obj) obj->unref();
1171   
1172    return NULL;
1173}
1174
1175
1176//
1177// read drawable from input iterator.
1178//
1179Drawable* Registry::readDrawable(Input& fr)
1180{
1181    if (fr[0].matchWord("Use"))
1182    {
1183        if (fr[1].isString())
1184        {
1185            Drawable* drawable = dynamic_cast<Drawable*>(fr.getObjectForUniqueID(fr[1].getStr()));
1186            if (drawable) fr+=2;
1187            return drawable;
1188        }
1189        else return NULL;
1190
1191    }
1192
1193    osg::Object* obj = readObject(_drawableWrapperMap,fr);
1194    osg::Drawable* drawable = dynamic_cast<Drawable*>(obj);
1195    if (drawable) return drawable;
1196    else if (obj) obj->unref();
1197   
1198    return NULL;
1199}
1200
1201//
1202// read drawable from input iterator.
1203//
1204StateAttribute* Registry::readStateAttribute(Input& fr)
1205{
1206
1207    if (fr[0].matchWord("Use"))
1208    {
1209        if (fr[1].isString())
1210        {
1211            StateAttribute* attribute = dynamic_cast<StateAttribute*>(fr.getObjectForUniqueID(fr[1].getStr()));
1212            if (attribute) fr+=2;
1213            return attribute;
1214        }
1215        else return NULL;
1216
1217    }
1218
1219    return dynamic_cast<StateAttribute*>(readObject(_stateAttrWrapperMap,fr));
1220}
1221
1222//
1223// read drawable from input iterator.
1224//
1225Uniform* Registry::readUniform(Input& fr)
1226{
1227
1228    if (fr[0].matchWord("Use"))
1229    {
1230        if (fr[1].isString())
1231        {
1232            Uniform* attribute = dynamic_cast<Uniform*>(fr.getObjectForUniqueID(fr[1].getStr()));
1233            if (attribute) fr+=2;
1234            return attribute;
1235        }
1236        else return NULL;
1237
1238    }
1239
1240    return dynamic_cast<Uniform*>(readObject(_uniformWrapperMap,fr));
1241}
1242
1243//
1244// read node from input iterator.
1245//
1246Node* Registry::readNode(Input& fr)
1247{
1248    if (fr[0].matchWord("Use"))
1249    {
1250        if (fr[1].isString())
1251        {
1252            Node* node = dynamic_cast<Node*>(fr.getObjectForUniqueID(fr[1].getStr()));
1253            if (node) fr+=2;
1254            return node;
1255        }
1256        else return NULL;
1257
1258    }
1259
1260    osg::Object* obj = readObject(_nodeWrapperMap,fr);
1261    osg::Node* node = dynamic_cast<Node*>(obj);
1262    if (node) return node;
1263    else if (obj) obj->unref();
1264   
1265    return NULL;
1266}
1267
1268//
1269// read image from input iterator.
1270//
1271Shader* Registry::readShader(Input& fr)
1272{
1273    if (fr[0].matchWord("Use"))
1274    {
1275        if (fr[1].isString())
1276        {
1277            Shader* shader = dynamic_cast<Shader*>(fr.getObjectForUniqueID(fr[1].getStr()));
1278            if (shader) fr+=2;
1279            return shader;
1280        }
1281        else return NULL;
1282
1283    }
1284
1285    osg::Object* obj = readObject(_shaderWrapperMap,fr);
1286    osg::Shader* shader = dynamic_cast<Shader*>(obj);
1287    if (shader) return shader;
1288    else if (obj) obj->unref();
1289   
1290    return NULL;
1291}
1292
1293//
1294// Write object to output
1295//
1296bool Registry::writeObject(const osg::Object& obj,Output& fw)
1297{
1298
1299    if (obj.referenceCount()>1)
1300    {
1301        std::string uniqueID;
1302        if (fw.getUniqueIDForObject(&obj,uniqueID))
1303        {
1304            fw.writeUseID( uniqueID );
1305            return true;
1306        }
1307    }
1308
1309    const std::string classname( obj.className() );
1310    const std::string libraryName( obj.libraryName() );
1311    const std::string compositeName( libraryName + "::" + classname );
1312
1313    // try composite name first
1314    DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName);
1315
1316    if (itr==_classNameWrapperMap.end())
1317    {
1318        // first try the standard nodekit library.
1319        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1320        if (loadLibrary(nodeKitLibraryName)==LOADED) return writeObject(obj,fw);
1321
1322        // otherwise try the osgdb_ plugin library.
1323        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1324        if (loadLibrary(pluginLibraryName)==LOADED) return writeObject(obj,fw);
1325
1326        // otherwise try simple class name
1327        if (itr == _classNameWrapperMap.end())
1328            itr = _classNameWrapperMap.find(classname);
1329    }
1330
1331    if (itr!=_classNameWrapperMap.end())
1332    {
1333        DotOsgWrapper* wrapper = itr->second.get();
1334        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1335
1336        if (libraryName=="osg")
1337        {
1338            // member of the core osg, so no need to have composite library::class name.
1339            fw.writeBeginObject( wrapper->getName() );
1340        }
1341        else
1342        {
1343            // member of the node kit so must use composite library::class name.
1344            std::string::size_type posDoubleColon = wrapper->getName().find("::");
1345            if (posDoubleColon != std::string::npos)
1346            {
1347                fw.writeBeginObject( wrapper->getName() );
1348            }
1349            else
1350            {
1351                fw.writeBeginObject( libraryName + "::" + wrapper->getName() );
1352            }
1353        }
1354        fw.moveIn();
1355
1356
1357        // write out the unique ID if required.
1358        if (obj.referenceCount()>1)
1359        {
1360            std::string uniqueID;
1361            fw.createUniqueIDForObject(&obj,uniqueID);
1362            fw.registerUniqueIDForObject(&obj,uniqueID);
1363            fw.writeUniqueID( uniqueID );
1364        }
1365
1366        // read the local data by iterating through the associate
1367        // list, mapping the associate names to DotOsgWrapper's which
1368        // in turn have the appropriate functions.
1369        for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1370                                                      aitr!=assoc.end();
1371                                                      ++aitr)
1372        {
1373            DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1374            if (mitr==_objectWrapperMap.end())
1375            {
1376                // not found so check if a library::class composite name.
1377                std::string token = *aitr;
1378                std::string::size_type posDoubleColon = token.rfind("::");
1379                if (posDoubleColon != std::string::npos)
1380                {
1381
1382                    // we have a composite name so now strip off the library name
1383                    // are try to load it, and then retry the find to see
1384                    // if we can recognize the objects.
1385
1386                    std::string libraryName = std::string(token,0,posDoubleColon);
1387
1388                    // first try the standard nodekit library.
1389                    std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1390                    if (loadLibrary(nodeKitLibraryName)==LOADED)
1391                    {
1392                        mitr = _objectWrapperMap.find(*aitr);
1393                    }
1394
1395                    if (mitr==_objectWrapperMap.end())
1396                    {
1397                        // otherwise try the osgdb_ plugin library.
1398                        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1399                        if (loadLibrary(pluginLibraryName)==LOADED)
1400                        {
1401                            mitr = _objectWrapperMap.find(*aitr);
1402                        }
1403                    }
1404
1405                }
1406            }
1407            if (mitr!=_objectWrapperMap.end())
1408            {
1409                // get the function to read the data...
1410                DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc();
1411                if (wf) (*wf)(obj,fw);
1412            }
1413
1414        }
1415
1416        fw.moveOut();
1417        fw.writeEndObject();
1418
1419        return true;
1420    }
1421   
1422    return false;
1423}
1424
1425
1426
1427struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
1428{
1429    ReadObjectFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
1430
1431    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }   
1432    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
1433    virtual bool isValid(osg::Object* object) const { return object!=0;  }
1434};
1435
1436struct Registry::ReadImageFunctor : public Registry::ReadFunctor
1437{
1438    ReadImageFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
1439
1440    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }   
1441    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
1442    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
1443};
1444
1445struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
1446{
1447    ReadHeightFieldFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
1448
1449    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }   
1450    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
1451    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
1452};
1453
1454struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
1455{
1456    ReadNodeFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
1457
1458    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }   
1459    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
1460    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
1461
1462};
1463
1464struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
1465{
1466    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options):
1467        ReadFunctor(filename,options),
1468        _status(status),
1469        _indexBlockSizeHint(indexBlockSizeHint) {}
1470       
1471    ReaderWriter::ArchiveStatus _status;
1472    unsigned int _indexBlockSizeHint;
1473
1474    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
1475    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
1476    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
1477
1478};
1479
1480struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
1481{
1482    ReadShaderFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
1483
1484    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }   
1485    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
1486    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
1487};
1488
1489void Registry::addArchiveExtension(const std::string ext)
1490{
1491    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1492        aitr!=_archiveExtList.end();
1493        ++aitr)
1494    {
1495        if ( (*aitr) == ext)   // extension already in archive extension list
1496            return;
1497    }
1498    _archiveExtList.push_back(ext);
1499}
1500
1501std::string Registry::findDataFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
1502{
1503    if (filename.empty()) return filename;
1504
1505    // if data file contains a server address then we can't find it in local directories so return empty string.
1506    if (containsServerAddress(filename)) return std::string();
1507
1508    if(fileExists(filename))
1509    {
1510        osg::notify(osg::DEBUG_INFO) << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1511        return filename;
1512    }
1513
1514    std::string fileFound;
1515
1516    if (options && !options->getDatabasePathList().empty())
1517    {
1518        fileFound = findFileInPath(filename, options->getDatabasePathList(), caseSensitivity);
1519        if (!fileFound.empty()) return fileFound;
1520    }
1521
1522    const FilePathList& filepath = Registry::instance()->getDataFilePathList();
1523    if (!filepath.empty())
1524    {
1525        fileFound = findFileInPath(filename, filepath,caseSensitivity);
1526        if (!fileFound.empty()) return fileFound;
1527    }
1528
1529
1530    // if a directory is included in the filename, get just the (simple) filename itself and try that
1531    std::string simpleFileName = getSimpleFileName(filename);
1532    if (simpleFileName!=filename)
1533    {
1534
1535        if(fileExists(simpleFileName))
1536        {
1537            osg::notify(osg::DEBUG_INFO) << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1538            return simpleFileName;
1539        }
1540
1541        if (options && !options->getDatabasePathList().empty())
1542        {
1543            fileFound = findFileInPath(simpleFileName, options->getDatabasePathList(), caseSensitivity);
1544            if (!fileFound.empty()) return fileFound;
1545        }
1546
1547        if (!filepath.empty())
1548        {
1549            fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
1550            if (!fileFound.empty()) return fileFound;
1551        }
1552
1553    }
1554
1555    // return empty string.
1556    return std::string();
1557}
1558
1559std::string Registry::findLibraryFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
1560{
1561    if (filename.empty())
1562        return filename;
1563
1564    const FilePathList& filepath = Registry::instance()->getLibraryFilePathList();
1565
1566    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
1567    if (!fileFound.empty())
1568        return fileFound;
1569
1570    if(fileExists(filename))
1571    {
1572        osg::notify(osg::DEBUG_INFO) << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1573        return filename;
1574    }
1575
1576    // if a directory is included in the filename, get just the (simple) filename itself and try that
1577    std::string simpleFileName = getSimpleFileName(filename);
1578    if (simpleFileName!=filename)
1579    {
1580        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
1581        if (!fileFound.empty()) return fileFound;
1582    }
1583
1584    // failed return empty string.
1585    return std::string();
1586}
1587
1588
1589
1590ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1591{
1592    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1593        aitr!=_archiveExtList.end();
1594        ++aitr)
1595    {
1596        std::string archiveExtension = "." + (*aitr);
1597
1598        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1599        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1600        if (positionArchive!=std::string::npos)
1601        {
1602            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1603            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1604            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1605            osg::notify(osg::INFO)<<"Contains archive : "<<readFunctor._filename<<std::endl;
1606            osg::notify(osg::INFO)<<"         archive : "<<archiveName<<std::endl;
1607            osg::notify(osg::INFO)<<"         filename : "<<fileName<<std::endl;
1608       
1609            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1610       
1611            if (!result.validArchive()) return result;
1612
1613            osgDB::Archive* archive = result.getArchive();
1614       
1615            osg::ref_ptr<Options> options = new Options;
1616            options->setDatabasePath(archiveName);
1617
1618            return archive->readObject(fileName,options.get());
1619        }
1620    }
1621 
1622    // record the errors reported by readerwriters.
1623    typedef std::vector<ReaderWriter::ReadResult> Results;
1624    Results results;
1625
1626    // first attempt to load the file from existing ReaderWriter's
1627    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1628    for(;itr.valid();++itr)
1629    {
1630        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1631        if (readFunctor.isValid(rr)) return rr;
1632        else results.push_back(rr);
1633    }
1634
1635    if (!results.empty())
1636    {
1637        unsigned int num_FILE_NOT_HANDLED = 0;
1638        unsigned int num_FILE_NOT_FOUND = 0;
1639        unsigned int num_ERROR_IN_READING_FILE = 0;
1640
1641        Results::iterator ritr;
1642        for(ritr=results.begin();
1643            ritr!=results.end();
1644            ++ritr)
1645        {
1646            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1647            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1648            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1649        }
1650       
1651        if (num_FILE_NOT_HANDLED!=results.size())
1652        {
1653            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1654            {
1655                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1656                {
1657                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1658                    return *ritr;
1659                }
1660            }
1661
1662            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1663            if (!osgDB::containsServerAddress(readFunctor._filename))
1664            {
1665                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1666                {
1667                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1668                    {
1669                        //osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1670                        return *ritr;
1671                    }
1672                }
1673            }
1674        }
1675    }
1676
1677    results.clear();
1678
1679    // now look for a plug-in to load the file.
1680    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1681    if (loadLibrary(libraryName)!=NOT_LOADED)
1682    {
1683        for(;itr.valid();++itr)
1684        {
1685            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1686            if (readFunctor.isValid(rr)) return rr;
1687            else results.push_back(rr);
1688        }
1689    }
1690
1691    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1692    //to download the file and use the stream reading functionality of the plugins to load the file
1693    if (containsServerAddress(readFunctor._filename))
1694    {
1695        ReaderWriter* rw = getReaderWriterForExtension("curl");
1696        if (rw)
1697        {
1698            return readFunctor.doRead(*rw);
1699        }
1700        else
1701        {
1702            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1703        }
1704    }
1705   
1706    if (!results.empty())
1707    {
1708        unsigned int num_FILE_NOT_HANDLED = 0;
1709        unsigned int num_FILE_NOT_FOUND = 0;
1710        unsigned int num_ERROR_IN_READING_FILE = 0;
1711
1712        Results::iterator ritr;
1713        for(ritr=results.begin();
1714            ritr!=results.end();
1715            ++ritr)
1716        {
1717            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1718            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1719            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1720        }
1721       
1722        if (num_FILE_NOT_HANDLED!=results.size())
1723        {
1724            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1725            {
1726                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1727                {
1728                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1729                    return *ritr;
1730                }
1731            }
1732
1733            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1734            {
1735                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1736                {
1737                    // osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1738                    return *ritr;
1739                }
1740            }
1741        }
1742    }
1743    else
1744    {
1745        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1746    }
1747
1748    return results.front();
1749}
1750
1751ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint)
1752{
1753    std::string file(readFunctor._filename);
1754
1755    bool useObjectCache=false;
1756    //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
1757    if (cacheHint!=Options::CACHE_ARCHIVES)
1758    {
1759        const Options* options=readFunctor._options;
1760        useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
1761    }
1762    if (useObjectCache)
1763    {
1764        // search for entry in the object cache.
1765        {
1766            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1767            ObjectCache::iterator oitr=_objectCache.find(file);
1768            if (oitr!=_objectCache.end())
1769            {
1770                notify(INFO)<<"returning cached instanced of "<<file<<std::endl;
1771                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1772                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1773            }
1774        }
1775       
1776        ReaderWriter::ReadResult rr = read(readFunctor);
1777        if (rr.validObject())
1778        {
1779            // update cache with new entry.
1780            notify(INFO)<<"Adding to object cache "<<file<<std::endl;
1781            addEntryToObjectCache(file,rr.getObject());
1782        }
1783        else
1784        {
1785            notify(INFO)<<"No valid object found for "<<file<<std::endl;
1786        }
1787
1788        return rr;
1789
1790    }
1791    else
1792    {
1793        ReaderWriter::ReadResult rr = read(readFunctor);
1794        return rr;
1795    }
1796}
1797
1798
1799ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options)
1800{
1801    osgDB::Archive* archive = getFromArchiveCache(fileName);
1802    if (archive) return archive;
1803
1804    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),Options::CACHE_ARCHIVES);
1805
1806    // default to using caching archive if no options structure provided, but if options are provided use archives
1807    // only if supplied.
1808    if (result.validArchive() &&
1809        (!options || (options->getObjectCacheHint() & Options::CACHE_ARCHIVES)) )
1810    {
1811        addToArchiveCache(fileName,result.getArchive());
1812    }
1813    return result;
1814}
1815
1816
1817ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const Options* options)
1818{
1819    return readImplementation(ReadObjectFunctor(fileName, options),Options::CACHE_OBJECTS);
1820}
1821
1822ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const Options* options)
1823{
1824    // record the errors reported by readerwriters.
1825    typedef std::vector<ReaderWriter::WriteResult> Results;
1826    Results results;
1827
1828    // first attempt to load the file from existing ReaderWriter's
1829    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1830    for(;itr.valid();++itr)
1831    {
1832        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1833        if (rr.success()) return rr;
1834        else results.push_back(rr);
1835    }
1836
1837    // now look for a plug-in to save the file.
1838    std::string libraryName = createLibraryNameForFile(fileName);
1839    if (loadLibrary(libraryName)==LOADED)
1840    {
1841        for(;itr.valid();++itr)
1842        {
1843            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1844            if (rr.success()) return rr;
1845            else results.push_back(rr);
1846        }
1847    }
1848
1849    if (results.empty())
1850    {
1851        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1852    }
1853
1854    if (results.front().message().empty())
1855    {
1856        switch(results.front().status())
1857        {
1858            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1859            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1860            default: break;
1861        }
1862    }
1863
1864    return results.front();
1865}
1866
1867
1868
1869ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const Options* options)
1870{
1871    return readImplementation(ReadImageFunctor(fileName, options),Options::CACHE_IMAGES);
1872}
1873
1874ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const Options* options)
1875{
1876    // record the errors reported by readerwriters.
1877    typedef std::vector<ReaderWriter::WriteResult> Results;
1878    Results results;
1879
1880    // first attempt to load the file from existing ReaderWriter's
1881    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1882    for(;itr.valid();++itr)
1883    {
1884        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1885        if (rr.success()) return rr;
1886        else results.push_back(rr);
1887    }
1888
1889    results.clear();
1890
1891    // now look for a plug-in to save the file.
1892    std::string libraryName = createLibraryNameForFile(fileName);
1893    if (loadLibrary(libraryName)==LOADED)
1894    {
1895        for(;itr.valid();++itr)
1896        {
1897            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1898            if (rr.success()) return rr;
1899            else results.push_back(rr);
1900        }
1901    }
1902
1903    if (results.empty())
1904    {
1905        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1906    }
1907   
1908    if (results.front().message().empty())
1909    {
1910        switch(results.front().status())
1911        {
1912            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1913            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1914            default: break;
1915        }
1916    }
1917
1918    return results.front();
1919}
1920
1921
1922ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const Options* options)
1923{
1924    return readImplementation(ReadHeightFieldFunctor(fileName, options),Options::CACHE_HEIGHTFIELDS);
1925}
1926
1927ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const Options* options)
1928{
1929    // record the errors reported by readerwriters.
1930    typedef std::vector<ReaderWriter::WriteResult> Results;
1931    Results results;
1932
1933    // first attempt to load the file from existing ReaderWriter's
1934    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1935    for(;itr.valid();++itr)
1936    {
1937        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1938        if (rr.success()) return rr;
1939        else results.push_back(rr);
1940    }
1941
1942    results.clear();
1943
1944    // now look for a plug-in to save the file.
1945    std::string libraryName = createLibraryNameForFile(fileName);
1946    if (loadLibrary(libraryName)==LOADED)
1947    {
1948        for(;itr.valid();++itr)
1949        {
1950            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1951            if (rr.success()) return rr;
1952            else results.push_back(rr);
1953        }
1954    }
1955
1956    if (results.empty())
1957    {
1958        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1959    }
1960
1961    if (results.front().message().empty())
1962    {
1963        switch(results.front().status())
1964        {
1965            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1966            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1967            default: break;
1968        }
1969    }
1970   
1971    return results.front();
1972}
1973
1974
1975ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options)
1976{
1977#if 0
1978
1979    osg::Timer_t startTick = osg::Timer::instance()->tick();
1980    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1981    osg::Timer_t endTick = osg::Timer::instance()->tick();
1982    osg::notify(osg::NOTICE)<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1983    return result;
1984
1985#else
1986
1987    return readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1988                             
1989#endif
1990}
1991
1992ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const Options* options)
1993{
1994    // record the errors reported by readerwriters.
1995    typedef std::vector<ReaderWriter::WriteResult> Results;
1996    Results results;
1997
1998    // first attempt to write the file from existing ReaderWriter's
1999    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
2000    for(;itr.valid();++itr)
2001    {
2002        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
2003        if (rr.success()) return rr;
2004        else results.push_back(rr);
2005    }
2006
2007    results.clear();
2008
2009    // now look for a plug-in to save the file.
2010    std::string libraryName = createLibraryNameForFile(fileName);
2011
2012
2013    if (loadLibrary(libraryName)==LOADED)
2014    {
2015        for(;itr.valid();++itr)
2016        {
2017            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
2018   
2019            if (rr.success()) return rr;
2020            else results.push_back(rr);
2021        }
2022    }
2023
2024    if (results.empty())
2025    {
2026        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
2027    }
2028
2029    if (results.front().message().empty())
2030    {
2031        switch(results.front().status())
2032        {
2033            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
2034            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
2035            default: break;
2036        }
2037    }
2038
2039    return results.front();
2040}
2041
2042ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const Options* options)
2043{
2044    return readImplementation(ReadShaderFunctor(fileName, options),Options::CACHE_SHADERS);
2045}
2046
2047ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const Options* options)
2048{
2049    // record the errors reported by readerwriters.
2050    typedef std::vector<ReaderWriter::WriteResult> Results;
2051    Results results;
2052
2053    // first attempt to load the file from existing ReaderWriter's
2054    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
2055    for(;itr.valid();++itr)
2056    {
2057        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
2058        if (rr.success()) return rr;
2059        else results.push_back(rr);
2060    }
2061
2062    results.clear();
2063
2064    // now look for a plug-in to save the file.
2065    std::string libraryName = createLibraryNameForFile(fileName);
2066    if (loadLibrary(libraryName)==LOADED)
2067    {
2068        for(;itr.valid();++itr)
2069        {
2070            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
2071            if (rr.success()) return rr;
2072            else results.push_back(rr);
2073        }
2074    }
2075
2076    if (results.empty())
2077    {
2078        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
2079    }
2080   
2081    if (results.front().message().empty())
2082    {
2083        switch(results.front().status())
2084        {
2085            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
2086            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
2087            default: break;
2088        }
2089    }
2090
2091    return results.front();
2092}
2093
2094void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
2095{
2096    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2097    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
2098}
2099osg::Object* Registry::getFromObjectCache(const std::string& fileName)
2100{
2101    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2102    ObjectCache::iterator itr = _objectCache.find(fileName);
2103    if (itr!=_objectCache.end()) return itr->second.first.get();
2104    else return 0;
2105}
2106
2107void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(double currentTime)
2108{
2109    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2110
2111    // look for objects with external references and update their time stamp.
2112    for(ObjectCache::iterator itr=_objectCache.begin();
2113        itr!=_objectCache.end();
2114        ++itr)
2115    {
2116        // if ref count is greater the 1 the object has an external reference.
2117        if (itr->second.first->referenceCount()>1)
2118        {
2119            // so update it time stamp.
2120            itr->second.second = currentTime;
2121        }
2122    }
2123}
2124
2125void Registry::removeExpiredObjectsInCache(double expiryTime)
2126{
2127    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2128
2129    typedef std::vector<std::string> ObjectsToRemove;
2130    ObjectsToRemove objectsToRemove;
2131
2132    // first collect all the expired entries in the ObjectToRemove list.
2133    for(ObjectCache::iterator oitr=_objectCache.begin();
2134        oitr!=_objectCache.end();
2135        ++oitr)
2136    {
2137        if (oitr->second.second<=expiryTime)
2138        {
2139            // record the filename of the entry to use as key for deleting
2140            // afterwards/
2141            objectsToRemove.push_back(oitr->first);
2142        }
2143    }
2144   
2145    // remove the entries from the _objectCaache.
2146    for(ObjectsToRemove::iterator ritr=objectsToRemove.begin();
2147        ritr!=objectsToRemove.end();
2148        ++ritr)
2149    {
2150        // std::cout<<"Removing from Registry object cache '"<<*ritr<<"'"<<std::endl;
2151        _objectCache.erase(*ritr);
2152    }
2153       
2154}
2155
2156void Registry::clearObjectCache()
2157{
2158    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2159    _objectCache.clear();
2160}
2161
2162void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
2163{
2164    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2165    _archiveCache[fileName] = archive;
2166}
2167
2168/** Remove archive from cache.*/
2169void Registry::removeFromArchiveCache(const std::string& fileName)
2170{
2171    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2172    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2173    if (itr!=_archiveCache.end())
2174    {
2175        _archiveCache.erase(itr);
2176    }
2177}
2178
2179osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
2180{
2181    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2182    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2183    if (itr!=_archiveCache.end()) return itr->second.get();
2184    else return 0;
2185}
2186
2187void Registry::clearArchiveCache()
2188{
2189    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2190    _archiveCache.clear();
2191}
2192
2193void Registry::releaseGLObjects(osg::State* state)
2194{
2195    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2196
2197    for(ObjectCache::iterator itr = _objectCache.begin();
2198        itr != _objectCache.end();
2199        ++itr)
2200    {
2201        osg::Object* object = itr->second.first.get();
2202        object->releaseGLObjects(state);
2203    }
2204}
2205
2206SharedStateManager* Registry::getOrCreateSharedStateManager()
2207{
2208    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
2209   
2210    return _sharedStateManager.get();
2211}
2212
2213
2214void Registry::registerProtocol(const std::string& protocol)
2215
2216    _registeredProtocols.insert( convertToLowerCase(protocol) );
2217}
2218       
2219bool Registry::isProtocolRegistered(const std::string& protocol)
2220{
2221    return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end());
2222}
Note: See TracBrowser for help on using the browser.