1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "convert.hxx"
24 #include <rtl/math.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <osl/diagnose.h>
27 #include <tools/date.hxx>
28 #include <com/sun/star/lang/IllegalArgumentException.hpp>
29 #include <com/sun/star/uno/Type.hxx>
30 #include <com/sun/star/util/Date.hpp>
31 #include <com/sun/star/util/DateTime.hpp>
32 #include <com/sun/star/util/Time.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <unotools/datetime.hxx>
36 using xforms::Convert
;
37 using com::sun::star::uno::Any
;
48 OUString
lcl_toXSD_OUString( const Any
& rAny
)
49 { OUString sStr
; rAny
>>= sStr
; return sStr
; }
52 Any
lcl_toAny_OUString( const OUString
& rStr
)
55 OUString
lcl_toXSD_bool( const Any
& rAny
)
56 { bool b
= false; rAny
>>= b
; return b
? u
"true"_ustr
: u
"false"_ustr
; }
58 Any
lcl_toAny_bool( const OUString
& rStr
)
60 bool b
= ( rStr
== "true" || rStr
== "1" );
64 OUString
lcl_toXSD_double( const Any
& rAny
)
69 return std::isfinite( f
)
70 ? rtl::math::doubleToUString( f
, rtl_math_StringFormat_Automatic
,
71 rtl_math_DecimalPlaces_Max
, '.',
77 Any
lcl_toAny_double( const OUString
& rString
)
79 rtl_math_ConversionStatus eStatus
;
80 double f
= rtl::math::stringToDouble(
81 rString
.replace(',','.'), '.', ',', &eStatus
);
82 return ( eStatus
== rtl_math_ConversionStatus_Ok
) ? Any( f
) : Any();
85 void lcl_appendInt32ToBuffer( const sal_Int32 _nValue
, OUStringBuffer
& _rBuffer
, sal_Int16 _nMinDigits
)
87 if ( ( _nMinDigits
>= 4 ) && ( _nValue
< 1000 ) )
88 _rBuffer
.append( '0' );
89 if ( ( _nMinDigits
>= 3 ) && ( _nValue
< 100 ) )
90 _rBuffer
.append( '0' );
91 if ( ( _nMinDigits
>= 2 ) && ( _nValue
< 10 ) )
92 _rBuffer
.append( '0' );
93 _rBuffer
.append( _nValue
);
97 OUString
lcl_toXSD_UNODate_typed( const css::util::Date
& rDate
)
100 OUStringBuffer sInfo
;
101 lcl_appendInt32ToBuffer( rDate
.Year
, sInfo
, 4 );
103 lcl_appendInt32ToBuffer( rDate
.Month
, sInfo
, 2 );
105 lcl_appendInt32ToBuffer( rDate
.Day
, sInfo
, 2 );
107 return sInfo
.makeStringAndClear();
111 OUString
lcl_toXSD_UNODate( const Any
& rAny
)
113 css::util::Date aDate
;
114 OSL_VERIFY( rAny
>>= aDate
);
115 return lcl_toXSD_UNODate_typed( aDate
);
119 css::util::Date
lcl_toUNODate( std::u16string_view rString
)
121 css::util::Date
aDate( 1, 1, 1900 );
123 bool bWellformed
= ISO8601parseDate(rString
, aDate
);
126 if ( ( aDate
.Year
> 9999 ) || ( aDate
.Month
< 1 ) || ( aDate
.Month
> 12 ) || ( aDate
.Day
< 1 ) || ( aDate
.Day
> 31 ) )
130 ::Date
aDateCheck( 1, aDate
.Month
, aDate
.Year
);
131 if ( aDate
.Day
> aDateCheck
.GetDaysInMonth() )
137 throw css::lang::IllegalArgumentException();
143 Any
lcl_toAny_UNODate( const OUString
& rString
)
145 return Any( lcl_toUNODate( rString
) );
149 OUString
lcl_toXSD_UNOTime_typed( const css::util::Time
& rTime
)
152 OUStringBuffer sInfo
;
153 lcl_appendInt32ToBuffer( rTime
.Hours
, sInfo
, 2 );
155 lcl_appendInt32ToBuffer( rTime
.Minutes
, sInfo
, 2 );
157 lcl_appendInt32ToBuffer( rTime
.Seconds
, sInfo
, 2 );
158 if ( rTime
.NanoSeconds
!= 0 )
160 OSL_ENSURE(rTime
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
162 std::ostringstream ostr
;
165 ostr
<< rTime
.NanoSeconds
;
166 sInfo
.appendAscii(ostr
.str().c_str());
169 return sInfo
.makeStringAndClear();
173 OUString
lcl_toXSD_UNOTime( const Any
& rAny
)
175 css::util::Time aTime
;
176 OSL_VERIFY( rAny
>>= aTime
);
177 return lcl_toXSD_UNOTime_typed( aTime
);
181 css::util::Time
lcl_toUNOTime( std::u16string_view rString
)
183 css::util::Time aTime
;
185 bool bWellformed
= ISO8601parseTime(rString
, aTime
);
188 // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere,
189 // but we accept them all the time for simplicity reasons
190 if ( ( aTime
.Hours
> 24 )
191 || ( aTime
.Minutes
> 59 )
192 || ( aTime
.Seconds
> 60 )
197 && ( aTime
.Hours
== 24 )
198 && ( ( aTime
.Minutes
!= 0 )
199 || ( aTime
.Seconds
!= 0 )
200 || ( aTime
.NanoSeconds
!= 0 )
207 throw css::lang::IllegalArgumentException();
213 Any
lcl_toAny_UNOTime( const OUString
& rString
)
215 return Any( lcl_toUNOTime( rString
) );
219 OUString
lcl_toXSD_UNODateTime( const Any
& rAny
)
221 css::util::DateTime aDateTime
;
222 OSL_VERIFY( rAny
>>= aDateTime
);
224 css::util::Date
aDate( aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
225 OUString sDate
= lcl_toXSD_UNODate_typed( aDate
);
227 css::util::Time
const aTime( aDateTime
.NanoSeconds
, aDateTime
.Seconds
,
228 aDateTime
.Minutes
, aDateTime
.Hours
, aDateTime
.IsUTC
);
229 OUString sTime
= lcl_toXSD_UNOTime_typed( aTime
);
231 OUString sRet
= sDate
+ "T" + sTime
;
236 Any
lcl_toAny_UNODateTime( const OUString
& rString
)
238 // separate the date from the time part
239 sal_Int32 nDateTimeSep
= rString
.indexOf( 'T' );
240 if ( nDateTimeSep
== -1 )
241 nDateTimeSep
= rString
.indexOf( 't' );
243 css::util::Date aDate
;
244 css::util::Time aTime
;
245 if ( nDateTimeSep
== -1 )
247 aDate
= lcl_toUNODate( rString
);
251 aDate
= lcl_toUNODate( rString
.subView( 0, nDateTimeSep
) );
252 aTime
= lcl_toUNOTime( rString
.subView( nDateTimeSep
+ 1 ) );
254 css::util::DateTime
aDateTime(
255 aTime
.NanoSeconds
, aTime
.Seconds
, aTime
.Minutes
, aTime
.Hours
,
256 aDate
.Day
, aDate
.Month
, aDate
.Year
, aTime
.IsUTC
258 return Any( aDateTime
);
265 maMap
[ cppu::UnoType
<OUString
>::get() ] = Convert_t(&lcl_toXSD_OUString
, &lcl_toAny_OUString
);
266 maMap
[ cppu::UnoType
<bool>::get() ] = Convert_t(&lcl_toXSD_bool
, &lcl_toAny_bool
);
267 maMap
[ cppu::UnoType
<double>::get() ] = Convert_t(&lcl_toXSD_double
, &lcl_toAny_double
);
268 maMap
[ cppu::UnoType
<css::util::Date
>::get() ] = Convert_t( &lcl_toXSD_UNODate
, &lcl_toAny_UNODate
);
269 maMap
[ cppu::UnoType
<css::util::Time
>::get() ] = Convert_t( &lcl_toXSD_UNOTime
, &lcl_toAny_UNOTime
);
270 maMap
[ cppu::UnoType
<css::util::DateTime
>::get() ] = Convert_t( &lcl_toXSD_UNODateTime
, &lcl_toAny_UNODateTime
);
274 Convert
& Convert::get()
276 // create our Singleton instance on demand
277 static Convert aConvert
;
281 bool Convert::hasType( const css::uno::Type
& rType
)
283 return maMap
.find( rType
) != maMap
.end();
286 css::uno::Sequence
<css::uno::Type
> Convert::getTypes() const
288 return comphelper::mapKeysToSequence( maMap
);
291 OUString
Convert::toXSD( const css::uno::Any
& rAny
)
293 Map_t::iterator aIter
= maMap
.find( rAny
.getValueType() );
294 return aIter
!= maMap
.end() ? aIter
->second
.first( rAny
) : OUString();
297 css::uno::Any
Convert::toAny( const OUString
& rValue
,
298 const css::uno::Type
& rType
)
300 Map_t::iterator aIter
= maMap
.find( rType
);
301 return aIter
!= maMap
.end() ? aIter
->second
.second( rValue
) : css::uno::Any();
305 OUString
Convert::collapseWhitespace( const OUString
& _rString
)
307 sal_Int32 nLength
= _rString
.getLength();
308 OUStringBuffer
aBuffer( nLength
);
309 const sal_Unicode
* pStr
= _rString
.getStr();
311 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
313 sal_Unicode c
= pStr
[i
];
314 if( c
== u
'\x0008' ||
321 aBuffer
.append( u
' ' );
331 if( aBuffer
[ aBuffer
.getLength() - 1 ] == u
' ' )
332 aBuffer
.setLength( aBuffer
.getLength() - 1 );
333 return aBuffer
.makeStringAndClear();
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */