6 #include <simgear/compiler.h>
8 #include <stdlib.h> // atof() atoi()
10 #include <simgear/debug/logstream.hxx>
11 #include <simgear/xml/easyxml.hxx>
16 #if !defined(FG_HAVE_NATIVE_SGI_COMPILERS)
25 #if !defined(FG_HAVE_NATIVE_SGI_COMPILERS)
26 FG_USING_STD(istream);
27 FG_USING_STD(ifstream);
28 FG_USING_STD(ostream);
29 FG_USING_STD(ofstream);
37 ////////////////////////////////////////////////////////////////////////
38 // Property list visitor, for XML parsing.
39 ////////////////////////////////////////////////////////////////////////
41 class PropsVisitor : public XMLVisitor
45 PropsVisitor (SGPropertyNode * root) : _ok(true), _root(root), _level(0) {}
49 void startElement (const char * name, const XMLAttributes &atts);
50 void endElement (const char * name);
51 void data (const char * s, int length);
52 void warning (const char * message, int line, int column);
53 void error (const char * message, int line, int column);
55 bool isOK () const { return _ok; }
61 State () : node(0), type("") {}
62 State (SGPropertyNode * _node, const char * _type)
63 : node(_node), type(_type) {}
64 SGPropertyNode * node;
66 map<string,int> counters;
69 State &state () { return _state_stack[_state_stack.size() - 1]; }
71 void push_state (SGPropertyNode * node, const char * type) {
73 _state_stack.push_back(State(node, "unknown"));
75 _state_stack.push_back(State(node, type));
81 _state_stack.pop_back();
87 SGPropertyNode * _root;
89 vector<State> _state_stack;
94 PropsVisitor::startXML ()
97 _state_stack.resize(0);
101 PropsVisitor::endXML ()
104 _state_stack.resize(0);
108 PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
113 push_state(_root, "");
117 const char * att_n = atts.getValue("n");
121 st.counters[name] = max(st.counters[name], index+1);
123 index = st.counters[name];
126 push_state(st.node->getChild(name, index, true),
127 atts.getValue("type"));
132 PropsVisitor::endElement (const char * name)
137 // If there are no children, then
138 // it is a leaf value.
139 if (st.node->nChildren() == 0) {
140 if (st.type == "bool") {
141 if (_data == "true" || atoi(_data.c_str()) != 0)
142 ret = st.node->setBoolValue(true);
144 ret = st.node->setBoolValue(false);
145 } else if (st.type == "int") {
146 ret = st.node->setIntValue(atoi(_data.c_str()));
147 } else if (st.type == "float") {
148 ret = st.node->setFloatValue(atof(_data.c_str()));
149 } else if (st.type == "double") {
150 ret = st.node->setDoubleValue(atof(_data.c_str()));
151 } else if (st.type == "string") {
152 ret = st.node->setStringValue(_data);
153 } else if (st.type == "unknown") {
154 ret = st.node->setUnknownValue(_data);
156 FG_LOG(FG_INPUT, FG_ALERT, "Unknown data type " << st.type
157 << " assuming 'unknown'");
158 ret = st.node->setUnknownValue(_data);
161 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: Failed to set "
162 << st.node->getPath() << " to value \""
163 << _data << "\" with type " << st.type);
170 PropsVisitor::data (const char * s, int length)
172 if (state().node->nChildren() == 0)
173 _data.append(string(s, length));
177 PropsVisitor::warning (const char * message, int line, int column)
179 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: warning: "
180 << message << " at line " << line << ", column " << column);
184 PropsVisitor::error (const char * message, int line, int column)
186 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: FATAL: "
187 << message << " at line " << line << ", column " << column);
193 ////////////////////////////////////////////////////////////////////////
194 // Property list reader.
195 ////////////////////////////////////////////////////////////////////////
198 readProperties (istream &input, SGPropertyNode * start_node)
200 PropsVisitor visitor(start_node);
201 return readXML(input, visitor) && visitor.isOK();
205 readProperties (const string &file, SGPropertyNode * start_node)
207 ifstream input(file.c_str());
209 return readProperties(input, start_node);
211 FG_LOG(FG_INPUT, FG_ALERT, "Error reading property list from file "
219 ////////////////////////////////////////////////////////////////////////
220 // Property list writer.
221 ////////////////////////////////////////////////////////////////////////
223 #define INDENT_STEP 2
226 * Return the type name.
229 getTypeName (SGValue::Type type)
232 case SGValue::UNKNOWN:
240 case SGValue::DOUBLE:
242 case SGValue::STRING:
246 // keep the compiler from squawking
252 * Escape characters for output.
255 writeData (ostream &output, const string &data)
257 for (int i = 0; i < (int)data.size(); i++) {
276 doIndent (ostream &output, int indent)
278 while (indent-- > 0) {
285 writeNode (ostream &output, const SGPropertyNode * node, int indent)
287 const string &name = node->getName();
288 int index = node->getIndex();
289 int nChildren = node->nChildren();
291 // If there is a literal value,
293 if (node->hasValue()) {
294 doIndent(output, indent);
295 output << '<' << name << " n=\"" << index
296 << "\" type=\"" << getTypeName(node->getType()) << "\">";
297 writeData(output, node->getStringValue());
298 output << "</" << name << '>' << endl;;
301 // If there are children, write them
304 doIndent(output, indent);
305 output << '<' << name << " n=\"" << index << "\">" << endl;;
306 for (int i = 0; i < nChildren; i++)
307 writeNode(output, node->getChild(i), indent + INDENT_STEP);
308 doIndent(output, indent);
309 output << "</" << name << '>' << endl;
312 // If there were no children and no
313 // value, at least note the presence
315 if (nChildren == 0 && !node->hasValue()) {
316 doIndent(output, indent);
317 output << '<' << name << " n=\"" << index << "\"/>" << endl;
324 writeProperties (ostream &output, const SGPropertyNode * start_node)
326 int nChildren = start_node->nChildren();
328 output << "<?xml version=\"1.0\"?>" << endl << endl;
329 output << "<PropertyList>" << endl;
331 for (int i = 0; i < nChildren; i++) {
332 writeNode(output, start_node->getChild(i), INDENT_STEP);
335 output << "</PropertyList>" << endl;
341 writeProperties (const string &file, const SGPropertyNode * start_node)
343 ofstream output(file.c_str());
345 return writeProperties(output, start_node);
347 FG_LOG(FG_INPUT, FG_ALERT, "Cannot write properties to file "
355 * Copy one property list to another.
358 copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
362 // First, copy the actual value,
364 if (in->hasValue()) {
365 switch (in->getType()) {
367 if (!out->setBoolValue(in->getBoolValue()))
371 if (!out->setIntValue(in->getIntValue()))
375 if (!out->setFloatValue(in->getFloatValue()))
378 case SGValue::DOUBLE:
379 if (!out->setDoubleValue(in->getDoubleValue()))
382 case SGValue::STRING:
383 if (!out->setStringValue(in->getStringValue()))
386 case SGValue::UNKNOWN:
387 if (!out->setUnknownValue(in->getStringValue()))
391 throw string("Unknown SGValue type"); // FIXME!!!
395 // Next, copy the children.
396 int nChildren = in->nChildren();
397 for (int i = 0; i < nChildren; i++) {
398 const SGPropertyNode * in_child = in->getChild(i);
399 SGPropertyNode * out_child = out->getChild(in_child->getName(),
400 in_child->getIndex(),
402 if (!copyProperties(in_child, out_child))
409 // end of props_io.cxx