root/OpenSceneGraph/trunk/src/osgDB/XmlParser.cpp @ 13041

Revision 13041, 14.7 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/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgDB/XmlParser>
15#include <osgDB/FileUtils>
16
17#include <osg/Notify>
18
19using namespace osgDB;
20
21XmlNode* osgDB::readXmlFile(const std::string& filename,const Options* options)
22{
23    std::string foundFile = osgDB::findDataFile(filename, options);
24    if (!foundFile.empty())
25    {
26        XmlNode::Input input;
27        input.open(foundFile);
28        input.readAllDataIntoBuffer();
29
30        if (!input)
31        {
32            OSG_NOTICE<<"Could not open XML file: "<<filename<<std::endl;
33            return 0;
34        }
35
36        osg::ref_ptr<XmlNode> root = new XmlNode;
37        root->read(input);
38
39        return root.release();
40    }
41    else
42    {
43        OSG_NOTICE<<"Could not find XML file: "<<filename<<std::endl;
44        return 0;
45    }
46}
47
48std::string osgDB::trimEnclosingSpaces(const std::string& str)
49{
50    if (str.empty()) return str;
51
52    std::string::size_type start = str.find_first_not_of(' ');
53    if (start==std::string::npos) return std::string();
54
55    std::string::size_type end = str.find_last_not_of(' ');
56    if (end==std::string::npos) return std::string();
57
58    return std::string(str, start, (end-start)+1);
59}
60
61
62XmlNode* osgDB::readXmlStream(std::istream& fin)
63{
64    XmlNode::Input input;
65    input.attach(fin);
66    input.readAllDataIntoBuffer();
67
68    if (!input)
69    {
70        OSG_NOTICE<<"Could not attach to XML stream."<<std::endl;
71        return 0;
72    }
73
74    osg::ref_ptr<XmlNode> root = new XmlNode;
75    root->read(input);
76
77    return root.release();
78}
79
80XmlNode::ControlMap::ControlMap()
81{
82    setUpControlMappings();
83}
84
85void XmlNode::ControlMap::addControlToCharacter(const std::string& control, int c)
86{
87    _controlToCharacterMap[control] = c;
88    _characterToControlMap[c] = control;
89}
90
91void XmlNode::ControlMap::setUpControlMappings()
92{
93    addControlToCharacter("&amp;",'&');
94    addControlToCharacter("&lt;",'<');
95    addControlToCharacter("&gt;",'>');
96    addControlToCharacter("&quot;",'"');
97    addControlToCharacter("&apos;",'\'');
98}
99
100XmlNode::Input::Input():
101    _currentPos(0)
102{
103}
104
105XmlNode::Input::Input(const Input&):
106    ControlMap(),
107    _currentPos(0)
108{
109}
110
111XmlNode::Input::~Input()
112{
113}
114void XmlNode::Input::open(const std::string& filename)
115{
116    _fin.open(filename.c_str());
117}
118
119void XmlNode::Input::attach(std::istream& fin)
120{
121    std::ios &fios = _fin;
122    fios.rdbuf(fin.rdbuf());
123}
124
125void XmlNode::Input::readAllDataIntoBuffer()
126{
127    while(_fin)
128    {
129        int c = _fin.get();
130        if (c>=0 && c<=255)
131        {
132            _buffer.push_back(c);
133        }
134    }
135}
136
137void XmlNode::Input::skipWhiteSpace()
138{
139    while(_currentPos<_buffer.size() && (_buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t' || _buffer[_currentPos]=='\n' || _buffer[_currentPos]=='\r'))
140    {
141        //OSG_NOTICE<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<int(_buffer[_currentPos])<<std::endl;
142        ++_currentPos;
143    }
144    //OSG_NOTICE<<"done"<<std::endl;
145}
146
147XmlNode::XmlNode()
148{
149    type = UNASSIGNED;
150}
151
152bool XmlNode::read(Input& input)
153{
154    if (type == UNASSIGNED) type = ROOT;
155
156    while(input)
157    {
158        //input.skipWhiteSpace();
159        if (input.match("<!--"))
160        {
161            XmlNode* commentNode = new XmlNode;
162            commentNode->type = XmlNode::COMMENT;
163            children.push_back(commentNode);
164
165            input += 4;
166            XmlNode::Input::size_type end = input.find("-->");
167            commentNode->contents = input.substr(0, end);
168            if (end!=std::string::npos)
169            {
170                OSG_INFO<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
171                input += (end+3);
172            }
173            else
174            {
175                OSG_NOTICE<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
176                input += end;
177            }
178        }
179        else if (input.match("</"))
180        {
181            input += 2;
182            XmlNode::Input::size_type end = input.find(">");
183            std::string comment = input.substr(0, end);
184            if (end!=std::string::npos)
185            {
186                OSG_INFO<<"Valid end tag ["<<comment<<"]"<<std::endl;
187                input += (end+1);
188            }
189            else
190            {
191                OSG_NOTICE<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
192                input += end;
193            }
194
195            if (comment==name) { OSG_INFO<<"end tag is matched correctly"<<std::endl; }
196            else { OSG_NOTICE<<"Error: end tag is not matched correctly"<<std::endl; }
197
198            return true;
199        }
200        else if (input.match("<!DOCTYPE"))
201        {
202            XmlNode* commentNode = new XmlNode;
203            commentNode->type = XmlNode::INFORMATION;
204            children.push_back(commentNode);
205
206            ++input;
207            XmlNode::Input::size_type end = input.find(">");
208            commentNode->contents = input.substr(0, end);
209            if (end!=std::string::npos)
210            {
211                OSG_INFO<<"Valid infomation record ["<<commentNode->contents<<"]"<<std::endl;
212                input += (end+2);
213            }
214            else
215            {
216                OSG_NOTICE<<"Error: Unclosed infomation record ["<<commentNode->contents<<"]"<<std::endl;
217                input += end;
218            }
219        }
220        else if (input.match("<?"))
221        {
222            XmlNode* commentNode = new XmlNode;
223            commentNode->type = XmlNode::INFORMATION;
224            children.push_back(commentNode);
225
226            input += 2;
227            XmlNode::Input::size_type end = input.find("?>");
228            commentNode->contents = input.substr(0, end);
229            if (end!=std::string::npos)
230            {
231                OSG_INFO<<"Valid infomation record ["<<commentNode->contents<<"]"<<std::endl;
232                input += (end+2);
233            }
234            else
235            {
236                OSG_NOTICE<<"Error: Unclosed infomation record ["<<commentNode->contents<<"]"<<std::endl;
237                input += end;
238            }
239        }
240        else if (input.match("<"))
241        {
242            XmlNode* childNode = new XmlNode;
243            childNode->type = XmlNode::NODE;
244            children.push_back(childNode);
245
246            input += 1;
247
248            input.skipWhiteSpace();
249
250            int c = 0;
251            while ((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='>' && c!='/')
252            {
253                childNode->name.push_back(c);
254                ++input;
255            }
256
257            while ((c=input[0])>=0 && c!='>' && c!='/')
258            {
259                Input::size_type prev_pos = input.currentPosition();
260
261                input.skipWhiteSpace();
262                std::string option;
263                std::string value;
264
265                if (input[0]=='"')
266                {
267                    option.push_back(input[0]);
268                    ++input;
269                    while((c=input[0])>=0 && c!='"')
270                    {
271                        if (c=='&')
272                            readAndReplaceControl(option, input);
273                        else
274                        {
275                            option.push_back(c);
276                            ++input;
277                        }
278                    }
279                    option.push_back(input[0]);
280                    ++input;
281                }
282                else
283                {
284                    while((c=input[0])>=0 && c!='>' && c!='/' && c!='"' && c!='\'' && c!='=' && c!=' ' && c!='\n' && c!='\r')
285                    {
286                        option.push_back(c);
287                        ++input;
288                    }
289                }
290
291                input.skipWhiteSpace();
292                if (input[0]=='=')
293                {
294                    ++input;
295
296                    input.skipWhiteSpace();
297
298                    if (input[0]=='"')
299                    {
300                        ++input;
301                        while((c=input[0])>=0 && c!='"')
302                        {
303                            if (c=='&')
304                                readAndReplaceControl(value, input);
305                            else
306                            {
307                                value.push_back(c);
308                                ++input;
309                            }
310                        }
311                        ++input;
312                    }
313                    else if (input[0]=='\'')
314                    {
315                        ++input;
316                        while((c=input[0])>=0 && c!='\'')
317                        {
318                            if (c=='&')
319                                readAndReplaceControl(value, input);
320                            else
321                            {
322                                value.push_back(c);
323                                ++input;
324                            }
325                        }
326                        ++input;
327                    }
328                    else
329                    {
330                        ++input;
331                        while((c=input[0])>=0 && c!=' ' && c!='\n' && c!='\r' && c!='"' && c!='\'' && c!='>')
332                        {
333                            value.push_back(c);
334                            ++input;
335                        }
336                    }
337                }
338
339                if (prev_pos == input.currentPosition())
340                {
341                    OSG_NOTICE<<"Error, parser iterator not advanced, position: "<<input.substr(0,50)<<std::endl;
342                    ++input;
343                }
344
345                if (!option.empty())
346                {
347                    OSG_INFO<<"Assigning option "<<option<<" with value "<<value<<std::endl;
348                    childNode->properties[option] = value;
349                }
350            }
351
352            if ((c=input[0])>=0 && (c=='>' || c=='/'))
353            {
354                ++input;
355
356                OSG_INFO<<"Valid tag ["<<childNode->name<<"]"<<std::endl;
357
358                if (c=='/')
359                {
360                    if ((c=input[0])>=0 && c=='>')
361                    {
362                        ++input;
363                        OSG_INFO<<"tag is closed correctly"<<std::endl;
364                        childNode->type = ATOM;
365                    }
366                    else
367                        OSG_NOTICE<<"Error: tag is not closed correctly"<<std::endl;
368                }
369                else
370                {
371                    bool result = childNode->read(input);
372                    if (!result) return false;
373                }
374
375                if (type==NODE && !children.empty()) type = GROUP;
376            }
377            else
378            {
379                OSG_NOTICE<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
380                return false;
381            }
382
383        }
384        else
385        {
386            int c = input[0];
387
388            if (c=='&')
389            {
390                readAndReplaceControl(contents, input);
391            }
392            else
393            {
394                contents.push_back( c );
395                ++input;
396            }
397
398        }
399    }
400
401    if (type==NODE && !children.empty()) type = GROUP;
402    return false;
403}
404
405bool XmlNode::write(std::ostream& fout, const std::string& indent) const
406{
407    ControlMap controlMap;
408    return write(controlMap, fout, indent);
409}
410
411bool XmlNode::write(const ControlMap& controlMap, std::ostream& fout, const std::string& indent) const
412{
413    switch(type)
414    {
415        case(UNASSIGNED):
416            OSG_NOTICE<<"UNASSIGNED"<<std::endl;
417            return false;
418        case(ATOM):
419        {
420            fout<<indent<<"<"<<name;
421            writeProperties(controlMap, fout);
422            fout<<" />"<<std::endl;
423            return true;
424        }
425        case(ROOT):
426        {
427            writeChildren(controlMap, fout, indent);
428            return true;
429        }
430        case(NODE):
431            fout<<indent<<"<"<<name;
432            writeProperties(controlMap,fout);
433            fout<<">"; writeString(controlMap, fout, contents); fout<<"</"<<name<<">"<<std::endl;
434            return true;
435        case(GROUP):
436        {
437            fout<<indent<<"<"<<name;
438            writeProperties(controlMap,fout);
439            fout<<">"<<std::endl;
440
441            writeChildren(controlMap, fout, indent + "  ");
442
443            fout<<indent<<"</"<<name<<">"<<std::endl;
444            return true;
445        }
446        case(COMMENT):
447        {
448            fout<<indent<<"<!--"<<contents<<"-->"<<std::endl;
449            return true;
450        }
451        case(INFORMATION):
452        {
453            fout<<indent<<"<?"<<contents<<"?>"<<std::endl;
454            return true;
455        }
456    }
457    return false;
458}
459
460bool XmlNode::writeString(const ControlMap& controlMap, std::ostream& fout, const std::string& str) const
461{
462    for(std::string::const_iterator itr = str.begin();
463        itr != str.end();
464        ++itr)
465    {
466        int c = *itr;
467        ControlMap::CharacterToControlMap::const_iterator citr = controlMap._characterToControlMap.find(c);
468        if (citr != controlMap._characterToControlMap.end()) fout << citr->second;
469        else fout.put(c);
470    }
471    return true;
472}
473
474bool XmlNode::writeChildren(const ControlMap& controlMap, std::ostream& fout, const std::string& indent) const
475{
476    for(Children::const_iterator citr = children.begin();
477        citr != children.end();
478        ++citr)
479    {
480        if (!(*citr)->write(fout, indent))
481            return false;
482    }
483
484    return true;
485}
486
487bool XmlNode::writeProperties(const ControlMap& controlMap, std::ostream& fout) const
488{
489    for(Properties::const_iterator oitr = properties.begin();
490        oitr != properties.end();
491        ++oitr)
492    {
493        fout<<" "<<oitr->first<<"=\"";
494        if (!writeString(controlMap,fout,oitr->second))
495            return false;
496        fout<<"\"";
497    }
498
499    return true;
500}
501
502bool XmlNode::readAndReplaceControl(std::string& contents, XmlNode::Input& input)
503{
504    int c = 0;
505    std::string value;
506    while(input && (c=input.get())!=';') { value.push_back(c); }
507    value.push_back(c);
508
509    if (input._controlToCharacterMap.count(value)!=0)
510    {
511        c = input._controlToCharacterMap[value];
512        OSG_INFO<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
513        contents.push_back(c);
514        return true;
515    }
516    else
517    {
518        OSG_NOTICE<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
519        return false;
520    }
521}
Note: See TracBrowser for help on using the browser.