From 6e7e30b5fd87766566620d48e785072e0b5c52cd Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 8 May 2007 06:33:25 +0000 Subject: Now they all read "taf" not "tsf" :) --- src/tafwriter.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/tafwriter.h (limited to 'src/tafwriter.h') diff --git a/src/tafwriter.h b/src/tafwriter.h new file mode 100644 index 0000000..7057d62 --- /dev/null +++ b/src/tafwriter.h @@ -0,0 +1,22 @@ +#ifndef BU_TAF_WRITER_H +#define BU_TAF_WRITER_H + +#include + +namespace Bu +{ + /** + * + */ + class TafWriter + { + public: + TafWriter(); + virtual ~TafWriter(); + + private: + + }; +} + +#endif -- cgit v1.2.3 From ad92dc50b7cdf7cfe086f21d19442d03a90fd05d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 9 May 2007 15:04:31 +0000 Subject: Just a few things re-arranged, moved the new taf/xml systems to the inprogress directory, and moved the old xml system in, so it will require heavy changes. --- src/inprogress/tafdocument.cpp | 9 + src/inprogress/tafdocument.h | 22 ++ src/inprogress/tafnode.cpp | 9 + src/inprogress/tafnode.h | 21 ++ src/inprogress/tafreader.cpp | 11 + src/inprogress/tafreader.h | 25 ++ src/inprogress/tafwriter.cpp | 9 + src/inprogress/tafwriter.h | 22 ++ src/inprogress/xmldocument.cpp | 9 + src/inprogress/xmldocument.h | 22 ++ src/inprogress/xmlnode.cpp | 9 + src/inprogress/xmlnode.h | 22 ++ src/inprogress/xmlreader.cpp | 267 +++++++++++++++++ src/inprogress/xmlreader.h | 121 ++++++++ src/inprogress/xmlwriter.cpp | 9 + src/inprogress/xmlwriter.h | 22 ++ src/old/xmldocument.cpp | 149 --------- src/old/xmldocument.h | 171 ----------- src/old/xmlnode.cpp | 445 --------------------------- src/old/xmlnode.h | 236 --------------- src/old/xmlreader.cpp | 602 ------------------------------------- src/old/xmlreader.h | 141 --------- src/old/xmlwriter.cpp | 173 ----------- src/old/xmlwriter.h | 96 ------ src/tafdocument.cpp | 9 - src/tafdocument.h | 22 -- src/tafnode.cpp | 9 - src/tafnode.h | 21 -- src/tafreader.cpp | 11 - src/tafreader.h | 25 -- src/tafwriter.cpp | 9 - src/tafwriter.h | 22 -- src/xmldocument.cpp | 146 ++++++++- src/xmldocument.h | 175 ++++++++++- src/xmlnode.cpp | 440 ++++++++++++++++++++++++++- src/xmlnode.h | 240 ++++++++++++++- src/xmlreader.cpp | 665 +++++++++++++++++++++++++++++++---------- src/xmlreader.h | 252 +++++++++------- src/xmlwriter.cpp | 168 ++++++++++- src/xmlwriter.h | 100 ++++++- 40 files changed, 2468 insertions(+), 2468 deletions(-) create mode 100644 src/inprogress/tafdocument.cpp create mode 100644 src/inprogress/tafdocument.h create mode 100644 src/inprogress/tafnode.cpp create mode 100644 src/inprogress/tafnode.h create mode 100644 src/inprogress/tafreader.cpp create mode 100644 src/inprogress/tafreader.h create mode 100644 src/inprogress/tafwriter.cpp create mode 100644 src/inprogress/tafwriter.h create mode 100644 src/inprogress/xmldocument.cpp create mode 100644 src/inprogress/xmldocument.h create mode 100644 src/inprogress/xmlnode.cpp create mode 100644 src/inprogress/xmlnode.h create mode 100644 src/inprogress/xmlreader.cpp create mode 100644 src/inprogress/xmlreader.h create mode 100644 src/inprogress/xmlwriter.cpp create mode 100644 src/inprogress/xmlwriter.h delete mode 100644 src/old/xmldocument.cpp delete mode 100644 src/old/xmldocument.h delete mode 100644 src/old/xmlnode.cpp delete mode 100644 src/old/xmlnode.h delete mode 100644 src/old/xmlreader.cpp delete mode 100644 src/old/xmlreader.h delete mode 100644 src/old/xmlwriter.cpp delete mode 100644 src/old/xmlwriter.h delete mode 100644 src/tafdocument.cpp delete mode 100644 src/tafdocument.h delete mode 100644 src/tafnode.cpp delete mode 100644 src/tafnode.h delete mode 100644 src/tafreader.cpp delete mode 100644 src/tafreader.h delete mode 100644 src/tafwriter.cpp delete mode 100644 src/tafwriter.h (limited to 'src/tafwriter.h') diff --git a/src/inprogress/tafdocument.cpp b/src/inprogress/tafdocument.cpp new file mode 100644 index 0000000..bd44dd5 --- /dev/null +++ b/src/inprogress/tafdocument.cpp @@ -0,0 +1,9 @@ +#include "tafdocument.h" + +Bu::TafDocument::TafDocument() +{ +} + +Bu::TafDocument::~TafDocument() +{ +} diff --git a/src/inprogress/tafdocument.h b/src/inprogress/tafdocument.h new file mode 100644 index 0000000..171f829 --- /dev/null +++ b/src/inprogress/tafdocument.h @@ -0,0 +1,22 @@ +#ifndef BU_TAF_DOCUMENT_H +#define BU_TAF_DOCUMENT_H + +#include + +namespace Bu +{ + /** + * + */ + class TafDocument + { + public: + TafDocument(); + virtual ~TafDocument(); + + private: + + }; +} + +#endif diff --git a/src/inprogress/tafnode.cpp b/src/inprogress/tafnode.cpp new file mode 100644 index 0000000..c9756ec --- /dev/null +++ b/src/inprogress/tafnode.cpp @@ -0,0 +1,9 @@ +#include "tafnode.h" + +Bu::TafNode::TafNode() +{ +} + +Bu::TafNode::~TafNode() +{ +} diff --git a/src/inprogress/tafnode.h b/src/inprogress/tafnode.h new file mode 100644 index 0000000..34f5289 --- /dev/null +++ b/src/inprogress/tafnode.h @@ -0,0 +1,21 @@ +#ifndef BU_TAF_NODE_H +#define BU_TAF_NODE_H + +#include + +namespace Bu +{ + /** + * + */ + class TafNode + { + public: + TafNode(); + virtual ~TafNode(); + + private: + + }; +} +#endif diff --git a/src/inprogress/tafreader.cpp b/src/inprogress/tafreader.cpp new file mode 100644 index 0000000..f94fe44 --- /dev/null +++ b/src/inprogress/tafreader.cpp @@ -0,0 +1,11 @@ +#include "tafreader.h" + +Bu::TafReader::TafReader( Bu::Stream &sIn ) : + sIn( sIn ) +{ +} + +Bu::TafReader::~TafReader() +{ +} + diff --git a/src/inprogress/tafreader.h b/src/inprogress/tafreader.h new file mode 100644 index 0000000..2dbb9ea --- /dev/null +++ b/src/inprogress/tafreader.h @@ -0,0 +1,25 @@ +#ifndef BU_TAF_READER_H +#define BU_TAF_READER_H + +#include +#include "bu/tafdocument.h" +#include "bu/stream.h" + +namespace Bu +{ + /** + * + */ + class TafReader : public Bu::TafDocument + { + public: + TafReader( Bu::Stream &sIn ); + virtual ~TafReader(); + + private: + Stream &sIn; + + }; +} + +#endif diff --git a/src/inprogress/tafwriter.cpp b/src/inprogress/tafwriter.cpp new file mode 100644 index 0000000..3e6c025 --- /dev/null +++ b/src/inprogress/tafwriter.cpp @@ -0,0 +1,9 @@ +#include "tafwriter.h" + +Bu::TafWriter::TafWriter() +{ +} + +Bu::TafWriter::~TafWriter() +{ +} diff --git a/src/inprogress/tafwriter.h b/src/inprogress/tafwriter.h new file mode 100644 index 0000000..7057d62 --- /dev/null +++ b/src/inprogress/tafwriter.h @@ -0,0 +1,22 @@ +#ifndef BU_TAF_WRITER_H +#define BU_TAF_WRITER_H + +#include + +namespace Bu +{ + /** + * + */ + class TafWriter + { + public: + TafWriter(); + virtual ~TafWriter(); + + private: + + }; +} + +#endif diff --git a/src/inprogress/xmldocument.cpp b/src/inprogress/xmldocument.cpp new file mode 100644 index 0000000..cb21826 --- /dev/null +++ b/src/inprogress/xmldocument.cpp @@ -0,0 +1,9 @@ +#include "xmldocument.h" + +Bu::XmlDocument::XmlDocument() +{ +} + +Bu::XmlDocument::~XmlDocument() +{ +} diff --git a/src/inprogress/xmldocument.h b/src/inprogress/xmldocument.h new file mode 100644 index 0000000..e16e3ea --- /dev/null +++ b/src/inprogress/xmldocument.h @@ -0,0 +1,22 @@ +#ifndef XML_DOCUMENT_H +#define XML_DOCUMENT_H + +#include + +namespace Bu +{ + /** + * + */ + class XmlDocument + { + public: + XmlDocument(); + virtual ~XmlDocument(); + + private: + + }; +} + +#endif diff --git a/src/inprogress/xmlnode.cpp b/src/inprogress/xmlnode.cpp new file mode 100644 index 0000000..58ef5c5 --- /dev/null +++ b/src/inprogress/xmlnode.cpp @@ -0,0 +1,9 @@ +#include "xmlnode.h" + +Bu::XmlNode::XmlNode() +{ +} + +Bu::XmlNode::~XmlNode() +{ +} diff --git a/src/inprogress/xmlnode.h b/src/inprogress/xmlnode.h new file mode 100644 index 0000000..cd9961a --- /dev/null +++ b/src/inprogress/xmlnode.h @@ -0,0 +1,22 @@ +#ifndef XML_NODE_H +#define XML_NODE_H + +#include + +namespace Bu +{ + /** + * + */ + class XmlNode + { + public: + XmlNode(); + virtual ~XmlNode(); + + private: + + }; +} + +#endif diff --git a/src/inprogress/xmlreader.cpp b/src/inprogress/xmlreader.cpp new file mode 100644 index 0000000..bd241cf --- /dev/null +++ b/src/inprogress/xmlreader.cpp @@ -0,0 +1,267 @@ +#include "xmlreader.h" + +Bu::XmlReader::XmlReader( Bu::Stream &sIn ) : + sIn( sIn ) +{ +} + +Bu::XmlReader::~XmlReader() +{ +} + +const char *Bu::XmlReader::lookahead( int nAmnt ) +{ + if( sBuf.getSize() >= nAmnt ) + return sBuf.getStr(); + + int nNew = nAmnt - sBuf.getSize(); + char *buf = new char[nNew]; + sIn.read( buf, nNew ); + sBuf.append( buf ); + + return sBuf.getStr(); +} + +void Bu::XmlReader::burn( int nAmnt ) +{ + if( sBuf.getSize() < nAmnt ) + { + lookahead( nAmnt ); + } + + //sBuf.remove( nAmnt ); +} + +void Bu::XmlReader::checkString( const char *str, int nLen ) +{ + if( !strncmp( str, lookahead( nLen ), nLen ) ) + { + burn( nLen ); + return; + } + + throw Bu::ExceptionBase("Expected string '%s'", str ); +} + +Bu::XmlNode *Bu::XmlReader::read() +{ + prolog(); +} + +void Bu::XmlReader::prolog() +{ + XMLDecl(); + Misc(); +} + +void Bu::XmlReader::XMLDecl() +{ + checkString("", 2 ); +} + +void Bu::XmlReader::Misc() +{ + for(;;) + { + S(); + if( !strncmp("", 3 ); + return; + } + } + burn( 1 ); + } +} + +void Bu::XmlReader::PI() +{ + checkString("", lookahead(j+2)+j, 2 ) ) + { + burn( j+2 ); + return; + } + } +} + +void Bu::XmlReader::S() +{ + for( int j = 0;; j++ ) + { + char c = *lookahead( 1 ); + if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) + continue; + if( j == 0 ) + throw ExceptionBase("Expected whitespace."); + return; + } +} + +void Bu::XmlReader::Sq() +{ + for(;;) + { + char c = *lookahead( 1 ); + if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) + continue; + return; + } +} + +void Bu::XmlReader::VersionInfo() +{ + try + { + S(); + checkString("version", 7 ); + } + catch( ExceptionBase &e ) + { + return; + } + Eq(); + Bu::FString ver = AttValue(); + if( ver != "1.1" ) + throw ExceptionBase("Currently we only support xml version 1.1\n"); +} + +void Bu::XmlReader::Eq() +{ + Sq(); + checkString("=", 1 ); + Sq(); +} + +void Bu::XmlReader::EncodingDecl() +{ + S(); + try + { + checkString("encoding", 8 ); + } + catch( ExceptionBase &e ) + { + return; + } + + Eq(); + AttValue(); +} + +void Bu::XmlReader::SDDecl() +{ + S(); + try + { + checkString("standalone", 10 ); + } + catch( ExceptionBase &e ) + { + return; + } + + Eq(); + AttValue(); +} + +Bu::FString Bu::XmlReader::AttValue() +{ + char q = *lookahead(1); + if( q == '\"' ) + { + for( int j = 2;; j++ ) + { + if( lookahead(j)[j-1] == '\"' ) + { + Bu::FString ret( lookahead(j)+1, j-2 ); + burn( j ); + return ret; + } + } + } + else if( q == '\'' ) + { + for( int j = 2;; j++ ) + { + if( lookahead(j)[j-1] == '\'' ) + { + Bu::FString ret( lookahead(j)+1, j-2 ); + burn( j ); + return ret; + } + } + } + + throw ExceptionBase("Excpected either \' or \".\n"); +} + +Bu::FString Bu::XmlReader::Name() +{ + unsigned char c = *lookahead( 1 ); + if( c != ':' && c != '_' && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z') && + (c < 0xC0 || c > 0xD6 ) && + (c < 0xD8 || c > 0xF6 ) && + (c < 0xF8)) + { + throw ExceptionBase("Invalid entity name starting character."); + } + + for( int j = 1;; j++ ) + { + unsigned char c = lookahead(j+1)[j]; + if( isS( c ) ) + { + FString ret( lookahead(j+1), j+1 ); + burn( j+1 ); + return ret; + } + if( c != ':' && c != '_' && c != '-' && c != '.' && c != 0xB7 && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z') && + (c < '0' || c > '9') && + (c < 0xC0 || c > 0xD6 ) && + (c < 0xD8 || c > 0xF6 ) && + (c < 0xF8)) + { + throw ExceptionBase("Invalid character in name."); + } + } +} + diff --git a/src/inprogress/xmlreader.h b/src/inprogress/xmlreader.h new file mode 100644 index 0000000..708a386 --- /dev/null +++ b/src/inprogress/xmlreader.h @@ -0,0 +1,121 @@ +#ifndef XML_READER_H +#define XML_READER_H + +#include +#include "bu/stream.h" +#include "bu/fstring.h" +#include "bu/xmlnode.h" + +namespace Bu +{ + /** + * An Xml 1.1 reader. I've decided to write this, this time, based on the + * official W3C reccomendation, now included with the source code. I've + * named the productions in the parser states the same as in that document, + * which may make them easier to find, etc, although possibly slightly less + * optimized than writing my own reduced grammer. + * + * Below I will list differences between my parser and the official standard + * as I come up with them. + * - Encoding and Standalone headings are ignored for the moment. (4.3.3, + * 2.9) + * - The standalone heading attribute can have any standard whitespace + * before it (the specs say only spaces, no newlines). (2.9) + * - Since standalone is ignored, it is currently allowed to have any + * value (should be restricted to "yes" or "no"). (2.9) + * - Currently only UTF-8 / ascii are parsed. + * - [optional] The content of comments is thrown away. (2.5) + * - The content of processing instruction blocks is parsed properly, but + * thrown away. (2.6) + */ + class XmlReader + { + public: + XmlReader( Bu::Stream &sIn ); + virtual ~XmlReader(); + + XmlNode *read(); + + private: + Bu::Stream &sIn; + Bu::FString sBuf; + + private: // Helpers + const char *lookahead( int nAmnt ); + void burn( int nAmnt ); + void checkString( const char *str, int nLen ); + + private: // States + /** + * The headers, etc. + */ + void prolog(); + + /** + * The xml decleration (version, encoding, etc). + */ + void XMLDecl(); + + /** + * Misc things, Includes Comments and PIData (Processing Instructions). + */ + void Misc(); + + /** + * Comments + */ + void Comment(); + + /** + * Processing Instructions + */ + void PI(); + + /** + * Whitespace eater. + */ + void S(); + + /** + * Optional whitespace eater. + */ + void Sq(); + + /** + * XML Version spec + */ + void VersionInfo(); + + /** + * Your basic equals sign with surrounding whitespace. + */ + void Eq(); + + /** + * Read in an attribute value. + */ + FString AttValue(); + + /** + * Read in the name of something. + */ + FString Name(); + + /** + * Encoding decleration in the header + */ + void EncodingDecl(); + + /** + * Standalone decleration in the header + */ + void SDDecl(); + + bool isS( unsigned char c ) + { + return ( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ); + } + }; +} + +#endif diff --git a/src/inprogress/xmlwriter.cpp b/src/inprogress/xmlwriter.cpp new file mode 100644 index 0000000..23a5175 --- /dev/null +++ b/src/inprogress/xmlwriter.cpp @@ -0,0 +1,9 @@ +#include "xmlwriter.h" + +Bu::XmlWriter::XmlWriter() +{ +} + +Bu::XmlWriter::~XmlWriter() +{ +} diff --git a/src/inprogress/xmlwriter.h b/src/inprogress/xmlwriter.h new file mode 100644 index 0000000..796d6fb --- /dev/null +++ b/src/inprogress/xmlwriter.h @@ -0,0 +1,22 @@ +#ifndef XML_WRITER_H +#define XML_WRITER_H + +#include + +namespace Bu +{ + /** + * + */ + class XmlWriter + { + public: + XmlWriter(); + virtual ~XmlWriter(); + + private: + + }; +} + +#endif diff --git a/src/old/xmldocument.cpp b/src/old/xmldocument.cpp deleted file mode 100644 index d7867d5..0000000 --- a/src/old/xmldocument.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include "xmlwriter.h" - -XmlDocument::XmlDocument( XmlNode *pRoot ) -{ - this->pRoot = pRoot; - pCurrent = NULL; - bCompleted = (pRoot!=NULL); -} - -XmlDocument::~XmlDocument() -{ - if( pRoot ) - { - delete pRoot; - } -} - -void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) -{ - if( pRoot == NULL ) - { - // This is the first node, so ignore position and just insert it. - pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); - } - else - { - pCurrent = pCurrent->addChild( sName, sContent ); - } - - if( bClose ) - { - closeNode(); - } -} - -void XmlDocument::setName( const char *sName ) -{ - pCurrent->setName( sName ); -} - -bool XmlDocument::isCompleted() -{ - return bCompleted; -} - -XmlNode *XmlDocument::getRoot() -{ - return pRoot; -} - -XmlNode *XmlDocument::detatchRoot() -{ - XmlNode *pTemp = pRoot; - pRoot = NULL; - return pTemp; -} - -XmlNode *XmlDocument::getCurrent() -{ - return pCurrent; -} - -void XmlDocument::closeNode() -{ - if( pCurrent != NULL ) - { - pCurrent = pCurrent->getParent(); - - if( pCurrent == NULL ) - { - bCompleted = true; - } - } -} - -void XmlDocument::addProperty( const char *sName, const char *sValue ) -{ - if( pCurrent ) - { - pCurrent->addProperty( sName, sValue ); - } -} - -void XmlDocument::addProperty( const char *sName, const unsigned char nValue ) -{ - char buf[12]; - sprintf( buf, "%hhi", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const char nValue ) -{ - char buf[12]; - sprintf( buf, "%hhi", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const unsigned short nValue ) -{ - char buf[12]; - sprintf( buf, "%hi", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const short nValue ) -{ - char buf[12]; - sprintf( buf, "%hi", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const int nValue ) -{ - char buf[12]; - sprintf( buf, "%d", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const unsigned long nValue ) -{ - char buf[12]; - sprintf( buf, "%li", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const long nValue ) -{ - char buf[12]; - sprintf( buf, "%li", nValue ); - addProperty( sName, buf ); -} - -void XmlDocument::addProperty( const char *sName, const double dValue ) -{ - char buf[40]; - sprintf( buf, "%f", dValue ); - addProperty( sName, buf ); -} - -void XmlDocument::setContent( const char *sContent ) -{ - if( pCurrent ) - { - pCurrent->setContent( sContent ); - } -} - diff --git a/src/old/xmldocument.h b/src/old/xmldocument.h deleted file mode 100644 index 6671c41..0000000 --- a/src/old/xmldocument.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef XMLDOCUMENT -#define XMLDOCUMENT - -#include "xmlnode.h" - -/** - * Keeps track of an easily managed set of XmlNode information. Allows simple - * operations for logical writing to and reading from XML structures. Using - * already formed structures is simply done through the XmlNode structures, - * and the getRoot function here. Creation is performed through a simple set - * of operations that creates the data in a stream type format. - *@author Mike Buland - */ -class XmlDocument -{ -public: - /** - * Construct either a blank XmlDocuemnt or construct a document around an - * existing XmlNode. Be careful, once an XmlNode is passed into a document - * the document takes over ownership and will delete it when the XmlDocument - * is deleted. - *@param pRoot The XmlNode to use as the root of this document, or NULL if - * you want to start a new document. - */ - XmlDocument( XmlNode *pRoot=NULL ); - - /** - * Destroy all contained nodes. - */ - virtual ~XmlDocument(); - - /** - * Add a new node to the document. The new node is appended to the end of - * the current context, i.e. XmlNode, and the new node, provided it isn't - * close as part of this operation, will become the current context. - *@param sName The name of the new node to add. - *@param sContent A content string to be placed inside of the new node. - *@param bClose Set this to true to close the node immediately after adding - * the node and setting the content and name. If this is set to true the - * node is appended, but the context node doesn't change. - */ - void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); - - /** - * Set the name of the current node context. - *@param sName The new name of the node. - */ - void setName( const char *sName ); - - /** - * Close the current node context. This will move the current context to - * the parent node of the former current node. If the current node was the - * root then the "completed" flag is set and no more operations are allowed. - */ - void closeNode(); - - /** - * Change the content of the current node at the current position between - * nodes. - *@param sContent The new content of the current node. - */ - void setContent( const char *sContent ); - - /** - * Add a named property to the current context node. - *@param sName The name of the property to add. - *@param sValue The string value of the property. - */ - void addProperty( const char *sName, const char *sValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const unsigned char nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const char nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const unsigned short nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const short nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const unsigned long nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const long nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param nValue The numerical value to add. - */ - void addProperty( const char *sName, const int nValue ); - - /** - * Add a named property to the current context node, converting the - * numerical parameter to text using standrd printf style conversion. - *@param sName The name of the property to add. - *@param dValue The numerical value to add. - */ - void addProperty( const char *sName, const double dValue ); - - /** - * The XmlDocuemnt is considered completed if the root node has been closed. - * Once an XmlDocument has been completed, you can no longer perform - * operations on it. - *@return True if completed, false if still in progress. - */ - bool isCompleted(); - - /** - * Get a pointer to the root object of this XmlDocument. - *@returns A pointer to an internally owned XmlNode. Do not delete this - * XmlNode. - */ - XmlNode *getRoot(); - - /** - * Get a pointer to the root object of this XmlDocument, and remove the - * ownership from this object. - *@returns A pointer to an internally owned XmlNode. Do not delete this - * XmlNode. - */ - XmlNode *detatchRoot(); - - /** - * Get the current context node, which could be the same as the root node. - *@returns A pointer to an internally owned XmlNode. Do not delete this - * XmlNode. - */ - XmlNode *getCurrent(); - -private: - XmlNode *pRoot; /**< The root node. */ - XmlNode *pCurrent; /**< The current node. */ - bool bCompleted; /**< Is it completed? */ -}; - -#endif diff --git a/src/old/xmlnode.cpp b/src/old/xmlnode.cpp deleted file mode 100644 index b1ed9a9..0000000 --- a/src/old/xmlnode.cpp +++ /dev/null @@ -1,445 +0,0 @@ -#include "xmlnode.h" -#include "hashfunctionstring.h" - -XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : - hProperties( new HashFunctionString(), 53, false ), - hChildren( new HashFunctionString(), 53, true ) -{ - this->pParent = pParent; - if( sName != NULL ) - { - setName( sName ); - } - if( sContent != NULL ) - { - this->sPreContent = new std::string( sContent ); - } - else - { - this->sPreContent = NULL; - } - nCurContent = 0; -} - -XmlNode::~XmlNode() -{ - for( int j = 0; j < lChildren.getSize(); j++ ) - { - delete (XmlNode *)lChildren[j]; - } - for( int j = 0; j < lPropNames.getSize(); j++ ) - { - delete (std::string *)lPropNames[j]; - } - for( int j = 0; j < lPropValues.getSize(); j++ ) - { - delete (std::string *)lPropValues[j]; - } - for( int j = 0; j < lPostContent.getSize(); j++ ) - { - if( lPostContent[j] != NULL ) - { - delete (std::string *)lPostContent[j]; - } - } - if( sPreContent ) - { - delete sPreContent; - } -} - -void XmlNode::setName( const char *sName ) -{ - if( pParent ) - { - if( this->sName.size() == 0 ) - { - // We're not in the hash yet, so add us - this->sName = sName; - pParent->hChildren.insert( this->sName.c_str(), this ); - } - else - { - // Slightly more tricky, delete us, then add us... - pParent->hChildren.del( this->sName.c_str() ); - this->sName = sName; - pParent->hChildren.insert( this->sName.c_str(), this ); - } - } - else - { - // If we have no parent, then just set the name string, we don't need - // to worry about hashing. - this->sName = sName; - } -} - -void XmlNode::setContent( const char *sContent, int nIndex ) -{ - if( nIndex == -1 ) - { - nIndex = nCurContent; - } - if( nIndex == 0 ) - { - if( this->sPreContent ) - { - delete this->sPreContent; - } - - this->sPreContent = new std::string( sContent ); - } - else - { - nIndex--; - if( lPostContent[nIndex] ) - { - delete (std::string *)lPostContent[nIndex]; - } - - lPostContent.setAt( nIndex, new std::string( sContent ) ); - } -} - -const char *XmlNode::getContent( int nIndex ) -{ - if( nIndex == 0 ) - { - if( sPreContent ) - { - return sPreContent->c_str(); - } - } - else - { - nIndex--; - if( lPostContent[nIndex] ) - { - return ((std::string *)lPostContent[nIndex])->c_str(); - } - } - - return NULL; -} - -XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) -{ - return addChild( new XmlNode( sName, this, sContent ) ); -} - -XmlNode *XmlNode::addChild( XmlNode *pNode ) -{ - lChildren.append( pNode ); - lPostContent.append( NULL ); - nCurContent++; - pNode->pParent = this; - - return pNode; -} - -XmlNode *XmlNode::getParent() -{ - return pParent; -} - -void XmlNode::addProperty( const char *sName, const char *sValue ) -{ - std::string *pName = new std::string( sName ); - std::string *pValue = new std::string( sValue ); - - hProperties.insert( pName->c_str(), pValue->c_str() ); - lPropNames.append( pName ); - lPropValues.append( pValue ); -} - -int XmlNode::getNumProperties() -{ - return lPropNames.getSize(); -} - -const char *XmlNode::getPropertyName( int nIndex ) -{ - std::string *tmp = ((std::string *)lPropNames[nIndex]); - if( tmp == NULL ) - return NULL; - return tmp->c_str(); -} - -const char *XmlNode::getProperty( int nIndex ) -{ - std::string *tmp = ((std::string *)lPropValues[nIndex]); - if( tmp == NULL ) - return NULL; - return tmp->c_str(); -} - -const char *XmlNode::getProperty( const char *sName ) -{ - const char *tmp = (const char *)hProperties[sName]; - if( tmp == NULL ) - return NULL; - return tmp; -} - -void XmlNode::deleteProperty( int nIndex ) -{ - hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); - - delete (std::string *)lPropNames[nIndex]; - delete (std::string *)lPropValues[nIndex]; - - lPropNames.deleteAt( nIndex ); - lPropValues.deleteAt( nIndex ); -} - -bool XmlNode::hasChildren() -{ - return lChildren.getSize()>0; -} - -int XmlNode::getNumChildren() -{ - return lChildren.getSize(); -} - -XmlNode *XmlNode::getChild( int nIndex ) -{ - return (XmlNode *)lChildren[nIndex]; -} - -XmlNode *XmlNode::getChild( const char *sName, int nSkip ) -{ - return (XmlNode *)hChildren.get( sName, nSkip ); -} - -const char *XmlNode::getName() -{ - return sName.c_str(); -} - -void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) -{ - XmlNode *xRet = detatchNode( nIndex, sReplacementText ); - - if( xRet != NULL ) - { - delete xRet; - } -} - -XmlNode *XmlNode::detatchNode( int nIndex, const char *sReplacementText ) -{ - if( nIndex < 0 || nIndex >= lChildren.getSize() ) - return NULL; - - // The real trick when deleteing a node isn't actually deleting it, it's - // reforming the content around the node that's now missing...hmmm... - - if( nIndex == 0 ) - { - // If the index is zero we have to deal with the pre-content - if( sReplacementText ) - { - if( sPreContent == NULL ) - { - sPreContent = new std::string( sReplacementText ); - } - else - { - *sPreContent += sReplacementText; - } - } - if( lPostContent.getSize() > 0 ) - { - if( lPostContent[0] != NULL ) - { - if( sPreContent == NULL ) - { - sPreContent = new std::string( - ((std::string *)lPostContent[0])->c_str() - ); - } - else - { - *sPreContent += - ((std::string *)lPostContent[0])->c_str(); - } - } - delete (std::string *)lPostContent[0]; - lPostContent.deleteAt( 0 ); - } - } - else - { - int nCont = nIndex-1; - // If it's above zero we deal with the post-content only - if( sReplacementText ) - { - if( lPostContent[nCont] == NULL ) - { - lPostContent.setAt( nCont, new std::string( sReplacementText ) ); - } - else - { - *((std::string *)lPostContent[nCont]) += sReplacementText; - } - } - if( lPostContent.getSize() > nIndex ) - { - if( lPostContent[nIndex] != NULL ) - { - if( lPostContent[nCont] == NULL ) - { - lPostContent.setAt( nCont, new std::string( - ((std::string *)lPostContent[nIndex])->c_str() - ) ); - } - else - { - *((std::string *)lPostContent[nCont]) += - ((std::string *)lPostContent[nIndex])->c_str(); - } - } - delete (std::string *)lPostContent[nIndex]; - lPostContent.deleteAt( nIndex ); - } - } - - XmlNode *xRet = (XmlNode *)lChildren[nIndex]; - hChildren.del( ((XmlNode *)lChildren[nIndex])->getName() ); - lChildren.deleteAt( nIndex ); - - return xRet; -} - -void XmlNode::replaceNode( int nIndex, XmlNode *pNewNode ) -{ - if( nIndex < 0 || nIndex >= lChildren.getSize() ) - return; //TODO: throw an exception - - delete (XmlNode *)lChildren[nIndex]; - lChildren.setAt( nIndex, pNewNode ); - pNewNode->pParent = this; -} - -XmlNode *XmlNode::getCopy() -{ - XmlNode *pNew = new XmlNode(); - - pNew->sName = sName; - if( sPreContent ) - { - pNew->sPreContent = new std::string( sPreContent->c_str() ); - } - else - { - pNew->sPreContent = NULL; - } - pNew->nCurContent = 0; - - int nSize = lPostContent.getSize(); - pNew->lPostContent.setSize( nSize ); - for( int j = 0; j < nSize; j++ ) - { - if( lPostContent[j] ) - { - pNew->lPostContent.setAt( - j, new std::string( - ((std::string *)lPostContent[j])->c_str() - ) - ); - } - else - { - pNew->lPostContent.setAt( j, NULL ); - } - } - - nSize = lChildren.getSize(); - pNew->lChildren.setSize( nSize ); - for( int j = 0; j < nSize; j++ ) - { - XmlNode *pChild = ((XmlNode *)lChildren[j])->getCopy(); - pNew->lChildren.setAt( j, pChild ); - pChild->pParent = pNew; - pNew->hChildren.insert( pChild->getName(), pChild ); - } - - nSize = lPropNames.getSize(); - pNew->lPropNames.setSize( nSize ); - pNew->lPropValues.setSize( nSize ); - for( int j = 0; j < nSize; j++ ) - { - std::string *pProp = new std::string( ((std::string *)lPropNames[j])->c_str() ); - std::string *pVal = new std::string( ((std::string *)lPropValues[j])->c_str() ); - pNew->lPropNames.setAt( j, pProp ); - pNew->lPropValues.setAt( j, pVal ); - pNew->hProperties.insert( pProp->c_str(), pVal->c_str() ); - pNew->nCurContent++; - } - - return pNew; -} - -void XmlNode::deleteNodeKeepChildren( int nIndex ) -{ - // This is a tricky one...we need to do some patching to keep things all - // even... - XmlNode *xRet = (XmlNode *)lChildren[nIndex]; - - if( xRet == NULL ) - { - return; - } - else - { - if( getContent( nIndex ) ) - { - std::string sBuf( getContent( nIndex ) ); - sBuf += xRet->getContent( 0 ); - setContent( sBuf.c_str(), nIndex ); - } - else - { - setContent( xRet->getContent( 0 ), nIndex ); - } - - int nSize = xRet->lChildren.getSize(); - for( int j = 0; j < nSize; j++ ) - { - XmlNode *pCopy = ((XmlNode *)xRet->lChildren[j])->getCopy(); - pCopy->pParent = this; - lChildren.insertBefore( pCopy, nIndex+j ); - - if( xRet->lPostContent[j] ) - { - lPostContent.insertBefore( - new std::string( ((std::string *)xRet->lPostContent[j])->c_str() ), - nIndex+j - ); - } - else - { - lPostContent.insertBefore( NULL, nIndex+j ); - } - } - - if( getContent( nIndex+nSize ) ) - { - //SString sBuf( getContent( nIndex+nSize ) ); - //sBuf.catfrom( xRet->getContent( nSize ) ); - //setContent( sBuf, nIndex+nSize ); - } - else - { - setContent( xRet->getContent( nSize ), nIndex+nSize ); - } - - deleteNode( nIndex+nSize ); - } -} - -void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) -{ -} - diff --git a/src/old/xmlnode.h b/src/old/xmlnode.h deleted file mode 100644 index 7525306..0000000 --- a/src/old/xmlnode.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef XMLNODE -#define XMLNODE - -#include -#include "linkedlist.h" -#include "hashtable.h" - -/** - * Maintains all data pertient to an XML node, including sub-nodes and content. - * All child nodes can be accessed through index and through name via a hash - * table. This makes it very easy to gain simple and fast access to all of - * your data. For most applications, the memory footprint is also rather - * small. While XmlNode objects can be used directly to create XML structures - * it is highly reccomended that all operations be performed through the - * XmlDocument class. - *@author Mike Buland - */ -class XmlNode -{ -public: - /** - * Construct a new XmlNode. - *@param sName The name of the node. - *@param pParent The parent node. - *@param sContent The initial content string. - */ - XmlNode( - const char *sName=NULL, - XmlNode *pParent = NULL, - const char *sContent=NULL - ); - - /** - * Delete the node and cleanup all memory. - */ - virtual ~XmlNode(); - - /** - * Change the name of the node. - *@param sName The new name of the node. - */ - void setName( const char *sName ); - - /** - * Construct a new node and add it as a child to this node, also return a - * pointer to the newly constructed node. - *@param sName The name of the new node. - *@param sContent The initial content of the new node. - *@returns A pointer to the newly created child node. - */ - XmlNode *addChild( const char *sName, const char *sContent=NULL ); - - /** - * Add an already created XmlNode as a child to this node. The new child - * XmlNode's parent will be changed appropriately and the parent XmlNode - * will take ownership of the child. - *@param pChild The child XmlNode to add to this XmlNode. - *@returns A pointer to the child node that was just added. - */ - XmlNode *addChild( XmlNode *pChild ); - - /** - * Add a new property to the XmlNode. Properties are name/value pairs. - *@param sName The name of the property. Specifying a name that's already - * in use will overwrite that property. - *@param sValue The textual value of the property. - */ - void addProperty( const char *sName, const char *sValue ); - - /** - * Get a pointer to the parent node, if any. - *@returns A pointer to the node's parent, or NULL if there isn't one. - */ - XmlNode *getParent(); - - /** - * Tells you if this node has children. - *@returns True if this node has at least one child, false otherwise. - */ - bool hasChildren(); - - /** - * Tells you how many children this node has. - *@returns The number of children this node has. - */ - int getNumChildren(); - - /** - * Get a child node at a specific index. - *@param nIndex The zero-based index of the child to retreive. - *@returns A pointer to the child, or NULL if you requested an invalid - * index. - */ - XmlNode *getChild( int nIndex ); - - /** - * Get a child with the specified name, and possibly skip value. For an - * explination of skip values see the HashTable. - *@param sName The name of the child to find. - *@param nSkip The number of nodes with that name to skip. - *@returns A pointer to the child, or NULL if no child with that name was - * found. - */ - XmlNode *getChild( const char *sName, int nSkip=0 ); - - /** - * Get a pointer to the name of this node. Do not change this, use setName - * instead. - *@returns A pointer to the name of this node. - */ - const char *getName(); - - /** - * Set the content of this node, optionally at a specific index. Using the - * default of -1 will set the content after the last added node. - *@param sContent The content string to use. - *@param nIndex The index of the content. - */ - void setContent( const char *sContent, int nIndex=-1 ); - - /** - * Get the content string at a given index, or zero for initial content. - *@param nIndex The index of the content. - *@returns A pointer to the content at that location. - */ - const char *getContent( int nIndex = 0 ); - - /** - * Get the number of properties in this node. - *@returns The number of properties in this node. - */ - int getNumProperties(); - - /** - * Get a property's name by index. - *@param nIndex The index of the property to examine. - *@returns A pointer to the name of the property specified, or NULL if none - * found. - */ - const char *getPropertyName( int nIndex ); - - /** - * Get a proprty's value by index. - *@param nIndex The index of the property to examine. - *@returns A pointer to the value of the property specified, or NULL if none - * found. - */ - const char *getProperty( int nIndex ); - - /** - * Get a propery's value by name. - *@param sName The name of the property to examine. - *@returns A pointer to the value of the property specified, or NULL if none - * found. - */ - const char *getProperty( const char *sName ); - - /** - * Delete a property by index. - *@param nIndex The index of the property to delete. - *@returns True if the property was found and deleted, false if it wasn't - * found. - */ - void deleteProperty( int nIndex ); - - /** - * Delete a child node, possibly replacing it with some text. This actually - * fixes all content strings around the newly deleted child node. - *@param nIndex The index of the node to delete. - *@param sReplacementText The optional text to replace the node with. - *@returns True of the node was found, and deleted, false if it wasn't - * found. - */ - void deleteNode( int nIndex, const char *sReplacementText = NULL ); - - /** - * Delete a given node, but move all of it's children and content up to - * replace the deleted node. All of the content of the child node is - * spliced seamlessly into place with the parent node's content. - *@param nIndex The node to delete. - *@returns True if the node was found and deleted, false if it wasn't. - */ - void deleteNodeKeepChildren( int nIndex ); - - /** - * Detatch a given child node from this node. This effectively works just - * like a deleteNode, except that instead of deleting the node it is removed - * and returned, and all ownership is given up. - *@param nIndex The index of the node to detatch. - *@param sReplacementText The optional text to replace the detatched node - * with. - *@returns A pointer to the newly detatched node, which then passes - * ownership to the caller. - */ - XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); - - /** - * Replace a given node with a different node that is not currently owned by - * this XmlNode or any ancestor. - *@param nIndex The index of the node to replace. - *@param pNewNode The new node to replace the old node with. - *@returns True if the node was found and replaced, false if it wasn't. - */ - void replaceNode( int nIndex, XmlNode *pNewNode ); - - /** - * Replace a given node with the children and content of a given node. - *@param nIndex The index of the node to replace. - *@param pNewNode The node that contains the children and content that will - * replace the node specified by nIndex. - *@returns True if the node was found and replaced, false if it wasn't. - */ - void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); - - /** - * Get a copy of this node and all children. getCopy is recursive, so - * beware copying large trees of xml. - *@returns A newly created copy of this node and all of it's children. - */ - XmlNode *getCopy(); - -private: - std::string sName; /**< The name of the node. */ - std::string *sPreContent; /**< The content that goes before any node. */ - LinkedList lChildren; /**< The children. */ - LinkedList lPostContent; /**< The content that comes after children. */ - HashTable hProperties; /**< Property hashtable. */ - HashTable hChildren; /**< Children hashtable. */ - LinkedList lPropNames; /**< List of property names. */ - LinkedList lPropValues; /**< List of property values. */ - XmlNode *pParent; /**< A pointer to the parent of this node. */ - int nCurContent; /**< The current content we're on, for using the -1 on - setContent. */ -}; - -#endif diff --git a/src/old/xmlreader.cpp b/src/old/xmlreader.cpp deleted file mode 100644 index 18df69c..0000000 --- a/src/old/xmlreader.cpp +++ /dev/null @@ -1,602 +0,0 @@ -#include "xmlreader.h" -#include "exceptions.h" -#include -#include "hashfunctionstring.h" - -XmlReader::XmlReader( bool bStrip ) : - bStrip( bStrip ), - htEntity( new HashFunctionString(), 11 ) -{ -} - -XmlReader::~XmlReader() -{ - void *i = htEntity.getFirstItemPos(); - while( (i = htEntity.getNextItemPos( i ) ) ) - { - free( (char *)(htEntity.getItemID( i )) ); - delete (StaticString *)htEntity.getItemData( i ); - } -} - -void XmlReader::addEntity( const char *name, const char *value ) -{ - if( htEntity[name] ) return; - - char *sName = strdup( name ); - StaticString *sValue = new StaticString( value ); - - htEntity.insert( sName, sValue ); -} - -#define gcall( x ) if( x == false ) return false; - -bool XmlReader::isws( char chr ) -{ - return ( chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r' ); -} - -bool XmlReader::ws() -{ - while( true ) - { - char chr = getChar(); - if( isws( chr ) ) - { - usedChar(); - } - else - { - return true; - } - } - return true; -} - -bool XmlReader::buildDoc() -{ - // take care of initial whitespace - gcall( ws() ); - textDecl(); - entity(); - addEntity("gt", ">"); - addEntity("lt", "<"); - addEntity("amp", "&"); - addEntity("apos", "\'"); - addEntity("quot", "\""); - gcall( node() ); - - return true; -} - -void XmlReader::textDecl() -{ - if( getChar() == '<' && getChar( 1 ) == '?' ) - { - usedChar( 2 ); - for(;;) - { - if( getChar() == '?' ) - { - if( getChar( 1 ) == '>' ) - { - usedChar( 2 ); - return; - } - } - usedChar(); - } - } -} - -void XmlReader::entity() -{ - for(;;) - { - ws(); - - if( getChar() == '<' && getChar( 1 ) == '!' ) - { - usedChar( 2 ); - ws(); - std::string buf; - for(;;) - { - char chr = getChar(); - usedChar(); - if( isws( chr ) ) break; - buf += chr; - } - - if( strcmp( buf.c_str(), "ENTITY") == 0 ) - { - ws(); - std::string name; - for(;;) - { - char chr = getChar(); - usedChar(); - if( isws( chr ) ) break; - name += chr; - } - ws(); - char quot = getChar(); - usedChar(); - if( quot != '\'' && quot != '\"' ) - { - throw XmlException( - "Only quoted entity values are supported." - ); - } - std::string value; - for(;;) - { - char chr = getChar(); - usedChar(); - if( chr == '&' ) - { - StaticString *tmp = getEscape(); - if( tmp == NULL ) throw XmlException("Entity thing"); - value += tmp->getString(); - delete tmp; - } - else if( chr == quot ) - { - break; - } - else - { - value += chr; - } - } - ws(); - if( getChar() == '>' ) - { - usedChar(); - - addEntity( name.c_str(), value.c_str() ); - } - else - { - throw XmlException( - "Malformed ENTITY: unexpected '%c' found.", - getChar() - ); - } - } - else - { - throw XmlException( - "Unsupported header symbol: %s", - buf.c_str() - ); - } - } - else - { - return; - } - } -} - -bool XmlReader::node() -{ - gcall( startNode() ) - - // At this point, we are closing the startNode - char chr = getChar(); - if( chr == '>' ) - { - usedChar(); - - // Now we process the guts of the node. - gcall( content() ); - } - else if( chr == '/' ) - { - // This is the tricky one, one more validation, then we close the node. - usedChar(); - if( getChar() == '>' ) - { - closeNode(); - usedChar(); - } - else - { - throw XmlException("Close node in singleNode malformed!"); - } - } - else - { - throw XmlException("Close node expected, but not found."); - return false; - } - - return true; -} - -bool XmlReader::startNode() -{ - if( getChar() == '<' ) - { - usedChar(); - - if( getChar() == '/' ) - { - // Heh, it's actually a close node, go figure - FlexBuf fbName; - usedChar(); - gcall( ws() ); - - while( true ) - { - char chr = getChar(); - if( isws( chr ) || chr == '>' ) - { - // Here we actually compare the name we got to the name - // we already set, they have to match exactly. - if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) - { - closeNode(); - break; - } - else - { - throw XmlException("Got a mismatched node close tag."); - } - } - else - { - fbName.appendData( chr ); - usedChar(); - } - } - - gcall( ws() ); - if( getChar() == '>' ) - { - // Everything is cool. - usedChar(); - } - else - { - throw XmlException("Got extra junk data instead of node close tag."); - } - } - else - { - // We're good, format is consistant - addNode(); - - // Skip extra whitespace - gcall( ws() ); - gcall( name() ); - gcall( ws() ); - gcall( paramlist() ); - gcall( ws() ); - } - } - else - { - throw XmlException("Expected to find node opening char, '<'."); - } - - return true; -} - -bool XmlReader::name() -{ - FlexBuf fbName; - - while( true ) - { - char chr = getChar(); - if( isws( chr ) || chr == '>' || chr == '/' ) - { - setName( fbName.getData() ); - return true; - } - else - { - fbName.appendData( chr ); - usedChar(); - } - } - - return true; -} - -bool XmlReader::paramlist() -{ - while( true ) - { - char chr = getChar(); - if( chr == '/' || chr == '>' ) - { - return true; - } - else - { - gcall( param() ); - gcall( ws() ); - } - } - - return true; -} - -StaticString *XmlReader::getEscape() -{ - if( getChar( 1 ) == '#' ) - { - // If the entity starts with a # it's a character escape code - int base = 10; - usedChar( 2 ); - if( getChar() == 'x' ) - { - base = 16; - usedChar(); - } - char buf[4]; - int j = 0; - for( j = 0; getChar() != ';'; j++ ) - { - buf[j] = getChar(); - usedChar(); - } - usedChar(); - buf[j] = '\0'; - buf[0] = (char)strtol( buf, (char **)NULL, base ); - buf[1] = '\0'; - - return new StaticString( buf ); - } - else - { - // ...otherwise replace with the appropriate string... - std::string buf; - usedChar(); - for(;;) - { - char cbuf = getChar(); - usedChar(); - if( cbuf == ';' ) break; - buf += cbuf; - } - - StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; - if( tmp == NULL ) return NULL; - - StaticString *ret = new StaticString( *tmp ); - return ret; - } -} - -bool XmlReader::param() -{ - FlexBuf fbName; - FlexBuf fbValue; - - while( true ) - { - char chr = getChar(); - if( isws( chr ) || chr == '=' ) - { - break; - } - else - { - fbName.appendData( chr ); - usedChar(); - } - } - - gcall( ws() ); - - if( getChar() == '=' ) - { - usedChar(); - - gcall( ws() ); - - char chr = getChar(); - if( chr == '"' ) - { - // Better quoted rhs - usedChar(); - - while( true ) - { - chr = getChar(); - if( chr == '"' ) - { - usedChar(); - addProperty( fbName.getData(), fbValue.getData() ); - return true; - } - else - { - if( chr == '&' ) - { - StaticString *tmp = getEscape(); - if( tmp == NULL ) return false; - fbValue.appendData( tmp->getString() ); - delete tmp; - } - else - { - fbValue.appendData( chr ); - usedChar(); - } - } - } - } - else - { - // Simple one-word rhs - while( true ) - { - chr = getChar(); - if( isws( chr ) || chr == '/' || chr == '>' ) - { - addProperty( fbName.getData(), fbValue.getData() ); - return true; - } - else - { - if( chr == '&' ) - { - StaticString *tmp = getEscape(); - if( tmp == NULL ) return false; - fbValue.appendData( tmp->getString() ); - delete tmp; - } - else - { - fbValue.appendData( chr ); - usedChar(); - } - } - } - } - } - else - { - throw XmlException("Expected an equals to seperate the params."); - return false; - } - - return true; -} - -bool XmlReader::content() -{ - FlexBuf fbContent; - - if( bStrip ) gcall( ws() ); - - while( true ) - { - char chr = getChar(); - if( chr == '<' ) - { - if( getChar(1) == '/' ) - { - if( fbContent.getLength() > 0 ) - { - if( bStrip ) - { - int j; - for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); - ((char *)fbContent.getData())[j+1] = '\0'; - } - setContent( fbContent.getData() ); - } - usedChar( 2 ); - gcall( ws() ); - FlexBuf fbName; - while( true ) - { - chr = getChar(); - if( isws( chr ) || chr == '>' ) - { - if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) - { - closeNode(); - break; - } - else - { - throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); - } - } - else - { - fbName.appendData( chr ); - usedChar(); - } - } - gcall( ws() ); - if( getChar() == '>' ) - { - usedChar(); - return true; - } - else - { - throw XmlException("Malformed close tag."); - } - } - else if( getChar(1) == '!' ) - { - // We know it's a comment, let's see if it's proper - if( getChar(2) != '-' || - getChar(3) != '-' ) - { - // Not a valid XML comment - throw XmlException("Malformed comment start tag found."); - } - - usedChar( 4 ); - - // Now burn text until we find the close tag - for(;;) - { - if( getChar() == '-' ) - { - if( getChar( 1 ) == '-' ) - { - // The next one has to be a '>' now - if( getChar( 2 ) != '>' ) - { - throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); - } - usedChar( 3 ); - break; - } - else - { - // Found a dash followed by a non dash, that's ok... - usedChar( 2 ); - } - } - else - { - // Burn comment chars - usedChar(); - } - } - } - else - { - if( fbContent.getLength() > 0 ) - { - if( bStrip ) - { - int j; - for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); - ((char *)fbContent.getData())[j+1] = '\0'; - } - setContent( fbContent.getData() ); - fbContent.clearData(); - } - gcall( node() ); - } - - if( bStrip ) gcall( ws() ); - } - else if( chr == '&' ) - { - StaticString *tmp = getEscape(); - if( tmp == NULL ) return false; - fbContent.appendData( tmp->getString() ); - delete tmp; - } - else - { - fbContent.appendData( chr ); - usedChar(); - } - } -} - diff --git a/src/old/xmlreader.h b/src/old/xmlreader.h deleted file mode 100644 index c8f7202..0000000 --- a/src/old/xmlreader.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef XMLREADER -#define XMLREADER - -#include -#include "xmldocument.h" -#include "flexbuf.h" -#include "hashtable.h" -#include "staticstring.h" - -/** - * Takes care of reading in xml formatted data from a file. This could/should - * be made more arbitrary in the future so that we can read the data from any - * source. This is actually made quite simple already since all data read in - * is handled by one single helper function and then palced into a FlexBuf for - * easy access by the other functions. The FlexBuf also allows for block - * reading from disk, which improves speed by a noticable amount. - *
- * There are also some extra features implemented that allow you to break the - * standard XML reader specs and eliminate leading and trailing whitespace in - * all read content. This is useful in situations where you allow additional - * whitespace in the files to make them easily human readable. The resturned - * content will be NULL in sitautions where all content between nodes was - * stripped. - *@author Mike Buland - */ -class XmlReader : public XmlDocument -{ -public: - /** - * Create a standard XmlReader. The optional parameter bStrip allows you to - * create a reader that will strip out all leading and trailing whitespace - * in content, a-la html. - *@param bStrip Strip out leading and trailing whitespace? - */ - XmlReader( bool bStrip=false ); - - /** - * Destroy this XmlReader. - */ - virtual ~XmlReader(); - - /** - * Build a document based on some kind of input. This is called - * automatically by the constructor. - */ - bool buildDoc(); - -private: - /** - * This is called by the low level automoton in order to get the next - * character. This function should return a character at the current - * position plus nIndex, but does not increment the current character. - *@param nIndex The index of the character from the current stream position. - *@returns A single character at the requested position, or 0 for end of - * stream. - */ - virtual char getChar( int nIndex = 0 ) = 0; - - /** - * Called to increment the current stream position by a single character. - */ - virtual void usedChar( int nAmnt = 1) = 0; - - /** - * Automoton function: is whitespace. - *@param chr A character - *@returns True if chr is whitespace, false otherwise. - */ - bool isws( char chr ); - - /** - * Automoton function: ws. Skips sections of whitespace. - *@returns True if everything was ok, False for end of stream. - */ - bool ws(); - - /** - * Automoton function: node. Processes an XmlNode - *@returns True if everything was ok, False for end of stream. - */ - bool node(); - - /** - * Automoton function: startNode. Processes the begining of a node. - *@returns True if everything was ok, False for end of stream. - */ - bool startNode(); - - /** - * Automoton function: name. Processes the name of a node. - *@returns True if everything was ok, False for end of stream. - */ - bool name(); - - /** - * Automoton function: textDecl. Processes the xml text decleration, if - * there is one. - */ - void textDecl(); - - /** - * Automoton function: entity. Processes an entity from the header. - */ - void entity(); - - /** - * Adds an entity to the list, if it doesn't already exist. - *@param name The name of the entity - *@param value The value of the entity - */ - void addEntity( const char *name, const char *value ); - - StaticString *getEscape(); - - /** - * Automoton function: paramlist. Processes a list of node params. - *@returns True if everything was ok, False for end of stream. - */ - bool paramlist(); - - /** - * Automoton function: param. Processes a single parameter. - *@returns True if everything was ok, False for end of stream. - */ - bool param(); - - /** - * Automoton function: content. Processes node content. - *@returns True if everything was ok, False for end of stream. - */ - bool content(); - - FlexBuf fbContent; /**< buffer for the current node's content. */ - FlexBuf fbParamName; /**< buffer for the current param's name. */ - FlexBuf fbParamValue; /**< buffer for the current param's value. */ - bool bStrip; /**< Are we stripping whitespace? */ - - HashTable htEntity; /**< Entity type definitions. */ -}; - -#endif diff --git a/src/old/xmlwriter.cpp b/src/old/xmlwriter.cpp deleted file mode 100644 index 56880b6..0000000 --- a/src/old/xmlwriter.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include "xmlwriter.h" - -XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : - XmlDocument( pRoot ) -{ - if( sIndent == NULL ) - { - this->sIndent = ""; - } - else - { - this->sIndent = sIndent; - } -} - -XmlWriter::~XmlWriter() -{ -} - -void XmlWriter::write() -{ - write( getRoot(), sIndent.c_str() ); -} - -void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) -{ - writeNode( pRoot, 0, sIndent ); -} - -void XmlWriter::closeNode() -{ - XmlDocument::closeNode(); - - if( isCompleted() ) - { - write( getRoot(), sIndent.c_str() ); - } -} - -void XmlWriter::writeIndent( int nIndent, const char *sIndent ) -{ - if( sIndent == NULL ) return; - for( int j = 0; j < nIndent; j++ ) - { - writeString( sIndent ); - } -} - -std::string XmlWriter::escape( std::string sIn ) -{ - std::string sOut; - - std::string::const_iterator i; - for( i = sIn.begin(); i != sIn.end(); i++ ) - { - if( ((*i >= ' ' && *i <= '9') || - (*i >= 'a' && *i <= 'z') || - (*i >= 'A' && *i <= 'Z') ) && - (*i != '\"' && *i != '\'' && *i != '&') - ) - { - sOut += *i; - } - else - { - sOut += "&#"; - char buf[4]; - sprintf( buf, "%u", (unsigned char)*i ); - sOut += buf; - sOut += ';'; - } - } - - return sOut; -} - -void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) -{ - for( int j = 0; j < pNode->getNumProperties(); j++ ) - { - writeString(" "); - writeString( pNode->getPropertyName( j ) ); - writeString("=\""); - writeString( escape( pNode->getProperty( j ) ).c_str() ); - writeString("\""); - } -} - -void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) -{ - if( pNode->hasChildren() ) - { - writeIndent( nIndent, sIndent ); - writeString("<"); - writeString( pNode->getName() ); - writeNodeProps( pNode, nIndent, sIndent ); - if( sIndent ) - writeString(">\n"); - else - writeString(">"); - - if( pNode->getContent( 0 ) ) - { - writeIndent( nIndent+1, sIndent ); - if( sIndent ) - { - writeString( pNode->getContent( 0 ) ); - writeString("\n"); - } - else - writeString( pNode->getContent( 0 ) ); - } - - int nNumChildren = pNode->getNumChildren(); - for( int j = 0; j < nNumChildren; j++ ) - { - writeNode( pNode->getChild( j ), nIndent+1, sIndent ); - if( pNode->getContent( j+1 ) ) - { - writeIndent( nIndent+1, sIndent ); - if( sIndent ) - { - writeString( pNode->getContent( j+1 ) ); - writeString("\n"); - } - else - writeString( pNode->getContent( j+1 ) ); - } - } - - writeIndent( nIndent, sIndent ); - if( sIndent ) - { - writeString("getName() ); - writeString(">\n"); - } - else - { - writeString("getName() ); - writeString(">"); - } - } - else if( pNode->getContent() ) - { - writeIndent( nIndent, sIndent ); - writeString("<"); - writeString( pNode->getName() ); - writeNodeProps( pNode, nIndent, sIndent ); - writeString(">"); - writeString( pNode->getContent() ); - writeString("getName() ); - writeString(">"); - if( sIndent ) - writeString("\n"); - } - else - { - writeIndent( nIndent, sIndent ); - writeString("<"); - writeString( pNode->getName() ); - writeNodeProps( pNode, nIndent, sIndent ); - if( sIndent ) - writeString("/>\n"); - else - writeString("/>"); - } -} - diff --git a/src/old/xmlwriter.h b/src/old/xmlwriter.h deleted file mode 100644 index c48e810..0000000 --- a/src/old/xmlwriter.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef XMLWRITER -#define XMLWRITER - -#include "xmlnode.h" -#include "xmldocument.h" - -/** - * Implements xml writing in the XML standard format. Also allows you to - * break that format and auto-indent your exported xml data for ease of - * reading. The auto-indenting will only be applied to sections that - * have no content of their own already. This means that except for - * whitespace all of your data will be preserved perfectly. - * You can create an XmlWriter object around a file, or access the static - * write function directly and just hand it a filename and a root XmlNode. - * When using an XmlWriter object the interface is identicle to that of - * the XmlDocument class, so reference that class for API info. However - * when the initial (or root) node is closed, and the document is finished - * the file will be created and written to automatically. The user can - * check to see if this is actually true by calling the isFinished - * function in the XmlDocument class. - *@author Mike Buland - */ -class XmlWriter : public XmlDocument -{ -public: - /** - * Construct a standard XmlWriter. - *@param sIndent Set this to something other than NULL to include it as an - * indent before each node in the output that doesn't already have content. - * If you are using the whitespace stripping option in the XmlReader and set - * this to a tab or some spaces it will never effect the content of your - * file. - */ - XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); - - /** - * Destroy the writer. - */ - virtual ~XmlWriter(); - - /** - * This override of the parent class closeNode function calls the parent - * class, but also triggers a write operation when the final node is closed. - * This means that by checking the isCompleted() function the user may also - * check to see if their file has been written or not. - */ - void closeNode(); - - void write(); - -private: - std::string sIndent; /**< The indent string */ - - std::string escape( std::string sIn ); - - /** - * Write the file. - *@param pNode The root node - *@param sIndent The indent text. - */ - void write( XmlNode *pNode, const char *sIndent=NULL ); - - /** - * Write a node in the file, including children. - *@param pNode The node to write. - *@param nIndent The indent level (the number of times to include sIndent) - *@param sIndent The indent text. - */ - void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); - - /** - * Write the properties of a node. - *@param pNode The node who's properties to write. - *@param nIndent The indent level of the containing node - *@param sIndent The indent text. - */ - void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); - - /** - * Called to write the actual indent. - *@param nIndent The indent level. - *@param sIndent The indent text. - */ - void writeIndent( int nIndent, const char *sIndent ); - - /** - * This is the function that must be overridden in order to use this class. - * It must write the null-terminated string sString, minus the mull, - * verbatum to it's output device. Adding extra characters for any reason - * will break the XML formatting. - *@param sString The string data to write to the output. - */ - virtual void writeString( const char *sString ) = 0; -}; - -#endif diff --git a/src/tafdocument.cpp b/src/tafdocument.cpp deleted file mode 100644 index bd44dd5..0000000 --- a/src/tafdocument.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafdocument.h" - -Bu::TafDocument::TafDocument() -{ -} - -Bu::TafDocument::~TafDocument() -{ -} diff --git a/src/tafdocument.h b/src/tafdocument.h deleted file mode 100644 index 171f829..0000000 --- a/src/tafdocument.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BU_TAF_DOCUMENT_H -#define BU_TAF_DOCUMENT_H - -#include - -namespace Bu -{ - /** - * - */ - class TafDocument - { - public: - TafDocument(); - virtual ~TafDocument(); - - private: - - }; -} - -#endif diff --git a/src/tafnode.cpp b/src/tafnode.cpp deleted file mode 100644 index c9756ec..0000000 --- a/src/tafnode.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafnode.h" - -Bu::TafNode::TafNode() -{ -} - -Bu::TafNode::~TafNode() -{ -} diff --git a/src/tafnode.h b/src/tafnode.h deleted file mode 100644 index 34f5289..0000000 --- a/src/tafnode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef BU_TAF_NODE_H -#define BU_TAF_NODE_H - -#include - -namespace Bu -{ - /** - * - */ - class TafNode - { - public: - TafNode(); - virtual ~TafNode(); - - private: - - }; -} -#endif diff --git a/src/tafreader.cpp b/src/tafreader.cpp deleted file mode 100644 index f94fe44..0000000 --- a/src/tafreader.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "tafreader.h" - -Bu::TafReader::TafReader( Bu::Stream &sIn ) : - sIn( sIn ) -{ -} - -Bu::TafReader::~TafReader() -{ -} - diff --git a/src/tafreader.h b/src/tafreader.h deleted file mode 100644 index 2dbb9ea..0000000 --- a/src/tafreader.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef BU_TAF_READER_H -#define BU_TAF_READER_H - -#include -#include "bu/tafdocument.h" -#include "bu/stream.h" - -namespace Bu -{ - /** - * - */ - class TafReader : public Bu::TafDocument - { - public: - TafReader( Bu::Stream &sIn ); - virtual ~TafReader(); - - private: - Stream &sIn; - - }; -} - -#endif diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp deleted file mode 100644 index 3e6c025..0000000 --- a/src/tafwriter.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafwriter.h" - -Bu::TafWriter::TafWriter() -{ -} - -Bu::TafWriter::~TafWriter() -{ -} diff --git a/src/tafwriter.h b/src/tafwriter.h deleted file mode 100644 index 7057d62..0000000 --- a/src/tafwriter.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BU_TAF_WRITER_H -#define BU_TAF_WRITER_H - -#include - -namespace Bu -{ - /** - * - */ - class TafWriter - { - public: - TafWriter(); - virtual ~TafWriter(); - - private: - - }; -} - -#endif diff --git a/src/xmldocument.cpp b/src/xmldocument.cpp index cb21826..d7867d5 100644 --- a/src/xmldocument.cpp +++ b/src/xmldocument.cpp @@ -1,9 +1,149 @@ -#include "xmldocument.h" +#include +#include +#include "xmlwriter.h" -Bu::XmlDocument::XmlDocument() +XmlDocument::XmlDocument( XmlNode *pRoot ) { + this->pRoot = pRoot; + pCurrent = NULL; + bCompleted = (pRoot!=NULL); } -Bu::XmlDocument::~XmlDocument() +XmlDocument::~XmlDocument() { + if( pRoot ) + { + delete pRoot; + } } + +void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) +{ + if( pRoot == NULL ) + { + // This is the first node, so ignore position and just insert it. + pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); + } + else + { + pCurrent = pCurrent->addChild( sName, sContent ); + } + + if( bClose ) + { + closeNode(); + } +} + +void XmlDocument::setName( const char *sName ) +{ + pCurrent->setName( sName ); +} + +bool XmlDocument::isCompleted() +{ + return bCompleted; +} + +XmlNode *XmlDocument::getRoot() +{ + return pRoot; +} + +XmlNode *XmlDocument::detatchRoot() +{ + XmlNode *pTemp = pRoot; + pRoot = NULL; + return pTemp; +} + +XmlNode *XmlDocument::getCurrent() +{ + return pCurrent; +} + +void XmlDocument::closeNode() +{ + if( pCurrent != NULL ) + { + pCurrent = pCurrent->getParent(); + + if( pCurrent == NULL ) + { + bCompleted = true; + } + } +} + +void XmlDocument::addProperty( const char *sName, const char *sValue ) +{ + if( pCurrent ) + { + pCurrent->addProperty( sName, sValue ); + } +} + +void XmlDocument::addProperty( const char *sName, const unsigned char nValue ) +{ + char buf[12]; + sprintf( buf, "%hhi", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const char nValue ) +{ + char buf[12]; + sprintf( buf, "%hhi", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const unsigned short nValue ) +{ + char buf[12]; + sprintf( buf, "%hi", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const short nValue ) +{ + char buf[12]; + sprintf( buf, "%hi", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const int nValue ) +{ + char buf[12]; + sprintf( buf, "%d", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const unsigned long nValue ) +{ + char buf[12]; + sprintf( buf, "%li", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const long nValue ) +{ + char buf[12]; + sprintf( buf, "%li", nValue ); + addProperty( sName, buf ); +} + +void XmlDocument::addProperty( const char *sName, const double dValue ) +{ + char buf[40]; + sprintf( buf, "%f", dValue ); + addProperty( sName, buf ); +} + +void XmlDocument::setContent( const char *sContent ) +{ + if( pCurrent ) + { + pCurrent->setContent( sContent ); + } +} + diff --git a/src/xmldocument.h b/src/xmldocument.h index e16e3ea..6671c41 100644 --- a/src/xmldocument.h +++ b/src/xmldocument.h @@ -1,22 +1,171 @@ -#ifndef XML_DOCUMENT_H -#define XML_DOCUMENT_H +#ifndef XMLDOCUMENT +#define XMLDOCUMENT -#include +#include "xmlnode.h" -namespace Bu +/** + * Keeps track of an easily managed set of XmlNode information. Allows simple + * operations for logical writing to and reading from XML structures. Using + * already formed structures is simply done through the XmlNode structures, + * and the getRoot function here. Creation is performed through a simple set + * of operations that creates the data in a stream type format. + *@author Mike Buland + */ +class XmlDocument { +public: /** - * + * Construct either a blank XmlDocuemnt or construct a document around an + * existing XmlNode. Be careful, once an XmlNode is passed into a document + * the document takes over ownership and will delete it when the XmlDocument + * is deleted. + *@param pRoot The XmlNode to use as the root of this document, or NULL if + * you want to start a new document. */ - class XmlDocument - { - public: - XmlDocument(); - virtual ~XmlDocument(); + XmlDocument( XmlNode *pRoot=NULL ); - private: + /** + * Destroy all contained nodes. + */ + virtual ~XmlDocument(); + + /** + * Add a new node to the document. The new node is appended to the end of + * the current context, i.e. XmlNode, and the new node, provided it isn't + * close as part of this operation, will become the current context. + *@param sName The name of the new node to add. + *@param sContent A content string to be placed inside of the new node. + *@param bClose Set this to true to close the node immediately after adding + * the node and setting the content and name. If this is set to true the + * node is appended, but the context node doesn't change. + */ + void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); + + /** + * Set the name of the current node context. + *@param sName The new name of the node. + */ + void setName( const char *sName ); + + /** + * Close the current node context. This will move the current context to + * the parent node of the former current node. If the current node was the + * root then the "completed" flag is set and no more operations are allowed. + */ + void closeNode(); + + /** + * Change the content of the current node at the current position between + * nodes. + *@param sContent The new content of the current node. + */ + void setContent( const char *sContent ); + + /** + * Add a named property to the current context node. + *@param sName The name of the property to add. + *@param sValue The string value of the property. + */ + void addProperty( const char *sName, const char *sValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const unsigned char nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const char nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const unsigned short nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const short nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const unsigned long nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const long nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param nValue The numerical value to add. + */ + void addProperty( const char *sName, const int nValue ); + + /** + * Add a named property to the current context node, converting the + * numerical parameter to text using standrd printf style conversion. + *@param sName The name of the property to add. + *@param dValue The numerical value to add. + */ + void addProperty( const char *sName, const double dValue ); + + /** + * The XmlDocuemnt is considered completed if the root node has been closed. + * Once an XmlDocument has been completed, you can no longer perform + * operations on it. + *@return True if completed, false if still in progress. + */ + bool isCompleted(); + + /** + * Get a pointer to the root object of this XmlDocument. + *@returns A pointer to an internally owned XmlNode. Do not delete this + * XmlNode. + */ + XmlNode *getRoot(); + + /** + * Get a pointer to the root object of this XmlDocument, and remove the + * ownership from this object. + *@returns A pointer to an internally owned XmlNode. Do not delete this + * XmlNode. + */ + XmlNode *detatchRoot(); + + /** + * Get the current context node, which could be the same as the root node. + *@returns A pointer to an internally owned XmlNode. Do not delete this + * XmlNode. + */ + XmlNode *getCurrent(); - }; -} +private: + XmlNode *pRoot; /**< The root node. */ + XmlNode *pCurrent; /**< The current node. */ + bool bCompleted; /**< Is it completed? */ +}; #endif diff --git a/src/xmlnode.cpp b/src/xmlnode.cpp index 58ef5c5..b1ed9a9 100644 --- a/src/xmlnode.cpp +++ b/src/xmlnode.cpp @@ -1,9 +1,445 @@ #include "xmlnode.h" +#include "hashfunctionstring.h" -Bu::XmlNode::XmlNode() +XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : + hProperties( new HashFunctionString(), 53, false ), + hChildren( new HashFunctionString(), 53, true ) { + this->pParent = pParent; + if( sName != NULL ) + { + setName( sName ); + } + if( sContent != NULL ) + { + this->sPreContent = new std::string( sContent ); + } + else + { + this->sPreContent = NULL; + } + nCurContent = 0; } -Bu::XmlNode::~XmlNode() +XmlNode::~XmlNode() { + for( int j = 0; j < lChildren.getSize(); j++ ) + { + delete (XmlNode *)lChildren[j]; + } + for( int j = 0; j < lPropNames.getSize(); j++ ) + { + delete (std::string *)lPropNames[j]; + } + for( int j = 0; j < lPropValues.getSize(); j++ ) + { + delete (std::string *)lPropValues[j]; + } + for( int j = 0; j < lPostContent.getSize(); j++ ) + { + if( lPostContent[j] != NULL ) + { + delete (std::string *)lPostContent[j]; + } + } + if( sPreContent ) + { + delete sPreContent; + } } + +void XmlNode::setName( const char *sName ) +{ + if( pParent ) + { + if( this->sName.size() == 0 ) + { + // We're not in the hash yet, so add us + this->sName = sName; + pParent->hChildren.insert( this->sName.c_str(), this ); + } + else + { + // Slightly more tricky, delete us, then add us... + pParent->hChildren.del( this->sName.c_str() ); + this->sName = sName; + pParent->hChildren.insert( this->sName.c_str(), this ); + } + } + else + { + // If we have no parent, then just set the name string, we don't need + // to worry about hashing. + this->sName = sName; + } +} + +void XmlNode::setContent( const char *sContent, int nIndex ) +{ + if( nIndex == -1 ) + { + nIndex = nCurContent; + } + if( nIndex == 0 ) + { + if( this->sPreContent ) + { + delete this->sPreContent; + } + + this->sPreContent = new std::string( sContent ); + } + else + { + nIndex--; + if( lPostContent[nIndex] ) + { + delete (std::string *)lPostContent[nIndex]; + } + + lPostContent.setAt( nIndex, new std::string( sContent ) ); + } +} + +const char *XmlNode::getContent( int nIndex ) +{ + if( nIndex == 0 ) + { + if( sPreContent ) + { + return sPreContent->c_str(); + } + } + else + { + nIndex--; + if( lPostContent[nIndex] ) + { + return ((std::string *)lPostContent[nIndex])->c_str(); + } + } + + return NULL; +} + +XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) +{ + return addChild( new XmlNode( sName, this, sContent ) ); +} + +XmlNode *XmlNode::addChild( XmlNode *pNode ) +{ + lChildren.append( pNode ); + lPostContent.append( NULL ); + nCurContent++; + pNode->pParent = this; + + return pNode; +} + +XmlNode *XmlNode::getParent() +{ + return pParent; +} + +void XmlNode::addProperty( const char *sName, const char *sValue ) +{ + std::string *pName = new std::string( sName ); + std::string *pValue = new std::string( sValue ); + + hProperties.insert( pName->c_str(), pValue->c_str() ); + lPropNames.append( pName ); + lPropValues.append( pValue ); +} + +int XmlNode::getNumProperties() +{ + return lPropNames.getSize(); +} + +const char *XmlNode::getPropertyName( int nIndex ) +{ + std::string *tmp = ((std::string *)lPropNames[nIndex]); + if( tmp == NULL ) + return NULL; + return tmp->c_str(); +} + +const char *XmlNode::getProperty( int nIndex ) +{ + std::string *tmp = ((std::string *)lPropValues[nIndex]); + if( tmp == NULL ) + return NULL; + return tmp->c_str(); +} + +const char *XmlNode::getProperty( const char *sName ) +{ + const char *tmp = (const char *)hProperties[sName]; + if( tmp == NULL ) + return NULL; + return tmp; +} + +void XmlNode::deleteProperty( int nIndex ) +{ + hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); + + delete (std::string *)lPropNames[nIndex]; + delete (std::string *)lPropValues[nIndex]; + + lPropNames.deleteAt( nIndex ); + lPropValues.deleteAt( nIndex ); +} + +bool XmlNode::hasChildren() +{ + return lChildren.getSize()>0; +} + +int XmlNode::getNumChildren() +{ + return lChildren.getSize(); +} + +XmlNode *XmlNode::getChild( int nIndex ) +{ + return (XmlNode *)lChildren[nIndex]; +} + +XmlNode *XmlNode::getChild( const char *sName, int nSkip ) +{ + return (XmlNode *)hChildren.get( sName, nSkip ); +} + +const char *XmlNode::getName() +{ + return sName.c_str(); +} + +void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) +{ + XmlNode *xRet = detatchNode( nIndex, sReplacementText ); + + if( xRet != NULL ) + { + delete xRet; + } +} + +XmlNode *XmlNode::detatchNode( int nIndex, const char *sReplacementText ) +{ + if( nIndex < 0 || nIndex >= lChildren.getSize() ) + return NULL; + + // The real trick when deleteing a node isn't actually deleting it, it's + // reforming the content around the node that's now missing...hmmm... + + if( nIndex == 0 ) + { + // If the index is zero we have to deal with the pre-content + if( sReplacementText ) + { + if( sPreContent == NULL ) + { + sPreContent = new std::string( sReplacementText ); + } + else + { + *sPreContent += sReplacementText; + } + } + if( lPostContent.getSize() > 0 ) + { + if( lPostContent[0] != NULL ) + { + if( sPreContent == NULL ) + { + sPreContent = new std::string( + ((std::string *)lPostContent[0])->c_str() + ); + } + else + { + *sPreContent += + ((std::string *)lPostContent[0])->c_str(); + } + } + delete (std::string *)lPostContent[0]; + lPostContent.deleteAt( 0 ); + } + } + else + { + int nCont = nIndex-1; + // If it's above zero we deal with the post-content only + if( sReplacementText ) + { + if( lPostContent[nCont] == NULL ) + { + lPostContent.setAt( nCont, new std::string( sReplacementText ) ); + } + else + { + *((std::string *)lPostContent[nCont]) += sReplacementText; + } + } + if( lPostContent.getSize() > nIndex ) + { + if( lPostContent[nIndex] != NULL ) + { + if( lPostContent[nCont] == NULL ) + { + lPostContent.setAt( nCont, new std::string( + ((std::string *)lPostContent[nIndex])->c_str() + ) ); + } + else + { + *((std::string *)lPostContent[nCont]) += + ((std::string *)lPostContent[nIndex])->c_str(); + } + } + delete (std::string *)lPostContent[nIndex]; + lPostContent.deleteAt( nIndex ); + } + } + + XmlNode *xRet = (XmlNode *)lChildren[nIndex]; + hChildren.del( ((XmlNode *)lChildren[nIndex])->getName() ); + lChildren.deleteAt( nIndex ); + + return xRet; +} + +void XmlNode::replaceNode( int nIndex, XmlNode *pNewNode ) +{ + if( nIndex < 0 || nIndex >= lChildren.getSize() ) + return; //TODO: throw an exception + + delete (XmlNode *)lChildren[nIndex]; + lChildren.setAt( nIndex, pNewNode ); + pNewNode->pParent = this; +} + +XmlNode *XmlNode::getCopy() +{ + XmlNode *pNew = new XmlNode(); + + pNew->sName = sName; + if( sPreContent ) + { + pNew->sPreContent = new std::string( sPreContent->c_str() ); + } + else + { + pNew->sPreContent = NULL; + } + pNew->nCurContent = 0; + + int nSize = lPostContent.getSize(); + pNew->lPostContent.setSize( nSize ); + for( int j = 0; j < nSize; j++ ) + { + if( lPostContent[j] ) + { + pNew->lPostContent.setAt( + j, new std::string( + ((std::string *)lPostContent[j])->c_str() + ) + ); + } + else + { + pNew->lPostContent.setAt( j, NULL ); + } + } + + nSize = lChildren.getSize(); + pNew->lChildren.setSize( nSize ); + for( int j = 0; j < nSize; j++ ) + { + XmlNode *pChild = ((XmlNode *)lChildren[j])->getCopy(); + pNew->lChildren.setAt( j, pChild ); + pChild->pParent = pNew; + pNew->hChildren.insert( pChild->getName(), pChild ); + } + + nSize = lPropNames.getSize(); + pNew->lPropNames.setSize( nSize ); + pNew->lPropValues.setSize( nSize ); + for( int j = 0; j < nSize; j++ ) + { + std::string *pProp = new std::string( ((std::string *)lPropNames[j])->c_str() ); + std::string *pVal = new std::string( ((std::string *)lPropValues[j])->c_str() ); + pNew->lPropNames.setAt( j, pProp ); + pNew->lPropValues.setAt( j, pVal ); + pNew->hProperties.insert( pProp->c_str(), pVal->c_str() ); + pNew->nCurContent++; + } + + return pNew; +} + +void XmlNode::deleteNodeKeepChildren( int nIndex ) +{ + // This is a tricky one...we need to do some patching to keep things all + // even... + XmlNode *xRet = (XmlNode *)lChildren[nIndex]; + + if( xRet == NULL ) + { + return; + } + else + { + if( getContent( nIndex ) ) + { + std::string sBuf( getContent( nIndex ) ); + sBuf += xRet->getContent( 0 ); + setContent( sBuf.c_str(), nIndex ); + } + else + { + setContent( xRet->getContent( 0 ), nIndex ); + } + + int nSize = xRet->lChildren.getSize(); + for( int j = 0; j < nSize; j++ ) + { + XmlNode *pCopy = ((XmlNode *)xRet->lChildren[j])->getCopy(); + pCopy->pParent = this; + lChildren.insertBefore( pCopy, nIndex+j ); + + if( xRet->lPostContent[j] ) + { + lPostContent.insertBefore( + new std::string( ((std::string *)xRet->lPostContent[j])->c_str() ), + nIndex+j + ); + } + else + { + lPostContent.insertBefore( NULL, nIndex+j ); + } + } + + if( getContent( nIndex+nSize ) ) + { + //SString sBuf( getContent( nIndex+nSize ) ); + //sBuf.catfrom( xRet->getContent( nSize ) ); + //setContent( sBuf, nIndex+nSize ); + } + else + { + setContent( xRet->getContent( nSize ), nIndex+nSize ); + } + + deleteNode( nIndex+nSize ); + } +} + +void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) +{ +} + diff --git a/src/xmlnode.h b/src/xmlnode.h index cd9961a..7525306 100644 --- a/src/xmlnode.h +++ b/src/xmlnode.h @@ -1,22 +1,236 @@ -#ifndef XML_NODE_H -#define XML_NODE_H +#ifndef XMLNODE +#define XMLNODE -#include +#include +#include "linkedlist.h" +#include "hashtable.h" -namespace Bu +/** + * Maintains all data pertient to an XML node, including sub-nodes and content. + * All child nodes can be accessed through index and through name via a hash + * table. This makes it very easy to gain simple and fast access to all of + * your data. For most applications, the memory footprint is also rather + * small. While XmlNode objects can be used directly to create XML structures + * it is highly reccomended that all operations be performed through the + * XmlDocument class. + *@author Mike Buland + */ +class XmlNode { +public: /** - * + * Construct a new XmlNode. + *@param sName The name of the node. + *@param pParent The parent node. + *@param sContent The initial content string. */ - class XmlNode - { - public: - XmlNode(); - virtual ~XmlNode(); + XmlNode( + const char *sName=NULL, + XmlNode *pParent = NULL, + const char *sContent=NULL + ); + + /** + * Delete the node and cleanup all memory. + */ + virtual ~XmlNode(); + + /** + * Change the name of the node. + *@param sName The new name of the node. + */ + void setName( const char *sName ); + + /** + * Construct a new node and add it as a child to this node, also return a + * pointer to the newly constructed node. + *@param sName The name of the new node. + *@param sContent The initial content of the new node. + *@returns A pointer to the newly created child node. + */ + XmlNode *addChild( const char *sName, const char *sContent=NULL ); + + /** + * Add an already created XmlNode as a child to this node. The new child + * XmlNode's parent will be changed appropriately and the parent XmlNode + * will take ownership of the child. + *@param pChild The child XmlNode to add to this XmlNode. + *@returns A pointer to the child node that was just added. + */ + XmlNode *addChild( XmlNode *pChild ); + + /** + * Add a new property to the XmlNode. Properties are name/value pairs. + *@param sName The name of the property. Specifying a name that's already + * in use will overwrite that property. + *@param sValue The textual value of the property. + */ + void addProperty( const char *sName, const char *sValue ); + + /** + * Get a pointer to the parent node, if any. + *@returns A pointer to the node's parent, or NULL if there isn't one. + */ + XmlNode *getParent(); + + /** + * Tells you if this node has children. + *@returns True if this node has at least one child, false otherwise. + */ + bool hasChildren(); + + /** + * Tells you how many children this node has. + *@returns The number of children this node has. + */ + int getNumChildren(); + + /** + * Get a child node at a specific index. + *@param nIndex The zero-based index of the child to retreive. + *@returns A pointer to the child, or NULL if you requested an invalid + * index. + */ + XmlNode *getChild( int nIndex ); + + /** + * Get a child with the specified name, and possibly skip value. For an + * explination of skip values see the HashTable. + *@param sName The name of the child to find. + *@param nSkip The number of nodes with that name to skip. + *@returns A pointer to the child, or NULL if no child with that name was + * found. + */ + XmlNode *getChild( const char *sName, int nSkip=0 ); + + /** + * Get a pointer to the name of this node. Do not change this, use setName + * instead. + *@returns A pointer to the name of this node. + */ + const char *getName(); + + /** + * Set the content of this node, optionally at a specific index. Using the + * default of -1 will set the content after the last added node. + *@param sContent The content string to use. + *@param nIndex The index of the content. + */ + void setContent( const char *sContent, int nIndex=-1 ); - private: + /** + * Get the content string at a given index, or zero for initial content. + *@param nIndex The index of the content. + *@returns A pointer to the content at that location. + */ + const char *getContent( int nIndex = 0 ); + + /** + * Get the number of properties in this node. + *@returns The number of properties in this node. + */ + int getNumProperties(); + + /** + * Get a property's name by index. + *@param nIndex The index of the property to examine. + *@returns A pointer to the name of the property specified, or NULL if none + * found. + */ + const char *getPropertyName( int nIndex ); + + /** + * Get a proprty's value by index. + *@param nIndex The index of the property to examine. + *@returns A pointer to the value of the property specified, or NULL if none + * found. + */ + const char *getProperty( int nIndex ); + + /** + * Get a propery's value by name. + *@param sName The name of the property to examine. + *@returns A pointer to the value of the property specified, or NULL if none + * found. + */ + const char *getProperty( const char *sName ); + + /** + * Delete a property by index. + *@param nIndex The index of the property to delete. + *@returns True if the property was found and deleted, false if it wasn't + * found. + */ + void deleteProperty( int nIndex ); + + /** + * Delete a child node, possibly replacing it with some text. This actually + * fixes all content strings around the newly deleted child node. + *@param nIndex The index of the node to delete. + *@param sReplacementText The optional text to replace the node with. + *@returns True of the node was found, and deleted, false if it wasn't + * found. + */ + void deleteNode( int nIndex, const char *sReplacementText = NULL ); + + /** + * Delete a given node, but move all of it's children and content up to + * replace the deleted node. All of the content of the child node is + * spliced seamlessly into place with the parent node's content. + *@param nIndex The node to delete. + *@returns True if the node was found and deleted, false if it wasn't. + */ + void deleteNodeKeepChildren( int nIndex ); + + /** + * Detatch a given child node from this node. This effectively works just + * like a deleteNode, except that instead of deleting the node it is removed + * and returned, and all ownership is given up. + *@param nIndex The index of the node to detatch. + *@param sReplacementText The optional text to replace the detatched node + * with. + *@returns A pointer to the newly detatched node, which then passes + * ownership to the caller. + */ + XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); + + /** + * Replace a given node with a different node that is not currently owned by + * this XmlNode or any ancestor. + *@param nIndex The index of the node to replace. + *@param pNewNode The new node to replace the old node with. + *@returns True if the node was found and replaced, false if it wasn't. + */ + void replaceNode( int nIndex, XmlNode *pNewNode ); + + /** + * Replace a given node with the children and content of a given node. + *@param nIndex The index of the node to replace. + *@param pNewNode The node that contains the children and content that will + * replace the node specified by nIndex. + *@returns True if the node was found and replaced, false if it wasn't. + */ + void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); + + /** + * Get a copy of this node and all children. getCopy is recursive, so + * beware copying large trees of xml. + *@returns A newly created copy of this node and all of it's children. + */ + XmlNode *getCopy(); - }; -} +private: + std::string sName; /**< The name of the node. */ + std::string *sPreContent; /**< The content that goes before any node. */ + LinkedList lChildren; /**< The children. */ + LinkedList lPostContent; /**< The content that comes after children. */ + HashTable hProperties; /**< Property hashtable. */ + HashTable hChildren; /**< Children hashtable. */ + LinkedList lPropNames; /**< List of property names. */ + LinkedList lPropValues; /**< List of property values. */ + XmlNode *pParent; /**< A pointer to the parent of this node. */ + int nCurContent; /**< The current content we're on, for using the -1 on + setContent. */ +}; #endif diff --git a/src/xmlreader.cpp b/src/xmlreader.cpp index bd241cf..18df69c 100644 --- a/src/xmlreader.cpp +++ b/src/xmlreader.cpp @@ -1,82 +1,176 @@ #include "xmlreader.h" +#include "exceptions.h" +#include +#include "hashfunctionstring.h" -Bu::XmlReader::XmlReader( Bu::Stream &sIn ) : - sIn( sIn ) +XmlReader::XmlReader( bool bStrip ) : + bStrip( bStrip ), + htEntity( new HashFunctionString(), 11 ) { } -Bu::XmlReader::~XmlReader() +XmlReader::~XmlReader() { + void *i = htEntity.getFirstItemPos(); + while( (i = htEntity.getNextItemPos( i ) ) ) + { + free( (char *)(htEntity.getItemID( i )) ); + delete (StaticString *)htEntity.getItemData( i ); + } } -const char *Bu::XmlReader::lookahead( int nAmnt ) +void XmlReader::addEntity( const char *name, const char *value ) { - if( sBuf.getSize() >= nAmnt ) - return sBuf.getStr(); + if( htEntity[name] ) return; - int nNew = nAmnt - sBuf.getSize(); - char *buf = new char[nNew]; - sIn.read( buf, nNew ); - sBuf.append( buf ); + char *sName = strdup( name ); + StaticString *sValue = new StaticString( value ); - return sBuf.getStr(); + htEntity.insert( sName, sValue ); } -void Bu::XmlReader::burn( int nAmnt ) -{ - if( sBuf.getSize() < nAmnt ) - { - lookahead( nAmnt ); - } +#define gcall( x ) if( x == false ) return false; - //sBuf.remove( nAmnt ); +bool XmlReader::isws( char chr ) +{ + return ( chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r' ); } -void Bu::XmlReader::checkString( const char *str, int nLen ) +bool XmlReader::ws() { - if( !strncmp( str, lookahead( nLen ), nLen ) ) + while( true ) { - burn( nLen ); - return; + char chr = getChar(); + if( isws( chr ) ) + { + usedChar(); + } + else + { + return true; + } } - - throw Bu::ExceptionBase("Expected string '%s'", str ); + return true; } -Bu::XmlNode *Bu::XmlReader::read() +bool XmlReader::buildDoc() { - prolog(); -} + // take care of initial whitespace + gcall( ws() ); + textDecl(); + entity(); + addEntity("gt", ">"); + addEntity("lt", "<"); + addEntity("amp", "&"); + addEntity("apos", "\'"); + addEntity("quot", "\""); + gcall( node() ); -void Bu::XmlReader::prolog() -{ - XMLDecl(); - Misc(); + return true; } -void Bu::XmlReader::XMLDecl() +void XmlReader::textDecl() { - checkString("", 2 ); + if( getChar() == '<' && getChar( 1 ) == '?' ) + { + usedChar( 2 ); + for(;;) + { + if( getChar() == '?' ) + { + if( getChar( 1 ) == '>' ) + { + usedChar( 2 ); + return; + } + } + usedChar(); + } + } } -void Bu::XmlReader::Misc() +void XmlReader::entity() { for(;;) { - S(); - if( !strncmp("", 3 ); - return; - } + closeNode(); + usedChar(); + } + else + { + throw XmlException("Close node in singleNode malformed!"); } - burn( 1 ); } + else + { + throw XmlException("Close node expected, but not found."); + return false; + } + + return true; } -void Bu::XmlReader::PI() +bool XmlReader::startNode() { - checkString("", lookahead(j+2)+j, 2 ) ) + usedChar(); + + if( getChar() == '/' ) { - burn( j+2 ); - return; + // Heh, it's actually a close node, go figure + FlexBuf fbName; + usedChar(); + gcall( ws() ); + + while( true ) + { + char chr = getChar(); + if( isws( chr ) || chr == '>' ) + { + // Here we actually compare the name we got to the name + // we already set, they have to match exactly. + if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) + { + closeNode(); + break; + } + else + { + throw XmlException("Got a mismatched node close tag."); + } + } + else + { + fbName.appendData( chr ); + usedChar(); + } + } + + gcall( ws() ); + if( getChar() == '>' ) + { + // Everything is cool. + usedChar(); + } + else + { + throw XmlException("Got extra junk data instead of node close tag."); + } } + else + { + // We're good, format is consistant + addNode(); + + // Skip extra whitespace + gcall( ws() ); + gcall( name() ); + gcall( ws() ); + gcall( paramlist() ); + gcall( ws() ); + } + } + else + { + throw XmlException("Expected to find node opening char, '<'."); } + + return true; } -void Bu::XmlReader::S() +bool XmlReader::name() { - for( int j = 0;; j++ ) + FlexBuf fbName; + + while( true ) { - char c = *lookahead( 1 ); - if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) - continue; - if( j == 0 ) - throw ExceptionBase("Expected whitespace."); - return; + char chr = getChar(); + if( isws( chr ) || chr == '>' || chr == '/' ) + { + setName( fbName.getData() ); + return true; + } + else + { + fbName.appendData( chr ); + usedChar(); + } } + + return true; } -void Bu::XmlReader::Sq() +bool XmlReader::paramlist() { - for(;;) + while( true ) { - char c = *lookahead( 1 ); - if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ) - continue; - return; + char chr = getChar(); + if( chr == '/' || chr == '>' ) + { + return true; + } + else + { + gcall( param() ); + gcall( ws() ); + } } + + return true; } -void Bu::XmlReader::VersionInfo() +StaticString *XmlReader::getEscape() { - try + if( getChar( 1 ) == '#' ) { - S(); - checkString("version", 7 ); + // If the entity starts with a # it's a character escape code + int base = 10; + usedChar( 2 ); + if( getChar() == 'x' ) + { + base = 16; + usedChar(); + } + char buf[4]; + int j = 0; + for( j = 0; getChar() != ';'; j++ ) + { + buf[j] = getChar(); + usedChar(); + } + usedChar(); + buf[j] = '\0'; + buf[0] = (char)strtol( buf, (char **)NULL, base ); + buf[1] = '\0'; + + return new StaticString( buf ); } - catch( ExceptionBase &e ) + else { - return; + // ...otherwise replace with the appropriate string... + std::string buf; + usedChar(); + for(;;) + { + char cbuf = getChar(); + usedChar(); + if( cbuf == ';' ) break; + buf += cbuf; + } + + StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; + if( tmp == NULL ) return NULL; + + StaticString *ret = new StaticString( *tmp ); + return ret; } - Eq(); - Bu::FString ver = AttValue(); - if( ver != "1.1" ) - throw ExceptionBase("Currently we only support xml version 1.1\n"); } -void Bu::XmlReader::Eq() +bool XmlReader::param() { - Sq(); - checkString("=", 1 ); - Sq(); -} + FlexBuf fbName; + FlexBuf fbValue; -void Bu::XmlReader::EncodingDecl() -{ - S(); - try - { - checkString("encoding", 8 ); - } - catch( ExceptionBase &e ) + while( true ) { - return; + char chr = getChar(); + if( isws( chr ) || chr == '=' ) + { + break; + } + else + { + fbName.appendData( chr ); + usedChar(); + } } - Eq(); - AttValue(); -} + gcall( ws() ); -void Bu::XmlReader::SDDecl() -{ - S(); - try - { - checkString("standalone", 10 ); - } - catch( ExceptionBase &e ) + if( getChar() == '=' ) { - return; - } + usedChar(); - Eq(); - AttValue(); -} + gcall( ws() ); -Bu::FString Bu::XmlReader::AttValue() -{ - char q = *lookahead(1); - if( q == '\"' ) - { - for( int j = 2;; j++ ) + char chr = getChar(); + if( chr == '"' ) { - if( lookahead(j)[j-1] == '\"' ) + // Better quoted rhs + usedChar(); + + while( true ) { - Bu::FString ret( lookahead(j)+1, j-2 ); - burn( j ); - return ret; + chr = getChar(); + if( chr == '"' ) + { + usedChar(); + addProperty( fbName.getData(), fbValue.getData() ); + return true; + } + else + { + if( chr == '&' ) + { + StaticString *tmp = getEscape(); + if( tmp == NULL ) return false; + fbValue.appendData( tmp->getString() ); + delete tmp; + } + else + { + fbValue.appendData( chr ); + usedChar(); + } + } } } - } - else if( q == '\'' ) - { - for( int j = 2;; j++ ) + else { - if( lookahead(j)[j-1] == '\'' ) + // Simple one-word rhs + while( true ) { - Bu::FString ret( lookahead(j)+1, j-2 ); - burn( j ); - return ret; + chr = getChar(); + if( isws( chr ) || chr == '/' || chr == '>' ) + { + addProperty( fbName.getData(), fbValue.getData() ); + return true; + } + else + { + if( chr == '&' ) + { + StaticString *tmp = getEscape(); + if( tmp == NULL ) return false; + fbValue.appendData( tmp->getString() ); + delete tmp; + } + else + { + fbValue.appendData( chr ); + usedChar(); + } + } } } } + else + { + throw XmlException("Expected an equals to seperate the params."); + return false; + } - throw ExceptionBase("Excpected either \' or \".\n"); + return true; } -Bu::FString Bu::XmlReader::Name() +bool XmlReader::content() { - unsigned char c = *lookahead( 1 ); - if( c != ':' && c != '_' && - (c < 'A' || c > 'Z') && - (c < 'a' || c > 'z') && - (c < 0xC0 || c > 0xD6 ) && - (c < 0xD8 || c > 0xF6 ) && - (c < 0xF8)) - { - throw ExceptionBase("Invalid entity name starting character."); - } + FlexBuf fbContent; - for( int j = 1;; j++ ) + if( bStrip ) gcall( ws() ); + + while( true ) { - unsigned char c = lookahead(j+1)[j]; - if( isS( c ) ) + char chr = getChar(); + if( chr == '<' ) + { + if( getChar(1) == '/' ) + { + if( fbContent.getLength() > 0 ) + { + if( bStrip ) + { + int j; + for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); + ((char *)fbContent.getData())[j+1] = '\0'; + } + setContent( fbContent.getData() ); + } + usedChar( 2 ); + gcall( ws() ); + FlexBuf fbName; + while( true ) + { + chr = getChar(); + if( isws( chr ) || chr == '>' ) + { + if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) + { + closeNode(); + break; + } + else + { + throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); + } + } + else + { + fbName.appendData( chr ); + usedChar(); + } + } + gcall( ws() ); + if( getChar() == '>' ) + { + usedChar(); + return true; + } + else + { + throw XmlException("Malformed close tag."); + } + } + else if( getChar(1) == '!' ) + { + // We know it's a comment, let's see if it's proper + if( getChar(2) != '-' || + getChar(3) != '-' ) + { + // Not a valid XML comment + throw XmlException("Malformed comment start tag found."); + } + + usedChar( 4 ); + + // Now burn text until we find the close tag + for(;;) + { + if( getChar() == '-' ) + { + if( getChar( 1 ) == '-' ) + { + // The next one has to be a '>' now + if( getChar( 2 ) != '>' ) + { + throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); + } + usedChar( 3 ); + break; + } + else + { + // Found a dash followed by a non dash, that's ok... + usedChar( 2 ); + } + } + else + { + // Burn comment chars + usedChar(); + } + } + } + else + { + if( fbContent.getLength() > 0 ) + { + if( bStrip ) + { + int j; + for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); + ((char *)fbContent.getData())[j+1] = '\0'; + } + setContent( fbContent.getData() ); + fbContent.clearData(); + } + gcall( node() ); + } + + if( bStrip ) gcall( ws() ); + } + else if( chr == '&' ) { - FString ret( lookahead(j+1), j+1 ); - burn( j+1 ); - return ret; + StaticString *tmp = getEscape(); + if( tmp == NULL ) return false; + fbContent.appendData( tmp->getString() ); + delete tmp; } - if( c != ':' && c != '_' && c != '-' && c != '.' && c != 0xB7 && - (c < 'A' || c > 'Z') && - (c < 'a' || c > 'z') && - (c < '0' || c > '9') && - (c < 0xC0 || c > 0xD6 ) && - (c < 0xD8 || c > 0xF6 ) && - (c < 0xF8)) + else { - throw ExceptionBase("Invalid character in name."); + fbContent.appendData( chr ); + usedChar(); } } } diff --git a/src/xmlreader.h b/src/xmlreader.h index 708a386..c8f7202 100644 --- a/src/xmlreader.h +++ b/src/xmlreader.h @@ -1,121 +1,141 @@ -#ifndef XML_READER_H -#define XML_READER_H +#ifndef XMLREADER +#define XMLREADER + +#include +#include "xmldocument.h" +#include "flexbuf.h" +#include "hashtable.h" +#include "staticstring.h" + +/** + * Takes care of reading in xml formatted data from a file. This could/should + * be made more arbitrary in the future so that we can read the data from any + * source. This is actually made quite simple already since all data read in + * is handled by one single helper function and then palced into a FlexBuf for + * easy access by the other functions. The FlexBuf also allows for block + * reading from disk, which improves speed by a noticable amount. + *
+ * There are also some extra features implemented that allow you to break the + * standard XML reader specs and eliminate leading and trailing whitespace in + * all read content. This is useful in situations where you allow additional + * whitespace in the files to make them easily human readable. The resturned + * content will be NULL in sitautions where all content between nodes was + * stripped. + *@author Mike Buland + */ +class XmlReader : public XmlDocument +{ +public: + /** + * Create a standard XmlReader. The optional parameter bStrip allows you to + * create a reader that will strip out all leading and trailing whitespace + * in content, a-la html. + *@param bStrip Strip out leading and trailing whitespace? + */ + XmlReader( bool bStrip=false ); -#include -#include "bu/stream.h" -#include "bu/fstring.h" -#include "bu/xmlnode.h" + /** + * Destroy this XmlReader. + */ + virtual ~XmlReader(); + + /** + * Build a document based on some kind of input. This is called + * automatically by the constructor. + */ + bool buildDoc(); + +private: + /** + * This is called by the low level automoton in order to get the next + * character. This function should return a character at the current + * position plus nIndex, but does not increment the current character. + *@param nIndex The index of the character from the current stream position. + *@returns A single character at the requested position, or 0 for end of + * stream. + */ + virtual char getChar( int nIndex = 0 ) = 0; + + /** + * Called to increment the current stream position by a single character. + */ + virtual void usedChar( int nAmnt = 1) = 0; + + /** + * Automoton function: is whitespace. + *@param chr A character + *@returns True if chr is whitespace, false otherwise. + */ + bool isws( char chr ); + + /** + * Automoton function: ws. Skips sections of whitespace. + *@returns True if everything was ok, False for end of stream. + */ + bool ws(); + + /** + * Automoton function: node. Processes an XmlNode + *@returns True if everything was ok, False for end of stream. + */ + bool node(); -namespace Bu -{ /** - * An Xml 1.1 reader. I've decided to write this, this time, based on the - * official W3C reccomendation, now included with the source code. I've - * named the productions in the parser states the same as in that document, - * which may make them easier to find, etc, although possibly slightly less - * optimized than writing my own reduced grammer. - * - * Below I will list differences between my parser and the official standard - * as I come up with them. - * - Encoding and Standalone headings are ignored for the moment. (4.3.3, - * 2.9) - * - The standalone heading attribute can have any standard whitespace - * before it (the specs say only spaces, no newlines). (2.9) - * - Since standalone is ignored, it is currently allowed to have any - * value (should be restricted to "yes" or "no"). (2.9) - * - Currently only UTF-8 / ascii are parsed. - * - [optional] The content of comments is thrown away. (2.5) - * - The content of processing instruction blocks is parsed properly, but - * thrown away. (2.6) - */ - class XmlReader - { - public: - XmlReader( Bu::Stream &sIn ); - virtual ~XmlReader(); - - XmlNode *read(); - - private: - Bu::Stream &sIn; - Bu::FString sBuf; - - private: // Helpers - const char *lookahead( int nAmnt ); - void burn( int nAmnt ); - void checkString( const char *str, int nLen ); - - private: // States - /** - * The headers, etc. - */ - void prolog(); - - /** - * The xml decleration (version, encoding, etc). - */ - void XMLDecl(); - - /** - * Misc things, Includes Comments and PIData (Processing Instructions). - */ - void Misc(); - - /** - * Comments - */ - void Comment(); - - /** - * Processing Instructions - */ - void PI(); - - /** - * Whitespace eater. - */ - void S(); - - /** - * Optional whitespace eater. - */ - void Sq(); - - /** - * XML Version spec - */ - void VersionInfo(); - - /** - * Your basic equals sign with surrounding whitespace. - */ - void Eq(); - - /** - * Read in an attribute value. - */ - FString AttValue(); - - /** - * Read in the name of something. - */ - FString Name(); - - /** - * Encoding decleration in the header - */ - void EncodingDecl(); - - /** - * Standalone decleration in the header - */ - void SDDecl(); - - bool isS( unsigned char c ) - { - return ( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA ); - } - }; -} + * Automoton function: startNode. Processes the begining of a node. + *@returns True if everything was ok, False for end of stream. + */ + bool startNode(); + + /** + * Automoton function: name. Processes the name of a node. + *@returns True if everything was ok, False for end of stream. + */ + bool name(); + + /** + * Automoton function: textDecl. Processes the xml text decleration, if + * there is one. + */ + void textDecl(); + + /** + * Automoton function: entity. Processes an entity from the header. + */ + void entity(); + + /** + * Adds an entity to the list, if it doesn't already exist. + *@param name The name of the entity + *@param value The value of the entity + */ + void addEntity( const char *name, const char *value ); + + StaticString *getEscape(); + + /** + * Automoton function: paramlist. Processes a list of node params. + *@returns True if everything was ok, False for end of stream. + */ + bool paramlist(); + + /** + * Automoton function: param. Processes a single parameter. + *@returns True if everything was ok, False for end of stream. + */ + bool param(); + + /** + * Automoton function: content. Processes node content. + *@returns True if everything was ok, False for end of stream. + */ + bool content(); + + FlexBuf fbContent; /**< buffer for the current node's content. */ + FlexBuf fbParamName; /**< buffer for the current param's name. */ + FlexBuf fbParamValue; /**< buffer for the current param's value. */ + bool bStrip; /**< Are we stripping whitespace? */ + + HashTable htEntity; /**< Entity type definitions. */ +}; #endif diff --git a/src/xmlwriter.cpp b/src/xmlwriter.cpp index 23a5175..56880b6 100644 --- a/src/xmlwriter.cpp +++ b/src/xmlwriter.cpp @@ -1,9 +1,173 @@ +#include +#include #include "xmlwriter.h" -Bu::XmlWriter::XmlWriter() +XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : + XmlDocument( pRoot ) { + if( sIndent == NULL ) + { + this->sIndent = ""; + } + else + { + this->sIndent = sIndent; + } } -Bu::XmlWriter::~XmlWriter() +XmlWriter::~XmlWriter() { } + +void XmlWriter::write() +{ + write( getRoot(), sIndent.c_str() ); +} + +void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) +{ + writeNode( pRoot, 0, sIndent ); +} + +void XmlWriter::closeNode() +{ + XmlDocument::closeNode(); + + if( isCompleted() ) + { + write( getRoot(), sIndent.c_str() ); + } +} + +void XmlWriter::writeIndent( int nIndent, const char *sIndent ) +{ + if( sIndent == NULL ) return; + for( int j = 0; j < nIndent; j++ ) + { + writeString( sIndent ); + } +} + +std::string XmlWriter::escape( std::string sIn ) +{ + std::string sOut; + + std::string::const_iterator i; + for( i = sIn.begin(); i != sIn.end(); i++ ) + { + if( ((*i >= ' ' && *i <= '9') || + (*i >= 'a' && *i <= 'z') || + (*i >= 'A' && *i <= 'Z') ) && + (*i != '\"' && *i != '\'' && *i != '&') + ) + { + sOut += *i; + } + else + { + sOut += "&#"; + char buf[4]; + sprintf( buf, "%u", (unsigned char)*i ); + sOut += buf; + sOut += ';'; + } + } + + return sOut; +} + +void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) +{ + for( int j = 0; j < pNode->getNumProperties(); j++ ) + { + writeString(" "); + writeString( pNode->getPropertyName( j ) ); + writeString("=\""); + writeString( escape( pNode->getProperty( j ) ).c_str() ); + writeString("\""); + } +} + +void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) +{ + if( pNode->hasChildren() ) + { + writeIndent( nIndent, sIndent ); + writeString("<"); + writeString( pNode->getName() ); + writeNodeProps( pNode, nIndent, sIndent ); + if( sIndent ) + writeString(">\n"); + else + writeString(">"); + + if( pNode->getContent( 0 ) ) + { + writeIndent( nIndent+1, sIndent ); + if( sIndent ) + { + writeString( pNode->getContent( 0 ) ); + writeString("\n"); + } + else + writeString( pNode->getContent( 0 ) ); + } + + int nNumChildren = pNode->getNumChildren(); + for( int j = 0; j < nNumChildren; j++ ) + { + writeNode( pNode->getChild( j ), nIndent+1, sIndent ); + if( pNode->getContent( j+1 ) ) + { + writeIndent( nIndent+1, sIndent ); + if( sIndent ) + { + writeString( pNode->getContent( j+1 ) ); + writeString("\n"); + } + else + writeString( pNode->getContent( j+1 ) ); + } + } + + writeIndent( nIndent, sIndent ); + if( sIndent ) + { + writeString("getName() ); + writeString(">\n"); + } + else + { + writeString("getName() ); + writeString(">"); + } + } + else if( pNode->getContent() ) + { + writeIndent( nIndent, sIndent ); + writeString("<"); + writeString( pNode->getName() ); + writeNodeProps( pNode, nIndent, sIndent ); + writeString(">"); + writeString( pNode->getContent() ); + writeString("getName() ); + writeString(">"); + if( sIndent ) + writeString("\n"); + } + else + { + writeIndent( nIndent, sIndent ); + writeString("<"); + writeString( pNode->getName() ); + writeNodeProps( pNode, nIndent, sIndent ); + if( sIndent ) + writeString("/>\n"); + else + writeString("/>"); + } +} + diff --git a/src/xmlwriter.h b/src/xmlwriter.h index 796d6fb..c48e810 100644 --- a/src/xmlwriter.h +++ b/src/xmlwriter.h @@ -1,22 +1,96 @@ -#ifndef XML_WRITER_H -#define XML_WRITER_H +#ifndef XMLWRITER +#define XMLWRITER -#include +#include "xmlnode.h" +#include "xmldocument.h" -namespace Bu +/** + * Implements xml writing in the XML standard format. Also allows you to + * break that format and auto-indent your exported xml data for ease of + * reading. The auto-indenting will only be applied to sections that + * have no content of their own already. This means that except for + * whitespace all of your data will be preserved perfectly. + * You can create an XmlWriter object around a file, or access the static + * write function directly and just hand it a filename and a root XmlNode. + * When using an XmlWriter object the interface is identicle to that of + * the XmlDocument class, so reference that class for API info. However + * when the initial (or root) node is closed, and the document is finished + * the file will be created and written to automatically. The user can + * check to see if this is actually true by calling the isFinished + * function in the XmlDocument class. + *@author Mike Buland + */ +class XmlWriter : public XmlDocument { +public: /** - * + * Construct a standard XmlWriter. + *@param sIndent Set this to something other than NULL to include it as an + * indent before each node in the output that doesn't already have content. + * If you are using the whitespace stripping option in the XmlReader and set + * this to a tab or some spaces it will never effect the content of your + * file. */ - class XmlWriter - { - public: - XmlWriter(); - virtual ~XmlWriter(); + XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); - private: + /** + * Destroy the writer. + */ + virtual ~XmlWriter(); + + /** + * This override of the parent class closeNode function calls the parent + * class, but also triggers a write operation when the final node is closed. + * This means that by checking the isCompleted() function the user may also + * check to see if their file has been written or not. + */ + void closeNode(); + + void write(); - }; -} +private: + std::string sIndent; /**< The indent string */ + + std::string escape( std::string sIn ); + + /** + * Write the file. + *@param pNode The root node + *@param sIndent The indent text. + */ + void write( XmlNode *pNode, const char *sIndent=NULL ); + + /** + * Write a node in the file, including children. + *@param pNode The node to write. + *@param nIndent The indent level (the number of times to include sIndent) + *@param sIndent The indent text. + */ + void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); + + /** + * Write the properties of a node. + *@param pNode The node who's properties to write. + *@param nIndent The indent level of the containing node + *@param sIndent The indent text. + */ + void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); + + /** + * Called to write the actual indent. + *@param nIndent The indent level. + *@param sIndent The indent text. + */ + void writeIndent( int nIndent, const char *sIndent ); + + /** + * This is the function that must be overridden in order to use this class. + * It must write the null-terminated string sString, minus the mull, + * verbatum to it's output device. Adding extra characters for any reason + * will break the XML formatting. + *@param sString The string data to write to the output. + */ + virtual void writeString( const char *sString ) = 0; +}; #endif -- cgit v1.2.3 From cdca5e17e1ecb9f212353dce55c5df2930e34e9d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 6 Jun 2007 16:12:02 +0000 Subject: Moved Taf back into core. --- src/inprogress/tafdocument.cpp | 9 --------- src/inprogress/tafdocument.h | 22 ---------------------- src/inprogress/tafnode.cpp | 9 --------- src/inprogress/tafnode.h | 21 --------------------- src/inprogress/tafreader.cpp | 16 ---------------- src/inprogress/tafreader.h | 27 --------------------------- src/inprogress/tafwriter.cpp | 9 --------- src/inprogress/tafwriter.h | 22 ---------------------- src/tafdocument.cpp | 9 +++++++++ src/tafdocument.h | 22 ++++++++++++++++++++++ src/tafnode.cpp | 9 +++++++++ src/tafnode.h | 21 +++++++++++++++++++++ src/tafreader.cpp | 16 ++++++++++++++++ src/tafreader.h | 27 +++++++++++++++++++++++++++ src/tafwriter.cpp | 9 +++++++++ src/tafwriter.h | 22 ++++++++++++++++++++++ 16 files changed, 135 insertions(+), 135 deletions(-) delete mode 100644 src/inprogress/tafdocument.cpp delete mode 100644 src/inprogress/tafdocument.h delete mode 100644 src/inprogress/tafnode.cpp delete mode 100644 src/inprogress/tafnode.h delete mode 100644 src/inprogress/tafreader.cpp delete mode 100644 src/inprogress/tafreader.h delete mode 100644 src/inprogress/tafwriter.cpp delete mode 100644 src/inprogress/tafwriter.h create mode 100644 src/tafdocument.cpp create mode 100644 src/tafdocument.h create mode 100644 src/tafnode.cpp create mode 100644 src/tafnode.h create mode 100644 src/tafreader.cpp create mode 100644 src/tafreader.h create mode 100644 src/tafwriter.cpp create mode 100644 src/tafwriter.h (limited to 'src/tafwriter.h') diff --git a/src/inprogress/tafdocument.cpp b/src/inprogress/tafdocument.cpp deleted file mode 100644 index bd44dd5..0000000 --- a/src/inprogress/tafdocument.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafdocument.h" - -Bu::TafDocument::TafDocument() -{ -} - -Bu::TafDocument::~TafDocument() -{ -} diff --git a/src/inprogress/tafdocument.h b/src/inprogress/tafdocument.h deleted file mode 100644 index 171f829..0000000 --- a/src/inprogress/tafdocument.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BU_TAF_DOCUMENT_H -#define BU_TAF_DOCUMENT_H - -#include - -namespace Bu -{ - /** - * - */ - class TafDocument - { - public: - TafDocument(); - virtual ~TafDocument(); - - private: - - }; -} - -#endif diff --git a/src/inprogress/tafnode.cpp b/src/inprogress/tafnode.cpp deleted file mode 100644 index c9756ec..0000000 --- a/src/inprogress/tafnode.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafnode.h" - -Bu::TafNode::TafNode() -{ -} - -Bu::TafNode::~TafNode() -{ -} diff --git a/src/inprogress/tafnode.h b/src/inprogress/tafnode.h deleted file mode 100644 index 34f5289..0000000 --- a/src/inprogress/tafnode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef BU_TAF_NODE_H -#define BU_TAF_NODE_H - -#include - -namespace Bu -{ - /** - * - */ - class TafNode - { - public: - TafNode(); - virtual ~TafNode(); - - private: - - }; -} -#endif diff --git a/src/inprogress/tafreader.cpp b/src/inprogress/tafreader.cpp deleted file mode 100644 index 4d10b8d..0000000 --- a/src/inprogress/tafreader.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "tafreader.h" - -Bu::TafReader::TafReader( Bu::Stream &sIn ) : - sIn( sIn ) -{ -} - -Bu::TafReader::~TafReader() -{ -} - -void Bu::TafReader::next() -{ - sIn.read( &c, 1 ); -} - diff --git a/src/inprogress/tafreader.h b/src/inprogress/tafreader.h deleted file mode 100644 index b552f5d..0000000 --- a/src/inprogress/tafreader.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef BU_TAF_READER_H -#define BU_TAF_READER_H - -#include -#include "bu/tafdocument.h" -#include "bu/stream.h" - -namespace Bu -{ - /** - * - */ - class TafReader : public Bu::TafDocument - { - public: - TafReader( Bu::Stream &sIn ); - virtual ~TafReader(); - - private: - void next(); - char c; - Stream &sIn; - - }; -} - -#endif diff --git a/src/inprogress/tafwriter.cpp b/src/inprogress/tafwriter.cpp deleted file mode 100644 index 3e6c025..0000000 --- a/src/inprogress/tafwriter.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "tafwriter.h" - -Bu::TafWriter::TafWriter() -{ -} - -Bu::TafWriter::~TafWriter() -{ -} diff --git a/src/inprogress/tafwriter.h b/src/inprogress/tafwriter.h deleted file mode 100644 index 7057d62..0000000 --- a/src/inprogress/tafwriter.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BU_TAF_WRITER_H -#define BU_TAF_WRITER_H - -#include - -namespace Bu -{ - /** - * - */ - class TafWriter - { - public: - TafWriter(); - virtual ~TafWriter(); - - private: - - }; -} - -#endif diff --git a/src/tafdocument.cpp b/src/tafdocument.cpp new file mode 100644 index 0000000..bd44dd5 --- /dev/null +++ b/src/tafdocument.cpp @@ -0,0 +1,9 @@ +#include "tafdocument.h" + +Bu::TafDocument::TafDocument() +{ +} + +Bu::TafDocument::~TafDocument() +{ +} diff --git a/src/tafdocument.h b/src/tafdocument.h new file mode 100644 index 0000000..171f829 --- /dev/null +++ b/src/tafdocument.h @@ -0,0 +1,22 @@ +#ifndef BU_TAF_DOCUMENT_H +#define BU_TAF_DOCUMENT_H + +#include + +namespace Bu +{ + /** + * + */ + class TafDocument + { + public: + TafDocument(); + virtual ~TafDocument(); + + private: + + }; +} + +#endif diff --git a/src/tafnode.cpp b/src/tafnode.cpp new file mode 100644 index 0000000..c9756ec --- /dev/null +++ b/src/tafnode.cpp @@ -0,0 +1,9 @@ +#include "tafnode.h" + +Bu::TafNode::TafNode() +{ +} + +Bu::TafNode::~TafNode() +{ +} diff --git a/src/tafnode.h b/src/tafnode.h new file mode 100644 index 0000000..34f5289 --- /dev/null +++ b/src/tafnode.h @@ -0,0 +1,21 @@ +#ifndef BU_TAF_NODE_H +#define BU_TAF_NODE_H + +#include + +namespace Bu +{ + /** + * + */ + class TafNode + { + public: + TafNode(); + virtual ~TafNode(); + + private: + + }; +} +#endif diff --git a/src/tafreader.cpp b/src/tafreader.cpp new file mode 100644 index 0000000..4d10b8d --- /dev/null +++ b/src/tafreader.cpp @@ -0,0 +1,16 @@ +#include "tafreader.h" + +Bu::TafReader::TafReader( Bu::Stream &sIn ) : + sIn( sIn ) +{ +} + +Bu::TafReader::~TafReader() +{ +} + +void Bu::TafReader::next() +{ + sIn.read( &c, 1 ); +} + diff --git a/src/tafreader.h b/src/tafreader.h new file mode 100644 index 0000000..b552f5d --- /dev/null +++ b/src/tafreader.h @@ -0,0 +1,27 @@ +#ifndef BU_TAF_READER_H +#define BU_TAF_READER_H + +#include +#include "bu/tafdocument.h" +#include "bu/stream.h" + +namespace Bu +{ + /** + * + */ + class TafReader : public Bu::TafDocument + { + public: + TafReader( Bu::Stream &sIn ); + virtual ~TafReader(); + + private: + void next(); + char c; + Stream &sIn; + + }; +} + +#endif diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp new file mode 100644 index 0000000..3e6c025 --- /dev/null +++ b/src/tafwriter.cpp @@ -0,0 +1,9 @@ +#include "tafwriter.h" + +Bu::TafWriter::TafWriter() +{ +} + +Bu::TafWriter::~TafWriter() +{ +} diff --git a/src/tafwriter.h b/src/tafwriter.h new file mode 100644 index 0000000..7057d62 --- /dev/null +++ b/src/tafwriter.h @@ -0,0 +1,22 @@ +#ifndef BU_TAF_WRITER_H +#define BU_TAF_WRITER_H + +#include + +namespace Bu +{ + /** + * + */ + class TafWriter + { + public: + TafWriter(); + virtual ~TafWriter(); + + private: + + }; +} + +#endif -- cgit v1.2.3 From 3f26c19b0b7a9fa73c58189788972ea43b72f014 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 25 Jun 2007 21:15:55 +0000 Subject: I think the plugger and programchain are all up to date to work with the new libbu++. The program chain may undergo heavy changes still, or be removed entirely, but we need it for congo and squirrelmud, so here it is for a while longer. The TafWriter isn't much closer, you still only get the groups in the output. --- src/linkmessage.cpp | 43 ++++++++++ src/linkmessage.h | 42 ++++++++++ src/old/linkmessage.cpp | 44 ----------- src/old/linkmessage.h | 39 ---------- src/old/plugger.cpp | 1 - src/old/plugger.h | 198 ----------------------------------------------- src/old/programchain.cpp | 96 ----------------------- src/old/programchain.h | 95 ----------------------- src/old/programlink.cpp | 54 ------------- src/old/programlink.h | 99 ------------------------ src/plugger.cpp | 1 + src/plugger.h | 196 ++++++++++++++++++++++++++++++++++++++++++++++ src/programchain.cpp | 97 +++++++++++++++++++++++ src/programchain.h | 98 +++++++++++++++++++++++ src/programlink.cpp | 56 ++++++++++++++ src/programlink.h | 100 ++++++++++++++++++++++++ src/tafwriter.cpp | 25 +++++- src/tafwriter.h | 10 ++- 18 files changed, 665 insertions(+), 629 deletions(-) create mode 100644 src/linkmessage.cpp create mode 100644 src/linkmessage.h delete mode 100644 src/old/linkmessage.cpp delete mode 100644 src/old/linkmessage.h delete mode 100644 src/old/plugger.cpp delete mode 100644 src/old/plugger.h delete mode 100644 src/old/programchain.cpp delete mode 100644 src/old/programchain.h delete mode 100644 src/old/programlink.cpp delete mode 100644 src/old/programlink.h create mode 100644 src/plugger.cpp create mode 100644 src/plugger.h create mode 100644 src/programchain.cpp create mode 100644 src/programchain.h create mode 100644 src/programlink.cpp create mode 100644 src/programlink.h (limited to 'src/tafwriter.h') diff --git a/src/linkmessage.cpp b/src/linkmessage.cpp new file mode 100644 index 0000000..abe113c --- /dev/null +++ b/src/linkmessage.cpp @@ -0,0 +1,43 @@ +#include "bu/linkmessage.h" + +Bu::LinkMessage::LinkMessage( int nNewMsg ) +{ + nMsg = nNewMsg; +} + +Bu::LinkMessage::~LinkMessage() +{ +} + +/* +void LinkMessage::setBroadcast( bool bOn ) +{ + bBroadcast = bOn; +} + +bool LinkMessage::isBroadcast() +{ + return bBroadcast; +} + + +void LinkMessage::setFromID( int id ) +{ + nFromLinkID = id; +} + +int LinkMessage::getFromID() +{ + return nFromLinkID; +} + +void LinkMessage::setToID( int id ) +{ + nTargetLinkID = id; +} + +int LinkMessage::getToID() +{ + return nTargetLinkID; +} +*/ diff --git a/src/linkmessage.h b/src/linkmessage.h new file mode 100644 index 0000000..64b8bc2 --- /dev/null +++ b/src/linkmessage.h @@ -0,0 +1,42 @@ +/**\file linkmessage.h + */ + +#ifndef LINKMESSAGE_H +#define LINKMESSAGE_H + +namespace Bu +{ + /** + * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally + * one would make a subclass of this in order to transmit more useful + * information, but sometimes it isn't necesarry. + *@author Mike Buland + */ + class LinkMessage + { + public: + /** + * Construct a blank LinkMessage. + */ + LinkMessage() {}; + + /** + * Deconstruct a LinkMessage. + */ + virtual ~LinkMessage(); + + /** + * Create a LinkMessage object with a specific message assosiated with it + * to start with. + *@param nNewMsg The message to use in the Message object. + */ + LinkMessage( int nNewMsg ); + + /** + * The message contained in the Message object. + */ + int nMsg; + }; +} + +#endif diff --git a/src/old/linkmessage.cpp b/src/old/linkmessage.cpp deleted file mode 100644 index cf3df42..0000000 --- a/src/old/linkmessage.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "linkmessage.h" -#include - -LinkMessage::LinkMessage( int nNewMsg ) -{ - nMsg = nNewMsg; -} - -LinkMessage::~LinkMessage() -{ -} - -/* -void LinkMessage::setBroadcast( bool bOn ) -{ - bBroadcast = bOn; -} - -bool LinkMessage::isBroadcast() -{ - return bBroadcast; -} - - -void LinkMessage::setFromID( int id ) -{ - nFromLinkID = id; -} - -int LinkMessage::getFromID() -{ - return nFromLinkID; -} - -void LinkMessage::setToID( int id ) -{ - nTargetLinkID = id; -} - -int LinkMessage::getToID() -{ - return nTargetLinkID; -} -*/ diff --git a/src/old/linkmessage.h b/src/old/linkmessage.h deleted file mode 100644 index 6cdfb2f..0000000 --- a/src/old/linkmessage.h +++ /dev/null @@ -1,39 +0,0 @@ -/**\file linkmessage.h - */ - -#ifndef LINKMESSAGE_H -#define LINKMESSAGE_H - -/** - * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally - * one would make a subclass of this in order to transmit more useful - * information, but sometimes it isn't necesarry. - *@author Mike Buland - */ -class LinkMessage -{ -public: - /** - * Construct a blank LinkMessage. - */ - LinkMessage() {}; - - /** - * Deconstruct a LinkMessage. - */ - virtual ~LinkMessage(); - - /** - * Create a LinkMessage object with a specific message assosiated with it - * to start with. - *@param nNewMsg The message to use in the Message object. - */ - LinkMessage( int nNewMsg ); - - /** - * The message contained in the Message object. - */ - int nMsg; -}; - -#endif diff --git a/src/old/plugger.cpp b/src/old/plugger.cpp deleted file mode 100644 index f3bfa67..0000000 --- a/src/old/plugger.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "plugger.h" diff --git a/src/old/plugger.h b/src/old/plugger.h deleted file mode 100644 index d92f194..0000000 --- a/src/old/plugger.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef PLUGGER_H -#define PLUGGER_H - - -#include "hashtable.h" -#include "list" -#include "hashfunctionstring.h" -#include "hashfunctionint.h" -#include "dlfcn.h" -#include "exceptions.h" - -typedef struct PluginInfo -{ - const char *sID; - const char *sAuthor; - unsigned short nVersion; - unsigned short nRevision; - void *(*createPlugin)(); - void (*destroyPlugin)( void * ); -} PluginInfo; - -typedef struct PluginReg -{ - bool bBuiltin; - void *dlHandle; - PluginInfo *pInfo; -} PluginReg; - -#define PluginInterface( classname, baseclass, name, ver, rev ) \ -extern "C" { \ - baseclass *create ##classname() \ - { \ - return new classname(); \ - } \ - void destroy ##classname( baseclass *pCls ) \ - { \ - delete pCls; \ - } \ - PluginInfo classname = { \ - #classname, name, ver, rev, \ - create ##classname, destroy ##classname }; \ -} - -#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ -extern "C" { \ - baseclass *create ##classname() \ - { \ - return new classname(); \ - } \ - void destroy ##classname( baseclass *pCls ) \ - { \ - delete pCls; \ - } \ - PluginInfo pluginname = { \ - #pluginname, name, ver, rev, \ - (void *(*)())(create ##classname), \ - (void (*)( void * ))(destroy ##classname) }; \ -} - -#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ -extern "C" { \ - baseclass *create ##classname() \ - { \ - return new classname(); \ - } \ - void destroy ##classname( baseclass *pCls ) \ - { \ - delete pCls; \ - } \ - PluginInfo structname = { \ - #pluginname, name, ver, rev, \ - (void *(*)())(create ##classname), \ - (void (*)( void * ))(destroy ##classname) }; \ -} - -template -class Plugger -{ -public: - -public: - Plugger() : - hPlugin( new HashFunctionString(), 11 ), - hObj( new HashFunctionInt(), 11 ) - { - } - - virtual ~Plugger() - { - void *pos = hObj.getFirstItemPos(); - while( (pos = hObj.getNextItemPos( pos )) ) - { - T *pPlug = (T *)hObj.getItemID( pos ); - PluginReg *pReg = (PluginReg *)hObj.getItemData( pos ); - pReg->pInfo->destroyPlugin( pPlug ); - } - - std::list::iterator i; - for( i = lPlugin.begin(); i != lPlugin.end(); i++ ) - { - if( (*i)->bBuiltin == false ) - { - dlclose( (*i)->dlHandle ); - } - delete (*i); - } - } - - void registerBuiltinPlugin( PluginInfo *pInfo ) - { - PluginReg *pReg = new PluginReg; - pReg->bBuiltin = true; - pReg->pInfo = pInfo; - lPlugin.insert( lPlugin.end(), pReg ); - hPlugin.insert( pInfo->sID, pReg ); - } - - void registerExternalPlugin( const char *sFName, const char *sPluginName ) - { - PluginReg *pReg = (PluginReg *)hPlugin[sPluginName]; - if( pReg != NULL ) - { - hPlugin.del( sPluginName ); - dlclose( pReg->dlHandle ); - delete pReg; - pReg = NULL; - } - - pReg = new PluginReg; - - pReg->bBuiltin = false; - pReg->dlHandle = dlopen( sFName, RTLD_NOW ); - if( pReg->dlHandle == NULL ) - { - throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); - } - pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); - if( pReg->pInfo == NULL ) - { - throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); - } - hPlugin.insert( pReg->pInfo->sID, pReg ); - lPlugin.insert( lPlugin.end(), pReg ); - } - - T *instantiate( const char *lpName ) - { - PluginReg *pReg = (PluginReg *)hPlugin[lpName]; - if( pReg == NULL ) - return NULL; - - T *p = (T *)pReg->pInfo->createPlugin(); - hObj.insert( p, pReg ); - //printf("pReg: %08X, pPlug: %08X\n", pReg, p ); - - return p; - } - - bool hasPlugin( const char *lpName ) - { - if( hPlugin[lpName] == NULL ) - return false; - return true; - } - - void destroy( T *pPlug ) - { - PluginReg *pReg = (PluginReg *)hObj[pPlug]; - //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); - if( pReg == NULL ) - return; - - pReg->pInfo->destroyPlugin( pPlug ); - - hObj.del( pPlug ); - } - - void unloadAll() - { - std::list::iterator i; - for( i = lPlugin.begin(); i != lPlugin.end(); i++ ) - { - if( (*i)->bBuiltin == false ) - { - dlclose( (*i)->dlHandle ); - } - delete (*i); - } - hPlugin.clear(); - } - -private: - std::list lPlugin; - HashTable hPlugin; - HashTable hObj; -}; - -#endif diff --git a/src/old/programchain.cpp b/src/old/programchain.cpp deleted file mode 100644 index 6120d58..0000000 --- a/src/old/programchain.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include "programchain.h" - -ProgramChain::ProgramChain() : - xLog( MultiLog::getInstance() ) -{ - xLog.LineLog( MultiLog::LStatus, "Program Chain Initialized." ); -} - -ProgramChain::~ProgramChain() -{ -} - -bool ProgramChain::addLink( ProgramLink *pLink ) -{ - if( pLink->init() == false ) - { - emergencyShutdown(); - return false; - } - - lLink.append( pLink ); - - pLink->setChain( this ); - - return true; -} - -ProgramLink *ProgramChain::getLink( const char *lpName ) -{ - char a; - a = lpName[0]; - return NULL; -} - -ProgramLink *ProgramChain::getBaseLink() -{ - return NULL; -} - -bool ProgramChain::execChainOnce() -{ - int nLen = lLink.getSize(); - for( int j = 0; j < nLen; j++ ) - { - if( ((ProgramLink *)lLink[j])->timeSlice() == false ) - { - xLog.LineLog( MultiLog::LInfo, "Shutting down due to signal from link #%d", j ); - emergencyShutdown(); - return false; - } - } - - return true; -} - -bool ProgramChain::enterChainLoop() -{ - for(;;) - { - if( execChainOnce() == false ) - { - return false; - } - } - - return true; -} - -void ProgramChain::emergencyShutdown() -{ - int nLen = lLink.getSize(); - for( int j = 0; j < nLen; j++ ) - { - ((ProgramLink *)lLink[j])->deInit(); - delete (ProgramLink *)lLink[j]; - } - lLink.empty(); -} - -LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) -{ - int nLen = lLink.getSize(); - for( int j = 0; j < nLen; j++ ) - { - LinkMessage *pMsg = ((ProgramLink *)lLink[j])->processIRM( pMsgOut ); - if( pMsg != NULL ) - { - delete pMsgOut; - return pMsg; - } - } - - delete pMsgOut; - return NULL; -} diff --git a/src/old/programchain.h b/src/old/programchain.h deleted file mode 100644 index 2bdfeee..0000000 --- a/src/old/programchain.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef PROGRAMCHAIN_H -#define PROGRAMCHAIN_H - -#include "linkedlist.h" -#include "multilog.h" -#include "programlink.h" - -/** - * The Program Chain links together program "chunks" to more easily facilitate - * a generalized program loop with modular extensions. - *@author Mike Buland - */ -class ProgramChain -{ -public: - /** - * Construct an empty chain. - */ - ProgramChain(); - - /** - * Destroy your chain. - */ - virtual ~ProgramChain(); - - /** - * Adds a link to the end of the chain. - *@param pLink A pointer to the link to add to the chain. - *@returns True if adding the link was successful, otherwise false - *@author Mike Buland - */ - bool addLink( ProgramLink *pLink ); - - /** - * Gets a link by name. - *@param lpName The name of the link you're looking for. Every link has a - * name, apparently. - *@returns A pointer to the specified ProgramLink, or NULL if none were - * found matching your criteria. - *@author Mike Buland - */ - class ProgramLink *getLink( const char *lpName ); - - /** - * Gets the very first link in the chain. - *@returns A pointer to the first link in the chain. - *@author Mike Buland - */ - class ProgramLink *getBaseLink(); - - /** - * Runs through the chain once. Useful if you want to have more control - * over the operation of the chain. - *@returns true if every link returned true. If at least one link returns - * false, then returns false. - *@author Mike Buland - */ - bool execChainOnce(); - - /** - * Enters the master chain loop, looping over the entire chain and - * executing every link's TimeSlice routine in order, over and over, until - * a link returns a false value. - *@returns False, always. It returns true unless a link returned false, - * but loops until a link does return false. - *@author Mike Buland - **/ - bool enterChainLoop(); - - /** - * Broadcasts an Immediate Response Message to all active links, save the - * sender. Whatever link first responds with a non-null response message - * will have it's messages sent back to the broadcasting link as the returns - * of this function call. Therefore it is very important that all message - * processing code is handled in a fairly timely fasion. - *@param pMsgOut The message to broadcast in hopes of a response. - *@param pSender The message that sent out the message and doesn't want to - * receive it's own message. This should always just be "this". - *@returns The message that was returned by the first link to return a - * non-null response. If all messages return null responses then this also - * returns null. Please note that whoever calls this will be responsible - * for deleting the message returned by it, if non-null. - */ - class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); - -private: - /** - * Shuts down all operation no matter what point in the operation we were. - */ - void emergencyShutdown(); - MultiLog &xLog; /**< A reference to the log. */ - LinkedList lLink; /**< The linked list that contains all of the links. */ -}; - -#endif diff --git a/src/old/programlink.cpp b/src/old/programlink.cpp deleted file mode 100644 index 21c6fe4..0000000 --- a/src/old/programlink.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "programlink.h" -#include "programchain.h" - -ProgramLink::ProgramLink() -{ -} - -ProgramLink::~ProgramLink() -{ -} - -LinkMessage *ProgramLink::sendIRM( LinkMessage *pMsgOut ) -{ - return pChain->broadcastIRM( pMsgOut, this ); -} - -void ProgramLink::setChain( ProgramChain *pNewChain ) -{ - pChain = pNewChain; -} - -/* -void ProgramLink::postMessage( LinkMessage *pMsg, int nLvl ) -{ - if( nLvl == msgToChain ) - { - qMsgToChain.enqueue( pMsg ); - } - else if( nLvl == msgToLink ) - { - qMsgToLink.enqueue( pMsg ); - } - else - { - // ERROR! - } -} - -LinkMessage *ProgramLink::getMessage( int nLvl ) -{ - if( nLvl == msgToChain ) - { - return (LinkMessage *)qMsgToChain.dequeue(); - } - else if( nLvl == msgToLink ) - { - return (LinkMessage *)qMsgToLink.dequeue(); - } - else - { - // ERROR! - } -} -*/ diff --git a/src/old/programlink.h b/src/old/programlink.h deleted file mode 100644 index f93edcc..0000000 --- a/src/old/programlink.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef PROGRAMLINK_H -#define PROGRAMLINK_H - -class ProgramLink; -#include "queue.h" -#include "linkmessage.h" -#include "programchain.h" - -/** - * Program Link is the base class for any object that will be a piece of the - * main program chain loop. - *@author Mike Buland - */ -class ProgramLink -{ -friend class ProgramChain; -public: - /** - * Construct a program link. - */ - ProgramLink(); - - /** - * Deconstruct. - */ - virtual ~ProgramLink(); - - /** - * Initialization code required for a link that wasn't performed in the - * constructor. - *@returns true if initialization was successful. A false value will halt - * the chain. - */ - virtual bool init()=0; - - /** - * DeInitialization code that should happen, but doesn't belong in the - * destructor. - *@returns true means everything worked, false means failure, but is - * meaningless. - */ - virtual bool deInit()=0; - - /** - * Executed once per link per chain pass. Contains the guts of the program. - *@returns true if everything went well. A false value will halt the chain. - */ - virtual bool timeSlice()=0; - - /** - * This must be handled in order to process Instant Response Messages. - * This function should return null on all messages that it doesn't - * understand how to handle, and construct new messages to return to sender - * in the cases where it does understand. - *@param pMsgIn The message that must be processed. - *@returns Either a new message in cases where a response is required, - * or null if nothing needs to be done by this link. - */ - virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; - - /** - * Broadcast a LinkMessage to all other links in the system. Each other - * link will get a call of their processIRM function. If the message gets - * a response then you will regain control immediately, otherwise the system - * will give all other Links a chance to respond before returning NULL. - *@param pMsgOut The message to broadcast. - *@returns The message response, or NULL if no Link understood your message. - */ - LinkMessage *sendIRM( LinkMessage *pMsgOut ); - -private: - /** - * Set which chain we're assosiated with. This is how IRM messages make - * it out to the rest of the world. - *@param pNewChain A pointer to the containing program chain. - */ - void setChain( class ProgramChain *pNewChain ); - - /** - * The pointer to the containing chain. - */ - class ProgramChain *pChain; -/* - void postMessage( LinkMessage *pMsg, int nLvl ); - LinkMessage *getMessage( int nLvl ); - - enum - { - msgToChain, - msgToLink - }; - -private: - Queue qMsgToChain; - Queue qMsgToLink; -*/ -}; - -#endif diff --git a/src/plugger.cpp b/src/plugger.cpp new file mode 100644 index 0000000..f3bfa67 --- /dev/null +++ b/src/plugger.cpp @@ -0,0 +1 @@ +#include "plugger.h" diff --git a/src/plugger.h b/src/plugger.h new file mode 100644 index 0000000..98d4ecc --- /dev/null +++ b/src/plugger.h @@ -0,0 +1,196 @@ +#ifndef PLUGGER_H +#define PLUGGER_H + + +#include "bu/hash.h" +#include "bu/list.h" +#include +#include "bu/exceptions.h" +#include "bu/fstring.h" + +namespace Bu +{ + typedef struct PluginInfo + { + const char *sID; + const char *sAuthor; + unsigned short nVersion; + unsigned short nRevision; + void *(*createPlugin)(); + void (*destroyPlugin)( void * ); + } PluginInfo; + + typedef struct PluginReg + { + bool bBuiltin; + void *dlHandle; + PluginInfo *pInfo; + } PluginReg; + +#define PluginInterface( classname, baseclass, name, ver, rev ) \ + extern "C" { \ + baseclass *create ##classname() \ + { \ + return new classname(); \ + } \ + void destroy ##classname( baseclass *pCls ) \ + { \ + delete pCls; \ + } \ + PluginInfo classname = { \ + #classname, name, ver, rev, \ + create ##classname, destroy ##classname }; \ + } + +#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ + extern "C" { \ + baseclass *create ##classname() \ + { \ + return new classname(); \ + } \ + void destroy ##classname( baseclass *pCls ) \ + { \ + delete pCls; \ + } \ + PluginInfo pluginname = { \ + #pluginname, name, ver, rev, \ + (void *(*)())(create ##classname), \ + (void (*)( void * ))(destroy ##classname) }; \ + } + +#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ + extern "C" { \ + baseclass *create ##classname() \ + { \ + return new classname(); \ + } \ + void destroy ##classname( baseclass *pCls ) \ + { \ + delete pCls; \ + } \ + PluginInfo structname = { \ + #pluginname, name, ver, rev, \ + (void *(*)())(create ##classname), \ + (void (*)( void * ))(destroy ##classname) }; \ + } + + template + class Plugger + { + public: + typedef Bu::Hash PluginHash; + typedef Bu::Hash InstHash; + + public: + Plugger() + { + } + + virtual ~Plugger() + { + for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ ) + { + T *pPlug = (T *)i.getKey(); + PluginReg *pReg = (PluginReg *)*i; + pReg->pInfo->destroyPlugin( pPlug ); + } + + for( PluginHash::iterator i = hPlugin.begin(); + i != hPlugin.end(); i++ ) + { + if( (*i)->bBuiltin == false ) + { + dlclose( (*i)->dlHandle ); + } + delete (*i); + } + } + + void registerBuiltinPlugin( PluginInfo *pInfo ) + { + PluginReg *pReg = new PluginReg; + pReg->bBuiltin = true; + pReg->pInfo = pInfo; + hPlugin.insert( pInfo->sID, pReg ); + } + + void registerExternalPlugin( const char *sFName, const char *sPluginName ) + { + PluginReg *pReg = (PluginReg *)hPlugin[sPluginName]; + if( pReg != NULL ) + { + hPlugin.erase( sPluginName ); + dlclose( pReg->dlHandle ); + delete pReg; + pReg = NULL; + } + + pReg = new PluginReg; + + pReg->bBuiltin = false; + pReg->dlHandle = dlopen( sFName, RTLD_NOW ); + if( pReg->dlHandle == NULL ) + { + throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); + } + pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); + if( pReg->pInfo == NULL ) + { + throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); + } + hPlugin.insert( pReg->pInfo->sID, pReg ); + } + + T *instantiate( const char *lpName ) + { + PluginReg *pReg = (PluginReg *)hPlugin[lpName]; + if( pReg == NULL ) + return NULL; + + T *p = (T *)pReg->pInfo->createPlugin(); + hObj.insert( p, pReg ); + //printf("pReg: %08X, pPlug: %08X\n", pReg, p ); + + return p; + } + + bool hasPlugin( const char *lpName ) + { + if( hPlugin[lpName] == NULL ) + return false; + return true; + } + + void destroy( T *pPlug ) + { + PluginReg *pReg = (PluginReg *)hObj[pPlug]; + //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); + if( pReg == NULL ) + return; + + pReg->pInfo->destroyPlugin( pPlug ); + + hObj.erase( pPlug ); + } + + void unloadAll() + { + for( PluginHash::iterator i = hPlugin.begin(); + i != hPlugin.end(); i++ ) + { + if( (*i)->bBuiltin == false ) + { + dlclose( (*i)->dlHandle ); + } + delete (*i); + } + hPlugin.clear(); + } + + private: + PluginHash hPlugin; + InstHash hObj; + }; +} + +#endif diff --git a/src/programchain.cpp b/src/programchain.cpp new file mode 100644 index 0000000..0bb7a77 --- /dev/null +++ b/src/programchain.cpp @@ -0,0 +1,97 @@ +#include +#include "bu/programchain.h" +#include "bu/programlink.h" + +using namespace Bu; + +Bu::ProgramChain::ProgramChain() +{ +} + +Bu::ProgramChain::~ProgramChain() +{ +} + +bool Bu::ProgramChain::addLink( ProgramLink *pLink ) +{ + if( pLink->init() == false ) + { + emergencyShutdown(); + return false; + } + + lLink.append( pLink ); + + pLink->setChain( this ); + + return true; +} + +ProgramLink *Bu::ProgramChain::getLink( const char *lpName ) +{ + char a; + a = lpName[0]; + return NULL; +} + +ProgramLink *Bu::ProgramChain::getBaseLink() +{ + return NULL; +} + +bool Bu::ProgramChain::execChainOnce() +{ + for( Bu::List::iterator i = lLink.begin(); + i != lLink.end(); i++ ) + { + if( (*i)->timeSlice() == false ) + { + emergencyShutdown(); + return false; + } + } + + return true; +} + +bool Bu::ProgramChain::enterChainLoop() +{ + for(;;) + { + if( execChainOnce() == false ) + { + return false; + } + } + + return true; +} + +void Bu::ProgramChain::emergencyShutdown() +{ + for( Bu::List::iterator i = lLink.begin(); + i != lLink.end(); i++ ) + { + (*i)->deInit(); + delete *i; + } + lLink.clear(); +} + +LinkMessage *Bu::ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) +{ + for( Bu::List::iterator i = lLink.begin(); + i != lLink.end(); i++ ) + { + LinkMessage *pMsg = (*i)->processIRM( pMsgOut ); + if( pMsg != NULL ) + { + delete pMsgOut; + return pMsg; + } + } + + delete pMsgOut; + return NULL; +} + diff --git a/src/programchain.h b/src/programchain.h new file mode 100644 index 0000000..e73d659 --- /dev/null +++ b/src/programchain.h @@ -0,0 +1,98 @@ +#ifndef PROGRAMCHAIN_H +#define PROGRAMCHAIN_H + +#include "bu/list.h" +#include "bu/linkmessage.h" + +namespace Bu +{ + class ProgramLink; + /** + * The Program Chain links together program "chunks" to more easily facilitate + * a generalized program loop with modular extensions. + *@author Mike Buland + */ + class ProgramChain + { + public: + /** + * Construct an empty chain. + */ + ProgramChain(); + + /** + * Destroy your chain. + */ + virtual ~ProgramChain(); + + /** + * Adds a link to the end of the chain. + *@param pLink A pointer to the link to add to the chain. + *@returns True if adding the link was successful, otherwise false + *@author Mike Buland + */ + bool addLink( Bu::ProgramLink *pLink ); + + /** + * Gets a link by name. + *@param lpName The name of the link you're looking for. Every link has a + * name, apparently. + *@returns A pointer to the specified ProgramLink, or NULL if none were + * found matching your criteria. + *@author Mike Buland + */ + class ProgramLink *getLink( const char *lpName ); + + /** + * Gets the very first link in the chain. + *@returns A pointer to the first link in the chain. + *@author Mike Buland + */ + class ProgramLink *getBaseLink(); + + /** + * Runs through the chain once. Useful if you want to have more control + * over the operation of the chain. + *@returns true if every link returned true. If at least one link returns + * false, then returns false. + *@author Mike Buland + */ + bool execChainOnce(); + + /** + * Enters the master chain loop, looping over the entire chain and + * executing every link's TimeSlice routine in order, over and over, until + * a link returns a false value. + *@returns False, always. It returns true unless a link returned false, + * but loops until a link does return false. + *@author Mike Buland + **/ + bool enterChainLoop(); + + /** + * Broadcasts an Immediate Response Message to all active links, save the + * sender. Whatever link first responds with a non-null response message + * will have it's messages sent back to the broadcasting link as the returns + * of this function call. Therefore it is very important that all message + * processing code is handled in a fairly timely fasion. + *@param pMsgOut The message to broadcast in hopes of a response. + *@param pSender The message that sent out the message and doesn't want to + * receive it's own message. This should always just be "this". + *@returns The message that was returned by the first link to return a + * non-null response. If all messages return null responses then this also + * returns null. Please note that whoever calls this will be responsible + * for deleting the message returned by it, if non-null. + */ + class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); + + private: + /** + * Shuts down all operation no matter what point in the operation we were. + */ + void emergencyShutdown(); + Bu::List lLink; /**< The linked list that contains all of the links. */ + }; +} + + +#endif diff --git a/src/programlink.cpp b/src/programlink.cpp new file mode 100644 index 0000000..e5c624c --- /dev/null +++ b/src/programlink.cpp @@ -0,0 +1,56 @@ +#include "bu/programlink.h" +#include "bu/programchain.h" + +using namespace Bu; + +Bu::ProgramLink::ProgramLink() +{ +} + +Bu::ProgramLink::~ProgramLink() +{ +} + +LinkMessage *Bu::ProgramLink::sendIRM( LinkMessage *pMsgOut ) +{ + return pChain->broadcastIRM( pMsgOut, this ); +} + +void Bu::ProgramLink::setChain( ProgramChain *pNewChain ) +{ + pChain = pNewChain; +} + +/* +void ProgramLink::postMessage( LinkMessage *pMsg, int nLvl ) +{ + if( nLvl == msgToChain ) + { + qMsgToChain.enqueue( pMsg ); + } + else if( nLvl == msgToLink ) + { + qMsgToLink.enqueue( pMsg ); + } + else + { + // ERROR! + } +} + +LinkMessage *ProgramLink::getMessage( int nLvl ) +{ + if( nLvl == msgToChain ) + { + return (LinkMessage *)qMsgToChain.dequeue(); + } + else if( nLvl == msgToLink ) + { + return (LinkMessage *)qMsgToLink.dequeue(); + } + else + { + // ERROR! + } +} +*/ diff --git a/src/programlink.h b/src/programlink.h new file mode 100644 index 0000000..7c31a18 --- /dev/null +++ b/src/programlink.h @@ -0,0 +1,100 @@ +#ifndef PROGRAMLINK_H +#define PROGRAMLINK_H + +#include "bu/linkmessage.h" +#include "bu/programchain.h" + +namespace Bu +{ + /** + * Program Link is the base class for any object that will be a piece of the + * main program chain loop. + *@author Mike Buland + */ + class ProgramLink + { + friend class Bu::ProgramChain; + public: + /** + * Construct a program link. + */ + ProgramLink(); + + /** + * Deconstruct. + */ + virtual ~ProgramLink(); + + /** + * Initialization code required for a link that wasn't performed in the + * constructor. + *@returns true if initialization was successful. A false value will halt + * the chain. + */ + virtual bool init()=0; + + /** + * DeInitialization code that should happen, but doesn't belong in the + * destructor. + *@returns true means everything worked, false means failure, but is + * meaningless. + */ + virtual bool deInit()=0; + + /** + * Executed once per link per chain pass. Contains the guts of the program. + *@returns true if everything went well. A false value will halt the chain. + */ + virtual bool timeSlice()=0; + + /** + * This must be handled in order to process Instant Response Messages. + * This function should return null on all messages that it doesn't + * understand how to handle, and construct new messages to return to sender + * in the cases where it does understand. + *@param pMsgIn The message that must be processed. + *@returns Either a new message in cases where a response is required, + * or null if nothing needs to be done by this link. + */ + virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; + + /** + * Broadcast a LinkMessage to all other links in the system. Each other + * link will get a call of their processIRM function. If the message gets + * a response then you will regain control immediately, otherwise the system + * will give all other Links a chance to respond before returning NULL. + *@param pMsgOut The message to broadcast. + *@returns The message response, or NULL if no Link understood your message. + */ + LinkMessage *sendIRM( LinkMessage *pMsgOut ); + + private: + /** + * Set which chain we're assosiated with. This is how IRM messages make + * it out to the rest of the world. + *@param pNewChain A pointer to the containing program chain. + */ + void setChain( class ProgramChain *pNewChain ); + + /** + * The pointer to the containing chain. + */ + class ProgramChain *pChain; + /* + void postMessage( LinkMessage *pMsg, int nLvl ); + LinkMessage *getMessage( int nLvl ); + + enum + { + msgToChain, + msgToLink + }; + + private: + Queue qMsgToChain; + Queue qMsgToLink; + */ + }; +} + +#endif diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp index 3e6c025..ac42d3d 100644 --- a/src/tafwriter.cpp +++ b/src/tafwriter.cpp @@ -1,9 +1,32 @@ #include "tafwriter.h" -Bu::TafWriter::TafWriter() +Bu::TafWriter::TafWriter( Bu::Stream &sOut ) : + sOut( sOut ) { } Bu::TafWriter::~TafWriter() { } + +void Bu::TafWriter::writeNode( Bu::TafNode *pRoot ) +{ + sOut.write("{", 1 ); + writeString( pRoot->getName().getStr() ); + sOut.write(": ", 2 ); + sOut.write("}", 1 ); +} + +void Bu::TafWriter::writeString( const Bu::FString &str ) +{ + sOut.write("\"", 1 ); + for( const char *s = str.getStr(); *s; s++ ) + { + if( *s == '\"' ) + sOut.write("\\\"", 2 ); + else + sOut.write( s, 1 ); + } + sOut.write("\"", 1 ); +} + diff --git a/src/tafwriter.h b/src/tafwriter.h index 7057d62..4310e62 100644 --- a/src/tafwriter.h +++ b/src/tafwriter.h @@ -2,6 +2,9 @@ #define BU_TAF_WRITER_H #include +#include "bu/tafnode.h" +#include "bu/stream.h" +#include "bu/fstring.h" namespace Bu { @@ -11,11 +14,14 @@ namespace Bu class TafWriter { public: - TafWriter(); + TafWriter( Bu::Stream &sOut ); virtual ~TafWriter(); - private: + void writeNode( Bu::TafNode *pRoot ); + private: + void writeString( const Bu::FString &str ); + Bu::Stream &sOut; }; } -- cgit v1.2.3 From c86c0cf088492e02431dffb1f860ff2f6faa492d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 27 Jun 2007 18:11:13 +0000 Subject: The taf system is new and improved. The writer works, we added C++ style comment blocks, and it retains the order of all nodes. --- src/tafnode.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++------------ src/tafnode.h | 68 +++++++++++++++++++++++---- src/tafreader.cpp | 44 +++++++++++------ src/tafreader.h | 9 ++-- src/tafwriter.cpp | 42 ++++++++++++++++- src/tafwriter.h | 4 +- src/tests/taf.cpp | 13 +++-- src/unit/taf.cpp | 2 +- test.taf | 31 +++--------- 9 files changed, 260 insertions(+), 91 deletions(-) (limited to 'src/tafwriter.h') diff --git a/src/tafnode.cpp b/src/tafnode.cpp index b9a4a24..b7cf211 100644 --- a/src/tafnode.cpp +++ b/src/tafnode.cpp @@ -1,72 +1,148 @@ #include "tafnode.h" -Bu::TafNode::TafNode() +Bu::TafNode::TafNode( NodeType eType ) : + eType( eType ) { } Bu::TafNode::~TafNode() +{ +} + +const Bu::TafNode::NodeType Bu::TafNode::getType() const +{ + return eType; +} + +/* +const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const +{ + return hProp.get( sName ); +} + +const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const +{ + return hChildren.get( sName ); +} + +const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const +{ + return getProperties( sName ).first(); +} + +const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const +{ + return getChildren( sName ).first(); +} +*/ + +Bu::TafGroup::TafGroup( const Bu::FString &sName ) : + TafNode( typeGroup ), + sName( sName ) +{ +} + +Bu::TafGroup::~TafGroup() { //printf("Entering Bu::TafNode::~TafNode() \"%s\"\n", sName.getStr() ); - for( NodeHash::iterator i = hChildren.begin(); i != hChildren.end(); i++ ) + for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ ) { - NodeList &l = i.getValue(); - for( NodeList::iterator k = l.begin(); k != l.end(); k++ ) - { - //printf("deleting: [%08X] %s\n", *k, "" );//(*k)->getName().getStr() ); - delete (*k); - } + delete (*i); } } -void Bu::TafNode::setProperty( Bu::FString sName, Bu::FString sValue ) +const Bu::FString &Bu::TafGroup::getName() const { - if( !hProp.has( sName ) ) + return sName; +} + +void Bu::TafGroup::addChild( Bu::TafNode *pNode ) +{ + switch( pNode->getType() ) { - hProp.insert( sName, PropList() ); + case typeGroup: + { + TafGroup *pGroup = (TafGroup *)pNode; + if( !hChildren.has( pGroup->getName() ) ) + hChildren.insert( pGroup->getName(), GroupList() ); + hChildren.get( pGroup->getName() ).append( pGroup ); + } + break; + + case typeProperty: + { + TafProperty *pProperty = (TafProperty *)pNode; + if( !hProp.has( pProperty->getName() ) ) + hProp.insert( pProperty->getName(), PropList() ); + hProp.get( pProperty->getName() ).append( pProperty->getValue() ); + } + break; + + case typeComment: + break; } - hProp.get( sName ).append( sValue ); + lChildren.append( pNode ); } -void Bu::TafNode::addChild( TafNode *pNode ) +const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const { - if( !hChildren.has( pNode->getName() ) ) - { - hChildren.insert( pNode->getName(), NodeList() ); - } + return hChildren.get( sName ); +} - //printf("Appending \"%s\"\n", pNode->getName().getStr() ); - hChildren.get( pNode->getName() ).append( pNode ); - //printf("[%08X]\n", hChildren.get( pNode->getName() ).last() ); +const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const +{ + return lChildren; } -const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const +const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const { - return hProp.get( sName ); + return hChildren.get( sName ).first(); } -const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const +const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const { - return hChildren.get( sName ); + return hProp.get( sName ); } -const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const +const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const { - return getProperties( sName ).first(); + return hProp.get( sName ).first(); } -const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const +Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) : + TafNode( typeProperty ), + sName( sName ), + sValue( sValue ) { - return getChildren( sName ).first(); } -void Bu::TafNode::setName( const Bu::FString &sName ) +Bu::TafProperty::~TafProperty() { - this->sName = sName; } -const Bu::FString &Bu::TafNode::getName() const +const Bu::FString &Bu::TafProperty::getName() const { return sName; } +const Bu::FString &Bu::TafProperty::getValue() const +{ + return sValue; +} + +Bu::TafComment::TafComment( const Bu::FString &sText ) : + TafNode( typeComment ), + sText( sText ) +{ +} + +Bu::TafComment::~TafComment() +{ +} + +const Bu::FString &Bu::TafComment::getText() const +{ + return sText; +} + diff --git a/src/tafnode.h b/src/tafnode.h index 08f78e8..55a5123 100644 --- a/src/tafnode.h +++ b/src/tafnode.h @@ -14,29 +14,77 @@ namespace Bu class TafNode { public: - typedef Bu::List PropList; - typedef Bu::Hash PropHash; - typedef Bu::List NodeList; - typedef Bu::Hash NodeHash; + enum NodeType + { + typeGroup, + typeProperty, + typeComment + }; public: - TafNode(); + TafNode( NodeType eType ); virtual ~TafNode(); - void setName( const Bu::FString &sName ); + const NodeType getType() const; + + private: + NodeType eType; + }; + + class TafProperty; + class TafComment; + class TafGroup : public TafNode + { + public: + typedef Bu::List PropList; + typedef Bu::Hash PropHash; + typedef Bu::List GroupList; + typedef Bu::Hash GroupHash; + typedef Bu::List NodeList; + + TafGroup( const Bu::FString &sName ); + virtual ~TafGroup(); + const Bu::FString &getName() const; - void setProperty( Bu::FString sName, Bu::FString sValue ); const Bu::FString &getProperty( const Bu::FString &sName ) const; const PropList &getProperties( const Bu::FString &sName ) const; - const TafNode *getChild( const Bu::FString &sName ) const; - const NodeList &getChildren( const Bu::FString &sName ) const; + const TafGroup *getChild( const Bu::FString &sName ) const; + const GroupList &getChildren( const Bu::FString &sName ) const; void addChild( TafNode *pNode ); + const NodeList &getChildren() const; private: Bu::FString sName; PropHash hProp; - NodeHash hChildren; + GroupHash hChildren; + NodeList lChildren; + }; + + class TafProperty : public TafNode + { + public: + TafProperty( const Bu::FString &sName, const Bu::FString &sValue ); + virtual ~TafProperty(); + + const Bu::FString &getName() const; + const Bu::FString &getValue() const; + + private: + Bu::FString sName; + Bu::FString sValue; + }; + + class TafComment : public TafNode + { + public: + TafComment( const Bu::FString &sText ); + virtual ~TafComment(); + + const Bu::FString &getText() const; + + private: + Bu::FString sText; }; } diff --git a/src/tafreader.cpp b/src/tafreader.cpp index 1187176..db465e9 100644 --- a/src/tafreader.cpp +++ b/src/tafreader.cpp @@ -8,6 +8,7 @@ Bu::TafReader::TafReader( Bu::Stream &sIn ) : c( 0 ), sIn( sIn ) { + next(); next(); } Bu::TafReader::~TafReader() @@ -15,60 +16,74 @@ Bu::TafReader::~TafReader() } -Bu::TafNode *Bu::TafReader::getNode() +Bu::TafGroup *Bu::TafReader::readGroup() { - if( c == 0 ) next(); - TafNode *pNode = new TafNode(); ws(); if( c != '{' ) throw TafException("Expected '{'"); next(); ws(); FString sName = readStr(); - pNode->setName( sName ); + TafGroup *pGroup = new TafGroup( sName ); next(); //printf("Node[%s]:\n", sName.getStr() ); - nodeContent( pNode ); + groupContent( pGroup ); if( c != '}' ) throw TafException("Expected '}'"); next(); - return pNode; + return pGroup; } -void Bu::TafReader::nodeContent( Bu::TafNode *pNode ) +void Bu::TafReader::groupContent( Bu::TafGroup *pGroup ) { for(;;) { ws(); if( c == '{' ) - pNode->addChild( getNode() ); + pGroup->addChild( readGroup() ); else if( c == '}' ) return; + else if( c == '/' && la == '*' ) + pGroup->addChild( readComment() ); else - nodeProperty( pNode ); + pGroup->addChild( readProperty() ); } } -void Bu::TafReader::nodeProperty( Bu::TafNode *pNode ) +Bu::TafProperty *Bu::TafReader::readProperty() { FString sName = readStr(); ws(); if( c != '=' ) { //printf(" %s (true)\n", sName.getStr() ); - pNode->setProperty( sName, "" ); - return; + return new Bu::TafProperty( sName, "" ); } next(); FString sValue = readStr(); - pNode->setProperty( sName, sValue ); + return new Bu::TafProperty( sName, sValue ); //printf(" %s = %s\n", sName.getStr(), sValue.getStr() ); } +Bu::TafComment *Bu::TafReader::readComment() +{ + next(); + FString sCmnt; + for(;;) + { + next(); + if( c == '*' && la == '/' ) + break; + sCmnt += c; + } + + return new TafComment( sCmnt ); +} + Bu::FString Bu::TafReader::readStr() { ws(); @@ -134,6 +149,7 @@ bool Bu::TafReader::isws() void Bu::TafReader::next() { - sIn.read( &c, 1 ); + c = la; + sIn.read( &la, 1 ); } diff --git a/src/tafreader.h b/src/tafreader.h index 47ae187..eeaafb3 100644 --- a/src/tafreader.h +++ b/src/tafreader.h @@ -17,16 +17,17 @@ namespace Bu TafReader( Bu::Stream &sIn ); virtual ~TafReader(); - Bu::TafNode *getNode(); + Bu::TafGroup *readGroup(); private: - void nodeContent( Bu::TafNode *pNode ); - void nodeProperty( Bu::TafNode *pNode ); + void groupContent( Bu::TafGroup *pNode ); + Bu::TafProperty *readProperty(); + Bu::TafComment *readComment(); void ws(); bool isws(); void next(); Bu::FString readStr(); - char c; + char c, la; Bu::Stream &sIn; }; } diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp index ac42d3d..6b505ef 100644 --- a/src/tafwriter.cpp +++ b/src/tafwriter.cpp @@ -9,16 +9,54 @@ Bu::TafWriter::~TafWriter() { } -void Bu::TafWriter::writeNode( Bu::TafNode *pRoot ) +void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot ) { sOut.write("{", 1 ); - writeString( pRoot->getName().getStr() ); + writeString( pRoot->getName() ); sOut.write(": ", 2 ); + const Bu::TafGroup::NodeList &nl = pRoot->getChildren(); + for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ ) + { + switch( (*i)->getType() ) + { + case Bu::TafNode::typeGroup: + writeGroup( (Bu::TafGroup *)(*i) ); + break; + + case Bu::TafNode::typeProperty: + writeProperty( (Bu::TafProperty *)(*i) ); + break; + + case Bu::TafNode::typeComment: + writeComment( (Bu::TafComment *)(*i) ); + break; + } + } sOut.write("}", 1 ); } +void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp ) +{ + writeString( pProp->getName() ); + if( pProp->getValue().getStr() != NULL ) + { + sOut.write("=", 1 ); + writeString( pProp->getValue() ); + } + sOut.write(" ", 1 ); +} + +void Bu::TafWriter::writeComment( const Bu::TafComment *pComment ) +{ + sOut.write("/*", 2 ); + sOut.write( pComment->getText().getStr(), pComment->getText().getSize() ); + sOut.write("*/ ", 3 ); +} + void Bu::TafWriter::writeString( const Bu::FString &str ) { + if( str.getStr() == NULL ) + return; sOut.write("\"", 1 ); for( const char *s = str.getStr(); *s; s++ ) { diff --git a/src/tafwriter.h b/src/tafwriter.h index 4310e62..5f80504 100644 --- a/src/tafwriter.h +++ b/src/tafwriter.h @@ -17,9 +17,11 @@ namespace Bu TafWriter( Bu::Stream &sOut ); virtual ~TafWriter(); - void writeNode( Bu::TafNode *pRoot ); + void writeGroup( const Bu::TafGroup *pRoot ); private: + void writeProperty( const Bu::TafProperty *pProp ); + void writeComment( const Bu::TafComment *pComment ); void writeString( const Bu::FString &str ); Bu::Stream &sOut; }; diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp index d135e78..e3da120 100644 --- a/src/tests/taf.cpp +++ b/src/tests/taf.cpp @@ -1,4 +1,5 @@ #include "bu/tafreader.h" +#include "bu/tafwriter.h" #include "bu/file.h" int main() @@ -6,12 +7,18 @@ int main() Bu::File f("test.taf", "rb"); Bu::TafReader tr( f ); - Bu::TafNode *pNode = tr.getNode(); + Bu::TafGroup *pGroup = tr.readGroup(); - const Bu::TafNode *pStats = pNode->getChild("stats"); + const Bu::TafGroup *pStats = pGroup->getChild("stats"); printf("%s\n", pStats->getName().getStr() ); printf(" str = %s\n", pStats->getProperty("str").getStr() ); - delete pNode; + { + Bu::File fo("out.taf", "wb"); + Bu::TafWriter tw( fo ); + tw.writeGroup( pGroup ); + } + + delete pGroup; } diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp index ab485d0..5e0e914 100644 --- a/src/unit/taf.cpp +++ b/src/unit/taf.cpp @@ -32,7 +32,7 @@ public: Bu::File fIn(sFnTmp.c_str(), "rb"); Bu::TafReader tr(fIn); - Bu::TafNode *tn = tr.getNode(); + Bu::TafGroup *tn = tr.readGroup(); unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) ); delete tn; diff --git a/test.taf b/test.taf index 045b042..1d4e7d1 100644 --- a/test.taf +++ b/test.taf @@ -1,26 +1,7 @@ -{player: - password = "aoeuaoeuao" - userclass = "implementor" - species = "human" - sex = "male" - active - startroom = "Salourn::Xagafinelle's Room" - {stats: str=14 dex=12 spd=12 enr=7 rea=12 wil=10 int=13 cha=14} - {hp: cur = 100 max = 100} - {en: cur = 100 max = 100} - attackrate = 30 - gold = 0 - {inventory: - {: count=1 id="Salourn::Dark Blade"} - {: count=1 id="Salourn::Dark Suit"} - {: count=3 id="Salourn::Small Fig"} - } - {aliases: - {: key="." value="say"} - {: key="," value="yell"} - {: key="li" value="lightning"} - } - description = "They appear to be rather average looking, not particularly +{"player": "password"="aoeuaoeuao" "userclass"="implementor" "species"="human" "sex"="male" "active" "startroom"="Salourn::Xagafinelle's Room" {"stats": "str"="14" "dex"="12" "spd"="12" "enr"="7" "rea"="12" "wil"="10" "int"="13" "cha"="14" }{"hp": "cur"="100" "max"="100" }{"en": "cur"="100" "max"="100" }"attackrate"="30" "gold"="0" + + /* Hey, the inventory is next...isn't that cool? Oooooh yeah! */ + +{"inventory": {: "count"="1" "id"="Salourn::Dark Blade" }{: "count"="1" "id"="Salourn::Dark Suit" }{: "count"="3" "id"="Salourn::Small Fig" }}{"aliases": {: "key"="." "value"="say" }{: "key"="," "value"="yell" }{: "key"="li" "value"="lightning" }}"description"="They appear to be rather average looking, not particularly tall or short, with facial features that are difficult to remember even - seconds after witnessing them." -} + seconds after witnessing them." } -- cgit v1.2.3