topical media & game development
lib-of-vs-addons-ofxXmlSettings-src-ofxXmlSettings.cpp / cpp
include <ofxXmlSettings.h>
include <vector>
include <string>
include <iostream>
//----------------------------------------
// a pretty useful tokenization system:
static vector<string> tokenize(const string & str, const string & delim);
static vector<string> tokenize(const string & str, const string & delim)
{
vector<string> tokens;
size_t p0 = 0, p1 = string::npos;
while(p0 != string::npos)
{
p1 = str.find_first_of(delim, p0);
if(p1 != p0)
{
string token = str.substr(p0, p1 - p0);
tokens.push_back(token);
}
p0 = str.find_first_not_of(delim, p1);
}
return tokens;
}
//----------------------------------------
ofxXmlSettings::ofxXmlSettings(){
storedHandle = new TiXmlHandle(NULL);
level = 0;
//we do this so that we have a valid handle
//without the need for loadFile
*storedHandle = TiXmlHandle(&doc);
}
//---------------------------------------------------------
void ofxXmlSettings::setVerbose(bool _verbose){
}
//---------------------------------------------------------
void ofxXmlSettings::clear(){
//we clear from our root level
//this is usually the document
//but if we are pushed - it could
//be all the tags inside of the pushed
//node - including the node itself!
storedHandle->ToNode()->Clear();
}
//---------------------------------------------------------
bool ofxXmlSettings::loadFile(string xmlFile){
xmlFile = ofToDataPath(xmlFile);
bool loadOkay = doc.LoadFile(xmlFile.c_str());
//theo removed bool check as it would
//return false if the file exists but was
//empty
//our push pop level should be set to 0!
level = 0;
*storedHandle = TiXmlHandle(&doc);
return loadOkay;
}
//---------------------------------------------------------
void ofxXmlSettings::saveFile(string xmlFile){
xmlFile = ofToDataPath(xmlFile);
doc.SaveFile(xmlFile.c_str());
}
//---------------------------------------------------------
void ofxXmlSettings::clearTagContents(string tag, int which){
//we check it first to see if it exists
//otherwise setValue will make a new empty tag
if( tagExists(tag, which) )setValue(tag, "", which);
}
//---------------------------------------------------------
void ofxXmlSettings::removeTag(string tag, int which){
vector<string> tokens = tokenize(tag,":");
//no tags so we return
if( tokens.size() == 0 ) return;
//grab the handle from the level we are at
//normally this is the doc but could be a pushed node
TiXmlHandle tagHandle = *storedHandle;
if(which < 0) which = 0;
for(int x=0;x<(int)tokens.size();x++){
//we only support multi tags
//with same name at root level
if(x > 0) which = 0;
TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
if ( !isRealHandle.Node() ) break;
else{
if (x == (int)tokens.size()-1){
//if we are at the last tag and it exists
//we use its parent to remove it - haha
tagHandle.ToNode()->RemoveChild( isRealHandle.ToNode() );
}
tagHandle = isRealHandle;
}
}
tokens.clear();
}
//---------------------------------------------------------
int ofxXmlSettings::getValue(string tag, int defaultValue, int which){
char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
int returnValue = defaultValue;
if (readTag(tag, tempStr, which)){
returnValue = strtol(tempStr, NULL, 0);
}
delete tempStr;
return returnValue;
}
//---------------------------------------------------------
float ofxXmlSettings::getValue(string tag, double defaultValue, int which){
char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
float returnValue = defaultValue;
if (readTag(tag, tempStr, which)){
returnValue = strtod(tempStr, NULL);
}
delete tempStr;
return returnValue;
}
//---------------------------------------------------------
string ofxXmlSettings::getValue(string tag, string defaultValue, int which){
// lots of char *, string kung-fu here...
char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
char * returnPtr = (char *) defaultValue.c_str();
if (readTag(tag, tempStr, which)){
returnPtr = tempStr;
}
string returnString(returnPtr);
delete tempStr;
return returnString;
}
//---------------------------------------------------------
bool ofxXmlSettings::readTag(string tag, char * valueString, int which){
vector<string> tokens = tokenize(tag,":");
TiXmlHandle tagHandle = *storedHandle;
for(int x=0;x<(int)tokens.size();x++){
if(x == 0)tagHandle = tagHandle.ChildElement(tokens.at(x), which);
else tagHandle = tagHandle.FirstChildElement( tokens.at(x) );
}
// once we've walked, let's get that value...
TiXmlHandle valHandle = tagHandle.Child( 0 );
//now, clear that vector!
tokens.clear();
// if that value is really text, let's get the value out of it !
if (valHandle.Text()){
int maxLen = MIN(MAX_TAG_VALUE_LENGTH_IN_CHARS, strlen(valHandle.Text()->Value()));
memcpy(valueString, valHandle.Text()->Value(), maxLen);
return true;
} else {
return false;
}
}
//---------------------------------------------------------
bool ofxXmlSettings::pushTag(string tag, int which){
int pos = tag.find(":");
if(pos > 0){
tag = tag.substr(0,pos);
}
//we only allow to push one tag at a time.
TiXmlHandle isRealHandle = storedHandle->ChildElement(tag, which);
if( isRealHandle.Node() ){
*storedHandle = isRealHandle;
level++;
return true;
}else{
printf("pushTag - tag not found\n");
}
return false;
}
//---------------------------------------------------------
int ofxXmlSettings::popTag(){
if(level >= 1){
TiXmlHandle parent( (storedHandle->ToNode() )->Parent() );
*storedHandle = parent;
level--;
}else{
*storedHandle = TiXmlHandle(&doc);
level = 0;
}
return level;
}
//---------------------------------------------------------
int ofxXmlSettings::getPushLevel(){
return level;
}
//---------------------------------------------------------
bool ofxXmlSettings::tagExists(string tag, int which){
vector<string> tokens = tokenize(tag,":");
bool found = false;
//grab the handle from the level we are at
//normally this is the doc but could be a pushed node
TiXmlHandle tagHandle = *storedHandle;
if(which < 0) which = 0;
for(int x=0;x<(int)tokens.size();x++){
//we only support multi tags
//with same name at root level
if(x > 0) which = 0;
TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
//as soon as we find a tag that doesn't exist
//we return false;
if ( !isRealHandle.Node() ){
found = false;
break;
}
else{
found = true;
tagHandle = isRealHandle;
}
}
tokens.clear();
return found;
}
//---------------------------------------------------------
int ofxXmlSettings::getNumTags(string tag){
//this only works for tags at the current root level
int pos = tag.find(":");
if(pos > 0){
tag = tag.substr(0,pos);
}
//grab the handle from the level we are at
//normally this is the doc but could be a pushed node
TiXmlHandle tagHandle = *storedHandle;
int count = 0;
//ripped from tinyXML as doing this ourselves once is a LOT! faster
//than having this called n number of times in a while loop - we go from n*n iterations to n iterations
TiXmlElement* child = ( storedHandle->FirstChildElement( tag ) ).Element();
for (count = 0; child; child = child->NextSiblingElement( tag ), ++count){
//nothing
}
return count;
}
//---------------------------------------------------------
int ofxXmlSettings::writeTag(string tag, char * valueStr, int which){
vector<string> tokens = tokenize(tag,":");
// allocate then clean up :
TiXmlElement ** elements = new TiXmlElement*[tokens.size()];
for(int x=0;x<(int)tokens.size();x++){
elements[x] = new TiXmlElement(tokens.at(x));
}
TiXmlText Value(valueStr);
// search our way up - do these tags exist?
// find the first that DOESNT exist, then move backwards...
TiXmlHandle tagHandle = *storedHandle;
bool addNewTag = false;
if(which == -1)addNewTag = true;
for(int x=0;x<(int)tokens.size();x++){
if( x > 0 ){
//multi tags of same name
//only for the root level
which = 0;
addNewTag = false;
}
TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
if ( !isRealHandle.Node() || addNewTag){
for(int i=tokens.size()-1;i>=x;i--){
if (i == (int)tokens.size()-1){
elements[i]->InsertEndChild(Value);
} else {
elements[i]->InsertEndChild(*(elements[i+1]));
}
}
tagHandle.ToNode()->InsertEndChild(*(elements[x]));
break;
} else {
tagHandle = isRealHandle;
if (x == (int)tokens.size()-1){
// what we want to change : TiXmlHandle valHandle = tagHandle.Child( 0 );
tagHandle.ToNode()->Clear();
tagHandle.ToNode()->InsertEndChild(Value);
}
}
}
//lets count how many tags with our name exist so we can return an index
//ripped from tinyXML as doing this ourselves once is a LOT! faster
//than having this called n number of times in a while loop - we go from n*n iterations to n iterations
int numSameTags;
TiXmlElement* child = ( storedHandle->FirstChildElement( tokens.at(0) ) ).Element();
for (numSameTags = 0; child; child = child->NextSiblingElement( tokens.at(0) ), ++numSameTags){
//nothing
}
//now, clear that vector!
tokens.clear();
return numSameTags;
}
//---------------------------------------------------------
int ofxXmlSettings::setValue(string tag, int value, int which){
char valueStr[255];
sprintf(valueStr, "\%i", value);
int tagID = writeTag(tag, valueStr, which) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::setValue(string tag, double value, int which){
char valueStr[255];
sprintf(valueStr, "\%f", value);
int tagID = writeTag(tag, valueStr, which) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::setValue(string tag, string value, int which){
int tagID = writeTag(tag, (char *)value.c_str(), which) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::addValue(string tag, int value){
char valueStr[255];
sprintf(valueStr, "\%i", value);
int tagID = writeTag(tag, valueStr, -1) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::addValue(string tag, double value){
char valueStr[255];
sprintf(valueStr, "\%f", value);
int tagID = writeTag(tag, valueStr, -1) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::addValue(string tag, string value){
int tagID = writeTag(tag, (char *)value.c_str(), -1) -1;
return tagID;
}
//---------------------------------------------------------
int ofxXmlSettings::addTag(string tag){
int tagID = writeTag(tag, "", -1) -1;
return tagID;
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.