#define DEFAULT_MODE (SGPropertyNode::READ|SGPropertyNode::WRITE)
-\f
////////////////////////////////////////////////////////////////////////
// Property list visitor, for XML parsing.
////////////////////////////////////////////////////////////////////////
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) {}
+ bool hasChildren() const
+ {
+ int n_children = node->nChildren();
+ return n_children > 1
+ || (n_children == 1 && node->getChild(0)->getNameString() != "_attr_");
+ }
SGPropertyNode * node;
string type;
int mode;
/**
- * Check a yes/no flag, with default.
+ * Set/unset a yes/no flag.
*/
-static bool
-checkFlag (const char * flag, const sg_location& location,
- bool defaultState = true)
+static void
+setFlag( int& mode,
+ int mask,
+ const std::string& flag,
+ const sg_location& location )
{
- if (flag == 0)
- return defaultState;
- else if (!strcmp(flag, "y"))
- return true;
- else if (!strcmp(flag, "n"))
- return false;
- else {
+ if( flag == "y" )
+ mode |= mask;
+ else if( flag == "n" )
+ mode &= ~mask;
+ else
+ {
string message = "Unrecognized flag value '";
message += flag;
message += '\'';
throw sg_io_exception(message, location, "SimGear Property Reader");
}
- // Check for an include.
+ // Check for an include.
attval = atts.getValue("include");
if (attval != 0) {
try {
else {
State &st = state();
- // Get the index.
+
+ // Get the index.
attval = atts.getValue("n");
int index = 0;
string strName(name);
st.counters[strName]++;
}
- // Got the index, so grab the node.
+ // Got the index, so grab the node.
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 = &null;
}
- // Get the access-mode attributes,
- // but don't set yet (in case they
- // prevent us from recording the value).
- int mode = _default_mode;
-
- attval = atts.getValue("read");
- if (checkFlag(attval, location, true))
- mode |= SGPropertyNode::READ;
- attval = atts.getValue("write");
- if (checkFlag(attval, location, true))
- mode |= SGPropertyNode::WRITE;
- attval = atts.getValue("archive");
- if (checkFlag(attval, location, false))
- mode |= SGPropertyNode::ARCHIVE;
- attval = atts.getValue("trace-read");
- if (checkFlag(attval, location, false))
- mode |= SGPropertyNode::TRACE_READ;
- attval = atts.getValue("trace-write");
- if (checkFlag(attval, location, false))
- mode |= SGPropertyNode::TRACE_WRITE;
- attval = atts.getValue("userarchive");
- if (checkFlag(attval, location, false))
- mode |= SGPropertyNode::USERARCHIVE;
- attval = atts.getValue("preserve");
- if (checkFlag(attval, location, false))
- mode |= SGPropertyNode::PRESERVE;
-
- // Check for an alias.
- attval = atts.getValue("alias");
- if (attval != 0) {
- if (!node->alias(attval))
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to set alias to " << attval
- << "\n at " << location.asString());
- }
+ // TODO use correct default mode (keep for now to match past behavior)
+ int mode = _default_mode | SGPropertyNode::READ | SGPropertyNode::WRITE;
+ int omit = false;
+ const char* type = 0;
- // Check for an include.
- bool omit = false;
- attval = atts.getValue("include");
- if (attval != 0) {
- try {
- SGPath path = simgear::ResourceManager::instance()->findPath(attval, SGPath(_base).dir());
+ SGPropertyNode* attr_node = NULL;
+
+ for(int i = 0; i < atts.size(); ++i)
+ {
+ const std::string att_name = atts.getName(i);
+ const std::string val = atts.getValue(i);
+
+ // Get the access-mode attributes,
+ // but don't set yet (in case they
+ // prevent us from recording the value).
+ if( att_name == "read" )
+ setFlag(mode, SGPropertyNode::READ, val, location);
+ else if( att_name == "write" )
+ setFlag(mode, SGPropertyNode::WRITE, val, location);
+ else if( att_name == "archive" )
+ setFlag(mode, SGPropertyNode::ARCHIVE, val, location);
+ else if( att_name == "trace-read" )
+ setFlag(mode, SGPropertyNode::TRACE_READ, val, location);
+ else if( att_name == "trace-write" )
+ setFlag(mode, SGPropertyNode::TRACE_WRITE, val, location);
+ else if( att_name == "userarchive" )
+ setFlag(mode, SGPropertyNode::USERARCHIVE, val, location);
+ else if( att_name == "preserve" )
+ setFlag(mode, SGPropertyNode::PRESERVE, val, location);
+
+ // Check for an alias.
+ else if( att_name == "alias" )
+ {
+ if( !node->alias(val) )
+ SG_LOG
+ (
+ SG_INPUT,
+ SG_ALERT,
+ "Failed to set alias to " << val << "\n at " << location.asString()
+ );
+ }
+
+ // Check for an include.
+ else if( att_name == "include" )
+ {
+ try
+ {
+ SGPath path = simgear::ResourceManager::instance()
+ ->findPath(val, SGPath(_base).dir());
if (path.isNull())
{
- string message ="Cannot open file ";
- message += attval;
- throw sg_io_exception(message, location,
- "SimGear Property Reader");
+ string message ="Cannot open file ";
+ message += val;
+ throw sg_io_exception(message, location, "SimGear Property Reader");
}
readProperties(path.str(), node, 0, _extended);
- } catch (sg_io_exception &e) {
+ }
+ catch (sg_io_exception &e)
+ {
setException(e);
+ }
}
- attval = atts.getValue("omit-node");
- omit = checkFlag(attval, location, false);
- }
+ else if( att_name == "omit-node" )
+ setFlag(omit, 1, val, location);
+ else if( att_name == "type" )
+ {
+ type = atts.getValue(i);
+
+ // if a type is given and the node is tied,
+ // don't clear the value because
+ // clearValue() unties the property
+ if( !node->isTied() )
+ node->clearValue();
+ }
+ else if( att_name != "n" )
+ {
+ // Store all additional attributes in a special node named _attr_
+ if( !attr_node )
+ attr_node = node->getChild("_attr_", 0, true);
- const char *type = atts.getValue("type");
- // if a type is given and the node is tied,
- // don't clear the value because
- // clearValue() unties the property
- if (type && false == node->isTied() )
- node->clearValue();
+ attr_node->setUnspecifiedValue(att_name.c_str(), val.c_str());
+ }
+ }
push_state(node, type, mode, omit);
}
}
bool ret;
const sg_location location(getPath(), getLine(), getColumn());
- // If there are no children and it's
- // not an alias, then it's a leaf value.
- if (st.node->nChildren() == 0 && !st.node->isAlias()) {
+ // If there are no children and it's
+ // not an alias, then it's a leaf value.
+ if( !st.hasChildren() && !st.node->isAlias() )
+ {
if (st.type == "bool") {
if (_data == "true" || atoi(_data.c_str()) != 0)
- ret = st.node->setBoolValue(true);
+ ret = st.node->setBoolValue(true);
else
- ret = st.node->setBoolValue(false);
+ ret = st.node->setBoolValue(false);
} else if (st.type == "int") {
ret = st.node->setIntValue(atoi(_data.c_str()));
} else if (st.type == "long") {
string message = "Unrecognized data type '";
message += st.type;
message += '\'';
- // FIXME: add location information
+ // FIXME: add location information
throw sg_io_exception(message, location, "SimGear Property Reader");
}
- if (!ret)
- SG_LOG(SG_INPUT, SG_ALERT, "readProperties: Failed to set "
- << st.node->getPath() << " to value \""
- << _data << "\" with type " << st.type << "\n at "
- << location.asString());
+ if( !ret )
+ SG_LOG
+ (
+ SG_INPUT,
+ SG_ALERT,
+ "readProperties: Failed to set " << st.node->getPath()
+ << " to value \"" << _data
+ << "\" with type " << st.type
+ << "\n at " << location.asString()
+ );
}
- // Set the access-mode attributes now,
- // once the value has already been
- // assigned.
+ // Set the access-mode attributes now,
+ // once the value has already been
+ // assigned.
st.node->setAttributes(st.mode);
if (st.omit) {
void
PropsVisitor::data (const char * s, int length)
{
- if (state().node->nChildren() == 0)
+ if( !state().hasChildren() )
_data.append(string(s, length));
}
}
-\f
////////////////////////////////////////////////////////////////////////
// Property list reader.
////////////////////////////////////////////////////////////////////////
throw visitor.getException();
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Property list writer.
////////////////////////////////////////////////////////////////////////
}
-\f
////////////////////////////////////////////////////////////////////////
// Copy properties from one tree to another.
////////////////////////////////////////////////////////////////////////