update dev300-m58
[ooovba.git] / configmgr / source / xml / valueconverter.cxx
blob7143dd62607b020f17d74a96c00b5b1b1275cd52
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: valueconverter.cxx,v $
10 * $Revision: 1.23 $
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;
42 namespace configmgr
44 // -----------------------------------------------------------------------------
45 static
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);
52 throw error;
54 // -----------------------------------------------------------------------------
55 template <class Char>
56 inline
57 bool charInRange(Char ch, char from, char to) throw()
59 return Char(from) <= ch && ch <= Char(to);
62 // -----------------------------------------------------------------------------
63 static
64 inline
65 unsigned makeHexNibble(unsigned char ch) SAL_THROW((script::CannotConvertException))
67 unsigned nRet = 0;
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");
77 return nRet;
80 // -----------------------------------------------------------------------------
81 static
82 inline
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 // -----------------------------------------------------------------------------
91 static
92 inline
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 // -----------------------------------------------------------------------------
101 static
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");
112 nCount /= 2;
114 rBinarySeq_.realloc(nCount);
115 sal_Int8 * pBinary = rBinarySeq_.getArray();
117 while (nCount--)
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);
132 return aResultSeq;
135 // -----------------------------------------------------------------------------
136 static inline
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))
154 uno::Any aValue;
156 if (this->isNull())
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);
169 else
171 convertScalarToAny(aContent, aValue);
174 return 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");
184 // check for Binary
185 if (m_aType == getBinaryType())
187 com::sun::star::uno::Sequence<sal_Int8> aBinarySeq = parseBinary(aContent);
188 rValue <<= aBinarySeq;
191 else
193 rValue = toAny(m_xTypeConverter, aContent, m_aType.getTypeClass());
196 return !! rValue.hasValue();
199 // -----------------------------------------------------------------------------
200 template <class T>
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());
208 sal_uInt32 nPos = 0;
210 for(std::vector< rtl::OUString >::const_iterator it = aStringList.begin();
211 it != aStringList.end();
212 ++it)
214 uno::Any aValueAny = toAny(rConverter.getTypeConverter(), *it, aElementTypeClass);
216 if (aValueAny >>= rSequence[nPos])
217 ++nPos;
219 else if (!aValueAny.hasValue())
220 OSL_ENSURE(false,"UNEXPECTED: Found NULL value in List - ignoring value !");
222 else
223 OSL_ENSURE(false,"ERROR: Cannot extract converted value into List - skipping value !");
226 bool bOK = (nPos == aStringList.size());
228 if (!bOK)
230 OSL_ASSERT(nPos < aStringList.size());
231 rSequence.realloc(nPos);
233 return bOK;
236 // -----------------------------------------------------------------------------
237 // special conversion for string sequence
239 static
240 inline
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 // -----------------------------------------------------------------------------
249 static
250 inline
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);
268 return aResult;
270 // -----------------------------------------------------------------------------
272 uno::Any ValueConverter::convertListToAny(uno::Sequence< rtl::OUString > const& aContentList) const
273 SAL_THROW((script::CannotConvertException , com::sun::star::uno::RuntimeException))
275 uno::Any aResult;
276 std::vector< rtl::OUString > const aStringList = sequenceToStringList(aContentList);
277 convertListToAny(aStringList,aResult);
278 return 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());
292 sal_uInt32 nPos = 0;
294 for(std::vector< rtl::OUString >::const_iterator it = aStringList.begin();
295 it != aStringList.end();
296 ++it)
298 rSequence[nPos++] = rParser.parseBinary(*it);
300 return true;
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);
315 return true;
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 )
340 else
341 MAYBE_EXTRACT_SEQUENCE( sal_Bool )
342 else
343 MAYBE_EXTRACT_SEQUENCE( sal_Int16 )
344 else
345 MAYBE_EXTRACT_SEQUENCE( sal_Int32 )
346 else
347 MAYBE_EXTRACT_SEQUENCE( sal_Int64 )
348 else
349 MAYBE_EXTRACT_SEQUENCE( double )
350 else
351 MAYBE_EXTRACT_SEQUENCE( com::sun::star::uno::Sequence<sal_Int8> )
352 else
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 // -----------------------------------------------------------------------------
363 namespace
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]))
393 ++nPos;
396 if (nPos < nEnd)
397 return nPos;
398 else
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]))
412 ++nPos;
415 return 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(())
430 return 0;
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");
439 if (nPos < nEnd)
440 return nPos + sSeparator.getLength();
441 else
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);
452 if (nPos >= 0)
453 return nPos;
454 else
455 return nEnd;
458 // -----------------------------------------------------------------------------
459 template <class Tokenizer>
460 void tokenizeListData(Tokenizer const& aTokenizer, rtl::OUString const& aContent, std::vector< rtl::OUString >& rContentList)
461 SAL_THROW(())
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
481 SAL_THROW(())
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 );
494 else
496 OSL_ENSURE( sSeparator.trim()==sSeparator,
497 "Unexpected whitespace in separator");
499 tokenizeListData( OTokenizeBySeparator(sSeparator), aContent, rContentList );
502 // -----------------------------------------------------------------------------
504 } // namespace