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/uno/Type.hxx>
29 #include <com/sun/star/util/Date.hpp>
30 #include <com/sun/star/util/DateTime.hpp>
31 #include <com/sun/star/util/Time.hpp>
32 #include <comphelper/sequence.hxx>
33 #include <unotools/datetime.hxx>
35 using xforms::Convert
;
36 using com::sun::star::uno::Any
;
37 using com::sun::star::uno::makeAny
;
47 #define ADD_ENTRY(XCONVERT,TYPE) XCONVERT->maMap[ cppu::UnoType<TYPE>::get() ] = Convert_t( &lcl_toXSD_##TYPE, &lcl_toAny_##TYPE )
52 OUString
lcl_toXSD_OUString( const Any
& rAny
)
53 { OUString sStr
; rAny
>>= sStr
; return sStr
; }
56 Any
lcl_toAny_OUString( const OUString
& rStr
)
60 OUString
lcl_toXSD_bool( const Any
& rAny
)
61 { bool b
= false; rAny
>>= b
; return b
? OUString("true") : OUString("false"); }
64 Any
lcl_toAny_bool( const OUString
& rStr
)
66 bool b
= ( rStr
== "true" || rStr
== "1" );
71 OUString
lcl_toXSD_double( const Any
& rAny
)
76 return std::isfinite( f
)
77 ? rtl::math::doubleToUString( f
, rtl_math_StringFormat_Automatic
,
78 rtl_math_DecimalPlaces_Max
, '.',
84 Any
lcl_toAny_double( const OUString
& rString
)
86 rtl_math_ConversionStatus eStatus
;
87 double f
= rtl::math::stringToDouble(
88 rString
, '.', ',', &eStatus
);
89 return ( eStatus
== rtl_math_ConversionStatus_Ok
) ? makeAny( f
) : Any();
93 void lcl_appendInt32ToBuffer( const sal_Int32 _nValue
, OUStringBuffer
& _rBuffer
, sal_Int16 _nMinDigits
)
95 if ( ( _nMinDigits
>= 4 ) && ( _nValue
< 1000 ) )
96 _rBuffer
.append( '0' );
97 if ( ( _nMinDigits
>= 3 ) && ( _nValue
< 100 ) )
98 _rBuffer
.append( '0' );
99 if ( ( _nMinDigits
>= 2 ) && ( _nValue
< 10 ) )
100 _rBuffer
.append( '0' );
101 _rBuffer
.append( _nValue
);
105 OUString
lcl_toXSD_UNODate_typed( const css::util::Date
& rDate
)
108 OUStringBuffer sInfo
;
109 lcl_appendInt32ToBuffer( rDate
.Year
, sInfo
, 4 );
111 lcl_appendInt32ToBuffer( rDate
.Month
, sInfo
, 2 );
113 lcl_appendInt32ToBuffer( rDate
.Day
, sInfo
, 2 );
115 return sInfo
.makeStringAndClear();
119 OUString
lcl_toXSD_UNODate( const Any
& rAny
)
121 css::util::Date aDate
;
122 OSL_VERIFY( rAny
>>= aDate
);
123 return lcl_toXSD_UNODate_typed( aDate
);
127 css::util::Date
lcl_toUNODate( const OUString
& rString
)
129 css::util::Date
aDate( 1, 1, 1900 );
131 bool bWellformed
= ISO8601parseDate(rString
, aDate
);
134 if ( ( aDate
.Year
> 9999 ) || ( aDate
.Month
< 1 ) || ( aDate
.Month
> 12 ) || ( aDate
.Day
< 1 ) || ( aDate
.Day
> 31 ) )
138 ::Date
aDateCheck( 1, aDate
.Month
, aDate
.Year
);
139 if ( aDate
.Day
> aDateCheck
.GetDaysInMonth() )
145 return css::util::Date( 1, 1, 1900 );
151 Any
lcl_toAny_UNODate( const OUString
& rString
)
153 return makeAny( lcl_toUNODate( rString
) );
157 OUString
lcl_toXSD_UNOTime_typed( const css::util::Time
& rTime
)
160 OUStringBuffer sInfo
;
161 lcl_appendInt32ToBuffer( rTime
.Hours
, sInfo
, 2 );
163 lcl_appendInt32ToBuffer( rTime
.Minutes
, sInfo
, 2 );
165 lcl_appendInt32ToBuffer( rTime
.Seconds
, sInfo
, 2 );
166 if ( rTime
.NanoSeconds
!= 0 )
168 OSL_ENSURE(rTime
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
170 std::ostringstream ostr
;
173 ostr
<< rTime
.NanoSeconds
;
174 sInfo
.append(OUString::createFromAscii(ostr
.str().c_str()));
177 return sInfo
.makeStringAndClear();
181 OUString
lcl_toXSD_UNOTime( const Any
& rAny
)
183 css::util::Time aTime
;
184 OSL_VERIFY( rAny
>>= aTime
);
185 return lcl_toXSD_UNOTime_typed( aTime
);
189 css::util::Time
lcl_toUNOTime( const OUString
& rString
)
191 css::util::Time aTime
;
193 bool bWellformed
= ISO8601parseTime(rString
, aTime
);
196 // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere,
197 // but we accept them all the time for simplicity reasons
198 if ( ( aTime
.Hours
> 24 )
199 || ( aTime
.Minutes
> 59 )
200 || ( aTime
.Seconds
> 60 )
205 && ( aTime
.Hours
== 24 )
206 && ( ( aTime
.Minutes
!= 0 )
207 || ( aTime
.Seconds
!= 0 )
208 || ( aTime
.NanoSeconds
!= 0 )
215 return css::util::Time();
221 Any
lcl_toAny_UNOTime( const OUString
& rString
)
223 return makeAny( lcl_toUNOTime( rString
) );
227 OUString
lcl_toXSD_UNODateTime( const Any
& rAny
)
229 css::util::DateTime aDateTime
;
230 OSL_VERIFY( rAny
>>= aDateTime
);
232 css::util::Date
aDate( aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
233 OUString sDate
= lcl_toXSD_UNODate_typed( aDate
);
235 css::util::Time
const aTime( aDateTime
.NanoSeconds
, aDateTime
.Seconds
,
236 aDateTime
.Minutes
, aDateTime
.Hours
, aDateTime
.IsUTC
);
237 OUString sTime
= lcl_toXSD_UNOTime_typed( aTime
);
239 OUString sRet
= sDate
+ "T" + sTime
;
244 Any
lcl_toAny_UNODateTime( const OUString
& rString
)
246 // separate the date from the time part
247 sal_Int32 nDateTimeSep
= rString
.indexOf( 'T' );
248 if ( nDateTimeSep
== -1 )
249 nDateTimeSep
= rString
.indexOf( 't' );
251 css::util::Date aDate
;
252 css::util::Time aTime
;
253 if ( nDateTimeSep
== -1 )
255 aDate
= lcl_toUNODate( rString
);
259 aDate
= lcl_toUNODate( rString
.copy( 0, nDateTimeSep
) );
260 aTime
= lcl_toUNOTime( rString
.copy( nDateTimeSep
+ 1 ) );
262 css::util::DateTime
aDateTime(
263 aTime
.NanoSeconds
, aTime
.Seconds
, aTime
.Minutes
, aTime
.Hours
,
264 aDate
.Day
, aDate
.Month
, aDate
.Year
, aTime
.IsUTC
266 return makeAny( aDateTime
);
273 ADD_ENTRY( this, OUString
);
274 ADD_ENTRY( this, bool );
275 ADD_ENTRY( this, double );
276 maMap
[ cppu::UnoType
<css::util::Date
>::get() ] = Convert_t( &lcl_toXSD_UNODate
, &lcl_toAny_UNODate
);
277 maMap
[ cppu::UnoType
<css::util::Time
>::get() ] = Convert_t( &lcl_toXSD_UNOTime
, &lcl_toAny_UNOTime
);
278 maMap
[ cppu::UnoType
<css::util::DateTime
>::get() ] = Convert_t( &lcl_toXSD_UNODateTime
, &lcl_toAny_UNODateTime
);
282 Convert
& Convert::get()
284 // create our Singleton instance on demand
285 static Convert aConvert
;
289 bool Convert::hasType( const css::uno::Type
& rType
)
291 return maMap
.find( rType
) != maMap
.end();
294 css::uno::Sequence
<css::uno::Type
> Convert::getTypes() const
296 return comphelper::mapKeysToSequence( maMap
);
299 OUString
Convert::toXSD( const css::uno::Any
& rAny
)
301 Map_t::iterator aIter
= maMap
.find( rAny
.getValueType() );
302 return aIter
!= maMap
.end() ? aIter
->second
.first( rAny
) : OUString();
305 css::uno::Any
Convert::toAny( const OUString
& rValue
,
306 const css::uno::Type
& rType
)
308 Map_t::iterator aIter
= maMap
.find( rType
);
309 return aIter
!= maMap
.end() ? aIter
->second
.second( rValue
) : css::uno::Any();
313 OUString
Convert::collapseWhitespace( const OUString
& _rString
)
315 sal_Int32 nLength
= _rString
.getLength();
316 OUStringBuffer
aBuffer( nLength
);
317 const sal_Unicode
* pStr
= _rString
.getStr();
319 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
321 sal_Unicode c
= pStr
[i
];
322 if( c
== u
'\x0008' ||
329 aBuffer
.append( u
' ' );
339 if( aBuffer
[ aBuffer
.getLength() - 1 ] == u
' ' )
340 aBuffer
.setLength( aBuffer
.getLength() - 1 );
341 return aBuffer
.makeStringAndClear();
344 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */