512ef3c721
2006/09/01 17:20:53 kaib 1.4.60.1: #i68856# Added header markers and pch files
521 lines
16 KiB
C++
521 lines
16 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: valueformatter.cxx,v $
|
|
*
|
|
* $Revision: 1.5 $
|
|
*
|
|
* last change: $Author: obo $ $Date: 2006-09-16 15:36:04 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_configmgr.hxx"
|
|
|
|
#include "valueformatter.hxx"
|
|
|
|
#ifndef CONFIGMGR_XML_ELEMENTFORMATTER_HXX
|
|
#include "elementformatter.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_XML_STRINGS_HXX_
|
|
#include "xmlstrings.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_TYPECONVERTER_HXX
|
|
#include "typeconverter.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_SIMPLETYPEHELPER_HXX
|
|
#include "simpletypehelper.hxx"
|
|
#endif
|
|
|
|
#ifndef _RTL_USTRBUF_HXX_
|
|
#include <rtl/ustrbuf.hxx>
|
|
#endif
|
|
|
|
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
#endif
|
|
|
|
#ifndef INCLUDED_ALGORITHM
|
|
#include <algorithm>
|
|
#define INCLUDED_ALGORITHM
|
|
#endif
|
|
|
|
namespace configmgr
|
|
{
|
|
namespace uno = com::sun::star::uno;
|
|
using ::rtl::OUString;
|
|
|
|
namespace xml
|
|
{
|
|
|
|
//==========================================================================
|
|
//= Helper
|
|
//==========================================================================
|
|
|
|
// -----------------------------------------------------------------------------
|
|
namespace
|
|
{
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static
|
|
inline
|
|
bool isWhitespaceCharacter( sal_Unicode ch )
|
|
{
|
|
return ch <= 0x20 && ch;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static
|
|
inline
|
|
bool isWhitespaceString(OUString const & aStr)
|
|
{
|
|
sal_Unicode const * const pBegin = aStr.getStr();
|
|
sal_Unicode const * const pEnd = pBegin + aStr.getLength();
|
|
|
|
// BACK: true, if any whitespace in string or string is empty
|
|
if (pBegin == pEnd)
|
|
return true;
|
|
|
|
sal_Unicode const * const pSpace = std::find_if(pBegin,pEnd,isWhitespaceCharacter);
|
|
|
|
return pSpace != pEnd;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static
|
|
bool hasWhitespaceString( uno::Sequence< OUString > const & aSeq)
|
|
{
|
|
// BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
|
|
OUString const * const pBegin = aSeq.getConstArray();
|
|
OUString const * const pEnd = pBegin + aSeq.getLength();
|
|
|
|
OUString const * const pSpace = std::find_if(pBegin,pEnd,isWhitespaceString);
|
|
|
|
return pSpace != pEnd;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
struct HasSubString
|
|
{
|
|
HasSubString(OUString const & _aSubStr)
|
|
: m_aSubStr(_aSubStr)
|
|
{}
|
|
|
|
bool operator()(OUString const & _aStr)
|
|
{ return _aStr.indexOf(m_aSubStr) >= 0; }
|
|
|
|
OUString const m_aSubStr;
|
|
};
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static
|
|
bool hasStringWithSubstring(const uno::Sequence< OUString > &aSeq, OUString const & _aSubStr)
|
|
{
|
|
OUString const * const pBegin = aSeq.getConstArray();
|
|
OUString const * const pEnd = pBegin + aSeq.getLength();
|
|
|
|
OUString const * const pSpace = std::find_if(pBegin,pEnd,HasSubString(_aSubStr));
|
|
|
|
return pSpace != pEnd;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
template <class Element_>
|
|
struct IsEmptySequence
|
|
{
|
|
bool operator()(uno::Sequence<Element_> const & aSeq) const
|
|
{
|
|
return aSeq.getLength() == 0;
|
|
}
|
|
};
|
|
// -----------------------------------------------------------------------------
|
|
|
|
template <class Element_>
|
|
bool hasEmptySequence(uno::Sequence< uno::Sequence<Element_> > const & aSeqSeq)
|
|
{
|
|
// BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
|
|
uno::Sequence<Element_> const * const pBegin = aSeqSeq.getConstArray();
|
|
uno::Sequence<Element_> const * const pEnd = pBegin + aSeqSeq.getLength();
|
|
|
|
uno::Sequence<Element_> const * const pEmpty = std::find_if(pBegin, pEnd, IsEmptySequence<Element_>() );
|
|
|
|
return pEmpty != pEnd;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
inline
|
|
bool canUseSeparator(uno::Sequence< OUString > const & aSeq, OUString const & aSeparator)
|
|
{
|
|
return ! hasStringWithSubstring(aSeq,aSeparator);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
inline
|
|
bool canUseWhitespaceSeparator(uno::Sequence< OUString > const & aSeq)
|
|
{
|
|
return ! hasWhitespaceString(aSeq);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
template <class Element_>
|
|
inline
|
|
bool canUseWhitespaceSeparator(const uno::Sequence< uno::Sequence<Element_> > &aSeq)
|
|
{
|
|
return ! hasEmptySequence(aSeq);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class Separator
|
|
{
|
|
OUString m_sValue;
|
|
public:
|
|
// -----------------------------------------------------------------------------
|
|
Separator() : m_sValue() {}
|
|
// -----------------------------------------------------------------------------
|
|
bool isDefault() const { return m_sValue.getLength() == 0; }
|
|
// -----------------------------------------------------------------------------
|
|
OUString value() const { return isDefault() ? static_cast<OUString>(SEPARATOR_WHITESPACE) : m_sValue; }
|
|
// -----------------------------------------------------------------------------
|
|
|
|
bool check(const uno::Sequence<rtl::OUString> &aSeq) const
|
|
{
|
|
return isDefault() ? canUseWhitespaceSeparator(aSeq) : canUseSeparator(aSeq, m_sValue);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
bool trySeparator(rtl::OUString const& sSep, const uno::Sequence<rtl::OUString> & aSeq)
|
|
{
|
|
OSL_ENSURE( ! isWhitespaceString(sSep), "There should be no spaces in non-default separators");
|
|
// BACK: true, if Separator is ok, not in Strings
|
|
if (!canUseSeparator(aSeq, sSep))
|
|
return false;
|
|
this->setSeparator(sSep);
|
|
return true;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
void setSeparator(rtl::OUString const& sSep)
|
|
{
|
|
m_sValue = sSep;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
};
|
|
// -----------------------------------------------------------------------------
|
|
#define ASCII( STRING_LIT_ ) ( OUString( RTL_CONSTASCII_USTRINGPARAM( STRING_LIT_ ) ) )
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
Separator createSeparator(const uno::Any& aAny)
|
|
{
|
|
Separator aResult;
|
|
|
|
// create a Separator which isn't in any value
|
|
if (aAny.getValueTypeClass() == uno::TypeClass_SEQUENCE)
|
|
{
|
|
uno::Type aElementType = configmgr::getSequenceElementType(aAny.getValueType());
|
|
if (aElementType.getTypeClass() == uno::TypeClass_STRING)
|
|
{
|
|
// only in strings we need to search a separator
|
|
uno::Sequence<OUString> aSeq;
|
|
|
|
OSL_VERIFY (aAny >>= aSeq);
|
|
|
|
bool bValidSeparator =
|
|
canUseWhitespaceSeparator(aSeq) ||
|
|
aResult.trySeparator(ASCII(","), aSeq) ||
|
|
aResult.trySeparator(ASCII(";"), aSeq) ||
|
|
aResult.trySeparator(ASCII(":"), aSeq) ||
|
|
aResult.trySeparator(ASCII("|"), aSeq) ||
|
|
aResult.trySeparator(ASCII("#"), aSeq) ||
|
|
aResult.trySeparator(ASCII("-#*=+#-"), aSeq);
|
|
|
|
if (!bValidSeparator)
|
|
{
|
|
OSL_TRACE("ERROR: configuration formatter: Could not create Separator for string list");
|
|
OSL_ENSURE(false, "ERROR: Could not create Separator for string list");
|
|
}
|
|
else
|
|
{
|
|
// maybe the whitespace test was invalid ?
|
|
OSL_ENSURE(aResult.check(aSeq), "Found Separator does not pass check ?!");
|
|
}
|
|
}
|
|
else if (aElementType == SimpleTypeHelper::getBinaryType())
|
|
{
|
|
// only in strings we need to search a separator
|
|
uno::Sequence< uno::Sequence<sal_Int8> > aSeq;
|
|
OSL_VERIFY(aAny >>= aSeq);
|
|
|
|
if (!canUseWhitespaceSeparator(aSeq))
|
|
{
|
|
aResult.setSeparator( ASCII(":") );
|
|
}
|
|
}
|
|
}
|
|
|
|
// DefaultSeparator
|
|
return aResult;
|
|
}
|
|
#undef ASCII
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
inline
|
|
sal_Unicode hexNibble(sal_uInt8 _nNibble)
|
|
{
|
|
OSL_ASSERT(_nNibble <= 0x0F);
|
|
|
|
const sal_uInt8 cDecOffset = sal_uInt8('0');
|
|
const sal_uInt8 cHexOffset = sal_uInt8('a') - 10;
|
|
|
|
return _nNibble + (_nNibble<10 ? cDecOffset : cHexOffset);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
inline
|
|
void appendHex(rtl::OUStringBuffer& rBuff, sal_uInt8 _nByte)
|
|
{
|
|
rBuff.append( hexNibble(_nByte >> 4) );
|
|
rBuff.append( hexNibble(_nByte & 0x0f) );
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
OUString binaryToHex(const uno::Sequence<sal_Int8>& _aBinarySeq)
|
|
{
|
|
sal_Int32 const nLength = _aBinarySeq.getLength();
|
|
|
|
rtl::OUStringBuffer sHex(2*nLength);
|
|
|
|
for (sal_Int32 nPos = 0;nPos < nLength; ++nPos)
|
|
{
|
|
appendHex( sHex, _aBinarySeq[nPos] );
|
|
}
|
|
|
|
OSL_ASSERT(sHex.getLength() == 2*nLength);
|
|
return sHex.makeStringAndClear();;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
typedef ValueFormatter::TypeConverter TypeConverter;
|
|
// -----------------------------------------------------------------------------
|
|
OUString formatSimpleValue(uno::Any const & _aValue, TypeConverter const & _xTCV)
|
|
{
|
|
OUString sResult;
|
|
|
|
if (_aValue.hasValue())
|
|
{
|
|
if (_aValue .getValueType() == SimpleTypeHelper::getBinaryType())
|
|
{
|
|
uno::Sequence<sal_Int8> aBinarySeq;
|
|
|
|
OSL_VERIFY(_aValue >>= aBinarySeq);
|
|
|
|
sResult = binaryToHex(aBinarySeq);
|
|
}
|
|
else
|
|
{
|
|
// cannot have nested any
|
|
OSL_ASSERT(_aValue.getValueTypeClass() != uno::TypeClass_ANY);
|
|
|
|
sResult = toString(_xTCV, _aValue);
|
|
}
|
|
}
|
|
return sResult;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
template <class Element_>
|
|
OUString formatSequence(uno::Sequence< Element_ > const& aSequence, OUString const& sSeparator, TypeConverter const & _xTCV)
|
|
{
|
|
rtl::OUStringBuffer aResult;
|
|
|
|
if (sal_Int32 const nLength = aSequence.getLength())
|
|
{
|
|
Element_ const * pSeq = aSequence.getConstArray();
|
|
|
|
aResult = formatSimpleValue( uno::makeAny(pSeq[0]),_xTCV);
|
|
|
|
for(sal_Int32 i=1; i<nLength; ++i)
|
|
{
|
|
aResult.append( sSeparator );
|
|
aResult.append( formatSimpleValue(uno::makeAny(pSeq[i]),_xTCV) );
|
|
}
|
|
}
|
|
|
|
return aResult.makeStringAndClear();
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
// template <> // optimized overload for String
|
|
OUString formatSequence(uno::Sequence< OUString > const& aSequence, OUString const& sSeparator, TypeConverter const & )
|
|
{
|
|
rtl::OUStringBuffer aResult;
|
|
|
|
if (sal_Int32 const nLength = aSequence.getLength())
|
|
{
|
|
OUString const * pSeq = aSequence.getConstArray();
|
|
|
|
aResult = pSeq[0];
|
|
|
|
for(sal_Int32 i=1; i<nLength; ++i)
|
|
{
|
|
aResult.append( sSeparator ).append( pSeq[i] );
|
|
}
|
|
}
|
|
|
|
return aResult.makeStringAndClear();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
#define CASE_WRITE_SEQUENCE(TYPE_CLASS, DATA_TYPE) \
|
|
case TYPE_CLASS: \
|
|
{ \
|
|
uno::Sequence< DATA_TYPE > aData; \
|
|
OSL_ENSURE( ::getCppuType(static_cast< DATA_TYPE const*>(0)).getTypeClass() == (TYPE_CLASS), \
|
|
"Usage Error for CASE_WRITE_SEQUENCE: Type extracted does not match type class"); \
|
|
OSL_VERIFY( _aValue >>= aData ); \
|
|
aResult = formatSequence(aData,sSeparator,xTCV); \
|
|
} break \
|
|
|
|
OUString formatSequenceValue(uno::Any const& _aValue, OUString const& sSeparator, TypeConverter const & xTCV)
|
|
{
|
|
OUString aResult;
|
|
|
|
uno::Type aElementType = getSequenceElementType( _aValue.getValueType() );
|
|
|
|
switch(aElementType.getTypeClass())
|
|
{
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_BOOLEAN, sal_Bool );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_SHORT, sal_Int16 );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_LONG, sal_Int32 );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_HYPER, sal_Int64 );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_DOUBLE, double );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_STRING, OUString );
|
|
|
|
CASE_WRITE_SEQUENCE( uno::TypeClass_SEQUENCE, uno::Sequence<sal_Int8> );
|
|
|
|
default:
|
|
OSL_ENSURE(false, "Unexpected typeclass for sequence elements");
|
|
break;
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
#undef CASE_WRITE_SEQUENCE
|
|
// -----------------------------------------------------------------------------
|
|
} // anonymous namspace
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static inline bool isListVal(uno::Any const & _aValue)
|
|
{
|
|
bool bList = false;
|
|
if (_aValue.hasValue())
|
|
{
|
|
getBasicType(_aValue.getValueType(),bList);
|
|
}
|
|
return bList;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
void ValueFormatter::makeSeparator()
|
|
{
|
|
if (isListVal(m_aValue))
|
|
{
|
|
Separator aSeparator = createSeparator(m_aValue);
|
|
|
|
m_sSeparator = aSeparator.value();
|
|
m_bUseSeparator = !aSeparator.isDefault();
|
|
|
|
OSL_POSTCOND( this->isList() , "ValueFormatter: Could not mark as list");
|
|
}
|
|
else
|
|
{
|
|
m_sSeparator = OUString();
|
|
m_bUseSeparator = false;
|
|
|
|
OSL_POSTCOND( !this->isList(), "ValueFormatter: Could not mark as non-list");
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
OUString ValueFormatter::getContent(TypeConverter const & _xTCV) const
|
|
{
|
|
OUString aResult;
|
|
try
|
|
{
|
|
if (this->isList())
|
|
{
|
|
aResult = formatSequenceValue(m_aValue, m_sSeparator, _xTCV);
|
|
}
|
|
else
|
|
{
|
|
aResult = formatSimpleValue(m_aValue, _xTCV);
|
|
}
|
|
}
|
|
catch (script::CannotConvertException& cce)
|
|
{
|
|
OUString const sMessage(RTL_CONSTASCII_USTRINGPARAM("Configuration: Could not convert value to XML representation: "));
|
|
throw uno::RuntimeException(sMessage + cce.Message, cce.Context);
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
bool ValueFormatter::addValueAttributes(ElementFormatter & _rFormatter) const
|
|
{
|
|
// do we have a NULL value
|
|
if (!m_aValue.hasValue())
|
|
{
|
|
_rFormatter.addIsNull();
|
|
return false;
|
|
}
|
|
|
|
// create a sequence separator
|
|
if (m_bUseSeparator)
|
|
{
|
|
OSL_ASSERT(this->isList());
|
|
_rFormatter.addSeparator(m_sSeparator);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
} // namespace xml
|
|
|
|
// -----------------------------------------------------------------------------
|
|
} // namespace configmgr
|
|
|
|
|