office-gobmx/configmgr/source/xml/valueconverter.cxx
Oliver Bolte 59fe111895 INTEGRATION: CWS pchfix02 (1.21.18); FILE MERGED
2006/09/01 17:20:53 kaib 1.21.18.1: #i68856# Added header markers and pch files
2006-09-16 14:35:47 +00:00

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