From Wang Rui, "I've initially added the XML support of the new native osg format,
using osgDB::XmlParser. The extension for XML-formatted scenes is .osgx, corresponding to .osgb for binary and .osgt for ascii. It could either be rendered in osgviewer or edited by common web browsers and xml editors because of a range of changes to fit the XML syntax. For example, the recorded class names are slight modified, from 'osg::Geode' to 'osg--Geode'. To quickly get an XML file: # ./osgconv cow.osg cow.osgx The StreamOperator header, InputStreram and OutputStream classes are modified to be more portable for triple ascii/binary/XML formats. I also fixed a bug in readImage()/writeImage() to share image objects if needed. The ReaderWriterOSG2 class now supports all three formats and reading/writing scene objects (not nodes or images), thanks to Torben's advice before. "
This commit is contained in:
parent
ce19b37981
commit
e082b01f26
@ -61,7 +61,8 @@ public:
|
||||
{
|
||||
READ_UNKNOWN = 0,
|
||||
READ_SCENE,
|
||||
READ_IMAGE
|
||||
READ_IMAGE,
|
||||
READ_OBJECT
|
||||
};
|
||||
|
||||
InputStream( const osgDB::Options* options );
|
||||
@ -123,9 +124,9 @@ public:
|
||||
{ ptr = static_cast<T*>(readObject()); return *this; }
|
||||
|
||||
// Convenient methods for reading
|
||||
bool matchString( const std::string& str );
|
||||
void advanceToCurrentEndBracket();
|
||||
void readWrappedString( std::string& str );
|
||||
bool matchString( const std::string& str ) { return _in->matchString(str); }
|
||||
void advanceToCurrentEndBracket() { _in->advanceToCurrentEndBracket(); }
|
||||
void readWrappedString( std::string& str ) { _in->readWrappedString(str); checkStream(); }
|
||||
void readCharArray( char* s, unsigned int size ) { _in->readCharArray(s, size); }
|
||||
|
||||
// readSize() use unsigned int for all sizes.
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
{
|
||||
WRITE_UNKNOWN = 0,
|
||||
WRITE_SCENE,
|
||||
WRITE_IMAGE
|
||||
WRITE_IMAGE,
|
||||
WRITE_OBJECT
|
||||
};
|
||||
|
||||
enum WriteImageHint
|
||||
@ -133,7 +134,7 @@ public:
|
||||
{ writeObject(ptr.get()); return *this; }
|
||||
|
||||
// Convenient methods for writing
|
||||
void writeWrappedString( const std::string& str );
|
||||
void writeWrappedString( const std::string& str ) { _out->writeWrappedString(str); }
|
||||
void writeCharArray( const char* s, unsigned int size ) { _out->writeCharArray(s, size); }
|
||||
|
||||
// method for converting all data structure sizes to unsigned int to ensure architecture portability.
|
||||
|
@ -39,6 +39,9 @@ public:
|
||||
virtual void writeProperty( const ObjectProperty& prop ) = 0;
|
||||
virtual void writeMark( const ObjectMark& mark ) = 0;
|
||||
virtual void writeCharArray( const char* s, unsigned int size ) = 0;
|
||||
virtual void writeWrappedString( const std::string& str ) = 0;
|
||||
|
||||
virtual void flush() { _out->flush(); }
|
||||
|
||||
protected:
|
||||
std::ostream* _out;
|
||||
@ -79,6 +82,10 @@ public:
|
||||
virtual void readProperty( ObjectProperty& prop ) = 0;
|
||||
virtual void readMark( ObjectMark& mark ) = 0;
|
||||
virtual void readCharArray( char* s, unsigned int size ) = 0;
|
||||
virtual void readWrappedString( std::string& str ) = 0;
|
||||
|
||||
virtual bool matchString( const std::string& str ) { return false; }
|
||||
virtual void advanceToCurrentEndBracket() {}
|
||||
|
||||
protected:
|
||||
std::istream* _in;
|
||||
|
@ -161,77 +161,6 @@ InputStream& InputStream::operator>>( osg::Matrixd& mat )
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool InputStream::matchString( const std::string& str )
|
||||
{
|
||||
if ( !isBinary() )
|
||||
{
|
||||
std::string s; *this >> s;
|
||||
if ( s==str ) return true;
|
||||
else _in->getStream()->seekg( -(int)(s.length()), std::ios::cur );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputStream::advanceToCurrentEndBracket()
|
||||
{
|
||||
if ( isBinary() )
|
||||
return;
|
||||
|
||||
std::string passString;
|
||||
unsigned int blocks = 0;
|
||||
while ( !_in->getStream()->eof() )
|
||||
{
|
||||
passString.clear();
|
||||
*this >> passString;
|
||||
|
||||
if ( passString=="}" )
|
||||
{
|
||||
if ( blocks<=0 ) return;
|
||||
else blocks--;
|
||||
}
|
||||
else if ( passString=="{" )
|
||||
blocks++;
|
||||
}
|
||||
}
|
||||
|
||||
void InputStream::readWrappedString( std::string& str )
|
||||
{
|
||||
*this >> str;
|
||||
if ( !isBinary() )
|
||||
{
|
||||
if ( str[0]=='\"' )
|
||||
{
|
||||
if ( str.size()==1 || (*str.rbegin())!='\"' )
|
||||
{
|
||||
char ch;
|
||||
do
|
||||
{
|
||||
_in->getStream()->get( ch ); checkStream();
|
||||
if ( ch=='\\' )
|
||||
{
|
||||
_in->getStream()->get( ch ); checkStream();
|
||||
if ( ch=='\"' )
|
||||
{
|
||||
str += ch; ch = 0;
|
||||
}
|
||||
else if ( ch=='\\' )
|
||||
{
|
||||
str += ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += '\\'; str += ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
str += ch;
|
||||
} while ( ch!='\"' );
|
||||
}
|
||||
str = str.substr(1, str.size()-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osg::Array* InputStream::readArray()
|
||||
{
|
||||
osg::ref_ptr<osg::Array> array = NULL;
|
||||
@ -486,6 +415,17 @@ osg::PrimitiveSet* InputStream::readPrimitiveSet()
|
||||
|
||||
osg::Image* InputStream::readImage()
|
||||
{
|
||||
unsigned int id = 0;
|
||||
*this >> PROPERTY("ImageID") >> id;
|
||||
if ( getException() ) return NULL;
|
||||
|
||||
IdentifierMap::iterator itr = _identifierMap.find( id );
|
||||
if ( itr!=_identifierMap.end() )
|
||||
{
|
||||
advanceToCurrentEndBracket();
|
||||
return static_cast<osg::Image*>( itr->second.get() );
|
||||
}
|
||||
|
||||
std::string name;
|
||||
int writeHint, decision = IMAGE_EXTERNAL;
|
||||
*this >> PROPERTY("FileName"); readWrappedString(name);
|
||||
@ -693,6 +633,7 @@ InputStream::ReadType InputStream::start( InputIterator* inIterator )
|
||||
std::string typeString; *this >> typeString;
|
||||
if ( typeString=="Scene" ) type = READ_SCENE;
|
||||
else if ( typeString=="Image" ) type = READ_IMAGE;
|
||||
else if ( typeString=="Object" ) type = READ_OBJECT;
|
||||
|
||||
std::string osgName, osgVersion;
|
||||
*this >> PROPERTY("#Version") >> version;
|
||||
@ -712,12 +653,16 @@ InputStream::ReadType InputStream::start( InputIterator* inIterator )
|
||||
|
||||
void InputStream::decompress()
|
||||
{
|
||||
if ( !isBinary() ) return;
|
||||
_fields.clear();
|
||||
_fields.push_back( "Decompression" );
|
||||
if ( !isBinary() ) return;
|
||||
|
||||
std::string compressorName; *this >> compressorName;
|
||||
if ( compressorName=="0" ) return;
|
||||
if ( compressorName=="0" )
|
||||
{
|
||||
_fields.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(compressorName);
|
||||
if ( !compressor )
|
||||
@ -773,7 +718,7 @@ void InputStream::readArrayImplementation( T* a, int read_size, bool useByteSwap
|
||||
a->resize( size );
|
||||
if ( isBinary() )
|
||||
{
|
||||
_in->getStream()->read( (char*)&((*a)[0]), read_size*size ); checkStream();
|
||||
readCharArray( (char*)&((*a)[0]), read_size*size ); checkStream();
|
||||
if ( useByteSwap && _byteSwap )
|
||||
{
|
||||
for ( int i=0; i<size; ++i )
|
||||
|
@ -132,28 +132,6 @@ OutputStream& OutputStream::operator<<( const osg::Matrixd& mat )
|
||||
return *this;
|
||||
}
|
||||
|
||||
void OutputStream::writeWrappedString( const std::string& str )
|
||||
{
|
||||
if ( !isBinary() )
|
||||
{
|
||||
std::string wrappedStr;
|
||||
unsigned int size = str.size();
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
char ch = str[i];
|
||||
if ( ch=='\"' ) wrappedStr += '\\';
|
||||
else if ( ch=='\\' ) wrappedStr += '\\';
|
||||
wrappedStr += ch;
|
||||
}
|
||||
|
||||
wrappedStr.insert( 0, 1, '\"' );
|
||||
wrappedStr += '\"';
|
||||
*this << wrappedStr;
|
||||
}
|
||||
else
|
||||
*this << str;
|
||||
}
|
||||
|
||||
void OutputStream::writeArray( const osg::Array* a )
|
||||
{
|
||||
if ( !a ) return;
|
||||
@ -312,6 +290,10 @@ void OutputStream::writeImage( const osg::Image* img )
|
||||
{
|
||||
if ( !img ) return;
|
||||
|
||||
unsigned int id = findOrCreateObjectID( img );
|
||||
*this << PROPERTY("ImageID") << id << std::endl; // Write image ID
|
||||
if ( getException() ) return;
|
||||
|
||||
*this << PROPERTY("FileName"); writeWrappedString(img->getFileName()); *this << std::endl;
|
||||
*this << PROPERTY("WriteHint") << (int)img->getWriteHint();
|
||||
if ( getException() ) return;
|
||||
@ -487,7 +469,7 @@ void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType t
|
||||
else
|
||||
{
|
||||
*this << _compressorName;
|
||||
_out->getStream()->flush();
|
||||
_out->flush();
|
||||
_out->setStream( &_compressSource );
|
||||
return;
|
||||
}
|
||||
@ -501,6 +483,7 @@ void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType t
|
||||
{
|
||||
case WRITE_SCENE: typeString = "Scene"; break;
|
||||
case WRITE_IMAGE: typeString = "Image"; break;
|
||||
case WRITE_OBJECT: typeString = "Object"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -515,12 +498,16 @@ void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType t
|
||||
|
||||
void OutputStream::compress( std::ostream* ostream )
|
||||
{
|
||||
if ( _compressorName.empty() || !isBinary() ) return;
|
||||
_fields.clear();
|
||||
_fields.push_back( "Compression" );
|
||||
if ( _compressorName.empty() || !isBinary() ) return;
|
||||
|
||||
BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName);
|
||||
if ( !compressor || !ostream ) return;
|
||||
if ( !compressor || !ostream )
|
||||
{
|
||||
_fields.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !compressor->compress(*ostream, _compressSource.str()) )
|
||||
throwException( "OutputStream: Failed to compress stream." );
|
||||
|
@ -100,6 +100,23 @@ public:
|
||||
|
||||
virtual void writeCharArray( const char* s, unsigned int size ) {}
|
||||
|
||||
virtual void writeWrappedString( const std::string& str )
|
||||
{
|
||||
std::string wrappedStr;
|
||||
unsigned int size = str.size();
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
char ch = str[i];
|
||||
if ( ch=='\"' ) wrappedStr += '\\';
|
||||
else if ( ch=='\\' ) wrappedStr += '\\';
|
||||
wrappedStr += ch;
|
||||
}
|
||||
|
||||
wrappedStr.insert( 0, 1, '\"' );
|
||||
wrappedStr += '\"';
|
||||
writeString( wrappedStr );
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _readyForEndBracket;
|
||||
int _indent;
|
||||
@ -212,6 +229,68 @@ public:
|
||||
}
|
||||
|
||||
virtual void readCharArray( char* s, unsigned int size ) {}
|
||||
|
||||
virtual void readWrappedString( std::string& str )
|
||||
{
|
||||
readString( str );
|
||||
if ( str[0]=='\"' )
|
||||
{
|
||||
if ( str.size()==1 || (*str.rbegin())!='\"' )
|
||||
{
|
||||
char ch;
|
||||
do
|
||||
{
|
||||
_in->get( ch ); checkStream();
|
||||
if ( ch=='\\' )
|
||||
{
|
||||
_in->get( ch ); checkStream();
|
||||
if ( ch=='\"' )
|
||||
{
|
||||
str += ch; ch = 0;
|
||||
}
|
||||
else if ( ch=='\\' )
|
||||
{
|
||||
str += ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += '\\'; str += ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
str += ch;
|
||||
} while ( ch!='\"' );
|
||||
}
|
||||
str = str.substr(1, str.size()-2);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool matchString( const std::string& str )
|
||||
{
|
||||
std::string s; readString(s);
|
||||
if ( s==str ) return true;
|
||||
else _in->seekg( -(int)(s.length()), std::ios::cur );
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void advanceToCurrentEndBracket()
|
||||
{
|
||||
std::string passString;
|
||||
unsigned int blocks = 0;
|
||||
while ( !_in->eof() )
|
||||
{
|
||||
passString.clear();
|
||||
readString( passString );
|
||||
|
||||
if ( passString=="}" )
|
||||
{
|
||||
if ( blocks<=0 ) return;
|
||||
else blocks--;
|
||||
}
|
||||
else if ( passString=="{" )
|
||||
blocks++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -65,6 +65,9 @@ public:
|
||||
|
||||
virtual void writeCharArray( const char* s, unsigned int size )
|
||||
{ if ( size>0 ) _out->write( s, size ); }
|
||||
|
||||
virtual void writeWrappedString( const std::string& str )
|
||||
{ writeString( str ); }
|
||||
};
|
||||
|
||||
class BinaryInputIterator : public osgDB::InputIterator
|
||||
@ -177,6 +180,9 @@ public:
|
||||
virtual void readCharArray( char* s, unsigned int size )
|
||||
{ if ( size>0 ) _in->read( s, size ); }
|
||||
|
||||
virtual void readWrappedString( std::string& str )
|
||||
{ readString( str ); }
|
||||
|
||||
protected:
|
||||
int _byteSwap;
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <osgDB/ObjectWrapper>
|
||||
#include "AsciiStreamOperator.h"
|
||||
#include "BinaryStreamOperator.h"
|
||||
#include "XmlStreamOperator.h"
|
||||
|
||||
using namespace osgDB;
|
||||
|
||||
@ -26,11 +27,15 @@ using namespace osgDB;
|
||||
|
||||
InputIterator* readInputIterator( std::istream& fin, const Options* options )
|
||||
{
|
||||
bool extensionIsAscii = false;
|
||||
if ( options && options->getOptionString().find("Ascii")!=std::string::npos )
|
||||
extensionIsAscii = true;
|
||||
bool extensionIsAscii = false, extensionIsXML = false;
|
||||
if ( options )
|
||||
{
|
||||
const std::string& optionString = options->getOptionString();
|
||||
if ( optionString.find("Ascii")!=std::string::npos ) extensionIsAscii = true;
|
||||
else if ( optionString.find("XML")!=std::string::npos ) extensionIsXML = true;
|
||||
}
|
||||
|
||||
if ( !extensionIsAscii )
|
||||
if ( !extensionIsAscii && !extensionIsXML )
|
||||
{
|
||||
unsigned int headerLow = 0, headerHigh = 0;
|
||||
fin.read( (char*)&headerLow, INT_SIZE );
|
||||
@ -42,10 +47,24 @@ InputIterator* readInputIterator( std::istream& fin, const Options* options )
|
||||
fin.seekg( 0, std::ios::beg );
|
||||
}
|
||||
|
||||
std::string header; fin >> header;
|
||||
if ( header=="#Ascii" )
|
||||
if ( !extensionIsXML )
|
||||
{
|
||||
return new AsciiInputIterator(&fin);
|
||||
std::string header; fin >> header;
|
||||
if ( header=="#Ascii" )
|
||||
{
|
||||
return new AsciiInputIterator(&fin);
|
||||
}
|
||||
fin.seekg( 0, std::ios::beg );
|
||||
}
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
std::string header; std::getline( fin, header );
|
||||
if ( !header.compare(0, 5, "<?xml") )
|
||||
{
|
||||
return new XmlInputIterator(&fin);
|
||||
}
|
||||
fin.seekg( 0, std::ios::beg );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -57,6 +76,11 @@ OutputIterator* writeInputIterator( std::ostream& fout, const Options* options )
|
||||
fout << std::string("#Ascii") << ' ';
|
||||
return new AsciiOutputIterator(&fout);
|
||||
}
|
||||
else if ( options && options->getOptionString().find("XML")!=std::string::npos )
|
||||
{
|
||||
fout << std::string("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>") << std::endl;
|
||||
return new XmlOutputIterator(&fout);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int low = OSG_HEADER_LOW, high = OSG_HEADER_HIGH;
|
||||
@ -74,8 +98,10 @@ public:
|
||||
supportsExtension( "osg2", "OpenSceneGraph extendable format" );
|
||||
supportsExtension( "osgt", "OpenSceneGraph extendable ascii format" );
|
||||
supportsExtension( "osgb", "OpenSceneGraph extendable binary format" );
|
||||
supportsExtension( "osgx", "OpenSceneGraph extendable XML format" );
|
||||
|
||||
supportsOption( "Ascii", "Import/Export option: Force reading/writing ascii file" );
|
||||
supportsOption( "XML", "Import/Export option: Force reading/writing XML file" );
|
||||
supportsOption( "ForceReadingImage", "Import option: Load an empty image instead if required file missed" );
|
||||
supportsOption( "SchemaFile=<file>", "Import/Export option: Use/Record a ascii schema file" );
|
||||
supportsOption( "Compressor=<name>", "Export option: Use an inbuilt or user-defined compressor" );
|
||||
@ -99,26 +125,58 @@ public:
|
||||
virtual const char* className() const
|
||||
{ return "OpenSceneGraph Native Format Reader/Writer"; }
|
||||
|
||||
virtual ReadResult readObject( const std::string& file, const Options* options ) const
|
||||
{ return readNode(file, options); }
|
||||
|
||||
virtual ReadResult readObject( std::istream& fin, const Options* options ) const
|
||||
{ return readNode(fin, options); }
|
||||
|
||||
virtual ReadResult readImage( const std::string& file, const Options* options ) const
|
||||
Options* prepareReading( ReadResult& result, std::string& fileName, const Options* options ) const
|
||||
{
|
||||
std::string ext = osgDB::getLowerCaseFileExtension( file );
|
||||
if ( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;
|
||||
std::string fileName = osgDB::findDataFile( file, options );
|
||||
if ( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;
|
||||
std::string ext = osgDB::getLowerCaseFileExtension( fileName );
|
||||
if ( !acceptsExtension(ext) ) result = ReadResult::FILE_NOT_HANDLED;
|
||||
fileName = osgDB::findDataFile( fileName, options );
|
||||
if ( fileName.empty() ) result = ReadResult::FILE_NOT_FOUND;
|
||||
|
||||
osg::ref_ptr<Options> local_opt = options ?
|
||||
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
||||
if ( ext=="osgt" ) local_opt->setOptionString( local_opt->getOptionString() + " Ascii" );
|
||||
if ( ext=="osgx" ) local_opt->setOptionString( local_opt->getOptionString() + " XML" );
|
||||
|
||||
return local_opt.release();
|
||||
}
|
||||
|
||||
virtual ReadResult readObject( const std::string& file, const Options* options ) const
|
||||
{
|
||||
ReadResult result = ReadResult::FILE_LOADED;
|
||||
std::string fileName = file;
|
||||
Options* local_opt = prepareReading( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ifstream istream( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
return readImage( istream, local_opt.get() );
|
||||
return readObject( istream, local_opt );
|
||||
}
|
||||
|
||||
virtual ReadResult readObject( std::istream& fin, const Options* options ) const
|
||||
{
|
||||
osg::ref_ptr<InputIterator> ii = readInputIterator(fin, options);
|
||||
if ( !ii ) return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
InputStream is( options );
|
||||
if ( is.start(ii.get())!=InputStream::READ_OBJECT )
|
||||
{
|
||||
CATCH_EXCEPTION(is);
|
||||
return ReadResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
is.decompress(); CATCH_EXCEPTION(is);
|
||||
osg::Object* obj = is.readObject(); CATCH_EXCEPTION(is);
|
||||
return obj;
|
||||
}
|
||||
|
||||
virtual ReadResult readImage( const std::string& file, const Options* options ) const
|
||||
{
|
||||
ReadResult result = ReadResult::FILE_LOADED;
|
||||
std::string fileName = file;
|
||||
Options* local_opt = prepareReading( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ifstream istream( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
return readImage( istream, local_opt );
|
||||
}
|
||||
|
||||
virtual ReadResult readImage( std::istream& fin, const Options* options ) const
|
||||
@ -139,18 +197,13 @@ public:
|
||||
|
||||
virtual ReadResult readNode( const std::string& file, const Options* options ) const
|
||||
{
|
||||
std::string ext = osgDB::getLowerCaseFileExtension( file );
|
||||
if ( !acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;
|
||||
std::string fileName = osgDB::findDataFile( file, options );
|
||||
if ( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;
|
||||
|
||||
osg::ref_ptr<Options> local_opt = options ?
|
||||
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
||||
if ( ext=="osgt" ) local_opt->setOptionString( local_opt->getOptionString() + " Ascii" );
|
||||
ReadResult result = ReadResult::FILE_LOADED;
|
||||
std::string fileName = file;
|
||||
Options* local_opt = prepareReading( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ifstream istream( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
return readNode( istream, local_opt.get() );
|
||||
return readNode( istream, local_opt );
|
||||
}
|
||||
|
||||
virtual ReadResult readNode( std::istream& fin, const Options* options ) const
|
||||
@ -170,41 +223,65 @@ public:
|
||||
return node;
|
||||
}
|
||||
|
||||
virtual WriteResult writeObject( const osg::Object& object, const std::string& fileName, const Options* options ) const
|
||||
{
|
||||
const osg::Node* node = dynamic_cast<const osg::Node*>( &object );
|
||||
if ( node ) return writeNode( *node, fileName, options );
|
||||
|
||||
const osg::Image* image = dynamic_cast<const osg::Image*>( &object );
|
||||
if ( image ) return writeImage( *image, fileName, options );
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
virtual WriteResult writeObject( const osg::Object& object, std::ostream& fout, const Options* options ) const
|
||||
{
|
||||
const osg::Node* node = dynamic_cast<const osg::Node*>( &object );
|
||||
if ( node ) return writeNode( *node, fout, options );
|
||||
|
||||
const osg::Image* image = dynamic_cast<const osg::Image*>( &object );
|
||||
if ( image ) return writeImage( *image, fout, options );
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage( const osg::Image& image, const std::string& fileName, const Options* options ) const
|
||||
Options* prepareWriting( WriteResult& result, const std::string& fileName, const Options* options ) const
|
||||
{
|
||||
std::string ext = osgDB::getFileExtension( fileName );
|
||||
if ( !acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;
|
||||
if ( !acceptsExtension(ext) ) result = WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
osg::ref_ptr<Options> local_opt = options ?
|
||||
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
if( local_opt->getDatabasePathList().empty() )
|
||||
local_opt->setDatabasePath( osgDB::getFilePath(fileName) );
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
||||
if ( ext=="osgt" ) local_opt->setOptionString( local_opt->getOptionString() + " Ascii" );
|
||||
if ( ext=="osgx" ) local_opt->setOptionString( local_opt->getOptionString() + " XML" );
|
||||
|
||||
return local_opt.release();
|
||||
}
|
||||
|
||||
virtual WriteResult writeObject( const osg::Object& object, const std::string& fileName, const Options* options ) const
|
||||
{
|
||||
WriteResult result = WriteResult::FILE_SAVED;
|
||||
Options* local_opt = prepareWriting( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ofstream fout( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
|
||||
WriteResult result = writeImage( image, fout, local_opt.get() );
|
||||
result = writeObject( object, fout, local_opt );
|
||||
fout.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual WriteResult writeObject( const osg::Object& object, std::ostream& fout, const Options* options ) const
|
||||
{
|
||||
osg::ref_ptr<OutputIterator> oi = writeInputIterator(fout, options);
|
||||
|
||||
OutputStream os( options );
|
||||
os.start( oi.get(), OutputStream::WRITE_OBJECT ); CATCH_EXCEPTION(os);
|
||||
os.writeObject( &object ); CATCH_EXCEPTION(os);
|
||||
os.compress( &fout ); CATCH_EXCEPTION(os);
|
||||
|
||||
oi->flush();
|
||||
if ( !os.getSchemaName().empty() )
|
||||
{
|
||||
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
||||
if ( !schemaStream.fail() ) os.writeSchema( schemaStream );
|
||||
schemaStream.close();
|
||||
}
|
||||
|
||||
if ( fout.fail() ) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
return WriteResult::FILE_SAVED;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage( const osg::Image& image, const std::string& fileName, const Options* options ) const
|
||||
{
|
||||
WriteResult result = WriteResult::FILE_SAVED;
|
||||
Options* local_opt = prepareWriting( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ofstream fout( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
|
||||
result = writeImage( image, fout, local_opt );
|
||||
fout.close();
|
||||
return result;
|
||||
}
|
||||
@ -218,6 +295,7 @@ public:
|
||||
os.writeImage( &image ); CATCH_EXCEPTION(os);
|
||||
os.compress( &fout ); CATCH_EXCEPTION(os);
|
||||
|
||||
oi->flush();
|
||||
if ( !os.getSchemaName().empty() )
|
||||
{
|
||||
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
||||
@ -231,19 +309,14 @@ public:
|
||||
|
||||
virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
|
||||
{
|
||||
std::string ext = osgDB::getFileExtension( fileName );
|
||||
if ( !acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
osg::ref_ptr<Options> local_opt = options ?
|
||||
static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
if ( local_opt->getDatabasePathList().empty() )
|
||||
local_opt->setDatabasePath( osgDB::getFilePath(fileName) );
|
||||
if ( ext=="osgt" ) local_opt->setOptionString( local_opt->getOptionString() + " Ascii" );
|
||||
WriteResult result = WriteResult::FILE_SAVED;
|
||||
Options* local_opt = prepareWriting( result, fileName, options );
|
||||
if ( !result.success() ) return result;
|
||||
|
||||
osgDB::ofstream fout( fileName.c_str(), std::ios::out|std::ios::binary );
|
||||
if ( !fout ) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
|
||||
WriteResult result = writeNode( node, fout, local_opt.get() );
|
||||
result = writeNode( node, fout, local_opt );
|
||||
fout.close();
|
||||
return result;
|
||||
}
|
||||
@ -257,6 +330,7 @@ public:
|
||||
os.writeObject( &node ); CATCH_EXCEPTION(os);
|
||||
os.compress( &fout ); CATCH_EXCEPTION(os);
|
||||
|
||||
oi->flush();
|
||||
if ( !os.getSchemaName().empty() )
|
||||
{
|
||||
osgDB::ofstream schemaStream( os.getSchemaName().c_str(), std::ios::out );
|
||||
|
510
src/osgPlugins/osg/XmlStreamOperator.h
Normal file
510
src/osgPlugins/osg/XmlStreamOperator.h
Normal file
@ -0,0 +1,510 @@
|
||||
#ifndef OSGDB_XMLSTREAMOPERATOR
|
||||
#define OSGDB_XMLSTREAMOPERATOR
|
||||
|
||||
#include <osgDB/StreamOperator>
|
||||
#include <osgDB/XmlParser>
|
||||
#include <sstream>
|
||||
|
||||
class XmlOutputIterator : public osgDB::OutputIterator
|
||||
{
|
||||
public:
|
||||
enum ReadLineType
|
||||
{
|
||||
FIRST_LINE=0, // The first line of file
|
||||
NEW_LINE, // A new line without checking its type
|
||||
PROP_LINE, // A line starting with osgDB::PROPERTY
|
||||
SUB_PROP_LINE, // A property line containing another osgDB::PROPERTY
|
||||
BEGIN_BRACKET_LINE, // A line ending with a '{'
|
||||
END_BRACKET_LINE, // A line starting with a '}'
|
||||
TEXT_LINE // A text line, e.g. recording array elements
|
||||
};
|
||||
|
||||
XmlOutputIterator( std::ostream* ostream )
|
||||
: _readLineType(FIRST_LINE), _prevReadLineType(FIRST_LINE), _hasSubProperty(false)
|
||||
{
|
||||
_out = ostream;
|
||||
_root = new osgDB::XmlNode;
|
||||
_root->type = osgDB::XmlNode::GROUP;
|
||||
}
|
||||
|
||||
virtual ~XmlOutputIterator() {}
|
||||
|
||||
virtual bool isBinary() const { return false; }
|
||||
|
||||
virtual void writeBool( bool b )
|
||||
{ addToCurrentNode( b ? std::string("TRUE") : std::string("FALSE") ); }
|
||||
|
||||
virtual void writeChar( char c )
|
||||
{ _sstream << c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeUChar( unsigned char c )
|
||||
{ _sstream << c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeShort( short s )
|
||||
{ _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeUShort( unsigned short s )
|
||||
{ _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeInt( int i )
|
||||
{ _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeUInt( unsigned int i )
|
||||
{ _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeLong( long l )
|
||||
{ _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeULong( unsigned long l )
|
||||
{ _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeFloat( float f )
|
||||
{ _sstream << f; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeDouble( double d )
|
||||
{ _sstream << d; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
|
||||
|
||||
virtual void writeString( const std::string& s )
|
||||
{ addToCurrentNode( s, true ); }
|
||||
|
||||
virtual void writeStream( std::ostream& (*fn)(std::ostream&) )
|
||||
{
|
||||
if ( fn==static_cast<std::ostream& (*)(std::ostream&)>(std::endl) )
|
||||
{
|
||||
if ( _readLineType==PROP_LINE || _readLineType==END_BRACKET_LINE )
|
||||
{
|
||||
if ( _hasSubProperty )
|
||||
{
|
||||
_hasSubProperty = false;
|
||||
popNode(); // Exit the sub-property element
|
||||
}
|
||||
popNode(); // Exit the property element
|
||||
}
|
||||
else if ( _readLineType==SUB_PROP_LINE )
|
||||
{
|
||||
_hasSubProperty = false;
|
||||
popNode(); // Exit the sub-property element
|
||||
popNode(); // Exit the property element
|
||||
}
|
||||
else if ( _readLineType==TEXT_LINE )
|
||||
addToCurrentNode( fn );
|
||||
|
||||
setLineType( NEW_LINE );
|
||||
}
|
||||
else
|
||||
addToCurrentNode( fn );
|
||||
}
|
||||
|
||||
virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) )
|
||||
{
|
||||
_sstream << fn;
|
||||
}
|
||||
|
||||
virtual void writeGLenum( const osgDB::ObjectGLenum& value )
|
||||
{
|
||||
GLenum e = value.get();
|
||||
const std::string& enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString("GL", e);
|
||||
addToCurrentNode( enumString, true );
|
||||
}
|
||||
|
||||
virtual void writeProperty( const osgDB::ObjectProperty& prop )
|
||||
{
|
||||
std::string enumString = prop._name;
|
||||
if ( prop._mapProperty )
|
||||
{
|
||||
enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString(prop._name, prop._value);
|
||||
addToCurrentNode( enumString, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _readLineType==NEW_LINE || _readLineType==BEGIN_BRACKET_LINE )
|
||||
{
|
||||
pushNode( enumString );
|
||||
setLineType( PROP_LINE );
|
||||
}
|
||||
else if ( _readLineType==PROP_LINE )
|
||||
{
|
||||
pushNode( enumString );
|
||||
setLineType( SUB_PROP_LINE );
|
||||
_hasSubProperty = true;
|
||||
}
|
||||
else if ( _readLineType==SUB_PROP_LINE )
|
||||
{
|
||||
popNode();
|
||||
pushNode( enumString );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void writeMark( const osgDB::ObjectMark& mark )
|
||||
{
|
||||
int delta = mark._indentDelta;
|
||||
if ( delta>0 )
|
||||
{
|
||||
setLineType( BEGIN_BRACKET_LINE );
|
||||
}
|
||||
else if ( delta<0 )
|
||||
{
|
||||
setLineType( END_BRACKET_LINE );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void writeCharArray( const char* s, unsigned int size ) {}
|
||||
|
||||
virtual void writeWrappedString( const std::string& str )
|
||||
{
|
||||
std::string realStr;
|
||||
for ( std::string::const_iterator itr=str.begin(); itr!=str.end(); ++itr )
|
||||
{
|
||||
if ( *itr=='\"' )
|
||||
realStr += "''";
|
||||
else
|
||||
realStr += *itr;
|
||||
}
|
||||
addToCurrentNode( realStr );
|
||||
}
|
||||
|
||||
virtual void flush()
|
||||
{
|
||||
osg::ref_ptr<osgDB::XmlNode> xmlRoot = new osgDB::XmlNode;
|
||||
xmlRoot->type = osgDB::XmlNode::ROOT;
|
||||
xmlRoot->children.push_back( _root.get() );
|
||||
xmlRoot->write( *_out );
|
||||
}
|
||||
|
||||
protected:
|
||||
void addToCurrentNode( const std::string& str, bool isString=false )
|
||||
{
|
||||
if ( _readLineType==FIRST_LINE )
|
||||
{
|
||||
_root->name = str;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _readLineType==NEW_LINE )
|
||||
{
|
||||
if ( isString )
|
||||
{
|
||||
pushNode( str );
|
||||
setLineType( PROP_LINE );
|
||||
return;
|
||||
}
|
||||
else
|
||||
setLineType( TEXT_LINE );
|
||||
}
|
||||
|
||||
if ( _readLineType==TEXT_LINE )
|
||||
{
|
||||
std::string& text = _nodePath.back()->properties["text"];
|
||||
text += str + ' ';
|
||||
}
|
||||
else if ( _nodePath.size()>0 )
|
||||
{
|
||||
std::string& prop = _nodePath.back()->properties["attribute"];
|
||||
if ( !prop.empty() ) prop += ' ';
|
||||
prop += str;
|
||||
}
|
||||
else
|
||||
{
|
||||
pushNode( str );
|
||||
setLineType( PROP_LINE );
|
||||
}
|
||||
}
|
||||
|
||||
void addToCurrentNode( std::ostream& (*fn)(std::ostream&) )
|
||||
{
|
||||
if ( _nodePath.size()>0 )
|
||||
{
|
||||
osgDB::XmlNode* node = _nodePath.back();
|
||||
_sstream << fn;
|
||||
if ( _readLineType==TEXT_LINE ) node->properties["text"] += _sstream.str();
|
||||
else node->properties["attribute"] += _sstream.str();
|
||||
_sstream.str("");
|
||||
}
|
||||
}
|
||||
|
||||
osgDB::XmlNode* pushNode( const std::string& name )
|
||||
{
|
||||
osg::ref_ptr<osgDB::XmlNode> node = new osgDB::XmlNode;
|
||||
node->type = osgDB::XmlNode::ATOM;
|
||||
|
||||
// Set element name without '#' and '::' characters
|
||||
std::string realName;
|
||||
if ( name.length()>0 && name[0]=='#' )
|
||||
realName = name.substr(1);
|
||||
else
|
||||
{
|
||||
realName = name;
|
||||
|
||||
std::string::size_type pos = realName.find("::");
|
||||
if ( pos!=std::string::npos )
|
||||
realName.replace( pos, 2, "--" );
|
||||
}
|
||||
node->name = realName;
|
||||
|
||||
if ( _nodePath.size()>0 )
|
||||
{
|
||||
_nodePath.back()->type = osgDB::XmlNode::GROUP;
|
||||
_nodePath.back()->children.push_back(node);
|
||||
}
|
||||
else
|
||||
_root->children.push_back(node);
|
||||
|
||||
_nodePath.push_back( node.get() );
|
||||
return node.get();
|
||||
}
|
||||
|
||||
osgDB::XmlNode* popNode()
|
||||
{
|
||||
osgDB::XmlNode* node = NULL;
|
||||
if ( _nodePath.size()>0 )
|
||||
{
|
||||
node = _nodePath.back();
|
||||
trimEndMarkers( node, "attribute" );
|
||||
trimEndMarkers( node, "text" );
|
||||
_nodePath.pop_back();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void trimEndMarkers( osgDB::XmlNode* node, const std::string& name )
|
||||
{
|
||||
osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
|
||||
if ( itr==node->properties.end() ) return;
|
||||
|
||||
std::string& str = itr->second;
|
||||
if ( !str.empty() )
|
||||
{
|
||||
std::string::size_type end = str.find_last_not_of( " \t\r\n" );
|
||||
if ( end==std::string::npos ) return;
|
||||
str.erase( end+1 );
|
||||
}
|
||||
|
||||
if ( str.empty() )
|
||||
node->properties.erase(itr);
|
||||
}
|
||||
|
||||
void setLineType( ReadLineType type )
|
||||
{
|
||||
_prevReadLineType = _readLineType;
|
||||
_readLineType = type;
|
||||
}
|
||||
|
||||
typedef std::vector<osgDB::XmlNode*> XmlNodePath;
|
||||
XmlNodePath _nodePath;
|
||||
|
||||
osg::ref_ptr<osgDB::XmlNode> _root;
|
||||
std::stringstream _sstream;
|
||||
|
||||
ReadLineType _readLineType;
|
||||
ReadLineType _prevReadLineType;
|
||||
bool _hasSubProperty;
|
||||
};
|
||||
|
||||
class XmlInputIterator : public osgDB::InputIterator
|
||||
{
|
||||
public:
|
||||
XmlInputIterator( std::istream* istream )
|
||||
{
|
||||
_in = istream;
|
||||
_root = osgDB::readXmlStream( *istream );
|
||||
|
||||
if ( _root.valid() && _root->children.size()>0 )
|
||||
_nodePath.push_back( _root->children[0] );
|
||||
}
|
||||
|
||||
virtual ~XmlInputIterator() {}
|
||||
|
||||
virtual bool isBinary() const { return false; }
|
||||
|
||||
virtual void readBool( bool& b )
|
||||
{
|
||||
std::string boolString;
|
||||
if ( prepareStream() ) _sstream >> boolString;
|
||||
if ( boolString=="TRUE" ) b = true;
|
||||
else b = false;
|
||||
}
|
||||
|
||||
virtual void readChar( char& c )
|
||||
{ if ( prepareStream() ) _sstream >> c; }
|
||||
|
||||
virtual void readSChar( signed char& c )
|
||||
{ if ( prepareStream() ) _sstream >> c; }
|
||||
|
||||
virtual void readUChar( unsigned char& c )
|
||||
{ if ( prepareStream() ) _sstream >> c; }
|
||||
|
||||
virtual void readShort( short& s )
|
||||
{ if ( prepareStream() ) _sstream >> s; }
|
||||
|
||||
virtual void readUShort( unsigned short& s )
|
||||
{ if ( prepareStream() ) _sstream >> s; }
|
||||
|
||||
virtual void readInt( int& i )
|
||||
{ if ( prepareStream() ) _sstream >> i; }
|
||||
|
||||
virtual void readUInt( unsigned int& i )
|
||||
{ if ( prepareStream() ) _sstream >> i; }
|
||||
|
||||
virtual void readLong( long& l )
|
||||
{ if ( prepareStream() ) _sstream >> l; }
|
||||
|
||||
virtual void readULong( unsigned long& l )
|
||||
{ if ( prepareStream() ) _sstream >> l; }
|
||||
|
||||
virtual void readFloat( float& f )
|
||||
{ if ( prepareStream() ) _sstream >> f; }
|
||||
|
||||
virtual void readDouble( double& d )
|
||||
{ if ( prepareStream() ) _sstream >> d; }
|
||||
|
||||
virtual void readString( std::string& s )
|
||||
{
|
||||
if ( prepareStream() ) _sstream >> s;
|
||||
|
||||
// Replace '--' to '::' to get correct wrapper class
|
||||
std::string::size_type pos = s.find("--");
|
||||
if ( pos!=std::string::npos )
|
||||
s.replace( pos, 2, "::" );
|
||||
}
|
||||
|
||||
virtual void readStream( std::istream& (*fn)(std::istream&) )
|
||||
{ if ( prepareStream() ) _sstream >> fn; }
|
||||
|
||||
virtual void readBase( std::ios_base& (*fn)(std::ios_base&) )
|
||||
{ _sstream >> fn; }
|
||||
|
||||
virtual void readGLenum( osgDB::ObjectGLenum& value )
|
||||
{
|
||||
GLenum e = 0;
|
||||
std::string enumString;
|
||||
if ( prepareStream() ) _sstream >> enumString;
|
||||
e = osgDB::Registry::instance()->getObjectWrapperManager()->getValue("GL", enumString);
|
||||
value.set( e );
|
||||
}
|
||||
|
||||
virtual void readProperty( osgDB::ObjectProperty& prop )
|
||||
{
|
||||
int value = 0;
|
||||
std::string enumString;
|
||||
if ( prepareStream() ) _sstream >> enumString;
|
||||
if ( prop._mapProperty )
|
||||
{
|
||||
value = osgDB::Registry::instance()->getObjectWrapperManager()->getValue(prop._name, enumString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace '--' to '::' to get correct wrapper class
|
||||
std::string::size_type pos = enumString.find("--");
|
||||
if ( pos!=std::string::npos )
|
||||
enumString.replace( pos, 2, "::" );
|
||||
|
||||
if ( prop._name!=enumString )
|
||||
{
|
||||
if ( prop._name[0]=='#' )
|
||||
enumString = '#' + enumString;
|
||||
if ( prop._name!=enumString )
|
||||
{
|
||||
OSG_NOTIFY(osg::WARN) << "XmlInputIterator::readProperty(): Unmatched property "
|
||||
<< enumString << ", expecting " << prop._name << std::endl;
|
||||
}
|
||||
}
|
||||
prop._name = enumString;
|
||||
}
|
||||
prop.set( value );
|
||||
}
|
||||
|
||||
virtual void readMark( osgDB::ObjectMark& mark ) {}
|
||||
|
||||
virtual void readCharArray( char* s, unsigned int size ) {}
|
||||
|
||||
virtual void readWrappedString( std::string& str )
|
||||
{
|
||||
std::string realStr;
|
||||
if ( prepareStream() ) std::getline( _sstream, realStr );
|
||||
for ( std::string::const_iterator itr=realStr.begin(); itr!=realStr.end(); ++itr )
|
||||
{
|
||||
if ( *itr=='\'' )
|
||||
{
|
||||
itr++;
|
||||
if ( itr==realStr.end() ) break;
|
||||
|
||||
if ( *itr=='\'' ) str += '\"';
|
||||
else str += '\'' + *itr;
|
||||
}
|
||||
else
|
||||
str += *itr;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool matchString( const std::string& str )
|
||||
{
|
||||
prepareStream();
|
||||
unsigned int size = str.length();
|
||||
if ( _sstream.str().length()<size ) return false;
|
||||
|
||||
int result = _sstream.str().compare( 0, size, str );
|
||||
if ( !result )
|
||||
{
|
||||
std::string prop; readString( prop );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void advanceToCurrentEndBracket() {}
|
||||
|
||||
protected:
|
||||
bool isReadable() const { return _sstream.rdbuf()->in_avail()>0; }
|
||||
|
||||
bool prepareStream()
|
||||
{
|
||||
if ( !_nodePath.size() ) return false;
|
||||
if ( isReadable() ) return true;
|
||||
_sstream.clear();
|
||||
|
||||
osgDB::XmlNode* current = _nodePath.back();
|
||||
if ( !current->name.empty() )
|
||||
{
|
||||
_sstream.str( current->name );
|
||||
current->name.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( current->properties.size()>0 )
|
||||
{
|
||||
if ( applyPropertyToStream(current, "attribute") ) return true;
|
||||
else if ( applyPropertyToStream(current, "text") ) return true;
|
||||
}
|
||||
|
||||
if ( current->children.size()>0 )
|
||||
{
|
||||
_nodePath.push_back( current->children.front() );
|
||||
current->children.erase( current->children.begin() );
|
||||
return prepareStream();
|
||||
}
|
||||
|
||||
_nodePath.pop_back();
|
||||
return prepareStream();
|
||||
}
|
||||
|
||||
bool applyPropertyToStream( osgDB::XmlNode* node, const std::string& name )
|
||||
{
|
||||
osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
|
||||
if ( itr!=node->properties.end() )
|
||||
{
|
||||
_sstream.str( itr->second );
|
||||
node->properties.erase( itr );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef std::vector< osg::ref_ptr<osgDB::XmlNode> > XmlNodePath;
|
||||
XmlNodePath _nodePath;
|
||||
|
||||
osg::ref_ptr<osgDB::XmlNode> _root;
|
||||
std::stringstream _sstream;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user