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
;
48 OUString
lcl_toXSD_OUString( const Any
& rAny
)
49 { OUString sStr
; rAny
>>= sStr
; return sStr
; }
52 Any
lcl_toAny_OUString( const OUString
& rStr
)
55 void lcl_appendInt32ToBuffer( const sal_Int32 _nValue
, OUStringBuffer
& _rBuffer
, sal_Int16 _nMinDigits
)
57 if ( ( _nMinDigits
>= 4 ) && ( _nValue
< 1000 ) )
58 _rBuffer
.append( '0' );
59 if ( ( _nMinDigits
>= 3 ) && ( _nValue
< 100 ) )
60 _rBuffer
.append( '0' );
61 if ( ( _nMinDigits
>= 2 ) && ( _nValue
< 10 ) )
62 _rBuffer
.append( '0' );
63 _rBuffer
.append( _nValue
);
67 OUString
lcl_toXSD_UNODate_typed( const css::util::Date
& rDate
)
71 lcl_appendInt32ToBuffer( rDate
.Year
, sInfo
, 4 );
73 lcl_appendInt32ToBuffer( rDate
.Month
, sInfo
, 2 );
75 lcl_appendInt32ToBuffer( rDate
.Day
, sInfo
, 2 );
77 return sInfo
.makeStringAndClear();
81 OUString
lcl_toXSD_UNODate( const Any
& rAny
)
83 css::util::Date aDate
;
84 OSL_VERIFY( rAny
>>= aDate
);
85 return lcl_toXSD_UNODate_typed( aDate
);
89 css::util::Date
lcl_toUNODate( const OUString
& rString
)
91 css::util::Date
aDate( 1, 1, 1900 );
93 bool bWellformed
= ISO8601parseDate(rString
, aDate
);
96 if ( ( aDate
.Year
> 9999 ) || ( aDate
.Month
< 1 ) || ( aDate
.Month
> 12 ) || ( aDate
.Day
< 1 ) || ( aDate
.Day
> 31 ) )
100 ::Date
aDateCheck( 1, aDate
.Month
, aDate
.Year
);
101 if ( aDate
.Day
> aDateCheck
.GetDaysInMonth() )
107 return css::util::Date( 1, 1, 1900 );
113 Any
lcl_toAny_UNODate( const OUString
& rString
)
115 return makeAny( lcl_toUNODate( rString
) );
119 OUString
lcl_toXSD_UNOTime_typed( const css::util::Time
& rTime
)
122 OUStringBuffer sInfo
;
123 lcl_appendInt32ToBuffer( rTime
.Hours
, sInfo
, 2 );
125 lcl_appendInt32ToBuffer( rTime
.Minutes
, sInfo
, 2 );
127 lcl_appendInt32ToBuffer( rTime
.Seconds
, sInfo
, 2 );
128 if ( rTime
.NanoSeconds
!= 0 )
130 OSL_ENSURE(rTime
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
132 std::ostringstream ostr
;
135 ostr
<< rTime
.NanoSeconds
;
136 sInfo
.append(OUString::createFromAscii(ostr
.str().c_str()));
139 return sInfo
.makeStringAndClear();
143 OUString
lcl_toXSD_UNOTime( const Any
& rAny
)
145 css::util::Time aTime
;
146 OSL_VERIFY( rAny
>>= aTime
);
147 return lcl_toXSD_UNOTime_typed( aTime
);
151 css::util::Time
lcl_toUNOTime( const OUString
& rString
)
153 css::util::Time aTime
;
155 bool bWellformed
= ISO8601parseTime(rString
, aTime
);
158 // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere,
159 // but we accept them all the time for simplicity reasons
160 if ( ( aTime
.Hours
> 24 )
161 || ( aTime
.Minutes
> 59 )
162 || ( aTime
.Seconds
> 60 )
167 && ( aTime
.Hours
== 24 )
168 && ( ( aTime
.Minutes
!= 0 )
169 || ( aTime
.Seconds
!= 0 )
170 || ( aTime
.NanoSeconds
!= 0 )
177 return css::util::Time();
183 Any
lcl_toAny_UNOTime( const OUString
& rString
)
185 return makeAny( lcl_toUNOTime( rString
) );
189 OUString
lcl_toXSD_UNODateTime( const Any
& rAny
)
191 css::util::DateTime aDateTime
;
192 OSL_VERIFY( rAny
>>= aDateTime
);
194 css::util::Date
aDate( aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
195 OUString sDate
= lcl_toXSD_UNODate_typed( aDate
);
197 css::util::Time
const aTime( aDateTime
.NanoSeconds
, aDateTime
.Seconds
,
198 aDateTime
.Minutes
, aDateTime
.Hours
, aDateTime
.IsUTC
);
199 OUString sTime
= lcl_toXSD_UNOTime_typed( aTime
);
201 OUString sRet
= sDate
+ "T" + sTime
;
206 Any
lcl_toAny_UNODateTime( const OUString
& rString
)
208 // separate the date from the time part
209 sal_Int32 nDateTimeSep
= rString
.indexOf( 'T' );
210 if ( nDateTimeSep
== -1 )
211 nDateTimeSep
= rString
.indexOf( 't' );
213 css::util::Date aDate
;
214 css::util::Time aTime
;
215 if ( nDateTimeSep
== -1 )
217 aDate
= lcl_toUNODate( rString
);
221 aDate
= lcl_toUNODate( rString
.copy( 0, nDateTimeSep
) );
222 aTime
= lcl_toUNOTime( rString
.copy( nDateTimeSep
+ 1 ) );
224 css::util::DateTime
aDateTime(
225 aTime
.NanoSeconds
, aTime
.Seconds
, aTime
.Minutes
, aTime
.Hours
,
226 aDate
.Day
, aDate
.Month
, aDate
.Year
, aTime
.IsUTC
228 return makeAny( aDateTime
);
235 maMap
[ cppu::UnoType
<OUString
>::get() ] = Convert_t(&lcl_toXSD_OUString
, &lcl_toAny_OUString
);
236 maMap
[ cppu::UnoType
<css::util::Date
>::get() ] = Convert_t( &lcl_toXSD_UNODate
, &lcl_toAny_UNODate
);
237 maMap
[ cppu::UnoType
<css::util::Time
>::get() ] = Convert_t( &lcl_toXSD_UNOTime
, &lcl_toAny_UNOTime
);
238 maMap
[ cppu::UnoType
<css::util::DateTime
>::get() ] = Convert_t( &lcl_toXSD_UNODateTime
, &lcl_toAny_UNODateTime
);
242 Convert
& Convert::get()
244 // create our Singleton instance on demand
245 static Convert aConvert
;
249 bool Convert::hasType( const css::uno::Type
& rType
)
251 return maMap
.find( rType
) != maMap
.end();
254 css::uno::Sequence
<css::uno::Type
> Convert::getTypes() const
256 return comphelper::mapKeysToSequence( maMap
);
259 OUString
Convert::toXSD( const css::uno::Any
& rAny
)
261 Map_t::iterator aIter
= maMap
.find( rAny
.getValueType() );
262 return aIter
!= maMap
.end() ? aIter
->second
.first( rAny
) : OUString();
265 css::uno::Any
Convert::toAny( const OUString
& rValue
,
266 const css::uno::Type
& rType
)
268 Map_t::iterator aIter
= maMap
.find( rType
);
269 return aIter
!= maMap
.end() ? aIter
->second
.second( rValue
) : css::uno::Any();
273 OUString
Convert::collapseWhitespace( const OUString
& _rString
)
275 sal_Int32 nLength
= _rString
.getLength();
276 OUStringBuffer
aBuffer( nLength
);
277 const sal_Unicode
* pStr
= _rString
.getStr();
279 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
281 sal_Unicode c
= pStr
[i
];
282 if( c
== u
'\x0008' ||
289 aBuffer
.append( u
' ' );
299 if( aBuffer
[ aBuffer
.getLength() - 1 ] == u
' ' )
300 aBuffer
.setLength( aBuffer
.getLength() - 1 );
301 return aBuffer
.makeStringAndClear();
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */