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)
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);
35 ////////////////////////////////////////////////////////////////////////
36 // Property list visitor, for XML parsing.
37 ////////////////////////////////////////////////////////////////////////
39 class PropsVisitor : public XMLVisitor
43 PropsVisitor (SGPropertyNode * root) : _ok(true), _root(root), _level(0) {}
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);
53 bool isOK () const { return _ok; }
59 State () : node(0), type("") {}
60 State (SGPropertyNode * _node, const char * _type)
61 : node(_node), type(_type) {}
62 SGPropertyNode * node;
66 State &state () { return _state_stack[_state_stack.size() - 1]; }
68 void push_state (SGPropertyNode * node, const char * type) {
70 _state_stack.push_back(State(node, "unknown"));
72 _state_stack.push_back(State(node, type));
78 _state_stack.pop_back();
84 SGPropertyNode * _root;
86 vector<State> _state_stack;
91 PropsVisitor::startXML ()
94 _state_stack.resize(0);
98 PropsVisitor::endXML ()
101 _state_stack.resize(0);
105 PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
108 push_state(_root, "");
112 const char * att_n = atts.getValue("n");
116 push_state(state().node->getChild(name, index, true),
117 atts.getValue("type"));
122 PropsVisitor::endElement (const char * name)
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);
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);
146 FG_LOG(FG_INPUT, FG_ALERT, "Unknown data type " << st.type
147 << " assuming 'unknown'");
148 ret = st.node->setUnknownValue(_data);
151 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: Failed to set "
152 << st.node->getPath() << " to value \""
153 << _data << "\" with type " << st.type);
160 PropsVisitor::data (const char * s, int length)
162 if (state().node->nChildren() == 0)
163 _data.append(string(s, length));
167 PropsVisitor::warning (const char * message, int line, int column)
169 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: warning: "
170 << message << " at line " << line << ", column " << column);
174 PropsVisitor::error (const char * message, int line, int column)
176 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: FATAL: "
177 << message << " at line " << line << ", column " << column);
183 ////////////////////////////////////////////////////////////////////////
184 // Property list reader.
185 ////////////////////////////////////////////////////////////////////////
188 readProperties (istream &input, SGPropertyNode * start_node)
190 PropsVisitor visitor(start_node);
191 return readXML(input, visitor) && visitor.isOK();
195 readProperties (const string &file, SGPropertyNode * start_node)
197 ifstream input(file.c_str());
199 return readProperties(input, start_node);
201 FG_LOG(FG_INPUT, FG_ALERT, "Error reading property list from file "
209 ////////////////////////////////////////////////////////////////////////
210 // Property list writer.
211 ////////////////////////////////////////////////////////////////////////
213 #define INDENT_STEP 2
216 * Return the type name.
219 getTypeName (SGValue::Type type)
222 case SGValue::UNKNOWN:
230 case SGValue::DOUBLE:
232 case SGValue::STRING:
239 * Escape characters for output.
242 writeData (ostream &output, const string &data)
244 for (int i = 0; i < data.size(); i++) {
263 doIndent (ostream &output, int indent)
265 while (indent-- > 0) {
272 writeNode (ostream &output, const SGPropertyNode * node, int indent)
274 const string &name = node->getName();
275 int index = node->getIndex();
276 int nChildren = node->nChildren();
278 // If there is a literal value,
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;;
288 // If there are children, write them
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;
299 // If there were no children and no
300 // value, at least note the presence
302 if (nChildren == 0 && !node->hasValue()) {
303 doIndent(output, indent);
304 output << '<' << name << " n=\"" << index << "\"/>" << endl;
311 writeProperties (ostream &output, const SGPropertyNode * start_node)
313 int nChildren = start_node->nChildren();
315 output << "<?xml version=\"1.0\"?>" << endl << endl;
316 output << "<PropertyList>" << endl;
318 for (int i = 0; i < nChildren; i++) {
319 writeNode(output, start_node->getChild(i), INDENT_STEP);
322 output << "</PropertyList>" << endl;
328 writeProperties (const string &file, const SGPropertyNode * start_node)
330 ofstream output(file.c_str());
332 return writeProperties(output, start_node);
334 FG_LOG(FG_INPUT, FG_ALERT, "Cannot write properties to file "
342 * Copy one property list to another.
345 copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
349 // First, copy the actual value,
351 if (in->hasValue()) {
352 switch (in->getType()) {
354 if (!out->setBoolValue(in->getBoolValue()))
358 if (!out->setIntValue(in->getIntValue()))
362 if (!out->setFloatValue(in->getFloatValue()))
365 case SGValue::DOUBLE:
366 if (!out->setDoubleValue(in->getDoubleValue()))
369 case SGValue::STRING:
370 if (!out->setStringValue(in->getStringValue()))
373 case SGValue::UNKNOWN:
374 if (!out->setUnknownValue(in->getStringValue()))
378 throw string("Unknown SGValue type"); // FIXME!!!
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(),
389 if (!copyProperties(in_child, out_child))
396 // end of props_io.cxx