Click here to Skip to main content
15,885,435 members
Articles / Programming Languages / XML

Read and Write application parameters in XML

Rate me:
Please Sign up or sign in to vote.
4.38/5 (33 votes)
30 Jun 20034 min read 1.6M   6.8K   141  
This article provides an easy way to load and save the parameters of an application in XML format.
#include "XmlParser.h"

XmlParser::XmlParser () :
_strParse()
{ 
	clear(); 

	// get parser id
	_id = _parseid;

	// next id
	_parseid++;
}

// create/release
bool XmlParser::create ( const char * buffer, long parseStart, long parseEnd )
{
	// if invalid stop
	if ( !buffer || parseStart < 0 || parseEnd < parseStart )
		return false;

	return create( buffer + parseStart, getLength(parseStart,parseEnd) );
}	



bool XmlParser::create ( const char * buffer, long length )
{
	// if invalid stop
	if ( !buffer || length <= 0 )
		return false;

	// parse buffer and offsets of where we are parsing
	_buffer      = (char *) buffer;
	_parseLength = length;

	// current position in parse buffer
	_current    = 0;

	return true;
}	

void XmlParser::release ()
{

}

// cur position methods
long XmlParser::getCurrent ()
{
	return _current;
}

long XmlParser::getParseLength ()
{
	return _parseLength;
}

long XmlParser::getCurLength ()
{
	return getOffsetLength(_current);
}

long XmlParser::getOffsetLength ( long offset )
{
	return getLength(offset,_parseLength - 1);
}


char * XmlParser::getBufferPos ()
{
	return _buffer;
}

char * XmlParser::getLastBufferPos ()
{
	return _buffer + _parseLength;
}

char * XmlParser::getCurPos ()
{
	if ( isValid() )
		return _buffer + _current;
	else
		return NULL;
}

char * XmlParser::getParseState ( long & parseLength )
{
	// if not valid stop
	if ( !isValid() )
	{
		parseLength = 0;
		return getCurPos();
	}

	/*
	// if value has length
	if ( getValueLength() > 0 )
	{
		// if value has a tag it must be parsed
		if ( valueHasTag() )
		{
			// get parse length
			parseLength = getValueLength();

			// return ptr to start of value
			return _buffer + _valueStart;
		}
	}
	*/

	// get parse state
	parseLength = getCurLength();

	// get current buffer position
	//char * buffer = getCurPos();

	// if last tag is valid
	/*
	if ( hasLastTag() )
	{
		// if current position is in last tag
		// pos then show stop
		if ( getCurPos() >= getLastTagPos() )
		{
			parseLength = 0;
			return getLastBufferPos();
		}
	}
	*/

	return getCurPos();

}

// get ref to parse buffer
std::string & XmlParser::str ()
{
	return _strParse;
}

// state methods
void XmlParser::reset ()
{
	resetTagPositions();
}

bool XmlParser::isValid ()
{
	// if buffer state not valid
	if ( !_buffer || _parseLength <= 0 )
		return false;

	// if cur position not valid
	if ( _current < 0 || _current > _parseLength )
		return false;

	return true;
}

void XmlParser::resetTagPositions ( long start)
{
	// set tag positions
	_firstTagStart  = start;
	_firstTagEnd	= start;

	_lastTagStart   = start;
	_lastTagEnd	    = start;

	_nameStart	    = start;
	_nameEnd		= start;

	_attrStart      = start;
	_attrEnd        = start;

	_valueStart     = start;
	_valueEnd       = start;
}

void XmlParser::clear ()
{
	// parse buffer and offsets of where we are parsing
	_buffer		 = 0;
	_parseLength = 0;

	// current position in parse buffer
	_current	= 0;

	// reset tag positions
	reset();
}

// parse methods
bool XmlParser::parse ( const char * buffer, long parseStart, long parseEnd )
{
	// if create fails stop
	if ( !create(buffer,parseStart,parseEnd) )
		return false;

	return parse();
}

bool XmlParser::parse ( const char * buffer, long parseLength )
{
	// if create fails stop
	if ( !create(buffer,parseLength) )
		return false;

	return parse();
}

