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);
143 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: Failed to set "
144 << st.node->getPath() << " to value \""
145 << _data << "\" with type " << st.type);
152 PropsVisitor::data (const char * s, int length)
154 if (state().node->nChildren() == 0)
155 _data.append(string(s, length));
159 PropsVisitor::warning (const char * message, int line, int column)
161 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: warning: "
162 << message << " at line " << line << ", column " << column);
166 PropsVisitor::error (const char * message, int line, int column)
168 FG_LOG(FG_INPUT, FG_ALERT, "readProperties: FATAL: "
169 << message << " at line " << line << ", column " << column);
175 ////////////////////////////////////////////////////////////////////////
176 // Property list reader.
177 ////////////////////////////////////////////////////////////////////////
180 readProperties (istream &input, SGPropertyNode * start_node)
182 PropsVisitor visitor(start_node);
183 return readXML(input, visitor) && visitor.isOK();
187 readProperties (const string &file, SGPropertyNode * start_node)
189 ifstream input(file.c_str());
191 return readProperties(input, start_node);
193 FG_LOG(FG_INPUT, FG_ALERT, "Error reading property list from file "
201 ////////////////////////////////////////////////////////////////////////
202 // Property list writer.
203 ////////////////////////////////////////////////////////////////////////
205 #define INDENT_STEP 2
208 * Return the type name.
211 getTypeName (SGValue::Type type)
214 case SGValue::UNKNOWN:
222 case SGValue::DOUBLE:
224 case SGValue::STRING:
231 * Escape characters for output.
234 writeData (ostream &output, const string &data)
236 for (int i = 0; i < data.size(); i++) {
255 doIndent (ostream &output, int indent)
257 while (indent-- > 0) {
264 writeNode (ostream &output, const SGPropertyNode * node, int indent)
266 const string &name = node->getName();
267 int index = node->getIndex();
268 int nChildren = node->nChildren();
270 // If there is a literal value,
272 if (node->hasValue()) {
273 doIndent(output, indent);
274 output << '<' << name << " n=\"" << index
275 << "\" type=\"" << getTypeName(node->getType()) << "\">";
276 writeData(output, node->getStringValue());
277 output << "</" << name << '>' << endl;;
280 // If there are children, write them
283 doIndent(output, indent);
284 output << '<' << name << " n=\"" << index << "\">" << endl;;
285 for (int i = 0; i < nChildren; i++)
286 writeNode(output, node->getChild(i), indent + INDENT_STEP);
287 doIndent(output, indent);
288 output << "</" << name << '>' << endl;
291 // If there were no children and no
292 // value, at least note the presence
294 if (nChildren == 0 && !node->hasValue()) {
295 doIndent(output, indent);
296 output << '<' << name << " n=\"" << index << "\"/>" << endl;
303 writeProperties (ostream &output, const SGPropertyNode * start_node)
305 int nChildren = start_node->nChildren();
307 output << "<?xml version=\"1.0\"?>" << endl << endl;
308 output << "<PropertyList>" << endl;
310 for (int i = 0; i < nChildren; i++) {
311 writeNode(output, start_node->getChild(i), INDENT_STEP);
314 output << "</PropertyList>" << endl;
320 writeProperties (const string &file, const SGPropertyNode * start_node)
322 ofstream output(file.c_str());
324 return writeProperties(output, start_node);
326 FG_LOG(FG_INPUT, FG_ALERT, "Cannot write properties to file "
334 * Copy one property list to another.
337 copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
341 // First, copy the actual value,
343 if (in->hasValue()) {
344 switch (in->getType()) {
346 if (!out->setBoolValue(in->getBoolValue()))
350 if (!out->setIntValue(in->getIntValue()))
354 if (!out->setFloatValue(in->getFloatValue()))
357 case SGValue::DOUBLE:
358 if (!out->setDoubleValue(in->getDoubleValue()))
361 case SGValue::STRING:
362 if (!out->setStringValue(in->getStringValue()))
365 case SGValue::UNKNOWN:
366 if (!out->setUnknownValue(in->getStringValue()))
370 throw string("Unknown SGValue type"); // FIXME!!!
374 // Next, copy the children.
375 int nChildren = in->nChildren();
376 for (int i = 0; i < nChildren; i++) {
377 const SGPropertyNode * in_child = in->getChild(i);
378 SGPropertyNode * out_child = out->getChild(in_child->getName(),
379 in_child->getIndex(),
381 if (!copyProperties(in_child, out_child))
388 // end of props_io.cxx