X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fprops_io.cxx;h=9fea449730bf94122e3eea9c23c826b4eae5de68;hb=708ae35068499af33329f9db91f55441f4956acb;hp=cfd99debf8d08a8d26216fb5c8a46d96a5026d91;hpb=d4c7e950927b1e19a7a7622a7919f32233a6b7a8;p=simgear.git diff --git a/simgear/props/props_io.cxx b/simgear/props/props_io.cxx index cfd99deb..9fea4497 100644 --- a/simgear/props/props_io.cxx +++ b/simgear/props/props_io.cxx @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include // strcmp() #include #include @@ -52,8 +54,11 @@ class PropsVisitor : public XMLVisitor { public: - PropsVisitor (SGPropertyNode * root, const string &base, int default_mode = 0) - : _default_mode(default_mode), _root(root), _level(0), _base(base), _hasException(false) {} + PropsVisitor (SGPropertyNode * root, const string &base, int default_mode = 0, + bool extended = false) + : _default_mode(default_mode), _root(root), _level(0), _base(base), + _hasException(false), _extended(extended) + {} virtual ~PropsVisitor () {} @@ -75,22 +80,23 @@ private: struct State { - State () : node(0), type(""), mode(DEFAULT_MODE) {} - State (SGPropertyNode * _node, const char * _type, int _mode) - : node(_node), type(_type), mode(_mode) {} + State () : node(0), type(""), mode(DEFAULT_MODE), omit(false) {} + State (SGPropertyNode * _node, const char * _type, int _mode, bool _omit) + : node(_node), type(_type), mode(_mode), omit(_omit) {} SGPropertyNode * node; string type; int mode; + bool omit; map counters; }; State &state () { return _state_stack[_state_stack.size() - 1]; } - void push_state (SGPropertyNode * node, const char * type, int mode) { + void push_state (SGPropertyNode * node, const char * type, int mode, bool omit = false) { if (type == 0) - _state_stack.push_back(State(node, "unspecified", mode)); + _state_stack.push_back(State(node, "unspecified", mode, omit)); else - _state_stack.push_back(State(node, type, mode)); + _state_stack.push_back(State(node, type, mode, omit)); _level++; _data = ""; } @@ -109,6 +115,7 @@ private: string _base; sg_io_exception _exception; bool _hasException; + bool _extended; }; void @@ -166,7 +173,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) SGPath path(SGPath(_base).dir()); path.append(attval); try { - readProperties(path.str(), _root); + readProperties(path.str(), _root, 0, _extended); } catch (sg_io_exception &e) { setException(e); } @@ -180,16 +187,17 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) // Get the index. attval = atts.getValue("n"); int index = 0; + string strName(name); if (attval != 0) { index = atoi(attval); - st.counters[name] = SG_MAX2(st.counters[name], index+1); + st.counters[strName] = SG_MAX2(st.counters[strName], index+1); } else { - index = st.counters[name]; - st.counters[name]++; + index = st.counters[strName]; + st.counters[strName]++; } // Got the index, so grab the node. - SGPropertyNode * node = st.node->getChild(name, index, true); + SGPropertyNode * node = st.node->getChild(strName, index, true); if (!node->getAttribute(SGPropertyNode::WRITE)) { SG_LOG(SG_INPUT, SG_ALERT, "Not overwriting write-protected property " << node->getPath(true)); @@ -219,6 +227,9 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) attval = atts.getValue("userarchive"); if (checkFlag(attval, false)) mode |= SGPropertyNode::USERARCHIVE; + attval = atts.getValue("preserve"); + if (checkFlag(attval, false)) + mode |= SGPropertyNode::PRESERVE; // Check for an alias. attval = atts.getValue("alias"); @@ -228,36 +239,25 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) } // Check for an include. + bool omit = false; attval = atts.getValue("include"); if (attval != 0) { SGPath path(SGPath(_base).dir()); path.append(attval); try { - readProperties(path.str(), node); + readProperties(path.str(), node, 0, _extended); } catch (sg_io_exception &e) { setException(e); } - const char *omit = atts.getValue("omit-node"); - if (omit && !strcmp(omit, "y")) { - int nChildren = node->nChildren(); - for (int i = 0; i < nChildren; i++) { - SGPropertyNode *src = node->getChild(i); - const char *name = src->getName(); - int index = st.counters[name]; - st.counters[name]++; - SGPropertyNode *dst = st.node->getChild(name, index, true); - copyProperties(src, dst); - } - st.node->removeChild(node->getName(), node->getIndex(), false); - node = st.node; - } + attval = atts.getValue("omit-node"); + omit = checkFlag(attval, false); } const char *type = atts.getValue("type"); if (type) node->clearValue(); - push_state(node, type, mode); + push_state(node, type, mode, omit); } } @@ -285,6 +285,12 @@ PropsVisitor::endElement (const char * name) ret = st.node->setDoubleValue(strtod(_data.c_str(), 0)); } else if (st.type == "string") { ret = st.node->setStringValue(_data.c_str()); + } else if (st.type == "vec3d" && _extended) { + ret = st.node + ->setValue(simgear::parseString(_data)); + } else if (st.type == "vec4d" && _extended) { + ret = st.node + ->setValue(simgear::parseString(_data)); } else if (st.type == "unspecified") { ret = st.node->setUnspecifiedValue(_data.c_str()); } else if (_level == 1) { @@ -307,6 +313,19 @@ PropsVisitor::endElement (const char * name) // assigned. st.node->setAttributes(st.mode); + if (st.omit) { + State &parent = _state_stack[_state_stack.size() - 2]; + int nChildren = st.node->nChildren(); + for (int i = 0; i < nChildren; i++) { + SGPropertyNode *src = st.node->getChild(i); + const char *name = src->getName(); + int index = parent.counters[name]; + parent.counters[name]++; + SGPropertyNode *dst = parent.node->getChild(name, index, true); + copyProperties(src, dst); + } + parent.node->removeChild(st.node->getName(), st.node->getIndex(), false); + } pop_state(); } @@ -341,9 +360,9 @@ PropsVisitor::warning (const char * message, int line, int column) */ void readProperties (istream &input, SGPropertyNode * start_node, - const string &base, int default_mode) + const string &base, int default_mode, bool extended) { - PropsVisitor visitor(start_node, base, default_mode); + PropsVisitor visitor(start_node, base, default_mode, extended); readXML(input, visitor, base); if (visitor.hasException()) throw visitor.getException(); @@ -359,9 +378,9 @@ readProperties (istream &input, SGPropertyNode * start_node, */ void readProperties (const string &file, SGPropertyNode * start_node, - int default_mode) + int default_mode, bool extended) { - PropsVisitor visitor(start_node, file, default_mode); + PropsVisitor visitor(start_node, file, default_mode, extended); readXML(file, visitor); if (visitor.hasException()) throw visitor.getException(); @@ -377,9 +396,10 @@ readProperties (const string &file, SGPropertyNode * start_node, * @return true if the read succeeded, false otherwise. */ void readProperties (const char *buf, const int size, - SGPropertyNode * start_node, int default_mode) + SGPropertyNode * start_node, int default_mode, + bool extended) { - PropsVisitor visitor(start_node, "", default_mode); + PropsVisitor visitor(start_node, "", default_mode, extended); readXML(buf, size, visitor); if (visitor.hasException()) throw visitor.getException(); @@ -396,26 +416,33 @@ void readProperties (const char *buf, const int size, * Return the type name. */ static const char * -getTypeName (SGPropertyNode::Type type) +getTypeName (simgear::props::Type type) { + using namespace simgear; switch (type) { - case SGPropertyNode::UNSPECIFIED: + case props::UNSPECIFIED: return "unspecified"; - case SGPropertyNode::BOOL: + case props::BOOL: return "bool"; - case SGPropertyNode::INT: + case props::INT: return "int"; - case SGPropertyNode::LONG: + case props::LONG: return "long"; - case SGPropertyNode::FLOAT: + case props::FLOAT: return "float"; - case SGPropertyNode::DOUBLE: + case props::DOUBLE: return "double"; - case SGPropertyNode::STRING: + case props::STRING: return "string"; - case SGPropertyNode::ALIAS: - case SGPropertyNode::NONE: + case props::VEC3D: + return "vec3d"; + case props::VEC4D: + return "vec4d"; + case props::ALIAS: + case props::NONE: return "unspecified"; + default: // avoid compiler warning + break; } // keep the compiler from squawking @@ -521,7 +548,7 @@ writeNode (ostream &output, const SGPropertyNode * node, output << " alias=\"" << node->getAliasTarget()->getPath() << "\"/>" << endl; } else { - if (node->getType() != SGPropertyNode::UNSPECIFIED) + if (node->getType() != simgear::props::UNSPECIFIED) output << " type=\"" << getTypeName(node->getType()) << '"'; output << '>'; writeData(output, node->getStringValue()); @@ -578,6 +605,13 @@ writeProperties (const string &file, const SGPropertyNode * start_node, } } +// Another variation, useful when called from gdb +void +writeProperties (const char* file, const SGPropertyNode * start_node) +{ + writeProperties(string(file), start_node, true); +} + //////////////////////////////////////////////////////////////////////// @@ -590,46 +624,60 @@ writeProperties (const string &file, const SGPropertyNode * start_node, * * @param in The source property tree. * @param out The destination property tree. + * @param attr_value Only copy properties with given attribute values. + * @param attr_mask Mask for attributes to be considered by attr_value + * (default is 0 = attributes not considered, all + * properties copied). * @return true if all properties were copied, false if some failed * (for example, if the property's value is tied read-only). */ bool -copyProperties (const SGPropertyNode *in, SGPropertyNode *out) +copyProperties (const SGPropertyNode *in, SGPropertyNode *out, + int attr_value, int attr_mask) { + using namespace simgear; bool retval = true; // First, copy the actual value, // if any. if (in->hasValue()) { switch (in->getType()) { - case SGPropertyNode::BOOL: + case props::BOOL: if (!out->setBoolValue(in->getBoolValue())) retval = false; break; - case SGPropertyNode::INT: + case props::INT: if (!out->setIntValue(in->getIntValue())) retval = false; break; - case SGPropertyNode::LONG: + case props::LONG: if (!out->setLongValue(in->getLongValue())) retval = false; break; - case SGPropertyNode::FLOAT: + case props::FLOAT: if (!out->setFloatValue(in->getFloatValue())) retval = false; break; - case SGPropertyNode::DOUBLE: + case props::DOUBLE: if (!out->setDoubleValue(in->getDoubleValue())) retval = false; break; - case SGPropertyNode::STRING: + case props::STRING: if (!out->setStringValue(in->getStringValue())) retval = false; break; - case SGPropertyNode::UNSPECIFIED: + case props::UNSPECIFIED: if (!out->setUnspecifiedValue(in->getStringValue())) retval = false; break; + case props::VEC3D: + if (!out->setValue(in->getValue())) + retval = false; + break; + case props::VEC4D: + if (!out->setValue(in->getValue())) + retval = false; + break; default: if (in->isAlias()) break; @@ -639,18 +687,41 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out) } } - // copy the attributes. + // copy the attributes. out->setAttributes( in->getAttributes() ); - // Next, copy the children. + // Next, copy the children. int nChildren = in->nChildren(); for (int i = 0; i < nChildren; i++) { const SGPropertyNode * in_child = in->getChild(i); - SGPropertyNode * out_child = out->getChild(in_child->getName(), - in_child->getIndex(), - true); - if (!copyProperties(in_child, out_child)) - retval = false; + int mask = attr_mask; + /* attributes have no meaning for nodes without values - except + * the PRESERVE flag. So ignore them. */ + if (!in_child->hasValue()) + mask &= SGPropertyNode::PRESERVE; + if ((in_child->getAttributes() & mask) == (attr_value & mask)) + { + SGPropertyNode * out_child = out->getChild(in_child->getNameString(), + in_child->getIndex(), + false); + if (!out_child) + { + out_child = out->getChild(in_child->getNameString(), + in_child->getIndex(), + true); + } + else + { + mask = attr_mask; + if (!out_child->hasValue()) + mask &= SGPropertyNode::PRESERVE; + if ((out_child->getAttributes() & mask) != (attr_value & mask)) + out_child = NULL; + } + if (out_child && + (!copyProperties(in_child, out_child, attr_value, attr_mask))) + retval = false; + } } return retval;