/************************************************************************* * * 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 #endif #ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_ #include #endif #ifndef INCLUDED_ALGORITHM #include #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 struct IsEmptySequence { bool operator()(uno::Sequence const & aSeq) const { return aSeq.getLength() == 0; } }; // ----------------------------------------------------------------------------- template bool hasEmptySequence(uno::Sequence< uno::Sequence > const & aSeqSeq) { // BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings) uno::Sequence const * const pBegin = aSeqSeq.getConstArray(); uno::Sequence const * const pEnd = pBegin + aSeqSeq.getLength(); uno::Sequence const * const pEmpty = std::find_if(pBegin, pEnd, IsEmptySequence() ); 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 inline bool canUseWhitespaceSeparator(const uno::Sequence< uno::Sequence > &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(SEPARATOR_WHITESPACE) : m_sValue; } // ----------------------------------------------------------------------------- bool check(const uno::Sequence &aSeq) const { return isDefault() ? canUseWhitespaceSeparator(aSeq) : canUseSeparator(aSeq, m_sValue); } // ----------------------------------------------------------------------------- bool trySeparator(rtl::OUString const& sSep, const uno::Sequence & 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 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 > 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& _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 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 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 // 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 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 ); 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