root/OpenSceneGraph/trunk/src/osgPlugins/osg/XmlStreamOperator.h @ 13041

Revision 13041, 16.5 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1#ifndef OSGDB_XMLSTREAMOPERATOR
2#define OSGDB_XMLSTREAMOPERATOR
3
4#include <osgDB/StreamOperator>
5#include <osgDB/XmlParser>
6#include <sstream>
7
8class XmlOutputIterator : public osgDB::OutputIterator
9{
10public:
11    enum ReadLineType
12    {
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
20    };
21
22    XmlOutputIterator( std::ostream* ostream, int precision )
23    :   _readLineType(FIRST_LINE), _prevReadLineType(FIRST_LINE), _hasSubProperty(false)
24    {
25        _out = ostream;
26        if (precision>0) _sstream.precision(precision);
27        _root = new osgDB::XmlNode;
28        _root->type = osgDB::XmlNode::GROUP;
29    }
30
31    virtual ~XmlOutputIterator() {}
32
33    virtual bool isBinary() const { return false; }
34
35    virtual void writeBool( bool b )
36    { addToCurrentNode( b ? std::string("TRUE") : std::string("FALSE") ); }
37
38    virtual void writeChar( char c )
39    { _sstream << (short)c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
40
41    virtual void writeUChar( unsigned char c )
42    { _sstream << (unsigned short)c; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
43
44    virtual void writeShort( short s )
45    { _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
46
47    virtual void writeUShort( unsigned short s )
48    { _sstream << s; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
49
50    virtual void writeInt( int i )
51    { _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
52
53    virtual void writeUInt( unsigned int i )
54    { _sstream << i; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
55
56    virtual void writeLong( long l )
57    { _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
58
59    virtual void writeULong( unsigned long l )
60    { _sstream << l; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
61
62    virtual void writeFloat( float f )
63    { _sstream << f; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
64
65    virtual void writeDouble( double d )
66    { _sstream << d; addToCurrentNode( _sstream.str() ); _sstream.str(""); }
67
68    virtual void writeString( const std::string& s )
69    { addToCurrentNode( s, true ); }
70
71    virtual void writeStream( std::ostream& (*fn)(std::ostream&) )
72    {
73        if ( isEndl( fn ) )
74        {
75            if ( _readLineType==PROP_LINE || _readLineType==END_BRACKET_LINE )
76            {
77                if ( _hasSubProperty )
78                {
79                    _hasSubProperty = false;
80                    popNode();  // Exit the sub-property element
81                }
82                popNode();  // Exit the property element
83            }
84            else if ( _readLineType==SUB_PROP_LINE )
85            {
86                _hasSubProperty = false;
87                popNode();  // Exit the sub-property element
88                popNode();  // Exit the property element
89            }
90            else if ( _readLineType==TEXT_LINE )
91                addToCurrentNode( fn );
92
93            setLineType( NEW_LINE );
94        }
95        else
96            addToCurrentNode( fn );
97    }
98
99    virtual void writeBase( std::ios_base& (*fn)(std::ios_base&) )
100    {
101        _sstream << fn;
102    }
103
104    virtual void writeGLenum( const osgDB::ObjectGLenum& value )
105    {
106        GLenum e = value.get();
107        const std::string& enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString("GL", e);
108        addToCurrentNode( enumString, true );
109    }
110
111    virtual void writeProperty( const osgDB::ObjectProperty& prop )
112    {
113        std::string enumString = prop._name;
114        if ( prop._mapProperty )
115        {
116            enumString = osgDB::Registry::instance()->getObjectWrapperManager()->getString(prop._name, prop._value);
117            addToCurrentNode( enumString, true );
118        }
119        else
120        {
121            if ( _readLineType==NEW_LINE || _readLineType==BEGIN_BRACKET_LINE )
122            {
123                pushNode( enumString );
124                setLineType( PROP_LINE );
125            }
126            else if ( _readLineType==PROP_LINE )
127            {
128                pushNode( enumString );
129                setLineType( SUB_PROP_LINE );
130                _hasSubProperty = true;
131            }
132            else if ( _readLineType==SUB_PROP_LINE )
133            {
134                popNode();
135                pushNode( enumString );
136            }
137        }
138    }
139
140    virtual void writeMark( const osgDB::ObjectMark& mark )
141    {
142        int delta = mark._indentDelta;
143        if ( delta>0 )
144        {
145            setLineType( BEGIN_BRACKET_LINE );
146        }
147        else if ( delta<0 )
148        {
149            setLineType( END_BRACKET_LINE );
150        }
151    }
152
153    virtual void writeCharArray( const char* s, unsigned int size ) {}
154
155    virtual void writeWrappedString( const std::string& str )
156    {
157        std::string realStr;
158        for ( std::string::const_iterator itr=str.begin(); itr!=str.end(); ++itr )
159        {
160            char ch = *itr;
161            if ( ch=='\"' ) realStr += '\\';
162            else if ( ch=='\\' ) realStr += '\\';
163            realStr += ch;
164        }
165        realStr.insert( std::string::size_type(0), 1, '\"' );
166        realStr += '\"';
167        addToCurrentNode( realStr );
168    }
169
170    virtual void flush()
171    {
172        osg::ref_ptr<osgDB::XmlNode> xmlRoot = new osgDB::XmlNode;
173        xmlRoot->type = osgDB::XmlNode::ROOT;
174        xmlRoot->children.push_back( _root.get() );
175        xmlRoot->write( *_out );
176    }
177
178protected:
179    void addToCurrentNode( const std::string& str, bool isString=false )
180    {
181        if ( _readLineType==FIRST_LINE )
182        {
183            _root->name = str;
184            return;
185        }
186
187        if ( _readLineType==NEW_LINE )
188        {
189            if ( isString )
190            {
191                pushNode( str );
192                setLineType( PROP_LINE );
193                return;
194            }
195            else
196                setLineType( TEXT_LINE );
197        }
198
199        if ( _readLineType==TEXT_LINE )
200        {
201            std::string& text = _nodePath.back()->properties["text"];
202            text += str + ' ';
203        }
204        else if ( _nodePath.size()>0 )
205        {
206            std::string& prop = _nodePath.back()->properties["attribute"];
207            if ( !prop.empty() ) prop += ' ';
208            prop += str;
209        }
210        else
211        {
212            pushNode( str );
213            setLineType( PROP_LINE );
214        }
215    }
216
217    void addToCurrentNode( std::ostream& (*fn)(std::ostream&) )
218    {
219        if ( _nodePath.size()>0 )
220        {
221            osgDB::XmlNode* node = _nodePath.back();
222            _sstream << fn;
223            if ( _readLineType==TEXT_LINE ) node->properties["text"] += _sstream.str();
224            else node->properties["attribute"] += _sstream.str();
225            _sstream.str("");
226        }
227    }
228
229    osgDB::XmlNode* pushNode( const std::string& name )
230    {
231        osg::ref_ptr<osgDB::XmlNode> node = new osgDB::XmlNode;
232        node->type = osgDB::XmlNode::ATOM;
233
234        // Set element name without '#' and '::' characters
235        std::string realName;
236        if ( name.length()>0 && name[0]=='#' )
237            realName = name.substr(1);
238        else
239        {
240            realName = name;
241
242            std::string::size_type pos = realName.find("::");
243            if ( pos!=std::string::npos )
244                realName.replace( pos, 2, "--" );
245        }
246        node->name = realName;
247
248        if ( _nodePath.size()>0 )
249        {
250            _nodePath.back()->type = osgDB::XmlNode::GROUP;
251            _nodePath.back()->children.push_back(node);
252        }
253        else
254            _root->children.push_back(node);
255
256        _nodePath.push_back( node.get() );
257        return node.get();
258    }
259
260    osgDB::XmlNode* popNode()
261    {
262        osgDB::XmlNode* node = NULL;
263        if ( _nodePath.size()>0 )
264        {
265            node = _nodePath.back();
266            trimEndMarkers( node, "attribute" );
267            trimEndMarkers( node, "text" );
268            _nodePath.pop_back();
269        }
270        return node;
271    }
272
273    void trimEndMarkers( osgDB::XmlNode* node, const std::string& name )
274    {
275        osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
276        if ( itr==node->properties.end() ) return;
277
278        std::string& str = itr->second;
279        if ( !str.empty() )
280        {
281            std::string::size_type end = str.find_last_not_of( " \t\r\n" );
282            if ( end==std::string::npos ) return;
283            str.erase( end+1 );
284        }
285
286        if ( str.empty() )
287            node->properties.erase(itr);
288    }
289
290    void setLineType( ReadLineType type )
291    {
292        _prevReadLineType = _readLineType;
293        _readLineType = type;
294    }
295
296    typedef std::vector<osgDB::XmlNode*> XmlNodePath;
297    XmlNodePath _nodePath;
298
299    osg::ref_ptr<osgDB::XmlNode> _root;
300    std::stringstream _sstream;
301
302    ReadLineType _readLineType;
303    ReadLineType _prevReadLineType;
304    bool _hasSubProperty;
305};
306
307class XmlInputIterator : public osgDB::InputIterator
308{
309public:
310    XmlInputIterator( std::istream* istream )
311    {
312        _in = istream;
313        _root = osgDB::readXmlStream( *istream );
314
315        if ( _root.valid() && _root->children.size()>0 )
316            _nodePath.push_back( _root->children[0] );
317    }
318
319    virtual ~XmlInputIterator() {}
320
321    virtual bool isBinary() const { return false; }
322
323    virtual void readBool( bool& b )
324    {
325        std::string boolString;
326        if ( prepareStream() ) _sstream >> boolString;
327        if ( boolString=="TRUE" ) b = true;
328        else b = false;
329    }
330
331    virtual void readChar( char& c )
332    {
333        short s = 0;
334        if ( prepareStream() ) _sstream >> s;
335        c = (char)s;
336    }
337
338    virtual void readSChar( signed char& c )
339    {
340        short s = 0;
341        if ( prepareStream() ) _sstream >> s;
342        c = (signed char)s;
343    }
344
345    virtual void readUChar( unsigned char& c )
346    {
347        unsigned short s = 0;
348        if ( prepareStream() ) _sstream >> s;
349        c = (unsigned char)s;
350    }
351
352    virtual void readShort( short& s )
353    { std::string str; if (prepareStream()) _sstream >> str; s = static_cast<short>(strtol(str.c_str(), NULL, 0)); }
354
355    virtual void readUShort( unsigned short& s )
356    { std::string str; if (prepareStream()) _sstream >> str; s = static_cast<unsigned short>(strtoul(str.c_str(), NULL, 0)); }
357
358    virtual void readInt( int& i )
359    { std::string str; if (prepareStream()) _sstream >> str; i = static_cast<int>(strtol(str.c_str(), NULL, 0)); }
360
361    virtual void readUInt( unsigned int& i )
362    { std::string str; if (prepareStream()) _sstream >> str; i = static_cast<unsigned int>(strtoul(str.c_str(), NULL, 0)); }
363
364    virtual void readLong( long& l )
365    { std::string str; if (prepareStream()) _sstream >> str; l = strtol(str.c_str(), NULL, 0); }
366
367    virtual void readULong( unsigned long& l )
368    { std::string str; if (prepareStream()) _sstream >> str; l = strtoul(str.c_str(), NULL, 0); }
369
370    virtual void readFloat( float& f )
371    { std::string str; if (prepareStream()) _sstream >> str; f = osg::asciiToFloat(str.c_str()); }
372
373    virtual void readDouble( double& d )
374    { std::string str; if (prepareStream()) _sstream >> str; d = osg::asciiToDouble(str.c_str()); }
375
376    virtual void readString( std::string& s )
377    {
378        if ( prepareStream() ) _sstream >> s;
379
380        // Replace '--' to '::' to get correct wrapper class
381        std::string::size_type pos = s.find("--");
382        if ( pos!=std::string::npos )
383            s.replace( pos, 2, "::" );
384    }
385
386    virtual void readStream( std::istream& (*fn)(std::istream&) )
387    { if ( prepareStream() ) _sstream >> fn; }
388
389    virtual void readBase( std::ios_base& (*fn)(std::ios_base&) )
390    { _sstream >> fn; }
391
392    virtual void readGLenum( osgDB::ObjectGLenum& value )
393    {
394        GLenum e = 0;
395        std::string enumString;
396        if ( prepareStream() ) _sstream >> enumString;
397        e = osgDB::Registry::instance()->getObjectWrapperManager()->getValue("GL", enumString);
398        value.set( e );
399    }
400
401    virtual void readProperty( osgDB::ObjectProperty& prop )
402    {
403        int value = 0;
404        std::string enumString;
405        if ( prepareStream() ) _sstream >> enumString;
406        if ( prop._mapProperty )
407        {
408            value = osgDB::Registry::instance()->getObjectWrapperManager()->getValue(prop._name, enumString);
409        }
410        else
411        {
412            // Replace '--' to '::' to get correct wrapper class
413            std::string::size_type pos = enumString.find("--");
414            if ( pos!=std::string::npos )
415                enumString.replace( pos, 2, "::" );
416
417            if ( prop._name!=enumString )
418            {
419                if ( prop._name[0]=='#' )
420                    enumString = '#' + enumString;
421                if ( prop._name!=enumString )
422                {
423                    OSG_WARN << "XmlInputIterator::readProperty(): Unmatched property "
424                                           << enumString << ", expecting " << prop._name << std::endl;
425                }
426            }
427            prop._name = enumString;
428        }
429        prop.set( value );
430    }
431
432    virtual void readMark( osgDB::ObjectMark& mark ) {}
433
434    virtual void readCharArray( char* s, unsigned int size ) {}
435
436    virtual void readWrappedString( std::string& str )
437    {
438        if ( !prepareStream() ) return;
439
440        // Read available string in the stream buffer
441        unsigned int availSize = _sstream.rdbuf()->in_avail();
442        std::string realStr = _sstream.str();
443        _sstream.str("");
444
445        // Find the first quot or valid character
446        bool hasQuot = false;
447        std::string::iterator itr = realStr.begin() + (realStr.size() - availSize);
448        for ( ; itr!=realStr.end(); ++itr )
449        {
450            char ch = *itr;
451            if ((ch==' ') || (ch=='\n') || (ch=='\r')) continue;
452            else if (ch=='"') hasQuot = true;
453            else str += ch;
454
455            itr++;
456            break;
457        }
458
459        for ( ; itr!=realStr.end(); ++itr )
460        {
461            char ch = *itr;
462            if (ch=='\\')
463            {
464                itr++;
465                if (itr == realStr.end()) break;
466                str += *itr;
467            }
468            else if (hasQuot && ch=='"')
469            {
470                // Get to the end of the wrapped string
471                itr++;
472                break;
473            }
474            else
475                str += ch;
476        }
477        if (itr != realStr.end())
478        {
479            _sstream << std::string(itr, realStr.end());
480        }
481    }
482
483    virtual bool matchString( const std::string& str )
484    {
485        prepareStream();
486        std::string strInStream = osgDB::trimEnclosingSpaces(_sstream.str());
487        if ( strInStream==str )
488        {
489            std::string prop; readString( prop );
490            return true;
491        }
492        return false;
493    }
494
495    virtual void advanceToCurrentEndBracket() {}
496
497protected:
498    bool isReadable() const { return _sstream.rdbuf()->in_avail()>0; }
499
500    bool prepareStream()
501    {
502        if ( !_nodePath.size() ) return false;
503        if ( isReadable() ) return true;
504        _sstream.clear();
505
506        osgDB::XmlNode* current = _nodePath.back().get();
507        if ( current->type!=osgDB::XmlNode::COMMENT )
508        {
509            if ( !current->name.empty() )
510            {
511                _sstream.str( current->name );
512                current->name.clear();
513                return true;
514            }
515
516            if ( current->properties.size()>0 )
517            {
518                if ( applyPropertyToStream(current, "attribute") ) return true;
519                else if ( applyPropertyToStream(current, "text") ) return true;
520            }
521
522            if ( current->children.size()>0 )
523            {
524                _nodePath.push_back( current->children.front() );
525                current->children.erase( current->children.begin() );
526                return prepareStream();
527            }
528        }
529        _nodePath.pop_back();
530        return prepareStream();
531    }
532
533    bool applyPropertyToStream( osgDB::XmlNode* node, const std::string& name )
534    {
535        osgDB::XmlNode::Properties::iterator itr = node->properties.find(name);
536        if ( itr!=node->properties.end() )
537        {
538            _sstream.str( itr->second );
539            node->properties.erase( itr );
540            return true;
541        }
542        return false;
543    }
544
545    typedef std::vector< osg::ref_ptr<osgDB::XmlNode> > XmlNodePath;
546    XmlNodePath _nodePath;
547
548    osg::ref_ptr<osgDB::XmlNode> _root;
549    std::stringstream _sstream;
550};
551
552#endif
Note: See TracBrowser for help on using the browser.