6 #include <stdlib.h> // atof() atoi()
8 #include <simgear/debug/logstream.hxx>
9 #include <simgear/xml/easyxml.hxx>
27 ////////////////////////////////////////////////////////////////////////
28 // Property list visitor, for XML parsing.
29 ////////////////////////////////////////////////////////////////////////
31 class PropsVisitor : public XMLVisitor
35 PropsVisitor (SGPropertyNode * root) : _ok(true), _root(root), _level(0) {}
39 void startElement (const char * name, const XMLAttributes &atts);
40 void endElement (const char * name);
41 void data (const char * s, int length);
42 void warning (const char * message, int line, int column);
43 void error (const char * message, int line, int column);
45 bool isOK () const { return _ok; }
51 State () : node(0), type("") {}
52 State (SGPropertyNode * _node, const char * _type)
53 : node(_node), type(_type) {}
54 SGPropertyNode * node;
58 State &state () { return _state_stack[_state_stack.size() - 1]; }
60 void push_state (SGPropertyNode * node, const char * type) {
62 _state_stack.push_back(State(node, "unknown"));
64 _state_stack.push_back(State(node, type));
70 _state_stack.pop_back();
76 SGPropertyNode * _root;
78 vector<State> _state_stack;
83 PropsVisitor::startXML ()
86 _state_stack.resize(0);
90 PropsVisitor::endXML ()
93 _state_stack.resize(0);
97 PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
100 push_state(_root, "");
104 const char * att_n = atts.getValue("n");
108 push_state(state().node->getChild(name, index, true),
109 atts.getValue("type"));
114 PropsVisitor::endElement (const char * name)
119 // If there are no children, then
120 // it is a leaf value.
121 if (st.node->nChildren() == 0) {
122 if (st.type == "bool") {
123 if (_data == "true" || atoi(_data.c_str()) != 0)
124 ret = st.node->setBoolValue(true);
126 ret = st.node->setBoolValue(false);
127 } else if (st.type == "int") {
128 ret = st.node->setIntValue(atoi(_data.c_str()));
129 } else if (st.type == "float") {
130 ret = st.node->setFloatValue(atof(_data.c_str()));
131 } else if (st.type == "double") {
132 ret = st.node->setDoubleValue(atof(_data.c_str()));
133 } else if (st.type == "string") {
134 ret = st.node->setStringValue(_data);
135 } else if (st.type == "unknown") {
136 ret = st.node->setUnknownValue(_data);
138 FG_LOG(FG_INPUT, FG_ALERT, "Unknown data type " << st.type
139 << " assuming 'unknown'");
140 ret = st.node->setUnknownValue(_data);
145 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: Failed to set "
146 << st.node->getPath() << " to value \""
147 << _data << " with type " << st.type);
153 PropsVisitor::data (const char * s, int length)
155 if (state().node->nChildren() == 0)
156 _data.append(string(s, length));
160 PropsVisitor::warning (const char * message, int line, int column)
162 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: warning: "
163 << message << " at line " << line << ", column " << column);
167 PropsVisitor::error (const char * message, int line, int column)
169 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: FATAL: "
170 << message << " at line " << line << ", column " << column);
176 ////////////////////////////////////////////////////////////////////////
177 // Property list reader.
178 ////////////////////////////////////////////////////////////////////////
181 readProperties (istream &input, SGPropertyNode * start_node)
183 PropsVisitor visitor(start_node);
184 return readXML(input, visitor) && visitor.isOK();
188 readProperties (const string &file, SGPropertyNode * start_node)
190 ifstream input(file.c_str());
192 return readProperties(input, start_node);
194 FG_LOG(FG_INPUT, FG_ALERT, "Error reading property list from file "
202 ////////////////////////////////////////////////////////////////////////
203 // Property list writer.
204 ////////////////////////////////////////////////////////////////////////
206 #define INDENT_STEP 2
209 * Return the type name.
212 getTypeName (SGValue::Type type)
215 case SGValue::UNKNOWN:
223 case SGValue::DOUBLE:
225 case SGValue::STRING:
232 * Escape characters for output.
235 writeData (ostream &output, const string &data)
237 for (int i = 0; i < data.size(); i++) {
256 doIndent (ostream &output, int indent)
258 while (indent-- > 0) {
265 writeNode (ostream &output, const SGPropertyNode * node, int indent)
267 const string &name = node->getName();
268 int index = node->getIndex();
269 int nChildren = node->nChildren();
271 // If there is a literal value,
273 if (node->hasValue()) {
274 doIndent(output, indent);
275 output << '<' << name << " n=\"" << index
276 << "\" type=\"" << getTypeName(node->getType()) << "\">";
277 writeData(output, node->getStringValue());
278 output << "</" << name << '>' << endl;;
281 // If there are children, write them
284 doIndent(output, indent);
285 output << '<' << name << " n=\"" << index << "\">" << endl;;
286 for (int i = 0; i < nChildren; i++)
287 writeNode(output, node->getChild(i), indent + INDENT_STEP);
288 doIndent(output, indent);
289 output << "</" << name << '>' << endl;
292 // If there were no children and no
293 // value, at least note the presence
295 if (nChildren == 0 && !node->hasValue()) {
296 doIndent(output, indent);
297 output << '<' << name << " n=\"" << index << "\"/>" << endl;
304 writeProperties (ostream &output, const SGPropertyNode * start_node)
306 int nChildren = start_node->nChildren();
308 output << "<?xml version=\"1.0\"?>" << endl << endl;
309 output << "<PropertyList>" << endl;
311 for (int i = 0; i < nChildren; i++) {
312 writeNode(output, start_node->getChild(i), INDENT_STEP);
315 output << "</PropertyList>" << endl;
321 writeProperties (const string &file, const SGPropertyNode * start_node)
323 ofstream output(file.c_str());
325 return writeProperties(output, start_node);
327 FG_LOG(FG_INPUT, FG_ALERT, "Cannot write properties to file "