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

Revision 10930, 13.0 kB (checked in by robert, 5 years ago)

Fixed writing out of ATOM.

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::notify(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::notify(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::notify(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
80
81XmlNode::Input::Input():
82    _currentPos(0)
83{
84    setUpControlMappings();
85}
86
87XmlNode::Input::Input(const Input&):
88    _currentPos(0)
89{
90    setUpControlMappings();
91}
92
93XmlNode::Input::~Input()
94{
95}
96
97void XmlNode::Input::setUpControlMappings()
98{
99    addControlToCharacter("&amp;",'&');
100    addControlToCharacter("&lt;",'<');
101    addControlToCharacter("&gt;",'>');
102    addControlToCharacter("&quot;",'"');
103    addControlToCharacter("&apos;",'\'');
104}
105
106void XmlNode::Input::addControlToCharacter(const std::string& control, int c)
107{
108    _controlToCharacterMap[control] = c;
109    _characterToControlMap[c] = control;
110}
111
112void XmlNode::Input::open(const std::string& filename)
113{
114    _fin.open(filename.c_str());
115}
116
117void XmlNode::Input::attach(std::istream& fin)
118{
119    std::ios &fios = _fin;
120    fios.rdbuf(fin.rdbuf());
121}
122
123void XmlNode::Input::readAllDataIntoBuffer()
124{
125    while(_fin)
126    {
127        int c = _fin.get();
128        if (c>=0 && c<=255)
129        {
130            _buffer.push_back(c);
131        }
132    }
133}
134
135void XmlNode::Input::skipWhiteSpace()
136{
137    while(_currentPos<_buffer.size() && (_buffer[_currentPos]==' ' || _buffer[_currentPos]=='\t'))
138    {
139        // osg::notify(osg::NOTICE)<<"_currentPos="<<_currentPos<<"_buffer.size()="<<_buffer.size()<<" v="<<_buffer[_currentPos]<<std::endl;
140        ++_currentPos;
141    }
142    //osg::notify(osg::NOTICE)<<"done"<<std::endl;
143}
144
145XmlNode::XmlNode()
146{
147    type = UNASSIGNED;
148}
149
150bool XmlNode::read(Input& input)
151{
152    if (type == UNASSIGNED) type = ROOT;
153
154    while(input)
155    {
156        //input.skipWhiteSpace();
157        if (input.match("<!--"))
158        {
159            XmlNode* commentNode = new XmlNode;
160            commentNode->type = XmlNode::COMMENT;
161            children.push_back(commentNode);
162
163            input += 4;
164            XmlNode::Input::size_type end = input.find("-->");
165            commentNode->contents = input.substr(0, end);
166            if (end!=std::string::npos)
167            {
168                osg::notify(osg::INFO)<<"Valid Comment record ["<<commentNode->contents<<"]"<<std::endl;
169                input += (end+3);
170            }
171            else
172            {
173                osg::notify(osg::NOTICE)<<"Error: Unclosed Comment record ["<<commentNode->contents<<"]"<<std::endl;
174                input += end;
175            }
176        }
177        else if (input.match("</"))
178        {
179            input += 2;
180            XmlNode::Input::size_type end = input.find(">");
181            std::string comment = input.substr(0, end);
182            if (end!=std::string::npos)
183            {
184                osg::notify(osg::INFO)<<"Valid end tag ["<<comment<<"]"<<std::endl;
185                input += (end+1);
186            }
187            else
188            {
189                osg::notify(osg::NOTICE)<<"Error: Unclosed end tag ["<<comment<<"]"<<std::endl;
190                input += end;
191            }
192
193            if (comment==name) osg::notify(osg::INFO)<<"end tag is matched correctly"<<std::endl;
194            else osg::notify(osg::NOTICE)<<"Error: end tag is not matched correctly"<<std::endl;
195
196            return true;
197        }
198        else if (input.match("<?"))
199        {
200            XmlNode* commentNode = new XmlNode;
201            commentNode->type = XmlNode::INFORMATION;
202            children.push_back(commentNode);
203
204            input += 2;
205            XmlNode::Input::size_type end = input.find("?>");
206            commentNode->contents = input.substr(0, end);
207            if (end!=std::string::npos)
208            {
209                osg::notify(osg::INFO)<<"Valid infomation record ["<<commentNode->contents<<"]"<<std::endl;
210                input += (end+2);
211            }
212            else
213            {
214                osg::notify(osg::NOTICE)<<"Error: Unclosed infomation record ["<<commentNode->contents<<"]"<<std::endl;
215                input += end;
216            }
217        }
218        else if (input.match("<"))
219        {
220            XmlNode* childNode = new XmlNode;
221            childNode->type = XmlNode::NODE;
222            children.push_back(childNode);
223
224            input += 1;
225
226            input.skipWhiteSpace();
227
228            int c = 0;
229            while ((c=input[0])>=0 && c!=' ' && c!='>' && c!='/')
230            {
231                childNode->name.push_back(c);
232                ++input;
233            }
234
235            while ((c=input[0])>=0 && c!='>' && c!='/')
236            {
237                Input::size_type prev_pos = input.currentPosition();
238
239                input.skipWhiteSpace();
240                std::string option;
241                std::string value;
242                while((c=input[0])>=0 && c!='>' && c!='/' && c!='"' && c!='\'' && c!='=' && c!=' ')
243                {
244                    option.push_back(c);
245                    ++input;
246                }
247                input.skipWhiteSpace();
248                if (input[0]=='=')
249                {
250                    ++input;
251
252                    input.skipWhiteSpace();
253
254                    if (input[0]=='"')
255                    {
256                        ++input;
257                        while((c=input[0])>=0 && c!='"')
258                        {
259                            value.push_back(c);
260                            ++input;
261                        }
262                        ++input;
263                    }
264                    else if (input[0]=='\'')
265                    {
266                        ++input;
267                        while((c=input[0])>=0 && c!='\'')
268                        {
269                            value.push_back(c);
270                            ++input;
271                        }
272                        ++input;
273                    }
274                    else
275                    {
276                        ++input;
277                        while((c=input[0])>=0 && c!=' ' && c!='"' && c!='\'' && c!='>')
278                        {
279                            value.push_back(c);
280                            ++input;
281                        }
282                    }
283                }
284
285                if (prev_pos == input.currentPosition())
286                {
287                    osg::notify(osg::NOTICE)<<"Error, parser iterator note advanced, position: "<<input.substr(0,50)<<std::endl;
288                    ++input;
289                }
290
291                if (!option.empty())
292                {
293                    osg::notify(osg::INFO)<<"Assigning option "<<option<<" with value "<<value<<std::endl;
294                    childNode->properties[option] = value;
295                }
296            }
297
298            if ((c=input[0])>=0 && (c=='>' || c=='/'))
299            {
300                ++input;
301
302                osg::notify(osg::INFO)<<"Valid tag ["<<childNode->name<<"]"<<std::endl;
303
304                if (c=='/')
305                {
306                    if ((c=input[0])>=0 && c=='>')
307                    {
308                        ++input;
309                        osg::notify(osg::INFO)<<"tag is closed correctly"<<std::endl;
310                    }
311                    else 
312                        osg::notify(osg::NOTICE)<<"Error: tag is not closed correctly"<<std::endl;
313                }
314                else
315                {
316                    bool result = childNode->read(input);
317                    if (!result) return false;
318                }
319
320                if (type==NODE && !children.empty()) type = GROUP;
321            }
322            else
323            {
324                osg::notify(osg::NOTICE)<<"Unclosed tag ["<<childNode->name<<"]"<<std::endl;
325                return false;
326            }
327
328        }
329        else
330        {
331            int c = input[0];
332
333            if (c=='&')
334            {
335                std::string value;
336                while(input && (c=input.get())!=';') { value.push_back(c); }
337                value.push_back(c);
338
339                if (input._controlToCharacterMap.count(value)!=0)
340                {
341                    c = input._controlToCharacterMap[value];
342                    osg::notify(osg::INFO)<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
343                    contents.push_back(c);
344                }
345                else
346                {
347                    osg::notify(osg::NOTICE)<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
348                }
349            }
350            else
351            {
352                contents.push_back( c );
353                ++input;
354            }
355
356        }
357    }
358
359    if (type==NODE && !children.empty()) type = GROUP;
360    return false;
361}
362
363bool XmlNode::write(std::ostream& fout) const
364{
365    switch(type)
366    {
367        case(UNASSIGNED):
368            return false;
369        case(ATOM):
370        {
371            fout<<"<"<<name;
372            for(Properties::const_iterator oitr = properties.begin();
373                oitr != properties.end();
374                ++oitr)
375            {
376                fout<<oitr->first<<"\"";
377                writeString(fout,oitr->second);
378                fout<<"\""<<std::endl;
379            }
380            return true;
381            fout<<" />"<<std::endl;
382        }
383        case(ROOT):
384        {
385            for(Children::const_iterator citr = children.begin();
386                citr != children.end();
387                ++citr)
388            {
389                (*citr)->write(fout);
390            }
391            return true;
392        }
393        case(NODE):
394        {
395            fout<<"<"<<name;
396            for(Properties::const_iterator oitr = properties.begin();
397                oitr != properties.end();
398                ++oitr)
399            {
400                fout<<" "<<oitr->first<<"=\"";
401                writeString(fout,oitr->second);
402                fout<<"\"";
403            }
404
405            if (children.empty() && contents.empty())
406            {
407                fout<<" />"<<std::endl;
408            }
409            else
410            {
411                fout<<">";
412                for(Children::const_iterator citr = children.begin();
413                    citr != children.end();
414                    ++citr)
415                {
416                    (*citr)->write(fout);
417                }
418
419                if (!contents.empty()) writeString(fout,contents);
420
421                fout<<"</"<<name<<">"<<std::endl;
422            }
423            return true;
424        }
425        case(GROUP):
426        {
427            fout<<"<"<<name;
428            for(Properties::const_iterator oitr = properties.begin();
429                oitr != properties.end();
430                ++oitr)
431            {
432                fout<<" "<<oitr->first<<"=\"";
433                writeString(fout,oitr->second);
434                fout<<"\"";
435            }
436            fout<<">"<<std::endl;
437
438            for(Children::const_iterator citr = children.begin();
439                citr != children.end();
440                ++citr)
441            {
442                (*citr)->write(fout);
443            }
444
445            fout<<"</"<<name<<">"<<std::endl;
446            return true;
447        }
448        case(COMMENT):
449        {
450            fout<<"<!--"<<contents<<"-->"<<std::endl;
451            return true;
452        }
453        case(INFORMATION):
454        {
455            fout<<"<?"<<contents<<"?>"<<std::endl;
456            return true;
457        }
458    }
459    return false;
460}
461
462bool XmlNode::writeString(std::ostream& fout, const std::string& str) const
463{
464    fout<<str;
465    return true;
466}
Note: See TracBrowser for help on using the browser.