]> git.mxchange.org Git - simgear.git/blob - simgear/xml/easyxml.cxx
Added the ability to access the file name and position (line, column) from which...
[simgear.git] / simgear / xml / easyxml.cxx
1 /**
2  * \file easyxml.cxx - implementation of EasyXML interfaces.
3  * Written by David Megginson, 2000-2001
4  * This file is in the Public Domain, and comes with NO WARRANTY of any kind.
5  */
6
7 #ifdef HAVE_CONFIG_H
8 #  include <simgear_config.h>
9 #endif
10      
11 #include <simgear/compiler.h>
12
13 #include <string.h>             // strcmp()
14
15 #include "easyxml.hxx"
16      
17 #ifdef SYSTEM_EXPAT
18 #  include <expat.h>
19 #else
20 #  include "sg_expat.h"     
21 #endif
22      
23 #include <fstream>
24 #include <iostream>
25
26 using std::ifstream;
27
28
29 \f
30 ////////////////////////////////////////////////////////////////////////
31 // Implementation of XMLAttributes.
32 ////////////////////////////////////////////////////////////////////////
33
34 XMLAttributes::XMLAttributes ()
35 {
36 }
37
38 XMLAttributes::~XMLAttributes ()
39 {
40 }
41
42 int
43 XMLAttributes::findAttribute (const char * name) const
44 {
45   int s = size();
46   for (int i = 0; i < s; i++) {
47     if (strcmp(name, getName(i)) == 0)
48       return i;
49   }
50   return -1;
51 }
52
53 bool
54 XMLAttributes::hasAttribute (const char * name) const
55 {
56   return (findAttribute(name) != -1);
57 }
58
59 const char *
60 XMLAttributes::getValue (const char * name) const
61 {
62   int pos = findAttribute(name);
63   if (pos >= 0)
64     return getValue(pos);
65   else
66     return 0;
67 }
68
69 \f
70 ////////////////////////////////////////////////////////////////////////
71 // Implementation of XMLAttributesDefault.
72 ////////////////////////////////////////////////////////////////////////
73
74 XMLAttributesDefault::XMLAttributesDefault ()
75 {
76 }
77
78 XMLAttributesDefault::XMLAttributesDefault (const XMLAttributes &atts)
79 {
80   int s = atts.size();
81   for (int i = 0; i < s; i++)
82     addAttribute(atts.getName(i), atts.getValue(i));
83 }
84
85 XMLAttributesDefault::~XMLAttributesDefault ()
86 {
87 }
88
89 int
90 XMLAttributesDefault::size () const
91 {
92   return _atts.size() / 2;
93 }
94
95 const char *
96 XMLAttributesDefault::getName (int i) const
97 {
98   return _atts[i*2].c_str();
99 }
100
101 const char *
102 XMLAttributesDefault::getValue (int i) const
103 {
104   return _atts[i*2+1].c_str();
105 }
106
107 void
108 XMLAttributesDefault::addAttribute (const char * name, const char * value)
109 {
110   _atts.push_back(name);
111   _atts.push_back(value);
112 }
113
114 void
115 XMLAttributesDefault::setName (int i, const char * name)
116 {
117   _atts[i*2] = name;
118 }
119
120 void
121 XMLAttributesDefault::setValue (int i, const char * name)
122 {
123   _atts[i*2+1] = name;
124 }
125
126 void
127 XMLAttributesDefault::setValue (const char * name, const char * value)
128 {
129   int pos = findAttribute(name);
130   if (pos >= 0) {
131     setName(pos, name);
132     setValue(pos, value);
133   } else {
134     addAttribute(name, value);
135   }
136 }
137
138
139 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140
141 void XMLVisitor::savePosition(void)
142 {
143   column = XML_GetCurrentColumnNumber(parser);
144   line = XML_GetCurrentLineNumber(parser);
145 }
146
147 ////////////////////////////////////////////////////////////////////////
148 // Attribute list wrapper for Expat.
149 ////////////////////////////////////////////////////////////////////////
150
151 int
152 ExpatAtts::size () const
153 {
154   int s = 0;
155   for (int i = 0; _atts[i] != 0; i += 2)
156     s++;
157   return s;
158 }
159
160 const char *
161 ExpatAtts::getName (int i) const
162 {
163   return _atts[i*2];
164 }
165
166 const char *
167 ExpatAtts::getValue (int i) const
168 {
169   return _atts[i*2+1];
170 }
171
172 const char * 
173 ExpatAtts::getValue (const char * name) const
174 {
175   return XMLAttributes::getValue(name);
176 }
177
178 \f
179 ////////////////////////////////////////////////////////////////////////
180 // Static callback functions for Expat.
181 ////////////////////////////////////////////////////////////////////////
182
183 #define VISITOR (*((XMLVisitor *)userData))
184
185 static void
186 start_element (void * userData, const char * name, const char ** atts)
187 {
188   VISITOR.savePosition();
189   VISITOR.startElement(name, ExpatAtts(atts));
190 }
191
192 static void
193 end_element (void * userData, const char * name)
194 {
195   VISITOR.savePosition();
196   VISITOR.endElement(name);
197 }
198
199 static void
200 character_data (void * userData, const char * s, int len)
201 {
202   VISITOR.savePosition();
203   VISITOR.data(s, len);
204 }
205
206 static void
207 processing_instruction (void * userData,
208                         const char * target,
209                         const char * data)
210 {
211   VISITOR.savePosition();
212   VISITOR.pi(target, data);
213 }
214
215 #undef VISITOR
216
217
218 \f
219 ////////////////////////////////////////////////////////////////////////
220 // Implementation of XMLReader.
221 ////////////////////////////////////////////////////////////////////////
222
223 void
224 readXML (istream &input, XMLVisitor &visitor, const string &path)
225 {
226   XML_Parser parser = XML_ParserCreate(0);
227   XML_SetUserData(parser, &visitor);
228   XML_SetElementHandler(parser, start_element, end_element);
229   XML_SetCharacterDataHandler(parser, character_data);
230   XML_SetProcessingInstructionHandler(parser, processing_instruction);
231
232   visitor.setParser(parser);
233   visitor.setPath(path);
234   visitor.startXML();
235
236   char buf[16384];
237   while (!input.eof()) {
238
239                                 // FIXME: get proper error string from system
240     if (!input.good()) {
241       sg_io_exception ex ("Problem reading file",
242                             sg_location(path,
243                                         XML_GetCurrentLineNumber(parser),
244                                         XML_GetCurrentColumnNumber(parser)),
245                             "SimGear XML Parser");
246       visitor.setParser(0);
247       XML_ParserFree(parser);
248       throw ex;
249     }
250
251     input.read(buf,16384);
252     if (!XML_Parse(parser, buf, input.gcount(), false)) {
253       sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
254                             sg_location(path,
255                                         XML_GetCurrentLineNumber(parser),
256                                         XML_GetCurrentColumnNumber(parser)),
257                             "SimGear XML Parser");
258       visitor.setParser(0);
259       XML_ParserFree(parser);
260       throw ex;
261     }
262
263   }
264
265                                 // Verify end of document.
266   if (!XML_Parse(parser, buf, 0, true)) {
267     sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
268                           sg_location(path,
269                                       XML_GetCurrentLineNumber(parser),
270                                       XML_GetCurrentColumnNumber(parser)),
271                           "SimGear XML Parser");
272     visitor.setParser(0);
273     XML_ParserFree(parser);
274     throw ex;
275   }
276
277   visitor.setParser(0);
278   XML_ParserFree(parser);
279   visitor.endXML();
280 }
281
282 void
283 readXML (const string &path, XMLVisitor &visitor)
284 {
285   ifstream input(path.c_str());
286   if (input.good()) {
287     try {
288       readXML(input, visitor, path);
289     } catch (sg_io_exception &) {
290       input.close();
291       throw;
292     } catch (sg_throwable &) {
293       input.close();
294       throw;
295     }
296   } else {
297     throw sg_io_exception("Failed to open file", sg_location(path),
298                           "SimGear XML Parser");
299   }
300   input.close();
301 }
302
303 void
304 readXML (const char *buf, const int size, XMLVisitor &visitor)
305 {
306   XML_Parser parser = XML_ParserCreate(0);
307   XML_SetUserData(parser, &visitor);
308   XML_SetElementHandler(parser, start_element, end_element);
309   XML_SetCharacterDataHandler(parser, character_data);
310   XML_SetProcessingInstructionHandler(parser, processing_instruction);
311
312   visitor.startXML();
313
314   if (!XML_Parse(parser, buf, size, false)) {
315       sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
316                             sg_location("In-memory XML buffer",
317                                         XML_GetCurrentLineNumber(parser),
318                                         XML_GetCurrentColumnNumber(parser)),
319                             "SimGear XML Parser");
320       XML_ParserFree(parser);
321       throw ex;
322   }
323
324   XML_ParserFree(parser);
325   visitor.endXML();
326 }
327
328 // end of easyxml.cxx