bool XmlParser::parse () 
{
	// init tag position
	_firstTagStart = _current;
	_firstTagEnd   = _current;

	_lastTagStart  = _current;
	_lastTagEnd    = _current;

				 
	// find first tag
	long first = find( idTagLeft, _current );
	if ( first == -1 )
		return false;


	// if find right tag
	long last  = find( idTagRight, first );
	if ( last == -1  )
		return false;

	// set first tag start/end
	_firstTagStart = first;
	_firstTagEnd   = last;

	// now parse name
	if ( !parseName() )
		return false;

	// parse attributes
	parseAttributes();

	// if null tag no data or last tag
	if ( hasNullTag() || isSpecialXMLTag() )
	{
		// update cur position
		_current  = _firstTagEnd + idTagRightLength;

		// done so show success
		return true;
	}		

	// form end tag
	std::string endTag;
	endTag  = idTagEnd;
	endTag += getName();
	endTag += idTagRight;

	// find last tag
	first = find( endTag, last );
	if ( first == -1 )
		return false;


   // ARNAUD bug fix
   // If there is a tag with the same name before endTag we're in troubles
   // So we have to check this possibility
	std::string Tag;
	Tag  = idTagLeft;
	Tag += getName();
	Tag += idTagRight;

   long sameNameFirst; 
   while((sameNameFirst = find(Tag, last, first-last)) != -1)
   {
      // We have to fix
      first = find(endTag, first+1);
	   if ( first == -1 )
		   return false;
      last = sameNameFirst+1;
   }
   // ARNAUD bug fix

	// set last tag start/end
	_lastTagStart = first;
	_lastTagEnd   = first + endTag.size() - 1;

	// parse the value if not a null tag
	if ( !hasNullTag() )
		parseValue();

	// update cur position
	// we have parsed a tag so look for the start
	// of a new tag, if found set current position
	// to it, else set to last tag
	long pos = find( idTagLeft, _lastTagEnd );
	if ( pos != -1 )
		_current = pos;
	else
		_current = _lastTagEnd;


	return true;
}

bool XmlParser::parse ( std::string & name,
						std::string & value,
						std::string & attributes,
						long & current )
{

	return true;
}



// tag search methods

bool XmlParser::hasNullTag ()
{
	// get end of first tag
	char * buffer = _buffer + _firstTagEnd - 1;

	// if null tag marker
	if ( *buffer == '/' && *(buffer+1) == '>' )
		return true;
	else
		return false;
}

bool XmlParser::isSpecialXMLTag()
{
	std::string name = getName();

   return name.compare(0, 4, "?xml") == 0 || // <?xml tag ?>
          name.compare(0, 3, "!--")  == 0;   // <!-- comment tar -->
}

// name search methods
bool XmlParser::parseName ()
{
	// if first tag search failed show failed
	if ( _firstTagStart < 0 ||  _firstTagEnd < 0 ||
		 _firstTagEnd <= _firstTagStart )
	{
		_nameStart = -1;
		_nameEnd   = -1;
		return false;
	}

	// init name start/end position
	_nameStart = _firstTagStart + idTagLeftLength;
	_nameEnd   = _firstTagEnd - 1;

	// if null tag then backup before
	// null tag marker
	if ( hasNullTag() )
		_nameEnd -= 1;

	// check for separator (i.e. there are attributes)
	long last = find(' ',_nameStart, getNameLength());
	if ( last != -1 )
	{
		// there are attributes so backup
		// before attributes
		_nameEnd = last - 1;
	}

	return true;
}

bool XmlParser::parseName ( std::string & name )
{
	// set name state
	if ( !parseName() )
		return false;

	name = getName();

	return true;
}

// attribute search methods
bool XmlParser::parseAttributes ()
{
	// init name start/end position
	_attrStart = -1;
	_attrEnd   = -1;

	// if tag or name length invalid stop
	long tagLength  = getTagLength();
	long nameLength = getNameLength();
	if ( tagLength <= 0 || nameLength <= 0 )
		return 0;

	// if the difference in the lengths is
	// less than the length of the left/right marker
	// then no attributes
	long diff = getTagLength() - getNameLength();

	switch ( diff )
	{
		// no attribute case
		case 0:
		case 1:
		case 2:
			return false;

		// no attribute case but has null tag
		case 3:
			return false;
	}

	// init attributes start, move past space after name
	_attrStart = _nameEnd + 2;

	// init attribute end move before right tag marker
	// if null tag move before null tag marker
	_attrEnd = _firstTagEnd - 1;
	if ( hasNullTag() )
		_attrEnd -= -1;

	return true;
}

