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: valueconverter.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 "valuetypeconverter.hxx"
35 #include "typeconverter.hxx"
37 inline sal_Bool
rtl_ascii_isWhitespace( sal_Unicode ch
)
39 return ch
<= 0x20 && ch
;
44 // -----------------------------------------------------------------------------
46 void throwConversionError(sal_Char
const* pErrorMsg
) SAL_THROW((script::CannotConvertException
))
48 OSL_ENSURE(false, pErrorMsg
);
50 script::CannotConvertException error
;
51 error
.Message
= rtl::OUString::createFromAscii(pErrorMsg
);
54 // -----------------------------------------------------------------------------
57 bool charInRange(Char ch
, char from
, char to
) throw()
59 return Char(from
) <= ch
&& ch
<= Char(to
);
62 // -----------------------------------------------------------------------------
65 unsigned makeHexNibble(unsigned char ch
) SAL_THROW((script::CannotConvertException
))
69 if (charInRange(ch
, '0', '9')) nRet
= ch
- unsigned('0');
71 else if (charInRange(ch
, 'a', 'f')) nRet
= ch
- unsigned('a' - 10u);
73 else if (charInRange(ch
, 'A', 'F')) nRet
= ch
- unsigned('A' - 10u);
75 else throwConversionError("Invalid Hex Character in binary value");
80 // -----------------------------------------------------------------------------
83 unsigned readHexNibble(sal_Unicode ch
) SAL_THROW((script::CannotConvertException
))
85 if (!charInRange(ch
, 0, 127)) throwConversionError("Non-Ascii Character in binary value");
87 return makeHexNibble(static_cast<unsigned char>(ch
));
90 // -----------------------------------------------------------------------------
93 unsigned int readHexByte(sal_Unicode
const*& pStr
) SAL_THROW((script::CannotConvertException
))
95 register unsigned int nHigh
= readHexNibble(*pStr
++);
96 register unsigned int nLow
= readHexNibble(*pStr
++);
97 return (nHigh
<< 4) | nLow
;
100 // -----------------------------------------------------------------------------
102 void parseHexBinary(rtl::OUString
const& aHexString_
, uno::Sequence
<sal_Int8
>& rBinarySeq_
)
103 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
105 // PRE: aBinaryString with HexCode
106 // POST: rBinarySeq with the to Hex converted String
108 sal_uInt32 nCount
= aHexString_
.getLength();
109 sal_Unicode
const * pHex
= aHexString_
.getStr();
111 if (nCount
% 2) throwConversionError("Hex string has odd number of characters");
114 rBinarySeq_
.realloc(nCount
);
115 sal_Int8
* pBinary
= rBinarySeq_
.getArray();
119 *pBinary
++ = static_cast<sal_Int8
>(readHexByte(pHex
));
123 // -----------------------------------------------------------------------------
124 // -----------------------------------------------------------------------------
125 uno::Sequence
<sal_Int8
> ValueConverter::parseBinary(rtl::OUString
const& aBinaryString_
) const
126 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
128 uno::Sequence
<sal_Int8
> aResultSeq
;
130 parseHexBinary(aBinaryString_
,aResultSeq
);
135 // -----------------------------------------------------------------------------
137 uno::Type
getBinaryType()
139 uno::Sequence
<sal_Int8
> const * const for_binary
= 0;
140 return ::getCppuType(for_binary
);
143 // -----------------------------------------------------------------------------
144 bool ValueConverter::isList() const
146 return m_aType
.getTypeClass() == uno::TypeClass_SEQUENCE
&&
147 m_aType
!= getBinaryType();
150 // -----------------------------------------------------------------------------
151 uno::Any
ValueConverter::convertToAny(rtl::OUString
const& aContent
) const
152 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
158 OSL_ENSURE(aContent
.trim().getLength() == 0, "ValueConverter: Non-empty Null Value - ignoring content");
159 OSL_ASSERT(!aValue
.hasValue());
162 else if (this->isList())
164 std::vector
< rtl::OUString
> aContentList
;
165 splitListData(aContent
, aContentList
);
166 convertListToAny(aContentList
, aValue
);
171 convertScalarToAny(aContent
, aValue
);
177 // -----------------------------------------------------------------------------
178 bool ValueConverter::convertScalarToAny(rtl::OUString
const& aContent
, uno::Any
& rValue
) const
179 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
181 OSL_PRECOND(!this->isNull(),"ValueConverter::convertScalarToAny - check for NULL before calling");
182 OSL_ENSURE(m_aType
.getTypeClass() != uno::TypeClass_ANY
,"'Any' values must be NULL");
185 if (m_aType
== getBinaryType())
187 com::sun::star::uno::Sequence
<sal_Int8
> aBinarySeq
= parseBinary(aContent
);
188 rValue
<<= aBinarySeq
;
193 rValue
= toAny(m_xTypeConverter
, aContent
, m_aType
.getTypeClass());
196 return !! rValue
.hasValue();
199 // -----------------------------------------------------------------------------
201 bool convertListToSequence(std::vector
< rtl::OUString
> const& aStringList
, uno::Sequence
< T
>& rSequence
, uno::TypeClass aElementTypeClass
, ValueConverter
const& rConverter
)
202 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
204 OSL_ASSERT(aElementTypeClass
== ::getCppuType(static_cast<T
const*>(0)).getTypeClass());
206 rSequence
.realloc(aStringList
.size());
210 for(std::vector
< rtl::OUString
>::const_iterator it
= aStringList
.begin();
211 it
!= aStringList
.end();
214 uno::Any aValueAny
= toAny(rConverter
.getTypeConverter(), *it
, aElementTypeClass
);
216 if (aValueAny
>>= rSequence
[nPos
])
219 else if (!aValueAny
.hasValue())
220 OSL_ENSURE(false,"UNEXPECTED: Found NULL value in List - ignoring value !");
223 OSL_ENSURE(false,"ERROR: Cannot extract converted value into List - skipping value !");
226 bool bOK
= (nPos
== aStringList
.size());
230 OSL_ASSERT(nPos
< aStringList
.size());
231 rSequence
.realloc(nPos
);
236 // -----------------------------------------------------------------------------
237 // special conversion for string sequence
241 void stringListToSequence(uno::Sequence
< rtl::OUString
> & rSequence
, std::vector
< rtl::OUString
> const & aStringList
)
243 rSequence
.realloc( aStringList
.size() );
245 std::copy( aStringList
.begin(), aStringList
.end(), rSequence
.getArray() );
247 // -----------------------------------------------------------------------------
251 std::vector
< rtl::OUString
> sequenceToStringList(uno::Sequence
< rtl::OUString
> const & aSequence
)
253 rtl::OUString
const * const pBegin
= aSequence
.getConstArray();
254 rtl::OUString
const * const pEnd
= pBegin
+ aSequence
.getLength();
256 return std::vector
< rtl::OUString
>(pBegin
,pEnd
);
258 // -----------------------------------------------------------------------------
260 uno::Sequence
< rtl::OUString
> ValueConverter::splitStringList(rtl::OUString
const& aContent
) const
262 std::vector
< rtl::OUString
> aList
;
263 splitListData(aContent
, aList
);
265 uno::Sequence
< rtl::OUString
> aResult
;
266 stringListToSequence(aResult
,aList
);
270 // -----------------------------------------------------------------------------
272 uno::Any
ValueConverter::convertListToAny(uno::Sequence
< rtl::OUString
> const& aContentList
) const
273 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
276 std::vector
< rtl::OUString
> const aStringList
= sequenceToStringList(aContentList
);
277 convertListToAny(aStringList
,aResult
);
280 // -----------------------------------------------------------------------------
281 // special overload for binary sequence
283 // template<> // use an explicit specialization
284 bool convertListToSequence(std::vector
< rtl::OUString
> const& aStringList
, uno::Sequence
< uno::Sequence
<sal_Int8
> >& rSequence
, uno::TypeClass aElementTypeClass
, ValueConverter
const& rParser
)
285 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
287 { (void)aElementTypeClass
; }
288 OSL_ASSERT(aElementTypeClass
== uno::TypeClass_SEQUENCE
);
290 rSequence
.realloc(aStringList
.size());
294 for(std::vector
< rtl::OUString
>::const_iterator it
= aStringList
.begin();
295 it
!= aStringList
.end();
298 rSequence
[nPos
++] = rParser
.parseBinary(*it
);
303 // -----------------------------------------------------------------------------
304 // special overload for string sequence
306 // template<> // use an explicit specialization
307 bool convertListToSequence(std::vector
< rtl::OUString
> const& aStringList
, uno::Sequence
< rtl::OUString
>& rSequence
, uno::TypeClass aElementTypeClass
, ValueConverter
const& /*rParser*/ )
308 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
310 { (void)aElementTypeClass
; }
311 OSL_ASSERT(aElementTypeClass
== uno::TypeClass_STRING
);
313 stringListToSequence(rSequence
, aStringList
);
318 // -----------------------------------------------------------------------------
320 #define MAYBE_EXTRACT_SEQUENCE( type ) \
321 if (aElementType == ::getCppuType( (type const *)0)) \
323 com::sun::star::uno::Sequence< type > aSequence; \
324 convertListToSequence(aContentList,aSequence,aElementTypeClass, *this); \
325 rValue <<= aSequence; \
328 bool ValueConverter::convertListToAny(std::vector
< rtl::OUString
> const& aContentList
, uno::Any
& rValue
) const
329 SAL_THROW((script::CannotConvertException
, com::sun::star::uno::RuntimeException
))
331 OSL_PRECOND(!this->isNull(),"ValueConverter::convertListToAny - check for NULL before calling");
332 OSL_ENSURE(m_aType
.getTypeClass() == uno::TypeClass_SEQUENCE
,"'Any' not allowed for lists");
334 uno::Type aElementType
= getSequenceElementType(m_aType
);
335 uno::TypeClass aElementTypeClass
= aElementType
.getTypeClass();
337 OSL_ENSURE(aElementTypeClass
!= uno::TypeClass_ANY
,"'Any' not allowed for list elements");
339 MAYBE_EXTRACT_SEQUENCE( rtl::OUString
)
341 MAYBE_EXTRACT_SEQUENCE( sal_Bool
)
343 MAYBE_EXTRACT_SEQUENCE( sal_Int16
)
345 MAYBE_EXTRACT_SEQUENCE( sal_Int32
)
347 MAYBE_EXTRACT_SEQUENCE( sal_Int64
)
349 MAYBE_EXTRACT_SEQUENCE( double )
351 MAYBE_EXTRACT_SEQUENCE( com::sun::star::uno::Sequence
<sal_Int8
> )
354 OSL_ENSURE(false, "Unknown element type in list");
355 throwConversionError("Invalid value-type found in list value");
358 return !! rValue
.hasValue();
360 #undef MAYBE_EXTRACT_SEQUENCE
362 // -----------------------------------------------------------------------------
365 sal_Int32
const NO_MORE_TOKENS
= -1;
366 struct OTokenizeByWhitespace
369 static inline bool isWhitespace(sal_Unicode ch
)
371 // note: for definition of whitescape see also
372 // canUseWhitespace(rtl::OUString const&)
373 // in xmlformater.cxx
374 // -----------------------------------------------------------------------------
375 return rtl_ascii_isWhitespace(ch
) ? true : false;
378 sal_Int32
findFirstTokenStart(rtl::OUString
const& sText
) const SAL_THROW(())
380 return findNextTokenStart(sText
,0);
383 sal_Int32
findNextTokenStart(rtl::OUString
const& sText
, sal_Int32 nPrevTokenEnd
) const SAL_THROW(())
385 sal_Int32
const nEnd
= sText
.getLength();
386 sal_Int32 nPos
= nPrevTokenEnd
;
388 OSL_PRECOND( nPos
== 0 || (0 < nPos
&& nPos
< nEnd
&& isWhitespace(sText
[nPos
])) || nPos
== nEnd
,
389 "Invalid nPrevTokenEnd");
391 while (nPos
< nEnd
&& isWhitespace(sText
[nPos
]))
399 return NO_MORE_TOKENS
;
402 sal_Int32
findTokenEnd(rtl::OUString
const& sText
, sal_Int32 nTokenStart
) const SAL_THROW(())
404 sal_Int32
const nEnd
= sText
.getLength();
405 sal_Int32 nPos
= nTokenStart
;
407 OSL_PRECOND( 0 <= nPos
&& nPos
< nEnd
&& !isWhitespace(sText
[nPos
]),
408 "Invalid nTokenStart");
410 while (nPos
< nEnd
&& !isWhitespace(sText
[nPos
]))
418 // -----------------------------------------------------------------------------
419 struct OTokenizeBySeparator
421 rtl::OUString
const sSeparator
;
422 OTokenizeBySeparator(rtl::OUString
const& _sSeparator
) SAL_THROW(())
423 : sSeparator(_sSeparator
)
425 OSL_PRECOND(sSeparator
.trim().getLength() > 0, "Invalid empty separator string");
428 sal_Int32
findFirstTokenStart(rtl::OUString
const& /*sText*/) const SAL_THROW(())
432 sal_Int32
findNextTokenStart(rtl::OUString
const& sText
, sal_Int32 nPrevTokenEnd
) const SAL_THROW(())
434 sal_Int32
const nEnd
= sText
.getLength();
435 sal_Int32 nPos
= nPrevTokenEnd
;
436 OSL_PRECOND( nPos
== nEnd
|| (0 <= nPos
&& nPos
< nEnd
&& sText
.indexOf(sSeparator
, nPos
) == nPos
),
437 "Invalid nPrevTokenEnd");
440 return nPos
+ sSeparator
.getLength();
442 return NO_MORE_TOKENS
;
444 sal_Int32
findTokenEnd(rtl::OUString
const& sText
, sal_Int32 nTokenStart
) const SAL_THROW(())
446 sal_Int32
const nEnd
= sText
.getLength();
447 OSL_PRECOND( 0 <= nTokenStart
&& nTokenStart
<= nEnd
,
448 "Invalid nTokenStart");
450 sal_Int32 nPos
= sText
.indexOf(sSeparator
,nTokenStart
);
458 // -----------------------------------------------------------------------------
459 template <class Tokenizer
>
460 void tokenizeListData(Tokenizer
const& aTokenizer
, rtl::OUString
const& aContent
, std::vector
< rtl::OUString
>& rContentList
)
463 sal_Int32 nTokenPos
= aTokenizer
.findFirstTokenStart(aContent
);
465 while(nTokenPos
!= NO_MORE_TOKENS
)
467 sal_Int32 nTokenEnd
= aTokenizer
.findTokenEnd(aContent
, nTokenPos
);
469 // this is what the tokenizer must provide
470 OSL_ASSERT(0 <= nTokenPos
&& nTokenPos
<= nTokenEnd
&& nTokenEnd
<= aContent
.getLength());
472 rContentList
.push_back( aContent
.copy(nTokenPos
, nTokenEnd
-nTokenPos
) );
474 nTokenPos
= aTokenizer
.findNextTokenStart(aContent
, nTokenEnd
);
477 // -----------------------------------------------------------------------------
479 // -----------------------------------------------------------------------------
480 void ValueConverter::splitListData(rtl::OUString
const& aContent
, std::vector
< rtl::OUString
>& rContentList
) const
483 rtl::OUString sSeparator
= m_sSeparator
;
485 bool bSeparateByWhitespace
= (sSeparator
.trim().getLength() == 0);
487 if (bSeparateByWhitespace
)
489 OSL_ENSURE( sSeparator
.getLength()==0 || sSeparator
.equalsAscii(" "),
490 "Unexpected whitespace-only separator");
492 tokenizeListData( OTokenizeByWhitespace(), aContent
, rContentList
);
496 OSL_ENSURE( sSeparator
.trim()==sSeparator
,
497 "Unexpected whitespace in separator");
499 tokenizeListData( OTokenizeBySeparator(sSeparator
), aContent
, rContentList
);
502 // -----------------------------------------------------------------------------