From 070374dde0f53bff26078550997f7682e84412e5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 20:16:19 +0000 Subject: I did it, the streams don't start with an S now. --- src/file.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/file.cpp (limited to 'src/file.cpp') diff --git a/src/file.cpp b/src/file.cpp new file mode 100644 index 0000000..5de5f6c --- /dev/null +++ b/src/file.cpp @@ -0,0 +1,100 @@ +#include "file.h" +#include "exceptions.h" +#include + +Bu::File::File( const char *sName, const char *sFlags ) +{ + fh = fopen( sName, sFlags ); + if( fh == NULL ) + { + throw Bu::FileException( errno, strerror(errno) ); + } +} + +Bu::File::~File() +{ + close(); +} + +void Bu::File::close() +{ + if( fh ) + { + fclose( fh ); + fh = NULL; + } +} + +size_t Bu::File::read( void *pBuf, size_t nBytes ) +{ + if( !fh ) + throw FileException("File not open."); + + int nAmnt = fread( pBuf, 1, nBytes, fh ); + + if( nAmnt == 0 ) + throw FileException("End of file."); + + return nAmnt; +} + +size_t Bu::File::write( const void *pBuf, size_t nBytes ) +{ + if( !fh ) + throw FileException("File not open."); + + return fwrite( pBuf, 1, nBytes, fh ); +} + +long Bu::File::tell() +{ + if( !fh ) + throw FileException("File not open."); + + return ftell( fh ); +} + +void Bu::File::seek( long offset ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, offset, SEEK_CUR ); +} + +void Bu::File::setPos( long pos ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, pos, SEEK_SET ); +} + +void Bu::File::setPosEnd( long pos ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, pos, SEEK_END ); +} + +bool Bu::File::isEOS() +{ + return feof( fh ); +} + +bool Bu::File::canRead() +{ + return true; +} + +bool Bu::File::canWrite() +{ + return true; +} + +bool Bu::File::canSeek() +{ + return true; +} + -- cgit v1.2.3 From e0e7932a122614a0ff566fbfd8de5776de8b9f6d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 17 May 2007 05:56:26 +0000 Subject: Lots of cool new stuff, the Server class actually works for everything except actually interacting with clients, and the Client class is almost there, except that it doesn't really do anything yet. --- src/client.cpp | 9 +++++++ src/client.h | 23 +++++++++++++++++ src/file.cpp | 10 +++++++ src/file.h | 3 +++ src/list.h | 5 ++++ src/old/singleton.h | 59 ------------------------------------------ src/server.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/server.h | 49 +++++++++++++++++++++++++++++++++++ src/serversocket.cpp | 5 ++++ src/serversocket.h | 3 ++- src/singleton.h | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/socket.cpp | 9 +++++++ src/socket.h | 3 ++- src/stream.h | 3 +++ src/tests/hash.cpp | 24 +++++++++++++++++ 15 files changed, 279 insertions(+), 61 deletions(-) create mode 100644 src/client.cpp create mode 100644 src/client.h delete mode 100644 src/old/singleton.h create mode 100644 src/server.cpp create mode 100644 src/server.h create mode 100644 src/singleton.h create mode 100644 src/tests/hash.cpp (limited to 'src/file.cpp') diff --git a/src/client.cpp b/src/client.cpp new file mode 100644 index 0000000..a048ca3 --- /dev/null +++ b/src/client.cpp @@ -0,0 +1,9 @@ +#include "client.h" + +Bu::Client::Client() +{ +} + +Bu::Client::~Client() +{ +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..27fbad4 --- /dev/null +++ b/src/client.h @@ -0,0 +1,23 @@ +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include "bu/socket.h" + +namespace Bu +{ + /** + * + */ + class Client + { + public: + Client(); + virtual ~Client(); + + private: + + }; +} + +#endif diff --git a/src/file.cpp b/src/file.cpp index 5de5f6c..26986a5 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -98,3 +98,13 @@ bool Bu::File::canSeek() return true; } +bool Bu::File::isBlocking() +{ + return true; +} + +void Bu::File::setBlocking( bool bBlocking ) +{ + return; +} + diff --git a/src/file.h b/src/file.h index bbc620c..ee3fdb3 100644 --- a/src/file.h +++ b/src/file.h @@ -27,6 +27,9 @@ namespace Bu virtual bool canWrite(); virtual bool canSeek(); + virtual bool isBlocking(); + virtual void setBlocking( bool bBlocking=true ); + private: FILE *fh; diff --git a/src/list.h b/src/list.h index 4d16872..6081ea5 100644 --- a/src/list.h +++ b/src/list.h @@ -217,6 +217,11 @@ namespace Bu { } + const_iterator( const iterator &i ) : + pLink( i.pLink ) + { + } + public: bool operator==( const const_iterator &oth ) const { diff --git a/src/old/singleton.h b/src/old/singleton.h deleted file mode 100644 index 47adbd5..0000000 --- a/src/old/singleton.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef SINGLETON_H -#define SINGLETON_H - -#include - -/** - * Provides singleton functionality in a modular sort of way. Make this the - * base class of any other class and you immediately gain singleton - * functionality. Be sure to make your constructor and various functions use - * intellegent scoping. Cleanup and instantiation are performed automatically - * for you at first use and program exit. There are two things that you must - * do when using this template, first is to inherit from it with the name of - * your class filling in for T and then make this class a friend of your class. - *@code - * // Making the Single Singleton: - * class Single : public Singleton - * { - * friend class Singleton; - * protected: - * Single(); - * ... - * }; - @endcode - * You can still add public functions and variables to your new Singleton child - * class, but your constructor should be protected (hence the need for the - * friend decleration). - *@author Mike Buland - */ -template -class Singleton -{ -protected: - /** - * Private constructor. This constructor is empty but has a body so that - * you can make your own override of it. Be sure that you're override is - * also protected. - */ - Singleton() {}; - -private: - /** - * Copy constructor, defined so that you could write your own as well. - */ - Singleton( const Singleton& ); - -public: - /** - * Get a handle to the contained instance of the contained class. It is - * a reference. - *@returns A reference to the contained object. - */ - static T &getInstance() - { - static T i; - return i; - } -}; - -#endif diff --git a/src/server.cpp b/src/server.cpp new file mode 100644 index 0000000..f93238c --- /dev/null +++ b/src/server.cpp @@ -0,0 +1,73 @@ +#include "server.h" +#include + +Bu::Server::Server() : + nTimeoutSec( 0 ), + nTimeoutUSec( 0 ) +{ + FD_ZERO( &fdActive ); +} + +Bu::Server::~Server() +{ +} + +void Bu::Server::addPort( int nPort, int nPoolSize ) +{ + ServerSocket *s = new ServerSocket( nPort, nPoolSize ); + int nSocket = s->getSocket(); + FD_SET( nSocket, &fdActive ); + hServers.insert( nSocket, s ); +} + +void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) +{ + ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); + int nSocket = s->getSocket(); + FD_SET( nSocket, &fdActive ); + hServers.insert( nSocket, s ); +} + +void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec ) +{ + this->nTimeoutSec = nTimeoutSec; + this->nTimeoutUSec = nTimeoutUSec; +} + +void Bu::Server::scan() +{ + struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec }; + + fd_set fdRead = fdActive; + fd_set fdWrite = fdActive; + fd_set fdException = fdActive; + + if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, &fdRead, NULL, &fdException, &xTimeout ) ) < 0 ) + { + throw ExceptionBase("Error attempting to scan open connections."); + } + + for( int j = 0; j < FD_SETSIZE; j++ ) + { + if( FD_ISSET( j, &fdRead ) ) + { + if( hServers.has( j ) ) + { + addClient( hServers.get( j )->accept() ); + } + else + { + + } + } + } +} + +void Bu::Server::addClient( int nSocket ) +{ + FD_SET( nSocket, &fdActive ); + + Client *c = new Client(); + hClients.insert( nSocket, c ); +} + diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..9f4f459 --- /dev/null +++ b/src/server.h @@ -0,0 +1,49 @@ +#ifndef SERVER_H +#define SERVER_H + +#include +#include "bu/serversocket.h" +#include "bu/list.h" +#include "bu/client.h" + +namespace Bu +{ + /** + * Core of a network server. This class is distinct from a ServerSocket in + * that a ServerSocket is one listening socket, nothing more. Socket will + * manage a pool of both ServerSockets and connected Sockets along with + * their protocols and buffers. + * + * To start serving on a new port, use the addPort functions. Each call to + * addPort creates a new ServerSocket, starts it listening, and adds it to + * the server pool. + * + * All of the real work is done by scan, which will wait for up + * to the timeout set by setTimeout before returning if there is no data + * pending. scan should probably be called in some sort of tight + * loop, possibly in it's own thread, or in the main control loop. + */ + class Server + { + public: + Server(); + virtual ~Server(); + + void addPort( int nPort, int nPoolSize=40 ); + void addPort( const FString &sAddr, int nPort, int nPoolSize=40 ); + + void scan(); + void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 ); + + void addClient( int nSocket ); + + private: + int nTimeoutSec; + int nTimeoutUSec; + fd_set fdActive; + Hash hServers; + Hash hClients; + }; +} + +#endif diff --git a/src/serversocket.cpp b/src/serversocket.cpp index c53c80d..9c8f743 100644 --- a/src/serversocket.cpp +++ b/src/serversocket.cpp @@ -85,6 +85,11 @@ void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) FD_SET( nServer, &fdActive ); } +int Bu::ServerSocket::getSocket() +{ + return nServer; +} + int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) { fd_set fdRead = fdActive; diff --git a/src/serversocket.h b/src/serversocket.h index f146d91..d2601e4 100644 --- a/src/serversocket.h +++ b/src/serversocket.h @@ -23,7 +23,8 @@ namespace Bu ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); virtual ~ServerSocket(); - int accept( int nTimeoutSec, int nTimeoutUSec ); + int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); + int getSocket(); private: void startServer( struct sockaddr_in &name, int nPoolSize ); diff --git a/src/singleton.h b/src/singleton.h new file mode 100644 index 0000000..4976a61 --- /dev/null +++ b/src/singleton.h @@ -0,0 +1,62 @@ +#ifndef SINGLETON_H +#define SINGLETON_H + +#include + +namespace Bu +{ + /** + * Provides singleton functionality in a modular sort of way. Make this the + * base class of any other class and you immediately gain singleton + * functionality. Be sure to make your constructor and various functions use + * intellegent scoping. Cleanup and instantiation are performed automatically + * for you at first use and program exit. There are two things that you must + * do when using this template, first is to inherit from it with the name of + * your class filling in for T and then make this class a friend of your class. + *@code + * // Making the Single Singleton: + * class Single : public Singleton + * { + * friend class Singleton; + * protected: + * Single(); + * ... + * }; + @endcode + * You can still add public functions and variables to your new Singleton child + * class, but your constructor should be protected (hence the need for the + * friend decleration). + *@author Mike Buland + */ + template + class Singleton + { + protected: + /** + * Private constructor. This constructor is empty but has a body so that + * you can make your own override of it. Be sure that you're override is + * also protected. + */ + Singleton() {}; + + private: + /** + * Copy constructor, defined so that you could write your own as well. + */ + Singleton( const Singleton& ); + + public: + /** + * Get a handle to the contained instance of the contained class. It is + * a reference. + *@returns A reference to the contained object. + */ + static T &getInstance() + { + static T i; + return i; + } + }; +} + +#endif diff --git a/src/socket.cpp b/src/socket.cpp index 455b5c8..441678a 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -231,3 +231,12 @@ bool Bu::Socket::canSeek() return false; } +bool Bu::Socket::isBlocking() +{ + return false; +} + +void Bu::Socket::setBlocking( bool bBlocking ) +{ +} + diff --git a/src/socket.h b/src/socket.h index 568cad6..e65eb74 100644 --- a/src/socket.h +++ b/src/socket.h @@ -33,7 +33,8 @@ namespace Bu virtual bool canWrite(); virtual bool canSeek(); - + virtual bool isBlocking(); + virtual void setBlocking( bool bBlocking=true ); private: int nSocket; diff --git a/src/stream.h b/src/stream.h index e640959..5f586e6 100644 --- a/src/stream.h +++ b/src/stream.h @@ -36,6 +36,9 @@ namespace Bu virtual bool canWrite() = 0; virtual bool canSeek() = 0; + virtual bool isBlocking() = 0; + virtual void setBlocking( bool bBlocking=true ) = 0; + private: }; diff --git a/src/tests/hash.cpp b/src/tests/hash.cpp new file mode 100644 index 0000000..73cfb27 --- /dev/null +++ b/src/tests/hash.cpp @@ -0,0 +1,24 @@ +#include "bu/hash.h" +#include "bu/sptr.h" + +typedef struct Bob +{ + int nID; +} Bob; + +int main() +{ + Bu::Hash > lb; + for( int j = 0; j < 10; j++ ) + { + Bob *b = new Bob; + b->nID = j; + lb.insert( j, b ); + } + + for( int j = 0; j < 10; j++ ) + { + printf("%d\n", lb[j].value()->nID ); + } +} + -- cgit v1.2.3 From 5f39066a4f561e9a94a6cc9293ab9b978ebf1f81 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 10 Jun 2007 21:28:14 +0000 Subject: Bunch of maintenence type things. Minor tweaks and the like. The file class has a lot more helper functions and the like, the filters give more info back to the caller, minor updates to taf. --- src/bzip2.cpp | 41 ++++++++++++++++++++++++++++++++++------- src/bzip2.h | 2 +- src/file.cpp | 31 +++++++++++++++++++++++++++++++ src/file.h | 17 ++++++++++++++++- src/filter.cpp | 7 ++++++- src/filter.h | 4 +++- src/socket.cpp | 4 ++++ src/socket.h | 2 ++ src/stream.h | 2 ++ src/tafnode.cpp | 6 +++--- src/tafnode.h | 4 ++-- src/tests/taf.cpp | 2 +- 12 files changed, 105 insertions(+), 17 deletions(-) (limited to 'src/file.cpp') diff --git a/src/bzip2.cpp b/src/bzip2.cpp index 433fc91..5423a10 100644 --- a/src/bzip2.cpp +++ b/src/bzip2.cpp @@ -26,16 +26,18 @@ void Bu::BZip2::start() pBuf = new char[nBufSize]; } -void Bu::BZip2::stop() +size_t Bu::BZip2::stop() { if( bzState.state ) { if( bReading ) { BZ2_bzDecompressEnd( &bzState ); + return 0; } else { + size_t sTotal = 0; for(;;) { bzState.next_in = NULL; @@ -45,14 +47,16 @@ void Bu::BZip2::stop() int res = BZ2_bzCompress( &bzState, BZ_FINISH ); if( bzState.avail_out < nBufSize ) { - rNext.write( pBuf, nBufSize-bzState.avail_out ); + sTotal += rNext.write( pBuf, nBufSize-bzState.avail_out ); } if( res == BZ_STREAM_END ) break; } BZ2_bzCompressEnd( &bzState ); + return sTotal; } } + return 0; } void Bu::BZip2::bzError( int code ) @@ -63,13 +67,35 @@ void Bu::BZip2::bzError( int code ) return; case BZ_CONFIG_ERROR: - throw ExceptionBase("The bzip2 library has been miscompiled."); + throw ExceptionBase("BZip2: Library configured improperly, reinstall."); + + case BZ_SEQUENCE_ERROR: + throw ExceptionBase("BZip2: Functions were called in an invalid sequence."); case BZ_PARAM_ERROR: - throw ExceptionBase("bzip2 parameter error."); + throw ExceptionBase("BZip2: Invalid parameter was passed into a function."); case BZ_MEM_ERROR: - throw ExceptionBase("Not enough memory available for bzip2."); + throw ExceptionBase("BZip2: Couldn't allocate sufficient memory."); + + case BZ_DATA_ERROR: + throw ExceptionBase("BZip2: Data was corrupted before decompression."); + + case BZ_DATA_ERROR_MAGIC: + throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data."); + + case BZ_IO_ERROR: + throw ExceptionBase("BZip2: File couldn't be read from / written to."); + + case BZ_UNEXPECTED_EOF: + throw ExceptionBase("BZip2: End of file encountered before end of stream."); + + case BZ_OUTBUFF_FULL: + throw ExceptionBase("BZip2: Buffer not large enough to accomidate data."); + + default: + throw ExceptionBase("BZip2: Unknown error encountered."); + } } @@ -124,6 +150,7 @@ size_t Bu::BZip2::write( const void *pData, size_t nBytes ) if( bReading == true ) throw ExceptionBase("This bzip2 filter is in reading mode, you can't write."); + size_t sTotalOut = 0; bzState.next_in = (char *)pData; bzState.avail_in = nBytes; for(;;) @@ -135,12 +162,12 @@ size_t Bu::BZip2::write( const void *pData, size_t nBytes ) if( bzState.avail_out < nBufSize ) { - rNext.write( pBuf, nBufSize-bzState.avail_out ); + sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out ); } if( bzState.avail_in == 0 ) break; } - return 0; + return sTotalOut; } diff --git a/src/bzip2.h b/src/bzip2.h index 056f336..a23f07a 100644 --- a/src/bzip2.h +++ b/src/bzip2.h @@ -18,7 +18,7 @@ namespace Bu virtual ~BZip2(); virtual void start(); - virtual void stop(); + virtual size_t stop(); virtual size_t read( void *pBuf, size_t nBytes ); virtual size_t write( const void *pBuf, size_t nBytes ); diff --git a/src/file.cpp b/src/file.cpp index 26986a5..14b6e54 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1,6 +1,8 @@ #include "file.h" #include "exceptions.h" #include +#include +#include Bu::File::File( const char *sName, const char *sFlags ) { @@ -11,6 +13,20 @@ Bu::File::File( const char *sName, const char *sFlags ) } } +Bu::File::File( const Bu::FString &sName, const char *sFlags ) +{ + fh = fopen( sName.getStr(), sFlags ); + if( fh == NULL ) + { + throw Bu::FileException( errno, strerror(errno) ); + } +} + +Bu::File::File( int fd, const char *sFlags ) +{ + fh = fdopen( fd, sFlags ); +} + Bu::File::~File() { close(); @@ -108,3 +124,18 @@ void Bu::File::setBlocking( bool bBlocking ) return; } +void Bu::File::truncate( long nSize ) +{ + ftruncate( fileno( fh ), nSize ); +} + +void Bu::File::flush() +{ + fflush( fh ); +} + +void Bu::File::chmod( mode_t t ) +{ + fchmod( fileno( fh ), t ); +} + diff --git a/src/file.h b/src/file.h index ee3fdb3..8107a1b 100644 --- a/src/file.h +++ b/src/file.h @@ -3,7 +3,8 @@ #include -#include "stream.h" +#include "bu/stream.h" +#include "bu/fstring.h" namespace Bu { @@ -11,6 +12,8 @@ namespace Bu { public: File( const char *sName, const char *sFlags ); + File( const Bu::FString &sName, const char *sFlags ); + File( int fd, const char *sFlags ); virtual ~File(); virtual void close(); @@ -23,6 +26,8 @@ namespace Bu virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual void flush(); + virtual bool canRead(); virtual bool canWrite(); virtual bool canSeek(); @@ -30,6 +35,16 @@ namespace Bu virtual bool isBlocking(); virtual void setBlocking( bool bBlocking=true ); + inline static Bu::File tempFile( Bu::FString &sName, const char *sFlags ) + { + int afh_d = mkstemp( sName.getStr() ); + + return Bu::File( afh_d, sFlags ); + } + + void truncate( long nSize ); + void chmod( mode_t t ); + private: FILE *fh; diff --git a/src/filter.cpp b/src/filter.cpp index d3faa00..693fb9f 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -7,7 +7,7 @@ Bu::Filter::Filter( Bu::Stream &rNext ) : Bu::Filter::~Filter() { - printf("-> Bu::Filter::~Filter()\n"); + //printf("-> Bu::Filter::~Filter()\n"); } /* void Bu::Filter::start() @@ -75,3 +75,8 @@ void Bu::Filter::setBlocking( bool bBlocking ) rNext.setBlocking( bBlocking ); } +void Bu::Filter::flush() +{ + rNext.flush(); +} + diff --git a/src/filter.h b/src/filter.h index b068206..088d46e 100644 --- a/src/filter.h +++ b/src/filter.h @@ -33,7 +33,7 @@ namespace Bu virtual ~Filter(); virtual void start()=0; - virtual void stop()=0; + virtual size_t stop()=0; virtual void close(); virtual long tell(); virtual void seek( long offset ); @@ -41,6 +41,8 @@ namespace Bu virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual void flush(); + virtual bool canRead(); virtual bool canWrite(); virtual bool canSeek(); diff --git a/src/socket.cpp b/src/socket.cpp index 441678a..1832898 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -240,3 +240,7 @@ void Bu::Socket::setBlocking( bool bBlocking ) { } +void Bu::Socket::flush() +{ +} + diff --git a/src/socket.h b/src/socket.h index e65eb74..30a43fb 100644 --- a/src/socket.h +++ b/src/socket.h @@ -29,6 +29,8 @@ namespace Bu virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual void flush(); + virtual bool canRead(); virtual bool canWrite(); virtual bool canSeek(); diff --git a/src/stream.h b/src/stream.h index fa0a606..a80586b 100644 --- a/src/stream.h +++ b/src/stream.h @@ -32,6 +32,8 @@ namespace Bu virtual void setPosEnd( long pos ) = 0; virtual bool isEOS() = 0; + virtual void flush() = 0; + virtual bool canRead() = 0; virtual bool canWrite() = 0; virtual bool canSeek() = 0; diff --git a/src/tafnode.cpp b/src/tafnode.cpp index 3060606..b9a4a24 100644 --- a/src/tafnode.cpp +++ b/src/tafnode.cpp @@ -45,7 +45,7 @@ const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sNam return hProp.get( sName ); } -const Bu::TafNode::NodeList &Bu::TafNode::getNodes( const Bu::FString &sName ) const +const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const { return hChildren.get( sName ); } @@ -55,9 +55,9 @@ const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const return getProperties( sName ).first(); } -const Bu::TafNode *Bu::TafNode::getNode( const Bu::FString &sName ) const +const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const { - return getNodes( sName ).first(); + return getChildren( sName ).first(); } void Bu::TafNode::setName( const Bu::FString &sName ) diff --git a/src/tafnode.h b/src/tafnode.h index 10232d2..08f78e8 100644 --- a/src/tafnode.h +++ b/src/tafnode.h @@ -28,9 +28,9 @@ namespace Bu void setProperty( Bu::FString sName, Bu::FString sValue ); const Bu::FString &getProperty( const Bu::FString &sName ) const; - const TafNode *getNode( const Bu::FString &sName ) const; const PropList &getProperties( const Bu::FString &sName ) const; - const NodeList &getNodes( const Bu::FString &sName ) const; + const TafNode *getChild( const Bu::FString &sName ) const; + const NodeList &getChildren( const Bu::FString &sName ) const; void addChild( TafNode *pNode ); private: diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp index e7bad52..d135e78 100644 --- a/src/tests/taf.cpp +++ b/src/tests/taf.cpp @@ -8,7 +8,7 @@ int main() Bu::TafNode *pNode = tr.getNode(); - const Bu::TafNode *pStats = pNode->getNode("stats"); + const Bu::TafNode *pStats = pNode->getChild("stats"); printf("%s\n", pStats->getName().getStr() ); printf(" str = %s\n", pStats->getProperty("str").getStr() ); -- cgit v1.2.3 From 4cb166570a8e2e97216bf6c7aeb99b971ff58ad7 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 12 Jun 2007 01:28:27 +0000 Subject: Moved out the xml system again. I think that if I am going to do it again, I'm going to do it over from scratch, that was just painful. Also, started in again on the server system, it's looking pretty good, already got connections working, next up is managing data flow through clients and protocols! --- src/client.cpp | 1 + src/file.cpp | 4 +- src/old/xmldocument.cpp | 145 ++++++++++++ src/old/xmldocument.h | 165 +++++++++++++ src/old/xmlnode.cpp | 403 ++++++++++++++++++++++++++++++++ src/old/xmlnode.h | 207 +++++++++++++++++ src/old/xmlreader.cpp | 604 ++++++++++++++++++++++++++++++++++++++++++++++++ src/old/xmlreader.h | 144 ++++++++++++ src/old/xmlwriter.cpp | 167 +++++++++++++ src/old/xmlwriter.h | 96 ++++++++ src/server.cpp | 7 +- src/server.h | 9 +- src/serversocket.cpp | 5 + src/serversocket.h | 1 + src/xmldocument.cpp | 145 ------------ src/xmldocument.h | 165 ------------- src/xmlnode.cpp | 403 -------------------------------- src/xmlnode.h | 207 ----------------- src/xmlreader.cpp | 604 ------------------------------------------------ src/xmlreader.h | 144 ------------ src/xmlwriter.cpp | 167 ------------- src/xmlwriter.h | 96 -------- 22 files changed, 1953 insertions(+), 1936 deletions(-) create mode 100644 src/old/xmldocument.cpp create mode 100644 src/old/xmldocument.h create mode 100644 src/old/xmlnode.cpp create mode 100644 src/old/xmlnode.h create mode 100644 src/old/xmlreader.cpp create mode 100644 src/old/xmlreader.h create mode 100644 src/old/xmlwriter.cpp create mode 100644 src/old/xmlwriter.h delete mode 100644 src/xmldocument.cpp delete mode 100644 src/xmldocument.h delete mode 100644 src/xmlnode.cpp delete mode 100644 src/xmlnode.h delete mode 100644 src/xmlreader.cpp delete mode 100644 src/xmlreader.h delete mode 100644 src/xmlwriter.cpp delete mode 100644 src/xmlwriter.h (limited to 'src/file.cpp') diff --git a/src/client.cpp b/src/client.cpp index a048ca3..a33cdc3 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -7,3 +7,4 @@ Bu::Client::Client() Bu::Client::~Client() { } + diff --git a/src/file.cpp b/src/file.cpp index 14b6e54..2965afa 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -48,8 +48,8 @@ size_t Bu::File::read( void *pBuf, size_t nBytes ) int nAmnt = fread( pBuf, 1, nBytes, fh ); - if( nAmnt == 0 ) - throw FileException("End of file."); + //if( nAmnt == 0 ) + // throw FileException("End of file."); return nAmnt; } diff --git a/src/old/xmldocument.cpp b/src/old/xmldocument.cpp new file mode 100644 index 0000000..95b9788 --- /dev/null +++ b/src/old/xmldocument.cpp @@ -0,0 +1,145 @@ +#include +#include +#include "xmldocument.h" + +XmlDocument::XmlDocument( XmlNode *pRoot ) +{ + this->pRoot = pRoot; + pCurrent = NULL; + bCompleted = (pRoot!=NULL); +} + +XmlDocument::~XmlDocument() +{ + if( pRoot ) + { + delete pRoot; + } +} + +void XmlDocument::addNode( const Bu::FString &sName ) +{ + if( pRoot == NULL ) + { + // This is the first node, so ignore position and just insert it. + pCurrent = pRoot = new XmlNode( sName ); + } + else + { + pCurrent = pCurrent->addChild( sName ); + } +} +/* +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 ) + { + printf("XmlDocument::setContent: not yet implemented.\n"); + //pCurrent->setContent( sContent ); + } +} + diff --git a/src/old/xmldocument.h b/src/old/xmldocument.h new file mode 100644 index 0000000..e0c36eb --- /dev/null +++ b/src/old/xmldocument.h @@ -0,0 +1,165 @@ +#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 Bu::FString &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 new file mode 100644 index 0000000..96d5850 --- /dev/null +++ b/src/old/xmlnode.cpp @@ -0,0 +1,403 @@ +#include "xmlnode.h" + +XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) : + sName( sName ), + pParent( pParent ) +{ +} + +XmlNode::~XmlNode() +{ +} +/* +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 Bu::FString &sName ) +{ + return addChild( new XmlNode( sName, this ) ); +} + +XmlNode *XmlNode::addChild( XmlNode *pNode ) +{ + Child c = { typeNode }; + c.pNode = pNode; + lChildren.append( c ); + pNode->pParent = this; + + return pNode; +} + +XmlNode *XmlNode::getParent() +{ + return pParent; +} + +void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue ) +{ + hProperties.insert( sName, sValue ); +} + +int XmlNode::getNumProperties() +{ + return hProperties.size(); +} +/* +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(); +} +*/ +Bu::FString XmlNode::getProperty( const Bu::FString &sName ) +{ + return hProperties[sName]; +} +/* +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 hChildren.getSize()>0; +}*/ + +int XmlNode::getNumChildren() +{ + return lChildren.getSize(); +} +/* +XmlNode *XmlNode::getChild( int nIndex ) +{ + return (XmlNode *)lChildren[nIndex]; +} +*/ +XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip ) +{ + if( !hChildren.has( sName ) ) + return NULL; + + Bu::List::iterator i = hChildren[sName]->begin(); + return *i; +} + +Bu::FString XmlNode::getName() +{ + return sName; +} +/* +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 new file mode 100644 index 0000000..c895cd8 --- /dev/null +++ b/src/old/xmlnode.h @@ -0,0 +1,207 @@ +#ifndef XMLNODE +#define XMLNODE + +#include +#include "bu/list.h" +#include "bu/hash.h" +#include "bu/fstring.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 Bu::FString &sName, + XmlNode *pParent=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 Bu::FString &sName ); + + /** + * 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 Bu::FString &sName, const Bu::FString &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 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 Bu::FString &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. + */ + Bu::FString 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 number of properties in this node. + *@returns The number of properties in this node. + */ + int getNumProperties(); + + /** + * 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. + */ + Bu::FString getProperty( const Bu::FString &sName ); + + /** + * 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(); + + enum ChildType + { + typeNode, + typeContent + }; + +private: + typedef struct + { + uint8_t nType; + union { + XmlNode *pNode; + Bu::FString *pContent; + }; + } Child; + Bu::FString sName; /**< The name of the node. */ + Bu::List lChildren; /**< The children. */ + Bu::Hash hProperties; /**< Property hashtable. */ + Bu::Hash > hChildren; /**< Children hashtable. */ + 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 new file mode 100644 index 0000000..38cad5f --- /dev/null +++ b/src/old/xmlreader.cpp @@ -0,0 +1,604 @@ +#include "bu/xmlreader.h" +#include "bu/exceptions.h" +#include + +XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) : + sIn( sIn ), + bStrip( bStrip ) +{ + buildDoc(); +} + +XmlReader::~XmlReader() +{ +} + +char XmlReader::getChar( int nIndex ) +{ + if( sBuf.getSize() <= nIndex ) + { + int nInc = nIndex-sBuf.getSize()+1; + char *buf = new char[nInc]; + sIn.read( buf, nInc ); + sBuf.append( buf, nInc ); + delete[] buf; + } + + return sBuf[nIndex]; +} + +void XmlReader::usedChar( int nAmnt ) +{ + if( nAmnt >= sBuf.getSize() ) + { + sBuf.clear(); + } + else + { + char *s = sBuf.getStr(); + memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt ); + sBuf.resize( sBuf.getSize()-nAmnt ); + } +} + +void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value ) +{ + htEntity[name] = value; +} + +#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(); + Bu::FString buf; + for(;;) + { + char chr = getChar(); + usedChar(); + if( isws( chr ) ) break; + buf += chr; + } + + if( strcmp( buf.c_str(), "ENTITY") == 0 ) + { + ws(); + Bu::FString name; + for(;;) + { + char chr = getChar(); + usedChar(); + if( isws( chr ) ) break; + name += chr; + } + ws(); + char quot = getChar(); + usedChar(); + if( quot != '\'' && quot != '\"' ) + { + throw Bu::XmlException( + "Only quoted entity values are supported." + ); + } + Bu::FString value; + for(;;) + { + char chr = getChar(); + usedChar(); + if( chr == '&' ) + { + Bu::FString tmp = getEscape(); + value += tmp; + } + else if( chr == quot ) + { + break; + } + else + { + value += chr; + } + } + ws(); + if( getChar() == '>' ) + { + usedChar(); + + addEntity( name.c_str(), value.c_str() ); + } + else + { + throw Bu::XmlException( + "Malformed ENTITY: unexpected '%c' found.", + getChar() + ); + } + } + else + { + throw Bu::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 Bu::XmlException("Close node in singleNode malformed!"); + } + } + else + { + throw Bu::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 + Bu::FString sName; + 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( getCurrent()->getName() == sName ) + { + closeNode(); + break; + } + else + { + throw Bu::XmlException("Got a mismatched node close tag."); + } + } + else + { + sName += chr; + usedChar(); + } + } + + gcall( ws() ); + if( getChar() == '>' ) + { + // Everything is cool. + usedChar(); + } + else + { + throw Bu::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 Bu::XmlException("Expected to find node opening char, '<'."); + } + + return true; +} + +bool XmlReader::name() +{ + Bu::FString sName; + + while( true ) + { + char chr = getChar(); + if( isws( chr ) || chr == '>' || chr == '/' ) + { + addNode( sName ); + return true; + } + else + { + sName += chr; + usedChar(); + } + } + + return true; +} + +bool XmlReader::paramlist() +{ + while( true ) + { + char chr = getChar(); + if( chr == '/' || chr == '>' ) + { + return true; + } + else + { + gcall( param() ); + gcall( ws() ); + } + } + + return true; +} + +Bu::FString 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 buf; + } + else + { + // ...otherwise replace with the appropriate string... + Bu::FString buf; + usedChar(); + for(;;) + { + char cbuf = getChar(); + usedChar(); + if( cbuf == ';' ) break; + buf += cbuf; + } + + return htEntity[buf]; + } +} + +bool XmlReader::param() +{ + Bu::FString sName; + Bu::FString sValue; + + while( true ) + { + char chr = getChar(); + if( isws( chr ) || chr == '=' ) + { + break; + } + else + { + sName.append( 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( sName.getStr(), sValue.getStr() ); + return true; + } + else + { + if( chr == '&' ) + { + sValue += getEscape(); + } + else + { + sValue += chr; + usedChar(); + } + } + } + } + else + { + // Simple one-word rhs + while( true ) + { + chr = getChar(); + if( isws( chr ) || chr == '/' || chr == '>' ) + { + addProperty( sName.getStr(), sValue.getStr() ); + return true; + } + else + { + if( chr == '&' ) + { + sValue += getEscape(); + } + else + { + sValue += chr; + usedChar(); + } + } + } + } + } + else + { + throw Bu::XmlException("Expected an equals to seperate the params."); + return false; + } + + return true; +} + +bool XmlReader::content() +{ + Bu::FString sContent; + + if( bStrip ) gcall( ws() ); + + while( true ) + { + char chr = getChar(); + if( chr == '<' ) + { + if( getChar(1) == '/' ) + { + if( sContent.getSize() > 0 ) + { + if( bStrip ) + { + int j; + for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); + sContent[j+1] = '\0'; + } + setContent( sContent.getStr() ); + } + usedChar( 2 ); + gcall( ws() ); + Bu::FString sName; + while( true ) + { + chr = getChar(); + if( isws( chr ) || chr == '>' ) + { + if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) ) + { + closeNode(); + break; + } + else + { + throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() ); + } + } + else + { + sName += chr; + usedChar(); + } + } + gcall( ws() ); + if( getChar() == '>' ) + { + usedChar(); + return true; + } + else + { + throw Bu::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 Bu::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 Bu::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( sContent.getSize() > 0 ) + { + if( bStrip ) + { + int j; + for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); + sContent[j+1] = '\0'; + } + setContent( sContent.getStr() ); + sContent.clear(); + } + gcall( node() ); + } + + if( bStrip ) gcall( ws() ); + } + else if( chr == '&' ) + { + sContent += getEscape(); + } + else + { + sContent += chr; + usedChar(); + } + } +} + diff --git a/src/old/xmlreader.h b/src/old/xmlreader.h new file mode 100644 index 0000000..7c85ddb --- /dev/null +++ b/src/old/xmlreader.h @@ -0,0 +1,144 @@ +#ifndef XMLREADER +#define XMLREADER + +#include +#include "bu/xmldocument.h" +#include "bu/hash.h" +#include "bu/fstring.h" +#include "bu/stream.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( Bu::Stream &sIn, 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 ); + + /** + * Called to increment the current stream position by a single character. + */ + virtual void usedChar( int nAmnt = 1 ); + + /** + * 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 Bu::FString &name, const Bu::FString &value ); + + Bu::FString 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(); + + Bu::FString sContent; /**< buffer for the current node's content. */ + Bu::FString sParamName; /**< buffer for the current param's name. */ + Bu::FString sParamValue; /**< buffer for the current param's value. */ + Bu::Stream &sIn; + bool bStrip; /**< Are we stripping whitespace? */ + + Bu::Hash htEntity; /**< Entity type definitions. */ + + Bu::FString sBuf; +}; + +#endif diff --git a/src/old/xmlwriter.cpp b/src/old/xmlwriter.cpp new file mode 100644 index 0000000..7dc6ca9 --- /dev/null +++ b/src/old/xmlwriter.cpp @@ -0,0 +1,167 @@ +#include +#include +#include "xmlwriter.h" + +XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) : + XmlDocument( pRoot ), + sIndent( sIndent ) +{ +} + +XmlWriter::~XmlWriter() +{ +} + +void XmlWriter::write() +{ + write( getRoot(), sIndent.c_str() ); +} + +void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent ) +{ + writeNode( pRoot, 0, sIndent ); +} + +void XmlWriter::closeNode() +{ + XmlDocument::closeNode(); + + if( isCompleted() ) + { + write( getRoot(), sIndent.c_str() ); + } +} + +void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent ) +{ + if( sIndent == NULL ) return; + for( int j = 0; j < nIndent; j++ ) + { + writeString( sIndent ); + } +} + +Bu::FString XmlWriter::escape( const Bu::FString &sIn ) +{ + Bu::FString sOut; + + int nMax = sIn.getSize(); + for( int j = 0; j < nMax; j++ ) + { + char c = sIn[j]; + if( ((c >= ' ' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') ) && + (c != '\"' && c != '\'' && c != '&') + ) + { + sOut += c; + } + else + { + sOut += "&#"; + char buf[4]; + sprintf( buf, "%u", (unsigned char)c ); + sOut += buf; + sOut += ';'; + } + } + + return sOut; +} + +void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &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 Bu::FString &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 new file mode 100644 index 0000000..7e3c876 --- /dev/null +++ b/src/old/xmlwriter.h @@ -0,0 +1,96 @@ +#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 Bu::FString &sIndent="", 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: + Bu::FString sIndent; /**< The indent string */ + + Bu::FString escape( const Bu::FString &sIn ); + + /** + * Write the file. + *@param pNode The root node + *@param sIndent The indent text. + */ + void write( XmlNode *pNode, const Bu::FString &sIndent ); + + /** + * 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 Bu::FString &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 Bu::FString &sIndent ); + + /** + * Called to write the actual indent. + *@param nIndent The indent level. + *@param sIndent The indent text. + */ + void writeIndent( int nIndent, const Bu::FString &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 Bu::FString &sString ) = 0; +}; + +#endif diff --git a/src/server.cpp b/src/server.cpp index f93238c..abf4c5b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -53,7 +53,8 @@ void Bu::Server::scan() { if( hServers.has( j ) ) { - addClient( hServers.get( j )->accept() ); + ServerSocket *pSrv = hServers.get( j ); + addClient( pSrv->accept(), pSrv->getPort() ); } else { @@ -63,11 +64,13 @@ void Bu::Server::scan() } } -void Bu::Server::addClient( int nSocket ) +void Bu::Server::addClient( int nSocket, int nPort ) { FD_SET( nSocket, &fdActive ); Client *c = new Client(); hClients.insert( nSocket, c ); + + onNewConnection( c, nPort ); } diff --git a/src/server.h b/src/server.h index 9f4f459..942eb32 100644 --- a/src/server.h +++ b/src/server.h @@ -22,6 +22,10 @@ namespace Bu * to the timeout set by setTimeout before returning if there is no data * pending. scan should probably be called in some sort of tight * loop, possibly in it's own thread, or in the main control loop. + * + * In order to use a Server you must subclass it and implement the pure + * virtual functions. These allow you to receive notification of events + * happening within the server itself, and actually makes it useful. */ class Server { @@ -35,7 +39,10 @@ namespace Bu void scan(); void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 ); - void addClient( int nSocket ); + void addClient( int nSocket, int nPort ); + + virtual void onNewConnection( Client *pClient, int nPort )=0; + virtual void onClosedConnection( Client *pClient )=0; private: int nTimeoutSec; diff --git a/src/serversocket.cpp b/src/serversocket.cpp index 9c8f743..1424630 100644 --- a/src/serversocket.cpp +++ b/src/serversocket.cpp @@ -151,3 +151,8 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) return -1; } +int Bu::ServerSocket::getPort() +{ + return nPort; +} + diff --git a/src/serversocket.h b/src/serversocket.h index d2601e4..cb86078 100644 --- a/src/serversocket.h +++ b/src/serversocket.h @@ -25,6 +25,7 @@ namespace Bu int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); int getSocket(); + int getPort(); private: void startServer( struct sockaddr_in &name, int nPoolSize ); diff --git a/src/xmldocument.cpp b/src/xmldocument.cpp deleted file mode 100644 index 95b9788..0000000 --- a/src/xmldocument.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include "xmldocument.h" - -XmlDocument::XmlDocument( XmlNode *pRoot ) -{ - this->pRoot = pRoot; - pCurrent = NULL; - bCompleted = (pRoot!=NULL); -} - -XmlDocument::~XmlDocument() -{ - if( pRoot ) - { - delete pRoot; - } -} - -void XmlDocument::addNode( const Bu::FString &sName ) -{ - if( pRoot == NULL ) - { - // This is the first node, so ignore position and just insert it. - pCurrent = pRoot = new XmlNode( sName ); - } - else - { - pCurrent = pCurrent->addChild( sName ); - } -} -/* -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 ) - { - printf("XmlDocument::setContent: not yet implemented.\n"); - //pCurrent->setContent( sContent ); - } -} - diff --git a/src/xmldocument.h b/src/xmldocument.h deleted file mode 100644 index e0c36eb..0000000 --- a/src/xmldocument.h +++ /dev/null @@ -1,165 +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 Bu::FString &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 deleted file mode 100644 index 96d5850..0000000 --- a/src/xmlnode.cpp +++ /dev/null @@ -1,403 +0,0 @@ -#include "xmlnode.h" - -XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) : - sName( sName ), - pParent( pParent ) -{ -} - -XmlNode::~XmlNode() -{ -} -/* -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 Bu::FString &sName ) -{ - return addChild( new XmlNode( sName, this ) ); -} - -XmlNode *XmlNode::addChild( XmlNode *pNode ) -{ - Child c = { typeNode }; - c.pNode = pNode; - lChildren.append( c ); - pNode->pParent = this; - - return pNode; -} - -XmlNode *XmlNode::getParent() -{ - return pParent; -} - -void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue ) -{ - hProperties.insert( sName, sValue ); -} - -int XmlNode::getNumProperties() -{ - return hProperties.size(); -} -/* -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(); -} -*/ -Bu::FString XmlNode::getProperty( const Bu::FString &sName ) -{ - return hProperties[sName]; -} -/* -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 hChildren.getSize()>0; -}*/ - -int XmlNode::getNumChildren() -{ - return lChildren.getSize(); -} -/* -XmlNode *XmlNode::getChild( int nIndex ) -{ - return (XmlNode *)lChildren[nIndex]; -} -*/ -XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip ) -{ - if( !hChildren.has( sName ) ) - return NULL; - - Bu::List::iterator i = hChildren[sName]->begin(); - return *i; -} - -Bu::FString XmlNode::getName() -{ - return sName; -} -/* -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 deleted file mode 100644 index c895cd8..0000000 --- a/src/xmlnode.h +++ /dev/null @@ -1,207 +0,0 @@ -#ifndef XMLNODE -#define XMLNODE - -#include -#include "bu/list.h" -#include "bu/hash.h" -#include "bu/fstring.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 Bu::FString &sName, - XmlNode *pParent=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 Bu::FString &sName ); - - /** - * 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 Bu::FString &sName, const Bu::FString &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 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 Bu::FString &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. - */ - Bu::FString 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 number of properties in this node. - *@returns The number of properties in this node. - */ - int getNumProperties(); - - /** - * 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. - */ - Bu::FString getProperty( const Bu::FString &sName ); - - /** - * 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(); - - enum ChildType - { - typeNode, - typeContent - }; - -private: - typedef struct - { - uint8_t nType; - union { - XmlNode *pNode; - Bu::FString *pContent; - }; - } Child; - Bu::FString sName; /**< The name of the node. */ - Bu::List lChildren; /**< The children. */ - Bu::Hash hProperties; /**< Property hashtable. */ - Bu::Hash > hChildren; /**< Children hashtable. */ - 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 deleted file mode 100644 index 38cad5f..0000000 --- a/src/xmlreader.cpp +++ /dev/null @@ -1,604 +0,0 @@ -#include "bu/xmlreader.h" -#include "bu/exceptions.h" -#include - -XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) : - sIn( sIn ), - bStrip( bStrip ) -{ - buildDoc(); -} - -XmlReader::~XmlReader() -{ -} - -char XmlReader::getChar( int nIndex ) -{ - if( sBuf.getSize() <= nIndex ) - { - int nInc = nIndex-sBuf.getSize()+1; - char *buf = new char[nInc]; - sIn.read( buf, nInc ); - sBuf.append( buf, nInc ); - delete[] buf; - } - - return sBuf[nIndex]; -} - -void XmlReader::usedChar( int nAmnt ) -{ - if( nAmnt >= sBuf.getSize() ) - { - sBuf.clear(); - } - else - { - char *s = sBuf.getStr(); - memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt ); - sBuf.resize( sBuf.getSize()-nAmnt ); - } -} - -void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value ) -{ - htEntity[name] = value; -} - -#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(); - Bu::FString buf; - for(;;) - { - char chr = getChar(); - usedChar(); - if( isws( chr ) ) break; - buf += chr; - } - - if( strcmp( buf.c_str(), "ENTITY") == 0 ) - { - ws(); - Bu::FString name; - for(;;) - { - char chr = getChar(); - usedChar(); - if( isws( chr ) ) break; - name += chr; - } - ws(); - char quot = getChar(); - usedChar(); - if( quot != '\'' && quot != '\"' ) - { - throw Bu::XmlException( - "Only quoted entity values are supported." - ); - } - Bu::FString value; - for(;;) - { - char chr = getChar(); - usedChar(); - if( chr == '&' ) - { - Bu::FString tmp = getEscape(); - value += tmp; - } - else if( chr == quot ) - { - break; - } - else - { - value += chr; - } - } - ws(); - if( getChar() == '>' ) - { - usedChar(); - - addEntity( name.c_str(), value.c_str() ); - } - else - { - throw Bu::XmlException( - "Malformed ENTITY: unexpected '%c' found.", - getChar() - ); - } - } - else - { - throw Bu::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 Bu::XmlException("Close node in singleNode malformed!"); - } - } - else - { - throw Bu::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 - Bu::FString sName; - 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( getCurrent()->getName() == sName ) - { - closeNode(); - break; - } - else - { - throw Bu::XmlException("Got a mismatched node close tag."); - } - } - else - { - sName += chr; - usedChar(); - } - } - - gcall( ws() ); - if( getChar() == '>' ) - { - // Everything is cool. - usedChar(); - } - else - { - throw Bu::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 Bu::XmlException("Expected to find node opening char, '<'."); - } - - return true; -} - -bool XmlReader::name() -{ - Bu::FString sName; - - while( true ) - { - char chr = getChar(); - if( isws( chr ) || chr == '>' || chr == '/' ) - { - addNode( sName ); - return true; - } - else - { - sName += chr; - usedChar(); - } - } - - return true; -} - -bool XmlReader::paramlist() -{ - while( true ) - { - char chr = getChar(); - if( chr == '/' || chr == '>' ) - { - return true; - } - else - { - gcall( param() ); - gcall( ws() ); - } - } - - return true; -} - -Bu::FString 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 buf; - } - else - { - // ...otherwise replace with the appropriate string... - Bu::FString buf; - usedChar(); - for(;;) - { - char cbuf = getChar(); - usedChar(); - if( cbuf == ';' ) break; - buf += cbuf; - } - - return htEntity[buf]; - } -} - -bool XmlReader::param() -{ - Bu::FString sName; - Bu::FString sValue; - - while( true ) - { - char chr = getChar(); - if( isws( chr ) || chr == '=' ) - { - break; - } - else - { - sName.append( 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( sName.getStr(), sValue.getStr() ); - return true; - } - else - { - if( chr == '&' ) - { - sValue += getEscape(); - } - else - { - sValue += chr; - usedChar(); - } - } - } - } - else - { - // Simple one-word rhs - while( true ) - { - chr = getChar(); - if( isws( chr ) || chr == '/' || chr == '>' ) - { - addProperty( sName.getStr(), sValue.getStr() ); - return true; - } - else - { - if( chr == '&' ) - { - sValue += getEscape(); - } - else - { - sValue += chr; - usedChar(); - } - } - } - } - } - else - { - throw Bu::XmlException("Expected an equals to seperate the params."); - return false; - } - - return true; -} - -bool XmlReader::content() -{ - Bu::FString sContent; - - if( bStrip ) gcall( ws() ); - - while( true ) - { - char chr = getChar(); - if( chr == '<' ) - { - if( getChar(1) == '/' ) - { - if( sContent.getSize() > 0 ) - { - if( bStrip ) - { - int j; - for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); - sContent[j+1] = '\0'; - } - setContent( sContent.getStr() ); - } - usedChar( 2 ); - gcall( ws() ); - Bu::FString sName; - while( true ) - { - chr = getChar(); - if( isws( chr ) || chr == '>' ) - { - if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) ) - { - closeNode(); - break; - } - else - { - throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() ); - } - } - else - { - sName += chr; - usedChar(); - } - } - gcall( ws() ); - if( getChar() == '>' ) - { - usedChar(); - return true; - } - else - { - throw Bu::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 Bu::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 Bu::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( sContent.getSize() > 0 ) - { - if( bStrip ) - { - int j; - for( j = sContent.getSize()-1; isws(sContent[j]); j-- ); - sContent[j+1] = '\0'; - } - setContent( sContent.getStr() ); - sContent.clear(); - } - gcall( node() ); - } - - if( bStrip ) gcall( ws() ); - } - else if( chr == '&' ) - { - sContent += getEscape(); - } - else - { - sContent += chr; - usedChar(); - } - } -} - diff --git a/src/xmlreader.h b/src/xmlreader.h deleted file mode 100644 index 7c85ddb..0000000 --- a/src/xmlreader.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef XMLREADER -#define XMLREADER - -#include -#include "bu/xmldocument.h" -#include "bu/hash.h" -#include "bu/fstring.h" -#include "bu/stream.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( Bu::Stream &sIn, 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 ); - - /** - * Called to increment the current stream position by a single character. - */ - virtual void usedChar( int nAmnt = 1 ); - - /** - * 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 Bu::FString &name, const Bu::FString &value ); - - Bu::FString 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(); - - Bu::FString sContent; /**< buffer for the current node's content. */ - Bu::FString sParamName; /**< buffer for the current param's name. */ - Bu::FString sParamValue; /**< buffer for the current param's value. */ - Bu::Stream &sIn; - bool bStrip; /**< Are we stripping whitespace? */ - - Bu::Hash htEntity; /**< Entity type definitions. */ - - Bu::FString sBuf; -}; - -#endif diff --git a/src/xmlwriter.cpp b/src/xmlwriter.cpp deleted file mode 100644 index 7dc6ca9..0000000 --- a/src/xmlwriter.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include "xmlwriter.h" - -XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) : - XmlDocument( pRoot ), - sIndent( sIndent ) -{ -} - -XmlWriter::~XmlWriter() -{ -} - -void XmlWriter::write() -{ - write( getRoot(), sIndent.c_str() ); -} - -void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent ) -{ - writeNode( pRoot, 0, sIndent ); -} - -void XmlWriter::closeNode() -{ - XmlDocument::closeNode(); - - if( isCompleted() ) - { - write( getRoot(), sIndent.c_str() ); - } -} - -void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent ) -{ - if( sIndent == NULL ) return; - for( int j = 0; j < nIndent; j++ ) - { - writeString( sIndent ); - } -} - -Bu::FString XmlWriter::escape( const Bu::FString &sIn ) -{ - Bu::FString sOut; - - int nMax = sIn.getSize(); - for( int j = 0; j < nMax; j++ ) - { - char c = sIn[j]; - if( ((c >= ' ' && c <= '9') || - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') ) && - (c != '\"' && c != '\'' && c != '&') - ) - { - sOut += c; - } - else - { - sOut += "&#"; - char buf[4]; - sprintf( buf, "%u", (unsigned char)c ); - sOut += buf; - sOut += ';'; - } - } - - return sOut; -} - -void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &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 Bu::FString &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 deleted file mode 100644 index 7e3c876..0000000 --- a/src/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 Bu::FString &sIndent="", 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: - Bu::FString sIndent; /**< The indent string */ - - Bu::FString escape( const Bu::FString &sIn ); - - /** - * Write the file. - *@param pNode The root node - *@param sIndent The indent text. - */ - void write( XmlNode *pNode, const Bu::FString &sIndent ); - - /** - * 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 Bu::FString &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 Bu::FString &sIndent ); - - /** - * Called to write the actual indent. - *@param nIndent The indent level. - *@param sIndent The indent text. - */ - void writeIndent( int nIndent, const Bu::FString &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 Bu::FString &sString ) = 0; -}; - -#endif -- cgit v1.2.3 From 8b12972092777af56ae21f65b41f4c40d52c2367 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 18 Jun 2007 19:42:34 +0000 Subject: Added the protocol class. servers work, but don't send data, updated the streams to include many more state indicators and caps queries, and everything is working better in general. --- src/bzip2.cpp | 7 +++++- src/bzip2.h | 2 ++ src/client.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/client.h | 20 +++++++++++++--- src/file.cpp | 17 +++++++++++++- src/file.h | 6 ++++- src/filter.cpp | 19 ++++++++++++++-- src/filter.h | 6 ++++- src/protocol.cpp | 12 ++++++++++ src/protocol.h | 26 +++++++++++++++++++++ src/server.cpp | 11 ++++++--- src/server.h | 8 +++++-- src/socket.cpp | 48 ++++++++++++++++++++++++++++++++------- src/socket.h | 6 ++++- src/stream.h | 35 +++++++++++++++++++++++++++- 15 files changed, 266 insertions(+), 26 deletions(-) create mode 100644 src/protocol.cpp create mode 100644 src/protocol.h (limited to 'src/file.cpp') diff --git a/src/bzip2.cpp b/src/bzip2.cpp index d3f237a..66786e4 100644 --- a/src/bzip2.cpp +++ b/src/bzip2.cpp @@ -128,7 +128,7 @@ size_t Bu::BZip2::read( void *pData, size_t nBytes ) { if( bzState.avail_in > 0 ) { - if( rNext.canSeek() ) + if( rNext.isSeekable() ) { rNext.seek( -bzState.avail_in ); } @@ -185,3 +185,8 @@ size_t Bu::BZip2::write( const void *pData, size_t nBytes ) return sTotalOut; } +bool Bu::BZip2::isOpen() +{ + return (bzState.state != NULL); +} + diff --git a/src/bzip2.h b/src/bzip2.h index a23f07a..25f10c5 100644 --- a/src/bzip2.h +++ b/src/bzip2.h @@ -22,6 +22,8 @@ namespace Bu virtual size_t read( void *pBuf, size_t nBytes ); virtual size_t write( const void *pBuf, size_t nBytes ); + virtual bool isOpen(); + private: void bzError( int code ); bz_stream bzState; diff --git a/src/client.cpp b/src/client.cpp index a33cdc3..cf96424 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1,6 +1,16 @@ -#include "client.h" +#include "bu/client.h" +#include "bu/socket.h" +#include +#include +#include "bu/exceptions.h" +#include "bu/protocol.h" -Bu::Client::Client() +/** Read buffer size. */ +#define RBS (1024*2) + +Bu::Client::Client( Bu::Socket *pSocket ) : + pSocket( pSocket ), + pProto( NULL ) { } @@ -8,3 +18,58 @@ Bu::Client::~Client() { } +void Bu::Client::processInput() +{ + char buf[RBS]; + size_t nRead, nTotal=0; + + for(;;) + { + nRead = pSocket->read( buf, nRead ); + if( nRead < 0 ) + { + throw Bu::ConnectionException( + excodeReadError, + "Read error: %s", + strerror( errno ) + ); + } + else if( nRead == 0 ) + { + break; + } + else + { + nTotal += nRead; + sReadBuf.append( buf, nRead ); + if( !pSocket->canRead() ) + break; + } + } + + if( pProto && nTotal ) + { + pProto->onNewData( this ); + } +} + +void Bu::Client::setProtocol( Protocol *pProto ) +{ + this->pProto = pProto; +} + +Bu::Protocol *Bu::Client::getProtocol() +{ + return pProto; +} + +void Bu::Client::clearProtocol() +{ + pProto = NULL; +} + +Bu::FString &Bu::Client::getInput() +{ + return sReadBuf; +} + diff --git a/src/client.h b/src/client.h index 27fbad4..1a189e2 100644 --- a/src/client.h +++ b/src/client.h @@ -2,21 +2,35 @@ #define CLIENT_H #include -#include "bu/socket.h" + +#include "bu/fstring.h" namespace Bu { + class Protocol; + class Socket; + /** * */ class Client { public: - Client(); + Client( Bu::Socket *pSocket ); virtual ~Client(); - private: + void processInput(); + Bu::FString &getInput(); + + void setProtocol( Protocol *pProto ); + Bu::Protocol *getProtocol(); + void clearProtocol(); + + private: + Bu::Socket *pSocket; + Bu::Protocol *pProto; + Bu::FString sReadBuf; }; } diff --git a/src/file.cpp b/src/file.cpp index 2965afa..368b788 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -109,7 +109,17 @@ bool Bu::File::canWrite() return true; } -bool Bu::File::canSeek() +bool Bu::File::isReadable() +{ + return true; +} + +bool Bu::File::isWritable() +{ + return true; +} + +bool Bu::File::isSeekable() { return true; } @@ -139,3 +149,8 @@ void Bu::File::chmod( mode_t t ) fchmod( fileno( fh ), t ); } +bool Bu::File::isOpen() +{ + return (fh != NULL); +} + diff --git a/src/file.h b/src/file.h index 8107a1b..fe8dbda 100644 --- a/src/file.h +++ b/src/file.h @@ -25,12 +25,16 @@ namespace Bu virtual void setPos( long pos ); virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual bool isOpen(); virtual void flush(); virtual bool canRead(); virtual bool canWrite(); - virtual bool canSeek(); + + virtual bool isReadable(); + virtual bool isWritable(); + virtual bool isSeekable(); virtual bool isBlocking(); virtual void setBlocking( bool bBlocking=true ); diff --git a/src/filter.cpp b/src/filter.cpp index 693fb9f..96a8694 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -50,6 +50,11 @@ bool Bu::Filter::isEOS() return rNext.isEOS(); } +bool Bu::Filter::isOpen() +{ + return rNext.isOpen(); +} + bool Bu::Filter::canRead() { return rNext.canRead(); @@ -60,9 +65,19 @@ bool Bu::Filter::canWrite() return rNext.canWrite(); } -bool Bu::Filter::canSeek() +bool Bu::Filter::isReadable() +{ + return rNext.isReadable(); +} + +bool Bu::Filter::isWritable() +{ + return rNext.isWritable(); +} + +bool Bu::Filter::isSeekable() { - return rNext.canSeek(); + return rNext.isSeekable(); } bool Bu::Filter::isBlocking() diff --git a/src/filter.h b/src/filter.h index 088d46e..7bb04bc 100644 --- a/src/filter.h +++ b/src/filter.h @@ -40,12 +40,16 @@ namespace Bu virtual void setPos( long pos ); virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual bool isOpen(); virtual void flush(); virtual bool canRead(); virtual bool canWrite(); - virtual bool canSeek(); + + virtual bool isReadable(); + virtual bool isWritable(); + virtual bool isSeekable(); virtual bool isBlocking(); virtual void setBlocking( bool bBlocking=true ); diff --git a/src/protocol.cpp b/src/protocol.cpp new file mode 100644 index 0000000..0976b3b --- /dev/null +++ b/src/protocol.cpp @@ -0,0 +1,12 @@ +#include "bu/protocol.h" + +using namespace Bu; + +Bu::Protocol::Protocol() +{ +} + +Bu::Protocol::~Protocol() +{ +} + diff --git a/src/protocol.h b/src/protocol.h new file mode 100644 index 0000000..3accd99 --- /dev/null +++ b/src/protocol.h @@ -0,0 +1,26 @@ +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include + +namespace Bu +{ + class Client; + + /** + * + */ + class Protocol + { + public: + Protocol(); + virtual ~Protocol(); + + virtual void onNewData( Bu::Client *pClient )=0; + + private: + + }; +} + +#endif diff --git a/src/server.cpp b/src/server.cpp index abf4c5b..bceeb81 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,5 +1,8 @@ -#include "server.h" +#include "bu/server.h" #include +#include "bu/serversocket.h" +#include "bu/client.h" +#include "bu/socket.h" Bu::Server::Server() : nTimeoutSec( 0 ), @@ -58,7 +61,7 @@ void Bu::Server::scan() } else { - + hClients.get( j )->processInput(); } } } @@ -68,7 +71,9 @@ void Bu::Server::addClient( int nSocket, int nPort ) { FD_SET( nSocket, &fdActive ); - Client *c = new Client(); + Client *c = new Client( + new Bu::Socket( nSocket ) + ); hClients.insert( nSocket, c ); onNewConnection( c, nPort ); diff --git a/src/server.h b/src/server.h index 942eb32..3331d2c 100644 --- a/src/server.h +++ b/src/server.h @@ -2,12 +2,16 @@ #define SERVER_H #include -#include "bu/serversocket.h" + +#include "bu/fstring.h" #include "bu/list.h" -#include "bu/client.h" namespace Bu { + class ServerSocket; + class Socket; + class Client; + /** * Core of a network server. This class is distinct from a ServerSocket in * that a ServerSocket is one listening socket, nothing more. Socket will diff --git a/src/socket.cpp b/src/socket.cpp index 1832898..bd05024 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -109,13 +109,6 @@ void Bu::Socket::close() ::close( nSocket ); } bActive = false; - //xInputBuf.clearData(); - //xOutputBuf.clearData(); - //if( pProtocol != NULL ) - //{ - // delete pProtocol; - // pProtocol = NULL; - //} } /* @@ -218,15 +211,49 @@ bool Bu::Socket::isEOS() bool Bu::Socket::canRead() { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nSocket, &rfds); + struct timeval tv = { 0, 0 }; + int retval = select( nSocket+1, &rfds, NULL, NULL, &tv ); + if( retval == -1 ) + throw ConnectionException( + excodeBadReadError, + "Bad Read error" + ); + if( !FD_ISSET( nSocket, &rfds ) ) + return false; return true; } bool Bu::Socket::canWrite() { + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(nSocket, &wfds); + struct timeval tv = { 0, 0 }; + int retval = select( nSocket+1, NULL, &wfds, NULL, &tv ); + if( retval == -1 ) + throw ConnectionException( + excodeBadReadError, + "Bad Read error" + ); + if( !FD_ISSET( nSocket, &wfds ) ) + return false; return true; } -bool Bu::Socket::canSeek() +bool Bu::Socket::isReadable() +{ + return true; +} + +bool Bu::Socket::isWritable() +{ + return true; +} + +bool Bu::Socket::isSeekable() { return false; } @@ -244,3 +271,8 @@ void Bu::Socket::flush() { } +bool Bu::Socket::isOpen() +{ + return bActive; +} + diff --git a/src/socket.h b/src/socket.h index 30a43fb..c9dbd8d 100644 --- a/src/socket.h +++ b/src/socket.h @@ -28,12 +28,16 @@ namespace Bu virtual void setPos( long pos ); virtual void setPosEnd( long pos ); virtual bool isEOS(); + virtual bool isOpen(); virtual void flush(); virtual bool canRead(); virtual bool canWrite(); - virtual bool canSeek(); + + virtual bool isReadable(); + virtual bool isWritable(); + virtual bool isSeekable(); virtual bool isBlocking(); virtual void setBlocking( bool bBlocking=true ); diff --git a/src/stream.h b/src/stream.h index a80586b..ba070d3 100644 --- a/src/stream.h +++ b/src/stream.h @@ -31,12 +31,45 @@ namespace Bu virtual void setPos( long pos ) = 0; virtual void setPosEnd( long pos ) = 0; virtual bool isEOS() = 0; + virtual bool isOpen() = 0; virtual void flush() = 0; + /** + * In non-blocking streams this indicates if a read operation will + * return data at the moment or not. In blocking streams this should + * return the same value as isEOS(). + */ virtual bool canRead() = 0; + + /** + * In non-blocking streams this indicates if a write operation will + * succeed or fail. In some cases writing is not allowed (e.g. + * internal buffers are full) temporarilly. In blocking streams this + * should return the same value as isWritable. + */ virtual bool canWrite() = 0; - virtual bool canSeek() = 0; + + /** + * Indicates if the stream is capable of read operations. This does not + * indicate if such operations will return useful data, see canRead for + * that. + */ + virtual bool isReadable() = 0; + + /** + * Indicates if the stream is capable of write operations. This does + * not indicate if such operations will succeed or fail, see canWrite + * for that. + */ + virtual bool isWritable() = 0; + + /** + * Indicates if the stream is capable of seek operations. This is + * generally false for non-blocking streams. Some buffered streams may + * support limited in-buffer seeking. + */ + virtual bool isSeekable() = 0; virtual bool isBlocking() = 0; virtual void setBlocking( bool bBlocking=true ) = 0; -- cgit v1.2.3 From 2b0fa89df615cb4789668014475ae64d99e773b5 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 19 Jun 2007 06:05:55 +0000 Subject: david - got some things compiling on win32 (wine/devc++) --- fstringtest.dev | 59 ++++++++++++++ libbu++.dev | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/file.cpp | 10 ++- src/file.h | 2 + src/tests/fstring.cpp | 10 +++ 5 files changed, 286 insertions(+), 4 deletions(-) create mode 100644 fstringtest.dev create mode 100644 libbu++.dev (limited to 'src/file.cpp') diff --git a/fstringtest.dev b/fstringtest.dev new file mode 100644 index 0000000..297242d --- /dev/null +++ b/fstringtest.dev @@ -0,0 +1,59 @@ +[Project] +FileName=fstringtest.dev +Name=fstringtest +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes=z:\home\neonphog\wine_documents\libbu++\src\bu +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler=_@@_ +Linker=libbu++.a_@@_ +IsCpp=1 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=fstringtest.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit1] +FileName=src\tests\fstring.cpp +CompileCpp=1 +Folder=fstringtest +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/libbu++.dev b/libbu++.dev new file mode 100644 index 0000000..2fb1ae9 --- /dev/null +++ b/libbu++.dev @@ -0,0 +1,209 @@ +[Project] +FileName=libbu++.dev +Name=libbu++ +UnitCount=16 +Type=2 +Ver=1 +ObjFiles= +Includes=z:\home\neonphog\wine_documents\libbu++\src\bu +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker= +IsCpp=1 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=libbu++.a +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 + +[Unit1] +FileName=src\stream.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit2] +FileName=src\stream.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=src\file.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=src\file.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=src\fstring.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=src\fstring.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=src\archival.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=src\archival.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=src\archive.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=src\archive.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=src\hash.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=src\hash.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=src\exceptionbase.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=src\exceptionbase.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=src\list.cpp +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=src\list.h +CompileCpp=1 +Folder=libbu++ +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/src/file.cpp b/src/file.cpp index 368b788..1a8bd08 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -134,19 +134,21 @@ void Bu::File::setBlocking( bool bBlocking ) return; } +#ifndef WIN32 void Bu::File::truncate( long nSize ) { ftruncate( fileno( fh ), nSize ); } -void Bu::File::flush() +void Bu::File::chmod( mode_t t ) { - fflush( fh ); + fchmod( fileno( fh ), t ); } +#endif -void Bu::File::chmod( mode_t t ) +void Bu::File::flush() { - fchmod( fileno( fh ), t ); + fflush( fh ); } bool Bu::File::isOpen() diff --git a/src/file.h b/src/file.h index 1a4421b..0f638a7 100644 --- a/src/file.h +++ b/src/file.h @@ -47,6 +47,7 @@ namespace Bu *@param sFlags (const char *) Standard file flags 'rb'... etc.. *@returns (Bu::File) A file object representing your temp file. */ +#ifndef WIN32 inline static Bu::File tempFile( Bu::FString &sName, const char *sFlags ) { int afh_d = mkstemp( sName.getStr() ); @@ -66,6 +67,7 @@ namespace Bu *@param t (mode_t) The new file access permissions. */ void chmod( mode_t t ); +#endif private: FILE *fh; diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp index d600be6..48dfc5f 100644 --- a/src/tests/fstring.cpp +++ b/src/tests/fstring.cpp @@ -3,12 +3,22 @@ #include #include +#ifndef WIN32 inline double getTime() { struct timeval tv; gettimeofday( &tv, NULL ); return ((double)tv.tv_sec) + ((double)tv.tv_usec/1000000.0); } +#else +#include "windows.h" +#include "winbase.h" +inline double getTime() +{ + uint32_t t = (uint32_t) GetTickCount(); + return (double) t / 1000.0; +} +#endif Bu::FString genThing() { -- cgit v1.2.3