/* * Copyright (C) 2007-2023 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/blob.h" #include "bu/blobbuilder.h" #include "bu/exceptioninvaliditerator.h" #include "bu/exceptionindexoutofbounds.h" // Temporary #include "bu/string.h" #include Bu::Blob::Blob() : pData( 0 ), iSize( 0 ) { } Bu::Blob::Blob( const Bu::Blob &rSrc ) : pData( 0 ), iSize( rSrc.iSize ) { pData = new char[rSrc.iSize+1]; memcpy( pData, rSrc.pData, iSize+1 ); } Bu::Blob::Blob( const class BlobBuilder &rSrc ) : pData( 0 ), iSize( 0 ) { iSize = rSrc.getSize(); pData = new char[iSize+1]; rSrc.copyTo( pData, iSize ); pData[iSize] = '\0'; } Bu::Blob::Blob( const char *pSrc ) : pData( 0 ), iSize( 0 ) { for(; iSize < __INT_MAX__ && pSrc[iSize]; iSize++ ) { } pData = new char[iSize+1]; memcpy( pData, pSrc, iSize+1 ); } Bu::Blob::Blob( const void *pSrc, int32_t iSize ) : pData( 0 ), iSize( iSize ) { pData = new char[iSize+1]; memcpy( pData, pSrc, iSize ); pData[iSize] = '\0'; } Bu::Blob::Blob( int32_t iSize ) : pData( 0 ), iSize( iSize ) { pData = new char[iSize+1]; memset( pData, iSize+1, 1 ); } Bu::Blob::Blob( const Bu::Blob::const_iterator &iStart ) : pData( 0 ), iSize( 0 ) { if( !iStart ) return; iSize = iStart.pBlob->iSize - iStart.iIndex; pData = new char[iSize+1]; memcpy( pData, iStart.pBlob->pData+iStart.iIndex, iSize ); } Bu::Blob::Blob( const Bu::Blob::const_iterator &iStart, const Bu::Blob::const_iterator &iEnd ) : pData( 0 ), iSize( 0 ) { if( !iStart ) return; if( iEnd ) { iSize = iEnd.iIndex - iStart.iIndex; } else { iSize = iStart.pBlob->iSize - iStart.iIndex; } pData = new char[iSize+1]; memcpy( pData, iStart.pBlob->pData+iStart.iIndex, iSize ); pData[iSize] = 0; } Bu::Blob::Blob( const Bu::String &rSrc ) : pData( 0 ), iSize( rSrc.getSize() ) { pData = new char[rSrc.getSize()+1]; memcpy( pData, rSrc.getStr(), iSize+1 ); } Bu::Blob::~Blob() { delete[] pData; pData = 0; iSize = 0; } void Bu::Blob::setSize( int32_t iSize ) { delete[] pData; pData = new char[iSize+1]; memset( pData, iSize, 1 ); this->iSize = iSize; } int32_t Bu::Blob::getSize() const { return iSize; } void Bu::Blob::setData( const char *pSrc, int32_t iSize ) { delete[] pData; pData = new char[iSize+1]; memset( pData, iSize, 1 ); this->iSize = iSize; memcpy( pData, pSrc, iSize ); } char *Bu::Blob::getData() const { return pData; } char *Bu::Blob::c_str() const { return pData; } char &Bu::Blob::operator[]( int32_t iIndex ) { if( iIndex < 0 || iIndex >= iSize || pData == NULL ) throw Bu::ExceptionIndexOutOfBounds(); return pData[iIndex]; } char Bu::Blob::operator[]( int32_t iIndex ) const { if( iIndex < 0 || iIndex >= iSize || pData == NULL ) throw Bu::ExceptionIndexOutOfBounds(); return pData[iIndex]; } bool Bu::Blob::isEmpty() const { return pData != NULL && iSize == 0; } bool Bu::Blob::isNull() const { return pData == NULL; } bool Bu::Blob::isNullOrEmpty() const { return pData == NULL || iSize == 0; } Bu::Blob &Bu::Blob::operator=( const Bu::Blob &rRhs ) { delete[] pData; iSize = rRhs.iSize; pData = new char[iSize+1]; memcpy( pData, rRhs.pData, iSize+1 ); return *this; } Bu::Blob &Bu::Blob::operator=( const char *pRhs ) { delete[] pData; for(iSize = 0; iSize < __INT_MAX__ && pRhs[iSize]; iSize++ ) { } pData = new char[iSize+1]; memcpy( pData, pRhs, iSize+1 ); return *this; } bool Bu::Blob::operator==( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return true; if( iSize != rRhs.iSize ) return false; for( int32_t j = 0; j < iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return false; } return true; } bool Bu::Blob::operator==( const char *pRhs ) const { if( pData == pRhs ) return true; for( int32_t j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) return false; } if( pRhs[iSize] == '\0' ) return true; return false; } bool Bu::Blob::operator!=( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return false; if( iSize != rRhs.iSize ) return true; for( int32_t j = 0; j < iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return true; } return false; } bool Bu::Blob::operator!=( const char *pRhs ) const { if( pData == pRhs ) return false; int32_t j; for( j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) { return true; } } if( !(iSize == j && pRhs[j] == '\0') ) { return true; } return false; } bool Bu::Blob::operator<( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return false; for( int32_t j = 0; j < iSize && j < rRhs.iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return pData[j] < rRhs.pData[j]; } if( iSize < rRhs.iSize ) return true; return false; } bool Bu::Blob::operator<( const char *pRhs ) const { if( pData == pRhs ) return false; for( int32_t j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) return pData[j] < pRhs[j]; } if( pRhs[iSize] == '\0' ) return false; return true; } bool Bu::Blob::operator<=( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return true; for( int32_t j = 0; j < iSize && j < rRhs.iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return pData[j] < rRhs.pData[j]; } return iSize <= rRhs.iSize; } bool Bu::Blob::operator<=( const char *pRhs ) const { if( pData == pRhs ) return true; for( int32_t j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) return pData[j] < pRhs[j]; } if( pRhs[iSize] == '\0' ) return true; return true; } bool Bu::Blob::operator>( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return false; for( int32_t j = 0; j < iSize && j < rRhs.iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return pData[j] > rRhs.pData[j]; } if( iSize > rRhs.iSize ) return true; return false; } bool Bu::Blob::operator>( const char *pRhs ) const { if( pData == pRhs ) return false; int32_t j; for( j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) return pData[j] > pRhs[j]; } if( pRhs[j] == '\0' && iSize-1 > j ) return true; return false; } bool Bu::Blob::operator>=( const Bu::Blob &rRhs ) const { if( pData == rRhs.pData ) return true; for( int32_t j = 0; j < iSize && j < rRhs.iSize; j++ ) { if( pData[j] != rRhs.pData[j] ) return pData[j] > rRhs.pData[j]; } return iSize >= rRhs.iSize; } bool Bu::Blob::operator>=( const char *pRhs ) const { if( pData == pRhs ) return true; int32_t j; for( j = 0; j < iSize && pRhs[j]; j++ ) { if( pData[j] != pRhs[j] ) return pData[j] > pRhs[j]; } if( pRhs[j] == '\0' ) return true; return true; } Bu::Blob::iterator Bu::Blob::begin() { return iterator( this, true ); } Bu::Blob::const_iterator Bu::Blob::begin() const { return const_iterator( this, true ); } Bu::Blob::iterator Bu::Blob::end() { return iterator(); } Bu::Blob::const_iterator Bu::Blob::end() const { return const_iterator(); } Bu::Blob::iterator Bu::Blob::rbegin() { return iterator( this, false ); } Bu::Blob::const_iterator Bu::Blob::rbegin() const { return const_iterator( this, false ); } Bu::Blob::iterator Bu::Blob::rend() { return iterator(); } Bu::Blob::const_iterator Bu::Blob::rend() const { return const_iterator(); } ///// // Iterators // Bu::Blob::iterator::iterator( Bu::Blob *pBlob, bool bForward ) : pBlob( pBlob ), iIndex( bForward?0:pBlob->iSize-1 ), bForward( bForward ) { } Bu::Blob::iterator::iterator( Bu::Blob *pBlob, int32_t iIndex, bool bForward ) : pBlob( pBlob ), iIndex( iIndex ), bForward( bForward ) { } Bu::Blob::iterator::iterator() : pBlob( NULL ), iIndex( -1 ), bForward( true ) { } Bu::Blob::iterator::iterator( const Bu::Blob::iterator &rSrc ) : pBlob( rSrc.pBlob ), iIndex( rSrc.iIndex ), bForward( rSrc.bForward ) { } bool Bu::Blob::iterator::isValid() const { if( !pBlob ) return false; if( iIndex < 0 || iIndex >= pBlob->iSize ) return false; return true; } Bu::Blob::iterator::operator bool() const { return isValid(); } char &Bu::Blob::iterator::operator *() { if( !isValid() ) throw Bu::ExceptionInvalidIterator(); return pBlob->pData[iIndex]; } Bu::Blob::iterator &Bu::Blob::iterator::operator++( int32_t ) { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::iterator &Bu::Blob::iterator::operator++() { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::iterator &Bu::Blob::iterator::operator--( int32_t ) { if( bForward ) --iIndex; else ++iIndex; return *this; } Bu::Blob::iterator &Bu::Blob::iterator::operator--() { if( bForward ) --iIndex; else ++iIndex; return *this; } Bu::Blob::iterator &Bu::Blob::iterator::operator+=( int32_t iDelta ) { if( bForward ) iIndex += iDelta; else iIndex -= iDelta; return *this; } Bu::Blob::iterator &Bu::Blob::iterator::operator-=( int32_t iDelta ) { if( bForward ) iIndex -= iDelta; else iIndex += iDelta; return *this; } Bu::Blob::iterator Bu::Blob::iterator::operator+( int32_t iDelta ) const { return iterator( pBlob, iIndex + iDelta, bForward ); } Bu::Blob::iterator Bu::Blob::iterator::operator-( int32_t iDelta ) const { return iterator( pBlob, iIndex - iDelta, bForward ); } bool Bu::Blob::iterator::operator==( const Bu::Blob::iterator &rRhs ) { if( isValid() == false && rRhs.isValid() == false ) return true; return pBlob == rRhs.pBlob && iIndex == rRhs.iIndex; } bool Bu::Blob::iterator::operator==( const Bu::Blob::const_iterator &rRhs ) { if( isValid() == false && rRhs.isValid() == false ) return true; return pBlob == rRhs.pBlob && iIndex == rRhs.iIndex; } bool Bu::Blob::iterator::operator!=( const Bu::Blob::iterator &rRhs ) { if( isValid() != rRhs.isValid() ) return true; return pBlob != rRhs.pBlob || iIndex != rRhs.iIndex; } bool Bu::Blob::iterator::operator!=( const Bu::Blob::const_iterator &rRhs ) { if( isValid() != rRhs.isValid() ) return true; return pBlob != rRhs.pBlob || iIndex != rRhs.iIndex; } Bu::Blob::iterator &Bu::Blob::iterator::operator=( const Bu::Blob::iterator &rRhs ) { pBlob = rRhs.pBlob; iIndex = rRhs.iIndex; bForward = rRhs.bForward; return *this; } Bu::Blob::const_iterator::const_iterator( const Blob *pBlob, bool bForward ) : pBlob( pBlob ), iIndex( bForward?0:pBlob->iSize-1 ), bForward( bForward ) { } Bu::Blob::const_iterator::const_iterator( const Blob *pBlob, int32_t iIndex, bool bForward ) : pBlob( pBlob ), iIndex( iIndex ), bForward( bForward ) { } Bu::Blob::const_iterator::const_iterator() : pBlob( NULL ), iIndex( -1 ), bForward( true ) { } Bu::Blob::const_iterator::const_iterator( const Bu::Blob::const_iterator &rSrc ) : pBlob( rSrc.pBlob ), iIndex( rSrc.iIndex ), bForward( rSrc.bForward ) { } Bu::Blob::const_iterator::const_iterator( const Bu::Blob::iterator &rSrc ) : pBlob( rSrc.pBlob ), iIndex( rSrc.iIndex ), bForward( rSrc.bForward ) { } bool Bu::Blob::const_iterator::isValid() const { if( !pBlob ) return false; if( iIndex < 0 || iIndex >= pBlob->iSize ) return false; return true; } Bu::Blob::const_iterator::operator bool() const { return isValid(); } char Bu::Blob::const_iterator::operator *() const { if( !isValid() ) throw Bu::ExceptionInvalidIterator(); return pBlob->pData[iIndex]; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator++( int ) { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator++() { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator--( int ) { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator--() { if( bForward ) ++iIndex; else --iIndex; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator+=( int32_t iDelta ) { if( bForward ) iIndex += iDelta; else iIndex -= iDelta; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator-=( int32_t iDelta ) { if( bForward ) iIndex -= iDelta; else iIndex += iDelta; return *this; } Bu::Blob::const_iterator Bu::Blob::const_iterator::operator+( int32_t iDelta ) const { return const_iterator( pBlob, iIndex + iDelta, bForward ); } Bu::Blob::const_iterator Bu::Blob::const_iterator::operator-( int32_t iDelta ) const { return const_iterator( pBlob, iIndex - iDelta, bForward ); } bool Bu::Blob::const_iterator::operator==( const Bu::Blob::iterator &rRhs ) { if( isValid() == false && rRhs.isValid() == false ) return true; return pBlob == rRhs.pBlob && iIndex == rRhs.iIndex; } bool Bu::Blob::const_iterator::operator==( const Bu::Blob::const_iterator &rRhs ) { if( isValid() == false && rRhs.isValid() == false ) return true; return pBlob == rRhs.pBlob && iIndex == rRhs.iIndex; } bool Bu::Blob::const_iterator::operator!=( const Bu::Blob::iterator &rRhs ) { if( isValid() != rRhs.isValid() ) return true; return pBlob != rRhs.pBlob || iIndex != rRhs.iIndex; } bool Bu::Blob::const_iterator::operator!=( const Bu::Blob::const_iterator &rRhs ) { if( isValid() != rRhs.isValid() ) return true; return pBlob != rRhs.pBlob || iIndex != rRhs.iIndex; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator=( const Bu::Blob::iterator &rRhs ) { pBlob = rRhs.pBlob; iIndex = rRhs.iIndex; bForward = rRhs.bForward; return *this; } Bu::Blob::const_iterator &Bu::Blob::const_iterator::operator=( const Bu::Blob::const_iterator &rRhs ) { pBlob = rRhs.pBlob; iIndex = rRhs.iIndex; bForward = rRhs.bForward; return *this; } ///// // Helper functions // template<> uint32_t Bu::__calcHashCode( const Bu::Blob &k ) { int32_t sz = k.getSize(); const char *s = k.getData(); uint32_t iPos = 0; for( int32_t j = 0; j < sz; j++, s++ ) { iPos = *s + (iPos << 6) + (iPos << 16) - iPos; } return iPos; } template<> bool Bu::__cmpHashKeys( const Bu::Blob &a, const Bu::Blob &b ) { return a == b; } #include template<> void Bu::__tracer_format( const Bu::Blob &v ) { printf("(%d)\"%s\"", v.getSize(), v.getData() ); } #include "bu/formatter.h" Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const Bu::Blob &b ) { rOut.writeAligned( b.getData(), b.getSize() ); return rOut; } Bu::Formatter &Bu::operator>>( Bu::Formatter &fIn, Bu::Blob &b ) { Bu::String sTmp = fIn.readToken(); b.setData( sTmp.getStr(), sTmp.getSize() ); return fIn; } Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, const Bu::Blob &b ) { int32_t iSize = b.getSize(); ar << iSize; ar.write( b.getData(), iSize ); return ar; } Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, Bu::Blob &b ) { int32_t iSize; ar >> iSize; b.setSize( iSize ); ar.read( b.getData(), iSize ); return ar; }