- modified both readProperties functions to return void, and modified
file-name variant to invoke new readXML function - readProperties and writeProperties will now throw exceptions if there are file I/O problems - replace error messages with exceptions - tunnel sg_io_exception through from nested property read, since the C-based Expat code cannot handle exceptions
This commit is contained in:
+41
-62
@@ -43,7 +43,9 @@ class PropsVisitor : public XMLVisitor
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
PropsVisitor (SGPropertyNode * root, const string &base)
|
PropsVisitor (SGPropertyNode * root, const string &base)
|
||||||
: _ok(true), _root(root), _level(0), _base(base) {}
|
: _root(root), _level(0), _base(base), _exception(0) {}
|
||||||
|
|
||||||
|
virtual ~PropsVisitor () { delete _exception; }
|
||||||
|
|
||||||
void startXML ();
|
void startXML ();
|
||||||
void endXML ();
|
void endXML ();
|
||||||
@@ -51,9 +53,9 @@ public:
|
|||||||
void endElement (const char * name);
|
void endElement (const char * name);
|
||||||
void data (const char * s, int length);
|
void data (const char * s, int length);
|
||||||
void warning (const char * message, int line, int column);
|
void warning (const char * message, int line, int column);
|
||||||
void error (const char * message, int line, int column);
|
|
||||||
|
|
||||||
bool isOK () const { return _ok; }
|
bool hasException () const { return (_exception != 0); }
|
||||||
|
const sg_io_exception * getException () const { return _exception; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -84,12 +86,12 @@ private:
|
|||||||
_level--;
|
_level--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _ok;
|
|
||||||
string _data;
|
string _data;
|
||||||
SGPropertyNode * _root;
|
SGPropertyNode * _root;
|
||||||
int _level;
|
int _level;
|
||||||
vector<State> _state_stack;
|
vector<State> _state_stack;
|
||||||
string _base;
|
string _base;
|
||||||
|
sg_io_exception * _exception;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -120,9 +122,11 @@ checkFlag (const char * flag, bool defaultState = true)
|
|||||||
else if (string(flag) == "n")
|
else if (string(flag) == "n")
|
||||||
return false;
|
return false;
|
||||||
else {
|
else {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized flag value '" << flag
|
string message = "Unrecognized flag value '";
|
||||||
<< "', assuming yes");
|
message += flag;
|
||||||
return true;
|
message += '\'';
|
||||||
|
// FIXME: add location info
|
||||||
|
throw sg_io_exception(message, "SimGear Property Reader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +137,10 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
|
|
||||||
if (_level == 0) {
|
if (_level == 0) {
|
||||||
if (string(name) != (string)"PropertyList") {
|
if (string(name) != (string)"PropertyList") {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Root element name is " <<
|
string message = "Root element name is ";
|
||||||
name << "; expected PropertyList");
|
message += name;
|
||||||
_ok = false;
|
message += "; expected PropertyList";
|
||||||
|
throw sg_io_exception(message, "SimGear Property Reader");
|
||||||
}
|
}
|
||||||
push_state(_root, "", DEFAULT_MODE);
|
push_state(_root, "", DEFAULT_MODE);
|
||||||
}
|
}
|
||||||
@@ -183,13 +188,12 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
attval = atts.getValue("include");
|
attval = atts.getValue("include");
|
||||||
if (attval != 0) {
|
if (attval != 0) {
|
||||||
SGPath path(SGPath(_base).dir());
|
SGPath path(SGPath(_base).dir());
|
||||||
cerr << "Base is " << _base << endl;
|
|
||||||
cerr << "Dir is " << SGPath(_base).dir() << endl;
|
|
||||||
path.append(attval);
|
path.append(attval);
|
||||||
if (!readProperties(path.str(), node)) {
|
try {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to read include file "
|
readProperties(path.str(), node);
|
||||||
<< attval);
|
} catch (const sg_io_exception &t) {
|
||||||
_ok = false;
|
cerr << "Caught exception\n";
|
||||||
|
_exception = t.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,9 +228,11 @@ PropsVisitor::endElement (const char * name)
|
|||||||
} else if (st.type == "unspecified") {
|
} else if (st.type == "unspecified") {
|
||||||
ret = st.node->setUnspecifiedValue(_data);
|
ret = st.node->setUnspecifiedValue(_data);
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Unrecognized data type " << st.type
|
string message = "Unrecognized data type '";
|
||||||
<< " assuming 'unspecified'");
|
message += st.type;
|
||||||
ret = st.node->setUnspecifiedValue(_data);
|
message += '\'';
|
||||||
|
// FIXME: add location information
|
||||||
|
throw sg_io_exception(message, "SimGear Property Reader");
|
||||||
}
|
}
|
||||||
if (!ret)
|
if (!ret)
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "readProperties: Failed to set "
|
SG_LOG(SG_INPUT, SG_ALERT, "readProperties: Failed to set "
|
||||||
@@ -256,14 +262,6 @@ PropsVisitor::warning (const char * message, int line, int column)
|
|||||||
<< message << " at line " << line << ", column " << column);
|
<< message << " at line " << line << ", column " << column);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
PropsVisitor::error (const char * message, int line, int column)
|
|
||||||
{
|
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "readProperties: FATAL: " <<
|
|
||||||
message << " at line " << line << ", column " << column);
|
|
||||||
_ok = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@@ -279,12 +277,14 @@ PropsVisitor::error (const char * message, int line, int column)
|
|||||||
* @param base A base path for resolving external include references.
|
* @param base A base path for resolving external include references.
|
||||||
* @return true if the read succeeded, false otherwise.
|
* @return true if the read succeeded, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool
|
void
|
||||||
readProperties (istream &input, SGPropertyNode * start_node,
|
readProperties (istream &input, SGPropertyNode * start_node,
|
||||||
const string &base)
|
const string &base)
|
||||||
{
|
{
|
||||||
PropsVisitor visitor(start_node, base);
|
PropsVisitor visitor(start_node, base);
|
||||||
return readXML(input, visitor) && visitor.isOK();
|
readXML(input, visitor, base);
|
||||||
|
if (visitor.hasException())
|
||||||
|
throw *(visitor.getException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -295,18 +295,13 @@ readProperties (istream &input, SGPropertyNode * start_node,
|
|||||||
* @param start_node The root node for reading properties.
|
* @param start_node The root node for reading properties.
|
||||||
* @return true if the read succeeded, false otherwise.
|
* @return true if the read succeeded, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool
|
void
|
||||||
readProperties (const string &file, SGPropertyNode * start_node)
|
readProperties (const string &file, SGPropertyNode * start_node)
|
||||||
{
|
{
|
||||||
cerr << "Reading properties from " << file << endl;
|
PropsVisitor visitor(start_node, file);
|
||||||
ifstream input(file.c_str());
|
readXML(file, visitor);
|
||||||
if (input.good()) {
|
if (visitor.hasException())
|
||||||
return readProperties(input, start_node, file);
|
throw *(visitor.getException());
|
||||||
} else {
|
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Error reading property list from file "
|
|
||||||
<< file);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -467,14 +462,7 @@ writeNode (ostream &output, const SGPropertyNode * node, int indent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
void
|
||||||
* Write a property tree to an output stream in XML format.
|
|
||||||
*
|
|
||||||
* @param output The output stream.
|
|
||||||
* @param start_node The root node to write.
|
|
||||||
* @return true if the write succeeded, false otherwise.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
writeProperties (ostream &output, const SGPropertyNode * start_node)
|
writeProperties (ostream &output, const SGPropertyNode * start_node)
|
||||||
{
|
{
|
||||||
int nChildren = start_node->nChildren();
|
int nChildren = start_node->nChildren();
|
||||||
@@ -487,28 +475,17 @@ writeProperties (ostream &output, const SGPropertyNode * start_node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
output << "</PropertyList>" << endl;
|
output << "</PropertyList>" << endl;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
void
|
||||||
* Write a property tree to a file in XML format.
|
|
||||||
*
|
|
||||||
* @param file The destination file.
|
|
||||||
* @param start_node The root node to write.
|
|
||||||
* @return true if the write succeeded, false otherwise.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
writeProperties (const string &file, const SGPropertyNode * start_node)
|
writeProperties (const string &file, const SGPropertyNode * start_node)
|
||||||
{
|
{
|
||||||
ofstream output(file.c_str());
|
ofstream output(file.c_str());
|
||||||
if (output.good()) {
|
if (output.good()) {
|
||||||
return writeProperties(output, start_node);
|
writeProperties(output, start_node);
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Cannot write properties to file "
|
throw sg_io_exception("Cannot open file", sg_location(file));
|
||||||
<< file);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,7 +542,9 @@ copyProperties (const SGPropertyNode *in, SGPropertyNode *out)
|
|||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw string("Unrecognized SGPropertyNode type");
|
string message = "Unknown internal SGPropertyNode type";
|
||||||
|
message += in->getType();
|
||||||
|
throw sg_error(message, "SimGear Property Reader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user