bool XmlParser::parseAttributes ( std::string & attributes )
{
	// set name state
	if ( !parseAttributes() )
		return false;

	attributes = getAttributes();

	return true;
}


// data search methods
bool XmlParser::parseValue ()
{
	// if first tag search failed show failed
	if ( _firstTagStart < 0 ||  _lastTagEnd < 0 ||
		 _lastTagEnd <= _firstTagStart )
	{
		_valueStart = -1;
		_valueEnd   = -1;
		return false;
	}

	// init value start/end positions
	_valueStart = _firstTagEnd + 1;
	_valueEnd   = _lastTagStart - 1;

	return true;
}


bool XmlParser::parseValue ( std::string & value )
{
	// set name state
	if ( !parseValue() )
		return false;

	value = getValue();

	return true;
}

char * XmlParser::getNamePos ()
{
	if ( hasName() )
		return _buffer + _nameStart;
	else
		return NULL;
}

bool XmlParser::hasName ()
{
	if ( getNameLength() > 0 )
		return true;
	else
		return false;
}

long XmlParser::getNameLength ()
{
	long length = getLength(_nameStart,_nameEnd);
	return length;
}


std::string XmlParser::getName ()
{
	// get name length
	long length = getNameLength();

	// if length invalid show null string
	// else get string
	if ( length <= 0 )
		return std::string("");
	else
		return substr(_nameStart,length);
}


// attribute access methods
char * XmlParser::getAttributesPos ()
{
	if ( hasAttributes() )
		return _buffer + _attrStart;
	else
		return NULL;
}

bool XmlParser::hasAttributes ()
{
	if ( getValueLength() > 0 )
		return true;
	else
		return false;
}

long XmlParser::getAttributesLength ()
{
	long length = getLength(_attrStart,_attrEnd);
	return length;
}

std::string XmlParser::getAttributes ()
{
	// get attribute length
	long length = getAttributesLength();

	// if length invalid show null string
	// else get string
	if ( length <= 0 )
		return std::string("");
	else
		return substr(_attrStart,length);
}

// value access methods
char * XmlParser::getValuePos ()
{
	if ( hasValue() )
		return _buffer + _valueStart;
	else
		return NULL;
}

bool XmlParser::hasValue ()
{
	if ( getValueLength() > 0 )
		return true;
	else
		return false;
}

long XmlParser::getValueLength ()
{
	long length = getLength(_valueStart,_valueEnd);
	return length;
}

std::string XmlParser::getValue ()
{
	// get tag data length
	long length = getValueLength();

	// if length invalid show null string
	// else get string
	if ( length <= 0 )
		return std::string("");
	else
		return substr(_valueStart,length);
}

char * XmlParser::getValueState ( long & valueLength )
{
	// get value state
	valueLength = getValueLength();

	// return value buffer pos
	return _buffer + _valueStart;
}

bool XmlParser::valueHasTag ()
{
	// if find end tag
	long pos = find( idTagLeft, _valueStart, getValueLength() );

	// if found tag
	if ( pos != -1 )
		return true;
	else
		return false;
}

// tag access methods
long XmlParser::getTagLength ()
{
	long length = getLength( _firstTagStart, _firstTagEnd );
	return length;
}

long XmlParser::getLastTagLength ()
{
	long length = getLength( _lastTagStart, _lastTagEnd );
	return length;
}

bool XmlParser::hasTag ()
{
	if ( getTagLength() > 0 )
		return true;
	else
		return false;
}

bool XmlParser::hasLastTag ()
{
	if ( getLastTagLength() > 0 )
		return true;
	else
		return false;
}

char * XmlParser::getTagPos ()
{
	if ( hasTag() )
		return _buffer + _firstTagStart;
	else
		return NULL;
}

char * XmlParser::getLastTagPos ()
{
	if ( hasTag() )
		return _buffer + _lastTagStart;
	else
		return NULL;
}

std::string XmlParser::getTag ()
{
	// get tag data length
	long length = getTagLength();
	return substr(_firstTagStart,length);
}

