Files
OpenSceneGraph/src/osgPlugins/osg/XmlStreamOperator.h
Robert Osfield 68a1ed2dcf Fixes for building OSG with OSG_USE_REF_PTR_IMPLICIT_OUTPUT_CONVERSION set to OFF.
Fixed copy and paste error in Camera::getImplicitBufferAttachmentResolveMask().
2010-05-12 11:37:27 +00:00

523 lines
16 KiB
C++

#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 << (short)c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
virtual void writeUChar( unsigned char c )
{ _sstream << (unsigned short)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 )
{
short s = 0;
if ( prepareStream() ) _sstream >> s;
c = (char)s;
}
virtual void readSChar( signed char& c )
{
short s = 0;
if ( prepareStream() ) _sstream >> s;
c = (signed char)s;
}
virtual void readUChar( unsigned char& c )
{
unsigned short s = 0;
if ( prepareStream() ) _sstream >> s;
c = (unsigned char)s;
}
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().get();
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