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 #include <osgDB/DotOsgWrapper>
14 #include <osgDB/Registry>
15 
16 using namespace osgDB;
17 
DotOsgWrapper(osg::Object * proto,const std::string & name,const std::string & associates,ReadFunc readFunc,WriteFunc writeFunc,ReadWriteMode readWriteMode)18 DotOsgWrapper::DotOsgWrapper(osg::Object* proto,
19               const std::string& name,
20               const std::string& associates,
21               ReadFunc readFunc,
22               WriteFunc writeFunc,
23               ReadWriteMode readWriteMode)
24 {
25 
26 
27     _prototype = proto;
28     _name = name;
29 
30 
31     // copy the names in the space delimited associates input into
32     // a vector of separated names.
33     std::string::size_type start_of_name = associates.find_first_not_of(' ');
34     while (start_of_name!=std::string::npos)
35     {
36         std::string::size_type end_of_name = associates.find_first_of(' ',start_of_name);
37         if (end_of_name!=std::string::npos)
38         {
39             _associates.push_back(std::string(associates,start_of_name,end_of_name-start_of_name));
40             start_of_name = associates.find_first_not_of(' ',end_of_name);
41         }
42         else
43         {
44             _associates.push_back(std::string(associates,start_of_name,associates.size()-start_of_name));
45             start_of_name = end_of_name;
46         }
47     }
48 
49     _readFunc = readFunc;
50     _writeFunc = writeFunc;
51 
52     _readWriteMode = readWriteMode;
53 }
54 
55 
RegisterDotOsgWrapperProxy(osg::Object * proto,const std::string & name,const std::string & associates,DotOsgWrapper::ReadFunc readFunc,DotOsgWrapper::WriteFunc writeFunc,DotOsgWrapper::ReadWriteMode readWriteMode)56 RegisterDotOsgWrapperProxy::RegisterDotOsgWrapperProxy(osg::Object* proto,
57                             const std::string& name,
58                             const std::string& associates,
59                             DotOsgWrapper::ReadFunc readFunc,
60                             DotOsgWrapper::WriteFunc writeFunc,
61                             DotOsgWrapper::ReadWriteMode readWriteMode)
62 {
63     if (Registry::instance())
64     {
65         _wrapper = new DotOsgWrapper(proto,name,associates,readFunc,writeFunc,readWriteMode);
66         Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->addDotOsgWrapper(_wrapper.get());
67     }
68 }
69 
~RegisterDotOsgWrapperProxy()70 RegisterDotOsgWrapperProxy::~RegisterDotOsgWrapperProxy()
71 {
72     if (Registry::instance())
73     {
74         Registry::instance()->getDeprecatedDotOsgObjectWrapperManager()->removeDotOsgWrapper(_wrapper.get());
75     }
76 }
77 
78 
79 
addDotOsgWrapper(DotOsgWrapper * wrapper)80 void DeprecatedDotOsgWrapperManager::addDotOsgWrapper(DotOsgWrapper* wrapper)
81 {
82     if (wrapper==0L) return;
83 
84     //OSG_INFO << "osg::Registry::addDotOsgWrapper("<<wrapper->getName()<<")"<< std::endl;
85     const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
86 
87     for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin();
88                                                   itr!=assoc.end();
89                                                   ++itr)
90     {
91         //OSG_INFO << "    ("<<*itr<<")"<< std::endl;
92     }
93 
94     const std::string& name = wrapper->getName();
95     const osg::Object* proto = wrapper->getPrototype();
96 
97     _objectWrapperMap[name] = wrapper;
98     if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper;
99 
100     if (proto)
101     {
102         std::string libraryName = proto->libraryName();
103         std::string compositeName = libraryName + "::" + name;
104 
105         _objectWrapperMap[compositeName] = wrapper;
106         if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper;
107 
108         if (dynamic_cast<const osg::Image*>(proto))
109         {
110             _imageWrapperMap[name] = wrapper;
111             _imageWrapperMap[compositeName] = wrapper;
112         }
113         if (dynamic_cast<const osg::Drawable*>(proto))
114         {
115               _drawableWrapperMap[name] = wrapper;
116               _drawableWrapperMap[compositeName] = wrapper;
117         }
118         if (dynamic_cast<const osg::StateAttribute*>(proto))
119         {
120             _stateAttrWrapperMap[name] = wrapper;
121             _stateAttrWrapperMap[compositeName] = wrapper;
122         }
123         if (dynamic_cast<const osg::Uniform*>(proto))
124         {
125             _uniformWrapperMap[name] = wrapper;
126             _uniformWrapperMap[compositeName] = wrapper;
127         }
128         if (dynamic_cast<const osg::Node*>(proto))
129         {
130             _nodeWrapperMap[name] = wrapper;
131             _nodeWrapperMap[compositeName] = wrapper;
132         }
133         if (dynamic_cast<const osg::Shader*>(proto))
134         {
135             _shaderWrapperMap[name] = wrapper;
136             _shaderWrapperMap[compositeName] = wrapper;
137         }
138 
139 
140     }
141 }
142 
143 // need to change to delete all instances of wrapper, since we
144 // now can have a wrapper entered twice with the addition of the
145 // library::class composite name.
eraseWrapper(DotOsgWrapperMap & wrappermap,DotOsgWrapper * wrapper)146 void DeprecatedDotOsgWrapperManager::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper)
147 {
148     typedef std::vector<DotOsgWrapperMap::iterator> EraseList;
149     EraseList eraseList;
150     for(DotOsgWrapperMap::iterator witr=wrappermap.begin();
151         witr!=wrappermap.end();
152         ++witr)
153     {
154         if (witr->second==wrapper) eraseList.push_back(witr);
155     }
156     for(EraseList::iterator eitr=eraseList.begin();
157         eitr!=eraseList.end();
158         ++eitr)
159     {
160         wrappermap.erase(*eitr);
161     }
162 }
163 
removeDotOsgWrapper(DotOsgWrapper * wrapper)164 void DeprecatedDotOsgWrapperManager::removeDotOsgWrapper(DotOsgWrapper* wrapper)
165 {
166     if (wrapper==0L) return;
167 
168     eraseWrapper(_objectWrapperMap,wrapper);
169     eraseWrapper(_classNameWrapperMap,wrapper);
170     eraseWrapper(_imageWrapperMap,wrapper);
171     eraseWrapper(_drawableWrapperMap,wrapper);
172     eraseWrapper(_uniformWrapperMap,wrapper);
173     eraseWrapper(_stateAttrWrapperMap,wrapper);
174     eraseWrapper(_nodeWrapperMap,wrapper);
175     eraseWrapper(_shaderWrapperMap,wrapper);
176 }
177 
178 struct concrete_wrapper: basic_type_wrapper
179 {
~concrete_wrapperconcrete_wrapper180     virtual ~concrete_wrapper() {}
concrete_wrapperconcrete_wrapper181     concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
matchesconcrete_wrapper182     bool matches(const osg::Object *proto) const
183     {
184         return myobj_->isSameKindAs(proto);
185     }
186     const osg::Object *myobj_;
187 };
188 
189 
readObjectOfType(const osg::Object & compObj,Input & fr)190 osg::Object* DeprecatedDotOsgWrapperManager::readObjectOfType(const osg::Object& compObj,Input& fr)
191 {
192     return readObjectOfType(concrete_wrapper(&compObj), fr);
193 }
194 
getLibraryFileNamesToTry(const std::string & name,FileNames & fileNames)195 bool DeprecatedDotOsgWrapperManager::getLibraryFileNamesToTry(const std::string& name, FileNames& fileNames)
196 {
197     FileNames::size_type sizeBefore = fileNames.size();
198 
199     std::string libraryName = osgDB::Registry::instance()->createLibraryNameForNodeKit(name);
200     if (!libraryName.empty()) fileNames.push_back(libraryName);
201 
202     libraryName = osgDB::Registry::instance()->createLibraryNameForExtension(std::string("deprecated_")+name);
203     if (!libraryName.empty()) fileNames.push_back(libraryName);
204 
205     libraryName = osgDB::Registry::instance()->createLibraryNameForExtension(name);
206     if (!libraryName.empty()) fileNames.push_back(libraryName);
207 
208     return fileNames.size() != sizeBefore;
209 }
210 
readObjectOfType(const basic_type_wrapper & btw,Input & fr)211 osg::Object* DeprecatedDotOsgWrapperManager::readObjectOfType(const basic_type_wrapper &btw,Input& fr)
212 {
213     const char *str = fr[0].getStr();
214     if (str==NULL) return NULL;
215 
216     if (fr[0].matchWord("Use"))
217     {
218         if (fr[1].isString())
219         {
220             osg::Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
221             if (obj && btw.matches(obj))
222             {
223                 fr+=2;
224                 return obj;
225             }
226         }
227         else return NULL;
228 
229     }
230 
231     std::string name = str;
232     DotOsgWrapperMap::iterator ow_itr = _objectWrapperMap.find(name);
233     if (ow_itr==_objectWrapperMap.end())
234     {
235         // not found so check if a library::class composite name.
236         std::string token = fr[0].getStr();
237         std::string::size_type posDoubleColon = token.rfind("::");
238         if (posDoubleColon != std::string::npos)
239         {
240             // we have a composite name so now strip off the library name
241             // are try to load it, and then retry the readObject to see
242             // if we can recognize the objects.
243             std::string libraryName = std::string(token,0,posDoubleColon);
244 
245             FileNames fileNames;
246             if (getLibraryFileNamesToTry(libraryName, fileNames))
247             {
248                 for(FileNames::iterator itr = fileNames.begin();
249                     itr != fileNames.end();
250                     ++itr)
251                 {
252                     if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return readObjectOfType(btw,fr);
253                 }
254             }
255         }
256     }
257     else if (fr[1].isOpenBracket())
258     {
259         DotOsgWrapper* wrapper = ow_itr->second.get();
260         const osg::Object* proto = wrapper->getPrototype();
261         if (proto==NULL)
262         {
263             OSG_WARN<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
264             return NULL;
265         }
266 
267         if (!btw.matches(proto))
268         {
269             return NULL;
270         }
271 
272         // record the number of nested brackets move the input iterator
273         // over the name { tokens.
274         int entry = fr[0].getNoNestedBrackets();
275         fr+=2;
276 
277         const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
278         osg::Object* obj = proto->cloneType();
279 
280         while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
281         {
282             bool iteratorAdvanced = false;
283             if (fr[0].matchWord("UniqueID") && fr[1].isString())
284             {
285                 fr.registerUniqueIDForObject(fr[1].getStr(),obj);
286                 fr += 2;
287                 iteratorAdvanced = true;
288             }
289 
290             // read the local data by iterating through the associate
291             // list, mapping the associate names to DotOsgWrapper's which
292             // in turn have the appropriate functions.
293             for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
294                                                           aitr!=assoc.end();
295                                                           ++aitr)
296             {
297                 DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
298                 if (mitr==_objectWrapperMap.end())
299                 {
300                     // not found so check if a library::class composite name.
301                     std::string token = *aitr;
302                     std::string::size_type posDoubleColon = token.rfind("::");
303                     if (posDoubleColon != std::string::npos)
304                     {
305                         // we have a composite name so now strip off the library name
306                         // and try to load it, and then retry the find to see
307                         // if we can recognize the objects.
308                         std::string libraryName = std::string(token,0,posDoubleColon);
309 
310                         FileNames fileNames;
311                         if (getLibraryFileNamesToTry(libraryName, fileNames))
312                         {
313                             for(FileNames::iterator itr = fileNames.begin();
314                                 itr != fileNames.end() && mitr==_objectWrapperMap.end();
315                                 ++itr)
316                             {
317                                 if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED)
318                                 {
319                                     mitr = _objectWrapperMap.find(*aitr);
320                                 }
321                             }
322                         }
323                     }
324                 }
325 
326                 if (mitr!=_objectWrapperMap.end())
327                 {
328                     // get the function to read the data...
329                     DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
330                     if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
331                 }
332 
333             }
334 
335             if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
336         }
337         ++fr;                        // step over trailing '}'
338 
339         return obj;
340 
341     }
342     return 0L;
343 }
344 
345 //
346 // read object from input iterator.
347 //
readObject(DotOsgWrapperMap & dowMap,Input & fr)348 osg::Object* DeprecatedDotOsgWrapperManager::readObject(DotOsgWrapperMap& dowMap,Input& fr)
349 {
350     const char *str = fr[0].getStr();
351     if (str==NULL) return NULL;
352 
353     std::string name = str;
354     DotOsgWrapperMap::iterator dow_itr = dowMap.find(name);
355     if (dow_itr==dowMap.end())
356     {
357         // not found so check if a library::class composite name.
358         std::string token = fr[0].getStr();
359         std::string::size_type posDoubleColon = token.rfind("::");
360         if (posDoubleColon != std::string::npos)
361         {
362             // we have a composite name so now strip off the library name
363             // are try to load it, and then retry the readObject to see
364             // if we can recognize the objects.
365 
366             std::string libraryName = std::string(token,0,posDoubleColon);
367 
368             FileNames fileNames;
369             if (getLibraryFileNamesToTry(libraryName, fileNames))
370             {
371                 for(FileNames::iterator itr = fileNames.begin();
372                     itr != fileNames.end();
373                     ++itr)
374                 {
375                     if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return readObject(dowMap,fr);
376                 }
377             }
378         }
379     }
380     else if (fr[1].isOpenBracket())
381     {
382 
383         DotOsgWrapper* wrapper = dow_itr->second.get();
384         const osg::Object* proto = wrapper->getPrototype();
385         if (proto==NULL)
386         {
387             OSG_WARN<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
388             return NULL;
389         }
390 
391         // record the number of nested brackets move the input iterator
392         // over the name { tokens.
393         int entry = fr[0].getNoNestedBrackets();
394         fr+=2;
395 
396         const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
397         osg::Object* obj = proto->cloneType();
398 
399         while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
400         {
401             bool iteratorAdvanced = false;
402             if (fr[0].matchWord("UniqueID") && fr[1].isString())
403             {
404                 fr.registerUniqueIDForObject(fr[1].getStr(),obj);
405                 fr += 2;
406                 iteratorAdvanced = true;
407             }
408 
409             // read the local data by iterating through the associate
410             // list, mapping the associate names to DotOsgWrapper's which
411             // in turn have the appropriate functions.
412             for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
413                                                           aitr!=assoc.end();
414                                                           ++aitr)
415             {
416                 DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
417                 if (mitr==_objectWrapperMap.end())
418                 {
419                     // not found so check if a library::class composite name.
420                     std::string token = *aitr;
421                     std::string::size_type posDoubleColon = token.rfind("::");
422                     if (posDoubleColon != std::string::npos)
423                     {
424 
425                         // we have a composite name so now strip off the library name
426                         // are try to load it, and then retry the find to see
427                         // if we can recognize the objects.
428 
429                         std::string libraryName = std::string(token,0,posDoubleColon);
430 
431                         FileNames fileNames;
432                         if (getLibraryFileNamesToTry(libraryName, fileNames))
433                         {
434                             for(FileNames::iterator itr = fileNames.begin();
435                                 itr != fileNames.end() && mitr==_objectWrapperMap.end();
436                                 ++itr)
437                             {
438                                 if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED)
439                                 {
440                                     mitr = _objectWrapperMap.find(*aitr);
441                                 }
442                             }
443                         }
444                     }
445                 }
446 
447                 if (mitr!=_objectWrapperMap.end())
448                 {
449                     // get the function to read the data...
450                     DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
451                     if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
452                 }
453 
454             }
455 
456             if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
457         }
458         ++fr;                        // step over trailing '}'
459 
460         return obj;
461 
462     }
463 
464     return 0L;
465 }
466 
467 //
468 // read object from input iterator.
469 //
readObject(Input & fr)470 osg::Object* DeprecatedDotOsgWrapperManager::readObject(Input& fr)
471 {
472     if (fr[0].matchWord("Use"))
473     {
474         if (fr[1].isString())
475         {
476             osg::Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
477             if (obj) fr+=2;
478             return obj;
479         }
480         else return NULL;
481 
482     }
483 
484     return readObject(_objectWrapperMap,fr);
485 }
486 
487 
488 //
489 // read image from input iterator.
490 //
readImage(Input & fr)491 osg::Image* DeprecatedDotOsgWrapperManager::readImage(Input& fr)
492 {
493     if (fr[0].matchWord("Use"))
494     {
495         if (fr[1].isString())
496         {
497             osg::Image* image = dynamic_cast<osg::Image*>(fr.getObjectForUniqueID(fr[1].getStr()));
498             if (image) fr+=2;
499             return image;
500         }
501         else return NULL;
502 
503     }
504 
505     osg::Object* obj = readObject(_imageWrapperMap,fr);
506     osg::Image* image = dynamic_cast<osg::Image*>(obj);
507     if (image) return image;
508     else if (obj) obj->unref();
509 
510     return NULL;
511 }
512 
513 
514 //
515 // read drawable from input iterator.
516 //
readDrawable(Input & fr)517 osg::Drawable* DeprecatedDotOsgWrapperManager::readDrawable(Input& fr)
518 {
519     if (fr[0].matchWord("Use"))
520     {
521         if (fr[1].isString())
522         {
523             osg::Drawable* drawable = dynamic_cast<osg::Drawable*>(fr.getObjectForUniqueID(fr[1].getStr()));
524             if (drawable) fr+=2;
525             return drawable;
526         }
527         else return NULL;
528 
529     }
530 
531     osg::Object* obj = readObject(_drawableWrapperMap,fr);
532     osg::Drawable* drawable = dynamic_cast<osg::Drawable*>(obj);
533     if (drawable) return drawable;
534     else if (obj) obj->unref();
535 
536     return NULL;
537 }
538 
539 //
540 // read drawable from input iterator.
541 //
readStateAttribute(Input & fr)542 osg::StateAttribute* DeprecatedDotOsgWrapperManager::readStateAttribute(Input& fr)
543 {
544 
545     if (fr[0].matchWord("Use"))
546     {
547         if (fr[1].isString())
548         {
549             osg::StateAttribute* attribute = dynamic_cast<osg::StateAttribute*>(fr.getObjectForUniqueID(fr[1].getStr()));
550             if (attribute) fr+=2;
551             return attribute;
552         }
553         else return NULL;
554 
555     }
556 
557     return dynamic_cast<osg::StateAttribute*>(readObject(_stateAttrWrapperMap,fr));
558 }
559 
560 //
561 // read drawable from input iterator.
562 //
readUniform(Input & fr)563 osg::Uniform* DeprecatedDotOsgWrapperManager::readUniform(Input& fr)
564 {
565 
566     if (fr[0].matchWord("Use"))
567     {
568         if (fr[1].isString())
569         {
570             osg::Uniform* attribute = dynamic_cast<osg::Uniform*>(fr.getObjectForUniqueID(fr[1].getStr()));
571             if (attribute) fr+=2;
572             return attribute;
573         }
574         else return NULL;
575 
576     }
577 
578     return dynamic_cast<osg::Uniform*>(readObject(_uniformWrapperMap,fr));
579 }
580 
581 //
582 // read node from input iterator.
583 //
readNode(Input & fr)584 osg::Node* DeprecatedDotOsgWrapperManager::readNode(Input& fr)
585 {
586     if (fr[0].matchWord("Use"))
587     {
588         if (fr[1].isString())
589         {
590             osg::Node* node = dynamic_cast<osg::Node*>(fr.getObjectForUniqueID(fr[1].getStr()));
591             if (node) fr+=2;
592             return node;
593         }
594         else return NULL;
595 
596     }
597 
598     osg::Object* obj = readObject(_nodeWrapperMap,fr);
599     osg::Node* node = dynamic_cast<osg::Node*>(obj);
600     if (node) return node;
601     else if (obj) obj->unref();
602 
603     return NULL;
604 }
605 
606 //
607 // read image from input iterator.
608 //
readShader(Input & fr)609 osg::Shader* DeprecatedDotOsgWrapperManager::readShader(Input& fr)
610 {
611     if (fr[0].matchWord("Use"))
612     {
613         if (fr[1].isString())
614         {
615             osg::Shader* shader = dynamic_cast<osg::Shader*>(fr.getObjectForUniqueID(fr[1].getStr()));
616             if (shader) fr+=2;
617             return shader;
618         }
619         else return NULL;
620 
621     }
622 
623     osg::Object* obj = readObject(_shaderWrapperMap,fr);
624     osg::Shader* shader = dynamic_cast<osg::Shader*>(obj);
625     if (shader) return shader;
626     else if (obj) obj->unref();
627 
628     return NULL;
629 }
630 
631 //
632 // Write object to output
633 //
writeObject(const osg::Object & obj,Output & fw)634 bool DeprecatedDotOsgWrapperManager::writeObject(const osg::Object& obj,Output& fw)
635 {
636 
637     if (obj.referenceCount()>1)
638     {
639         std::string uniqueID;
640         if (fw.getUniqueIDForObject(&obj,uniqueID))
641         {
642             fw.writeUseID( uniqueID );
643             return true;
644         }
645     }
646 
647     const std::string classname( obj.className() );
648     const std::string libraryName( obj.libraryName() );
649     const std::string compositeName( libraryName + "::" + classname );
650 
651     // try composite name first
652     DotOsgWrapperMap::iterator cnw_itr = _classNameWrapperMap.find(compositeName);
653 
654     if (cnw_itr==_classNameWrapperMap.end())
655     {
656         FileNames fileNames;
657         if (getLibraryFileNamesToTry(libraryName, fileNames))
658         {
659             for(FileNames::iterator itr = fileNames.begin();
660                 itr != fileNames.end();
661                 ++itr)
662             {
663                 if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED) return writeObject(obj,fw);
664             }
665         }
666 
667         // otherwise try simple class name
668         if (cnw_itr == _classNameWrapperMap.end())
669             cnw_itr = _classNameWrapperMap.find(classname);
670     }
671 
672     if (cnw_itr!=_classNameWrapperMap.end())
673     {
674         DotOsgWrapper* wrapper = cnw_itr->second.get();
675         const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
676 
677         if (libraryName=="osg")
678         {
679             // member of the core osg, so no need to have composite library::class name.
680             fw.writeBeginObject( wrapper->getName() );
681         }
682         else
683         {
684             // member of the node kit so must use composite library::class name.
685             std::string::size_type posDoubleColon = wrapper->getName().find("::");
686             if (posDoubleColon != std::string::npos)
687             {
688                 fw.writeBeginObject( wrapper->getName() );
689             }
690             else
691             {
692                 fw.writeBeginObject( libraryName + "::" + wrapper->getName() );
693             }
694         }
695         fw.moveIn();
696 
697 
698         // write out the unique ID if required.
699         if (obj.referenceCount()>1)
700         {
701             std::string uniqueID;
702             fw.createUniqueIDForObject(&obj,uniqueID);
703             fw.registerUniqueIDForObject(&obj,uniqueID);
704             fw.writeUniqueID( uniqueID );
705         }
706 
707         // read the local data by iterating through the associate
708         // list, mapping the associate names to DotOsgWrapper's which
709         // in turn have the appropriate functions.
710         for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
711                                                       aitr!=assoc.end();
712                                                       ++aitr)
713         {
714             DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
715             if (mitr==_objectWrapperMap.end())
716             {
717                 // not found so check if a library::class composite name.
718                 std::string token = *aitr;
719                 std::string::size_type posDoubleColon = token.rfind("::");
720                 if (posDoubleColon != std::string::npos)
721                 {
722 
723                     // we have a composite name so now strip off the library name
724                     // are try to load it, and then retry the find to see
725                     // if we can recognize the objects.
726 
727                     std::string assoc_libraryName = std::string(token,0,posDoubleColon);
728 
729                     FileNames fileNames;
730                     if (getLibraryFileNamesToTry(assoc_libraryName, fileNames))
731                     {
732                         for(FileNames::iterator itr = fileNames.begin();
733                             itr != fileNames.end() && mitr==_objectWrapperMap.end();
734                             ++itr)
735                         {
736                             if (osgDB::Registry::instance()->loadLibrary(*itr)==osgDB::Registry::LOADED)
737                             {
738                                 mitr = _objectWrapperMap.find(*aitr);
739                             }
740                         }
741                     }
742                 }
743             }
744             if (mitr!=_objectWrapperMap.end())
745             {
746                 // get the function to read the data...
747                 DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc();
748                 if (wf) (*wf)(obj,fw);
749             }
750 
751         }
752 
753         fw.moveOut();
754         fw.writeEndObject();
755 
756         return true;
757     }
758 
759     return false;
760 }
761 
762