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"
23 #include "unohelper.hxx"
26 #include <o3tl/compat_functional.hxx>
27 #include <rtl/math.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <osl/diagnose.h>
30 #include <tools/date.hxx>
31 #include <com/sun/star/uno/Type.hxx>
32 #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
33 #include <com/sun/star/util/Date.hpp>
34 #include <com/sun/star/util/DateTime.hpp>
35 #include <com/sun/star/util/Time.hpp>
36 #include <unotools/datetime.hxx>
38 using xforms::Convert
;
39 using com::sun::star::uno::Any
;
40 using com::sun::star::uno::makeAny
;
45 typedef com::sun::star::util::Date UNODate
;
46 typedef com::sun::star::util::Time UNOTime
;
47 typedef com::sun::star::util::DateTime UNODateTime
;
55 #define ADD_ENTRY(XCONVERT,TYPE) XCONVERT->maMap[ cppu::UnoType<TYPE>::get() ] = Convert_t( &lcl_toXSD_##TYPE, &lcl_toAny_##TYPE )
60 OUString
lcl_toXSD_OUString( const Any
& rAny
)
61 { OUString sStr
; rAny
>>= sStr
; return sStr
; }
64 Any
lcl_toAny_OUString( const OUString
& rStr
)
65 { Any aAny
; aAny
<<= rStr
; return aAny
; }
68 OUString
lcl_toXSD_bool( const Any
& rAny
)
69 { bool b
= false; rAny
>>= b
; return b
? OUString("true") : OUString("false"); }
72 Any
lcl_toAny_bool( const OUString
& rStr
)
74 bool b
= ( rStr
== "true" || rStr
== "1" );
79 OUString
lcl_toXSD_double( const Any
& rAny
)
84 return rtl::math::isFinite( f
)
85 ? rtl::math::doubleToUString( f
, rtl_math_StringFormat_Automatic
,
86 rtl_math_DecimalPlaces_Max
, '.',
92 Any
lcl_toAny_double( const OUString
& rString
)
94 rtl_math_ConversionStatus eStatus
;
95 double f
= rtl::math::stringToDouble(
96 rString
, '.', ',', &eStatus
, NULL
);
97 return ( eStatus
== rtl_math_ConversionStatus_Ok
) ? makeAny( f
) : Any();
101 void lcl_appendInt32ToBuffer( const sal_Int32 _nValue
, OUStringBuffer
& _rBuffer
, sal_Int16 _nMinDigits
)
103 if ( ( _nMinDigits
>= 4 ) && ( _nValue
< 1000 ) )
104 _rBuffer
.append( '0' );
105 if ( ( _nMinDigits
>= 3 ) && ( _nValue
< 100 ) )
106 _rBuffer
.append( '0' );
107 if ( ( _nMinDigits
>= 2 ) && ( _nValue
< 10 ) )
108 _rBuffer
.append( '0' );
109 _rBuffer
.append( _nValue
);
113 OUString
lcl_toXSD_UNODate_typed( const UNODate
& rDate
)
116 OUStringBuffer sInfo
;
117 lcl_appendInt32ToBuffer( rDate
.Year
, sInfo
, 4 );
118 sInfo
.appendAscii( "-" );
119 lcl_appendInt32ToBuffer( rDate
.Month
, sInfo
, 2 );
120 sInfo
.appendAscii( "-" );
121 lcl_appendInt32ToBuffer( rDate
.Day
, sInfo
, 2 );
123 return sInfo
.makeStringAndClear();
127 OUString
lcl_toXSD_UNODate( const Any
& rAny
)
130 OSL_VERIFY( rAny
>>= aDate
);
131 return lcl_toXSD_UNODate_typed( aDate
);
135 UNODate
lcl_toUNODate( const OUString
& rString
)
137 UNODate
aDate( 1, 1, 1900 );
139 bool bWellformed
= ISO8601parseDate(rString
, aDate
);
142 if ( ( aDate
.Year
> 9999 ) || ( aDate
.Month
< 1 ) || ( aDate
.Month
> 12 ) || ( aDate
.Day
< 1 ) || ( aDate
.Day
> 31 ) )
146 ::Date
aDateCheck( 1, aDate
.Month
, aDate
.Year
);
147 if ( aDate
.Day
> aDateCheck
.GetDaysInMonth() )
153 return UNODate( 1, 1, 1900 );
159 Any
lcl_toAny_UNODate( const OUString
& rString
)
161 return makeAny( lcl_toUNODate( rString
) );
165 OUString
lcl_toXSD_UNOTime_typed( const UNOTime
& rTime
)
168 OUStringBuffer sInfo
;
169 lcl_appendInt32ToBuffer( rTime
.Hours
, sInfo
, 2 );
170 sInfo
.appendAscii( ":" );
171 lcl_appendInt32ToBuffer( rTime
.Minutes
, sInfo
, 2 );
172 sInfo
.appendAscii( ":" );
173 lcl_appendInt32ToBuffer( rTime
.Seconds
, sInfo
, 2 );
174 if ( rTime
.NanoSeconds
!= 0 )
176 OSL_ENSURE(rTime
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
178 std::ostringstream ostr
;
181 ostr
<< rTime
.NanoSeconds
;
182 sInfo
.append(OUString::createFromAscii(ostr
.str().c_str()));
185 return sInfo
.makeStringAndClear();
189 OUString
lcl_toXSD_UNOTime( const Any
& rAny
)
192 OSL_VERIFY( rAny
>>= aTime
);
193 return lcl_toXSD_UNOTime_typed( aTime
);
197 UNOTime
lcl_toUNOTime( const OUString
& rString
)
201 bool bWellformed
= ISO8601parseTime(rString
, aTime
);
204 // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere,
205 // but we accept them all the time for simplicity reasons
206 if ( ( aTime
.Hours
> 24 )
207 || ( aTime
.Minutes
> 59 )
208 || ( aTime
.Seconds
> 60 )
213 && ( aTime
.Hours
== 24 )
214 && ( ( aTime
.Minutes
!= 0 )
215 || ( aTime
.Seconds
!= 0 )
216 || ( aTime
.NanoSeconds
!= 0 )
229 Any
lcl_toAny_UNOTime( const OUString
& rString
)
231 return makeAny( lcl_toUNOTime( rString
) );
235 OUString
lcl_toXSD_UNODateTime( const Any
& rAny
)
237 UNODateTime aDateTime
;
238 OSL_VERIFY( rAny
>>= aDateTime
);
240 UNODate
aDate( aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
241 OUString sDate
= lcl_toXSD_UNODate_typed( aDate
);
243 UNOTime
const aTime( aDateTime
.NanoSeconds
, aDateTime
.Seconds
,
244 aDateTime
.Minutes
, aDateTime
.Hours
, aDateTime
.IsUTC
);
245 OUString sTime
= lcl_toXSD_UNOTime_typed( aTime
);
247 OUString sRet
= sDate
+ "T" + sTime
;
252 Any
lcl_toAny_UNODateTime( const OUString
& rString
)
254 // separate the date from the time part
255 sal_Int32 nDateTimeSep
= rString
.indexOf( 'T' );
256 if ( nDateTimeSep
== -1 )
257 nDateTimeSep
= rString
.indexOf( 't' );
261 if ( nDateTimeSep
== -1 )
263 aDate
= lcl_toUNODate( rString
);
267 aDate
= lcl_toUNODate( rString
.copy( 0, nDateTimeSep
) );
268 aTime
= lcl_toUNOTime( rString
.copy( nDateTimeSep
+ 1 ) );
270 UNODateTime
aDateTime(
271 aTime
.NanoSeconds
, aTime
.Seconds
, aTime
.Minutes
, aTime
.Hours
,
272 aDate
.Day
, aDate
.Month
, aDate
.Year
, aTime
.IsUTC
274 return makeAny( aDateTime
);
281 ADD_ENTRY( this, OUString
);
282 ADD_ENTRY( this, bool );
283 ADD_ENTRY( this, double );
284 ADD_ENTRY( this, UNODate
);
285 ADD_ENTRY( this, UNOTime
);
286 ADD_ENTRY( this, UNODateTime
);
290 Convert
& Convert::get()
292 // create our Singleton instance on demand
293 static Convert
* pConvert
= NULL
;
294 if( pConvert
== NULL
)
295 pConvert
= new Convert();
297 OSL_ENSURE( pConvert
!= NULL
, "no converter?" );
301 bool Convert::hasType( const Type_t
& rType
)
303 return maMap
.find( rType
) != maMap
.end();
306 Convert::Types_t
Convert::getTypes()
308 Types_t
aTypes( maMap
.size() );
309 transform( maMap
.begin(), maMap
.end(), aTypes
.getArray(),
310 o3tl::select1st
<Map_t::value_type
>() );
314 OUString
Convert::toXSD( const Any_t
& rAny
)
316 Map_t::iterator aIter
= maMap
.find( rAny
.getValueType() );
317 return aIter
!= maMap
.end() ? aIter
->second
.first( rAny
) : OUString();
320 Convert::Any_t
Convert::toAny( const OUString
& rValue
,
321 const Type_t
& rType
)
323 Map_t::iterator aIter
= maMap
.find( rType
);
324 return aIter
!= maMap
.end() ? aIter
->second
.second( rValue
) : Any_t();
328 OUString
Convert::collapseWhitespace( const OUString
& _rString
)
330 sal_Int32 nLength
= _rString
.getLength();
331 OUStringBuffer
aBuffer( nLength
);
332 const sal_Unicode
* pStr
= _rString
.getStr();
334 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
336 sal_Unicode c
= pStr
[i
];
337 if( c
== sal_Unicode(0x08) ||
338 c
== sal_Unicode(0x0A) ||
339 c
== sal_Unicode(0x0D) ||
340 c
== sal_Unicode(0x20) )
344 aBuffer
.append( sal_Unicode(0x20) );
354 if( aBuffer
[ aBuffer
.getLength() - 1 ] == sal_Unicode( 0x20 ) )
355 aBuffer
.setLength( aBuffer
.getLength() - 1 );
356 return aBuffer
.makeStringAndClear();
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */