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

Revision 10000, 69.8 kB (checked in by robert, 6 years ago)

From Glenn Waldron, "Here is a first cut at the mime-type support we discussed a little while ago
(http://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg23098.html)

Background: when you access a file over HTTP, you cannot rely on a file extension being present; instead the file's mime-type is conveyed in the HTTP Content-Type response header. This facility adds a mime-type-to-extension map to the registry to handle this.

There are two new osgDB::Registry functions which are pretty self-explanatory:

void addMimeTypeExtensionMapping( mime-type, extension )
ReaderWriter?* getReaderWriterForMimeType( mime-type )

I also added the file osgDB/MimeTypes.cpp which houses a hard-coded list of built-in types. I took the list from here (http://www.webmaster-toolkit.com/mime-types.shtml) and then pared it down to include mostly image and video types, editing them to map to existing plugins where possible.

In addition, I updated the CURL plugin to a) install a set of built-in mime-type mappings, and b) use them to look up an extension in the event that the target filename does not have an extension.

Here is a test case. This URL pulls down a JPEG (without a file extension):
osgviewer --image "http://us.maps3.yimg.com/aerial.maps.yimg.com/ximg?v=1.8&s=256&t=a&r=1&x=0&y=0&z=2"
"

  • 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#ifdef OSG_JAVA_BUILD
678    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
679#elseif defined(__APPLE__)
680    // OSX is rather a mess in FileUtils.cpp w.r.t its appendPlatformSpecificLibraryFilePaths implementation
681    // as it hardwires the plugin name to PlugIns.  This *needs* fixing to use the naming convention as all
682    // other platforms.
683    static std::string prepend = "";
684#else
685    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
686#endif
687
688#if defined(__CYGWIN__)
689    #ifdef _DEBUG
690        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_DEBUG_POSTFIX_WITH_QUOTES+".dll";
691    #else
692        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+".dll";
693    #endif
694#elif defined(__MINGW32__)
695    return prepend+"mingw_"+"osgdb_"+lowercase_ext+".dll";
696#elif defined(WIN32)
697    #ifdef _DEBUG
698        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
699    #else
700        return prepend+"osgdb_"+lowercase_ext+".dll";
701    #endif
702#elif macintosh
703    #ifdef _DEBUG
704        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES;
705    #else
706        return prepend+"osgdb_"+lowercase_ext;
707    #endif
708#elif defined(__hpux__)
709    // why don't we use PLUGIN_EXT from the makefiles here?
710    return prepend+"osgdb_"+lowercase_ext+".sl";
711#else
712    #ifdef _DEBUG
713         return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES + ".so";
714    #else
715         return prepend+"osgdb_"+lowercase_ext+".so";
716    #endif
717#endif
718
719}
720
721std::string Registry::createLibraryNameForNodeKit(const std::string& name)
722{
723#if defined(__CYGWIN__)
724    return "cyg"+name+".dll";
725#elif defined(__MINGW32__)
726    return "lib"+name+".dll";
727#elif defined(WIN32)
728    #ifdef _DEBUG
729        return name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
730    #else
731        return name+".dll";
732    #endif
733#elif macintosh
734    #ifdef _DEBUG
735        return name+OSGDEBUG_POSTFIX_WITH_QUOTES;
736    #else
737        return name;
738    #endif
739#elif defined(__hpux__)
740    // why don't we use PLUGIN_EXT from the makefiles here?
741    return "lib"+name+".sl";
742#else
743    #ifdef _DEBUG
744        return "lib"+name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".so";
745    #else
746        return "lib"+name+".so";
747    #endif
748#endif
749}
750
751Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
752{
753    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
754
755    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
756    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
757
758    _openingLibrary=true;
759
760    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
761    _openingLibrary=false;
762
763    if (dl)
764    {
765        _dlList.push_back(dl);
766        return LOADED;
767    }
768    return NOT_LOADED;
769}
770
771
772bool Registry::closeLibrary(const std::string& fileName)
773{
774    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
775    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
776    if (ditr!=_dlList.end())
777    {
778        _dlList.erase(ditr);
779        return true;
780    }
781    return false;
782}
783
784void Registry::closeAllLibraries()
785{
786    // osg::notify(osg::NOTICE)<<"Registry::closeAllLibraries()"<<std::endl;
787    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
788    _dlList.clear();
789}
790
791Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
792{
793    DynamicLibraryList::iterator ditr = _dlList.begin();
794    for(;ditr!=_dlList.end();++ditr)
795    {
796        if ((*ditr)->getName()==fileName) return ditr;
797    }
798    return _dlList.end();
799}
800
801DynamicLibrary* Registry::getLibrary(const std::string& fileName)
802{
803    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
804    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
805    if (ditr!=_dlList.end()) return ditr->get();
806    else return NULL;
807}
808
809ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
810{
811    // record the existing reader writer.
812    std::set<ReaderWriter*> rwOriginal;
813
814    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
815
816    // first attemt one of the installed loaders
817    for(ReaderWriterList::iterator itr=_rwList.begin();
818        itr!=_rwList.end();
819        ++itr)
820    {
821        rwOriginal.insert(itr->get());
822        if((*itr)->acceptsExtension(ext)) return (*itr).get();
823    }
824   
825    // now look for a plug-in to load the file.
826    std::string libraryName = createLibraryNameForExtension(ext);
827    notify(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
828    if (loadLibrary(libraryName)==LOADED)
829    {
830        for(ReaderWriterList::iterator itr=_rwList.begin();
831            itr!=_rwList.end();
832            ++itr)
833        {
834            if (rwOriginal.find(itr->get())==rwOriginal.end())
835            {
836                if((*itr)->acceptsExtension(ext)) return (*itr).get();
837            }
838        }
839    }
840
841    return NULL;
842
843}
844
845ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType)
846{
847    MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType );
848    return i != _mimeTypeExtMap.end()?
849        getReaderWriterForExtension( i->second ) :
850        NULL;
851}
852
853struct concrete_wrapper: basic_type_wrapper
854{
855    virtual ~concrete_wrapper() {}
856    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
857    bool matches(const osg::Object *proto) const
858    {
859        return myobj_->isSameKindAs(proto);
860    }
861    const osg::Object *myobj_;
862};
863
864osg::Object* Registry::readObjectOfType(const osg::Object& compObj,Input& fr)
865{
866    return readObjectOfType(concrete_wrapper(&compObj), fr);
867}
868
869osg::Object* Registry::readObjectOfType(const basic_type_wrapper &btw,Input& fr)
870{
871    const char *str = fr[0].getStr();
872    if (str==NULL) return NULL;
873
874    if (fr[0].matchWord("Use"))
875    {
876        if (fr[1].isString())
877        {
878            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
879            if (obj && btw.matches(obj))
880            {
881                fr+=2;
882                return obj;
883            }
884        }
885        else return NULL;
886
887    }
888
889    std::string name = str;
890    DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name);
891    if (itr==_objectWrapperMap.end())
892    {
893        // not found so check if a library::class composite name.
894        std::string token = fr[0].getStr();
895        std::string::size_type posDoubleColon = token.rfind("::");
896        if (posDoubleColon != std::string::npos)
897        {
898            // we have a composite name so now strip off the library name
899            // are try to load it, and then retry the readObject to see
900            // if we can recognize the objects.
901            std::string libraryName = std::string(token,0,posDoubleColon);
902
903            // first try the standard nodekit library.
904            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
905            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObjectOfType(btw,fr);
906           
907            // otherwise try the osgdb_ plugin library.
908            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
909            if (loadLibrary(pluginLibraryName)==LOADED) return readObjectOfType(btw,fr);
910        }
911    }
912    else if (fr[1].isOpenBracket())
913    {
914        DotOsgWrapper* wrapper = itr->second.get();
915        const osg::Object* proto = wrapper->getPrototype();
916        if (proto==NULL)
917        {
918            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
919            return NULL;
920        }
921       
922        if (!btw.matches(proto))
923        {
924            return NULL;
925        }
926
927        // record the number of nested brackets move the input iterator
928        // over the name { tokens.
929        int entry = fr[0].getNoNestedBrackets();
930        fr+=2;
931
932        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
933        osg::Object* obj = proto->cloneType();
934
935        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
936        {
937            bool iteratorAdvanced = false;
938            if (fr[0].matchWord("UniqueID") && fr[1].isString())
939            {
940                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
941                fr += 2;
942                iteratorAdvanced = true;
943            }
944
945            // read the local data by iterating through the associate
946            // list, mapping the associate names to DotOsgWrapper's which
947            // in turn have the appropriate functions.
948            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
949                                                          aitr!=assoc.end();
950                                                          ++aitr)
951            {
952                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
953                if (mitr==_objectWrapperMap.end())
954                {
955                    // not found so check if a library::class composite name.
956                    std::string token = *aitr;
957                    std::string::size_type posDoubleColon = token.rfind("::");
958                    if (posDoubleColon != std::string::npos)
959                    {
960                        // we have a composite name so now strip off the library name
961                        // and try to load it, and then retry the find to see
962                        // if we can recognize the objects.
963                        std::string libraryName = std::string(token,0,posDoubleColon);
964
965                        // first try the standard nodekit library.
966                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
967                        if (loadLibrary(nodeKitLibraryName)==LOADED)
968                        {
969                            mitr = _objectWrapperMap.find(*aitr);
970                            if (mitr==_objectWrapperMap.end())
971                            {
972                                // otherwise try the osgdb_ plugin library.
973                                std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
974                                if (loadLibrary(pluginLibraryName)==LOADED)
975                                {
976                                    mitr = _objectWrapperMap.find(*aitr);
977                                }
978                            }
979                        }
980                    }
981                }
982
983                if (mitr!=_objectWrapperMap.end())
984                {
985                    // get the function to read the data...
986                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
987                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
988                }
989
990            }
991
992            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
993        }
994        ++fr;                        // step over trailing '}'
995       
996        return obj;
997       
998    }
999    return 0L;
1000}
1001
1002//
1003// read object from input iterator.
1004//
1005osg::Object* Registry::readObject(DotOsgWrapperMap& dowMap,Input& fr)
1006{
1007    const char *str = fr[0].getStr();
1008    if (str==NULL) return NULL;
1009
1010    std::string name = str;
1011    DotOsgWrapperMap::iterator itr = dowMap.find(name);
1012    if (itr==dowMap.end())
1013    {
1014        // not found so check if a library::class composite name.
1015        std::string token = fr[0].getStr();
1016        std::string::size_type posDoubleColon = token.rfind("::");
1017        if (posDoubleColon != std::string::npos)
1018        {
1019            // we have a composite name so now strip off the library name
1020            // are try to load it, and then retry the readObject to see
1021            // if we can recognize the objects.
1022       
1023            std::string libraryName = std::string(token,0,posDoubleColon);
1024
1025            // first try the standard nodekit library.
1026            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1027            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObject(dowMap,fr);
1028           
1029            // otherwise try the osgdb_ plugin library.
1030            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1031            if (loadLibrary(pluginLibraryName)==LOADED) return readObject(dowMap,fr);
1032        }
1033    }
1034    else if (fr[1].isOpenBracket())
1035    {
1036   
1037        DotOsgWrapper* wrapper = itr->second.get();
1038        const osg::Object* proto = wrapper->getPrototype();
1039        if (proto==NULL)
1040        {
1041            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
1042            return NULL;
1043        }
1044
1045        // record the number of nested brackets move the input iterator
1046        // over the name { tokens.
1047        int entry = fr[0].getNoNestedBrackets();
1048        fr+=2;
1049
1050        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1051        osg::Object* obj = proto->cloneType();
1052
1053        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
1054        {
1055            bool iteratorAdvanced = false;
1056            if (fr[0].matchWord("UniqueID") && fr[1].isString())
1057            {
1058                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
1059                fr += 2;
1060                iteratorAdvanced = true;
1061            }
1062
1063            // read the local data by iterating through the associate
1064            // list, mapping the associate names to DotOsgWrapper's which
1065            // in turn have the appropriate functions.
1066            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1067                                                          aitr!=assoc.end();
1068                                                          ++aitr)
1069            {
1070                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1071                if (mitr==_objectWrapperMap.end())
1072                {
1073                    // not found so check if a library::class composite name.
1074                    std::string token = *aitr;
1075                    std::string::size_type posDoubleColon = token.rfind("::");
1076                    if (posDoubleColon != std::string::npos)
1077                    {
1078
1079                        // we have a composite name so now strip off the library name
1080                        // are try to load it, and then retry the find to see
1081                        // if we can recognize the objects.
1082
1083                        std::string libraryName = std::string(token,0,posDoubleColon);
1084
1085                        // first try the standard nodekit library.
1086                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1087                        if (loadLibrary(nodeKitLibraryName)==LOADED)
1088                        {
1089                            mitr = _objectWrapperMap.find(*aitr);
1090                        }
1091
1092                        if (mitr==_objectWrapperMap.end())
1093                        {
1094                            // otherwise try the osgdb_ plugin library.
1095                            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1096                            if (loadLibrary(pluginLibraryName)==LOADED)
1097                            {
1098                                mitr = _objectWrapperMap.find(*aitr);
1099                            }
1100                        }
1101
1102                    }
1103                }
1104
1105                if (mitr!=_objectWrapperMap.end())
1106                {
1107                    // get the function to read the data...
1108                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
1109                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
1110                }
1111
1112            }
1113
1114            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
1115        }
1116        ++fr;                        // step over trailing '}'
1117       
1118        return obj;
1119       
1120    }
1121
1122    return 0L;
1123}
1124
1125//
1126// read object from input iterator.
1127//
1128Object* Registry::readObject(Input& fr)
1129{
1130    if (fr[0].matchWord("Use"))
1131    {
1132        if (fr[1].isString())
1133        {
1134            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
1135            if (obj) fr+=2;
1136            return obj;
1137        }
1138        else return NULL;
1139
1140    }
1141
1142    return readObject(_objectWrapperMap,fr);
1143}
1144
1145
1146//
1147// read image from input iterator.
1148//
1149Image* Registry::readImage(Input& fr)
1150{
1151    if (fr[0].matchWord("Use"))
1152    {
1153        if (fr[1].isString())
1154        {
1155            Image* image = dynamic_cast<Image*>(fr.getObjectForUniqueID(fr[1].getStr()));
1156            if (image) fr+=2;
1157            return image;
1158        }
1159        else return NULL;
1160
1161    }
1162
1163    osg::Object* obj = readObject(_imageWrapperMap,fr);
1164    osg::Image* image = dynamic_cast<Image*>(obj);
1165    if (image) return image;
1166    else if (obj) obj->unref();
1167   
1168    return NULL;
1169}
1170
1171
1172//
1173// read drawable from input iterator.
1174//
1175Drawable* Registry::readDrawable(Input& fr)
1176{
1177    if (fr[0].matchWord("Use"))
1178    {
1179        if (fr[1].isString())
1180        {
1181            Drawable* drawable = dynamic_cast<Drawable*>(fr.getObjectForUniqueID(fr[1].getStr()));
1182            if (drawable) fr+=2;
1183            return drawable;
1184        }
1185        else return NULL;
1186
1187    }
1188
1189    osg::Object* obj = readObject(_drawableWrapperMap,fr);
1190    osg::Drawable* drawable = dynamic_cast<Drawable*>(obj);
1191    if (drawable) return drawable;
1192    else if (obj) obj->unref();
1193   
1194    return NULL;
1195}
1196
1197//
1198// read drawable from input iterator.
1199//
1200StateAttribute* Registry::readStateAttribute(Input& fr)
1201{
1202
1203    if (fr[0].matchWord("Use"))
1204    {
1205        if (fr[1].isString())
1206        {
1207            StateAttribute* attribute = dynamic_cast<StateAttribute*>(fr.getObjectForUniqueID(fr[1].getStr()));
1208            if (attribute) fr+=2;
1209            return attribute;
1210        }
1211        else return NULL;
1212
1213    }
1214
1215    return dynamic_cast<StateAttribute*>(readObject(_stateAttrWrapperMap,fr));
1216}
1217
1218//
1219// read drawable from input iterator.
1220//
1221Uniform* Registry::readUniform(Input& fr)
1222{
1223
1224    if (fr[0].matchWord("Use"))
1225    {
1226        if (fr[1].isString())
1227        {
1228            Uniform* attribute = dynamic_cast<Uniform*>(fr.getObjectForUniqueID(fr[1].getStr()));
1229            if (attribute) fr+=2;
1230            return attribute;
1231        }
1232        else return NULL;
1233
1234    }
1235
1236    return dynamic_cast<Uniform*>(readObject(_uniformWrapperMap,fr));
1237}
1238
1239//
1240// read node from input iterator.
1241//
1242Node* Registry::readNode(Input& fr)
1243{
1244    if (fr[0].matchWord("Use"))
1245    {
1246        if (fr[1].isString())
1247        {
1248            Node* node = dynamic_cast<Node*>(fr.getObjectForUniqueID(fr[1].getStr()));
1249            if (node) fr+=2;
1250            return node;
1251        }
1252        else return NULL;
1253
1254    }
1255
1256    osg::Object* obj = readObject(_nodeWrapperMap,fr);
1257    osg::Node* node = dynamic_cast<Node*>(obj);
1258    if (node) return node;
1259    else if (obj) obj->unref();
1260   
1261    return NULL;
1262}
1263
1264//
1265// read image from input iterator.
1266//
1267Shader* Registry::readShader(Input& fr)
1268{
1269    if (fr[0].matchWord("Use"))
1270    {
1271        if (fr[1].isString())
1272        {
1273            Shader* shader = dynamic_cast<Shader*>(fr.getObjectForUniqueID(fr[1].getStr()));
1274            if (shader) fr+=2;
1275            return shader;
1276        }
1277        else return NULL;
1278
1279    }
1280
1281    osg::Object* obj = readObject(_shaderWrapperMap,fr);
1282    osg::Shader* shader = dynamic_cast<Shader*>(obj);
1283    if (shader) return shader;
1284    else if (obj) obj->unref();
1285   
1286    return NULL;
1287}
1288
1289//
1290// Write object to output
1291//
1292bool Registry::writeObject(const osg::Object& obj,Output& fw)
1293{
1294
1295    if (obj.referenceCount()>1)
1296    {
1297        std::string uniqueID;
1298        if (fw.getUniqueIDForObject(&obj,uniqueID))
1299        {
1300            fw.writeUseID( uniqueID );
1301            return true;
1302        }
1303    }
1304
1305    const std::string classname( obj.className() );
1306    const std::string libraryName( obj.libraryName() );
1307    const std::string compositeName( libraryName + "::" + classname );
1308
1309    // try composite name first
1310    DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName);
1311
1312    if (itr==_classNameWrapperMap.end())
1313    {
1314        // first try the standard nodekit library.
1315        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1316        if (loadLibrary(nodeKitLibraryName)==LOADED) return writeObject(obj,fw);
1317
1318        // otherwise try the osgdb_ plugin library.
1319        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1320        if (loadLibrary(pluginLibraryName)==LOADED) return writeObject(obj,fw);
1321
1322        // otherwise try simple class name
1323        if (itr == _classNameWrapperMap.end())
1324            itr = _classNameWrapperMap.find(classname);
1325    }
1326
1327    if (itr!=_classNameWrapperMap.end())
1328    {
1329        DotOsgWrapper* wrapper = itr->second.get();
1330        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1331
1332        if (libraryName=="osg")
1333        {
1334            // member of the core osg, so no need to have composite library::class name.
1335            fw.writeBeginObject( wrapper->getName() );
1336        }
1337        else
1338        {
1339            // member of the node kit so must use composite library::class name.
1340            std::string::size_type posDoubleColon = wrapper->getName().find("::");
1341            if (posDoubleColon != std::string::npos)
1342            {
1343                fw.writeBeginObject( wrapper->getName() );
1344            }
1345            else
1346            {
1347                fw.writeBeginObject( libraryName + "::" + wrapper->getName() );
1348            }
1349        }
1350        fw.moveIn();
1351
1352
1353        // write out the unique ID if required.
1354        if (obj.referenceCount()>1)
1355        {
1356            std::string uniqueID;
1357            fw.createUniqueIDForObject(&obj,uniqueID);
1358            fw.registerUniqueIDForObject(&obj,uniqueID);
1359            fw.writeUniqueID( uniqueID );
1360        }
1361
1362        // read the local data by iterating through the associate
1363        // list, mapping the associate names to DotOsgWrapper's which
1364        // in turn have the appropriate functions.
1365        for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1366                                                      aitr!=assoc.end();
1367                                                      ++aitr)
1368        {
1369            DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1370            if (mitr==_objectWrapperMap.end())
1371            {
1372                // not found so check if a library::class composite name.
1373                std::string token = *aitr;
1374                std::string::size_type posDoubleColon = token.rfind("::");
1375                if (posDoubleColon != std::string::npos)
1376                {
1377
1378                    // we have a composite name so now strip off the library name
1379                    // are try to load it, and then retry the find to see
1380                    // if we can recognize the objects.
1381
1382                    std::string libraryName = std::string(token,0,posDoubleColon);
1383
1384                    // first try the standard nodekit library.
1385                    std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1386                    if (loadLibrary(nodeKitLibraryName)==LOADED)
1387                    {
1388                        mitr = _objectWrapperMap.find(*aitr);
1389                    }
1390
1391                    if (mitr==_objectWrapperMap.end())
1392                    {
1393                        // otherwise try the osgdb_ plugin library.
1394                        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1395                        if (loadLibrary(pluginLibraryName)==LOADED)
1396                        {
1397                            mitr = _objectWrapperMap.find(*aitr);
1398                        }
1399                    }
1400
1401                }
1402            }
1403            if (mitr!=_objectWrapperMap.end())
1404            {
1405                // get the function to read the data...
1406                DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc();
1407                if (wf) (*wf)(obj,fw);
1408            }
1409
1410        }
1411
1412        fw.moveOut();
1413        fw.writeEndObject();
1414
1415        return true;
1416    }
1417   
1418    return false;
1419}
1420
1421
1422
1423struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
1424{
1425    ReadObjectFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1426
1427    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }   
1428    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
1429    virtual bool isValid(osg::Object* object) const { return object!=0;  }
1430};
1431
1432struct Registry::ReadImageFunctor : public Registry::ReadFunctor
1433{
1434    ReadImageFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1435
1436    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }   
1437    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
1438    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
1439};
1440
1441struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
1442{
1443    ReadHeightFieldFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1444
1445    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }   
1446    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
1447    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
1448};
1449
1450struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
1451{
1452    ReadNodeFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1453
1454    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }   
1455    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
1456    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
1457
1458};
1459
1460struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
1461{
1462    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options):
1463        ReadFunctor(filename,options),
1464        _status(status),
1465        _indexBlockSizeHint(indexBlockSizeHint) {}
1466       
1467    ReaderWriter::ArchiveStatus _status;
1468    unsigned int _indexBlockSizeHint;
1469
1470    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
1471    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
1472    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
1473
1474};
1475
1476struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
1477{
1478    ReadShaderFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1479
1480    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }   
1481    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
1482    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
1483};
1484
1485void Registry::addArchiveExtension(const std::string ext)
1486{
1487    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1488        aitr!=_archiveExtList.end();
1489        ++aitr)
1490    {
1491        if ( (*aitr) == ext)   // extension already in archive extension list
1492            return;
1493    }
1494    _archiveExtList.push_back(ext);
1495}
1496
1497ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1498{
1499    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1500        aitr!=_archiveExtList.end();
1501        ++aitr)
1502    {
1503        std::string archiveExtension = "." + (*aitr);
1504
1505        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1506        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1507        if (positionArchive!=std::string::npos)
1508        {
1509            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1510            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1511            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1512            osg::notify(osg::INFO)<<"Contains archive : "<<readFunctor._filename<<std::endl;
1513            osg::notify(osg::INFO)<<"         archive : "<<archiveName<<std::endl;
1514            osg::notify(osg::INFO)<<"         filename : "<<fileName<<std::endl;
1515       
1516            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1517       
1518            if (!result.validArchive()) return result;
1519
1520            osgDB::Archive* archive = result.getArchive();
1521       
1522            osg::ref_ptr<ReaderWriter::Options> options = new ReaderWriter::Options;
1523            options->setDatabasePath(archiveName);
1524
1525            return archive->readObject(fileName,options.get());
1526        }
1527    }
1528 
1529    // record the errors reported by readerwriters.
1530    typedef std::vector<ReaderWriter::ReadResult> Results;
1531    Results results;
1532
1533    // first attempt to load the file from existing ReaderWriter's
1534    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1535    for(;itr.valid();++itr)
1536    {
1537        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1538        if (readFunctor.isValid(rr)) return rr;
1539        else results.push_back(rr);
1540    }
1541
1542    if (!results.empty())
1543    {
1544        unsigned int num_FILE_NOT_HANDLED = 0;
1545        unsigned int num_FILE_NOT_FOUND = 0;
1546        unsigned int num_ERROR_IN_READING_FILE = 0;
1547
1548        Results::iterator ritr;
1549        for(ritr=results.begin();
1550            ritr!=results.end();
1551            ++ritr)
1552        {
1553            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1554            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1555            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1556        }
1557       
1558        if (num_FILE_NOT_HANDLED!=results.size())
1559        {
1560            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1561            {
1562                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1563                {
1564                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1565                    return *ritr;
1566                }
1567            }
1568
1569            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1570            if (!osgDB::containsServerAddress(readFunctor._filename))
1571            {
1572                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1573                {
1574                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1575                    {
1576                        //osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1577                        return *ritr;
1578                    }
1579                }
1580            }
1581        }
1582    }
1583
1584    results.clear();
1585
1586    // now look for a plug-in to load the file.
1587    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1588    if (loadLibrary(libraryName)!=NOT_LOADED)
1589    {
1590        for(;itr.valid();++itr)
1591        {
1592            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1593            if (readFunctor.isValid(rr)) return rr;
1594            else results.push_back(rr);
1595        }
1596    }
1597
1598    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1599    //to download the file and use the stream reading functionality of the plugins to load the file
1600    if (containsServerAddress(readFunctor._filename))
1601    {
1602        ReaderWriter* rw = getReaderWriterForExtension("curl");
1603        if (rw)
1604        {
1605            return readFunctor.doRead(*rw);
1606        }
1607        else
1608        {
1609            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1610        }
1611    }
1612   
1613    if (!results.empty())
1614    {
1615        unsigned int num_FILE_NOT_HANDLED = 0;
1616        unsigned int num_FILE_NOT_FOUND = 0;
1617        unsigned int num_ERROR_IN_READING_FILE = 0;
1618
1619        Results::iterator ritr;
1620        for(ritr=results.begin();
1621            ritr!=results.end();
1622            ++ritr)
1623        {
1624            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1625            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1626            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1627        }
1628       
1629        if (num_FILE_NOT_HANDLED!=results.size())
1630        {
1631            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1632            {
1633                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1634                {
1635                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1636                    return *ritr;
1637                }
1638            }
1639
1640            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1641            {
1642                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1643                {
1644                    // osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1645                    return *ritr;
1646                }
1647            }
1648        }
1649    }
1650    else
1651    {
1652        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1653    }
1654
1655    return results.front();
1656}
1657
1658ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,ReaderWriter::Options::CacheHintOptions cacheHint)
1659{
1660    std::string file(readFunctor._filename);
1661
1662    bool useObjectCache=false;
1663    //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
1664    if (cacheHint!=ReaderWriter::Options::CACHE_ARCHIVES)
1665    {
1666        const ReaderWriter::Options* options=readFunctor._options;
1667        useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
1668    }
1669    if (useObjectCache)
1670    {
1671        // search for entry in the object cache.
1672        {
1673            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1674            ObjectCache::iterator oitr=_objectCache.find(file);
1675            if (oitr!=_objectCache.end())
1676            {
1677                notify(INFO)<<"returning cached instanced of "<<file<<std::endl;
1678                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1679                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1680            }
1681        }
1682       
1683        ReaderWriter::ReadResult rr = read(readFunctor);
1684        if (rr.validObject())
1685        {
1686            // update cache with new entry.
1687            notify(INFO)<<"Adding to object cache "<<file<<std::endl;
1688            addEntryToObjectCache(file,rr.getObject());
1689        }
1690        else
1691        {
1692            notify(INFO)<<"No valid object found for "<<file<<std::endl;
1693        }
1694
1695        return rr;
1696
1697    }
1698    else
1699    {
1700        ReaderWriter::ReadResult rr = read(readFunctor);
1701        return rr;
1702    }
1703}
1704
1705
1706ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options)
1707{
1708    osgDB::Archive* archive = getFromArchiveCache(fileName);
1709    if (archive) return archive;
1710
1711    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),ReaderWriter::Options::CACHE_ARCHIVES);
1712
1713    // default to using caching archive if no options structure provided, but if options are provided use archives
1714    // only if supplied.
1715    if (result.validArchive() &&
1716        (!options || (options->getObjectCacheHint() & ReaderWriter::Options::CACHE_ARCHIVES)) )
1717    {
1718        addToArchiveCache(fileName,result.getArchive());
1719    }
1720    return result;
1721}
1722
1723
1724ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1725{
1726    return readImplementation(ReadObjectFunctor(fileName, options),ReaderWriter::Options::CACHE_OBJECTS);
1727}
1728
1729ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const ReaderWriter::Options* options)
1730{
1731    // record the errors reported by readerwriters.
1732    typedef std::vector<ReaderWriter::WriteResult> Results;
1733    Results results;
1734
1735    // first attempt to load the file from existing ReaderWriter's
1736    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1737    for(;itr.valid();++itr)
1738    {
1739        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1740        if (rr.success()) return rr;
1741        else results.push_back(rr);
1742    }
1743
1744    // now look for a plug-in to save the file.
1745    std::string libraryName = createLibraryNameForFile(fileName);
1746    if (loadLibrary(libraryName)==LOADED)
1747    {
1748        for(;itr.valid();++itr)
1749        {
1750            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1751            if (rr.success()) return rr;
1752            else results.push_back(rr);
1753        }
1754    }
1755
1756    if (results.empty())
1757    {
1758        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1759    }
1760
1761    if (results.front().message().empty())
1762    {
1763        switch(results.front().status())
1764        {
1765            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1766            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1767            default: break;
1768        }
1769    }
1770
1771    return results.front();
1772}
1773
1774
1775
1776ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1777{
1778    return readImplementation(ReadImageFunctor(fileName, options),ReaderWriter::Options::CACHE_IMAGES);
1779}
1780
1781ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const ReaderWriter::Options* options)
1782{
1783    // record the errors reported by readerwriters.
1784    typedef std::vector<ReaderWriter::WriteResult> Results;
1785    Results results;
1786
1787    // first attempt to load the file from existing ReaderWriter's
1788    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1789    for(;itr.valid();++itr)
1790    {
1791        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1792        if (rr.success()) return rr;
1793        else results.push_back(rr);
1794    }
1795
1796    results.clear();
1797
1798    // now look for a plug-in to save the file.
1799    std::string libraryName = createLibraryNameForFile(fileName);
1800    if (loadLibrary(libraryName)==LOADED)
1801    {
1802        for(;itr.valid();++itr)
1803        {
1804            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1805            if (rr.success()) return rr;
1806            else results.push_back(rr);
1807        }
1808    }
1809
1810    if (results.empty())
1811    {
1812        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1813    }
1814   
1815    if (results.front().message().empty())
1816    {
1817        switch(results.front().status())
1818        {
1819            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1820            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1821            default: break;
1822        }
1823    }
1824
1825    return results.front();
1826}
1827
1828
1829ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1830{
1831    return readImplementation(ReadHeightFieldFunctor(fileName, options),ReaderWriter::Options::CACHE_HEIGHTFIELDS);
1832}
1833
1834ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const ReaderWriter::Options* options)
1835{
1836    // record the errors reported by readerwriters.
1837    typedef std::vector<ReaderWriter::WriteResult> Results;
1838    Results results;
1839
1840    // first attempt to load the file from existing ReaderWriter's
1841    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1842    for(;itr.valid();++itr)
1843    {
1844        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1845        if (rr.success()) return rr;
1846        else results.push_back(rr);
1847    }
1848
1849    results.clear();
1850
1851    // now look for a plug-in to save the file.
1852    std::string libraryName = createLibraryNameForFile(fileName);
1853    if (loadLibrary(libraryName)==LOADED)
1854    {
1855        for(;itr.valid();++itr)
1856        {
1857            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1858            if (rr.success()) return rr;
1859            else results.push_back(rr);
1860        }
1861    }
1862
1863    if (results.empty())
1864    {
1865        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1866    }
1867
1868    if (results.front().message().empty())
1869    {
1870        switch(results.front().status())
1871        {
1872            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1873            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1874            default: break;
1875        }
1876    }
1877   
1878    return results.front();
1879}
1880
1881
1882ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1883{
1884#if 0
1885
1886    osg::Timer_t startTick = osg::Timer::instance()->tick();
1887    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),ReaderWriter::Options::CACHE_NODES);
1888    osg::Timer_t endTick = osg::Timer::instance()->tick();
1889    osg::notify(osg::NOTICE)<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1890    return result;
1891
1892#else
1893
1894    return readImplementation(ReadNodeFunctor(fileName, options),ReaderWriter::Options::CACHE_NODES);
1895                             
1896#endif
1897}
1898
1899ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const ReaderWriter::Options* options)
1900{
1901    // record the errors reported by readerwriters.
1902    typedef std::vector<ReaderWriter::WriteResult> Results;
1903    Results results;
1904
1905    // first attempt to write the file from existing ReaderWriter's
1906    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1907    for(;itr.valid();++itr)
1908    {
1909        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1910        if (rr.success()) return rr;
1911        else results.push_back(rr);
1912    }
1913
1914    results.clear();
1915
1916    // now look for a plug-in to save the file.
1917    std::string libraryName = createLibraryNameForFile(fileName);
1918
1919
1920    if (loadLibrary(libraryName)==LOADED)
1921    {
1922        for(;itr.valid();++itr)
1923        {
1924            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1925   
1926            if (rr.success()) return rr;
1927            else results.push_back(rr);
1928        }
1929    }
1930
1931    if (results.empty())
1932    {
1933        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
1934    }
1935
1936    if (results.front().message().empty())
1937    {
1938        switch(results.front().status())
1939        {
1940            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1941            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1942            default: break;
1943        }
1944    }
1945
1946    return results.front();
1947}
1948
1949ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1950{
1951    return readImplementation(ReadShaderFunctor(fileName, options),ReaderWriter::Options::CACHE_SHADERS);
1952}
1953
1954ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const ReaderWriter::Options* options)
1955{
1956    // record the errors reported by readerwriters.
1957    typedef std::vector<ReaderWriter::WriteResult> Results;
1958    Results results;
1959
1960    // first attempt to load the file from existing ReaderWriter's
1961    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1962    for(;itr.valid();++itr)
1963    {
1964        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1965        if (rr.success()) return rr;
1966        else results.push_back(rr);
1967    }
1968
1969    results.clear();
1970
1971    // now look for a plug-in to save the file.
1972    std::string libraryName = createLibraryNameForFile(fileName);
1973    if (loadLibrary(libraryName)==LOADED)
1974    {
1975        for(;itr.valid();++itr)
1976        {
1977            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1978            if (rr.success()) return rr;
1979            else results.push_back(rr);
1980        }
1981    }
1982
1983    if (results.empty())
1984    {
1985        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
1986    }
1987   
1988    if (results.front().message().empty())
1989    {
1990        switch(results.front().status())
1991        {
1992            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1993            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1994            default: break;
1995        }
1996    }
1997
1998    return results.front();
1999}
2000
2001void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
2002{
2003    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2004    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
2005}
2006osg::Object* Registry::getFromObjectCache(const std::string& fileName)
2007{
2008    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2009    ObjectCache::iterator itr = _objectCache.find(fileName);
2010    if (itr!=_objectCache.end()) return itr->second.first.get();
2011    else return 0;
2012}
2013
2014void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(double currentTime)
2015{
2016    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2017
2018    // look for objects with external references and update their time stamp.
2019    for(ObjectCache::iterator itr=_objectCache.begin();
2020        itr!=_objectCache.end();
2021        ++itr)
2022    {
2023        // if ref count is greater the 1 the object has an external reference.
2024        if (itr->second.first->referenceCount()>1)
2025        {
2026            // so update it time stamp.
2027            itr->second.second = currentTime;
2028        }
2029    }
2030}
2031
2032void Registry::removeExpiredObjectsInCache(double expiryTime)
2033{
2034    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2035
2036    typedef std::vector<std::string> ObjectsToRemove;
2037    ObjectsToRemove objectsToRemove;
2038
2039    // first collect all the expired entries in the ObjectToRemove list.
2040    for(ObjectCache::iterator oitr=_objectCache.begin();
2041        oitr!=_objectCache.end();
2042        ++oitr)
2043    {
2044        if (oitr->second.second<=expiryTime)
2045        {
2046            // record the filename of the entry to use as key for deleting
2047            // afterwards/
2048            objectsToRemove.push_back(oitr->first);
2049        }
2050    }
2051   
2052    // remove the entries from the _objectCaache.
2053    for(ObjectsToRemove::iterator ritr=objectsToRemove.begin();
2054        ritr!=objectsToRemove.end();
2055        ++ritr)
2056    {
2057        // std::cout<<"Removing from Registry object cache '"<<*ritr<<"'"<<std::endl;
2058        _objectCache.erase(*ritr);
2059    }
2060       
2061}
2062
2063void Registry::clearObjectCache()
2064{
2065    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2066    _objectCache.clear();
2067}
2068
2069void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
2070{
2071    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2072    _archiveCache[fileName] = archive;
2073}
2074
2075/** Remove archive from cache.*/
2076void Registry::removeFromArchiveCache(const std::string& fileName)
2077{
2078    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2079    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2080    if (itr!=_archiveCache.end())
2081    {
2082        _archiveCache.erase(itr);
2083    }
2084}
2085
2086osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
2087{
2088    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2089    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2090    if (itr!=_archiveCache.end()) return itr->second.get();
2091    else return 0;
2092}
2093
2094void Registry::clearArchiveCache()
2095{
2096    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2097    _archiveCache.clear();
2098}
2099
2100void Registry::releaseGLObjects(osg::State* state)
2101{
2102    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2103
2104    for(ObjectCache::iterator itr = _objectCache.begin();
2105        itr != _objectCache.end();
2106        ++itr)
2107    {
2108        osg::Object* object = itr->second.first.get();
2109        object->releaseGLObjects(state);
2110    }
2111}
2112
2113SharedStateManager* Registry::getOrCreateSharedStateManager()
2114{
2115    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
2116   
2117    return _sharedStateManager.get();
2118}
2119
2120
2121void Registry::registerProtocol(const std::string& protocol)
2122
2123    _registeredProtocols.insert( convertToLowerCase(protocol) );
2124}
2125       
2126bool Registry::isProtocolRegistered(const std::string& protocol)
2127{
2128    return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end());
2129}
Note: See TracBrowser for help on using the browser.