]> git.mxchange.org Git - simgear.git/blob - simgear/xml/easyxml.cxx
Patch from Erik Hofman:
[simgear.git] / simgear / xml / easyxml.cxx
1 // easyxml.cxx - implementation of EasyXML interfaces.
2
3 #include <simgear/compiler.h>
4
5 #include <string.h>             // strcmp()
6
7 #include "easyxml.hxx"
8 #include "xmlparse.h"
9
10 #include STL_FSTREAM
11
12 SG_USING_STD(ifstream);
13
14
15 \f
16 ////////////////////////////////////////////////////////////////////////
17 // Implementation of XMLAttributes.
18 ////////////////////////////////////////////////////////////////////////
19
20 XMLAttributes::XMLAttributes ()
21 {
22 }
23
24 XMLAttributes::~XMLAttributes ()
25 {
26 }
27
28 int
29 XMLAttributes::findAttribute (const char * name) const
30 {
31   int s = size();
32   for (int i = 0; i < s; i++) {
33     if (strcmp(name, getName(i)) == 0)
34       return i;
35   }
36   return -1;
37 }
38
39 bool
40 XMLAttributes::hasAttribute (const char * name) const
41 {
42   return (findAttribute(name) != -1);
43 }
44
45 const char *
46 XMLAttributes::getValue (const char * name) const
47 {
48   int pos = findAttribute(name);
49   if (pos >= 0)
50     return getValue(pos);
51   else
52     return 0;
53 }
54
55 \f
56 ////////////////////////////////////////////////////////////////////////
57 // Implementation of XMLAttributesDefault.
58 ////////////////////////////////////////////////////////////////////////
59
60 XMLAttributesDefault::XMLAttributesDefault ()
61 {
62 }
63
64 XMLAttributesDefault::XMLAttributesDefault (const XMLAttributes &atts)
65 {
66   int s = atts.size();
67   for (int i = 0; i < s; i++)
68     addAttribute(atts.getName(i), atts.getValue(i));
69 }
70
71 XMLAttributesDefault::~XMLAttributesDefault ()
72 {
73 }
74
75 int
76 XMLAttributesDefault::size () const
77 {
78   return _atts.size() / 2;
79 }
80
81 const char *
82 XMLAttributesDefault::getName (int i) const
83 {
84   return _atts[i*2].c_str();
85 }
86
87 const char *
88 XMLAttributesDefault::getValue (int i) const
89 {
90   return _atts[i*2+1].c_str();
91 }
92
93 void
94 XMLAttributesDefault::addAttribute (const char * name, const char * value)
95 {
96   _atts.push_back(name);
97   _atts.push_back(value);
98 }
99
100 void
101 XMLAttributesDefault::setName (int i, const char * name)
102 {
103   _atts[i*2] = name;
104 }
105
106 void
107 XMLAttributesDefault::setValue (int i, const char * name)
108 {
109   _atts[i*2+1] = name;
110 }
111
112 void
113 XMLAttributesDefault::setValue (const char * name, const char * value)
114 {
115   int pos = findAttribute(name);
116   if (pos >= 0) {
117     setName(pos, name);
118     setValue(pos, value);
119   } else {
120     addAttribute(name, value);
121   }
122 }
123
124
125 \f
126 ////////////////////////////////////////////////////////////////////////
127 // Attribute list wrapper for Expat.
128 ////////////////////////////////////////////////////////////////////////
129
130 class ExpatAtts : public XMLAttributes
131 {
132 public:
133   ExpatAtts (const char ** atts) : _atts(atts) {}
134   
135   virtual int size () const;
136   virtual const char * getName (int i) const;
137   virtual const char * getValue (int i) const;
138   
139 private:
140   const char ** _atts;
141 };
142
143 int
144 ExpatAtts::size () const
145 {
146   int s = 0;
147   for (int i = 0; _atts[i] != 0; i += 2)
148     s++;
149   return s;
150 }
151
152 const char *
153 ExpatAtts::getName (int i) const
154 {
155   return _atts[i*2];
156 }
157
158 const char *
159 ExpatAtts::getValue (int i) const
160 {
161   return _atts[i*2+1];
162 }
163
164
165 \f
166 ////////////////////////////////////////////////////////////////////////
167 // Static callback functions for Expat.
168 ////////////////////////////////////////////////////////////////////////
169
170 #define VISITOR (*((XMLVisitor *)userData))
171
172 static void
173 start_element (void * userData, const char * name, const char ** atts)
174 {
175   VISITOR.startElement(name, ExpatAtts(atts));
176 }
177
178 static void
179 end_element (void * userData, const char * name)
180 {
181   VISITOR.endElement(name);
182 }
183
184 static void
185 character_data (void * userData, const char * s, int len)
186 {
187   VISITOR.data(s, len);
188 }
189
190 static void
191 processing_instruction (void * userData,
192                         const char * target,
193                         const char * data)
194 {
195   VISITOR.pi(target, data);
196 }
197
198 #undef VISITOR
199
200
201 \f
202 ////////////////////////////////////////////////////////////////////////
203 // Implementation of XMLReader.
204 ////////////////////////////////////////////////////////////////////////
205
206 void
207 readXML (istream &input, XMLVisitor &visitor, const string &path)
208 {
209   XML_Parser parser = XML_ParserCreate(0);
210   XML_SetUserData(parser, &visitor);
211   XML_SetElementHandler(parser, start_element, end_element);
212   XML_SetCharacterDataHandler(parser, character_data);
213   XML_SetProcessingInstructionHandler(parser, processing_instruction);
214
215   visitor.startXML();
216
217   char buf[16384];
218   while (!input.eof()) {
219
220                                 // FIXME: get proper error string from system
221     if (!input.good()) {
222       XML_ParserFree(parser);
223       throw sg_io_exception("Problem reading file",
224                             sg_location(path,
225                                         XML_GetCurrentLineNumber(parser),
226                                         XML_GetCurrentColumnNumber(parser)),
227                             "SimGear XML Parser");
228     }
229
230     input.read(buf,16384);
231     if (!XML_Parse(parser, buf, input.gcount(), false)) {
232       XML_ParserFree(parser);
233       throw sg_io_exception(XML_ErrorString(XML_GetErrorCode(parser)),
234                             sg_location(path,
235                                         XML_GetCurrentLineNumber(parser),
236                                         XML_GetCurrentColumnNumber(parser)),
237                             "SimGear XML Parser");
238     }
239
240   }
241
242                                 // Verify end of document.
243   if (!XML_Parse(parser, buf, 0, true)) {
244     XML_ParserFree(parser);
245     throw sg_io_exception(XML_ErrorString(XML_GetErrorCode(parser)),
246                           sg_location(path,
247                                       XML_GetCurrentLineNumber(parser),
248                                       XML_GetCurrentColumnNumber(parser)),
249                           "SimGear XML Parser");
250   }
251
252   XML_ParserFree(parser);
253 }
254
255 void
256 readXML (const string &path, XMLVisitor &visitor)
257 {
258   ifstream input(path.c_str());
259   if (input.good()) {
260     try {
261       readXML(input, visitor, path);
262     } catch (sg_io_exception &e) {
263       input.close();
264       throw e;
265     } catch (sg_throwable &t) {
266       input.close();
267       throw t;
268     }
269   } else {
270     throw sg_io_exception("Failed to open file", sg_location(path),
271                           "SimGear XML Parser");
272   }
273   input.close();
274 }
275
276 // end of easyxml.cxx