office-gobmx/cosv/source/strings/streamstr.cxx
2012-06-13 13:31:56 +01:00

606 lines
13 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#define CSV_USE_CSV_ASSERTIONS
#include <cosv/csv_env.hxx>
#include <cosv/comfunc.hxx>
#include <cosv/string.hxx>
#include <cosv/streamstr.hxx>
#include <cosv/std_outp.hxx>
#include <cosv/tpl/dyn.hxx>
// NOT FULLY DECLARED SERVICES
#include <string.h>
#include <stdio.h>
#include <stdarg.h> // both are needed to satisfy all compilers
#include <cstdarg> // std::va_list and friends
#include <cosv/tpl/swelist.hxx>
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 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()
{
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);
}
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<seek_type>(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::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<String>::const_iterator i_rBegin,
std::vector<String>::const_iterator i_rEnd,
const char * i_sLink )
{
std::vector<String>::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<size_type>(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);
}
// Check for line-end:
if ( NOT (nCount == 0) 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_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::replace_all( char i_cCarToSearch,
char i_cReplacement )
{
for ( char * p = dpData; p != pEnd; ++p )
{
if (*p == i_cCarToSearch)
*p = i_cReplacement;
}
}
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.
}
} // namespace csv
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */