1
#ifndef OSGDB_XMLSTREAMOPERATOR
2
#define OSGDB_XMLSTREAMOPERATOR
4
#include <osgDB/StreamOperator>
5
#include <osgDB/XmlParser>
8
class XmlOutputIterator : public osgDB::OutputIterator
13
FIRST_LINE=0, // The first line of file
14
NEW_LINE, // A new line without checking its type
15
PROP_LINE, // A line starting with osgDB::PROPERTY
16
SUB_PROP_LINE, // A property line containing another osgDB::PROPERTY
17
BEGIN_BRACKET_LINE, // A line ending with a '{'
18
END_BRACKET_LINE, // A line starting with a '}'
19
TEXT_LINE // A text line, e.g. recording array elements
22
XmlOutputIterator( std::ostream* ostream )
23
: _readLineType(FIRST_LINE), _prevReadLineType(FIRST_LINE), _hasSubProperty(false)
26
_root = new osgDB::XmlNode;
27
_root->type = osgDB::XmlNode::GROUP;
30
virtual ~XmlOutputIterator() {}
32
virtual bool isBinary() const { return false; }
34
virtual void writeBool( bool b )
35
{ addToCurrentNode( b ? std::string("TRUE") : std::string("FALSE") ); }
37
virtual void writeChar( char c )
38
{ _sstream << (short)c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
40
virtual void writeUChar( unsigned char c )
41
{ _sstream << (unsigned short)c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
43
virtual void writeShort( short s )
44
{ _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
46
virtual void writeUShort( unsigned short s )
47
{ _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
49
virtual void writeInt( int i )
50
{ _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
52
virtual void writeUInt( unsigned int i )
53
{ _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
55
virtual void writeLong( long l )
56
{ _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
58
virtual void writeULong( unsigned long l )
59
{ _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
61
virtual void writeFloat( float f )
62
{ _sstream << f; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
64
virtual void writeDouble( double d )
65
{ _sstream << d; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
67
virtual void writeString( const std::string& s )
68
{ addToCurrentNode( s, true ); }
70
virtual void writeStream( std::ostream& (*fn)(std::ostream&) )
74
if ( _readLineType==PROP_LINE || _readLineType==END_BRACKET_LINE )
76
if ( _hasSubProperty )
78
_hasSubProperty = false;
79
popNode(); // Exit the sub-property element
81
popNode(); // Exit the property element
83
else if ( _readLineType==SUB_PROP_LINE )
85
_hasSubProperty = false;
86
popNode(); // Exit the sub-property element
87
popNode(); // Exit the property element
89
else if ( _readLineType==TEXT_LINE )
90
addToCurrentNode( fn );
92
setLineType( NEW_LINE );
95
addToCurrentNode( fn );
98
virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) )
103
virtual void writeGLenum( const osgDB::ObjectGLenum& value )
105
GLenum e = value.get();
106
const std::string& enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString("GL", e);
107
addToCurrentNode( enumString, true );
110
virtual void writeProperty( const osgDB::ObjectProperty& prop )
112
std::string enumString = prop._name;
113
if ( prop._mapProperty )
115
enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString(prop._name, prop._value);
116
addToCurrentNode( enumString, true );
120
if ( _readLineType==NEW_LINE || _readLineType==BEGIN_BRACKET_LINE )
122
pushNode( enumString );
123
setLineType( PROP_LINE );
125
else if ( _readLineType==PROP_LINE )
127
pushNode( enumString );
128
setLineType( SUB_PROP_LINE );
129
_hasSubProperty = true;
131
else if ( _readLineType==SUB_PROP_LINE )
134
pushNode( enumString );
139
virtual void writeMark( const osgDB::ObjectMark& mark )
141
int delta = mark._indentDelta;
144
setLineType( BEGIN_BRACKET_LINE );
148
setLineType( END_BRACKET_LINE );
152
virtual void writeCharArray( const char* s, unsigned int size ) {}
154
virtual void writeWrappedString( const std::string& str )
157
for ( std::string::const_iterator itr=str.begin(); itr!=str.end(); ++itr )
160
if ( ch=='\"' ) realStr += '\\';
161
else if ( ch=='\\' ) realStr += '\\';
164
realStr.insert( std::string::size_type(0), 1, '\"' );
166
addToCurrentNode( realStr );
171
osg::ref_ptr<osgDB::XmlNode> xmlRoot = new osgDB::XmlNode;
172
xmlRoot->type = osgDB::XmlNode::ROOT;
173
xmlRoot->children.push_back( _root.get() );
174
xmlRoot->write( *_out );
178
void addToCurrentNode( const std::string& str, bool isString=false )
180
if ( _readLineType==FIRST_LINE )
186
if ( _readLineType==NEW_LINE )
191
setLineType( PROP_LINE );
195
setLineType( TEXT_LINE );
198
if ( _readLineType==TEXT_LINE )
200
std::string& text = _nodePath.back()->properties["text"];
203
else if ( _nodePath.size()>0 )
205
std::string& prop = _nodePath.back()->properties["attribute"];
206
if ( !prop.empty() ) prop += ' ';
212
setLineType( PROP_LINE );
216
void addToCurrentNode( std::ostream& (*fn)(std::ostream&) )
218
if ( _nodePath.size()>0 )
220
osgDB::XmlNode* node = _nodePath.back();
222
if ( _readLineType==TEXT_LINE ) node->properties["text"] += _sstream.str();
223
else node->properties["attribute"] += _sstream.str();
228
osgDB::XmlNode* pushNode( const std::string& name )
230
osg::ref_ptr<osgDB::XmlNode> node = new osgDB::XmlNode;
231
node->type = osgDB::XmlNode::ATOM;
233
// Set element name without '#' and '::' characters
234
std::string realName;
235
if ( name.length()>0 && name[0]=='#' )
236
realName = name.substr(1);
241
std::string::size_type pos = realName.find("::");
242
if ( pos!=std::string::npos )
243
realName.replace( pos, 2, "--" );
245
node->name = realName;
247
if ( _nodePath.size()>0 )
249
_nodePath.back()->type = osgDB::XmlNode::GROUP;
250
_nodePath.back()->children.push_back(node);
253
_root->children.push_back(node);
255
_nodePath.push_back( node.get() );
259
osgDB::XmlNode* popNode()
261
osgDB::XmlNode* node = NULL;
262
if ( _nodePath.size()>0 )
264
node = _nodePath.back();
265
trimEndMarkers( node, "attribute" );
266
trimEndMarkers( node, "text" );
267
_nodePath.pop_back();
272
void trimEndMarkers( osgDB::XmlNode* node, const std::string& name )
274
osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
275
if ( itr==node->properties.end() ) return;
277
std::string& str = itr->second;
280
std::string::size_type end = str.find_last_not_of( " \t\r\n" );
281
if ( end==std::string::npos ) return;
286
node->properties.erase(itr);
289
void setLineType( ReadLineType type )
291
_prevReadLineType = _readLineType;
292
_readLineType = type;
295
typedef std::vector<osgDB::XmlNode*> XmlNodePath;
296
XmlNodePath _nodePath;
298
osg::ref_ptr<osgDB::XmlNode> _root;
299
std::stringstream _sstream;
301
ReadLineType _readLineType;
302
ReadLineType _prevReadLineType;
303
bool _hasSubProperty;
306
class XmlInputIterator : public osgDB::InputIterator
309
XmlInputIterator( std::istream* istream )
312
_root = osgDB::readXmlStream( *istream );
314
if ( _root.valid() && _root->children.size()>0 )
315
_nodePath.push_back( _root->children[0] );
318
virtual ~XmlInputIterator() {}
320
virtual bool isBinary() const { return false; }
322
virtual void readBool( bool& b )
324
std::string boolString;
325
if ( prepareStream() ) _sstream >> boolString;
326
if ( boolString=="TRUE" ) b = true;
330
virtual void readChar( char& c )
333
if ( prepareStream() ) _sstream >> s;
337
virtual void readSChar( signed char& c )
340
if ( prepareStream() ) _sstream >> s;
344
virtual void readUChar( unsigned char& c )
346
unsigned short s = 0;
347
if ( prepareStream() ) _sstream >> s;
348
c = (unsigned char)s;
351
virtual void readShort( short& s )
352
{ if ( prepareStream() ) _sstream >> s; }
354
virtual void readUShort( unsigned short& s )
355
{ if ( prepareStream() ) _sstream >> s; }
357
virtual void readInt( int& i )
358
{ if ( prepareStream() ) _sstream >> i; }
360
virtual void readUInt( unsigned int& i )
361
{ if ( prepareStream() ) _sstream >> i; }
363
virtual void readLong( long& l )
364
{ if ( prepareStream() ) _sstream >> l; }
366
virtual void readULong( unsigned long& l )
367
{ if ( prepareStream() ) _sstream >> l; }
369
virtual void readFloat( float& f )
370
{ if ( prepareStream() ) _sstream >> f; }
372
virtual void readDouble( double& d )
373
{ if ( prepareStream() ) _sstream >> d; }
375
virtual void readString( std::string& s )
377
if ( prepareStream() ) _sstream >> s;
379
// Replace '--' to '::' to get correct wrapper class
380
std::string::size_type pos = s.find("--");
381
if ( pos!=std::string::npos )
382
s.replace( pos, 2, "::" );
385
virtual void readStream( std::istream& (*fn)(std::istream&) )
386
{ if ( prepareStream() ) _sstream >> fn; }
388
virtual void readBase( std::ios_base& (*fn)(std::ios_base&) )
391
virtual void readGLenum( osgDB::ObjectGLenum& value )
394
std::string enumString;
395
if ( prepareStream() ) _sstream >> enumString;
396
e = osgDB::Registry::instance()->getObjectWrapperManager()->getValue("GL", enumString);
400
virtual void readProperty( osgDB::ObjectProperty& prop )
403
std::string enumString;
404
if ( prepareStream() ) _sstream >> enumString;
405
if ( prop._mapProperty )
407
value = osgDB::Registry::instance()->getObjectWrapperManager()->getValue(prop._name, enumString);
411
// Replace '--' to '::' to get correct wrapper class
412
std::string::size_type pos = enumString.find("--");
413
if ( pos!=std::string::npos )
414
enumString.replace( pos, 2, "::" );
416
if ( prop._name!=enumString )
418
if ( prop._name[0]=='#' )
419
enumString = '#' + enumString;
420
if ( prop._name!=enumString )
422
OSG_WARN << "XmlInputIterator::readProperty(): Unmatched property "
423
<< enumString << ", expecting " << prop._name << std::endl;
426
prop._name = enumString;
431
virtual void readMark( osgDB::ObjectMark& mark ) {}
433
virtual void readCharArray( char* s, unsigned int size ) {}
435
virtual void readWrappedString( std::string& str )
437
if ( !prepareStream() ) return;
439
// Read available string in the stream buffer
440
unsigned int availSize = _sstream.rdbuf()->in_avail();
441
std::string realStr = _sstream.str();
444
// Find the first quot or valid character
445
bool hasQuot = false;
446
std::string::iterator itr = realStr.begin() + (realStr.size() - availSize);
447
for ( ; itr!=realStr.end(); ++itr )
450
if ((ch==' ') || (ch=='\n') || (ch=='\r')) continue;
451
else if (ch=='"') hasQuot = true;
458
for ( ; itr!=realStr.end(); ++itr )
464
if (itr == realStr.end()) break;
467
else if (hasQuot && ch=='"')
469
// Get to the end of the wrapped string
476
if (itr != realStr.end())
478
_sstream << std::string(itr, realStr.end());
482
virtual bool matchString( const std::string& str )
485
std::string strInStream = osgDB::trimEnclosingSpaces(_sstream.str());
486
if ( strInStream==str )
488
std::string prop; readString( prop );
494
virtual void advanceToCurrentEndBracket() {}
497
bool isReadable() const { return _sstream.rdbuf()->in_avail()>0; }
501
if ( !_nodePath.size() ) return false;
502
if ( isReadable() ) return true;
505
osgDB::XmlNode* current = _nodePath.back().get();
506
if ( current->type!=osgDB::XmlNode::COMMENT )
508
if ( !current->name.empty() )
510
_sstream.str( current->name );
511
current->name.clear();
515
if ( current->properties.size()>0 )
517
if ( applyPropertyToStream(current, "attribute") ) return true;
518
else if ( applyPropertyToStream(current, "text") ) return true;
521
if ( current->children.size()>0 )
523
_nodePath.push_back( current->children.front() );
524
current->children.erase( current->children.begin() );
525
return prepareStream();
528
_nodePath.pop_back();
529
return prepareStream();
532
bool applyPropertyToStream( osgDB::XmlNode* node, const std::string& name )
534
osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
535
if ( itr!=node->properties.end() )
537
_sstream.str( itr->second );
538
node->properties.erase( itr );
544
typedef std::vector< osg::ref_ptr<osgDB::XmlNode> > XmlNodePath;
545
XmlNodePath _nodePath;
547
osg::ref_ptr<osgDB::XmlNode> _root;
548
std::stringstream _sstream;