]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props_io.cxx
Changes for the native Irix CC compiler contributed by Erik Hofman.
[simgear.git] / simgear / misc / props_io.cxx
1
2 #ifdef HAVE_CONFIG_H
3 #  include <config.h>
4 #endif
5
6 #include <simgear/compiler.h>
7
8 #include <stdlib.h>             // atof() atoi()
9
10 #include <simgear/debug/logstream.hxx>
11 #include <simgear/xml/easyxml.hxx>
12
13 #include "props.hxx"
14
15 #include STL_IOSTREAM
16 #if !defined(FG_HAVE_NATIVE_SGI_COMPILERS)
17 #  include <fstream>
18 #else
19 #  include <fstream.h>
20 #endif
21 #include STL_STRING
22 #include <vector>
23
24 #if !defined(FG_HAVE_NATIVE_SGI_COMPILERS)
25 FG_USING_STD(istream);
26 FG_USING_STD(ifstream);
27 FG_USING_STD(ostream);
28 FG_USING_STD(ofstream);
29 #endif
30 FG_USING_STD(string);
31 FG_USING_STD(vector);
32
33
34 \f
35 ////////////////////////////////////////////////////////////////////////
36 // Property list visitor, for XML parsing.
37 ////////////////////////////////////////////////////////////////////////
38
39 class PropsVisitor : public XMLVisitor
40 {
41 public:
42
43   PropsVisitor (SGPropertyNode * root) : _ok(true), _root(root), _level(0) {}
44
45   void startXML ();
46   void endXML ();
47   void startElement (const char * name, const XMLAttributes &atts);
48   void endElement (const char * name);
49   void data (const char * s, int length);
50   void warning (const char * message, int line, int column);
51   void error (const char * message, int line, int column);
52
53   bool isOK () const { return _ok; }
54
55 private:
56
57   struct State
58   {
59     State () : node(0), type("") {}
60     State (SGPropertyNode * _node, const char * _type)
61       : node(_node), type(_type) {}
62     SGPropertyNode * node;
63     string type;
64   };
65
66   State &state () { return _state_stack[_state_stack.size() - 1]; }
67
68   void push_state (SGPropertyNode * node, const char * type) {
69     if (type == 0)
70       _state_stack.push_back(State(node, "unknown"));
71     else
72       _state_stack.push_back(State(node, type));
73     _level++;
74     _data = "";
75   }
76
77   void pop_state () {
78     _state_stack.pop_back();
79     _level--;
80   }
81
82   bool _ok;
83   string _data;
84   SGPropertyNode * _root;
85   int _level;
86   vector<State> _state_stack;
87
88 };
89
90 void
91 PropsVisitor::startXML ()
92 {
93   _level = 0;
94   _state_stack.resize(0);
95 }
96
97 void
98 PropsVisitor::endXML ()
99 {
100   _level = 0;
101   _state_stack.resize(0);
102 }
103
104 void
105 PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
106 {
107   if (_level == 0) {
108     push_state(_root, "");
109   }
110
111   else {
112     const char * att_n = atts.getValue("n");
113     int index = 0;
114     if (att_n != 0)
115       index = atoi(att_n);
116     push_state(state().node->getChild(name, index, true),
117                atts.getValue("type"));
118   }
119 }
120
121 void
122 PropsVisitor::endElement (const char * name)
123 {
124   State &st = state();
125   bool ret;
126
127                                 // If there are no children, then
128                                 // it is a leaf value.
129   if (st.node->nChildren() == 0) {
130     if (st.type == "bool") {
131       if (_data == "true" || atoi(_data.c_str()) != 0)
132         ret = st.node->setBoolValue(true);
133       else
134         ret = st.node->setBoolValue(false);
135     } else if (st.type == "int") {
136       ret = st.node->setIntValue(atoi(_data.c_str()));
137     } else if (st.type == "float") {
138       ret = st.node->setFloatValue(atof(_data.c_str()));
139     } else if (st.type == "double") {
140       ret = st.node->setDoubleValue(atof(_data.c_str()));
141     } else if (st.type == "string") {
142       ret = st.node->setStringValue(_data);
143     } else if (st.type == "unknown") {
144       ret = st.node->setUnknownValue(_data);
145     } else {
146       FG_LOG(FG_INPUT, FG_ALERT, "Unknown data type " << st.type
147              << " assuming 'unknown'");
148       ret = st.node->setUnknownValue(_data);
149     }
150     if (!ret)
151       FG_LOG(FG_INPUT, FG_ALERT, "readProperties: Failed to set "
152              << st.node->getPath() << " to value \""
153              << _data << "\" with type " << st.type);
154   }
155
156   pop_state();
157 }
158
159 void
160 PropsVisitor::data (const char * s, int length)
161 {
162   if (state().node->nChildren() == 0)
163     _data.append(string(s, length));
164 }
165
166 void
167 PropsVisitor::warning (const char * message, int line, int column)
168 {
169   FG_LOG(FG_INPUT, FG_ALERT, "readProperties: warning: "
170          << message << " at line " << line << ", column " << column);
171 }
172
173 void
174 PropsVisitor::error (const char * message, int line, int column)
175 {
176   FG_LOG(FG_INPUT, FG_ALERT, "readProperties: FATAL: "
177          << message << " at line " << line << ", column " << column);
178   _ok = false;
179 }
180
181
182 \f
183 ////////////////////////////////////////////////////////////////////////
184 // Property list reader.
185 ////////////////////////////////////////////////////////////////////////
186
187 bool
188 readProperties (istream &input, SGPropertyNode * start_node)
189 {
190   PropsVisitor visitor(start_node);
191   return readXML(input, visitor) && visitor.isOK();
192 }
193
194 bool
195 readProperties (const string &file, SGPropertyNode * start_node)
196 {
197   ifstream input(file.c_str());
198   if (input.good()) {
199     return readProperties(input, start_node);
200   } else {
201     FG_LOG(FG_INPUT, FG_ALERT, "Error reading property list from file "
202            << file);
203     return false;
204   }
205 }
206
207
208 \f
209 ////////////////////////////////////////////////////////////////////////
210 // Property list writer.
211 ////////////////////////////////////////////////////////////////////////
212
213 #define INDENT_STEP 2
214
215 /**
216  * Return the type name.
217  */
218 static const char *
219 getTypeName (SGValue::Type type)
220 {
221   switch (type) {
222   case SGValue::UNKNOWN:
223     return "unknown";
224   case SGValue::BOOL:
225     return "bool";
226   case SGValue::INT:
227     return "int";
228   case SGValue::FLOAT:
229     return "float";
230   case SGValue::DOUBLE:
231     return "double";
232   case SGValue::STRING:
233     return "string";
234   }
235 }
236
237
238 /**
239  * Escape characters for output.
240  */
241 static void
242 writeData (ostream &output, const string &data)
243 {
244   for (int i = 0; i < data.size(); i++) {
245     switch (data[i]) {
246     case '&':
247       output << "&amp;";
248       break;
249     case '<':
250       output << "&lt;";
251       break;
252     case '>':
253       output << "&gt;";
254       break;
255     default:
256       output << data[i];
257       break;
258     }
259   }
260 }
261
262 static void
263 doIndent (ostream &output, int indent)
264 {
265   while (indent-- > 0) {
266     output << ' ';
267   }
268 }
269
270
271 static bool
272 writeNode (ostream &output, const SGPropertyNode * node, int indent)
273 {
274   const string &name = node->getName();
275   int index = node->getIndex();
276   int nChildren = node->nChildren();
277
278                                 // If there is a literal value,
279                                 // write it first.
280   if (node->hasValue()) {
281     doIndent(output, indent);
282     output << '<' << name << " n=\"" << index
283            << "\" type=\"" << getTypeName(node->getType()) << "\">";
284     writeData(output, node->getStringValue());
285     output << "</" << name << '>' << endl;;
286   }
287
288                                 // If there are children, write them
289                                 // next.
290   if (nChildren > 0) {
291     doIndent(output, indent);
292     output << '<' << name << " n=\"" << index << "\">" << endl;;
293     for (int i = 0; i < nChildren; i++)
294       writeNode(output, node->getChild(i), indent + INDENT_STEP);
295     doIndent(output, indent);
296     output << "</" << name << '>' << endl;
297   }
298
299                                 // If there were no children and no
300                                 // value, at least note the presence
301                                 // of the node.
302   if (nChildren == 0 && !node->hasValue()) {
303     doIndent(output, indent);
304     output << '<' << name << " n=\"" << index << "\"/>" << endl;
305   }
306
307   return true;
308 }
309
310 bool
311 writeProperties (ostream &output, const SGPropertyNode * start_node)
312 {
313   int nChildren = start_node->nChildren();
314
315   output << "<?xml version=\"1.0\"?>" << endl << endl;
316   output << "<PropertyList>" << endl;
317
318   for (int i = 0; i < nChildren; i++) {
319     writeNode(output, start_node->getChild(i), INDENT_STEP);
320   }
321
322   output << "</PropertyList>" << endl;
323
324   return true;
325 }
326
327 bool
328 writeProperties (const string &file, const SGPropertyNode * start_node)
329 {
330   ofstream output(file.c_str());
331   if (output.good()) {
332     return writeProperties(output, start_node);
333   } else {
334     FG_LOG(FG_INPUT, FG_ALERT, "Cannot write properties to file "
335            << file);
336     return false;
337   }
338 }
339
340
341 /**
342  * Copy one property list to another.
343  */
344 bool
345 copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
346 {
347   bool retval = true;
348
349                                 // First, copy the actual value,
350                                 // if any.
351   if (in->hasValue()) {
352     switch (in->getType()) {
353     case SGValue::BOOL:
354       if (!out->setBoolValue(in->getBoolValue()))
355         retval = false;
356       break;
357     case SGValue::INT:
358       if (!out->setIntValue(in->getIntValue()))
359         retval = false;
360       break;
361     case SGValue::FLOAT:
362       if (!out->setFloatValue(in->getFloatValue()))
363         retval = false;
364       break;
365     case SGValue::DOUBLE:
366       if (!out->setDoubleValue(in->getDoubleValue()))
367         retval = false;
368       break;
369     case SGValue::STRING:
370       if (!out->setStringValue(in->getStringValue()))
371         retval = false;
372       break;
373     case SGValue::UNKNOWN:
374       if (!out->setUnknownValue(in->getStringValue()))
375         retval = false;
376       break;
377     default:
378       throw string("Unknown SGValue type"); // FIXME!!!
379     }
380   }
381
382                                 // Next, copy the children.
383   int nChildren = in->nChildren();
384   for (int i = 0; i < nChildren; i++) {
385     const SGPropertyNode * in_child = in->getChild(i);
386     SGPropertyNode * out_child = out->getChild(in_child->getName(),
387                                                in_child->getIndex(),
388                                                true);
389     if (!copyProperties(in_child, out_child))
390       retval = false;
391   }
392
393   return retval;
394 }
395
396 // end of props_io.cxx