59fe111895
2006/09/01 17:20:53 kaib 1.21.18.1: #i68856# Added header markers and pch files
517 lines
17 KiB
C++
517 lines
17 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: valueconverter.cxx,v $
|
|
*
|
|
* $Revision: 1.22 $
|
|
*
|
|
* last change: $Author: obo $ $Date: 2006-09-16 15:35:47 $
|
|
*
|
|
* 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 "valuetypeconverter.hxx"
|
|
|
|
#ifndef CONFIGMGR_TYPECONVERTER_HXX
|
|
#include "typeconverter.hxx"
|
|
#endif
|
|
|
|
inline sal_Bool rtl_ascii_isWhitespace( sal_Unicode ch )
|
|
{
|
|
return ch <= 0x20 && ch;
|
|
}
|
|
|
|
namespace configmgr
|
|
{
|
|
using rtl::OUString;
|
|
using namespace com::sun::star::uno;
|
|
using namespace std;
|
|
// -----------------------------------------------------------------------------
|
|
typedef ValueConverter::StringList StringList;
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
void throwConversionError(sal_Char const* pErrorMsg) CFG_THROW1( script::CannotConvertException )
|
|
{
|
|
OSL_ENSURE(false, pErrorMsg);
|
|
|
|
script::CannotConvertException error;
|
|
error.Message = OUString::createFromAscii(pErrorMsg);
|
|
throw error;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
template <class Char>
|
|
inline
|
|
bool charInRange(Char ch, char from, char to) throw()
|
|
{
|
|
return Char(from) <= ch && ch <= Char(to);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
inline
|
|
unsigned makeHexNibble(unsigned char ch) CFG_THROW1 ( script::CannotConvertException)
|
|
{
|
|
unsigned nRet = 0;
|
|
|
|
if (charInRange(ch, '0', '9')) nRet = ch - unsigned('0');
|
|
|
|
else if (charInRange(ch, 'a', 'f')) nRet = ch - unsigned('a' - 10u);
|
|
|
|
else if (charInRange(ch, 'A', 'F')) nRet = ch - unsigned('A' - 10u);
|
|
|
|
else throwConversionError("Invalid Hex Character in binary value");
|
|
|
|
return nRet;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
inline
|
|
unsigned readHexNibble(sal_Unicode ch) CFG_THROW1 ( script::CannotConvertException)
|
|
{
|
|
if (!charInRange(ch, 0, 127)) throwConversionError("Non-Ascii Character in binary value");
|
|
|
|
return makeHexNibble(static_cast<unsigned char>(ch));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
inline
|
|
unsigned int readHexByte(sal_Unicode const*& pStr) CFG_THROW1 ( script::CannotConvertException)
|
|
{
|
|
register unsigned int nHigh = readHexNibble(*pStr++);
|
|
register unsigned int nLow = readHexNibble(*pStr++);
|
|
return (nHigh << 4) | nLow;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static
|
|
void parseHexBinary(OUString const& aHexString_, uno::Sequence<sal_Int8>& rBinarySeq_)
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
// PRE: aBinaryString with HexCode
|
|
// POST: rBinarySeq with the to Hex converted String
|
|
|
|
sal_uInt32 nCount = aHexString_.getLength();
|
|
sal_Unicode const * pHex = aHexString_.getStr();
|
|
|
|
if (nCount % 2) throwConversionError("Hex string has odd number of characters");
|
|
nCount /= 2;
|
|
|
|
rBinarySeq_.realloc(nCount);
|
|
sal_Int8 * pBinary = rBinarySeq_.getArray();
|
|
|
|
while (nCount--)
|
|
{
|
|
*pBinary++ = static_cast<sal_Int8>(readHexByte(pHex));
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------------
|
|
uno::Sequence<sal_Int8> ValueConverter::parseBinary(OUString const& aBinaryString_) const
|
|
CFG_UNO_THROW1 ( script::CannotConvertException)
|
|
{
|
|
uno::Sequence<sal_Int8> aResultSeq;
|
|
|
|
parseHexBinary(aBinaryString_,aResultSeq);
|
|
|
|
return aResultSeq;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
static inline
|
|
uno::Type getBinaryType()
|
|
{
|
|
uno::Sequence<sal_Int8> const * const for_binary = 0;
|
|
return ::getCppuType(for_binary);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
bool ValueConverter::isList() const
|
|
{
|
|
return m_aType.getTypeClass() == uno::TypeClass_SEQUENCE &&
|
|
m_aType != getBinaryType();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
uno::Any ValueConverter::convertToAny(OUString const& aContent) const
|
|
CFG_UNO_THROW1( script::CannotConvertException)
|
|
{
|
|
uno::Any aValue;
|
|
|
|
if (this->isNull())
|
|
{
|
|
OSL_ENSURE(aContent.trim().getLength() == 0, "ValueConverter: Non-empty Null Value - ignoring content");
|
|
OSL_ASSERT(!aValue.hasValue());
|
|
}
|
|
|
|
else if (this->isList())
|
|
{
|
|
StringList aContentList;
|
|
splitListData(aContent, aContentList);
|
|
convertListToAny(aContentList, aValue);
|
|
}
|
|
|
|
else
|
|
{
|
|
convertScalarToAny(aContent, aValue);
|
|
}
|
|
|
|
return aValue;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
bool ValueConverter::convertScalarToAny(OUString const& aContent, uno::Any& rValue) const
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
OSL_PRECOND(!this->isNull(),"ValueConverter::convertScalarToAny - check for NULL before calling");
|
|
OSL_ENSURE(m_aType.getTypeClass() != uno::TypeClass_ANY,"'Any' values must be NULL");
|
|
|
|
// check for Binary
|
|
if (m_aType == getBinaryType())
|
|
{
|
|
Sequence<sal_Int8> aBinarySeq = parseBinary(aContent);
|
|
rValue <<= aBinarySeq;
|
|
}
|
|
|
|
else
|
|
{
|
|
rValue = toAny(m_xTypeConverter, aContent, m_aType.getTypeClass());
|
|
}
|
|
|
|
return !! rValue.hasValue();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
template <class T>
|
|
bool convertListToSequence(StringList const& aStringList, uno::Sequence< T >& rSequence, uno::TypeClass aElementTypeClass, ValueConverter const& rConverter)
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
OSL_ASSERT(aElementTypeClass == ::getCppuType(static_cast<T const*>(0)).getTypeClass());
|
|
|
|
rSequence.realloc(aStringList.size());
|
|
|
|
sal_uInt32 nPos = 0;
|
|
|
|
for(StringList::const_iterator it = aStringList.begin();
|
|
it != aStringList.end();
|
|
++it)
|
|
{
|
|
uno::Any aValueAny = toAny(rConverter.getTypeConverter(), *it, aElementTypeClass);
|
|
|
|
if (aValueAny >>= rSequence[nPos])
|
|
++nPos;
|
|
|
|
else if (!aValueAny.hasValue())
|
|
OSL_ENSURE(false,"UNEXPECTED: Found NULL value in List - ignoring value !");
|
|
|
|
else
|
|
OSL_ENSURE(false,"ERROR: Cannot extract converted value into List - skipping value !");
|
|
}
|
|
|
|
bool bOK = (nPos == aStringList.size());
|
|
|
|
if (!bOK)
|
|
{
|
|
OSL_ASSERT(nPos < aStringList.size());
|
|
rSequence.realloc(nPos);
|
|
}
|
|
return bOK;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// special conversion for string sequence
|
|
|
|
static
|
|
inline
|
|
void stringListToSequence(uno::Sequence< OUString > & rSequence, StringList const & aStringList)
|
|
{
|
|
rSequence .realloc( aStringList.size() );
|
|
|
|
std::copy( aStringList.begin(), aStringList.end(), rSequence.getArray() );
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static
|
|
inline
|
|
StringList sequenceToStringList(uno::Sequence< OUString > const & aSequence)
|
|
{
|
|
OUString const * const pBegin = aSequence.getConstArray();
|
|
OUString const * const pEnd = pBegin + aSequence.getLength();
|
|
|
|
return StringList(pBegin,pEnd);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
uno::Sequence< OUString > ValueConverter::splitStringList(OUString const& aContent) const
|
|
{
|
|
StringList aList;
|
|
splitListData(aContent, aList);
|
|
|
|
uno::Sequence< OUString > aResult;
|
|
stringListToSequence(aResult,aList);
|
|
|
|
return aResult;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
uno::Any ValueConverter::convertListToAny(uno::Sequence< OUString > const& aContentList) const
|
|
CFG_UNO_THROW1( script::CannotConvertException )
|
|
{
|
|
uno::Any aResult;
|
|
StringList const aStringList = sequenceToStringList(aContentList);
|
|
convertListToAny(aStringList,aResult);
|
|
return aResult;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
// special overload for binary sequence
|
|
|
|
// template<> // use an explicit specialization
|
|
bool convertListToSequence(StringList const& aStringList, uno::Sequence< uno::Sequence<sal_Int8> >& rSequence, uno::TypeClass aElementTypeClass, ValueConverter const& rParser )
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
{ (void)aElementTypeClass; }
|
|
OSL_ASSERT(aElementTypeClass == uno::TypeClass_SEQUENCE);
|
|
|
|
rSequence.realloc(aStringList.size());
|
|
|
|
sal_uInt32 nPos = 0;
|
|
|
|
for(StringList::const_iterator it = aStringList.begin();
|
|
it != aStringList.end();
|
|
++it)
|
|
{
|
|
rSequence[nPos++] = rParser.parseBinary(*it);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// special overload for string sequence
|
|
|
|
// template<> // use an explicit specialization
|
|
bool convertListToSequence(StringList const& aStringList, uno::Sequence< OUString >& rSequence, uno::TypeClass aElementTypeClass, ValueConverter const& /*rParser*/ )
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
{ (void)aElementTypeClass; }
|
|
OSL_ASSERT(aElementTypeClass == uno::TypeClass_STRING);
|
|
|
|
stringListToSequence(rSequence, aStringList);
|
|
|
|
return true;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
#define MAYBE_EXTRACT_SEQUENCE( type ) \
|
|
if (aElementType == ::getCppuType( (type const *)0)) \
|
|
{ \
|
|
Sequence< type > aSequence; \
|
|
convertListToSequence(aContentList,aSequence,aElementTypeClass, *this); \
|
|
rValue <<= aSequence; \
|
|
}
|
|
|
|
bool ValueConverter::convertListToAny(StringList const& aContentList, uno::Any& rValue) const
|
|
CFG_UNO_THROW1 ( script::CannotConvertException )
|
|
{
|
|
OSL_PRECOND(!this->isNull(),"ValueConverter::convertListToAny - check for NULL before calling");
|
|
OSL_ENSURE(m_aType.getTypeClass() == uno::TypeClass_SEQUENCE,"'Any' not allowed for lists");
|
|
|
|
uno::Type aElementType = getSequenceElementType(m_aType);
|
|
uno::TypeClass aElementTypeClass = aElementType.getTypeClass();
|
|
|
|
OSL_ENSURE(aElementTypeClass != uno::TypeClass_ANY,"'Any' not allowed for list elements");
|
|
|
|
MAYBE_EXTRACT_SEQUENCE( OUString )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( sal_Bool )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( sal_Int16 )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( sal_Int32 )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( sal_Int64 )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( double )
|
|
else
|
|
MAYBE_EXTRACT_SEQUENCE( Sequence<sal_Int8> )
|
|
else
|
|
{
|
|
OSL_ENSURE(false, "Unknown element type in list");
|
|
throwConversionError("Invalid value-type found in list value");
|
|
}
|
|
|
|
return !! rValue.hasValue();
|
|
}
|
|
#undef MAYBE_EXTRACT_SEQUENCE
|
|
|
|
// -----------------------------------------------------------------------------
|
|
namespace
|
|
{
|
|
sal_Int32 const NO_MORE_TOKENS = -1;
|
|
struct OTokenizeByWhitespace
|
|
{
|
|
|
|
static inline bool isWhitespace(sal_Unicode ch)
|
|
{
|
|
// note: for definition of whitescape see also
|
|
// canUseWhitespace(OUString const&)
|
|
// in xmlformater.cxx
|
|
// -----------------------------------------------------------------------------
|
|
return rtl_ascii_isWhitespace(ch) ? true : false;
|
|
}
|
|
|
|
sal_Int32 findFirstTokenStart(OUString const& sText) const CFG_NOTHROW()
|
|
{
|
|
return findNextTokenStart(sText,0);
|
|
}
|
|
|
|
sal_Int32 findNextTokenStart(OUString const& sText, sal_Int32 nPrevTokenEnd) const CFG_NOTHROW()
|
|
{
|
|
sal_Int32 const nEnd = sText.getLength();
|
|
sal_Int32 nPos = nPrevTokenEnd;
|
|
|
|
OSL_PRECOND( nPos == 0 || (0 < nPos && nPos < nEnd && isWhitespace(sText[nPos])) || nPos == nEnd,
|
|
"Invalid nPrevTokenEnd");
|
|
|
|
while (nPos < nEnd && isWhitespace(sText[nPos]))
|
|
{
|
|
++nPos;
|
|
}
|
|
|
|
if (nPos < nEnd)
|
|
return nPos;
|
|
else
|
|
return NO_MORE_TOKENS;
|
|
}
|
|
|
|
sal_Int32 findTokenEnd(OUString const& sText, sal_Int32 nTokenStart) const CFG_NOTHROW()
|
|
{
|
|
sal_Int32 const nEnd = sText.getLength();
|
|
sal_Int32 nPos = nTokenStart;
|
|
|
|
OSL_PRECOND( 0 <= nPos && nPos < nEnd && !isWhitespace(sText[nPos]),
|
|
"Invalid nTokenStart");
|
|
|
|
while (nPos < nEnd && !isWhitespace(sText[nPos]))
|
|
{
|
|
++nPos;
|
|
}
|
|
|
|
return nPos;
|
|
}
|
|
};
|
|
// -----------------------------------------------------------------------------
|
|
struct OTokenizeBySeparator
|
|
{
|
|
OUString const sSeparator;
|
|
OTokenizeBySeparator(OUString const& _sSeparator) CFG_NOTHROW()
|
|
: sSeparator(_sSeparator)
|
|
{
|
|
OSL_PRECOND(sSeparator.trim().getLength() > 0, "Invalid empty separator string");
|
|
}
|
|
|
|
sal_Int32 findFirstTokenStart(OUString const& /*sText*/) const CFG_NOTHROW()
|
|
{
|
|
return 0;
|
|
}
|
|
sal_Int32 findNextTokenStart(OUString const& sText, sal_Int32 nPrevTokenEnd) const CFG_NOTHROW()
|
|
{
|
|
sal_Int32 const nEnd = sText.getLength();
|
|
sal_Int32 nPos = nPrevTokenEnd;
|
|
OSL_PRECOND( nPos == nEnd || (0 <= nPos && nPos < nEnd && sText.indexOf(sSeparator, nPos) == nPos),
|
|
"Invalid nPrevTokenEnd");
|
|
|
|
if (nPos < nEnd)
|
|
return nPos + sSeparator.getLength();
|
|
else
|
|
return NO_MORE_TOKENS;
|
|
}
|
|
sal_Int32 findTokenEnd(OUString const& sText, sal_Int32 nTokenStart) const CFG_NOTHROW()
|
|
{
|
|
sal_Int32 const nEnd = sText.getLength();
|
|
OSL_PRECOND( 0 <= nTokenStart && nTokenStart <= nEnd ,
|
|
"Invalid nTokenStart");
|
|
|
|
sal_Int32 nPos = sText.indexOf(sSeparator,nTokenStart);
|
|
|
|
if (nPos >= 0)
|
|
return nPos;
|
|
else
|
|
return nEnd;
|
|
}
|
|
};
|
|
// -----------------------------------------------------------------------------
|
|
template <class Tokenizer>
|
|
void tokenizeListData(Tokenizer const& aTokenizer, OUString const& aContent, StringList& rContentList)
|
|
CFG_NOTHROW( )
|
|
{
|
|
sal_Int32 nTokenPos = aTokenizer.findFirstTokenStart(aContent);
|
|
|
|
while(nTokenPos != NO_MORE_TOKENS)
|
|
{
|
|
sal_Int32 nTokenEnd = aTokenizer.findTokenEnd(aContent, nTokenPos);
|
|
|
|
// this is what the tokenizer must provide
|
|
OSL_ASSERT(0 <= nTokenPos && nTokenPos <= nTokenEnd && nTokenEnd <= aContent.getLength());
|
|
|
|
rContentList.push_back( aContent.copy(nTokenPos, nTokenEnd-nTokenPos) );
|
|
|
|
nTokenPos= aTokenizer.findNextTokenStart(aContent, nTokenEnd);
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
void ValueConverter::splitListData(OUString const& aContent, StringList& rContentList) const
|
|
CFG_NOTHROW( )
|
|
{
|
|
OUString sSeparator = m_sSeparator;
|
|
|
|
bool bSeparateByWhitespace = (sSeparator.trim().getLength() == 0);
|
|
|
|
if (bSeparateByWhitespace)
|
|
{
|
|
OSL_ENSURE( sSeparator.getLength()==0 || sSeparator.equalsAscii(" "),
|
|
"Unexpected whitespace-only separator");
|
|
|
|
tokenizeListData( OTokenizeByWhitespace(), aContent, rContentList );
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( sSeparator.trim()==sSeparator,
|
|
"Unexpected whitespace in separator");
|
|
|
|
tokenizeListData( OTokenizeBySeparator(sSeparator), aContent, rContentList );
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
} // namespace
|