|
XML Class Factory
Submitted by |
Some time ago I started to wonder about the flexible capabilities of
XML, but at the moment few game developers use it.
Talking about this matter with some others game developers I
saw that some of them are expecting to use it in their
new projects.
I wrote the class CClassFactory, that it's just a simple
implementation of "something like a" class factory, using XML.
It wasn't made to be really useful, but just to show how flexible
and easy it could be to make complex data relationships with
xml, which makes it a great point for game developers because sometimes
we really get mixed up with scripting, data, and so one.
This code could be extended further, with more features
and perhaps with some scripting system that allows (in a easy way) to
modify the context of the class factory, and so one.
In the source code you'll find :
The class factory itself
ClassFactory.h
ClassFactory.cpp
A visual Studio 6 MFC Project that uses those classes to show the
funcionality of the system.
A directory called \doc with the documentation of the class in html
and rtf format , thanks to Doxygen, a really great code doc tool.
Note : CClassFactory uses tinyxml a great XML parser included in
the project
Juan Antonio Medina ^ mICrO
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/tinyxml/tinyxml.cpp] - (20,401 bytes)
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "stdafx.h"
#include <ctype.h>
#include "tinyxml.h"
bool TiXmlBase::condenseWhiteSpace = true;
void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream )
{
TIXML_STRING buffer;
PutString( str, &buffer );
(*stream) << buffer;
}
void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString )
{
int i=0;
while( i<(int)str.length() )
{
int c = str[i];
if ( c == '&'
&& i < ( (int)str.length() - 2 )
&& str[i+1] == '#'
&& str[i+2] == 'x' )
{
// Hexadecimal character reference.
// Pass through unchanged.
// © -- copyright symbol, for example.
while ( i<(int)str.length() )
{
outString->append( str.c_str() + i, 1 );
++i;
if ( str[i] == ';' )
break;
}
}
else if ( c == '&' )
{
outString->append( entity[0].str, entity[0].strLength );
++i;
}
else if ( c == '<' )
{
outString->append( entity[1].str, entity[1].strLength );
++i;
}
else if ( c == '>' )
{
outString->append( entity[2].str, entity[2].strLength );
++i;
}
else if ( c == '\"' )
{
outString->append( entity[3].str, entity[3].strLength );
++i;
}
else if ( c == '\'' )
{
outString->append( entity[4].str, entity[4].strLength );
++i;
}
else if ( c < 32 || c > 126 )
{
// Easy pass at non-alpha/numeric/symbol
// 127 is the delete key. Below 32 is symbolic.
char buf[ 32 ];
sprintf( buf, "%02X;", (unsigned) ( c & 0xff ) );
outString->append( buf, strlen( buf ) );
++i;
}
else
{
char realc = (char) c;
outString->append( &realc, 1 );
++i;
}
}
}
// <-- Strange class for a bug fix. Search for STL_STRING_BUG
TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str )
{
buffer = new char[ str.length()+1 ];
if ( buffer )
{
strcpy( buffer, str.c_str() );
}
}
TiXmlBase::StringToBuffer::~StringToBuffer()
{
delete [] buffer;
}
// End strange bug fix. -->
TiXmlNode::TiXmlNode( NodeType _type )
{
parent = 0;
type = _type;
firstChild = 0;
lastChild = 0;
prev = 0;
next = 0;
userData = 0;
}
TiXmlNode::~TiXmlNode()
{
TiXmlNode* node = firstChild;
TiXmlNode* temp = 0;
while ( node )
{
temp = node;
node = node->next;
delete temp;
}
}
void TiXmlNode::Clear()
{
TiXmlNode* node = firstChild;
TiXmlNode* temp = 0;
while ( node )
{
temp = node;
node = node->next;
delete temp;
}
firstChild = 0;
lastChild = 0;
}
TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
{
node->parent = this;
node->prev = lastChild;
node->next = 0;
if ( lastChild )
lastChild->next = node;
else
firstChild = node; // it was an empty list.
lastChild = node;
return node;
}
TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
{
TiXmlNode* node = addThis.Clone();
if ( !node )
return 0;
return LinkEndChild( node );
}
TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
{
if ( !beforeThis || beforeThis->parent != this )
return 0;
TiXmlNode* node = addThis.Clone();
if ( !node )
return 0;
node->parent = this;
node->next = beforeThis;
node->prev = beforeThis->prev;
if ( beforeThis->prev )
{
beforeThis->prev->next = node;
}
else
{
assert( firstChild == beforeThis );
firstChild = node;
}
beforeThis->prev = node;
return node;
}
TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
{
if ( !afterThis || afterThis->parent != this )
return 0;
TiXmlNode* node = addThis.Clone();
if ( !node )
return 0;
node->parent = this;
node->prev = afterThis;
node->next = afterThis->next;
if ( afterThis->next )
{
afterThis->next->prev = node;
}
else
{
assert( lastChild == afterThis );
lastChild = node;
}
afterThis->next = node;
return node;
}
TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
{
if ( replaceThis->parent != this )
return 0;
TiXmlNode* node = withThis.Clone();
if ( !node )
return 0;
node->next = replaceThis->next;
node->prev = replaceThis->prev;
if ( replaceThis->next )
replaceThis->next->prev = node;
else
lastChild = node;
if ( replaceThis->prev )
replaceThis->prev->next = node;
else
firstChild = node;
delete replaceThis;
node->parent = this;
return node;
}
bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
{
if ( removeThis->parent != this )
{
assert( 0 );
return false;
}
if ( removeThis->next )
removeThis->next->prev = removeThis->prev;
else
lastChild = removeThis->prev;
if ( removeThis->prev )
removeThis->prev->next = removeThis->next;
else
firstChild = removeThis->next;
delete removeThis;
return true;
}
TiXmlNode* TiXmlNode::FirstChild( const char * value ) const
{
TiXmlNode* node;
for ( node = firstChild; node; node = node->next )
{
if ( node->SValue() == TIXML_STRING( value ))
return node;
}
return 0;
}
TiXmlNode* TiXmlNode::LastChild( const char * value ) const
{
TiXmlNode* node;
for ( node = lastChild; node; node = node->prev )
{
if ( node->SValue() == TIXML_STRING (value))
return node;
}
return 0;
}
TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const
{
if ( !previous )
{
return FirstChild();
}
else
{
assert( previous->parent == this );
return previous->NextSibling();
}
}
TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const
{
if ( !previous )
{
return FirstChild( val );
}
else
{
assert( previous->parent == this );
return previous->NextSibling( val );
}
}
TiXmlNode* TiXmlNode::NextSibling( const char * value ) const
{
TiXmlNode* node;
for ( node = next; node; node = node->next )
{
if ( node->SValue() == TIXML_STRING (value))
return node;
}
return 0;
}
TiXmlNode* TiXmlNode::PreviousSibling( const char * value ) const
{
TiXmlNode* node;
for ( node = prev; node; node = node->prev )
{
if ( node->SValue() == TIXML_STRING (value))
return node;
}
return 0;
}
void TiXmlElement::RemoveAttribute( const char * name )
{
TiXmlAttribute* node = attributeSet.Find( name );
if ( node )
{
attributeSet.Remove( node );
delete node;
}
}
TiXmlElement* TiXmlNode::FirstChildElement() const
{
TiXmlNode* node;
for ( node = FirstChild();
node;
node = node->NextSibling() )
{
if ( node->ToElement() )
return node->ToElement();
}
return 0;
}
TiXmlElement* TiXmlNode::FirstChildElement( const char * value ) const
{
TiXmlNode* node;
for ( node = FirstChild( value );
node;
node = node->NextSibling( value ) )
{
if ( node->ToElement() )
return node->ToElement();
}
return 0;
}
TiXmlElement* TiXmlNode::NextSiblingElement() const
{
TiXmlNode* node;
for ( node = NextSibling();
node;
node = node->NextSibling() )
{
if ( node->ToElement() )
return node->ToElement();
}
return 0;
}
TiXmlElement* TiXmlNode::NextSiblingElement( const char * value ) const
{
TiXmlNode* node;
for ( node = NextSibling( value );
node;
node = node->NextSibling( value ) )
{
if ( node->ToElement() )
return node->ToElement();
}
return 0;
}
TiXmlDocument* TiXmlNode::GetDocument() const
{
const TiXmlNode* node;
for( node = this; node; node = node->parent )
{
if ( node->ToDocument() )
return node->ToDocument();
}
return 0;
}
TiXmlElement::TiXmlElement (const char * _value)
: TiXmlNode( TiXmlNode::ELEMENT )
{
firstChild = lastChild = 0;
value = _value;
}
TiXmlElement::~TiXmlElement()
{
while( attributeSet.First() )
{
TiXmlAttribute* node = attributeSet.First();
attributeSet.Remove( node );
delete node;
}
}
const char * TiXmlElement::Attribute( const char * name ) const
{
TiXmlAttribute* node = attributeSet.Find( name );
if ( node )
return node->Value();
return 0;
}
const char * TiXmlElement::Attribute( const char * name, int* i ) const
{
const char * s = Attribute( name );
if ( i )
{
if ( s )
*i = atoi( s );
else
*i = 0;
}
return s;
}
void TiXmlElement::SetAttribute( const char * name, int val )
{
char buf[64];
sprintf( buf, "%d", val );
SetAttribute( name, buf );
}
void TiXmlElement::SetAttribute( const char * name, const char * value )
{
TiXmlAttribute* node = attributeSet.Find( name );
if ( node )
{
node->SetValue( value );
return;
}
TiXmlAttribute* attrib = new TiXmlAttribute( name, value );
if ( attrib )
{
attributeSet.Add( attrib );
}
else
{
TiXmlDocument* document = GetDocument();
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
}
}
void TiXmlElement::Print( FILE* cfile, int depth ) const
{
int i;
for ( i=0; i<depth; i++ )
{
fprintf( cfile, " " );
}
fprintf( cfile, "<%s", value.c_str() );
TiXmlAttribute* attrib;
for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
{
fprintf( cfile, " " );
attrib->Print( cfile, depth );
}
// There are 3 different formatting approaches:
// 1) An element without children is printed as a <foo /> node
// 2) An element with only a text child is printed as <foo> text </foo>
// 3) An element with children is printed on multiple lines.
TiXmlNode* node;
if ( !firstChild )
{
fprintf( cfile, " />" );
}
else if ( firstChild == lastChild && firstChild->ToText() )
{
fprintf( cfile, ">" );
firstChild->Print( cfile, depth + 1 );
fprintf( cfile, "</%s>", value.c_str() );
}
else
{
fprintf( cfile, ">" );
for ( node = firstChild; node; node=node->NextSibling() )
{
if ( !node->ToText() )
{
fprintf( cfile, "\n" );
}
node->Print( cfile, depth+1 );
}
fprintf( cfile, "\n" );
for( i=0; i<depth; ++i )
fprintf( cfile, " " );
fprintf( cfile, "</%s>", value.c_str() );
}
}
void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const
{
(*stream) << "<" << value;
TiXmlAttribute* attrib;
for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
{
(*stream) << " ";
attrib->StreamOut( stream );
}
// If this node has children, give it a closing tag. Else
// make it an empty tag.
TiXmlNode* node;
if ( firstChild )
{
(*stream) << ">";
for ( node = firstChild; node; node=node->NextSibling() )
{
node->StreamOut( stream );
}
(*stream) << "</" << value << ">";
}
else
{
(*stream) << " />";
}
}
TiXmlNode* TiXmlElement::Clone() const
{
TiXmlElement* clone = new TiXmlElement( Value() );
if ( !clone )
return 0;
CopyToClone( clone );
// Clone the attributes, then clone the children.
TiXmlAttribute* attribute = 0;
for( attribute = attributeSet.First();
attribute;
attribute = attribute->Next() )
{
clone->SetAttribute( attribute->Name(), attribute->Value() );
}
TiXmlNode* node = 0;
for ( node = firstChild; node; node = node->NextSibling() )
{
clone->LinkEndChild( node->Clone() );
}
return clone;
}
TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
{
error = false;
// ignoreWhiteSpace = true;
}
TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
{
// ignoreWhiteSpace = true;
value = documentName;
error = false;
}
bool TiXmlDocument::LoadFile()
{
// See STL_STRING_BUG below.
StringToBuffer buf( value );
if ( buf.buffer && LoadFile( buf.buffer ) )
return true;
return false;
}
bool TiXmlDocument::SaveFile() const
{
// See STL_STRING_BUG below.
StringToBuffer buf( value );
if ( buf.buffer && SaveFile( buf.buffer ) )
return true;
return false;
}
bool TiXmlDocument::LoadFile( const char* filename )
{
// Delete the existing data:
Clear();
// There was a really terrifying little bug here. The code:
// value = filename
// in the STL case, cause the assignment method of the std::string to
// be called. What is strange, is that the std::string had the same
// address as it's c_str() method, and so bad things happen. Looks
// like a bug in the Microsoft STL implementation.
// See STL_STRING_BUG above.
// Fixed with the StringToBuffer class.
value = filename;
FILE* file = fopen( value.c_str (), "r" );
if ( file )
{
// Get the file size, so we can pre-allocate the string. HUGE speed impact.
long length = 0;
fseek( file, 0, SEEK_END );
length = ftell( file );
fseek( file, 0, SEEK_SET );
// Strange case, but good to handle up front.
if ( length == 0 )
{
fclose( file );
return false;
}
// If we have a file, assume it is all one big XML file, and read it in.
// The document parser may decide the document ends sooner than the entire file, however.
TIXML_STRING data;
data.reserve( length );
const int BUF_SIZE = 2048;
char buf[BUF_SIZE];
while( fgets( buf, BUF_SIZE, file ) )
{
data += buf;
}
fclose( file );
Parse( data.c_str() );
if ( !Error() )
{
return true;
}
}
SetError( TIXML_ERROR_OPENING_FILE );
return false;
}
bool TiXmlDocument::SaveFile( const char * filename ) const
{
// The old c stuff lives on...
FILE* fp = fopen( filename, "w" );
if ( fp )
{
Print( fp, 0 );
fclose( fp );
return true;
}
return false;
}
TiXmlNode* TiXmlDocument::Clone() const
{
TiXmlDocument* clone = new TiXmlDocument();
if ( !clone )
return 0;
CopyToClone( clone );
clone->error = error;
clone->errorDesc = errorDesc.c_str ();
TiXmlNode* node = 0;
for ( node = firstChild; node; node = node->NextSibling() )
{
clone->LinkEndChild( node->Clone() );
}
return clone;
}
void TiXmlDocument::Print( FILE* cfile, int depth ) const
{
TiXmlNode* node;
for ( node=FirstChild(); node; node=node->NextSibling() )
{
node->Print( cfile, depth );
fprintf( cfile, "\n" );
}
}
void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const
{
TiXmlNode* node;
for ( node=FirstChild(); node; node=node->NextSibling() )
{
node->StreamOut( out );
// Special rule for streams: stop after the root element.
// The stream in code will only read one element, so don't
// write more than one.
if ( node->ToElement() )
break;
}
}
TiXmlAttribute* TiXmlAttribute::Next() const
{
// We are using knowledge of the sentinel. The sentinel
// have a value or name.
if ( next->value.empty() && next->name.empty() )
return 0;
return next;
}
TiXmlAttribute* TiXmlAttribute::Previous() const
{
// We are using knowledge of the sentinel. The sentinel
// have a value or name.
if ( prev->value.empty() && prev->name.empty() )
return 0;
return prev;
}
void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const
{
TIXML_STRING n, v;
PutString( Name(), &n );
PutString( Value(), &v );
if (value.find ('\"') == TIXML_STRING::npos)
fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
else
fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
}
void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const
{
if (value.find( '\"' ) != TIXML_STRING::npos)
{
PutString( name, stream );
(*stream) << "=" << "'";
PutString( value, stream );
(*stream) << "'";
}
else
{
PutString( name, stream );
(*stream) << "=" << "\"";
PutString( value, stream );
(*stream) << "\"";
}
}
void TiXmlAttribute::SetIntValue( int value )
{
char buf [64];
sprintf (buf, "%d", value);
SetValue (buf);
}
void TiXmlAttribute::SetDoubleValue( double value )
{
char buf [64];
sprintf (buf, "%lf", value);
SetValue (buf);
}
const int TiXmlAttribute::IntValue() const
{
return atoi (value.c_str ());
}
const double TiXmlAttribute::DoubleValue() const
{
return atof (value.c_str ());
}
void TiXmlComment::Print( FILE* cfile, int depth ) const
{
for ( int i=0; i<depth; i++ )
{
fputs( " ", cfile );
}
fprintf( cfile, "<!--%s-->", value.c_str() );
}
void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const
{
(*stream) << "<!--";
PutString( value, stream );
(*stream) << "-->";
}
TiXmlNode* TiXmlComment::Clone() const
{
TiXmlComment* clone = new TiXmlComment();
if ( !clone )
return 0;
CopyToClone( clone );
return clone;
}
void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const
{
TIXML_STRING buffer;
PutString( value, &buffer );
fprintf( cfile, "%s", buffer.c_str() );
}
void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const
{
PutString( value, stream );
}
TiXmlNode* TiXmlText::Clone() const
{
TiXmlText* clone = 0;
clone = new TiXmlText( "" );
if ( !clone )
return 0;
CopyToClone( clone );
return clone;
}
TiXmlDeclaration::TiXmlDeclaration( const char * _version,
const char * _encoding,
const char * _standalone )
: TiXmlNode( TiXmlNode::DECLARATION )
{
version = _version;
encoding = _encoding;
standalone = _standalone;
}
void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const
{
fprintf (cfile, "<?xml ");
if ( !version.empty() )
fprintf (cfile, "version=\"%s\" ", version.c_str ());
if ( !encoding.empty() )
fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
if ( !standalone.empty() )
fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
fprintf (cfile, "?>");
}
void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const
{
(*stream) << "<?xml ";
if ( !version.empty() )
{
(*stream) << "version=\"";
PutString( version, stream );
(*stream) << "\" ";
}
if ( !encoding.empty() )
{
(*stream) << "encoding=\"";
PutString( encoding, stream );
(*stream ) << "\" ";
}
if ( !standalone.empty() )
{
(*stream) << "standalone=\"";
PutString( standalone, stream );
(*stream) << "\" ";
}
(*stream) << "?>";
}
TiXmlNode* TiXmlDeclaration::Clone() const
{
TiXmlDeclaration* clone = new TiXmlDeclaration();
if ( !clone )
return 0;
CopyToClone( clone );
clone->version = version;
clone->encoding = encoding;
clone->standalone = standalone;
return clone;
}
void TiXmlUnknown::Print( FILE* cfile, int depth ) const
{
for ( int i=0; i<depth; i++ )
fprintf( cfile, " " );
fprintf( cfile, "%s", value.c_str() );
}
void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const
{
(*stream) << "<" << value << ">"; // Don't use entities hear! It is unknown.
}
TiXmlNode* TiXmlUnknown::Clone() const
{
TiXmlUnknown* clone = new TiXmlUnknown();
if ( !clone )
return 0;
CopyToClone( clone );
return clone;
}
TiXmlAttributeSet::TiXmlAttributeSet()
{
sentinel.next = &sentinel;
sentinel.prev = &sentinel;
}
TiXmlAttributeSet::~TiXmlAttributeSet()
{
assert( sentinel.next == &sentinel );
assert( sentinel.prev == &sentinel );
}
void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
{
assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
addMe->next = &sentinel;
addMe->prev = sentinel.prev;
sentinel.prev->next = addMe;
sentinel.prev = addMe;
}
void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
{
TiXmlAttribute* node;
for( node = sentinel.next; node != &sentinel; node = node->next )
{
if ( node == removeMe )
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = 0;
node->prev = 0;
return;
}
}
assert( 0 ); // we tried to remove a non-linked attribute.
}
TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const
{
TiXmlAttribute* node;
for( node = sentinel.next; node != &sentinel; node = node->next )
{
if ( node->name == name )
return node;
}
return 0;
}
#ifdef TIXML_USE_STL
TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base)
{
TIXML_STRING tag;
tag.reserve( 8 * 1000 );
base.StreamIn( &in, &tag );
base.Parse( tag.c_str() );
return in;
}
#endif
TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base)
{
base.StreamOut (& out);
return out;
} |
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/tinyxml/tinyxml.h] - (30,820 bytes)
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef TINYXML_INCLUDED
#define TINYXML_INCLUDED
#ifdef _MSC_VER
#pragma warning( disable : 4530 )
#pragma warning( disable : 4786 )
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// Help out windows:
#if defined( _DEBUG ) && !defined( DEBUG )
#define DEBUG
#endif
#if defined( DEBUG ) && defined( _MSC_VER )
#include <windows.h>
#define TIXML_LOG OutputDebugString
#else
#define TIXML_LOG printf
#endif
#ifdef TIXML_USE_STL
#include <string>
#define TIXML_STRING std::string
#define TIXML_ISTREAM std::istream
#define TIXML_OSTREAM std::ostream
#else
#include "tinystr.h"
#define TIXML_STRING TiXmlString
#define TIXML_OSTREAM TiXmlOutStream
#endif
class TiXmlDocument;
class TiXmlElement;
class TiXmlComment;
class TiXmlUnknown;
class TiXmlAttribute;
class TiXmlText;
class TiXmlDeclaration;
/** TiXmlBase is a base class for every class in TinyXml.
It does little except to establish that TinyXml classes
can be printed and provide some utility functions.
In XML, the document and elements can contain
other elements and other types of nodes.
@verbatim
A Document can contain: Element (container or leaf)
Comment (leaf)
Unknown (leaf)
Declaration( leaf )
An Element can contain: Element (container or leaf)
Text (leaf)
Attributes (not on tree)
Comment (leaf)
Unknown (leaf)
A Decleration contains: Attributes (not on tree)
@endverbatim
*/
class TiXmlBase
{
friend class TiXmlNode;
friend class TiXmlElement;
friend class TiXmlDocument;
public:
TiXmlBase() {}
virtual ~TiXmlBase() {}
/** All TinyXml classes can print themselves to a filestream.
This is a formatted print, and will insert tabs and newlines.
(For an unformatted stream, use the << operator.)
*/
virtual void Print( FILE* cfile, int depth ) const = 0;
/** The world does not agree on whether white space should be kept or
not. In order to make everyone happy, these global, static functions
are provided to set whether or not TinyXml will condense all white space
into a single space or not. The default is to condense. Note changing these
values is not thread safe.
*/
static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; }
/// Return the current white space setting.
static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
protected:
// See STL_STRING_BUG
// Utility class to overcome a bug.
class StringToBuffer
{
public:
StringToBuffer( const TIXML_STRING& str );
~StringToBuffer();
char* buffer;
};
static const char* SkipWhiteSpace( const char* );
inline static bool IsWhiteSpace( int c ) { return ( isspace( c ) || c == '\n' || c == '\r' ); }
virtual void StreamOut (TIXML_OSTREAM *) const = 0;
#ifdef TIXML_USE_STL
static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag );
static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag );
#endif
/* Reads an XML name into the string provided. Returns
a pointer just past the last character of the name,
or 0 if the function has an error.
*/
static const char* ReadName( const char* p, TIXML_STRING* name );
/* Reads text. Returns a pointer past the given end tag.
Wickedly complex options, but it keeps the (sensitive) code in one place.
*/
static const char* ReadText( const char* in, // where to start
TIXML_STRING* text, // the string read
bool ignoreWhiteSpace, // whether to keep the white space
const char* endTag, // what ends this text
bool ignoreCase ); // whether to ignore case in the end tag
virtual const char* Parse( const char* p ) = 0;
// If an entity has been found, transform it into a character.
static const char* GetEntity( const char* in, char* value );
// Get a character, while interpreting entities.
inline static const char* GetChar( const char* p, char* value )
{
assert( p );
if ( *p == '&' )
{
return GetEntity( p, value );
}
else
{
*value = *p;
return p+1;
}
}
// Puts a string to a stream, expanding entities as it goes.
// Note this should not contian the '<', '>', etc, or they will be transformed into entities!
static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out );
static void PutString( const TIXML_STRING& str, TIXML_STRING* out );
// Return true if the next characters in the stream are any of the endTag sequences.
bool static StringEqual( const char* p,
const char* endTag,
bool ignoreCase );
enum
{
TIXML_NO_ERROR = 0,
TIXML_ERROR,
TIXML_ERROR_OPENING_FILE,
TIXML_ERROR_OUT_OF_MEMORY,
TIXML_ERROR_PARSING_ELEMENT,
TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
TIXML_ERROR_READING_ELEMENT_VALUE,
TIXML_ERROR_READING_ATTRIBUTES,
TIXML_ERROR_PARSING_EMPTY,
TIXML_ERROR_READING_END_TAG,
TIXML_ERROR_PARSING_UNKNOWN,
TIXML_ERROR_PARSING_COMMENT,
TIXML_ERROR_PARSING_DECLARATION,
TIXML_ERROR_DOCUMENT_EMPTY,
TIXML_ERROR_STRING_COUNT
};
static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
private:
struct Entity
{
const char* str;
unsigned int strLength;
char chr;
};
enum
{
NUM_ENTITY = 5,
MAX_ENTITY_LENGTH = 6
};
static Entity entity[ NUM_ENTITY ];
static bool condenseWhiteSpace;
};
/** The parent class for everything in the Document Object Model.
(Except for attributes, which are contained in elements.)
Nodes have siblings, a parent, and children. A node can be
in a document, or stand on its own. The type of a TiXmlNode
can be queried, and it can be cast to its more defined type.
*/
class TiXmlNode : public TiXmlBase
{
friend class TiXmlDocument;
friend class TiXmlElement;
public:
#ifdef TIXML_USE_STL
/** An input stream operator, for every class. Tolerant of newlines and
formatting, but doesn't expect them.
*/
friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
/** An output stream operator, for every class. Note that this outputs
without any newlines or formatting, as opposed to Print(), which
includes tabs and new lines.
The operator<< and operator>> are not completely symmetric. Writing
a node to a stream is very well defined. You'll get a nice stream
of output, without any extra whitespace or newlines.
But reading is not as well defined. (As it always is.) If you create
a TiXmlElement (for example) and read that from an input stream,
the text needs to define an element or junk will result. This is
true of all input streams, but it's worth keeping in mind.
A TiXmlDocument will read nodes until it reads a root element.
*/
friend std::ostream & operator<< (std::ostream& out, const TiXmlNode& base);
#else
// Used internally, not part of the public API.
friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base);
#endif
/** The types of XML nodes supported by TinyXml. (All the
unsupported types are picked up by UNKNOWN.)
*/
enum NodeType
{
DOCUMENT,
ELEMENT,
COMMENT,
UNKNOWN,
TEXT,
DECLARATION,
TYPECOUNT
};
virtual ~TiXmlNode();
/** The meaning of 'value' changes for the specific type of
TiXmlNode.
@verbatim
Document: filename of the xml file
Element: name of the element
Comment: the comment text
Unknown: the tag contents
Text: the text string
@endverbatim
The subclasses will wrap this function.
*/
const char * Value () const { return value.c_str (); }
/** Changes the value of the node. Defined as:
@verbatim
Document: filename of the xml file
Element: name of the element
Comment: the comment text
Unknown: the tag contents
Text: the text string
@endverbatim
*/
void SetValue (const char * _value) { value = _value;}
#ifdef TIXML_USE_STL
/// STL std::string form.
void SetValue( const std::string& value )
{
StringToBuffer buf( value );
SetValue( buf.buffer ? buf.buffer : "" );
}
#endif
/// Delete all the children of this node. Does not affect 'this'.
void Clear();
/// One step up the DOM.
TiXmlNode* Parent() const { return parent; }
TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children.
TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found.
TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children.
TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children.
#ifdef TIXML_USE_STL
TiXmlNode* FirstChild( const std::string& value ) const { return FirstChild (value.c_str ()); } ///< STL std::string form.
TiXmlNode* LastChild( const std::string& value ) const { return LastChild (value.c_str ()); } ///< STL std::string form.
#endif
/** An alternate way to walk the children of a node.
One way to iterate over nodes is:
@verbatim
for( child = parent->FirstChild(); child; child = child->NextSibling() )
@endverbatim
IterateChildren does the same thing with the syntax:
@verbatim
child = 0;
while( child = parent->IterateChildren( child ) )
@endverbatim
IterateChildren takes the previous child as input and finds
the next one. If the previous child is null, it returns the
first. IterateChildren will return null when done.
*/
TiXmlNode* IterateChildren( TiXmlNode* previous ) const;
/// This flavor of IterateChildren searches for children with a particular 'value'
TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const;
#ifdef TIXML_USE_STL
TiXmlNode* IterateChildren( const std::string& value, TiXmlNode* previous ) const { return IterateChildren (value.c_str (), previous); } ///< STL std::string form.
#endif
/** Add a new node related to this. Adds a child past the LastChild.
Returns a pointer to the new object or NULL if an error occured.
*/
TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
/** Add a new node related to this. Adds a child before the specified child.
Returns a pointer to the new object or NULL if an error occured.
*/
TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
/** Add a new node related to this. Adds a child after the specified child.
Returns a pointer to the new object or NULL if an error occured.
*/
TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
/** Replace a child of this node.
Returns a pointer to the new object or NULL if an error occured.
*/
TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
/// Delete a child of this node.
bool RemoveChild( TiXmlNode* removeThis );
/// Navigate to a sibling node.
TiXmlNode* PreviousSibling() const { return prev; }
/// Navigate to a sibling node.
TiXmlNode* PreviousSibling( const char * ) const;
#ifdef TIXML_USE_STL
TiXmlNode* PreviousSibling( const std::string& value ) const { return PreviousSibling (value.c_str ()); } ///< STL std::string form.
TiXmlNode* NextSibling( const std::string& value) const { return NextSibling (value.c_str ()); } ///< STL std::string form.
#endif
/// Navigate to a sibling node.
TiXmlNode* NextSibling() const { return next; }
/// Navigate to a sibling node with the given 'value'.
TiXmlNode* NextSibling( const char * ) const;
/** Convenience function to get through elements.
Calls NextSibling and ToElement. Will skip all non-Element
nodes. Returns 0 if there is not another element.
*/
TiXmlElement* NextSiblingElement() const;
/** Convenience function to get through elements.
Calls NextSibling and ToElement. Will skip all non-Element
nodes. Returns 0 if there is not another element.
*/
TiXmlElement* NextSiblingElement( const char * ) const;
#ifdef TIXML_USE_STL
TiXmlElement* NextSiblingElement( const std::string& value) const { return NextSiblingElement (value.c_str ()); } ///< STL std::string form.
#endif
/// Convenience function to get through elements.
TiXmlElement* FirstChildElement() const;
/// Convenience function to get through elements.
TiXmlElement* FirstChildElement( const char * value ) const;
#ifdef TIXML_USE_STL
TiXmlElement* FirstChildElement( const std::string& value ) const { return FirstChildElement (value.c_str ()); } ///< STL std::string form.
#endif
/// Query the type (as an enumerated value, above) of this node.
virtual int Type() const { return type; }
/** Return a pointer to the Document this node lives in.
Returns null if not in a document.
*/
TiXmlDocument* GetDocument() const;
/// Returns true if this node has no children.
bool NoChildren() const { return !firstChild; }
TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type.
virtual TiXmlNode* Clone() const = 0;
void SetUserData( void* user ) { userData = user; }
void* GetUserData() { return userData; }
protected:
TiXmlNode( NodeType type );
#ifdef TIXML_USE_STL
// The real work of the input operator.
virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0;
#endif
// The node is passed in by ownership. This object will delete it.
TiXmlNode* LinkEndChild( TiXmlNode* addThis );
// Figure out what is at *p, and parse it. Returns null if it is not an xml node.
TiXmlNode* Identify( const char* start );
void CopyToClone( TiXmlNode* target ) const { target->SetValue (value.c_str() );
target->userData = userData; }
// Internal Value function returning a TIXML_STRING
TIXML_STRING SValue() const { return value ; }
TiXmlNode* parent;
NodeType type;
TiXmlNode* firstChild;
TiXmlNode* lastChild;
TIXML_STRING value;
TiXmlNode* prev;
TiXmlNode* next;
void* userData;
};
/** An attribute is a name-value pair. Elements have an arbitrary
number of attributes, each with a unique name.
@note The attributes are not TiXmlNodes, since they are not
part of the tinyXML document object model. There are other
suggested ways to look at this problem.
@note Attributes have a parent
*/
class TiXmlAttribute : public TiXmlBase
{
friend class TiXmlAttributeSet;
public:
/// Construct an empty attribute.
TiXmlAttribute() : prev( 0 ), next( 0 ) {}
#ifdef TIXML_USE_STL
/// std::string constructor.
TiXmlAttribute( const std::string& _name, const std::string& _value )
{
name = _name;
value = _value;
}
#endif
/// Construct an attribute with a name and value.
TiXmlAttribute( const char * _name, const char * _value ): name( _name ), value( _value ), prev( 0 ), next( 0 ) {}
const char* Name() const { return name.c_str (); } ///< Return the name of this attribute.
const char* Value() const { return value.c_str (); } ///< Return the value of this attribute.
const int IntValue() const; ///< Return the value of this attribute, converted to an integer.
const double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute.
void SetValue( const char* _value ) { value = _value; } ///< Set the value.
void SetIntValue( int value ); ///< Set the value from an integer.
void SetDoubleValue( double value ); ///< Set the value from a double.
#ifdef TIXML_USE_STL
/// STL std::string form.
void SetName( const std::string& _name )
{
StringToBuffer buf( _name );
SetName ( buf.buffer ? buf.buffer : "error" );
}
/// STL std::string form.
void SetValue( const std::string& _value )
{
StringToBuffer buf( _value );
SetValue( buf.buffer ? buf.buffer : "error" );
}
#endif
/// Get the next sibling attribute in the DOM. Returns null at end.
TiXmlAttribute* Next() const;
/// Get the previous sibling attribute in the DOM. Returns null at beginning.
TiXmlAttribute* Previous() const;
bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; }
bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; }
/* [internal use]
Attribtue parsing starts: first letter of the name
returns: the next char after the value end quote
*/
virtual const char* Parse( const char* p );
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
virtual void StreamOut( TIXML_OSTREAM * out ) const;
// [internal use]
// Set the document pointer so the attribute can report errors.
void SetDocument( TiXmlDocument* doc ) { document = doc; }
private:
TiXmlDocument* document; // A pointer back to a document, for error reporting.
TIXML_STRING name;
TIXML_STRING value;
TiXmlAttribute* prev;
TiXmlAttribute* next;
};
/* A class used to manage a group of attributes.
It is only used internally, both by the ELEMENT and the DECLARATION.
The set can be changed transparent to the Element and Declaration
classes that use it, but NOT transparent to the Attribute
which has to implement a next() and previous() method. Which makes
it a bit problematic and prevents the use of STL.
This version is implemented with circular lists because:
- I like circular lists
- it demonstrates some independence from the (typical) doubly linked list.
*/
class TiXmlAttributeSet
{
public:
TiXmlAttributeSet();
~TiXmlAttributeSet();
void Add( TiXmlAttribute* attribute );
void Remove( TiXmlAttribute* attribute );
TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
TiXmlAttribute* Find( const char * name ) const;
private:
TiXmlAttribute sentinel;
};
/** The element is a container class. It has a value, the element name,
and can contain other elements, text, comments, and unknowns.
Elements also contain an arbitrary number of attributes.
*/
class TiXmlElement : public TiXmlNode
{
public:
/// Construct an element.
TiXmlElement (const char * in_value);
#ifdef TIXML_USE_STL
/// std::string constructor.
TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::ELEMENT )
{
firstChild = lastChild = 0;
value = _value;
}
#endif
virtual ~TiXmlElement();
/** Given an attribute name, attribute returns the value
for the attribute of that name, or null if none exists.
*/
const char* Attribute( const char* name ) const;
/** Given an attribute name, attribute returns the value
for the attribute of that name, or null if none exists.
If the attribute exists and can be converted to an integer,
the integer value will be put in the return 'i', if 'i'
is non-null.
*/
const char* Attribute( const char* name, int* i ) const;
/** Sets an attribute of name to a given value. The attribute
will be created if it does not exist, or changed if it does.
*/
void SetAttribute( const char* name, const char * value );
#ifdef TIXML_USE_STL
const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); }
const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); }
/// STL std::string form.
void SetAttribute( const std::string& name, const std::string& value )
{
StringToBuffer n( name );
StringToBuffer v( value );
if ( n.buffer && v.buffer )
SetAttribute (n.buffer, v.buffer );
}
///< STL std::string form.
void SetAttribute( const std::string& name, int value )
{
StringToBuffer n( name );
if ( n.buffer )
SetAttribute (n.buffer, value);
}
#endif
/** Sets an attribute of name to a given value. The attribute
will be created if it does not exist, or changed if it does.
*/
void SetAttribute( const char * name, int value );
/** Deletes an attribute with the given name.
*/
void RemoveAttribute( const char * name );
#ifdef TIXML_USE_STL
void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form.
#endif
TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element.
TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element.
// [internal use] Creates a new Element and returs it.
virtual TiXmlNode* Clone() const;
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
protected:
// Used to be public [internal use]
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
virtual void StreamOut( TIXML_OSTREAM * out ) const;
/* [internal use]
Attribtue parsing starts: next char past '<'
returns: next char past '>'
*/
virtual const char* Parse( const char* p );
/* [internal use]
Reads the "value" of the element -- another element, or text.
This should terminate with the current end tag.
*/
const char* ReadValue( const char* in );
private:
TiXmlAttributeSet attributeSet;
};
/** An XML comment.
*/
class TiXmlComment : public TiXmlNode
{
public:
/// Constructs an empty comment.
TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
virtual ~TiXmlComment() {}
// [internal use] Creates a new Element and returs it.
virtual TiXmlNode* Clone() const;
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
protected:
// used to be public
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
virtual void StreamOut( TIXML_OSTREAM * out ) const;
/* [internal use]
Attribtue parsing starts: at the ! of the !--
returns: next char past '>'
*/
virtual const char* Parse( const char* p );
};
/** XML text. Contained in an element.
*/
class TiXmlText : public TiXmlNode
{
friend class TiXmlElement;
public:
/// Constructor.
TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT)
{
SetValue( initValue );
}
virtual ~TiXmlText() {}
#ifdef TIXML_USE_STL
/// Constructor.
TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
{
SetValue( initValue );
}
#endif
protected :
// [internal use] Creates a new Element and returns it.
virtual TiXmlNode* Clone() const;
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
virtual void StreamOut ( TIXML_OSTREAM * out ) const;
// [internal use]
bool Blank() const; // returns true if all white space and new lines
/* [internal use]
Attribtue parsing starts: First char of the text
returns: next char past '>'
*/
virtual const char* Parse( const char* p );
// [internal use]
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
};
/** In correct XML the declaration is the first entry in the file.
@verbatim
<?xml version="1.0" standalone="yes"?>
@endverbatim
TinyXml will happily read or write files without a declaration,
however. There are 3 possible attributes to the declaration:
version, encoding, and standalone.
Note: In this version of the code, the attributes are
handled as special cases, not generic attributes, simply
because there can only be at most 3 and they are always the same.
*/
class TiXmlDeclaration : public TiXmlNode
{
public:
/// Construct an empty declaration.
TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {}
#ifdef TIXML_USE_STL
/// Constructor.
TiXmlDeclaration(
const std::string& _version,
const std::string& _encoding,
const std::string& _standalone )
: TiXmlNode( TiXmlNode::DECLARATION )
{
version = _version;
encoding = _encoding;
standalone = _standalone;
}
#endif
/// Construct.
TiXmlDeclaration::TiXmlDeclaration( const char * _version,
const char * _encoding,
const char * _standalone );
virtual ~TiXmlDeclaration() {}
/// Version. Will return empty if none was found.
const char * Version() const { return version.c_str (); }
/// Encoding. Will return empty if none was found.
const char * Encoding() const { return encoding.c_str (); }
/// Is this a standalone document?
const char * Standalone() const { return standalone.c_str (); }
// [internal use] Creates a new Element and returs it.
virtual TiXmlNode* Clone() const;
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
protected:
// used to be public
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
virtual void StreamOut ( TIXML_OSTREAM * out) const;
// [internal use]
// Attribtue parsing starts: next char past '<'
// returns: next char past '>'
virtual const char* Parse( const char* p );
private:
TIXML_STRING version;
TIXML_STRING encoding;
TIXML_STRING standalone;
};
/** Any tag that tinyXml doesn't recognize is save as an
unknown. It is a tag of text, but should not be modified.
It will be written back to the XML, unchanged, when the file
is saved.
*/
class TiXmlUnknown : public TiXmlNode
{
public:
TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
virtual ~TiXmlUnknown() {}
// [internal use]
virtual TiXmlNode* Clone() const;
// [internal use]
virtual void Print( FILE* cfile, int depth ) const;
protected:
// used to be public
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
virtual void StreamOut ( TIXML_OSTREAM * out ) const;
/* [internal use]
Attribute parsing starts: First char of the text
returns: next char past '>'
*/
virtual const char* Parse( const char* p );
};
/** Always the top level node. A document binds together all the
XML pieces. It can be saved, loaded, and printed to the screen.
The 'value' of a document node is the xml file name.
*/
class TiXmlDocument : public TiXmlNode
{
public:
/// Create an empty document, that has no name.
TiXmlDocument();
/// Create a document with a name. The name of the document is also the filename of the xml.
TiXmlDocument( const char * documentName );
#ifdef TIXML_USE_STL
/// Constructor.
TiXmlDocument( const std::string& documentName ) :
TiXmlNode( TiXmlNode::DOCUMENT )
{
value = documentName;
error = false;
}
#endif
virtual ~TiXmlDocument() {}
/** Load a file using the current document value.
Returns true if successful. Will delete any existing
document data before loading.
*/
bool LoadFile();
/// Save a file using the current document value. Returns true if successful.
bool SaveFile() const;
/// Load a file using the given filename. Returns true if successful.
bool LoadFile( const char * filename );
/// Save a file using the given filename. Returns true if successful.
bool SaveFile( const char * filename ) const;
#ifdef TIXML_USE_STL
bool LoadFile( const std::string& filename ) ///< STL std::string version.
{
StringToBuffer f( filename );
return ( f.buffer && LoadFile( f.buffer ));
}
bool SaveFile( const std::string& filename ) const ///< STL std::string version.
{
StringToBuffer f( filename );
return ( f.buffer && SaveFile( f.buffer ));
}
#endif
/// Parse the given null terminated block of xml data.
virtual const char* Parse( const char* p );
/** Get the root element -- the only top level element -- of the document.
In well formed XML, there should only be one. TinyXml is tolerant of
multiple elements at the document level.
*/
TiXmlElement* RootElement() const { return FirstChildElement(); }
/// If, during parsing, a error occurs, Error will be set to true.
bool Error() const { return error; }
/// Contains a textual (english) description of the error if one occurs.
const char * ErrorDesc() const { return errorDesc.c_str (); }
/** Generally, you probably want the error string ( ErrorDesc() ). But if you
prefer the ErrorId, this function will fetch it.
*/
const int ErrorId() const { return errorId; }
/// If you have handled the error, it can be reset with this call.
void ClearError() { error = false; errorId = 0; errorDesc = ""; }
/** Dump the document to standard out. */
void Print() const { Print( stdout, 0 ); }
// [internal use]
virtual void Print( FILE* cfile, int depth = 0 ) const;
// [internal use]
void SetError( int err ) { assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
error = true;
errorId = err;
errorDesc = errorString[ errorId ]; }
protected :
virtual void StreamOut ( TIXML_OSTREAM * out) const;
// [internal use]
virtual TiXmlNode* Clone() const;
#ifdef TIXML_USE_STL
virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag );
#endif
private:
bool error;
int errorId;
TIXML_STRING errorDesc;
};
#endif
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/tinyxml/tinyxmlerror.cpp] - (1,657 bytes)
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "stdafx.h"
#include "tinyxml.h"
// The goal of the seperate error file is to make the first
// step towards localization. tinyxml (currently) only supports
// latin-1, but at least the error messages could now be translated.
//
// It also cleans up the code a bit.
//
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
{
"No error",
"Error",
"Failed to open file",
"Memory allocation failed.",
"Error parsing Element.",
"Failed to read Element name",
"Error reading Element value.",
"Error reading Attributes.",
"Error: empty tag.",
"Error reading end tag.",
"Error parsing Unknown.",
"Error parsing Comment.",
"Error parsing Declaration.",
"Error document empty."
};
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/tinyxml/tinyxmlparser.cpp] - (18,440 bytes)
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "stdafx.h"
#include "tinyxml.h"
#include <ctype.h>
//#define DEBUG_PARSER
// Note tha "PutString" hardcodes the same list. This
// is less flexible than it appears. Changing the entries
// or order will break putstring.
TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
{
{ "&", 5, '&' },
{ "<", 4, '<' },
{ ">", 4, '>' },
{ """, 6, '\"' },
{ "'", 6, '\'' }
};
const char* TiXmlBase::SkipWhiteSpace( const char* p )
{
if ( !p || !*p )
{
return 0;
}
while ( p && *p )
{
if ( isspace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space.
++p;
else
break;
}
return p;
}
#ifdef TIXML_USE_STL
/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
for( ;; )
{
if ( !in->good() ) return false;
int c = in->peek();
if ( !IsWhiteSpace( c ) )
return true;
*tag += in->get();
}
}
/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->peek();
if ( c == character )
return true;
in->get();
*tag += c;
}
return false;
}
#endif
const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name )
{
*name = "";
assert( p );
// Names start with letters or underscores.
// After that, they can be letters, underscores, numbers,
// hyphens, or colons. (Colons are valid ony for namespaces,
// but tinyxml can't tell namespaces from names.)
if ( p && *p
&& ( isalpha( (unsigned char) *p ) || *p == '_' ) )
{
while( p && *p
&& ( isalnum( (unsigned char ) *p )
|| *p == '_'
|| *p == '-'
|| *p == ':' ) )
{
(*name) += *p;
++p;
}
return p;
}
return 0;
}
const char* TiXmlBase::GetEntity( const char* p, char* value )
{
// Presume an entity, and pull it out.
TIXML_STRING ent;
int i;
// Ignore the entities.
if ( strncmp( "", p, 3 ) == 0
&& *(p+3)
&& *(p+4) )
{
*value = 0;
if ( isalpha( *(p+3) ) ) *value += ( tolower( *(p+3) ) - 'a' + 10 ) * 16;
else *value += ( *(p+3) - '0' ) * 16;
if ( isalpha( *(p+4) ) ) *value += ( tolower( *(p+4) ) - 'a' + 10 );
else *value += ( *(p+4) - '0' );
return p+6;
}
// Now try to match it.
for( i=0; i<NUM_ENTITY; ++i )
{
if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
{
assert( strlen( entity[i].str ) == entity[i].strLength );
*value = entity[i].chr;
return ( p + entity[i].strLength );
}
}
// So it wasn't an entity, its unrecognized, or something like that.
*value = *p; // Don't put back the last one, since we return it!
return p+1;
}
bool TiXmlBase::StringEqual( const char* p,
const char* tag,
bool ignoreCase )
{
assert( p );
if ( !p || !*p )
{
assert( 0 );
return false;
}
if ( tolower( *p ) == tolower( *tag ) )
{
const char* q = p;
if (ignoreCase)
{
while ( *q && *tag && *q == *tag )
{
++q;
++tag;
}
if ( *tag == 0 ) // Have we found the end of the tag, and everything equal?
{
return true;
}
}
else
{
while ( *q && *tag && tolower( *q ) == tolower( *tag ) )
{
++q;
++tag;
}
if ( *tag == 0 )
{
return true;
}
}
}
return false;
}
const char* TiXmlBase::ReadText( const char* p,
TIXML_STRING * text,
bool trimWhiteSpace,
const char* endTag,
bool caseInsensitive )
{
*text = "";
if ( !trimWhiteSpace // certain tags always keep whitespace
|| !condenseWhiteSpace ) // if true, whitespace is always kept
{
// Keep all the white space.
while ( p && *p
&& !StringEqual( p, endTag, caseInsensitive )
)
{
char c;
p = GetChar( p, &c );
(* text) += c;
}
}
else
{
bool whitespace = false;
// Remove leading white space:
p = SkipWhiteSpace( p );
while ( p && *p
&& !StringEqual( p, endTag, caseInsensitive ) )
{
if ( *p == '\r' || *p == '\n' )
{
whitespace = true;
++p;
}
else if ( isspace( *p ) )
{
whitespace = true;
++p;
}
else
{
// If we've found whitespace, add it before the
// new character. Any whitespace just becomes a space.
if ( whitespace )
{
(* text) += ' ';
whitespace = false;
}
char c;
p = GetChar( p, &c );
(* text) += c;
}
}
}
return p + strlen( endTag );
}
#ifdef TIXML_USE_STL
void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
// The basic issue with a document is that we don't know what we're
// streaming. Read something presumed to be a tag (and hope), then
// identify it, and call the appropriate stream method on the tag.
//
// This "pre-streaming" will never read the closing ">" so the
// sub-tag can orient itself.
if ( !StreamTo( in, '<', tag ) )
{
SetError( TIXML_ERROR_PARSING_EMPTY );
return;
}
while ( in->good() )
{
int tagIndex = tag->length();
while ( in->good() && in->peek() != '>' )
{
int c = in->get();
(*tag) += (char) c;
}
if ( in->good() )
{
// We now have something we presume to be a node of
// some sort. Identify it, and call the node to
// continue streaming.
TiXmlNode* node = Identify( tag->c_str() + tagIndex );
if ( node )
{
node->StreamIn( in, tag );
bool isElement = node->ToElement() != 0;
delete node;
node = 0;
// If this is the root element, we're done. Parsing will be
// done by the >> operator.
if ( isElement )
{
return;
}
}
else
{
SetError( TIXML_ERROR );
return;
}
}
}
// We should have returned sooner.
SetError( TIXML_ERROR );
}
#endif
const char* TiXmlDocument::Parse( const char* p )
{
// Parse away, at the document level. Since a document
// contains nothing but other tags, most of what happens
// here is skipping white space.
//
// In this variant (as opposed to stream and Parse) we
// read everything we can.
if ( !p || !*p )
{
SetError( TIXML_ERROR_DOCUMENT_EMPTY );
return false;
}
p = SkipWhiteSpace( p );
if ( !p )
{
SetError( TIXML_ERROR_DOCUMENT_EMPTY );
return false;
}
while ( p && *p )
{
TiXmlNode* node = Identify( p );
if ( node )
{
p = node->Parse( p );
LinkEndChild( node );
}
else
{
break;
}
p = SkipWhiteSpace( p );
}
// All is well.
return p;
}
TiXmlNode* TiXmlNode::Identify( const char* p )
{
TiXmlNode* returnNode = 0;
p = SkipWhiteSpace( p );
if( !p || !*p || *p != '<' )
{
return 0;
}
TiXmlDocument* doc = GetDocument();
p = SkipWhiteSpace( p );
if ( !p || !*p )
{
return 0;
}
// What is this thing?
// - Elements start with a letter or underscore, but xml is reserved.
// - Comments: <!--
// - Decleration: <?xml
// - Everthing else is unknown to tinyxml.
//
const char* xmlHeader = { "<?xml" };
const char* commentHeader = { "<!--" };
if ( StringEqual( p, xmlHeader, true ) )
{
#ifdef DEBUG_PARSER
TIXML_LOG( "XML parsing Declaration\n" );
#endif
returnNode = new TiXmlDeclaration();
}
else if ( isalpha( *(p+1) )
|| *(p+1) == '_' )
{
#ifdef DEBUG_PARSER
TIXML_LOG( "XML parsing Element\n" );
#endif
returnNode = new TiXmlElement( "" );
}
else if ( StringEqual( p, commentHeader, false ) )
{
#ifdef DEBUG_PARSER
TIXML_LOG( "XML parsing Comment\n" );
#endif
returnNode = new TiXmlComment();
}
else
{
#ifdef DEBUG_PARSER
TIXML_LOG( "XML parsing Unknown\n" );
#endif
returnNode = new TiXmlUnknown();
}
if ( returnNode )
{
// Set the parent, so it can report errors
returnNode->parent = this;
//p = returnNode->Parse( p );
}
else
{
if ( doc )
doc->SetError( TIXML_ERROR_OUT_OF_MEMORY );
}
return returnNode;
}
#ifdef TIXML_USE_STL
void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
{
// We're called with some amount of pre-parsing. That is, some of "this"
// element is in "tag". Go ahead and stream to the closing ">"
while( in->good() )
{
int c = in->get();
(*tag) += (char) c ;
if ( c == '>' )
break;
}
if ( tag->length() < 3 ) return;
// Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
// If not, identify and stream.
if ( tag->at( tag->length() - 1 ) == '>'
&& tag->at( tag->length() - 2 ) == '/' )
{
// All good!
return;
}
else if ( tag->at( tag->length() - 1 ) == '>' )
{
// There is more. Could be:
// text
// closing tag
// another node.
for ( ;; )
{
StreamWhiteSpace( in, tag );
// Do we have text?
if ( in->peek() != '<' )
{
// Yep, text.
TiXmlText text( "" );
text.StreamIn( in, tag );
// What follows text is a closing tag or another node.
// Go around again and figure it out.
continue;
}
// We now have either a closing tag...or another node.
// We should be at a "<", regardless.
if ( !in->good() ) return;
assert( in->peek() == '<' );
int tagIndex = tag->length();
bool closingTag = false;
bool firstCharFound = false;
for( ;; )
{
if ( !in->good() )
return;
int c = in->peek();
if ( c == '>' )
break;
*tag += c;
in->get();
if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
{
firstCharFound = true;
if ( c == '/' )
closingTag = true;
}
}
// If it was a closing tag, then read in the closing '>' to clean up the input stream.
// If it was not, the streaming will be done by the tag.
if ( closingTag )
{
int c = in->get();
assert( c == '>' );
*tag += c;
// We are done, once we've found our closing tag.
return;
}
else
{
// If not a closing tag, id it, and stream.
const char* tagloc = tag->c_str() + tagIndex;
TiXmlNode* node = Identify( tagloc );
if ( !node )
return;
node->StreamIn( in, tag );
delete node;
node = 0;
// No return: go around from the beginning: text, closing tag, or node.
}
}
}
}
#endif
const char* TiXmlElement::Parse( const char* p )
{
p = SkipWhiteSpace( p );
TiXmlDocument* document = GetDocument();
if ( !p || !*p || *p != '<' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
return false;
}
p = SkipWhiteSpace( p+1 );
// Read the name.
p = ReadName( p, &value );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME );
return false;
}
TIXML_STRING endTag ("</");
endTag += value;
endTag += ">";
// Check for and read attributes. Also look for an empty
// tag or an end tag.
while ( p && *p )
{
p = SkipWhiteSpace( p );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
return 0;
}
if ( *p == '/' )
{
++p;
// Empty tag.
if ( *p != '>' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY );
return 0;
}
return (p+1);
}
else if ( *p == '>' )
{
// Done with attributes (if there were any.)
// Read the value -- which can include other
// elements -- read the end tag, and return.
++p;
p = ReadValue( p ); // Note this is an Element method, and will set the error if one happens.
if ( !p || !*p )
return 0;
// We should find the end tag now
if ( StringEqual( p, endTag.c_str(), false ) )
{
p += endTag.length();
return p;
}
else
{
if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG );
return 0;
}
}
else
{
// Try to read an element:
TiXmlAttribute attrib;
attrib.SetDocument( document );
p = attrib.Parse( p );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
return 0;
}
SetAttribute( attrib.Name(), attrib.Value() );
}
}
return p;
}
const char* TiXmlElement::ReadValue( const char* p )
{
TiXmlDocument* document = GetDocument();
// Read in text and elements in any order.
p = SkipWhiteSpace( p );
while ( p && *p )
{
if ( *p != '<' )
{
// Take what we have, make a text element.
TiXmlText* textNode = new TiXmlText( "" );
if ( !textNode )
{
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
return 0;
}
p = textNode->Parse( p );
if ( !textNode->Blank() )
LinkEndChild( textNode );
else
delete textNode;
}
else
{
// We hit a '<'
// Have we hit a new element or an end tag?
if ( StringEqual( p, "</", false ) )
{
return p;
}
else
{
TiXmlNode* node = Identify( p );
if ( node )
{
p = node->Parse( p );
LinkEndChild( node );
}
else
{
return 0;
}
}
}
p = SkipWhiteSpace( p );
}
if ( !p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE );
}
return p;
}
#ifdef TIXML_USE_STL
void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlUnknown::Parse( const char* p )
{
TiXmlDocument* document = GetDocument();
p = SkipWhiteSpace( p );
if ( !p || !*p || *p != '<' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
return 0;
}
++p;
value = "";
while ( p && *p && *p != '>' )
{
value += *p;
++p;
}
if ( !p )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
}
if ( *p == '>' )
return p+1;
return p;
}
#ifdef TIXML_USE_STL
void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>'
&& tag->at( tag->length() - 2 ) == '-'
&& tag->at( tag->length() - 3 ) == '-' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlComment::Parse( const char* p )
{
TiXmlDocument* document = GetDocument();
value = "";
p = SkipWhiteSpace( p );
const char* startTag = "<!--";
const char* endTag = "-->";
if ( !StringEqual( p, startTag, false ) )
{
document->SetError( TIXML_ERROR_PARSING_COMMENT );
return 0;
}
p += strlen( startTag );
p = ReadText( p, &value, false, endTag, false );
return p;
}
const char* TiXmlAttribute::Parse( const char* p )
{
p = SkipWhiteSpace( p );
if ( !p || !*p ) return 0;
// Read the name, the '=' and the value.
p = ReadName( p, &name );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
return 0;
}
p = SkipWhiteSpace( p );
if ( !p || !*p || *p != '=' )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
return 0;
}
++p; // skip '='
p = SkipWhiteSpace( p );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
return 0;
}
const char* end;
if ( *p == '\'' )
{
++p;
end = "\'";
p = ReadText( p, &value, false, end, false );
}
else if ( *p == '"' )
{
++p;
end = "\"";
p = ReadText( p, &value, false, end, false );
}
else
{
// All attribute values should be in single or double quotes.
// But this is such a common error that the parser will try
// its best, even without them.
value = "";
while ( p && *p // existence
&& !isspace( *p ) && *p != '\n' && *p != '\r' // whitespace
&& *p != '/' && *p != '>' ) // tag end
{
value += *p;
++p;
}
}
return p;
}
#ifdef TIXML_USE_STL
void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->peek();
if ( c == '<' )
return;
(*tag) += c;
in->get();
}
}
#endif
const char* TiXmlText::Parse( const char* p )
{
value = "";
//TiXmlDocument* doc = GetDocument();
bool ignoreWhite = true;
// if ( doc && !doc->IgnoreWhiteSpace() ) ignoreWhite = false;
const char* end = "<";
p = ReadText( p, &value, ignoreWhite, end, false );
if ( p )
return p-1; // don't truncate the '<'
return 0;
}
#ifdef TIXML_USE_STL
void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlDeclaration::Parse( const char* p )
{
p = SkipWhiteSpace( p );
// Find the beginning, find the end, and look for
// the stuff in-between.
TiXmlDocument* document = GetDocument();
if ( !p || !*p || !StringEqual( p, "<?xml", true ) )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION );
return 0;
}
p += 5;
// const char* start = p+5;
// const char* end = strstr( start, "?>" );
version = "";
encoding = "";
standalone = "";
while ( p && *p )
{
if ( *p == '>' )
{
++p;
return p;
}
p = SkipWhiteSpace( p );
if ( StringEqual( p, "version", true ) )
{
// p += 7;
TiXmlAttribute attrib;
p = attrib.Parse( p );
version = attrib.Value();
}
else if ( StringEqual( p, "encoding", true ) )
{
// p += 8;
TiXmlAttribute attrib;
p = attrib.Parse( p );
encoding = attrib.Value();
}
else if ( StringEqual( p, "standalone", true ) )
{
// p += 10;
TiXmlAttribute attrib;
p = attrib.Parse( p );
standalone = attrib.Value();
}
else
{
// Read over whatever it is.
while( p && *p && *p != '>' && !isspace( *p ) )
++p;
}
}
return 0;
}
bool TiXmlText::Blank() const
{
for ( unsigned i=0; i<value.length(); i++ )
if ( !isspace( value[i] ) )
return false;
return true;
}
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/ClassFactory.h] - (10,074 bytes)
// ClassFactory.h: interface for the CClassFactory class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(XML_CLASS_FACTORY_INCLUDE)
#define XML_CLASS_FACTORY_INCLUDE
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "tinyxml\tinyxml.h"
/*!
\author Juan Antonio Medina ^ mICrO ( mail<_at_>juan-medina.com )
\mainpage Class Factorys using XML
\section intro Introduction
Class Factorys using XML.
Forgive me for my really bad English :)
This class its a implementation of something like class factory.
It's could be easy modified to make father implementations of
complex data structures with an easy Access System.
It's could be easy modified to make father implementations of
complex data structures with an easy Access System.
\section format Formats
XML Classes Definitions Format :
\verbatim
<classes>
<class name="className" extends="parentClass">
<attribute name="attriButeName"/>
...
</class>
...
</classes>
\endverbatim
Example :
\verbatim
<classes>
<class name="vehicle">
<attribute name="color"/>
<attribute name="model"/>
<attribute name="fabricant"/>
</class>
<class name="car" extends="vehicle">
<attribute name="wheels"/>
<attribute name="air-condition"/>
</class>
<class name="bus" extends="car">
<attribute name="paxes"/>
</class>
<class name="plane" extends="vehicle">
<attribute name="turbines"/>
</class>
</classes>
\endverbatim
XML Objects Instaces Context Format :
\verbatim
<instances>
<instance class="className" name="instaceName">
<attributeName>value</attributeName>
...
</instance>
...
</instances>
\endverbatim
Example :
\verbatim
<instances>
<instance class="car" name="car118256553">
<wheels>3</wheels>
<air-condition>no</air-condition>
<color>red</color>
<model>huge</model>
<fabricant />
</instance>
<instance class="bus" name="bus118260529">
<paxes>55</paxes>
<wheels>12</wheels>
<air-condition>yes</air-condition>
<color>blue</color>
<model />
<fabricant />
</instance>
</instances>
\endverbatim
*
*/
//! Class Factorys using XML.
/*!
This class its a implementation of something like class factory.
*/
class CClassFactory
{
public:
/* INITIALIZATION ****/
//! Default constructor
/*!
Default constructor
*/
CClassFactory();
//! Default destructor
/*!
Default destructor
*/
virtual ~CClassFactory();
//! Clear current classes definitions
/*!
Clear current classes definitions
*/
void clearClasDef();
//! Clear current context
/*!
Clear current context
*/
void clearCurContext();
/* CLASS MANIPULATION ****/
//! add a new Class Definitions to the class Factory
/*!
You should call this method to add new Class Definition to the Class
Factory.
\param className = class name for the new class definition
\param extends = parent class, NULL if we dont set it
\return true if the operations was valid
\sa deleteClass
\sa findClass
*/
bool addClass (const char * className, const char* extends);
//! find a particular class in the clasess Definitions of the class Factory
/*!
You should call this method to find a class definition giving a class
name.
\param className = class name that you searching for
\return an TiXmlNode pointer represents the class, NULL if we couldn't
find it
\sa addClass
\sa deleteClass
*/
TiXmlNode* findClass(const char* className);
//! delete a particular class in the clasess Definitions
/*!
You should call this method to delete a class definition giving a class
name.
\param className = class name that you want to delete
\return true if the operations was valid
\sa addClass
\sa findClass
*/
bool deleteClass(const char* className);
/* ATTRIBUTE MANIPULATION ****/
//! add a new Attribute to a giving class
/*!
You should call this method to add a new attribute to a giving class.
\param className = class name that holds the attribute
\param attributeName = attribute name for the new attribute
\return true if the operations was valid
\sa deleteAttribute
*/
bool addAttribute(const char* className, const char* attributeName);
//! delete an Attribute from a giving class
/*!
You should call this method to delete an attribute from a giving class.
\param className = class name that holds the attribute
\param attributeName = attribute name for delete
\return true if the operations was valid
\sa addAttribute
*/
bool deleteAttribute(const char *className, const char *attributeName);
/* INSTANCE MANIPULATION ****/
//! Make a new object instace of a giving class name
/*!
You should call this method to add a new object instance of a giving
name. This method olso creates the values of the atributes of this
class, and uppers classes following the hirearchy..
\param className = class name that we want to instance it
\param instanceName = instance name for the new instance
\return true if the operations was valid
\sa deleteInstace
\sa findInstance
*/
bool newInstance(const char * className, const char* instanceName);
//! find an object instace of a giving class name
/*!
You should call this method to find an object instance of a giving
instace name.
\param instanceName = instance name to be find
\return an TiXmlNode pointer represents the instance, NULL if we
couldn't find it
\sa deleteInstace
\sa newInstance
*/
TiXmlNode* findInstance(const char * instanceName);
//! delete an object instace of a giving instance name
/*!
You should call this method to delete an object instance of a giving
instace name.
\param instanceName = instance name to be delete
\return true if the operations was valid
\sa newInstance
\sa findInstance
*/
bool deleteInstace(const char* instanceName);
//! Set the value of an attribute in a giving object instance
/*!
You should call this method to set the value of an attribute in a
givging object instace
\param instanceName = instance name of the object instance
\param attributeName = attribute name in the object instance
\param value = value to set
\return true if the operations was valid
\sa getValue
*/
bool setValue(const char * instanceName, const char* attributeName,
const char* value);
//! Get the value of an attribute in a giving object instance
/*!
You should call this method to get the value of an attribute in a
givging object instace
\param instanceName = instance name of the object instance
\param attributeName = attribute name in the object instance
\return the value of the attribute, "" if isn't have any
\sa setValue
*/
CString getValue(const char * instanceName, const char* attributeName);
/* PERSISTENCE ****/
//! Load classes definitions from a XML / Text file
/*!
You should call this method to load the full classes definitions
from a XML FILE
\param filename = file to load
\return true if operation it's valid
\sa saveClassDef
*/
bool loadClassDef(const char* filename);
//! Save classes definitions from a XML / Text file
/*!
You should call this method to save the full classes definitions
to a XML FILE
\param filename = file to save
\return true if operation it's valid
\sa loadClassDef
*/
bool saveClassDef(const char *filename);
//! Load object instances context from a XML / Text file
/*!
You should call this method to load the full object instances context
from a XML FILE
\param filename = file to load
\return true if operation it's valid
\sa saveContext
*/
bool loadContext(const char *filename);
//! Save object instances context from a XML / Text file
/*!
You should call this method to save the full object instances context
to a XML FILE
\param filename = file to save
\return true if operation it's valid
\sa loadContext
*/
bool saveContext(const char *filename);
/* GETs ****/
//! Get the full classes definitions as an xml dom document
/*!
You should call this method to get the classes definitions
in a TiXmlDocument.
\return an TiXmlDocument pointer to the classes definitions
\sa getCurContext
*/
inline TiXmlDocument* getClassDef(){return &classesDefinitions;}
//! Get the full objects instances as an xml dom document
/*!
You should call this method to get the objects instances
in a TiXmlDocument.
\return an TiXmlDocument pointer to the objects instances
\sa getClassDef
*/
inline TiXmlDocument* getCurContext(){return ¤tContext;}
private:
/* ATTRIBUTES ****/
//! XML Document with classes definitions
/*!
XML Document with classes definitions
*/
TiXmlDocument classesDefinitions;
//! XML Document with objects instances
/*!
XML Document with objects instances
*/
TiXmlDocument currentContext;
/* HELPERS ****/
//! Add the attributes of a class to a instance (INTERNAL USE)
/*!
This function add the attributes of desired class to a giving
instance, this method work in recursive way to add all the
attribute of uppers classes to the instance.
\param element = TiXmlElement pointer represents the Instance
\param classNode = TiXmlElement pointer represents the class definition
\return true if operation it's valid
*/
bool addAttributesToInstance(TiXmlElement* element, TiXmlNode* classNode);
//! Display an Error Message
/*!
Nasty function to display errors
\param errorString = String with the error
*/
void error(char message[], ...);
};
#endif // !defined(XML_CLASS_FACTORY_INCLUDE)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewAttributeDlg.cpp] - (1,097 bytes)
// NewAttributeDlg.cpp : implementation file
//
#include "stdafx.h"
#include "xmlclass.h"
#include "NewAttributeDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNewAttributeDlg dialog
CNewAttributeDlg::CNewAttributeDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNewAttributeDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNewAttributeDlg)
m_attribute = _T("");
m_class = _T("");
//}}AFX_DATA_INIT
}
void CNewAttributeDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNewAttributeDlg)
DDX_Text(pDX, IDC_ATTRIBUTE, m_attribute);
DDX_Text(pDX, IDC_CLASS, m_class);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNewAttributeDlg, CDialog)
//{{AFX_MSG_MAP(CNewAttributeDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNewAttributeDlg message handlers
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewAttributeDlg.h] - (1,302 bytes)
#if !defined(AFX_NEWATTRIBUTEDLG_H__51538844_72C2_4F3C_B215_0B008681930F__INCLUDED_)
#define AFX_NEWATTRIBUTEDLG_H__51538844_72C2_4F3C_B215_0B008681930F__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// NewAttributeDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CNewAttributeDlg dialog
class CNewAttributeDlg : public CDialog
{
// Construction
public:
CNewAttributeDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CNewAttributeDlg)
enum { IDD = IDD_NEW_ATTRIBUTE };
CString m_attribute;
CString m_class;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CNewAttributeDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CNewAttributeDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_NEWATTRIBUTEDLG_H__51538844_72C2_4F3C_B215_0B008681930F__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewClassDlg.cpp] - (1,043 bytes)
// NewClassDlg.cpp : implementation file
//
#include "stdafx.h"
#include "xmlclass.h"
#include "NewClassDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNewClassDlg dialog
CNewClassDlg::CNewClassDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNewClassDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNewClassDlg)
m_class = _T("");
m_extends = _T("");
//}}AFX_DATA_INIT
}
void CNewClassDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNewClassDlg)
DDX_Text(pDX, IDC_CLASS, m_class);
DDX_Text(pDX, IDC_EXTENDS, m_extends);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNewClassDlg, CDialog)
//{{AFX_MSG_MAP(CNewClassDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNewClassDlg message handlers
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewClassDlg.h] - (1,256 bytes)
#if !defined(AFX_NEWCLASSDLG_H__8E8966E7_4A62_4A42_9D0C_E77438BC5F64__INCLUDED_)
#define AFX_NEWCLASSDLG_H__8E8966E7_4A62_4A42_9D0C_E77438BC5F64__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// NewClassDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CNewClassDlg dialog
class CNewClassDlg : public CDialog
{
// Construction
public:
CNewClassDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CNewClassDlg)
enum { IDD = IDD_NEW_CLASS };
CString m_class;
CString m_extends;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CNewClassDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CNewClassDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_NEWCLASSDLG_H__8E8966E7_4A62_4A42_9D0C_E77438BC5F64__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewInstanceDlg.cpp] - (1,070 bytes)
// NewInstanceDlg.cpp : implementation file
//
#include "stdafx.h"
#include "xmlclass.h"
#include "NewInstanceDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNewInstanceDlg dialog
CNewInstanceDlg::CNewInstanceDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNewInstanceDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNewInstanceDlg)
m_name = _T("");
m_class = _T("");
//}}AFX_DATA_INIT
}
void CNewInstanceDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNewInstanceDlg)
DDX_Text(pDX, IDC_NAME, m_name);
DDX_Text(pDX, IDC_CLASS, m_class);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNewInstanceDlg, CDialog)
//{{AFX_MSG_MAP(CNewInstanceDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNewInstanceDlg message handlers
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/NewInstanceDlg.h] - (1,286 bytes)
#if !defined(AFX_NewInstanceDlg_H__4D98A4B1_5E71_4C96_AA27_27B77A3F8FB0__INCLUDED_)
#define AFX_NewInstanceDlg_H__4D98A4B1_5E71_4C96_AA27_27B77A3F8FB0__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// NewInstanceDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CNewInstanceDlg dialog
class CNewInstanceDlg : public CDialog
{
// Construction
public:
CNewInstanceDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CNewInstanceDlg)
enum { IDD = IDD_NEW_INSTANCE };
CString m_name;
CString m_class;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CNewInstanceDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CNewInstanceDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_NewInstanceDlg_H__4D98A4B1_5E71_4C96_AA27_27B77A3F8FB0__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/Resource.h] - (2,013 bytes)
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by xmlclass.rc
//
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
#define IDS_ABOUTBOX 101
#define IDD_XMLCLASS_DIALOG 102
#define IDR_MAINFRAME 128
#define IDI_CLASS 131
#define IDI_CLASSES 132
#define IDD_NEW_INSTANCE 133
#define IDI_ATTRIBUTE 134
#define IDI_INSTANCE 135
#define IDD_NEW_CLASS 136
#define IDD_NEW_ATTRIBUTE 137
#define IDC_CLASSES_TREE 1000
#define IDC_LOAD_CLASSES 1001
#define IDC_CONTEXT_TREE 1002
#define IDC_SAVE_CLASSES 1003
#define IDC_LOAD_CONTEXT 1006
#define IDC_SAVE_CONTEXT 1007
#define IDC_NEW_INSTANCE 1010
#define IDC_INSTANCE_NAME 1011
#define IDC_ATTRIBUTE_NAME 1012
#define IDC_VALUE 1013
#define IDC_DELETE_INSTANCE 1014
#define IDC_NEW_CLASS 1015
#define IDC_SET_VALUE 1016
#define IDC_GET_VALUE 1017
#define IDC_QUIT 1018
#define IDC_CLASS 1019
#define IDC_NEW_ATTRIBUTE 1019
#define IDC_NAME 1020
#define IDC_DELETE_CLASS 1020
#define IDC_EXTENDS 1021
#define IDC_DELETE_ATTRIBUTE 1021
#define IDC_ATTRIBUTE 1022
#define IDC_RICHEDIT1 1023
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 139
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1025
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/StdAfx.cpp] - (210 bytes)
// stdafx.cpp : source file that includes just the standard includes
// xmlclass.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/StdAfx.h] - (999 bytes)
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__136C542D_14E1_46C8_A874_D38F1C1DA66B__INCLUDED_)
#define AFX_STDAFX_H__136C542D_14E1_46C8_A874_D38F1C1DA66B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__136C542D_14E1_46C8_A874_D38F1C1DA66B__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/xmlclass.cpp] - (2,058 bytes)
// xmlclass.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "xmlclass.h"
#include "xmlclassDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CXmlclassApp
BEGIN_MESSAGE_MAP(CXmlclassApp, CWinApp)
//{{AFX_MSG_MAP(CXmlclassApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXmlclassApp construction
CXmlclassApp::CXmlclassApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CXmlclassApp object
CXmlclassApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CXmlclassApp initialization
BOOL CXmlclassApp::InitInstance()
{
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CXmlclassDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/xmlclass.h] - (1,346 bytes)
// xmlclass.h : main header file for the XMLCLASS application
//
#if !defined(AFX_XMLCLASS_H__932E6872_4D2A_42C9_9056_AF38D9B0CA06__INCLUDED_)
#define AFX_XMLCLASS_H__932E6872_4D2A_42C9_9056_AF38D9B0CA06__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CXmlclassApp:
// See xmlclass.cpp for the implementation of this class
//
class CXmlclassApp : public CWinApp
{
public:
CXmlclassApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXmlclassApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CXmlclassApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_XMLCLASS_H__932E6872_4D2A_42C9_9056_AF38D9B0CA06__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/xmlclassDlg.cpp] - (15,435 bytes)
// xmlclassDlg.cpp : implementation file
//
#include "stdafx.h"
#include "xmlclass.h"
#include "xmlclassDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXmlclassDlg dialog
CXmlclassDlg::CXmlclassDlg(CWnd* pParent /*=NULL*/)
: CDialog(CXmlclassDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CXmlclassDlg)
m_instanceName = _T("");
m_attributeName = _T("");
m_value = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CXmlclassDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CXmlclassDlg)
DDX_Control(pDX, IDC_DELETE_ATTRIBUTE, m_bDeleteAttribute);
DDX_Control(pDX, IDC_DELETE_CLASS, m_bDeleteClass);
DDX_Control(pDX, IDC_NEW_ATTRIBUTE, m_bNewAttribute);
DDX_Control(pDX, IDC_DELETE_INSTANCE, m_bDeleteInstance);
DDX_Control(pDX, IDC_CONTEXT_TREE, m_contextTree);
DDX_Control(pDX, IDC_NEW_INSTANCE, m_bNewInstance);
DDX_Control(pDX, IDC_CLASSES_TREE, m_classTree);
DDX_Text(pDX, IDC_INSTANCE_NAME, m_instanceName);
DDX_Text(pDX, IDC_ATTRIBUTE_NAME, m_attributeName);
DDX_Text(pDX, IDC_VALUE, m_value);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CXmlclassDlg, CDialog)
//{{AFX_MSG_MAP(CXmlclassDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_QUIT, OnQuit)
ON_BN_CLICKED(IDC_LOAD_CLASSES, OnLoadClasses)
ON_NOTIFY(TVN_SELCHANGED, IDC_CLASSES_TREE, OnSelchangedClassesTree)
ON_BN_CLICKED(IDC_NEW_INSTANCE, OnNewInstance)
ON_NOTIFY(TVN_SELCHANGED, IDC_CONTEXT_TREE, OnSelchangedContextTree)
ON_BN_CLICKED(IDC_DELETE_INSTANCE, OnDeleteInstance)
ON_BN_CLICKED(IDC_SET_VALUE, OnSetValue)
ON_BN_CLICKED(IDC_GET_VALUE, OnGetValue)
ON_NOTIFY(NM_DBLCLK, IDC_CONTEXT_TREE, OnDblclkContextTree)
ON_BN_CLICKED(IDC_SAVE_CLASSES, OnSaveClasses)
ON_BN_CLICKED(IDC_LOAD_CONTEXT, OnLoadContext)
ON_BN_CLICKED(IDC_SAVE_CONTEXT, OnSaveContext)
ON_BN_CLICKED(IDC_NEW_CLASS, OnNewClass)
ON_BN_CLICKED(IDC_NEW_ATTRIBUTE, OnNewAttribute)
ON_BN_CLICKED(IDC_DELETE_CLASS, OnDeleteClass)
ON_BN_CLICKED(IDC_DELETE_ATTRIBUTE, OnDeleteAttribute)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXmlclassDlg message handlers
BOOL CXmlclassDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
//SetIcon(m_hIcon, FALSE); // Set small icon
initControls();
return TRUE; // return TRUE unless you set the focus to a control
}
void CXmlclassDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CXmlclassDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CXmlclassDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CXmlclassDlg::OnQuit()
{
EndDialog(IDOK);
}
void CXmlclassDlg::initControls()
{
m_classDefImages.Create(16,16,ILC_MASK,0,5);
m_classDefImages.Add(AfxGetApp()->LoadIcon(IDI_CLASSES));
m_classDefImages.Add(AfxGetApp()->LoadIcon(IDI_CLASS));
m_contextImages.Create(16,16,ILC_MASK,0,5);
m_contextImages.Add(AfxGetApp()->LoadIcon(IDI_INSTANCE));
m_contextImages.Add(AfxGetApp()->LoadIcon(IDI_ATTRIBUTE));
m_classTree.SetImageList(&m_classDefImages,TVSIL_NORMAL);
m_contextTree.SetImageList(&m_contextImages,TVSIL_NORMAL);
classFactory.clearClasDef();
classFactory.clearCurContext();
resetUI();
}
void CXmlclassDlg::OnLoadClasses()
{
CFileDialog fileDialog(true,".xml","classes.xml",OFN_HIDEREADONLY,"Xml Class definitions Files (*.xml)|*.xml|All Files (*.*)|*.*||");
if ( fileDialog.DoModal()==IDOK){
if ( classFactory.loadClassDef((LPCTSTR )fileDialog.GetPathName()) ) {
DrawClasses(classFactory.getClassDef()->RootElement());
}
}
}
void CXmlclassDlg::DrawClasses(TiXmlElement *classes)
{
resetUI();
if (classes==NULL) return;
char strBuf[1024];
TiXmlNode* classNode = NULL;
TiXmlNode* attributeNode = NULL;
const char* className=NULL;
const char* attributeName=NULL;
const char* extends=NULL;
classNode = classes->FirstChild("class");
while (classNode!=NULL){
className = classNode->ToElement()->Attribute("name");
extends = classNode->ToElement()->Attribute("extends");
if (className==NULL){
MessageBox("Error parsing class definition. Class need a name","Error",MB_OK|MB_ICONEXCLAMATION);
}else{
if (extends==NULL){
wsprintf (strBuf, "class : %s", className);
}else{
wsprintf (strBuf, "class : %s <extend %s>", className,extends);
}
HTREEITEM classInTree = m_classTree.InsertItem(strBuf,0);
attributeNode = classNode->FirstChild("attribute");
while ( attributeNode!=NULL){
attributeName = attributeNode->ToElement()->Attribute("name");
if (attributeName==NULL){
MessageBox("Error parsing class definition. Atribute need a name","Error",MB_OK|MB_ICONEXCLAMATION);
}else{
wsprintf (strBuf, "attribute : %s", attributeName);
m_classTree.InsertItem(strBuf,1,1,classInTree);
}
attributeNode = attributeNode->NextSibling("attribute");
}
}
classNode = classNode->NextSibling("class");
}
}
void CXmlclassDlg::OnSelchangedClassesTree(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
CString selected =m_classTree.GetItemText(pNMTreeView->itemNew.hItem);
BOOL itsClass = (selected.Find("class")!=-1);
m_bNewInstance.EnableWindow(itsClass);
m_bNewAttribute.EnableWindow(itsClass);
m_bDeleteAttribute.EnableWindow(!itsClass);
m_bDeleteClass.EnableWindow(itsClass);
*pResult = 0;
}
void CXmlclassDlg::OnNewInstance()
{
CString selected = m_classTree.GetItemText(m_classTree.GetSelectedItem());
int pos = selected.Find(":");
if (pos!=-1){
selected = selected.Mid(pos+2);
pos = selected.Find("<");
if (pos!=-1)
selected = selected.Left(pos-1);
newInstanceDlg.m_class = selected;
selected.Format("%s%08d",selected,GetTickCount());
newInstanceDlg.m_name = selected;
if ( newInstanceDlg.DoModal() == IDOK)
{
if ( classFactory.newInstance(newInstanceDlg.m_class,newInstanceDlg.m_name) )
{
DrawContext(classFactory.getCurContext()->RootElement());
}
}
}
}
void CXmlclassDlg::resetUI()
{
m_classTree.DeleteAllItems();
m_bNewInstance.EnableWindow(false);
m_bDeleteInstance.EnableWindow(false);
m_bNewAttribute.EnableWindow(false);
m_bDeleteAttribute.EnableWindow(false);
m_bDeleteClass.EnableWindow(false);
}
void CXmlclassDlg::DrawContext(TiXmlElement *context)
{
m_contextTree.DeleteAllItems();
if (context==NULL) return;
char strBuf[1024];
TiXmlNode* instanceNode = NULL;
TiXmlNode* attributeNode = NULL;
const char* instanceName=NULL;
const char* className=NULL;
instanceNode = context->FirstChild("instance");
while (instanceNode!=NULL){
instanceName = instanceNode->ToElement()->Attribute("name");
className = instanceNode->ToElement()->Attribute("class");
if (instanceName==NULL){
MessageBox("Error parsing instance, instance need a name","Error",MB_OK|MB_ICONEXCLAMATION);
}else{
wsprintf (strBuf, "%s : <class %s>", instanceName,className);
HTREEITEM instanceInTree = m_contextTree.InsertItem(strBuf,0);
attributeNode = instanceNode->FirstChild();
while ( attributeNode!=NULL){
wsprintf (strBuf, "%s", attributeNode->Value());
m_contextTree.InsertItem(strBuf,1,1,instanceInTree);
attributeNode = attributeNode->NextSibling();
}
}
instanceNode = instanceNode->NextSibling("instance");
}
}
void CXmlclassDlg::OnSelchangedContextTree(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
CString selected = m_classTree.GetItemText(pNMTreeView->itemNew.hItem);
BOOL itsInstance = (selected.Find("class")!=-1);
m_bDeleteInstance.EnableWindow(itsInstance);
*pResult = 0;
}
void CXmlclassDlg::OnDeleteInstance()
{
CString selected = m_contextTree.GetItemText(m_contextTree.GetSelectedItem());
int pos = selected.Find(":");
if (pos!=-1){
selected = selected.Left(pos-1);
if ( classFactory.deleteInstace(selected) )
{
DrawContext(classFactory.getCurContext()->RootElement());
}
}
}
void CXmlclassDlg::OnSetValue()
{
UpdateData(TRUE);
classFactory.setValue(m_instanceName,m_attributeName,m_value);
}
void CXmlclassDlg::OnGetValue()
{
UpdateData(TRUE);
m_value = classFactory.getValue(m_instanceName,m_attributeName);
UpdateData(FALSE);
}
void CXmlclassDlg::OnDblclkContextTree(NMHDR* pNMHDR, LRESULT* pResult)
{
HTREEITEM item, parentitem;
item = m_contextTree.GetSelectedItem();
parentitem = m_contextTree.GetParentItem(item);
CString selected;
selected = m_contextTree.GetItemText(item);
SetObjectInstaceData(selected);
selected = m_contextTree.GetItemText(parentitem);
SetObjectInstaceData(selected);
if (parentitem !=NULL){
OnGetValue();
}
*pResult = 0;
}
void CXmlclassDlg::SetObjectInstaceData(CString data)
{
int pos = data.Find(":");
if (pos!=-1){
data = data.Left(pos-1);
m_instanceName = data;
}else{
m_attributeName = data;
}
UpdateData(FALSE);
}
void CXmlclassDlg::OnSaveClasses()
{
CFileDialog fileDialog(false,".xml","classes.xml",OFN_HIDEREADONLY| OFN_OVERWRITEPROMPT,"Xml Class definitions Files (*.xml)|*.xml|All Files (*.*)|*.*||");
if ( fileDialog.DoModal()==IDOK){
classFactory.saveClassDef((LPCTSTR )fileDialog.GetPathName());
}
}
void CXmlclassDlg::OnLoadContext()
{
CFileDialog fileDialog(true,".xml","context.xml",OFN_HIDEREADONLY,"Xml Context Files (*.xml)|*.xml|All Files (*.*)|*.*||");
if ( fileDialog.DoModal()==IDOK){
if ( classFactory.loadContext((LPCTSTR )fileDialog.GetPathName()) ) {
DrawContext(classFactory.getCurContext()->RootElement());
}
}
}
void CXmlclassDlg::OnSaveContext()
{
CFileDialog fileDialog(false,".xml","context.xml",OFN_HIDEREADONLY| OFN_OVERWRITEPROMPT,"Xml Context Files (*.xml)|*.xml|All Files (*.*)|*.*||");
if ( fileDialog.DoModal()==IDOK){
classFactory.saveContext((LPCTSTR )fileDialog.GetPathName());
}
}
void CXmlclassDlg::OnNewClass()
{
if ( newClassDlg.DoModal() == IDOK)
{
if (classFactory.addClass(newClassDlg.m_class,newClassDlg.m_extends))
{
DrawClasses(classFactory.getClassDef()->RootElement());
}
}
}
void CXmlclassDlg::OnNewAttribute()
{
CString selected = m_classTree.GetItemText(m_classTree.GetSelectedItem());
int pos = selected.Find(":");
if (pos!=-1){
selected = selected.Mid(pos+2);
pos = selected.Find("<");
if (pos!=-1)
selected = selected.Left(pos-1);
newAttributeDlg.m_class = selected;
if ( newAttributeDlg.DoModal() == IDOK)
{
if (classFactory.addAttribute(newAttributeDlg.m_class,newAttributeDlg.m_attribute))
{
DrawClasses(classFactory.getClassDef()->RootElement());
}
}
}
}
void CXmlclassDlg::OnDeleteClass()
{
if ( MessageBox("Deleting a class dosen't delete current instance of this/descents classes.\nThis operation either delete descent class definitions.\n\nDo you really want to delete the class?","Warning!",MB_YESNO|MB_ICONQUESTION) == IDYES)
{
CString className = m_classTree.GetItemText(m_classTree.GetSelectedItem());
int pos = className.Find(":");
if (pos!=-1){
className = className.Mid(pos+2);
pos = className.Find("<");
if (pos!=-1)
className = className.Left(pos-1);
if (classFactory.deleteClass(className))
{
DrawClasses(classFactory.getClassDef()->RootElement());
}
}
}
}
void CXmlclassDlg::OnDeleteAttribute()
{
if ( MessageBox("Deleting an attribute donsen't afect to the instance objects that allready used it.\n\nDo you really want to delete the attribute?","Warning!",MB_YESNO|MB_ICONQUESTION) == IDYES)
{
CString className = m_classTree.GetItemText(m_classTree.GetParentItem(m_classTree.GetSelectedItem()));
int pos = className.Find(":");
if (pos!=-1){
className = className.Mid(pos+2);
pos = className.Find("<");
if (pos!=-1)
className = className.Left(pos-1);
CString attributeName = m_classTree.GetItemText(m_classTree.GetSelectedItem());
pos = attributeName.Find(":");
if (pos!=-1){
attributeName = attributeName.Mid(pos+2);
if (classFactory.deleteAttribute(className,attributeName))
{
DrawClasses(classFactory.getClassDef()->RootElement());
}
}
}
}
}
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/xmlclassDlg.h] - (2,675 bytes)
// xmlclassDlg.h : header file
//
#if !defined(AFX_XMLCLASSDLG_H__80332494_DEEC_43F3_B230_583E3254BCDE__INCLUDED_)
#define AFX_XMLCLASSDLG_H__80332494_DEEC_43F3_B230_583E3254BCDE__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ClassFactory.h"
#include "NewInstanceDlg.h"
#include "NewClassDlg.h"
#include "NewAttributeDlg.h"
/////////////////////////////////////////////////////////////////////////////
// CXmlclassDlg dialog
class CXmlclassDlg : public CDialog
{
// Construction
public:
void SetObjectInstaceData(CString data);
void DrawContext(TiXmlElement* context);
void resetUI();
void DrawClasses(TiXmlElement* classes);
void initControls();
CXmlclassDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CXmlclassDlg)
enum { IDD = IDD_XMLCLASS_DIALOG };
CButton m_bDeleteAttribute;
CButton m_bDeleteClass;
CButton m_bNewAttribute;
CButton m_bDeleteInstance;
CTreeCtrl m_contextTree;
CButton m_bNewInstance;
CTreeCtrl m_classTree;
CString m_instanceName;
CString m_attributeName;
CString m_value;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXmlclassDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CXmlclassDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnQuit();
afx_msg void OnLoadClasses();
afx_msg void OnSelchangedClassesTree(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnNewInstance();
afx_msg void OnSelchangedContextTree(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDeleteInstance();
afx_msg void OnSetValue();
afx_msg void OnGetValue();
afx_msg void OnDblclkContextTree(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnSaveClasses();
afx_msg void OnLoadContext();
afx_msg void OnSaveContext();
afx_msg void OnNewClass();
afx_msg void OnNewAttribute();
afx_msg void OnDeleteClass();
afx_msg void OnDeleteAttribute();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
CImageList m_classDefImages;
CImageList m_contextImages;
CClassFactory classFactory;
CNewInstanceDlg newInstanceDlg;
CNewClassDlg newClassDlg;
CNewAttributeDlg newAttributeDlg;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_XMLCLASSDLG_H__80332494_DEEC_43F3_B230_583E3254BCDE__INCLUDED_)
|
|
Currently browsing [xmlclass.zip] (149,064 bytes) - [xmlclass/ClassFactory.cpp] - (11,641 bytes)
#include "stdafx.h"
#include "ClassFactory.h"
CClassFactory::CClassFactory()
{
}
CClassFactory::~CClassFactory()
{
//don't forget to clear the documents. Just in case
clearClasDef();
clearCurContext();
}
void CClassFactory::clearClasDef()
{
//just clear the document
classesDefinitions.Clear();
}
void CClassFactory::clearCurContext()
{
//just clear the document
currentContext.Clear();
}
bool CClassFactory::loadContext(const char *filename)
{
//We load the file, and check Error
if (! currentContext.LoadFile(filename))
{
error("Error loading file = \"%s\" : %s.", filename,
currentContext.ErrorDesc());
return false;
}
else
return true;
}
bool CClassFactory::saveContext(const char *filename)
{
//We save the file, and check Error
if (! currentContext.SaveFile(filename))
{
error("Error saving file = \"%s\" : %s.", filename,
currentContext.ErrorDesc());
return false;
}
else
return true;
}
bool CClassFactory::loadClassDef(const char *filename)
{
//We load the file, and check Error
if (! classesDefinitions.LoadFile(filename))
{
error("Error loading file = \"%s\" : %s.", filename,
classesDefinitions.ErrorDesc());
return false;
}
else
return true;
}
bool CClassFactory::saveClassDef(const char *filename)
{
//We save the file, and check Error
if (! classesDefinitions.SaveFile(filename))
{
error("Error saving file = \"%s\" : %s.", filename,
classesDefinitions.ErrorDesc());
return false;
}
else
return true;
}
bool CClassFactory::newInstance(const char * className,
const char* instanceName)
{
TiXmlNode* classNode = findClass(className);
//we din't find the class
if (classNode == NULL)
{
error("Couldn't find class %s",className);
return false;
}
else
{
TiXmlElement* root = currentContext.RootElement();
//if document it's empty
if (root == NULL)
{
//create a root node
currentContext.Parse ("<instances/>");
root = currentContext.RootElement();
}
//new node for the instance
TiXmlElement element("instance");
//add the attributes to the instace
if (addAttributesToInstance(&element, classNode))
{
element.SetAttribute("class", className);
element.SetAttribute("name", instanceName);
//we add the instance it self
root->InsertEndChild(element);
}
else
return false;
}
return true;
}
TiXmlNode* CClassFactory::findClass(const char *className)
{
TiXmlNode* classNode = NULL;
bool found = false;
TiXmlElement* root = classesDefinitions.RootElement();
//if the document is empty return NULL
if (root == NULL)
{
return NULL;
}
//first class def
classNode = root->FirstChild("class");
const char* classNodeName;
//until be found it or they are no more class def
while ((classNode != NULL) && (!found))
{
//get the name of the class
classNodeName = classNode->ToElement()->Attribute("name");
//is the one?
if (strcmpi(classNodeName , className) == 0)
found = true;
else
//go to the next
classNode = classNode->NextSibling("class");
}
return ((found)?classNode:NULL);
}
bool CClassFactory::deleteInstace(const char *instanceName)
{
TiXmlNode* instanceNode = findInstance(instanceName);
//if we donde find it the instance
if (instanceNode == NULL)
{
error("Couldn't find instance %s",instanceName);
return false;
}
else
//remove the instance node
currentContext.RootElement()->RemoveChild(instanceNode);
return true;
}
TiXmlNode* CClassFactory::findInstance(const char *instanceName)
{
TiXmlNode* instanceNode = NULL;
bool found = false;
TiXmlElement* root = currentContext.RootElement();
//if the document is empty we return NULL
if (root == NULL)
{
return NULL;
}
//get first instance node
instanceNode = root->FirstChild("instance");
const char* instanceNodeName;
//until we found it or they are not more nodes
while ((instanceNode != NULL) && (!found))
{
//get instance name
instanceNodeName = instanceNode->ToElement()->Attribute("name");
//check if its the one
if (strcmpi(instanceNodeName , instanceName) == 0)
found = true;
else
//go to the next
instanceNode = instanceNode->NextSibling("instance");
}
return (found)?instanceNode:NULL;
}
bool CClassFactory::setValue(const char *instanceName,
const char *attributeName, const char *value)
{
TiXmlNode* instanceNode = findInstance(instanceName);
//if we don't find the instance
if (instanceNode == NULL)
{
error("Couldn't find instance %s",instanceName);
return false;
}
else
{
TiXmlNode* attributeNode = instanceNode->FirstChild(attributeName);
//if we don't find the attribute
if (attributeNode == NULL)
{
error("Couldn't find attribute %s",attributeName);
return false;
}
else
{
//if the attribute have a value (values are childs from attribute)
if (attributeNode->FirstChild() != NULL)
//set the value
attributeNode->FirstChild()->SetValue(value);
else
{
//add the value as children
TiXmlText text(value);
attributeNode->InsertEndChild(text);
}
}
}
return true;
}
CString CClassFactory::getValue(const char *instanceName,
const char *attributeName)
{
//by default "" value
CString value;
value = "";
TiXmlNode* instanceNode = findInstance(instanceName);
//if we din't found the instance
if (instanceNode == NULL)
error("Couldn't find instance %s",instanceName);
else
{
TiXmlNode* attributeNode = instanceNode->FirstChild(attributeName);
//if we find the attribute
if (attributeNode == NULL)
error("Couldn't find attribute %s",attributeName);
else
//if is have a value (values are childs from attribute)
if (attributeNode->FirstChild() != NULL)
value = attributeNode->FirstChild()->Value();
}
return value;
}
bool CClassFactory::addAttributesToInstance(TiXmlElement *element,
TiXmlNode *classNode)
{
TiXmlNode* attributeNode;
const char* attributeName;
//we get the first attribute
attributeNode = classNode->FirstChild("attribute");
//until we have not more attributes
while (attributeNode != NULL)
{
//get the name
attributeName = attributeNode->ToElement()->Attribute("name");
//add the attribute to the instance
TiXmlElement attrInstance (attributeName);
element->InsertEndChild(attrInstance);
//next attribute node
attributeNode = attributeNode->NextSibling("attribute");
}
const char* extends = NULL;
extends = classNode->ToElement()->Attribute("extends");
//if this class have a parent class
if (extends != NULL)
{
TiXmlNode* parentClassNode = findClass(extends);
//the parent class dosen't exist
if (parentClassNode == NULL)
{
error("Error couldn't find parent class %s",extends);
return false;
}
else
//add the attribute of the parent class (recursive)
return addAttributesToInstance(element, parentClassNode);
}
return true;
}
bool CClassFactory::addClass(const char *className, const char *extends)
{
TiXmlNode* classNode = findClass(className);
//if we allready have that class
if (classNode != NULL)
{
error("Class allready exits %s",className);
return false;
}
else
{
//new class def node
TiXmlElement element("class");
element.SetAttribute("name", className);
//if we set a parent class
if (extends != NULL)
{
//if we set a not empty class name
if (strcmpi(extends,"") != 0)
{
classNode = findClass(extends);
//if we din't find the parent class
if (classNode == NULL)
{
error("Parent class dont found %s","extends");
return false;
}
else
//set the parent as attribute of the node
element.SetAttribute("extends", extends);
}
}
TiXmlElement* root = classesDefinitions.RootElement();
//if document its empty
if (root == NULL)
{
//add a root node
classesDefinitions.Parse("<classes/>");
root = classesDefinitions.RootElement();
}
//insert the class def
root->InsertEndChild(element);
}
return true;;
}
bool CClassFactory::addAttribute(const char *className,
const char *attributeName)
{
TiXmlNode* classNode = findClass(className);
//if we din't find the class
if (classNode == NULL)
{
error("Class dosen't exits %s",className);
return false;
}
else
{
const char* findAttributeName = NULL;
bool found = false;
//get the fist attribute node
TiXmlNode* attributeNode = classNode->FirstChild("attribute");
//until be found it or they aren't more attributes nodes
while ((attributeNode != NULL) && (!found))
{
//get the attribute name
findAttributeName = attributeNode->ToElement()->Attribute("name");
//check if its the one
if (strcmpi(findAttributeName , attributeName) == 0)
found = true;
else
//go to the next attribute
attributeNode = attributeNode->NextSibling("attribute");
}
//if we found it
if (found)
{
error("Attribute allready defined for the class %s",attributeName);
return false;
}
else
{
//add the attribute to the class
TiXmlElement element("attribute");
element.SetAttribute("name", attributeName);
classNode->ToElement()->InsertEndChild(element);
}
}
return true;
}
bool CClassFactory::deleteClass(const char *className)
{
TiXmlNode* classNode = findClass(className);
//if we din't find the class
if (classNode == NULL)
{
error("Cant find the class %s",className);
return false;
}
else
//we remove the class def node. this olso remove all childrens
classesDefinitions.RootElement()->RemoveChild(classNode);
return true;
}
bool CClassFactory::deleteAttribute(const char *className,
const char *attributeName)
{
TiXmlNode* classNode = findClass(className);
//if we din't find the class name
if (classNode == NULL)
{
error("Class dosen't exits %s", className);
return false;
}
else
{
const char* findAttributeName = NULL;
bool found = false;
//get the first attribute node
TiXmlNode* attributeNode = classNode->FirstChild("attribute");
//until we found it or they aren't more attributes nodes
while ((attributeNode != NULL) && (!found))
{
//get the name
findAttributeName = attributeNode->ToElement()->Attribute("name");
//check if its the one
if (strcmpi(findAttributeName , attributeName) == 0)
found = true;
else
//go to the next
attributeNode = attributeNode->NextSibling("attribute");
}
//if we dont found it
if (!found)
{
error("Attribute dosen't exits for this class %s",attributeName);
return false;
}
else
//remove the attribute
classNode->RemoveChild(attributeNode);
}
return true;
}
void CClassFactory::error(char message[], ...)
{
//nasty code to display error messages
static char messageBuffer[8192];
va_list argumentsPointer;
va_start(argumentsPointer, message);
vsprintf(messageBuffer, message, argumentsPointer);
va_end(argumentsPointer);
MessageBox(NULL,messageBuffer,"Error", MB_OK | MB_ICONEXCLAMATION);
}
|
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|