9/05/2000 updates from David Megginson relating to the property manager and
easyxml support. This is a bit of simgear side support to facilitate a configurable instrument panel in flightgear.
This commit is contained in:
@@ -21,6 +21,7 @@ libsgmisc_a_SOURCES = \
|
||||
fgpath.cxx \
|
||||
fgstream.cxx \
|
||||
props.cxx \
|
||||
props_io.cxx \
|
||||
strutils.cxx \
|
||||
texcoord.cxx \
|
||||
zfstream.cxx
|
||||
|
||||
@@ -304,8 +304,6 @@ float
|
||||
SGValue::getFloatValue () const
|
||||
{
|
||||
switch (_type) {
|
||||
case UNKNOWN:
|
||||
return 0.0;
|
||||
case BOOL:
|
||||
return (float)(getRawBool());
|
||||
case INT:
|
||||
@@ -314,6 +312,7 @@ SGValue::getFloatValue () const
|
||||
return getRawFloat();
|
||||
case DOUBLE:
|
||||
return (float)(getRawDouble());
|
||||
case UNKNOWN:
|
||||
case STRING:
|
||||
return (float)atof(getRawString().c_str());
|
||||
}
|
||||
@@ -330,8 +329,6 @@ double
|
||||
SGValue::getDoubleValue () const
|
||||
{
|
||||
switch (_type) {
|
||||
case UNKNOWN:
|
||||
return 0.0;
|
||||
case BOOL:
|
||||
return (double)(getRawBool());
|
||||
case INT:
|
||||
@@ -340,6 +337,7 @@ SGValue::getDoubleValue () const
|
||||
return (double)(getRawFloat());
|
||||
case DOUBLE:
|
||||
return getRawDouble();
|
||||
case UNKNOWN:
|
||||
case STRING:
|
||||
return atof(getRawString().c_str());
|
||||
}
|
||||
@@ -357,8 +355,6 @@ SGValue::getStringValue () const
|
||||
{
|
||||
char buf[512];
|
||||
switch (_type) {
|
||||
case UNKNOWN:
|
||||
return getRawString();
|
||||
case BOOL:
|
||||
if (getRawBool())
|
||||
string_val = "true";
|
||||
@@ -377,6 +373,7 @@ SGValue::getStringValue () const
|
||||
sprintf(buf, "%f", getRawDouble());
|
||||
string_val = buf;
|
||||
return string_val;
|
||||
case UNKNOWN:
|
||||
case STRING:
|
||||
return getRawString();
|
||||
}
|
||||
@@ -739,11 +736,11 @@ SGPropertyList::getValue (const string &name) const
|
||||
* better to get the SGValue and query it repeatedly.
|
||||
*/
|
||||
bool
|
||||
SGPropertyList::getBoolValue (const string &name) const
|
||||
SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
|
||||
{
|
||||
const SGValue * val = getValue(name);
|
||||
if (val == 0)
|
||||
return false;
|
||||
return defaultValue;
|
||||
else
|
||||
return val->getBoolValue();
|
||||
}
|
||||
@@ -756,11 +753,11 @@ SGPropertyList::getBoolValue (const string &name) const
|
||||
* better to get the SGValue and query it repeatedly.
|
||||
*/
|
||||
int
|
||||
SGPropertyList::getIntValue (const string &name) const
|
||||
SGPropertyList::getIntValue (const string &name, int defaultValue) const
|
||||
{
|
||||
const SGValue * val = getValue(name);
|
||||
if (val == 0)
|
||||
return 0;
|
||||
return defaultValue;
|
||||
else
|
||||
return val->getIntValue();
|
||||
}
|
||||
@@ -773,11 +770,11 @@ SGPropertyList::getIntValue (const string &name) const
|
||||
* better to get the SGValue and query it repeatedly.
|
||||
*/
|
||||
float
|
||||
SGPropertyList::getFloatValue (const string &name) const
|
||||
SGPropertyList::getFloatValue (const string &name, float defaultValue) const
|
||||
{
|
||||
const SGValue * val = getValue(name);
|
||||
if (val == 0)
|
||||
return 0.0;
|
||||
return defaultValue;
|
||||
else
|
||||
return val->getFloatValue();
|
||||
}
|
||||
@@ -790,11 +787,11 @@ SGPropertyList::getFloatValue (const string &name) const
|
||||
* better to get the SGValue and query it repeatedly.
|
||||
*/
|
||||
double
|
||||
SGPropertyList::getDoubleValue (const string &name) const
|
||||
SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
|
||||
{
|
||||
const SGValue * val = getValue(name);
|
||||
if (val == 0)
|
||||
return 0.0;
|
||||
return defaultValue;
|
||||
else
|
||||
return val->getDoubleValue();
|
||||
}
|
||||
@@ -807,11 +804,12 @@ SGPropertyList::getDoubleValue (const string &name) const
|
||||
* better to save the SGValue and query it repeatedly.
|
||||
*/
|
||||
const string &
|
||||
SGPropertyList::getStringValue (const string &name) const
|
||||
SGPropertyList::getStringValue (const string &name,
|
||||
const string &defaultValue) const
|
||||
{
|
||||
const SGValue * val = getValue(name);
|
||||
if (val == 0)
|
||||
return empty_string;
|
||||
return defaultValue;
|
||||
else
|
||||
return val->getStringValue();
|
||||
}
|
||||
@@ -1041,7 +1039,7 @@ get_base (const string &parent, const string &child,
|
||||
*/
|
||||
SGPropertyNode::SGPropertyNode (const string &path = "",
|
||||
SGPropertyList * props = 0)
|
||||
: _props(props)
|
||||
: _props(props), _node(0)
|
||||
{
|
||||
setPath(path);
|
||||
}
|
||||
@@ -1052,6 +1050,8 @@ SGPropertyNode::SGPropertyNode (const string &path = "",
|
||||
*/
|
||||
SGPropertyNode::~SGPropertyNode ()
|
||||
{
|
||||
delete _node;
|
||||
_node = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1089,24 +1089,6 @@ SGPropertyNode::getName () const
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of the current node.
|
||||
*
|
||||
* Currently, this does a lookup each time, but we could cache the
|
||||
* value safely as long as it's non-zero.
|
||||
*
|
||||
* Note that this will not create the value if it doesn't already exist.
|
||||
*/
|
||||
SGValue *
|
||||
SGPropertyNode::getValue ()
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return 0;
|
||||
else
|
||||
return _props->getValue(_path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of children for the current node.
|
||||
*/
|
||||
@@ -1143,17 +1125,18 @@ SGPropertyNode::size () const
|
||||
* A return value of true means success; otherwise, the node supplied
|
||||
* is unmodified.
|
||||
*/
|
||||
bool
|
||||
SGPropertyNode::getParent (SGPropertyNode &parent) const
|
||||
SGPropertyNode &
|
||||
SGPropertyNode::getParent () const
|
||||
{
|
||||
if (_node == 0)
|
||||
_node = new SGPropertyNode();
|
||||
|
||||
string::size_type pos = _path.rfind('/');
|
||||
if (pos != string::npos) {
|
||||
parent.setPath(_path.substr(0, pos-1));
|
||||
parent.setPropertyList(_props);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
_node->setPropertyList(_props);
|
||||
_node->setPath(_path.substr(0, pos-1));
|
||||
}
|
||||
return *_node;
|
||||
}
|
||||
|
||||
|
||||
@@ -1163,11 +1146,14 @@ SGPropertyNode::getParent (SGPropertyNode &parent) const
|
||||
* A return value of true means success; otherwise, the node supplied
|
||||
* is unmodified.
|
||||
*/
|
||||
bool
|
||||
SGPropertyNode::getChild (SGPropertyNode &child, int n) const
|
||||
SGPropertyNode &
|
||||
SGPropertyNode::getChild (int n) const
|
||||
{
|
||||
if (_node == 0)
|
||||
_node = new SGPropertyNode();
|
||||
|
||||
if (_props == 0)
|
||||
return false;
|
||||
return *_node;
|
||||
|
||||
int s = 0;
|
||||
string base;
|
||||
@@ -1180,12 +1166,9 @@ SGPropertyNode::getChild (SGPropertyNode &child, int n) const
|
||||
while (it != end) {
|
||||
if (get_base(pattern, it->first, base) && base != lastBase) {
|
||||
if (s == n) {
|
||||
string path = _path;
|
||||
path += '/';
|
||||
path += base;
|
||||
child.setPath(path);
|
||||
child.setPropertyList(_props);
|
||||
return true;
|
||||
_node->setPropertyList(_props);
|
||||
_node->setPath(_path + string("/") + base);
|
||||
return *_node;
|
||||
} else {
|
||||
s++;
|
||||
lastBase = base;
|
||||
@@ -1194,7 +1177,133 @@ SGPropertyNode::getChild (SGPropertyNode &child, int n) const
|
||||
it++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return *_node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a node for an arbitrary subpath.
|
||||
*
|
||||
* Never returns 0.
|
||||
*/
|
||||
SGPropertyNode &
|
||||
SGPropertyNode::getSubNode (const string &subpath) const
|
||||
{
|
||||
if (_node == 0)
|
||||
_node = new SGPropertyNode();
|
||||
|
||||
_node->setPropertyList(_props);
|
||||
_node->setPath(_path + string("/") + subpath);
|
||||
return *_node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of the current node.
|
||||
*
|
||||
* Currently, this does a lookup each time, but we could cache the
|
||||
* value safely as long as it's non-zero.
|
||||
*
|
||||
* Note that this will not create the value if it doesn't already exist.
|
||||
*/
|
||||
SGValue *
|
||||
SGPropertyNode::getValue (const string &subpath)
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return 0;
|
||||
|
||||
if (subpath.size() == 0)
|
||||
return _props->getValue(_path);
|
||||
else
|
||||
return _props->getValue(_path + string("/") + subpath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a bool value.
|
||||
*/
|
||||
bool
|
||||
SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return defaultValue;
|
||||
|
||||
if (subpath == "")
|
||||
return _props->getBoolValue(_path, defaultValue);
|
||||
else
|
||||
return _props->getBoolValue(_path + string("/") + subpath,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an int value.
|
||||
*/
|
||||
int
|
||||
SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return defaultValue;
|
||||
|
||||
if (subpath == "")
|
||||
return _props->getIntValue(_path, defaultValue);
|
||||
else
|
||||
return _props->getIntValue(_path + string("/") + subpath,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a float value.
|
||||
*/
|
||||
float
|
||||
SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return defaultValue;
|
||||
|
||||
if (subpath == "")
|
||||
return _props->getFloatValue(_path, defaultValue);
|
||||
else
|
||||
return _props->getFloatValue(_path + string("/") + subpath,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a double value.
|
||||
*/
|
||||
double
|
||||
SGPropertyNode::getDoubleValue (const string &subpath,
|
||||
double defaultValue) const
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return defaultValue;
|
||||
|
||||
if (subpath == "")
|
||||
return _props->getDoubleValue(_path, defaultValue);
|
||||
else
|
||||
return _props->getDoubleValue(_path + string("/") + subpath,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string value.
|
||||
*/
|
||||
const string &
|
||||
SGPropertyNode::getStringValue (const string &subpath,
|
||||
const string &defaultValue) const
|
||||
{
|
||||
if (_props == 0 || _path.size() == 0)
|
||||
return defaultValue;
|
||||
|
||||
if (subpath == "")
|
||||
return _props->getStringValue(_path, defaultValue);
|
||||
else
|
||||
return _props->getStringValue(_path + string("/") + subpath,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
|
||||
// end of props.cxx
|
||||
|
||||
@@ -19,9 +19,42 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
using std::map;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
|
||||
#ifdef UNKNOWN
|
||||
#pragma warn A sloppy coder has defined UNKNOWN as a macro!
|
||||
#undef UNKNOWN
|
||||
#endif
|
||||
|
||||
#ifdef BOOL
|
||||
#pragma warn A sloppy coder has defined BOOL as a macro!
|
||||
#undef BOOL
|
||||
#endif
|
||||
|
||||
#ifdef INT
|
||||
#pragma warn A sloppy coder has defined INT as a macro!
|
||||
#undef INT
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT
|
||||
#pragma warn A sloppy coder has defined FLOAT as a macro!
|
||||
#undef FLOAT
|
||||
#endif
|
||||
|
||||
#ifdef DOUBLE
|
||||
#pragma warn A sloppy coder has defined DOUBLE as a macro!
|
||||
#undef DOUBLE
|
||||
#endif
|
||||
|
||||
#ifdef STRING
|
||||
#pragma warn A sloppy coder has defined STRING as a macro!
|
||||
#undef STRING
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -80,7 +113,7 @@ public:
|
||||
virtual int getIntValue () const;
|
||||
virtual float getFloatValue () const;
|
||||
virtual double getDoubleValue () const;
|
||||
virtual const string &getStringValue () const;
|
||||
virtual const string & getStringValue () const;
|
||||
|
||||
// Setters.
|
||||
virtual bool setBoolValue (bool value);
|
||||
@@ -231,11 +264,17 @@ public:
|
||||
virtual SGValue * getValue (const string &name, bool create = false);
|
||||
virtual const SGValue * getValue (const string &name) const;
|
||||
|
||||
virtual bool getBoolValue (const string &name) const;
|
||||
virtual int getIntValue (const string &name) const;
|
||||
virtual float getFloatValue (const string &name) const;
|
||||
virtual double getDoubleValue (const string &name) const;
|
||||
virtual const string &getStringValue (const string &name) const;
|
||||
virtual bool getBoolValue (const string &name,
|
||||
bool defaultValue = false) const;
|
||||
virtual int getIntValue (const string &name,
|
||||
int defaultValue = 0) const;
|
||||
virtual float getFloatValue (const string &name,
|
||||
float defaultValue = 0.0) const;
|
||||
virtual double getDoubleValue (const string &name,
|
||||
double defaultValue = 0.0L) const;
|
||||
virtual const string & getStringValue (const string &name,
|
||||
const string &defaultValue = "")
|
||||
const;
|
||||
|
||||
virtual bool setBoolValue (const string &name, bool value);
|
||||
virtual bool setIntValue (const string &name, int value);
|
||||
@@ -331,17 +370,45 @@ public:
|
||||
// Accessors for derived information.
|
||||
virtual int size () const;
|
||||
virtual const string &getName () const;
|
||||
virtual SGValue * getValue ();
|
||||
virtual bool getParent (SGPropertyNode &parent) const;
|
||||
virtual bool getChild (SGPropertyNode &child, int n) const;
|
||||
virtual SGPropertyNode &getParent () const;
|
||||
virtual SGPropertyNode &getChild (int n) const;
|
||||
virtual SGPropertyNode &getSubNode (const string &subpath) const;
|
||||
|
||||
// Get values directly.
|
||||
virtual SGValue * getValue (const string &subpath = "");
|
||||
virtual bool getBoolValue (const string &subpath = "",
|
||||
bool defaultValue = false) const;
|
||||
virtual int getIntValue (const string &subpath = "",
|
||||
int defaultValue = 0) const;
|
||||
virtual float getFloatValue (const string &subpath = "",
|
||||
float defaultValue = 0.0) const;
|
||||
virtual double getDoubleValue (const string &subpath = "",
|
||||
double defaultValue = 0.0L) const;
|
||||
virtual const string &
|
||||
getStringValue (const string &subpath = "",
|
||||
const string &defaultValue = "") const;
|
||||
|
||||
private:
|
||||
string _path;
|
||||
mutable string _name; // for pointer persistence only
|
||||
SGPropertyList * _props;
|
||||
// for pointer persistence...
|
||||
// NOT THREAD SAFE!!!
|
||||
// (each thread must have its own node
|
||||
// object)
|
||||
mutable string _name;
|
||||
mutable SGPropertyNode * _node;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Input and output.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern bool readPropertyList (istream &input, SGPropertyList * props);
|
||||
extern bool writePropertyList (ostream &output, const SGPropertyList * props);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Global property manager.
|
||||
|
||||
332
simgear/misc/props_io.cxx
Normal file
332
simgear/misc/props_io.cxx
Normal file
@@ -0,0 +1,332 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/xml/easyxml.hxx>
|
||||
|
||||
#include "props.hxx"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Visitor class for building the property list.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PropVisitor : public XMLVisitor
|
||||
{
|
||||
public:
|
||||
PropVisitor (SGPropertyList * props) : _props(props), _level(0), _ok(true) {}
|
||||
void startDocument ();
|
||||
void startElement (const char * name, const XMLAttributes &atts);
|
||||
void endElement (const char * name);
|
||||
void data (const char * s, int length);
|
||||
void warning (const char * message, int line, int col);
|
||||
void error (const char * message, int line, int col);
|
||||
|
||||
bool isOK () const { return _ok; }
|
||||
|
||||
private:
|
||||
|
||||
void pushState (const char * name) {
|
||||
_states.push_back(_state);
|
||||
_level++;
|
||||
_state.name = name;
|
||||
_state.type = SGValue::UNKNOWN;
|
||||
_state.data = "";
|
||||
_state.hasChildren = false;
|
||||
_state.hasData = false;
|
||||
}
|
||||
|
||||
void popState () {
|
||||
_state = _states.back();
|
||||
_states.pop_back();
|
||||
_level--;
|
||||
}
|
||||
|
||||
struct State
|
||||
{
|
||||
State () : hasChildren(false), hasData(false) {}
|
||||
string name;
|
||||
SGValue::Type type;
|
||||
string data;
|
||||
bool hasChildren;
|
||||
bool hasData;
|
||||
};
|
||||
|
||||
SGPropertyList * _props;
|
||||
State _state;
|
||||
vector<State> _states;
|
||||
int _level;
|
||||
bool _ok;
|
||||
};
|
||||
|
||||
void
|
||||
PropVisitor::startDocument ()
|
||||
{
|
||||
_level = 0;
|
||||
_ok = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PropVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
{
|
||||
if (!_ok)
|
||||
return;
|
||||
|
||||
if (_level == 0 && strcmp(name, "PropertyList")) {
|
||||
_ok = false;
|
||||
FG_LOG(FG_INPUT, FG_ALERT, "XML document has root element \""
|
||||
<< name << "\" instead of \"PropertyList\"");
|
||||
return;
|
||||
}
|
||||
|
||||
// Mixed content?
|
||||
_state.hasChildren = true;
|
||||
if (_state.hasData) {
|
||||
FG_LOG(FG_INPUT, FG_ALERT,
|
||||
"XML element has mixed elements and data in element "
|
||||
<< _state.name);
|
||||
_ok = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start a new state.
|
||||
pushState(name);
|
||||
|
||||
// See if there's a type specified.
|
||||
const char * type = atts.getValue("type");
|
||||
if (type == 0 || !strcmp("unknown", type))
|
||||
_state.type = SGValue::UNKNOWN;
|
||||
else if (!strcmp("bool", type))
|
||||
_state.type = SGValue::BOOL;
|
||||
else if (!strcmp("int", type))
|
||||
_state.type = SGValue::INT;
|
||||
else if (!strcmp("float", type))
|
||||
_state.type = SGValue::FLOAT;
|
||||
else if (!strcmp("double", type))
|
||||
_state.type = SGValue::DOUBLE;
|
||||
else if (!strcmp("string", type))
|
||||
_state.type = SGValue::STRING;
|
||||
else
|
||||
FG_LOG(FG_INPUT, FG_ALERT, "Unrecognized type " << type
|
||||
<< ", using UNKNOWN");
|
||||
}
|
||||
|
||||
void
|
||||
PropVisitor::endElement (const char * name)
|
||||
{
|
||||
if (!_ok)
|
||||
return;
|
||||
|
||||
// See if there's a property to add.
|
||||
if (_state.hasData) {
|
||||
bool status = false;
|
||||
|
||||
// Figure out the path name.
|
||||
string path = "";
|
||||
for (int i = 2; i < _level; i++) {
|
||||
path += '/';
|
||||
path += _states[i].name;
|
||||
}
|
||||
path += '/';
|
||||
path += _state.name;
|
||||
|
||||
// Set the value
|
||||
switch (_state.type) {
|
||||
case SGValue::BOOL:
|
||||
if (_state.data == "true" || _state.data == "TRUE") {
|
||||
status = _props->setBoolValue(path, true);
|
||||
} else if (atof(_state.data.c_str()) != 0.0) {
|
||||
status = _props->setBoolValue(path, true);
|
||||
} else {
|
||||
status =_props->setBoolValue(path, false);
|
||||
}
|
||||
break;
|
||||
case SGValue::INT :
|
||||
status = _props->setIntValue(path, atoi(_state.data.c_str()));
|
||||
break;
|
||||
case SGValue::FLOAT:
|
||||
status = _props->setFloatValue(path, atof(_state.data.c_str()));
|
||||
break;
|
||||
case SGValue::DOUBLE:
|
||||
status = _props->setDoubleValue(path, atof(_state.data.c_str()));
|
||||
break;
|
||||
case SGValue::STRING:
|
||||
status = _props->setStringValue(path, _state.data);
|
||||
break;
|
||||
default:
|
||||
status = _props->setUnknownValue(path, _state.data);
|
||||
break;
|
||||
}
|
||||
if (!status)
|
||||
FG_LOG(FG_INPUT, FG_ALERT, "Failed to set property "
|
||||
<< path << " to " << _state.data);
|
||||
}
|
||||
|
||||
// Pop the stack.
|
||||
popState();
|
||||
}
|
||||
|
||||
void
|
||||
PropVisitor::data (const char * s, int length)
|
||||
{
|
||||
if (!_ok)
|
||||
return;
|
||||
|
||||
// Check if there is any non-whitespace
|
||||
if (!_state.hasData)
|
||||
for (int i = 0; i < length; i++)
|
||||
if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n' && s[i] != '\r')
|
||||
_state.hasData = true;
|
||||
|
||||
_state.data += string(s, length); // FIXME: inefficient
|
||||
}
|
||||
|
||||
void
|
||||
PropVisitor::warning (const char * message, int line, int col)
|
||||
{
|
||||
FG_LOG(FG_INPUT, FG_ALERT, "Warning importing property list: "
|
||||
<< message << " (" << line << ',' << col << ')');
|
||||
}
|
||||
|
||||
void
|
||||
PropVisitor::error (const char * message, int line, int col)
|
||||
{
|
||||
FG_LOG(FG_INPUT, FG_ALERT, "Error importing property list: "
|
||||
<< message << " (" << line << ',' << col << ')');
|
||||
_ok = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Property list reader.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
readPropertyList (istream &input, SGPropertyList * props)
|
||||
{
|
||||
PropVisitor visitor(props);
|
||||
return readXML(input, visitor) && visitor.isOK();
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Property list writer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define INDENT_STEP 2
|
||||
|
||||
/**
|
||||
* Return the type name.
|
||||
*/
|
||||
static const char *
|
||||
getTypeName (SGValue::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SGValue::UNKNOWN:
|
||||
return "unknown";
|
||||
case SGValue::BOOL:
|
||||
return "bool";
|
||||
case SGValue::INT:
|
||||
return "int";
|
||||
case SGValue::FLOAT:
|
||||
return "float";
|
||||
case SGValue::DOUBLE:
|
||||
return "double";
|
||||
case SGValue::STRING:
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape characters for output.
|
||||
*/
|
||||
static void
|
||||
writeData (ostream &output, const string &data)
|
||||
{
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
switch (data[i]) {
|
||||
case '&':
|
||||
output << "&";
|
||||
break;
|
||||
case '<':
|
||||
output << "<";
|
||||
break;
|
||||
case '>':
|
||||
output << ">";
|
||||
break;
|
||||
default:
|
||||
output << data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
doIndent (ostream &output, int indent)
|
||||
{
|
||||
while (indent-- > 0) {
|
||||
output << ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
writeNode (ostream &output, SGPropertyNode node, int indent)
|
||||
{
|
||||
const string &name = node.getName();
|
||||
int size = node.size();
|
||||
|
||||
// Write out the literal value, if any.
|
||||
SGValue * value = node.getValue();
|
||||
if (value != 0) {
|
||||
SGValue::Type type = value->getType();
|
||||
doIndent(output, indent);
|
||||
output << '<' << name;
|
||||
if (type != SGValue::UNKNOWN)
|
||||
output << " type=\"" << getTypeName(type) << '"';
|
||||
output << '>';
|
||||
writeData(output, value->getStringValue());
|
||||
output << "</" << name << '>' << endl;
|
||||
}
|
||||
|
||||
// Write out the children, if any.
|
||||
if (size > 0) {
|
||||
doIndent(output, indent);
|
||||
output << '<' << name << '>' << endl;;
|
||||
for (int i = 0; i < size; i++) {
|
||||
writeNode(output, node.getChild(i), indent + INDENT_STEP);
|
||||
}
|
||||
doIndent(output, indent);
|
||||
output << "</" << name << '>' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
writePropertyList (ostream &output, const SGPropertyList * props)
|
||||
{
|
||||
SGPropertyNode root ("/", (SGPropertyList *)props); // FIXME
|
||||
|
||||
output << "<?xml version=\"1.0\"?>" << endl << endl;
|
||||
output << "<PropertyList>" << endl;
|
||||
|
||||
for (int i = 0; i < root.size(); i++) {
|
||||
writeNode(output, root.getChild(i), INDENT_STEP);
|
||||
}
|
||||
|
||||
output << "</PropertyList>" << endl;
|
||||
}
|
||||
@@ -20,9 +20,10 @@ int
|
||||
XMLAttributes::findAttribute (const char * name) const
|
||||
{
|
||||
int s = size();
|
||||
for (int i = 0; i < s; i++)
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (strcmp(name, getName(i)) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ XMLAttributes::getValue (const char * name) const
|
||||
if (pos >= 0)
|
||||
return getValue(pos);
|
||||
else
|
||||
return getValue(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,9 +123,9 @@ class ExpatAtts : public XMLAttributes
|
||||
public:
|
||||
ExpatAtts (const char ** atts) : _atts(atts) {}
|
||||
|
||||
int size () const;
|
||||
const char * getName (int i) const;
|
||||
const char * getValue (int i) const;
|
||||
virtual int size () const;
|
||||
virtual const char * getName (int i) const;
|
||||
virtual const char * getValue (int i) const;
|
||||
|
||||
private:
|
||||
const char ** _atts;
|
||||
@@ -162,8 +163,7 @@ ExpatAtts::getValue (int i) const
|
||||
static void
|
||||
start_element (void * userData, const char * name, const char ** atts)
|
||||
{
|
||||
ExpatAtts attributes(atts);
|
||||
VISITOR.startElement(name, attributes);
|
||||
VISITOR.startElement(name, ExpatAtts(atts));
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
Reference in New Issue
Block a user