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

Revision 10150, 69.5 kB (checked in by robert, 6 years ago)

From Stephan Huber, "while debugging a problem in finding plugins on OS X I discovered, that
the conditional directives for setting the prepend-string in
createLibraryNameForExtension were not in effect, because of the mixture
of different #ifdef styles.

I removed the conditional part for APPLE completely to be more
standard-conform with other platforms (plugins should be located in
osgPlugins-X.X.X/). Because of the wrong syntax of the conditional
compile the old code was not used anyway -- so no functional change.
"

  • 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 = ReaderWriter::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 = ReaderWriter::Options::DO_NOT_BUILD_KDTREES;
187        else _buildKdTreesHint = ReaderWriter::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    // add built-in mime-type extension mappings
339    for( int i=0; ; i+=2 )
340    {
341        std::string mimeType = builtinMimeTypeExtMappings[i];
342        if ( mimeType.length() == 0 )
343            break;
344        addMimeTypeExtensionMapping( mimeType, builtinMimeTypeExtMappings[i+1] );
345    }
346   
347    // register http-protocol, so the curl can handle it, if necessary
348    registerProtocol("http");
349}
350
351
352Registry::~Registry()
353{
354    destruct();
355}
356
357void Registry::destruct()
358{
359    // osg::notify(osg::NOTICE)<<"Registry::destruct()"<<std::endl;
360
361    // clean up the SharedStateManager
362    _sharedStateManager = 0;
363   
364
365    // clean up the FileCache
366    _fileCache = 0;
367   
368
369    // object cache clear needed here to prevent crash in unref() of
370    // the objects it contains when running the TXP plugin.
371    // Not sure why, but perhaps there is is something in a TXP plugin
372    // which deletes the data before its ref count hits zero, perhaps
373    // even some issue with objects be allocated by a plugin that is
374    // maintained after that plugin is deleted...  Robert Osfield, Jan 2004.
375    clearObjectCache();
376    clearArchiveCache();
377   
378
379    // unload all the plugin before we finally destruct.
380    closeAllLibraries();
381}
382
383#include <iostream>
384
385void Registry::initDataFilePathList()
386{
387    FilePathList filepath;
388    //
389    // set up data file paths
390    //
391    char *ptr;
392 
393    if( (ptr = getenv( "OSG_FILE_PATH" )) )
394    {
395        //notify(DEBUG_INFO) << "OSG_FILE_PATH("<<ptr<<")"<<std::endl;
396        convertStringPathIntoFilePathList(ptr, filepath);
397    }
398    else if( (ptr = getenv( "OSGFILEPATH" )) )
399    {
400        //notify(DEBUG_INFO) << "OSGFILEPATH("<<ptr<<")"<<std::endl;
401        convertStringPathIntoFilePathList(ptr, filepath);
402    }
403
404    osgDB::appendPlatformSpecificResourceFilePaths(filepath);
405    setDataFilePathList(filepath);
406   
407}
408
409void Registry::setDataFilePathList(const std::string& paths)
410{
411    _dataFilePath.clear();
412    convertStringPathIntoFilePathList(paths,_dataFilePath);
413}
414
415void Registry::setLibraryFilePathList(const std::string& paths) { _libraryFilePath.clear(); convertStringPathIntoFilePathList(paths,_libraryFilePath); }
416
417
418
419void Registry::initLibraryFilePathList()
420{
421    //
422    // set up library paths
423    //
424    char* ptr;
425    if( (ptr = getenv( "OSG_LIBRARY_PATH")) )
426    {
427        //notify(DEBUG_INFO) << "OSG_LIBRARY_PATH("<<ptr<<")"<<std::endl;
428        setLibraryFilePathList(ptr);
429    }
430    else if( (ptr = getenv( "OSG_LD_LIBRARY_PATH")) )
431    {
432        //notify(DEBUG_INFO) << "OSG_LD_LIBRARY_PATH("<<ptr<<")"<<std::endl;
433        setLibraryFilePathList(ptr);
434    }
435   
436    appendPlatformSpecificLibraryFilePaths(_libraryFilePath);
437
438}
439
440
441void Registry::readCommandLine(osg::ArgumentParser& arguments)
442{
443    // report the usage options.
444    if (arguments.getApplicationUsage())
445    {
446        arguments.getApplicationUsage()->addCommandLineOption("-l <library>","Load the plugin");
447        arguments.getApplicationUsage()->addCommandLineOption("-e <extension>","Load the plugin associated with handling files with specified extension");
448        arguments.getApplicationUsage()->addCommandLineOption("-O <option_string>","Provide an option string to reader/writers used to load databases");
449    }
450
451    std::string value;
452    while(arguments.read("-l",value))
453    {
454        loadLibrary(value);
455    }
456       
457    while(arguments.read("-e",value))
458    {
459        std::string libName = createLibraryNameForExtension(value);
460        loadLibrary(libName);
461    }
462
463    while(arguments.read("-O",value))
464    {
465        setOptions(new ReaderWriter::Options(value));
466    }
467}
468
469void Registry::addDotOsgWrapper(DotOsgWrapper* wrapper)
470{
471    if (wrapper==0L) return;
472
473    //notify(INFO) << "osg::Registry::addDotOsgWrapper("<<wrapper->getName()<<")"<< std::endl;
474    const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
475   
476    for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin();
477                                                  itr!=assoc.end();
478                                                  ++itr)
479    {
480        //notify(INFO) << "    ("<<*itr<<")"<< std::endl;
481    }
482
483    const std::string& name = wrapper->getName();
484    const osg::Object* proto = wrapper->getPrototype();
485
486    _objectWrapperMap[name] = wrapper;
487    if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper;
488   
489    if (proto)
490    {
491        std::string libraryName = proto->libraryName();
492        std::string compositeName = libraryName + "::" + name;
493
494        _objectWrapperMap[compositeName] = wrapper;
495        if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper;
496
497        if (dynamic_cast<const Image*>(proto))
498        {
499            _imageWrapperMap[name] = wrapper;
500            _imageWrapperMap[compositeName] = wrapper;
501        }
502        if (dynamic_cast<const Drawable*>(proto))
503        {
504              _drawableWrapperMap[name] = wrapper;
505              _drawableWrapperMap[compositeName] = wrapper;
506        }
507        if (dynamic_cast<const StateAttribute*>(proto))
508        {
509            _stateAttrWrapperMap[name] = wrapper;
510            _stateAttrWrapperMap[compositeName] = wrapper;
511        }
512        if (dynamic_cast<const Uniform*>(proto))
513        {
514            _uniformWrapperMap[name] = wrapper;
515            _uniformWrapperMap[compositeName] = wrapper;
516        }
517        if (dynamic_cast<const Node*>(proto))
518        {
519            _nodeWrapperMap[name] = wrapper;
520            _nodeWrapperMap[compositeName] = wrapper;
521        }
522        if (dynamic_cast<const Shader*>(proto))
523        {
524            _shaderWrapperMap[name] = wrapper;
525            _shaderWrapperMap[compositeName] = wrapper;
526        }
527
528
529    }
530}
531
532// need to change to delete all instances of wrapper, since we
533// now can have a wrapper entered twice with the addition of the
534// library::class composite name.
535void Registry::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper)
536{
537    typedef std::vector<DotOsgWrapperMap::iterator> EraseList;
538    EraseList eraseList;
539    for(DotOsgWrapperMap::iterator witr=wrappermap.begin();
540        witr!=wrappermap.end();
541        ++witr)
542    {
543        if (witr->second==wrapper) eraseList.push_back(witr);
544    }
545    for(EraseList::iterator eitr=eraseList.begin();
546        eitr!=eraseList.end();
547        ++eitr)
548    {
549        wrappermap.erase(*eitr);
550    }
551}
552
553void Registry::removeDotOsgWrapper(DotOsgWrapper* wrapper)
554{
555    if (wrapper==0L) return;
556
557    eraseWrapper(_objectWrapperMap,wrapper);
558    eraseWrapper(_classNameWrapperMap,wrapper);
559    eraseWrapper(_imageWrapperMap,wrapper);
560    eraseWrapper(_drawableWrapperMap,wrapper);
561    eraseWrapper(_uniformWrapperMap,wrapper);
562    eraseWrapper(_stateAttrWrapperMap,wrapper);
563    eraseWrapper(_nodeWrapperMap,wrapper);
564    eraseWrapper(_shaderWrapperMap,wrapper);
565}
566
567void Registry::addReaderWriter(ReaderWriter* rw)
568{
569    if (rw==0L) return;
570
571    // notify(INFO) << "osg::Registry::addReaderWriter("<<rw->className()<<")"<< std::endl;
572
573    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
574
575    _rwList.push_back(rw);
576
577}
578
579
580void Registry::removeReaderWriter(ReaderWriter* rw)
581{
582    if (rw==0L) return;
583
584//    notify(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl;
585
586    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
587
588    ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw);
589    if (rwitr!=_rwList.end())
590    {
591        _rwList.erase(rwitr);
592    }
593
594}
595
596
597void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
598{
599    _extAliasMap[mapExt] = toExt;
600}
601
602void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt)
603{
604    _mimeTypeExtMap[fromMimeType] = toExt;
605}
606
607bool Registry::readPluginAliasConfigurationFile( const std::string& file )
608{
609    std::string fileName = osgDB::findDataFile( file );
610    if (fileName.empty())
611    {
612        osg::notify( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl;
613        return false;
614    }
615
616    osgDB::ifstream ifs;
617    ifs.open( fileName.c_str() );
618    if (!ifs.good())
619    {
620        osg::notify( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl;
621        return false;
622    }
623
624    int lineNum( 0 );
625    while (ifs.good())
626    {
627        std::string raw;
628        ++lineNum;
629        std::getline( ifs, raw );
630        std::string ln = trim( raw );
631        if (ln.empty()) continue;
632        if (ln[0] == '#') continue;
633
634        std::string::size_type spIdx = ln.find_first_of( " \t" );
635        if (spIdx == ln.npos)
636        {
637            // mapExt and toExt must be on the same line, separated by a space.
638            osg::notify( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl;
639            continue;
640        }
641
642        const std::string mapExt = trim( ln.substr( 0, spIdx ) );
643        const std::string toExt = trim( ln.substr( spIdx+1 ) );
644        addFileExtensionAlias( mapExt, toExt );
645    }
646    return true;
647}
648
649std::string Registry::trim( const std::string& str )
650{
651    if (!str.size()) return str;
652    std::string::size_type first = str.find_first_not_of( " \t" );
653    std::string::size_type last = str.find_last_not_of( "  \t\r\n" );
654    if ((first==str.npos) || (last==str.npos)) return std::string( "" );
655    return str.substr( first, last-first+1 );
656}
657
658
659std::string Registry::createLibraryNameForFile(const std::string& fileName)
660{
661    return createLibraryNameForExtension(getFileExtension(fileName));
662}
663
664std::string Registry::createLibraryNameForExtension(const std::string& ext)
665{
666    std::string lowercase_ext;
667    for(std::string::const_iterator sitr=ext.begin();
668        sitr!=ext.end();
669        ++sitr)
670    {
671        lowercase_ext.push_back(tolower(*sitr));
672    }
673
674    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
675    if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);
676
677#if defined(OSG_JAVA_BUILD)
678    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
679#else
680    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
681#endif
682
683#if defined(__CYGWIN__)
684    #ifdef _DEBUG
685        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_DEBUG_POSTFIX_WITH_QUOTES+".dll";
686    #else
687        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+".dll";
688    #endif
689#elif defined(__MINGW32__)
690    return prepend+"mingw_"+"osgdb_"+lowercase_ext+".dll";
691#elif defined(WIN32)
692    #ifdef _DEBUG
693        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
694    #else
695        return prepend+"osgdb_"+lowercase_ext+".dll";
696    #endif
697#elif macintosh
698    #ifdef _DEBUG
699        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES;
700    #else
701        return prepend+"osgdb_"+lowercase_ext;
702    #endif
703#elif defined(__hpux__)
704    // why don't we use PLUGIN_EXT from the makefiles here?
705    return prepend+"osgdb_"+lowercase_ext+".sl";
706#else
707    #ifdef _DEBUG
708         return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES + ".so";
709    #else
710         return prepend+"osgdb_"+lowercase_ext+".so";
711    #endif
712#endif
713
714}
715
716std::string Registry::createLibraryNameForNodeKit(const std::string& name)
717{
718#if defined(__CYGWIN__)
719    return "cyg"+name+".dll";
720#elif defined(__MINGW32__)
721    return "lib"+name+".dll";
722#elif defined(WIN32)
723    #ifdef _DEBUG
724        return name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
725    #else
726        return name+".dll";
727    #endif
728#elif macintosh
729    #ifdef _DEBUG
730        return name+OSGDEBUG_POSTFIX_WITH_QUOTES;
731    #else
732        return name;
733    #endif
734#elif defined(__hpux__)
735    // why don't we use PLUGIN_EXT from the makefiles here?
736    return "lib"+name+".sl";
737#else
738    #ifdef _DEBUG
739        return "lib"+name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".so";
740    #else
741        return "lib"+name+".so";
742    #endif
743#endif
744}
745
746Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
747{
748    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
749
750    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
751    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
752
753    _openingLibrary=true;
754
755    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
756    _openingLibrary=false;
757
758    if (dl)
759    {
760        _dlList.push_back(dl);
761        return LOADED;
762    }
763    return NOT_LOADED;
764}
765
766
767bool Registry::closeLibrary(const std::string& fileName)
768{
769    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
770    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
771    if (ditr!=_dlList.end())
772    {
773        _dlList.erase(ditr);
774        return true;
775    }
776    return false;
777}
778
779void Registry::closeAllLibraries()
780{
781    // osg::notify(osg::NOTICE)<<"Registry::closeAllLibraries()"<<std::endl;
782    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
783    _dlList.clear();
784}
785
786Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
787{
788    DynamicLibraryList::iterator ditr = _dlList.begin();
789    for(;ditr!=_dlList.end();++ditr)
790    {
791        if ((*ditr)->getName()==fileName) return ditr;
792    }
793    return _dlList.end();
794}
795
796DynamicLibrary* Registry::getLibrary(const std::string& fileName)
797{
798    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
799    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
800    if (ditr!=_dlList.end()) return ditr->get();
801    else return NULL;
802}
803
804ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
805{
806    // record the existing reader writer.
807    std::set<ReaderWriter*> rwOriginal;
808
809    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
810
811    // first attemt one of the installed loaders
812    for(ReaderWriterList::iterator itr=_rwList.begin();
813        itr!=_rwList.end();
814        ++itr)
815    {
816        rwOriginal.insert(itr->get());
817        if((*itr)->acceptsExtension(ext)) return (*itr).get();
818    }
819   
820    // now look for a plug-in to load the file.
821    std::string libraryName = createLibraryNameForExtension(ext);
822    notify(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
823    if (loadLibrary(libraryName)==LOADED)
824    {
825        for(ReaderWriterList::iterator itr=_rwList.begin();
826            itr!=_rwList.end();
827            ++itr)
828        {
829            if (rwOriginal.find(itr->get())==rwOriginal.end())
830            {
831                if((*itr)->acceptsExtension(ext)) return (*itr).get();
832            }
833        }
834    }
835
836    return NULL;
837
838}
839
840ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType)
841{
842    MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType );
843    return i != _mimeTypeExtMap.end()?
844        getReaderWriterForExtension( i->second ) :
845        NULL;
846}
847
848struct concrete_wrapper: basic_type_wrapper
849{
850    virtual ~concrete_wrapper() {}
851    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
852    bool matches(const osg::Object *proto) const
853    {
854        return myobj_->isSameKindAs(proto);
855    }
856    const osg::Object *myobj_;
857};
858
859osg::Object* Registry::readObjectOfType(const osg::Object& compObj,Input& fr)
860{
861    return readObjectOfType(concrete_wrapper(&compObj), fr);
862}
863
864osg::Object* Registry::readObjectOfType(const basic_type_wrapper &btw,Input& fr)
865{
866    const char *str = fr[0].getStr();
867    if (str==NULL) return NULL;
868
869    if (fr[0].matchWord("Use"))
870    {
871        if (fr[1].isString())
872        {
873            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
874            if (obj && btw.matches(obj))
875            {
876                fr+=2;
877                return obj;
878            }
879        }
880        else return NULL;
881
882    }
883
884    std::string name = str;
885    DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name);
886    if (itr==_objectWrapperMap.end())
887    {
888        // not found so check if a library::class composite name.
889        std::string token = fr[0].getStr();
890        std::string::size_type posDoubleColon = token.rfind("::");
891        if (posDoubleColon != std::string::npos)
892        {
893            // we have a composite name so now strip off the library name
894            // are try to load it, and then retry the readObject to see
895            // if we can recognize the objects.
896            std::string libraryName = std::string(token,0,posDoubleColon);
897
898            // first try the standard nodekit library.
899            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
900            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObjectOfType(btw,fr);
901           
902            // otherwise try the osgdb_ plugin library.
903            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
904            if (loadLibrary(pluginLibraryName)==LOADED) return readObjectOfType(btw,fr);
905        }
906    }
907    else if (fr[1].isOpenBracket())
908    {
909        DotOsgWrapper* wrapper = itr->second.get();
910        const osg::Object* proto = wrapper->getPrototype();
911        if (proto==NULL)
912        {
913            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
914            return NULL;
915        }
916       
917        if (!btw.matches(proto))
918        {
919            return NULL;
920        }
921
922        // record the number of nested brackets move the input iterator
923        // over the name { tokens.
924        int entry = fr[0].getNoNestedBrackets();
925        fr+=2;
926
927        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
928        osg::Object* obj = proto->cloneType();
929
930        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
931        {
932            bool iteratorAdvanced = false;
933            if (fr[0].matchWord("UniqueID") && fr[1].isString())
934            {
935                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
936                fr += 2;
937                iteratorAdvanced = true;
938            }
939
940            // read the local data by iterating through the associate
941            // list, mapping the associate names to DotOsgWrapper's which
942            // in turn have the appropriate functions.
943            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
944                                                          aitr!=assoc.end();
945                                                          ++aitr)
946            {
947                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
948                if (mitr==_objectWrapperMap.end())
949                {
950                    // not found so check if a library::class composite name.
951                    std::string token = *aitr;
952                    std::string::size_type posDoubleColon = token.rfind("::");
953                    if (posDoubleColon != std::string::npos)
954                    {
955                        // we have a composite name so now strip off the library name
956                        // and try to load it, and then retry the find to see
957                        // if we can recognize the objects.
958                        std::string libraryName = std::string(token,0,posDoubleColon);
959
960                        // first try the standard nodekit library.
961                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
962                        if (loadLibrary(nodeKitLibraryName)==LOADED)
963                        {
964                            mitr = _objectWrapperMap.find(*aitr);
965                            if (mitr==_objectWrapperMap.end())
966                            {
967                                // otherwise try the osgdb_ plugin library.
968                                std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
969                                if (loadLibrary(pluginLibraryName)==LOADED)
970                                {
971                                    mitr = _objectWrapperMap.find(*aitr);
972                                }
973                            }
974                        }
975                    }
976                }
977
978                if (mitr!=_objectWrapperMap.end())
979                {
980                    // get the function to read the data...
981                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
982                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
983                }
984
985            }
986
987            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
988        }
989        ++fr;                        // step over trailing '}'
990       
991        return obj;
992       
993    }
994    return 0L;
995}
996
997//
998// read object from input iterator.
999//
1000osg::Object* Registry::readObject(DotOsgWrapperMap& dowMap,Input& fr)
1001{
1002    const char *str = fr[0].getStr();
1003    if (str==NULL) return NULL;
1004
1005    std::string name = str;
1006    DotOsgWrapperMap::iterator itr = dowMap.find(name);
1007    if (itr==dowMap.end())
1008    {
1009        // not found so check if a library::class composite name.
1010        std::string token = fr[0].getStr();
1011        std::string::size_type posDoubleColon = token.rfind("::");
1012        if (posDoubleColon != std::string::npos)
1013        {
1014            // we have a composite name so now strip off the library name
1015            // are try to load it, and then retry the readObject to see
1016            // if we can recognize the objects.
1017       
1018            std::string libraryName = std::string(token,0,posDoubleColon);
1019
1020            // first try the standard nodekit library.
1021            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1022            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObject(dowMap,fr);
1023           
1024            // otherwise try the osgdb_ plugin library.
1025            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1026            if (loadLibrary(pluginLibraryName)==LOADED) return readObject(dowMap,fr);
1027        }
1028    }
1029    else if (fr[1].isOpenBracket())
1030    {
1031   
1032        DotOsgWrapper* wrapper = itr->second.get();
1033        const osg::Object* proto = wrapper->getPrototype();
1034        if (proto==NULL)
1035        {
1036            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
1037            return NULL;
1038        }
1039
1040        // record the number of nested brackets move the input iterator
1041        // over the name { tokens.
1042        int entry = fr[0].getNoNestedBrackets();
1043        fr+=2;
1044
1045        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1046        osg::Object* obj = proto->cloneType();
1047
1048        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
1049        {
1050            bool iteratorAdvanced = false;
1051            if (fr[0].matchWord("UniqueID") && fr[1].isString())
1052            {
1053                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
1054                fr += 2;
1055                iteratorAdvanced = true;
1056            }
1057
1058            // read the local data by iterating through the associate
1059            // list, mapping the associate names to DotOsgWrapper's which
1060            // in turn have the appropriate functions.
1061            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1062                                                          aitr!=assoc.end();
1063                                                          ++aitr)
1064            {
1065                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1066                if (mitr==_objectWrapperMap.end())
1067                {
1068                    // not found so check if a library::class composite name.
1069                    std::string token = *aitr;
1070                    std::string::size_type posDoubleColon = token.rfind("::");
1071                    if (posDoubleColon != std::string::npos)
1072                    {
1073
1074                        // we have a composite name so now strip off the library name
1075                        // are try to load it, and then retry the find to see
1076                        // if we can recognize the objects.
1077
1078                        std::string libraryName = std::string(token,0,posDoubleColon);
1079
1080                        // first try the standard nodekit library.
1081                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1082                        if (loadLibrary(nodeKitLibraryName)==LOADED)
1083                        {
1084                            mitr = _objectWrapperMap.find(*aitr);
1085                        }
1086
1087                        if (mitr==_objectWrapperMap.end())
1088                        {
1089                            // otherwise try the osgdb_ plugin library.
1090                            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1091                            if (loadLibrary(pluginLibraryName)==LOADED)
1092                            {
1093                                mitr = _objectWrapperMap.find(*aitr);
1094                            }
1095                        }
1096
1097                    }
1098                }
1099
1100                if (mitr!=_objectWrapperMap.end())
1101                {
1102                    // get the function to read the data...
1103                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
1104                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
1105                }
1106
1107            }
1108
1109            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
1110        }
1111        ++fr;                        // step over trailing '}'
1112       
1113        return obj;
1114       
1115    }
1116
1117    return 0L;
1118}
1119
1120//
1121// read object from input iterator.
1122//
1123Object* Registry::readObject(Input& fr)
1124{
1125    if (fr[0].matchWord("Use"))
1126    {
1127        if (fr[1].isString())
1128        {
1129            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
1130            if (obj) fr+=2;
1131            return obj;
1132        }
1133        else return NULL;
1134
1135    }
1136
1137    return readObject(_objectWrapperMap,fr);
1138}
1139
1140
1141//
1142// read image from input iterator.
1143//
1144Image* Registry::readImage(Input& fr)
1145{
1146    if (fr[0].matchWord("Use"))
1147    {
1148        if (fr[1].isString())
1149        {
1150            Image* image = dynamic_cast<Image*>(fr.getObjectForUniqueID(fr[1].getStr()));
1151            if (image) fr+=2;
1152            return image;
1153        }
1154        else return NULL;
1155
1156    }
1157
1158    osg::Object* obj = readObject(_imageWrapperMap,fr);
1159    osg::Image* image = dynamic_cast<Image*>(obj);
1160    if (image) return image;
1161    else if (obj) obj->unref();
1162   
1163    return NULL;
1164}
1165
1166
1167//
1168// read drawable from input iterator.
1169//
1170Drawable* Registry::readDrawable(Input& fr)
1171{
1172    if (fr[0].matchWord("Use"))
1173    {
1174        if (fr[1].isString())
1175        {
1176            Drawable* drawable = dynamic_cast<Drawable*>(fr.getObjectForUniqueID(fr[1].getStr()));
1177            if (drawable) fr+=2;
1178            return drawable;
1179        }
1180        else return NULL;
1181
1182    }
1183
1184    osg::Object* obj = readObject(_drawableWrapperMap,fr);
1185    osg::Drawable* drawable = dynamic_cast<Drawable*>(obj);
1186    if (drawable) return drawable;
1187    else if (obj) obj->unref();
1188   
1189    return NULL;
1190}
1191
1192//
1193// read drawable from input iterator.
1194//
1195StateAttribute* Registry::readStateAttribute(Input& fr)
1196{
1197
1198    if (fr[0].matchWord("Use"))
1199    {
1200        if (fr[1].isString())
1201        {
1202            StateAttribute* attribute = dynamic_cast<StateAttribute*>(fr.getObjectForUniqueID(fr[1].getStr()));
1203            if (attribute) fr+=2;
1204            return attribute;
1205        }
1206        else return NULL;
1207
1208    }
1209
1210    return dynamic_cast<StateAttribute*>(readObject(_stateAttrWrapperMap,fr));
1211}
1212
1213//
1214// read drawable from input iterator.
1215//
1216Uniform* Registry::readUniform(Input& fr)
1217{
1218
1219    if (fr[0].matchWord("Use"))
1220    {
1221        if (fr[1].isString())
1222        {
1223            Uniform* attribute = dynamic_cast<Uniform*>(fr.getObjectForUniqueID(fr[1].getStr()));
1224            if (attribute) fr+=2;
1225            return attribute;
1226        }
1227        else return NULL;
1228
1229    }
1230
1231    return dynamic_cast<Uniform*>(readObject(_uniformWrapperMap,fr));
1232}
1233
1234//
1235// read node from input iterator.
1236//
1237Node* Registry::readNode(Input& fr)
1238{
1239    if (fr[0].matchWord("Use"))
1240    {
1241        if (fr[1].isString())
1242        {
1243            Node* node = dynamic_cast<Node*>(fr.getObjectForUniqueID(fr[1].getStr()));
1244            if (node) fr+=2;
1245            return node;
1246        }
1247        else return NULL;
1248
1249    }
1250
1251    osg::Object* obj = readObject(_nodeWrapperMap,fr);
1252    osg::Node* node = dynamic_cast<Node*>(obj);
1253    if (node) return node;
1254    else if (obj) obj->unref();
1255   
1256    return NULL;
1257}
1258
1259//
1260// read image from input iterator.
1261//
1262Shader* Registry::readShader(Input& fr)
1263{
1264    if (fr[0].matchWord("Use"))
1265    {
1266        if (fr[1].isString())
1267        {
1268            Shader* shader = dynamic_cast<Shader*>(fr.getObjectForUniqueID(fr[1].getStr()));
1269            if (shader) fr+=2;
1270            return shader;
1271        }
1272        else return NULL;
1273
1274    }
1275
1276    osg::Object* obj = readObject(_shaderWrapperMap,fr);
1277    osg::Shader* shader = dynamic_cast<Shader*>(obj);
1278    if (shader) return shader;
1279    else if (obj) obj->unref();
1280   
1281    return NULL;
1282}
1283
1284//
1285// Write object to output
1286//
1287bool Registry::writeObject(const osg::Object& obj,Output& fw)
1288{
1289
1290    if (obj.referenceCount()>1)
1291    {
1292        std::string uniqueID;
1293        if (fw.getUniqueIDForObject(&obj,uniqueID))
1294        {
1295            fw.writeUseID( uniqueID );
1296            return true;
1297        }
1298    }
1299
1300    const std::string classname( obj.className() );
1301    const std::string libraryName( obj.libraryName() );
1302    const std::string compositeName( libraryName + "::" + classname );
1303
1304    // try composite name first
1305    DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName);
1306
1307    if (itr==_classNameWrapperMap.end())
1308    {
1309        // first try the standard nodekit library.
1310        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1311        if (loadLibrary(nodeKitLibraryName)==LOADED) return writeObject(obj,fw);
1312
1313        // otherwise try the osgdb_ plugin library.
1314        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1315        if (loadLibrary(pluginLibraryName)==LOADED) return writeObject(obj,fw);
1316
1317        // otherwise try simple class name
1318        if (itr == _classNameWrapperMap.end())
1319            itr = _classNameWrapperMap.find(classname);
1320    }
1321
1322    if (itr!=_classNameWrapperMap.end())
1323    {
1324        DotOsgWrapper* wrapper = itr->second.get();
1325        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1326
1327        if (libraryName=="osg")
1328        {
1329            // member of the core osg, so no need to have composite library::class name.
1330            fw.writeBeginObject( wrapper->getName() );
1331        }
1332        else
1333        {
1334            // member of the node kit so must use composite library::class name.
1335            std::string::size_type posDoubleColon = wrapper->getName().find("::");
1336            if (posDoubleColon != std::string::npos)
1337            {
1338                fw.writeBeginObject( wrapper->getName() );
1339            }
1340            else
1341            {
1342                fw.writeBeginObject( libraryName + "::" + wrapper->getName() );
1343            }
1344        }
1345        fw.moveIn();
1346
1347
1348        // write out the unique ID if required.
1349        if (obj.referenceCount()>1)
1350        {
1351            std::string uniqueID;
1352            fw.createUniqueIDForObject(&obj,uniqueID);
1353            fw.registerUniqueIDForObject(&obj,uniqueID);
1354            fw.writeUniqueID( uniqueID );
1355        }
1356
1357        // read the local data by iterating through the associate
1358        // list, mapping the associate names to DotOsgWrapper's which
1359        // in turn have the appropriate functions.
1360        for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1361                                                      aitr!=assoc.end();
1362                                                      ++aitr)
1363        {
1364            DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1365            if (mitr==_objectWrapperMap.end())
1366            {
1367                // not found so check if a library::class composite name.
1368                std::string token = *aitr;
1369                std::string::size_type posDoubleColon = token.rfind("::");
1370                if (posDoubleColon != std::string::npos)
1371                {
1372
1373                    // we have a composite name so now strip off the library name
1374                    // are try to load it, and then retry the find to see
1375                    // if we can recognize the objects.
1376
1377                    std::string libraryName = std::string(token,0,posDoubleColon);
1378
1379                    // first try the standard nodekit library.
1380                    std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1381                    if (loadLibrary(nodeKitLibraryName)==LOADED)
1382                    {
1383                        mitr = _objectWrapperMap.find(*aitr);
1384                    }
1385
1386                    if (mitr==_objectWrapperMap.end())
1387                    {
1388                        // otherwise try the osgdb_ plugin library.
1389                        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1390                        if (loadLibrary(pluginLibraryName)==LOADED)
1391                        {
1392                            mitr = _objectWrapperMap.find(*aitr);
1393                        }
1394                    }
1395
1396                }
1397            }
1398            if (mitr!=_objectWrapperMap.end())
1399            {
1400                // get the function to read the data...
1401                DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc();
1402                if (wf) (*wf)(obj,fw);
1403            }
1404
1405        }
1406
1407        fw.moveOut();
1408        fw.writeEndObject();
1409
1410        return true;
1411    }
1412   
1413    return false;
1414}
1415
1416
1417
1418struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
1419{
1420    ReadObjectFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1421
1422    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }   
1423    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
1424    virtual bool isValid(osg::Object* object) const { return object!=0;  }
1425};
1426
1427struct Registry::ReadImageFunctor : public Registry::ReadFunctor
1428{
1429    ReadImageFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1430
1431    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }   
1432    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
1433    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
1434};
1435
1436struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
1437{
1438    ReadHeightFieldFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1439
1440    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }   
1441    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
1442    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
1443};
1444
1445struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
1446{
1447    ReadNodeFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1448
1449    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }   
1450    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
1451    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
1452
1453};
1454
1455struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
1456{
1457    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options):
1458        ReadFunctor(filename,options),
1459        _status(status),
1460        _indexBlockSizeHint(indexBlockSizeHint) {}
1461       
1462    ReaderWriter::ArchiveStatus _status;
1463    unsigned int _indexBlockSizeHint;
1464
1465    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
1466    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
1467    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
1468
1469};
1470
1471struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
1472{
1473    ReadShaderFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1474
1475    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }   
1476    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
1477    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
1478};
1479
1480void Registry::addArchiveExtension(const std::string ext)
1481{
1482    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1483        aitr!=_archiveExtList.end();
1484        ++aitr)
1485    {
1486        if ( (*aitr) == ext)   // extension already in archive extension list
1487            return;
1488    }
1489    _archiveExtList.push_back(ext);
1490}
1491
1492ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1493{
1494    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1495        aitr!=_archiveExtList.end();
1496        ++aitr)
1497    {
1498        std::string archiveExtension = "." + (*aitr);
1499
1500        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1501        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1502        if (positionArchive!=std::string::npos)
1503        {
1504            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1505            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1506            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1507            osg::notify(osg::INFO)<<"Contains archive : "<<readFunctor._filename<<std::endl;
1508            osg::notify(osg::INFO)<<"         archive : "<<archiveName<<std::endl;
1509            osg::notify(osg::INFO)<<"         filename : "<<fileName<<std::endl;
1510       
1511            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1512       
1513            if (!result.validArchive()) return result;
1514
1515            osgDB::Archive* archive = result.getArchive();
1516       
1517            osg::ref_ptr<ReaderWriter::Options> options = new ReaderWriter::Options;
1518            options->setDatabasePath(archiveName);
1519
1520            return archive->readObject(fileName,options.get());
1521        }
1522    }
1523 
1524    // record the errors reported by readerwriters.
1525    typedef std::vector<ReaderWriter::ReadResult> Results;
1526    Results results;
1527
1528    // first attempt to load the file from existing ReaderWriter's
1529    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1530    for(;itr.valid();++itr)
1531    {
1532        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1533        if (readFunctor.isValid(rr)) return rr;
1534        else results.push_back(rr);
1535    }
1536
1537    if (!results.empty())
1538    {
1539        unsigned int num_FILE_NOT_HANDLED = 0;
1540        unsigned int num_FILE_NOT_FOUND = 0;
1541        unsigned int num_ERROR_IN_READING_FILE = 0;
1542
1543        Results::iterator ritr;
1544        for(ritr=results.begin();
1545            ritr!=results.end();
1546            ++ritr)
1547        {
1548            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1549            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1550            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1551        }
1552       
1553        if (num_FILE_NOT_HANDLED!=results.size())
1554        {
1555            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1556            {
1557                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1558                {
1559                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1560                    return *ritr;
1561                }
1562            }
1563
1564            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1565            if (!osgDB::containsServerAddress(readFunctor._filename))
1566            {
1567                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1568                {
1569                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1570                    {
1571                        //osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1572                        return *ritr;
1573                    }
1574                }
1575            }
1576        }
1577    }
1578
1579    results.clear();
1580
1581    // now look for a plug-in to load the file.
1582    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1583    if (loadLibrary(libraryName)!=NOT_LOADED)
1584    {
1585        for(;itr.valid();++itr)
1586        {
1587            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1588            if (readFunctor.isValid(rr)) return rr;
1589            else results.push_back(rr);
1590        }
1591    }
1592
1593    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1594    //to download the file and use the stream reading functionality of the plugins to load the file
1595    if (containsServerAddress(readFunctor._filename))
1596    {
1597        ReaderWriter* rw = getReaderWriterForExtension("curl");
1598        if (rw)
1599        {
1600            return readFunctor.doRead(*rw);
1601        }
1602        else
1603        {
1604            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1605        }
1606    }
1607   
1608    if (!results.empty())
1609    {
1610        unsigned int num_FILE_NOT_HANDLED = 0;
1611        unsigned int num_FILE_NOT_FOUND = 0;
1612        unsigned int num_ERROR_IN_READING_FILE = 0;
1613
1614        Results::iterator ritr;
1615        for(ritr=results.begin();
1616            ritr!=results.end();
1617            ++ritr)
1618        {
1619            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1620            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1621            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1622        }
1623       
1624        if (num_FILE_NOT_HANDLED!=results.size())
1625        {
1626            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1627            {
1628                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1629                {
1630                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1631                    return *ritr;
1632                }
1633            }
1634
1635            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1636            {
1637                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1638                {
1639                    // osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1640                    return *ritr;
1641                }
1642            }
1643        }
1644    }
1645    else
1646    {
1647        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1648    }
1649
1650    return results.front();
1651}
1652
1653ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,ReaderWriter::Options::CacheHintOptions cacheHint)
1654{
1655    std::string file(readFunctor._filename);
1656
1657    bool useObjectCache=false;
1658    //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
1659    if (cacheHint!=ReaderWriter::Options::CACHE_ARCHIVES)
1660    {
1661        const ReaderWriter::Options* options=readFunctor._options;
1662        useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
1663    }
1664    if (useObjectCache)
1665    {
1666        // search for entry in the object cache.
1667        {
1668            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1669            ObjectCache::iterator oitr=_objectCache.find(file);
1670            if (oitr!=_objectCache.end())
1671            {
1672                notify(INFO)<<"returning cached instanced of "<<file<<std::endl;
1673                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1674                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1675            }
1676        }
1677       
1678        ReaderWriter::ReadResult rr = read(readFunctor);
1679        if (rr.validObject())
1680        {
1681            // update cache with new entry.
1682            notify(INFO)<<"Adding to object cache "<<file<<std::endl;
1683            addEntryToObjectCache(file,rr.getObject());
1684        }
1685        else
1686        {
1687            notify(INFO)<<"No valid object found for "<<file<<std::endl;
1688        }
1689
1690        return rr;
1691
1692    }
1693    else
1694    {
1695        ReaderWriter::ReadResult rr = read(readFunctor);
1696        return rr;
1697    }
1698}
1699
1700
1701ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options)
1702{
1703    osgDB::Archive* archive = getFromArchiveCache(fileName);
1704    if (archive) return archive;
1705
1706    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),ReaderWriter::Options::CACHE_ARCHIVES);
1707
1708    // default to using caching archive if no options structure provided, but if options are provided use archives
1709    // only if supplied.
1710    if (result.validArchive() &&
1711        (!options || (options->getObjectCacheHint() & ReaderWriter::Options::CACHE_ARCHIVES)) )
1712    {
1713        addToArchiveCache(fileName,result.getArchive());
1714    }
1715    return result;
1716}
1717
1718
1719ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1720{
1721    return readImplementation(ReadObjectFunctor(fileName, options),ReaderWriter::Options::CACHE_OBJECTS);
1722}
1723
1724ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const ReaderWriter::Options* options)
1725{
1726    // record the errors reported by readerwriters.
1727    typedef std::vector<ReaderWriter::WriteResult> Results;
1728    Results results;
1729
1730    // first attempt to load the file from existing ReaderWriter's
1731    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1732    for(;itr.valid();++itr)
1733    {
1734        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1735        if (rr.success()) return rr;
1736        else results.push_back(rr);
1737    }
1738
1739    // now look for a plug-in to save the file.
1740    std::string libraryName = createLibraryNameForFile(fileName);
1741    if (loadLibrary(libraryName)==LOADED)
1742    {
1743        for(;itr.valid();++itr)
1744        {
1745            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1746            if (rr.success()) return rr;
1747            else results.push_back(rr);
1748        }
1749    }
1750
1751    if (results.empty())
1752    {
1753        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1754    }
1755
1756    if (results.front().message().empty())
1757    {
1758        switch(results.front().status())
1759        {
1760            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1761            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1762            default: break;
1763        }
1764    }
1765
1766    return results.front();
1767}
1768
1769
1770
1771ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1772{
1773    return readImplementation(ReadImageFunctor(fileName, options),ReaderWriter::Options::CACHE_IMAGES);
1774}
1775
1776ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const ReaderWriter::Options* options)
1777{
1778    // record the errors reported by readerwriters.
1779    typedef std::vector<ReaderWriter::WriteResult> Results;
1780    Results results;
1781
1782    // first attempt to load the file from existing ReaderWriter's
1783    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1784    for(;itr.valid();++itr)
1785    {
1786        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1787        if (rr.success()) return rr;
1788        else results.push_back(rr);
1789    }
1790
1791    results.clear();
1792
1793    // now look for a plug-in to save the file.
1794    std::string libraryName = createLibraryNameForFile(fileName);
1795    if (loadLibrary(libraryName)==LOADED)
1796    {
1797        for(;itr.valid();++itr)
1798        {
1799            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1800            if (rr.success()) return rr;
1801            else results.push_back(rr);
1802        }
1803    }
1804
1805    if (results.empty())
1806    {
1807        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1808    }
1809   
1810    if (results.front().message().empty())
1811    {
1812        switch(results.front().status())
1813        {
1814            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1815            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1816            default: break;
1817        }
1818    }
1819
1820    return results.front();
1821}
1822
1823
1824ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1825{
1826    return readImplementation(ReadHeightFieldFunctor(fileName, options),ReaderWriter::Options::CACHE_HEIGHTFIELDS);
1827}
1828
1829ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const ReaderWriter::Options* options)
1830{
1831    // record the errors reported by readerwriters.
1832    typedef std::vector<ReaderWriter::WriteResult> Results;
1833    Results results;
1834
1835    // first attempt to load the file from existing ReaderWriter's
1836    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1837    for(;itr.valid();++itr)
1838    {
1839        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1840        if (rr.success()) return rr;
1841        else results.push_back(rr);
1842    }
1843
1844    results.clear();
1845
1846    // now look for a plug-in to save the file.
1847    std::string libraryName = createLibraryNameForFile(fileName);
1848    if (loadLibrary(libraryName)==LOADED)
1849    {
1850        for(;itr.valid();++itr)
1851        {
1852            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1853            if (rr.success()) return rr;
1854            else results.push_back(rr);
1855        }
1856    }
1857
1858    if (results.empty())
1859    {
1860        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1861    }
1862
1863    if (results.front().message().empty())
1864    {
1865        switch(results.front().status())
1866        {
1867            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1868            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1869            default: break;
1870        }
1871    }
1872   
1873    return results.front();
1874}
1875
1876
1877ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1878{
1879#if 0
1880
1881    osg::Timer_t startTick = osg::Timer::instance()->tick();
1882    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),ReaderWriter::Options::CACHE_NODES);
1883    osg::Timer_t endTick = osg::Timer::instance()->tick();
1884    osg::notify(osg::NOTICE)<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1885    return result;
1886
1887#else
1888
1889    return readImplementation(ReadNodeFunctor(fileName, options),ReaderWriter::Options::CACHE_NODES);
1890                             
1891#endif
1892}
1893
1894ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const ReaderWriter::Options* options)
1895{
1896    // record the errors reported by readerwriters.
1897    typedef std::vector<ReaderWriter::WriteResult> Results;
1898    Results results;
1899
1900    // first attempt to write the file from existing ReaderWriter's
1901    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1902    for(;itr.valid();++itr)
1903    {
1904        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1905        if (rr.success()) return rr;
1906        else results.push_back(rr);
1907    }
1908
1909    results.clear();
1910
1911    // now look for a plug-in to save the file.
1912    std::string libraryName = createLibraryNameForFile(fileName);
1913
1914
1915    if (loadLibrary(libraryName)==LOADED)
1916    {
1917        for(;itr.valid();++itr)
1918        {
1919            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1920   
1921            if (rr.success()) return rr;
1922            else results.push_back(rr);
1923        }
1924    }
1925
1926    if (results.empty())
1927    {
1928        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
1929    }
1930
1931    if (results.front().message().empty())
1932    {
1933        switch(results.front().status())
1934        {
1935            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1936            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1937            default: break;
1938        }
1939    }
1940
1941    return results.front();
1942}
1943
1944ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1945{
1946    return readImplementation(ReadShaderFunctor(fileName, options),ReaderWriter::Options::CACHE_SHADERS);
1947}
1948
1949ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const ReaderWriter::Options* options)
1950{
1951    // record the errors reported by readerwriters.
1952    typedef std::vector<ReaderWriter::WriteResult> Results;
1953    Results results;
1954
1955    // first attempt to load the file from existing ReaderWriter's
1956    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1957    for(;itr.valid();++itr)
1958    {
1959        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1960        if (rr.success()) return rr;
1961        else results.push_back(rr);
1962    }
1963
1964    results.clear();
1965
1966    // now look for a plug-in to save the file.
1967    std::string libraryName = createLibraryNameForFile(fileName);
1968    if (loadLibrary(libraryName)==LOADED)
1969    {
1970        for(;itr.valid();++itr)
1971        {
1972            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1973            if (rr.success()) return rr;
1974            else results.push_back(rr);
1975        }
1976    }
1977
1978    if (results.empty())
1979    {
1980        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
1981    }
1982   
1983    if (results.front().message().empty())
1984    {
1985        switch(results.front().status())
1986        {
1987            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1988            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1989            default: break;
1990        }
1991    }
1992
1993    return results.front();
1994}
1995
1996void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
1997{
1998    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1999    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
2000}
2001osg::Object* Registry::getFromObjectCache(const std::string& fileName)
2002{
2003    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2004    ObjectCache::iterator itr = _objectCache.find(fileName);
2005    if (itr!=_objectCache.end()) return itr->second.first.get();
2006    else return 0;
2007}
2008
2009void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(double currentTime)
2010{
2011    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2012
2013    // look for objects with external references and update their time stamp.
2014    for(ObjectCache::iterator itr=_objectCache.begin();
2015        itr!=_objectCache.end();
2016        ++itr)
2017    {
2018        // if ref count is greater the 1 the object has an external reference.
2019        if (itr->second.first->referenceCount()>1)
2020        {
2021            // so update it time stamp.
2022            itr->second.second = currentTime;
2023        }
2024    }
2025}
2026
2027void Registry::removeExpiredObjectsInCache(double expiryTime)
2028{
2029    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2030
2031    typedef std::vector<std::string> ObjectsToRemove;
2032    ObjectsToRemove objectsToRemove;
2033
2034    // first collect all the expired entries in the ObjectToRemove list.
2035    for(ObjectCache::iterator oitr=_objectCache.begin();
2036        oitr!=_objectCache.end();
2037        ++oitr)
2038    {
2039        if (oitr->second.second<=expiryTime)
2040        {
2041            // record the filename of the entry to use as key for deleting
2042            // afterwards/
2043            objectsToRemove.push_back(oitr->first);
2044        }
2045    }
2046   
2047    // remove the entries from the _objectCaache.
2048    for(ObjectsToRemove::iterator ritr=objectsToRemove.begin();
2049        ritr!=objectsToRemove.end();
2050        ++ritr)
2051    {
2052        // std::cout<<"Removing from Registry object cache '"<<*ritr<<"'"<<std::endl;
2053        _objectCache.erase(*ritr);
2054    }
2055       
2056}
2057
2058void Registry::clearObjectCache()
2059{
2060    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2061    _objectCache.clear();
2062}
2063
2064void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
2065{
2066    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2067    _archiveCache[fileName] = archive;
2068}
2069
2070/** Remove archive from cache.*/
2071void Registry::removeFromArchiveCache(const std::string& fileName)
2072{
2073    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2074    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2075    if (itr!=_archiveCache.end())
2076    {
2077        _archiveCache.erase(itr);
2078    }
2079}
2080
2081osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
2082{
2083    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2084    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2085    if (itr!=_archiveCache.end()) return itr->second.get();
2086    else return 0;
2087}
2088
2089void Registry::clearArchiveCache()
2090{
2091    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2092    _archiveCache.clear();
2093}
2094
2095void Registry::releaseGLObjects(osg::State* state)
2096{
2097    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2098
2099    for(ObjectCache::iterator itr = _objectCache.begin();
2100        itr != _objectCache.end();
2101        ++itr)
2102    {
2103        osg::Object* object = itr->second.first.get();
2104        object->releaseGLObjects(state);
2105    }
2106}
2107
2108SharedStateManager* Registry::getOrCreateSharedStateManager()
2109{
2110    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
2111   
2112    return _sharedStateManager.get();
2113}
2114
2115
2116void Registry::registerProtocol(const std::string& protocol)
2117
2118    _registeredProtocols.insert( convertToLowerCase(protocol) );
2119}
2120       
2121bool Registry::isProtocolRegistered(const std::string& protocol)
2122{
2123    return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end());
2124}
Note: See TracBrowser for help on using the browser.