]> git.mxchange.org Git - simgear.git/blob - simgear/xml/easyxml.cxx
Option to use system, instead of built-in, expat
[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 "xmlparse.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 \f
140 ////////////////////////////////////////////////////////////////////////
141 // Attribute list wrapper for Expat.
142 ////////////////////////////////////////////////////////////////////////
143
144 class ExpatAtts : public XMLAttributes
145 {
146 public:
147   ExpatAtts (const char ** atts) : _atts(atts) {}
148   
149   virtual int size () const;
150   virtual const char * getName (int i) const;
151   virtual const char * getValue (int i) const;
152   
153 private:
154   const char ** _atts;
155 };
156
157 int
158 ExpatAtts::size () const
159 {
160   int s = 0;
161   for (int i = 0; _atts[i] != 0; i += 2)
162     s++;
163   return s;
164 }
165
166 const char *
167 ExpatAtts::getName (int i) const
168 {
169   return _atts[i*2];
170 }
171
172 const char *
173 ExpatAtts::getValue (int i) const
174 {
175   return _atts[i*2+1];
176 }
177
178
179 \f
180 ////////////////////////////////////////////////////////////////////////
181 // Static callback functions for Expat.
182 ////////////////////////////////////////////////////////////////////////
183
184 #define VISITOR (*((XMLVisitor *)userData))
185
186 static void
187 start_element (void * userData, const char * name, const char ** atts)
188 {
189   VISITOR.startElement(name, ExpatAtts(atts));
190 }
191
192 static void
193 end_element (void * userData, const char * name)
194 {
195   VISITOR.endElement(name);
196 }
197
198 static void
199 character_data (void * userData, const char * s, int len)
200 {
201   VISITOR.data(s, len);
202 }
203
204 static void
205 processing_instruction (void * userData,
206                         const char * target,
207                         const char * data)
208 {
209   VISITOR.pi(target, data);
210 }
211
212 #undef VISITOR
213
214
215 \f
216 ////////////////////////////////////////////////////////////////////////
217 // Implementation of XMLReader.
218 ////////////////////////////////////////////////////////////////////////
219
220 void
221 readXML (istream &input, XMLVisitor &visitor, const string &path)
222 {
223   XML_Parser parser = XML_ParserCreate(0);
224   XML_SetUserData(parser, &visitor);
225   XML_SetElementHandler(parser, start_element, end_element);
226   XML_SetCharacterDataHandler(parser, character_data);
227   XML_SetProcessingInstructionHandler(parser, processing_instruction);
228
229   visitor.startXML();
230
231   char buf[16384];
232   while (!input.eof()) {
233
234                                 // FIXME: get proper error string from system
235     if (!input.good()) {
236       sg_io_exception ex ("Problem reading file",
237                             sg_location(path,
238                                         XML_GetCurrentLineNumber(parser),
239                                         XML_GetCurrentColumnNumber(parser)),
240                             "SimGear XML Parser");
241       XML_ParserFree(parser);
242       throw ex;
243     }
244
245     input.read(buf,16384);
246     if (!XML_Parse(parser, buf, input.gcount(), false)) {
247       sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
248                             sg_location(path,
249                                         XML_GetCurrentLineNumber(parser),
250                                         XML_GetCurrentColumnNumber(parser)),
251                             "SimGear XML Parser");
252       XML_ParserFree(parser);
253       throw ex;
254     }
255
256   }
257
258                                 // Verify end of document.
259   if (!XML_Parse(parser, buf, 0, true)) {
260     sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
261                           sg_location(path,
262                                       XML_GetCurrentLineNumber(parser),
263                                       XML_GetCurrentColumnNumber(parser)),
264                           "SimGear XML Parser");
265     XML_ParserFree(parser);
266     throw ex;
267   }
268
269   XML_ParserFree(parser);
270   visitor.endXML();
271 }
272
273 void
274 readXML (const string &path, XMLVisitor &visitor)
275 {
276   ifstream input(path.c_str());
277   if (input.good()) {
278     try {
279       readXML(input, visitor, path);
280     } catch (sg_io_exception &) {
281       input.close();
282       throw;
283     } catch (sg_throwable &) {
284       input.close();
285       throw;
286     }
287   } else {
288     throw sg_io_exception("Failed to open file", sg_location(path),
289                           "SimGear XML Parser");
290   }
291   input.close();
292 }
293
294 void
295 readXML (const char *buf, const int size, XMLVisitor &visitor)
296 {
297   XML_Parser parser = XML_ParserCreate(0);
298   XML_SetUserData(parser, &visitor);
299   XML_SetElementHandler(parser, start_element, end_element);
300   XML_SetCharacterDataHandler(parser, character_data);
301   XML_SetProcessingInstructionHandler(parser, processing_instruction);
302
303   visitor.startXML();
304
305   if (!XML_Parse(parser, buf, size, false)) {
306       sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
307                             sg_location("In-memory XML buffer",
308                                         XML_GetCurrentLineNumber(parser),
309                                         XML_GetCurrentColumnNumber(parser)),
310                             "SimGear XML Parser");
311       XML_ParserFree(parser);
312       throw ex;
313   }
314
315   XML_ParserFree(parser);
316   visitor.endXML();
317 }
318
319 // end of easyxml.cxx