X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fprops_io.cxx;h=232e3c2c79f4b2c4c4da20d00fa2c54e1c00d5f7;hb=07da1e7e1a753c59b805a6a071766ee08ac3c826;hp=d6b38c62d51199d43012f39f35f5dbcdd80b093a;hpb=cecdb15692318e2ca2cdba45c9d5870aa6ac8dc4;p=simgear.git diff --git a/simgear/props/props_io.cxx b/simgear/props/props_io.cxx index d6b38c62..232e3c2c 100644 --- a/simgear/props/props_io.cxx +++ b/simgear/props/props_io.cxx @@ -1,3 +1,16 @@ +/** + * \file props_io.cxx + * Started Fall 2000 by David Megginson, david@megginson.com + * This code is released into the Public Domain. + * + * See props.html for documentation [replace with URL when available]. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +# include +#endif #include @@ -5,25 +18,29 @@ #include #include +#include #include #include #include "props.hxx" #include "props_io.hxx" -#include STL_IOSTREAM -#include STL_FSTREAM -#include STL_STRING +#include +#include +#include +#include // strcmp() #include #include -SG_USING_STD(istream); -SG_USING_STD(ifstream); -SG_USING_STD(ostream); -SG_USING_STD(ofstream); -SG_USING_STD(string); -SG_USING_STD(vector); -SG_USING_STD(map); +using std::istream; +using std::ifstream; +using std::ostream; +using std::ofstream; +using std::string; +using std::vector; +using std::map; + +using std::endl; #define DEFAULT_MODE (SGPropertyNode::READ|SGPropertyNode::WRITE) @@ -37,8 +54,11 @@ class PropsVisitor : public XMLVisitor { public: - PropsVisitor (SGPropertyNode * root, const string &base) - : _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 () {} @@ -60,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 = ""; } @@ -85,13 +106,16 @@ private: _level--; } + int _default_mode; string _data; SGPropertyNode * _root; + SGPropertyNode null; int _level; vector _state_stack; string _base; sg_io_exception _exception; bool _hasException; + bool _extended; }; void @@ -133,7 +157,6 @@ checkFlag (const char * flag, bool defaultState = true) void PropsVisitor::startElement (const char * name, const XMLAttributes &atts) { - State &st = state(); const char * attval; if (_level == 0) { @@ -150,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); } @@ -160,6 +183,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) } else { + State &st = state(); // Get the index. attval = atts.getValue("n"); int index = 0; @@ -173,11 +197,16 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) // Got the index, so grab the node. SGPropertyNode * node = st.node->getChild(name, index, true); + if (!node->getAttribute(SGPropertyNode::WRITE)) { + SG_LOG(SG_INPUT, SG_ALERT, "Not overwriting write-protected property " + << node->getPath(true)); + node = &null; + } // Get the access-mode attributes, // but don't set yet (in case they // prevent us from recording the value). - int mode = 0; + int mode = _default_mode; attval = atts.getValue("read"); if (checkFlag(attval, true)) @@ -194,6 +223,9 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) attval = atts.getValue("trace-write"); if (checkFlag(attval, false)) mode |= SGPropertyNode::TRACE_WRITE; + attval = atts.getValue("userarchive"); + if (checkFlag(attval, false)) + mode |= SGPropertyNode::USERARCHIVE; // Check for an alias. attval = atts.getValue("alias"); @@ -203,18 +235,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); } + + attval = atts.getValue("omit-node"); + omit = checkFlag(attval, false); } - push_state(node, atts.getValue("type"), mode); + const char *type = atts.getValue("type"); + if (type) + node->clearValue(); + push_state(node, type, mode, omit); } } @@ -242,8 +281,16 @@ 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) { + ret = true; // empty } else { string message = "Unrecognized data type '"; message += st.type; @@ -262,6 +309,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(); } @@ -296,9 +356,9 @@ PropsVisitor::warning (const char * message, int line, int column) */ void readProperties (istream &input, SGPropertyNode * start_node, - const string &base) + const string &base, int default_mode, bool extended) { - PropsVisitor visitor(start_node, base); + PropsVisitor visitor(start_node, base, default_mode, extended); readXML(input, visitor, base); if (visitor.hasException()) throw visitor.getException(); @@ -313,15 +373,34 @@ readProperties (istream &input, SGPropertyNode * start_node, * @return true if the read succeeded, false otherwise. */ void -readProperties (const string &file, SGPropertyNode * start_node) +readProperties (const string &file, SGPropertyNode * start_node, + int default_mode, bool extended) { - PropsVisitor visitor(start_node, file); + PropsVisitor visitor(start_node, file, default_mode, extended); readXML(file, visitor); if (visitor.hasException()) throw visitor.getException(); } +/** + * Read properties from an in-memory buffer. + * + * @param buf A character buffer containing the xml data. + * @param size The size/length of the buffer in bytes + * @param start_node The root node for reading properties. + * @return true if the read succeeded, false otherwise. + */ +void readProperties (const char *buf, const int size, + SGPropertyNode * start_node, int default_mode, + bool extended) +{ + PropsVisitor visitor(start_node, "", default_mode, extended); + readXML(buf, size, visitor); + if (visitor.hasException()) + throw visitor.getException(); +} + //////////////////////////////////////////////////////////////////////// // Property list writer. @@ -333,26 +412,33 @@ readProperties (const string &file, SGPropertyNode * start_node) * 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 @@ -394,11 +480,11 @@ doIndent (ostream &output, int indent) static void -writeAtts (ostream &output, const SGPropertyNode * node) +writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex) { int index = node->getIndex(); - if (index != 0) + if (index != 0 || forceindex) output << " n=\"" << index << '"'; #if 0 @@ -419,15 +505,15 @@ writeAtts (ostream &output, const SGPropertyNode * node) * Test whether a node is archivable or has archivable descendants. */ static bool -isArchivable (const SGPropertyNode * node) +isArchivable (const SGPropertyNode * node, SGPropertyNode::Attribute archive_flag) { // FIXME: it's inefficient to do this all the time - if (node->getAttribute(SGPropertyNode::ARCHIVE)) + if (node->getAttribute(archive_flag)) return true; else { int nChildren = node->nChildren(); for (int i = 0; i < nChildren; i++) - if (isArchivable(node->getChild(i))) + if (isArchivable(node->getChild(i), archive_flag)) return true; } return false; @@ -436,43 +522,45 @@ isArchivable (const SGPropertyNode * node) static bool writeNode (ostream &output, const SGPropertyNode * node, - bool write_all, int indent) + bool write_all, int indent, SGPropertyNode::Attribute archive_flag) { // Don't write the node or any of // its descendants unless it is // allowed to be archived. - if (!write_all && !isArchivable(node)) + if (!write_all && !isArchivable(node, archive_flag)) return true; // Everything's OK, but we won't write. const string name = node->getName(); int nChildren = node->nChildren(); + bool node_has_value = false; // If there is a literal value, // write it first. - if (node->hasValue() && (write_all || node->getAttribute(SGPropertyNode::ARCHIVE))) { + if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) { doIndent(output, indent); output << '<' << name; - writeAtts(output, node); + writeAtts(output, node, nChildren != 0); if (node->isAlias() && node->getAliasTarget() != 0) { 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()); output << "' << endl; } + node_has_value = true; } // If there are children, write them next. - if (nChildren > 0 || node->isAlias()) { + if (nChildren > 0) { doIndent(output, indent); output << '<' << name; - writeAtts(output, node); + writeAtts(output, node, node_has_value); output << '>' << endl; for (int i = 0; i < nChildren; i++) - writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP); + writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag); doIndent(output, indent); output << "' << endl; } @@ -483,7 +571,7 @@ writeNode (ostream &output, const SGPropertyNode * node, void writeProperties (ostream &output, const SGPropertyNode * start_node, - bool write_all) + bool write_all, SGPropertyNode::Attribute archive_flag) { int nChildren = start_node->nChildren(); @@ -491,7 +579,7 @@ writeProperties (ostream &output, const SGPropertyNode * start_node, output << "" << endl; for (int i = 0; i < nChildren; i++) { - writeNode(output, start_node->getChild(i), write_all, INDENT_STEP); + writeNode(output, start_node->getChild(i), write_all, INDENT_STEP, archive_flag); } output << "" << endl; @@ -500,11 +588,14 @@ writeProperties (ostream &output, const SGPropertyNode * start_node, void writeProperties (const string &file, const SGPropertyNode * start_node, - bool write_all) + bool write_all, SGPropertyNode::Attribute archive_flag) { + SGPath path(file.c_str()); + path.create_dir(0777); + ofstream output(file.c_str()); if (output.good()) { - writeProperties(output, start_node, write_all); + writeProperties(output, start_node, write_all, archive_flag); } else { throw sg_io_exception("Cannot open file", sg_location(file)); } @@ -528,47 +619,61 @@ writeProperties (const string &file, const SGPropertyNode * start_node, bool copyProperties (const SGPropertyNode *in, SGPropertyNode *out) { + 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; string message = "Unknown internal SGPropertyNode type"; message += in->getType(); throw sg_error(message, "SimGear Property Reader"); } } + // copy the attributes. + out->setAttributes( in->getAttributes() ); + // Next, copy the children. int nChildren = in->nChildren(); for (int i = 0; i < nChildren; i++) {