1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: valueformatter.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "valueformatter.hxx"
35 #include "elementformatter.hxx"
36 #include "xmlstrings.hxx"
37 #include "typeconverter.hxx"
38 #include "simpletypehelper.hxx"
39 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/uno/Sequence.hxx>
42 #ifndef INCLUDED_ALGORITHM
44 #define INCLUDED_ALGORITHM
49 namespace uno
= com::sun::star::uno
;
54 //==========================================================================
56 //==========================================================================
58 // -----------------------------------------------------------------------------
61 // -----------------------------------------------------------------------------
65 bool isWhitespaceCharacter( sal_Unicode ch
)
67 return ch
<= 0x20 && ch
;
69 // -----------------------------------------------------------------------------
73 bool isWhitespaceString(rtl::OUString
const & aStr
)
75 sal_Unicode
const * const pBegin
= aStr
.getStr();
76 sal_Unicode
const * const pEnd
= pBegin
+ aStr
.getLength();
78 // BACK: true, if any whitespace in string or string is empty
82 sal_Unicode
const * const pSpace
= std::find_if(pBegin
,pEnd
,isWhitespaceCharacter
);
84 return pSpace
!= pEnd
;
86 // -----------------------------------------------------------------------------
89 bool hasWhitespaceString( uno::Sequence
< rtl::OUString
> const & aSeq
)
91 // BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
92 rtl::OUString
const * const pBegin
= aSeq
.getConstArray();
93 rtl::OUString
const * const pEnd
= pBegin
+ aSeq
.getLength();
95 rtl::OUString
const * const pSpace
= std::find_if(pBegin
,pEnd
,isWhitespaceString
);
97 return pSpace
!= pEnd
;
99 // -----------------------------------------------------------------------------
103 HasSubString(rtl::OUString
const & _aSubStr
)
104 : m_aSubStr(_aSubStr
)
107 bool operator()(rtl::OUString
const & _aStr
)
108 { return _aStr
.indexOf(m_aSubStr
) >= 0; }
110 rtl::OUString
const m_aSubStr
;
112 // -----------------------------------------------------------------------------
115 bool hasStringWithSubstring(const uno::Sequence
< rtl::OUString
> &aSeq
, rtl::OUString
const & _aSubStr
)
117 rtl::OUString
const * const pBegin
= aSeq
.getConstArray();
118 rtl::OUString
const * const pEnd
= pBegin
+ aSeq
.getLength();
120 rtl::OUString
const * const pSpace
= std::find_if(pBegin
,pEnd
,HasSubString(_aSubStr
));
122 return pSpace
!= pEnd
;
124 // -----------------------------------------------------------------------------
127 template <class Element_
>
128 struct IsEmptySequence
130 bool operator()(uno::Sequence
<Element_
> const & aSeq
) const
132 return aSeq
.getLength() == 0;
135 // -----------------------------------------------------------------------------
137 template <class Element_
>
138 bool hasEmptySequence(uno::Sequence
< uno::Sequence
<Element_
> > const & aSeqSeq
)
140 // BACK: true, if whitespace Separator is ok, (no whitespace in Strings, no empty strings)
141 uno::Sequence
<Element_
> const * const pBegin
= aSeqSeq
.getConstArray();
142 uno::Sequence
<Element_
> const * const pEnd
= pBegin
+ aSeqSeq
.getLength();
144 uno::Sequence
<Element_
> const * const pEmpty
= std::find_if(pBegin
, pEnd
, IsEmptySequence
<Element_
>() );
146 return pEmpty
!= pEnd
;
148 // -----------------------------------------------------------------------------
151 bool canUseSeparator(uno::Sequence
< rtl::OUString
> const & aSeq
, rtl::OUString
const & aSeparator
)
153 return ! hasStringWithSubstring(aSeq
,aSeparator
);
155 // -----------------------------------------------------------------------------
158 bool canUseWhitespaceSeparator(uno::Sequence
< rtl::OUString
> const & aSeq
)
160 return ! hasWhitespaceString(aSeq
);
162 // -----------------------------------------------------------------------------
164 template <class Element_
>
166 bool canUseWhitespaceSeparator(const uno::Sequence
< uno::Sequence
<Element_
> > &aSeq
)
168 return ! hasEmptySequence(aSeq
);
170 // -----------------------------------------------------------------------------
174 rtl::OUString m_sValue
;
176 // -----------------------------------------------------------------------------
177 Separator() : m_sValue() {}
178 // -----------------------------------------------------------------------------
179 bool isDefault() const { return m_sValue
.getLength() == 0; }
180 // -----------------------------------------------------------------------------
181 rtl::OUString
value() const { return isDefault() ? static_cast<rtl::OUString
>(SEPARATOR_WHITESPACE
) : m_sValue
; }
182 // -----------------------------------------------------------------------------
184 bool check(const uno::Sequence
<rtl::OUString
> &aSeq
) const
186 return isDefault() ? canUseWhitespaceSeparator(aSeq
) : canUseSeparator(aSeq
, m_sValue
);
189 // -----------------------------------------------------------------------------
190 bool trySeparator(rtl::OUString
const& sSep
, const uno::Sequence
<rtl::OUString
> & aSeq
)
192 OSL_ENSURE( ! isWhitespaceString(sSep
), "There should be no spaces in non-default separators");
193 // BACK: true, if Separator is ok, not in Strings
194 if (!canUseSeparator(aSeq
, sSep
))
196 this->setSeparator(sSep
);
199 // -----------------------------------------------------------------------------
200 void setSeparator(rtl::OUString
const& sSep
)
204 // -----------------------------------------------------------------------------
206 // -----------------------------------------------------------------------------
207 #define ASCII( STRING_LIT_ ) ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( STRING_LIT_ ) ) )
208 // -----------------------------------------------------------------------------
210 Separator
createSeparator(const uno::Any
& aAny
)
214 // create a Separator which isn't in any value
215 if (aAny
.getValueTypeClass() == uno::TypeClass_SEQUENCE
)
217 uno::Type aElementType
= configmgr::getSequenceElementType(aAny
.getValueType());
218 if (aElementType
.getTypeClass() == uno::TypeClass_STRING
)
220 // only in strings we need to search a separator
221 uno::Sequence
<rtl::OUString
> aSeq
;
223 OSL_VERIFY (aAny
>>= aSeq
);
225 bool bValidSeparator
=
226 canUseWhitespaceSeparator(aSeq
) ||
227 aResult
.trySeparator(ASCII(","), aSeq
) ||
228 aResult
.trySeparator(ASCII(";"), aSeq
) ||
229 aResult
.trySeparator(ASCII(":"), aSeq
) ||
230 aResult
.trySeparator(ASCII("|"), aSeq
) ||
231 aResult
.trySeparator(ASCII("#"), aSeq
) ||
232 aResult
.trySeparator(ASCII("-#*=+#-"), aSeq
);
234 if (!bValidSeparator
)
236 OSL_TRACE("ERROR: configuration formatter: Could not create Separator for string list");
237 OSL_ENSURE(false, "ERROR: Could not create Separator for string list");
241 // maybe the whitespace test was invalid ?
242 OSL_ENSURE(aResult
.check(aSeq
), "Found Separator does not pass check ?!");
245 else if (aElementType
== SimpleTypeHelper::getBinaryType())
247 // only in strings we need to search a separator
248 uno::Sequence
< uno::Sequence
<sal_Int8
> > aSeq
;
249 OSL_VERIFY(aAny
>>= aSeq
);
251 if (!canUseWhitespaceSeparator(aSeq
))
253 aResult
.setSeparator( ASCII(":") );
262 // -----------------------------------------------------------------------------
265 sal_Unicode
hexNibble(sal_uInt8 _nNibble
)
267 OSL_ASSERT(_nNibble
<= 0x0F);
269 const sal_uInt8 cDecOffset
= sal_uInt8('0');
270 const sal_uInt8 cHexOffset
= sal_uInt8('a') - 10;
272 return _nNibble
+ (_nNibble
<10 ? cDecOffset
: cHexOffset
);
275 // -----------------------------------------------------------------------------
278 void appendHex(rtl::OUStringBuffer
& rBuff
, sal_uInt8 _nByte
)
280 rBuff
.append( hexNibble(_nByte
>> 4) );
281 rBuff
.append( hexNibble(_nByte
& 0x0f) );
284 // -----------------------------------------------------------------------------
286 rtl::OUString
binaryToHex(const uno::Sequence
<sal_Int8
>& _aBinarySeq
)
288 sal_Int32
const nLength
= _aBinarySeq
.getLength();
290 rtl::OUStringBuffer
sHex(2*nLength
);
292 for (sal_Int32 nPos
= 0;nPos
< nLength
; ++nPos
)
294 appendHex( sHex
, _aBinarySeq
[nPos
] );
297 OSL_ASSERT(sHex
.getLength() == 2*nLength
);
298 return sHex
.makeStringAndClear();;
300 // -----------------------------------------------------------------------------
301 rtl::OUString
formatSimpleValue(uno::Any
const & _aValue
, uno::Reference
< script::XTypeConverter
> const & _xTCV
)
303 rtl::OUString sResult
;
305 if (_aValue
.hasValue())
307 if (_aValue
.getValueType() == SimpleTypeHelper::getBinaryType())
309 uno::Sequence
<sal_Int8
> aBinarySeq
;
311 OSL_VERIFY(_aValue
>>= aBinarySeq
);
313 sResult
= binaryToHex(aBinarySeq
);
317 // cannot have nested any
318 OSL_ASSERT(_aValue
.getValueTypeClass() != uno::TypeClass_ANY
);
320 sResult
= toString(_xTCV
, _aValue
);
326 // -----------------------------------------------------------------------------
327 template <class Element_
>
328 rtl::OUString
formatSequence(uno::Sequence
< Element_
> const& aSequence
, rtl::OUString
const& sSeparator
, uno::Reference
< script::XTypeConverter
> const & _xTCV
)
330 rtl::OUStringBuffer aResult
;
332 if (sal_Int32
const nLength
= aSequence
.getLength())
334 Element_
const * pSeq
= aSequence
.getConstArray();
336 aResult
= formatSimpleValue( uno::makeAny(pSeq
[0]),_xTCV
);
338 for(sal_Int32 i
=1; i
<nLength
; ++i
)
340 aResult
.append( sSeparator
);
341 aResult
.append( formatSimpleValue(uno::makeAny(pSeq
[i
]),_xTCV
) );
345 return aResult
.makeStringAndClear();
347 // -----------------------------------------------------------------------------
348 // template <> // optimized overload for String
349 rtl::OUString
formatSequence(uno::Sequence
< rtl::OUString
> const& aSequence
, rtl::OUString
const& sSeparator
, uno::Reference
< script::XTypeConverter
> const & )
351 rtl::OUStringBuffer aResult
;
353 if (sal_Int32
const nLength
= aSequence
.getLength())
355 rtl::OUString
const * pSeq
= aSequence
.getConstArray();
359 for(sal_Int32 i
=1; i
<nLength
; ++i
)
361 aResult
.append( sSeparator
).append( pSeq
[i
] );
365 return aResult
.makeStringAndClear();
368 // -----------------------------------------------------------------------------
370 #define CASE_WRITE_SEQUENCE(TYPE_CLASS, DATA_TYPE) \
373 uno::Sequence< DATA_TYPE > aData; \
374 OSL_ENSURE( ::getCppuType(static_cast< DATA_TYPE const*>(0)).getTypeClass() == (TYPE_CLASS), \
375 "Usage Error for CASE_WRITE_SEQUENCE: Type extracted does not match type class"); \
376 OSL_VERIFY( _aValue >>= aData ); \
377 aResult = formatSequence(aData,sSeparator,xTCV); \
380 rtl::OUString formatSequenceValue(uno::Any const& _aValue, rtl::OUString const& sSeparator, uno::Reference< script::XTypeConverter > const & xTCV)
382 rtl::OUString aResult
;
384 uno::Type aElementType
= getSequenceElementType( _aValue
.getValueType() );
386 switch(aElementType
.getTypeClass())
388 CASE_WRITE_SEQUENCE( uno::TypeClass_BOOLEAN
, sal_Bool
);
390 CASE_WRITE_SEQUENCE( uno::TypeClass_SHORT
, sal_Int16
);
392 CASE_WRITE_SEQUENCE( uno::TypeClass_LONG
, sal_Int32
);
394 CASE_WRITE_SEQUENCE( uno::TypeClass_HYPER
, sal_Int64
);
396 CASE_WRITE_SEQUENCE( uno::TypeClass_DOUBLE
, double );
398 CASE_WRITE_SEQUENCE( uno::TypeClass_STRING
, rtl::OUString
);
400 CASE_WRITE_SEQUENCE( uno::TypeClass_SEQUENCE
, uno::Sequence
<sal_Int8
> );
403 OSL_ENSURE(false, "Unexpected typeclass for sequence elements");
410 #undef CASE_WRITE_SEQUENCE
411 // -----------------------------------------------------------------------------
412 } // anonymous namspace
413 // -----------------------------------------------------------------------------
414 // -----------------------------------------------------------------------------
416 static inline bool isListVal(uno::Any
const & _aValue
)
419 if (_aValue
.hasValue())
421 getBasicType(_aValue
.getValueType(),bList
);
425 // -----------------------------------------------------------------------------
426 void ValueFormatter::makeSeparator()
428 if (isListVal(m_aValue
))
430 Separator aSeparator
= createSeparator(m_aValue
);
432 m_sSeparator
= aSeparator
.value();
433 m_bUseSeparator
= !aSeparator
.isDefault();
435 OSL_POSTCOND( this->isList() , "ValueFormatter: Could not mark as list");
439 m_sSeparator
= rtl::OUString();
440 m_bUseSeparator
= false;
442 OSL_POSTCOND( !this->isList(), "ValueFormatter: Could not mark as non-list");
445 // -----------------------------------------------------------------------------
447 rtl::OUString
ValueFormatter::getContent(uno::Reference
< script::XTypeConverter
> const & _xTCV
) const
449 rtl::OUString aResult
;
454 aResult
= formatSequenceValue(m_aValue
, m_sSeparator
, _xTCV
);
458 aResult
= formatSimpleValue(m_aValue
, _xTCV
);
461 catch (script::CannotConvertException
& cce
)
463 rtl::OUString
const sMessage(RTL_CONSTASCII_USTRINGPARAM("Configuration: Could not convert value to XML representation: "));
464 throw uno::RuntimeException(sMessage
+ cce
.Message
, cce
.Context
);
469 // -----------------------------------------------------------------------------
471 bool ValueFormatter::addValueAttributes(ElementFormatter
& _rFormatter
) const
473 // do we have a NULL value
474 if (!m_aValue
.hasValue())
476 _rFormatter
.addIsNull();
480 // create a sequence separator
483 OSL_ASSERT(this->isList());
484 _rFormatter
.addSeparator(m_sSeparator
);
489 // -----------------------------------------------------------------------------
491 // -----------------------------------------------------------------------------
492 // -----------------------------------------------------------------------------
495 // -----------------------------------------------------------------------------
496 } // namespace configmgr