// string utility methods
long XmlParser::getLength ( long startPos,
			     long endPos )
{
	// if positions invalid show no length
	if ( startPos < 0 || endPos < 0 ||
		 endPos < startPos )
		return 0;

	// get length
	long length = endPos - startPos + 1;
	return length;
}

std::string::iterator XmlParser::begin ()
{
	std::string::iterator buf = static_cast<std::string::iterator>(_buffer);
	return std::string::iterator(buf);
}

std::string ::iterator XmlParser::end ()
{
	std::string::iterator buf = static_cast<std::string::iterator>(_buffer + _parseLength);
	return std::string::iterator(buf);
}

long XmlParser::find ( char srchChar, long offset, long length)
{
	// if no length set to length to
	// end of parse buffer
	if ( length == -1 )
		length = getOffsetLength(offset);

	// set start and end of search 
	std::string::iterator start = static_cast<std::string::iterator>(_buffer + offset);
	std::string::iterator end   = static_cast<std::string::iterator>(_buffer + (offset + length));

	// search for it
	std::string::iterator found = std::find( start, end, srchChar );

	// if at end did not find it
	if ( found >= end )
	{
		return -1;
	}
	else
	{
		// as a last check make sure found is valid
		if ( found < start )
			return -1;

		// set position
		long pos = (found - start);
		pos += offset;

		return pos;
	}
}

long XmlParser::find ( char * srchStr, long offset, long length)
{
	// if no length set to length to
	// end of parse buffer
	if ( length == -1 )
		length = getOffsetLength(offset);

	// set start and end of search 
	std::string::iterator start = static_cast<std::string::iterator>(_buffer + offset);
	std::string::iterator end   = static_cast<std::string::iterator>(_buffer + (offset + length));


	std::string::iterator srchStart = static_cast<std::string::iterator>(srchStr);
	std::string::iterator srchEnd   = static_cast<std::string::iterator>(srchStr + strlen(srchStr));

	// search for it
	std::string::iterator found = std::search( start, end, srchStart, srchEnd );

	// if at end did not find it
	if ( found >= end )
	{
		return -1;
	}
	else
	{
		// as a last check make sure found is valid
		if ( found < start )
			return -1;

		// set position
		long pos = (found - start);
		pos += offset;

		return pos;
	}
}

long XmlParser::find ( std::string & srchStr, long offset, long length)
{
	// if no length set to length to
	// end of parse buffer
	if ( length == -1 )
		length = getOffsetLength(offset);

	// set start and end of search 
	std::string::iterator start = static_cast<std::string::iterator>(_buffer + offset);
	std::string::iterator end   = static_cast<std::string::iterator>(_buffer + (offset + length));


	std::string::iterator srchStart = srchStr.begin();
	std::string::iterator srchEnd   = srchStr.end();

	// search for it
	std::string::iterator found = std::search( start, end, srchStart, srchEnd );

	// if at end did not find it
	if ( found >= end )
	{
		return -1;
	}
	else
	{
		// as a last check make sure found is valid
		if ( found < start )
			return -1;

		// set position
		long pos = (found - start);
		pos += offset;

		return pos;
	}
}

long XmlParser::rfind ( char srchChar, long offset, long length )
{
	// setup srch string
	char srchStr[2];
	srchStr[0] = srchChar;
	srchStr[1] = '\0';

	return rfind(srchStr,offset,length);
}

long XmlParser::rfind ( char * srchStr, long offset, long length )
{
	/*
	// set start and end of search 
	string::reverse_iterator revStart = _buffer + (offset + length)
	string::reverse_iterator revEnd   = _buffer + offset;

	// search for it
	string::reverse_iterator found = std::find( start, end, srchStr );

	// get position 
	long pos = found - revStart;
	*/
	long pos = 0;

	return pos;
}


std::string XmlParser::substr ( long offset, long length )
{
	// get start of sub string
	char * ptr = _buffer + offset;

	// create string for it
	std::string str;
	str.assign( ptr, length );

	return std::string(str);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
China China
I've been living & working in Tokyo since 2000 . I'm currently working in Gentech Corp. (www.gen.co.jp), developing computer vision applications, especially in the field of face detection.

I've been interested in C++ for quite a while and recently discovered Ruby.

My hobbies are trekking, japanese food, yoga & onsens.

Comments and Discussions