From bf53de3dfa4db68627f2935e6b2144835604df3a Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 16 Oct 2009 16:09:02 +0000 Subject: Finally added the substream class, and added getByPath (for properties) and getChildByPath (for groups) to the TafGroup class. --- src/list.h | 62 ++++++++++++++++++++++++--- src/substream.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ src/substream.h | 63 ++++++++++++++++++++++++++++ src/tafgroup.cpp | 37 ++++++++++++++++ src/tafgroup.h | 5 +++ src/unit/substream.unit | 52 +++++++++++++++++++++++ src/unit/taf.unit | 10 +++++ 7 files changed, 333 insertions(+), 5 deletions(-) create mode 100644 src/substream.cpp create mode 100644 src/substream.h create mode 100644 src/unit/substream.unit diff --git a/src/list.h b/src/list.h index c587c1a..d8c5a4a 100644 --- a/src/list.h +++ b/src/list.h @@ -178,11 +178,11 @@ namespace Bu /** * Linked list template container. This class is similar to the stl list - * class except for a few minor changes. First, it doesn't mimic a stack or - * queue, use the Stack or Queue clasess for that. Second, when const, all - * members are only accessable const. Third, erasing a location does not - * invalidate the iterator, it simply points to the next valid location, or - * end() if there are no more. + * class except for a few minor changes. First, when const, all + * members are only accessable const. Second, erasing a location does not + * invalidate the iterator used, it simply points to the next valid + * location, or end() if there are no more. Other iterators pointing to + * the deleted record will, of course, no longer be valid. * *@param value (typename) The type of data to store in your list *@param valuealloc (typename) Memory Allocator for your value type @@ -506,6 +506,32 @@ namespace Bu return *this; } + iterator operator+( int iDelta ) + { + iterator ret( *this ); + for( int j = 0; j < iDelta; j++ ) + { + if( ret.pLink == NULL ) + throw Bu::ExceptionBase( + "Attempt to iterate past begining of list."); + ret.pLink = ret.pLink->pNext; + } + return ret; + } + + iterator operator-( int iDelta ) + { + iterator ret( *this ); + for( int j = 0; j < iDelta; j++ ) + { + if( ret.pLink == NULL ) + throw Bu::ExceptionBase( + "Attempt to iterate past begining of list."); + ret.pLink = ret.pLink->pPrev; + } + return ret; + } + operator bool() { return pLink != NULL; @@ -619,6 +645,32 @@ namespace Bu return *this; } + const_iterator operator+( int iDelta ) + { + const_iterator ret( *this ); + for( int j = 0; j < iDelta; j++ ) + { + if( ret.pLink == NULL ) + throw Bu::ExceptionBase( + "Attempt to iterate past begining of list."); + ret.pLink = ret.pLink->pNext; + } + return ret; + } + + const_iterator operator-( int iDelta ) + { + const_iterator ret( *this ); + for( int j = 0; j < iDelta; j++ ) + { + if( ret.pLink == NULL ) + throw Bu::ExceptionBase( + "Attempt to iterate past begining of list."); + ret.pLink = ret.pLink->pPrev; + } + return ret; + } + const_iterator &operator=( const iterator &oth ) { pLink = oth.pLink; diff --git a/src/substream.cpp b/src/substream.cpp new file mode 100644 index 0000000..ddb31b4 --- /dev/null +++ b/src/substream.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2007-2008 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/substream.h" + +Bu::SubStream::SubStream( Bu::Stream &rNext, long iSize ) : + Bu::Filter( rNext ), + iStart( 0 ), + iPos( 0 ), + iSize( iSize ) +{ + iStart = rNext.tell(); +} + +Bu::SubStream::~SubStream() +{ +} + +size_t Bu::SubStream::read( void *pBuf, size_t nBytes ) +{ + if( (long)nBytes > iSize-iPos ) + nBytes = iSize-iPos; + nBytes = rNext.read( pBuf, nBytes ); + iPos += nBytes; + return nBytes; +} + +size_t Bu::SubStream::write( const void *pBuf, size_t nBytes ) +{ + if( (long)nBytes > iSize-iPos ) + nBytes = iSize-iPos; + nBytes = rNext.write( pBuf, nBytes ); + iPos += nBytes; + return nBytes; +} + +void Bu::SubStream::start() +{ + // doesn't mean anything... +} + +size_t Bu::SubStream::stop() +{ + // doesn't mean anything... + return 0; +} + +void Bu::SubStream::close() +{ + // don't do anything? maybe... +} + +long Bu::SubStream::tell() +{ + return iPos; +} + +void Bu::SubStream::seek( long offset ) +{ + if( iPos+offset < 0 ) + offset = -iPos; + else if( iPos+offset > iSize ) + offset = iSize-iPos; + rNext.seek( offset ); + iPos += offset; +} + +void Bu::SubStream::setPos( long pos ) +{ + if( pos < 0 ) + pos = 0; + else if( pos > iSize ) + pos = iSize; + iPos = pos; + pos += iStart; + rNext.setPos( pos ); +} + +void Bu::SubStream::setPosEnd( long pos ) +{ + if( iSize-pos < 0 ) + pos = 0; + else if( iSize-pos > iSize ) + pos = iSize; + else + pos = iSize-pos; + iPos = pos; + rNext.setPos( iStart+pos ); +} + +bool Bu::SubStream::isEos() +{ + return rNext.isEos() || iPos == iSize; +} + +bool Bu::SubStream::canRead() +{ + return rNext.canRead() && (iPos < iSize); +} + +bool Bu::SubStream::canWrite() +{ + return rNext.canWrite() && (iPos < iSize); +} + diff --git a/src/substream.h b/src/substream.h new file mode 100644 index 0000000..5218493 --- /dev/null +++ b/src/substream.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2008 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_SUB_STREAM_H +#define BU_SUB_STREAM_H + +#include "bu/filter.h" + +namespace Bu +{ + /** + * Creates a sub-stream of a given stream. This allows you to read and + * write safely to a section of another stream, keeping all data within + * the given bounds. The substream acts exactly like a top level stream + * when you reach the bounds of either the containing stream or the + * artificial bounds of the substream, except that unlike many stream types, + * when writing you cannot move beyond the bounds of the substream. Reads, + * on the other hand, work exactly the same way, returning less data than + * requested when the end of the stream is reached. + * + * The substream always begins at the current position in the base stream, + * if you would like to skip some data first, simply seek. + * + * The substream class is safe to use with all blocking and non-blocking + * base streams, including sockets, however it can have unpredictable + * results when used on a buffering stream that may read more data than + * requested in order to complete a request such as the buffer or bzip2 + * filters. + */ + class SubStream : public Bu::Filter + { + public: + SubStream( Bu::Stream &rNext, long iSize ); + virtual ~SubStream(); + + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes ); + using Bu::Stream::write; + + virtual void start(); + virtual size_t stop(); + virtual void close(); + virtual long tell(); + virtual void seek( long offset ); + virtual void setPos( long pos ); + virtual void setPosEnd( long pos ); + virtual bool isEos(); + + virtual bool canRead(); + virtual bool canWrite(); + + protected: + long iStart; + long iPos; + long iSize; + }; +}; + +#endif diff --git a/src/tafgroup.cpp b/src/tafgroup.cpp index 1837bd8..9440912 100644 --- a/src/tafgroup.cpp +++ b/src/tafgroup.cpp @@ -162,3 +162,40 @@ const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName, } } +const Bu::TafGroup *Bu::TafGroup::getChildByPath( + const Bu::FString &sPath ) const +{ + return getChildByPath( sPath.split('/') ); +} + +const Bu::TafGroup *Bu::TafGroup::getChildByPath( Bu::StrList lPath ) const +{ + const Bu::TafGroup *cur = this; + + for( Bu::StrList::const_iterator i = lPath.begin(); i; i++ ) + { + cur = cur->getChild( *i ); + } + + return cur; +} + +const Bu::FString &Bu::TafGroup::getByPath( const Bu::FString &sPath ) const +{ + return getByPath( sPath.split('/') ); +} + +const Bu::FString &Bu::TafGroup::getByPath( Bu::StrList lPath ) const +{ + const Bu::TafGroup *cur = this; + + for( Bu::StrList::const_iterator i = lPath.begin(); i; i++ ) + { + if( !(i+1) ) + break; + cur = cur->getChild( *i ); + } + + return cur->getProperty( lPath.last() ); +} + diff --git a/src/tafgroup.h b/src/tafgroup.h index 6a50d11..f2df669 100644 --- a/src/tafgroup.h +++ b/src/tafgroup.h @@ -16,6 +16,7 @@ namespace Bu { + typedef Bu::List StrList; class TafProperty; class TafComment; /** @@ -53,6 +54,10 @@ namespace Bu TafProperty *addProperty( const Bu::FString &sName, const Bu::FString &sValue ); const NodeList &getChildren() const; + const TafGroup *getChildByPath( const Bu::FString &sPath ) const; + const TafGroup *getChildByPath( StrList lPath ) const; + const Bu::FString &getByPath( const Bu::FString &sPath ) const; + const Bu::FString &getByPath( StrList lPath ) const; private: Bu::FString sName; diff --git a/src/unit/substream.unit b/src/unit/substream.unit new file mode 100644 index 0000000..ef6c70b --- /dev/null +++ b/src/unit/substream.unit @@ -0,0 +1,52 @@ +// vim: syntax=cpp +/* + * Copyright (C) 2007-2008 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/membuf.h" +#include "bu/substream.h" + +{=Init} + +{%testRead01} +{ + Bu::MemBuf mb("abcdefghijklmnopqrstuvwxyz"); + mb.seek( 4 ); + Bu::SubStream ss( mb, 10 ); + unitTest( ss.readLine() == "efghijklmn" ); +} + +{%testRead02} +{ + Bu::MemBuf mb("abcdefghijklmnopqrstuvwxyz"); + mb.seek( 4 ); + Bu::SubStream ss( mb, 10 ); + char buf[8]; + size_t iRead = ss.read( buf, 8 ); + unitTest( iRead == 8 ); + unitTest( strncmp( buf, "efghijkl", 8 ) == 0 ); + unitTest( !ss.isEos() ); + iRead = ss.read( buf, 8 ); + unitTest( iRead == 2 ); + unitTest( strncmp( buf, "mn", 2 ) == 0 ); + unitTest( ss.isEos() ); +} + +{%testRead03} +{ + Bu::MemBuf mb("abcdefghijklmnopqrstuvwxyz"); + mb.seek( 20 ); + Bu::SubStream ss( mb, 10 ); + char buf[8]; + size_t iRead = ss.read( buf, 8 ); + unitTest( iRead == 6 ); + unitTest( strncmp( buf, "uvwxyz", 6 ) == 0 ); + unitTest( ss.isEos() ); + iRead = ss.read( buf, 8 ); + unitTest( iRead == 0 ); + unitTest( ss.isEos() ); +} + diff --git a/src/unit/taf.unit b/src/unit/taf.unit index eeddd53..a9329fe 100644 --- a/src/unit/taf.unit +++ b/src/unit/taf.unit @@ -109,3 +109,13 @@ // Woot } } + +{%bypath1} +{ + Bu::MemBuf mb("{outer: \"Hello=\" {inner: {final: test=hi} } }"); + Bu::TafReader tr( mb ); + const Bu::TafGroup *g = tr.readGroup(); + unitTest( g->getChildByPath("inner/final")->getProperty("test") == "hi" ); + unitTest( g->getByPath("inner/final/test") == "hi" ); +} + -- cgit v1.2.3