1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //-------------------------------
41 //-------------------------------
43 #define OSG_COMPILE_SCENEFILEHANDLER
50 #include "OSGConfig.h"
53 #include "OSGBaseTypes.h"
54 #include "OSGPathHandler.h"
56 #include "OSGGraphOpSeq.h"
58 #include "OSGImageFileHandler.h"
60 #include "OSGSceneFileHandler.h"
61 #include "OSGZStream.h"
64 #include "OSGThread.h"
65 #include "OSGThreadManager.h"
66 #include "OSGBaseFunctions.h"
67 #include "OSGFileContextAttachment.h"
69 #include "OSGSingletonHolder.ins"
73 OSG_SINGLETON_INST(SceneFileHandlerBase
, addPostFactoryExitFunction
)
75 template class SingletonHolder
<SceneFileHandlerBase
>;
77 GraphOpSeq
*SceneFileHandlerBase::_defaultgraphOpSeq
= NULL
;
79 SceneFileType
*SceneFileHandlerBase::getFileType(
80 const Char8
*fileNameOrExtension
)
82 const Char8 separator
= '.';
84 if(fileNameOrExtension
== NULL
)
87 std::string fe
= fileNameOrExtension
;
89 SizeT p
= fe
.rfind(separator
);
93 if(p
!= std::string::npos
)
95 ext
= fe
.substr(p
+ 1, fe
.length() - p
- 1);
99 ext
= fe
; // extension without '.'
102 // skip .gz extension
105 fe
= fe
.substr(0, p
);
106 p
= fe
.rfind(separator
);
108 if(p
!= std::string::npos
)
110 ext
= fe
.substr(p
+ 1, fe
.length() - p
- 1);
120 suffix
.assign (ext
.c_str());
121 // suffix.toLower( );
122 std::transform(suffix
.begin(), suffix
.end(), suffix
.begin(), ::tolower
);
124 FileTypeMap::iterator sI
= _suffixTypeMap
.find(suffix
);
126 SceneFileType
*type
=
127 (sI
== _suffixTypeMap
.end()) ? 0 : sI
->second
->front();
134 #pragma warning (disable : 383)
137 Int32
SceneFileHandlerBase::getSuffixList(std::list
<const Char8
*> &suffixList
,
141 FileTypeMap::iterator sI
;
145 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); ++sI
)
147 SceneFileType
*type
= sI
->second
->front();
149 if((type
->getFlags() & flags
) == flags
)
151 suffixList
.push_back(sI
->first
.c_str());
160 #pragma warning (default : 383)
164 NodeTransitPtr
SceneFileHandlerBase::read(
166 const Char8
*fileNameOrExtension
,
167 GraphOpSeq
*graphOpSeq
,
170 SceneFileType
*type
= getFileType(fileNameOrExtension
);
171 NodeUnrecPtr scene
= NULL
;
173 if(!fileNameOrExtension
)
175 SWARNING
<< "cannot read NULL extension" << std::endl
;
176 return NodeTransitPtr(scene
);
181 SINFO
<< "try to read stream as " << type
->getName() << std::endl
;
183 // check for fileio read callback
186 initReadProgress(is
);
187 scene
= _readFP(type
, is
, fileNameOrExtension
);
188 terminateReadProgress();
194 SINFO
<< "Detected gzip compressed stream." << std::endl
;
198 initReadProgress(is
);
200 zip_istream
unzipper(is
);
202 scene
= type
->read(unzipper
,
204 resolver
? resolver
: _oGlobalResolver
);
208 if(unzipper
.check_crc() == true)
210 SINFO
<< "Compressed stream has correct checksum."
215 SWARNING
<< "Compressed stream has wrong checksum."
219 terminateReadProgress();
221 SFATAL
<< "Compressed streams are not supported! Configure "
222 << "with --enable-png --with-png=DIR options."
228 initReadProgress(is
);
230 scene
= type
->read(is
,
232 resolver
? resolver
: _oGlobalResolver
);
234 terminateReadProgress();
240 if(graphOpSeq
!= NULL
)
241 graphOpSeq
->traverse(scene
);
243 SINFO
<< "read ok:" << std::endl
;
247 SWARNING
<< "could not read " << std::endl
;
252 SWARNING
<< "could not read unknown file format" << std::endl
;
257 return NodeTransitPtr(scene
);
261 NodeTransitPtr
SceneFileHandlerBase::read(const Char8
*fileName
,
262 GraphOpSeq
*graphOpSeq
,
266 NodeTransitPtr
returnValue(NULL
);
270 SWARNING
<< "cannot read NULL file" << std::endl
;
271 return NodeTransitPtr(NULL
);
274 std::string fullFilePath
= initPathHandler(fileName
);
276 if(fullFilePath
.empty() == true)
280 // that's a fallback could be a url so the callback
281 // can handle this correctly.
282 SceneFileType
*type
= getFileType(fileName
);
285 // create a dummy stream with the bad flag set.
287 in
.setstate(std::ios::badbit
);
288 returnValue
= _readFP(type
, in
, fileName
);
292 if(bWarnNotFound
== true)
293 SWARNING
<< "Couldn't open file " << fileName
<< std::endl
;
298 if(bWarnNotFound
== true)
299 SWARNING
<< "Couldn't open file " << fileName
<< std::endl
;
308 SceneFileType
*type
= getFileType(fullFilePath
.c_str());
309 NodeUnrecPtr scene
= NULL
;
313 triggerReadBegin(fullFilePath
.c_str());
314 updateReadProgress(0);
316 SINFO
<< "try to read " << fullFilePath
317 << " as " << type
->getName() << std::endl
;
319 std::ifstream
in(fullFilePath
.c_str(), std::ios::binary
);
323 scene
= read(in
, fullFilePath
.c_str(), graphOpSeq
);
329 triggerReadEnd(fullFilePath
.c_str());
331 FileContextAttachmentUnrecPtr pFContext
=
332 dynamic_cast<FileContextAttachment
*>(
333 scene
->findAttachment(
334 FileContextAttachment::getClassGroupId()));
336 if(pFContext
== NULL
)
338 pFContext
= FileContextAttachment::create();
340 pFContext
->setResolvedName(fullFilePath
);
342 scene
->addAttachment(pFContext
);
348 if(bWarnNotFound
== true)
350 SWARNING
<< "Couldn't open input stream for file "
356 #ifndef OSG_DISABLE_DEPRECATED
358 // Ok stream interface didn't work try via filename
360 scene
= type
->readFile(fullFilePath
.c_str());
364 if(graphOpSeq
!= NULL
)
365 graphOpSeq
->run(scene
);
367 SINFO
<< "read ok:" << std::endl
;
371 if(bWarnNotFound
== true)
372 SWARNING
<< "could not read " << std::endl
;
377 if(scene
!= NULL
&& graphOpSeq
!= NULL
)
379 SINFO
<< "Running GraphOps..." << std::endl
;
380 graphOpSeq
->run(scene
);
386 if(bWarnNotFound
== true)
388 SWARNING
<< "could not read " << fullFilePath
389 << "; unknown file format" << std::endl
;
395 return NodeTransitPtr(scene
);
399 void SceneFileHandlerBase::setReadCB(FileIOReadCBF fp
)
404 SceneFileHandlerBase::FileIOReadCBF
SceneFileHandlerBase::getReadCB(void)
409 bool SceneFileHandlerBase::write(Node
* const node
,
411 Char8
const *fileNameOrExtension
,
414 bool retCode
= false;
415 SceneFileType
*type
= getFileType(fileNameOrExtension
);
419 updateWriteProgress(0);
421 SINFO
<< "try to write stream as " << type
->getName() << std::endl
;
425 retCode
= _writeFP(type
, node
, os
, fileNameOrExtension
, compress
);
432 SINFO
<< "writing compressed stream." << std::endl
;
434 zip_ostream
zipper(os
, true);
436 retCode
= type
->write(node
, zipper
, fileNameOrExtension
);
440 SFATAL
<< "Compressed streams are not supported! Build "
441 << "with zlib= options."
447 retCode
= type
->write(node
, os
, fileNameOrExtension
);
453 SWARNING
<< "can't write stream unknown scene format" << std::endl
;
459 bool SceneFileHandlerBase::write(Node
* const node
,
460 Char8
const *fileName
,
463 bool retCode
= false;
464 SceneFileType
*type
= getFileType(fileName
);
468 updateWriteProgress(0);
469 triggerWriteBegin(fileName
);
471 SINFO
<< "try to write "
477 std::ofstream
out(fileName
, std::ios::binary
);
481 retCode
= write(node
, out
, fileName
, compress
);
486 SWARNING
<< "Can not open output stream for file '"
492 #ifndef OSG_DISABLE_DEPRECATED
495 retCode
= type
->writeFile(node
, fileName
);
501 SWARNING
<< "Couldn't write " << fileName
<< std::endl
;
505 triggerWriteEnd(fileName
);
509 SWARNING
<< "can't write "
511 << "; unknown scene format"
517 void SceneFileHandlerBase::setWriteCB(FileIOWriteCBF fp
)
522 SceneFileHandlerBase::FileIOWriteCBF
SceneFileHandlerBase::getWriteCB(void)
527 PathHandler
*SceneFileHandlerBase::getPathHandler(void)
529 if(_pathHandler
== NULL
)
531 return &_defaultPathHandler
;
539 void SceneFileHandlerBase::setPathHandler(PathHandler
*pathHandler
)
541 _pathHandler
= pathHandler
;
544 SceneFileHandlerBase::Resolver
545 SceneFileHandlerBase::getGlobalResolver(void) const
547 return _oGlobalResolver
;
550 void SceneFileHandlerBase::setGlobalResolver(Resolver oResolver
)
552 _oGlobalResolver
= oResolver
;
555 std::string
SceneFileHandlerBase::initPathHandler(const Char8
*fileName
)
557 std::string fullFilePath
;
559 if(_pathHandler
!= NULL
)
561 // Set also a image path handler if not set.
563 if(ImageFileHandler::the()->getPathHandler() == NULL
)
565 ImageFileHandler::the()->setPathHandler(_pathHandler
);
568 fullFilePath
= _pathHandler
->findFile(fileName
);
572 // Set a default image path handler if not set.
573 if(ImageFileHandler::the()->getPathHandler() == NULL
)
575 ImageFileHandler::the()->setPathHandler(&_defaultPathHandler
);
578 _defaultPathHandler
.clearPathList();
579 _defaultPathHandler
.clearBaseFile();
581 _defaultPathHandler
.push_frontCurrentDir( );
583 fullFilePath
= _defaultPathHandler
.findFile(fileName
);
585 _defaultPathHandler
.setBaseFile(fullFilePath
.c_str());
591 GraphOpSeq
*SceneFileHandlerBase::getDefaultGraphOp(void)
593 return _defaultgraphOpSeq
;
596 void SceneFileHandlerBase::setDefaultGraphOp(GraphOpSeq
*graphOpSeq
)
598 setRefd(_defaultgraphOpSeq
, graphOpSeq
);
601 /*-------------------------------------------------------------------------*/
604 /*! Sets the option \a name to \a value for the SceneFileType that handles
605 files with the given \a suffix.
606 Returns \c true if the option was set successfully, \c false otherwise.
608 \param[in] suffix File extension to choose the scene file type
609 this option applies to.
610 \param[in] name Name of the option.
611 \param[in] value Value of the option.
612 \return Whether the value was set successfully.
615 SceneFileHandlerBase::setOption(
616 const std::string
&suffix
,
617 const std::string
&name
,
618 const std::string
&value
)
621 SceneFileType
*type
= getFileType(suffix
.c_str());
625 type
->setOption(name
, value
);
632 /*! Removes the option \a name from the ImageFileType that handles files
633 with the given \a suffix. If the option is not present \c false is
634 returned, \c true otherwise.
636 \param[in] suffix File extension to choose the scene file type
637 this option applies to.
638 \param[in] name Name of the option.
639 \return Whether the option was successfully removed.
642 SceneFileHandlerBase::unsetOption(
643 const std::string
&suffix
,
644 const std::string
&name
)
647 SceneFileType
*type
= getFileType(suffix
.c_str());
651 retVal
= type
->unsetOption(name
);
657 /*! Retrieves the option \a name from the SceneFileType that handles files
658 with the given \a suffix and stores its value in \a value.
659 Returns \c true if successful, \c false otherwise in which case \a value has
662 \param[in] suffix File extension to choose the scene file type
663 this option applies to.
664 \param[in] name Name of the option.
665 \param[out] value Value the option.
666 \return Whether the option is present for the given SceneFileType.
669 SceneFileHandlerBase::getOption(
670 const std::string
&suffix
,
671 const std::string
&name
,
675 SceneFileType
*type
= getFileType(suffix
.c_str());
679 retVal
= type
->getOption(name
, value
);
685 void SceneFileHandlerBase::pushOptions(const std::string
&suffix
,
688 SceneFileType
*type
= getFileType(suffix
.c_str());
692 type
->pushOptions(copyTop
);
696 void SceneFileHandlerBase::popOptions(const std::string
&suffix
)
698 SceneFileType
*type
= getFileType(suffix
.c_str());
706 #if defined(OSG_1_COMPAT)
707 void SceneFileHandlerBase::setOptions(const std::string
&suffix
,
708 const std::string
&osg1Options
)
713 void SceneFileHandlerBase::print (void )
715 FileTypeMap::iterator sI
;
717 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); sI
++)
720 SceneFileType
*type
= sI
->second
->front();
722 if((type
->getFlags() & SceneFileType::OSG_READ_SUPPORTED
) &&
723 (type
->getFlags() & SceneFileType::OSG_WRITE_SUPPORTED
))
725 rw
= "reader and writer";
729 if(type
->getFlags() & SceneFileType::OSG_READ_SUPPORTED
)
732 if(type
->getFlags() & SceneFileType::OSG_WRITE_SUPPORTED
)
736 std::cerr
<< "suffix: " << sI
->first
.c_str()
737 << ", type: " << sI
->second
->front()->getName()
743 bool SceneFileHandlerBase::FindOverride::operator() (SceneFileType
*fileTypeP
)
745 if(fileTypeP
== NULL
)
748 if(fileTypeP
->doOverride() == false)
751 if(fileTypeP
->getOverridePriority() <= uiRefPriority
)
759 #pragma warning (disable : 383)
762 bool SceneFileHandlerBase::addSceneFileType(SceneFileType
&fileType
)
764 bool retCode
= false;
766 std::list
<std::string
>::iterator sI
;
767 FileTypeMap ::iterator smI
;
771 for( sI
= fileType
.suffixList().begin();
772 sI
!= fileType
.suffixList().end();
775 suffix
.assign (sI
->c_str());
777 std::transform(suffix
.begin(), suffix
.end(), suffix
.begin(), ::tolower
);
779 smI
= _suffixTypeMap
.find(suffix
);
781 if (smI
!= _suffixTypeMap
.end())
783 if(fileType
.doOverride() == true)
785 FindOverride overrideFinder
;
786 FileTypeList::iterator lIt
;
788 overrideFinder
.uiRefPriority
= fileType
.getOverridePriority();
790 lIt
= std::find_if(_suffixTypeMap
[suffix
]->begin(),
791 _suffixTypeMap
[suffix
]->end (),
794 _suffixTypeMap
[suffix
]->insert(lIt
, &fileType
);
796 SWARNING
<< "Added an file type with suffix "
803 _suffixTypeMap
[suffix
]->push_back(&fileType
);
805 SWARNING
<< "Added an file type with suffix "
807 << " non overriding at the end of the list"
813 FileTypeList
*pTmpList
= new FileTypeList
;
815 pTmpList
->push_back(&fileType
);
817 _suffixTypeMap
[suffix
] = pTmpList
;
826 bool SceneFileHandlerBase::subSceneFileType(SceneFileType
&fileType
)
828 bool retCode
= false;
830 std::list
<std::string
>::iterator sI
;
831 FileTypeMap ::iterator smI
;
835 for( sI
= fileType
.suffixList().begin();
836 sI
!= fileType
.suffixList().end();
839 suffix
.assign(sI
->c_str());
841 std::transform(suffix
.begin(), suffix
.end(), suffix
.begin(), ::tolower
);
842 smI
= _suffixTypeMap
.find(suffix
);
844 if (smI
!= _suffixTypeMap
.end())
846 _suffixTypeMap
.erase(smI
);
854 #pragma warning (default : 383)
858 static bool initializeDefaultGraphOps(void)
860 GraphOpSeqRefPtr ops
= GraphOpSeq::create();
863 "Stripe() SharePtr(includes=Material,StateChunk)");
865 SceneFileHandlerBase
*the
= SceneFileHandler::the();
867 the
->setDefaultGraphOp(ops
);
872 static bool terminateDefaultGraphOps(void)
874 SceneFileHandlerBase
*the
= SceneFileHandler::the();
876 the
->setDefaultGraphOp(NULL
);
881 SceneFileHandlerBase::SceneFileHandlerBase(void) :
883 _readProgressFP (NULL
),
884 _readBeginFP (NULL
),
888 _useProgressThread (false ),
889 _writeProgressFP (NULL
),
890 _writeBeginFP (NULL
),
892 _pathHandler (NULL
),
893 _defaultPathHandler( ),
896 _oGlobalResolver (NULL
)
898 _progressData
.length
= 0;
899 _progressData
.is
= NULL
;
901 addPostFactoryInitFunction(initializeDefaultGraphOps
);
902 addPreFactoryExitFunction (terminateDefaultGraphOps
);
903 addPreFactoryExitFunction (terminateSceneFileTypes
);
906 // read progress stuff.
908 void SceneFileHandlerBase::setReadProgressCB(progresscbfp fp
, bool use_thread
)
912 terminateReadProgress();
916 //check if setReadProgressCB was called before with use_thread enabled.
918 if(_useProgressThread
)
919 terminateReadProgress();
922 _readProgressFP
= fp
;
923 _useProgressThread
= use_thread
;
926 SceneFileHandlerBase::progresscbfp
927 SceneFileHandlerBase::getReadProgressCB(void)
929 return _readProgressFP
;
932 void SceneFileHandlerBase::setReadBeginCB(filenamecbfp fp
)
937 SceneFileHandlerBase::filenamecbfp
SceneFileHandlerBase::getReadBeginCB(void)
942 void SceneFileHandlerBase::setReadEndCB(filenamecbfp fp
)
947 SceneFileHandlerBase::filenamecbfp
SceneFileHandlerBase::getReadEndCB(void)
952 void SceneFileHandlerBase::triggerReadBegin(const Char8
*fname
)
954 if(_readBeginFP
!= NULL
)
958 void SceneFileHandlerBase::triggerReadEnd(const Char8
*fname
)
960 if(_readEndFP
!= NULL
)
964 void SceneFileHandlerBase::initReadProgress(std::istream
&is
)
966 if(_readProgressFP
== NULL
)
969 // get length of the stream.
970 _progressData
.is
= &is
;
971 is
.seekg(0, std::ios::end
);
972 _progressData
.length
= is
.tellg();
973 is
.seekg(0, std::ios::beg
);
977 if(_useProgressThread
)
979 _progressData
.thread
= Thread::find("OSG::FileIOReadProgressThread");
981 if(_progressData
.thread
== NULL
)
983 _progressData
.thread
=
984 OSG::Thread::get("OSG::FileIOReadProgressThread", true);
987 if(_progressData
.thread
!= NULL
)
989 _progressData
.thread
->runFunction(readProgress
, 0, NULL
);
993 SWARNING
<< "Couldn't create read progress thread!" << std::endl
;
998 void SceneFileHandlerBase::terminateReadProgress(void)
1000 if(_readProgressFP
== NULL
)
1005 if(_progressData
.thread
!= NULL
)
1008 Thread::join(_progressData
.thread
);
1009 _progressData
.thread
= NULL
;
1012 _progressData
.length
= 0;
1013 _progressData
.is
= NULL
;
1016 void SceneFileHandlerBase::readProgress(void * OSG_CHECK_ARG(data
))
1018 SceneFileHandlerBase
*the
= SceneFileHandler::the();
1020 if(the
->_readProgressFP
== NULL
|| the
->_progressData
.is
== NULL
)
1025 while(p
< 100 && !the
->_readReady
)
1027 if(!the
->_progressData
.is
->eof() &&
1028 !the
->_progressData
.is
->bad())
1030 UInt64 pos
= the
->_progressData
.is
->tellg();
1031 p
= UInt32((pos
* 100) / the
->_progressData
.length
);
1040 the
->_readProgressFP(p
);
1042 if(the
->_useProgressThread
)
1052 if(the
->_useProgressThread
&& p
< 100)
1054 the
->_readProgressFP(100);
1058 void SceneFileHandlerBase::updateReadProgress(void)
1060 if(_readProgressFP
== NULL
)
1063 if(_useProgressThread
)
1069 void SceneFileHandlerBase::updateReadProgress(UInt32 p
)
1071 if(_readProgressFP
== NULL
)
1077 // write progress stuff.
1079 void SceneFileHandlerBase::setWriteProgressCB(progresscbfp fp
)
1081 _writeProgressFP
= fp
;
1084 SceneFileHandlerBase::progresscbfp
1085 SceneFileHandlerBase::getWriteProgressCB(void)
1087 return _writeProgressFP
;
1090 void SceneFileHandlerBase::setWriteBeginCB(filenamecbfp fp
)
1095 SceneFileHandlerBase::filenamecbfp
SceneFileHandlerBase::getWriteBeginCB(void)
1097 return _writeBeginFP
;
1100 void SceneFileHandlerBase::setWriteEndCB(filenamecbfp fp
)
1105 SceneFileHandlerBase::filenamecbfp
SceneFileHandlerBase::getWriteEndCB(void)
1110 void SceneFileHandlerBase::triggerWriteBegin(const Char8
*fname
)
1112 if(_writeBeginFP
!= NULL
)
1113 _writeBeginFP(fname
);
1116 void SceneFileHandlerBase::triggerWriteEnd(const Char8
*fname
)
1118 if(_writeEndFP
!= NULL
)
1122 void SceneFileHandlerBase::updateWriteProgress(UInt32 p
)
1124 if(_writeProgressFP
== NULL
)
1127 _writeProgressFP(p
);
1130 SceneFileHandlerBase::~SceneFileHandlerBase(void)
1132 FileTypeMap::iterator smIt
= _suffixTypeMap
.begin();
1133 FileTypeMap::iterator smEnd
= _suffixTypeMap
.end ();
1135 while(smIt
!= smEnd
)
1137 delete (*smIt
).second
;
1141 _suffixTypeMap
.clear();
1144 bool SceneFileHandlerBase::doTerminateSceneFileTypes(void)
1146 FileTypeMap ::iterator sI
;
1147 FileTypeList::iterator lI
;
1149 for(sI
= _suffixTypeMap
.begin(); sI
!= _suffixTypeMap
.end(); ++sI
)
1151 for(lI
= sI
->second
->begin(); lI
!= sI
->second
->end(); ++lI
)
1160 bool SceneFileHandlerBase::terminateSceneFileTypes(void)
1162 return SceneFileHandler::the()->doTerminateSceneFileTypes();