/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include #include // NOT FULLY DECLARED SERVICES #include #include #include // both are needed to satisfy all compilers #include // std::va_list and friends #include #include namespace csv { // Maximal sizes of resulting integers in text form: const uintt C_short_max_size = sizeof(short) * 3; const uintt C_int_max_size = sizeof(int) * 3; const uintt C_long_max_size = sizeof(long) * 3; inline void StreamStr::Advance(size_type i_nAddedSize) { pCur += i_nAddedSize; } StreamStr::StreamStr( size_type i_nCapacity ) : bostream(), nCapacity1( i_nCapacity + 1 ), dpData( new char [i_nCapacity + 1] ), pEnd(dpData), pCur(dpData), eMode(str::overwrite) { *pEnd = '\0'; } StreamStr::StreamStr( const char * i_sInitStr, size_type i_nCapacity ) : bostream(), nCapacity1(0), dpData(0), pEnd(0), pCur(0), eMode(str::overwrite) { size_type nLength = strlen(i_sInitStr); nCapacity1 = csv::max(nLength, i_nCapacity) + 1; dpData = new char [nCapacity1]; strcpy(dpData, i_sInitStr); // SAFE STRCPY (#100211# - checked) pCur = dpData + nLength; pEnd = pCur; } StreamStr::StreamStr( size_type i_nGuessedCapacity, const char * str1, const char * str2, ... ) : bostream(), nCapacity1( i_nGuessedCapacity + 1 ), dpData( new char [i_nGuessedCapacity + 1] ), pEnd(dpData), pCur(dpData), eMode(str::overwrite) { *pEnd = '\0'; operator<<(str1); operator<<(str2); ::va_list ap; va_start(ap, str2); for ( const char * strAdd = va_arg(ap,const char*); strAdd != 0; strAdd = va_arg(ap,const char*) ) { size_type nLen = strlen(strAdd); ProvideAddingSize( nLen ); memcpy(pCur, strAdd, nLen); Advance(nLen); } // end for va_end(ap); } StreamStr::StreamStr( const self & i_rOther ) : bostream(), nCapacity1( i_rOther.nCapacity1 ), dpData( new char [i_rOther.nCapacity1] ), pEnd( dpData + strlen(i_rOther.dpData) ), pCur( dpData + i_rOther.tellp() ), eMode(i_rOther.eMode) { strcpy( dpData, i_rOther.dpData ); // SAFE STRCPY (#100211# - checked) } StreamStr::StreamStr(csv::bstream & i_source) : bostream(), nCapacity1(0), dpData(0), pEnd(0), pCur(0), eMode(str::overwrite) { i_source.seek(0, csv::end); nCapacity1 = static_cast(i_source.position()) + 1; i_source.seek(0); dpData = new char[nCapacity1]; i_source.read(dpData, nCapacity1 - 1); pCur = dpData + nCapacity1 - 1; pEnd = pCur; *pCur = '\0'; } StreamStr::~StreamStr() { delete [] dpData; } StreamStr & StreamStr::operator=( const self & i_rOther ) { delete [] dpData; nCapacity1 = i_rOther.nCapacity1; dpData = new char [i_rOther.nCapacity1]; pEnd = dpData + strlen(i_rOther.dpData); strcpy( dpData, i_rOther.dpData ); // SAFE STRCPY (#100211# - checked) pCur = dpData + i_rOther.tellp(); eMode = i_rOther.eMode; return *this; } StreamStr & StreamStr::operator<<( const char * i_s ) { size_type nLength = strlen(i_s); ProvideAddingSize( nLength ); memcpy( pCur, i_s, nLength ); Advance(nLength); return *this; } StreamStr & StreamStr::operator<<( const String & i_s ) { size_type nLength = i_s.length(); ProvideAddingSize( nLength ); memcpy( pCur, i_s.c_str(), nLength ); Advance(nLength); return *this; } StreamStr & StreamStr::operator<<( char i_c ) { ProvideAddingSize( 1 ); *pCur = i_c; Advance(1); return *this; } StreamStr & StreamStr::operator<<( unsigned char i_c ) { return operator<<( char(i_c) ); } StreamStr & StreamStr::operator<<( signed char i_c ) { return operator<<( char(i_c) ); } StreamStr & StreamStr::operator<<( short i_n ) { char buf[C_short_max_size] = ""; sprintf( buf, "%hi", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( unsigned short i_n ) { char buf[C_short_max_size] = ""; sprintf( buf, "%hu", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( int i_n ) { char buf[C_int_max_size] = ""; sprintf( buf, "%i", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( unsigned int i_n ) { char buf[C_int_max_size] = ""; sprintf( buf, "%u", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( long i_n ) { char buf[C_long_max_size] = ""; sprintf( buf, "%li", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( unsigned long i_n ) { char buf[C_long_max_size] = ""; sprintf( buf, "%lu", i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( float i_n ) { const int C_float_max_size = 20; char buf[C_float_max_size] = ""; sprintf( buf, "%.*g", C_float_max_size-8, i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } StreamStr & StreamStr::operator<<( double i_n ) { const int C_double_max_size = 30; char buf[C_double_max_size] = ""; sprintf( buf, "%.*lg", C_double_max_size-8, i_n ); // SAFE SPRINTF (#100211# - checked) size_type nLength = strlen(buf); ProvideAddingSize( nLength ); memcpy( pCur, buf, nLength ); Advance( nLength ); return *this; } const char & StreamStr::operator[]( position_type i_nPosition ) const { static const char aNull_ = '\0'; if ( position_type(pEnd - dpData) > i_nPosition ) return dpData[i_nPosition]; return aNull_; } char & StreamStr::operator[]( position_type i_nPosition ) { static char aDummy_ = '\0'; if ( position_type(pEnd - dpData) > i_nPosition ) return dpData[i_nPosition]; return aDummy_; } void StreamStr::resize( size_type i_nMinimumCapacity ) { if ( i_nMinimumCapacity <= capacity() ) return; Resize(i_nMinimumCapacity); } void StreamStr::swap( StreamStr & io_swap ) { size_type n = io_swap.nCapacity1; io_swap.nCapacity1 = nCapacity1; nCapacity1 = n; char * p = io_swap.dpData; io_swap.dpData = dpData; dpData = p; p = io_swap.pEnd; io_swap.pEnd = pEnd; pEnd = p; p = io_swap.pCur; io_swap.pCur = pCur; pCur = p; insert_mode m = io_swap.eMode; io_swap.eMode = eMode; eMode = m; } StreamStr & StreamStr::seekp( seek_type i_nCount, seek_dir i_eDirection ) { seek_type nLength = seek_type( length() ); seek_type nNewPos = tellp(); switch ( i_eDirection ) { case ::csv::beg: nNewPos = i_nCount; break; case ::csv::cur: nNewPos += i_nCount; break; case ::csv::end: nNewPos = nLength + i_nCount; break; } if ( in_range(0, nNewPos, nLength + 1) ) { pCur = dpData + nNewPos; if (eMode == str::overwrite) { pEnd = pCur; *pEnd = '\0'; } } return *this; } StreamStr & StreamStr::set_insert_mode( insert_mode i_eMode ) { eMode = i_eMode; return *this; } void StreamStr::push_front( const char * i_str ) { insert_mode eOriginalMode = eMode; char * pOriginalCur = pCur; eMode = str::insert; pCur = dpData; operator<<(i_str); eMode = eOriginalMode; pCur = pOriginalCur + strlen(i_str); } void StreamStr::push_front( char i_c ) { insert_mode eOriginalMode = eMode; char * pOriginalCur = pCur; eMode = str::insert; pCur = dpData; operator<<(i_c); eMode = eOriginalMode; pCur = pOriginalCur + 1; } void StreamStr::push_back( const char * i_str ) { insert_mode eOriginalMode = eMode; eMode = str::overwrite; operator<<(i_str); eMode = eOriginalMode; } void StreamStr::push_back( char i_c ) { insert_mode eOriginalMode = eMode; eMode = str::overwrite; operator<<(i_c); eMode = eOriginalMode; } void StreamStr::pop_front( size_type i_nCount ) { size_type nCount = min(i_nCount, length()); MoveData( dpData + nCount, pEnd, -(seek_type(nCount)) ); pCur -= nCount; pEnd -= nCount; *pEnd = '\0'; } void StreamStr::pop_back( size_type i_nCount ) { size_type nCount = min(i_nCount, length()); pEnd -= nCount; if (pCur > pEnd) pCur = pEnd; *pEnd = '\0'; } StreamStr & StreamStr::operator_join( std::vector::const_iterator i_rBegin, std::vector::const_iterator i_rEnd, const char * i_sLink ) { std::vector::const_iterator it = i_rBegin; if ( it != i_rEnd ) { operator<<(*it); for ( ++it; it != i_rEnd; ++it ) { operator<<(i_sLink); operator<<(*it); } } return *this; } StreamStr & StreamStr::operator_add_substr( const char * i_sText, size_type i_nLength ) { size_type nLength = csv::min(i_nLength, strlen(i_sText)); ProvideAddingSize( nLength ); memcpy( pCur, i_sText, nLength ); Advance(nLength); return *this; } StreamStr & StreamStr::operator_add_token( const char * i_sText, char i_cDelimiter ) { const char * pTokenEnd = strchr(i_sText, i_cDelimiter); if (pTokenEnd == 0) operator<<(i_sText); else operator_add_substr(i_sText, pTokenEnd-i_sText); return *this; } StreamStr & StreamStr::operator_read_line( bstream & i_src ) { char c = 0; intt nCount = 0; for ( nCount = i_src.read(&c, 1); nCount == 1 AND c != 13 AND c != 10; nCount = i_src.read(&c, 1) ) { operator<<(c); } bool bEndOfStream = nCount == 0; // Check for line-end: if ( NOT bEndOfStream AND c != 0 ) { char oldc = c; if (i_src.read(&c, 1) == 1) { if ( (c != 13 AND c != 10) OR c == oldc) i_src.seek(-1,::csv::cur); } } return *this; } void StreamStr::strip_front(char i_cToRemove) { const_iterator it = begin(); for ( ; it != end() ? *it == i_cToRemove : false; ++it ) ; pop_front(it - begin()); } void StreamStr::strip_back(char i_cToRemove) { const_iterator it = end(); for ( ; it != begin() ? *(it-1) == i_cToRemove : false; --it ) ; pop_back(end() - it); } void StreamStr::strip_frontback(char i_cToRemove) { strip_front(i_cToRemove); strip_back(i_cToRemove); } void StreamStr::strip_front_whitespace() { const_iterator it = begin(); for ( ; it != end() ? *it < 33 : false; ++it ) ; pop_front(it - begin()); } void StreamStr::strip_back_whitespace() { const_iterator it = end(); for ( ; it != begin() ? *(it-1) < 33 : false; --it ) ; pop_back(end() - it); } void StreamStr::strip_frontback_whitespace() { strip_front_whitespace(); strip_back_whitespace(); } void StreamStr::remove( iterator i_begin, iterator i_end ) { csv_assert(i_begin >= dpData AND i_begin <= pEnd); csv_assert(i_end >= dpData AND i_end <= pEnd); csv_assert(i_end >= i_begin); MoveData(i_end, pEnd, i_begin - i_end); pCur = pEnd; } void StreamStr::replace( position_type i_nStart, size_type i_nSize, Area i_aReplacement ) { if (i_nStart >= length() OR i_nSize < 1) return; insert_mode eOldMode = eMode; eMode = str::insert; pCur = dpData + i_nStart; size_type anz = min( length() - i_nStart, i_nSize ); if ( anz < i_aReplacement.nLength ) { ProvideAddingSize( i_aReplacement.nLength - anz ); } else if ( anz > i_aReplacement.nLength ) { seek_type nMove = seek_type(anz - i_aReplacement.nLength); MoveData( dpData + i_nStart + anz, pEnd, -nMove ); pEnd -= nMove; *pEnd = '\0'; } if (i_aReplacement.nLength > 0) { memcpy( dpData + i_nStart, i_aReplacement.sStr, i_aReplacement.nLength ); Advance(i_aReplacement.nLength); } eMode = eOldMode; pCur = pEnd; } void StreamStr::replace_all( char i_cCarToSearch, char i_cReplacement ) { for ( char * p = dpData; p != pEnd; ++p ) { if (*p == i_cCarToSearch) *p = i_cReplacement; } } void StreamStr::replace_all( Area i_aStrToSearch, Area i_aReplacement ) { position_type p = 0; const char * pSearch = i_aStrToSearch.sStr; size_type nSearch = i_aStrToSearch.nLength; while ( p <= length() - nSearch ) { if ( strncmp(dpData+p, pSearch, nSearch) == 0 ) { replace( p, nSearch, i_aReplacement ); p += i_aReplacement.nLength; } else { ++p; } } // end while } StreamStr & StreamStr::to_lower( position_type i_nStart, size_type i_nLength ) { static char cLower[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 }; if ( i_nStart < length() ) { char * pStop = i_nStart + i_nLength < length() ? dpData + i_nStart + i_nLength : pEnd; for ( char * pChange = dpData + i_nStart; pChange != pStop; ++pChange ) { *pChange = (static_cast< unsigned char >(*pChange) & 0x80) == 0 ? cLower[ UINT8(*pChange) ] : *pChange; } } return *this; } StreamStr & StreamStr::to_upper( position_type i_nStart, size_type i_nLength ) { static char cUpper[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127 }; if ( i_nStart < length() ) { char * pStop = i_nStart + i_nLength < length() ? dpData + i_nStart + i_nLength : pEnd; for ( char * pChange = dpData + i_nStart; pChange != pStop; ++pChange ) { *pChange = (static_cast< unsigned char >(*pChange) & 0x80) == 0 ? cUpper[ UINT8(*pChange) ] : *pChange; } } return *this; } StreamStr::size_type StreamStr::token_count( char i_cSplit ) const { return count_chars(dpData, i_cSplit) + 1; } String StreamStr::token( position_type i_nNr, char i_cSplit ) const { // Find begin: const char * pTokenBegin = dpData; for ( position_type nNr = i_nNr; nNr > 0; --nNr ) { pTokenBegin = strchr(pTokenBegin,i_cSplit); if (pTokenBegin == 0) return String(""); ++pTokenBegin; } // Find end: const char * pTokenEnd = strchr(pTokenBegin, i_cSplit); if (pTokenEnd == 0) pTokenEnd = pEnd; return String(pTokenBegin, size_type(pTokenEnd-pTokenBegin) ); } class StreamStrPool { public: StreamStrPool(); ~StreamStrPool(); private: // Non-copyable StreamStrPool(StreamStrPool &); // not defined void operator =(StreamStrPool &); // not defined // Interface to: friend class StreamStrLock; static StreamStr & AcquireFromPool_( uintt i_nMinimalSize ); static void ReleaseToPool_( DYN StreamStr * let_dpUsedStr ); // DATA SweList< DYN StreamStr* > aPool; }; StreamStrPool::StreamStrPool() { } StreamStrPool::~StreamStrPool() { for ( SweList< DYN StreamStr* >::iterator it = aPool.begin(); it != aPool.end(); ++it ) { delete (*it); } } namespace { static StreamStrPool aPool_; } StreamStr & StreamStrPool::AcquireFromPool_( uintt i_nMinimalSize ) { if ( aPool_.aPool.empty() ) { return *new StreamStr(i_nMinimalSize); } StreamStr & ret = *aPool_.aPool.front(); aPool_.aPool.pop_front(); ret.resize(i_nMinimalSize); ret.seekp(0); ret.set_insert_mode(str::overwrite); return ret; } void StreamStrPool::ReleaseToPool_( DYN StreamStr * let_dpUsedStr ) { aPool_.aPool.push_back( let_dpUsedStr ); } StreamStrLock::StreamStrLock( uintt i_nMinimalSize ) : pStr( &StreamStrPool::AcquireFromPool_(i_nMinimalSize) ) { } StreamStrLock::~StreamStrLock() { StreamStrPool::ReleaseToPool_(pStr); } UINT32 StreamStr::do_write( const void * i_pSrc, UINT32 i_nNrofBytes ) { ProvideAddingSize( i_nNrofBytes ); memcpy( pCur, i_pSrc, i_nNrofBytes ); Advance(i_nNrofBytes); return i_nNrofBytes; } void StreamStr::ProvideAddingSize( size_type i_nSize2Add ) { size_type nLength = length(); if ( capacity() - nLength < i_nSize2Add ) Resize( nLength + i_nSize2Add ); pEnd += i_nSize2Add; *pEnd = '\0'; if (eMode == str::insert AND pCur != pEnd) { MoveData( pCur, pCur + i_nSize2Add, seek_type(i_nSize2Add) ); } } void StreamStr::Resize( size_type i_nMinimumCapacity ) { size_type nNewSize = nCapacity1 < 128 ? nCapacity1 << 1 : (nCapacity1 << 1) - (nCapacity1 >> 1); nCapacity1 = csv::max( nNewSize, size_type(i_nMinimumCapacity + 1) ); char * pNew = new char[nCapacity1]; strcpy ( pNew, dpData ); // SAFE STRCPY (#100211# - checked) pEnd = pNew + (pEnd - dpData); pCur = pNew + (pCur - dpData); delete [] dpData; dpData = pNew; } void StreamStr::MoveData( char * i_pStart, char * i_pEnd, seek_type i_nDiff ) { if (i_nDiff > 0) { register const char * pSrc = i_pEnd; register char * pDest = i_pEnd + i_nDiff; for ( ; pSrc != i_pStart; --pSrc, --pDest ) { *pDest = *pSrc; } *pDest = *pSrc; } else if (i_nDiff < 0) { const char * pSrc = i_pStart; char * pDest = i_pStart + i_nDiff; for ( ; pSrc != i_pEnd; ++pSrc, ++pDest ) { *pDest = *pSrc; } } } // Does nothing, only the name of this function is needed. void c_str() { // Does nothing. } void Split( std::vector & o_list, const char * i_text ) { const char * pCurrentToken = 0; bool white = false; for (const char * p = i_text; *p != '\0'; ++p) { white = UINT8(*p) > 32; if (pCurrentToken != 0) { if (white) { o_list.push_back(String(pCurrentToken, p)); pCurrentToken = 0; } } else { if ( NOT white) pCurrentToken = p; } // endif (bInToken) else } // end for if (pCurrentToken != 0) { o_list.push_back(String(pCurrentToken)); } } } // namespace csv