LibreOffice Module forms (master) 1
convert.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include "convert.hxx"
22
23#include <sstream>
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>
34#include <unotools/datetime.hxx>
35
36using xforms::Convert;
37using com::sun::star::uno::Any;
38using namespace utl;
39
40Convert::Convert()
41{
42 init();
43}
44
45namespace
46{
47
48 OUString lcl_toXSD_OUString( const Any& rAny )
49 { OUString sStr; rAny >>= sStr; return sStr; }
50
51
52 Any lcl_toAny_OUString( const OUString& rStr )
53 { return Any(rStr); }
54
55 OUString lcl_toXSD_bool( const Any& rAny )
56 { bool b = false; rAny >>= b; return b ? OUString("true") : OUString("false"); }
57
58 Any lcl_toAny_bool( const OUString& rStr )
59 {
60 bool b = ( rStr == "true" || rStr == "1" );
61 return Any( b );
62 }
63
64 OUString lcl_toXSD_double( const Any& rAny )
65 {
66 double f = 0.0;
67 rAny >>= f;
68
69 return std::isfinite( f )
70 ? rtl::math::doubleToUString( f, rtl_math_StringFormat_Automatic,
71 rtl_math_DecimalPlaces_Max, '.',
72 true )
73 : OUString();
74 }
75
76
77 Any lcl_toAny_double( const OUString& rString )
78 {
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();
83 }
84
85 void lcl_appendInt32ToBuffer( const sal_Int32 _nValue, OUStringBuffer& _rBuffer, sal_Int16 _nMinDigits )
86 {
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 );
94 }
95
96
97 OUString lcl_toXSD_UNODate_typed( const css::util::Date& rDate )
98 {
99
100 OUStringBuffer sInfo;
101 lcl_appendInt32ToBuffer( rDate.Year, sInfo, 4 );
102 sInfo.append( "-" );
103 lcl_appendInt32ToBuffer( rDate.Month, sInfo, 2 );
104 sInfo.append( "-" );
105 lcl_appendInt32ToBuffer( rDate.Day, sInfo, 2 );
106
107 return sInfo.makeStringAndClear();
108 }
109
110
111 OUString lcl_toXSD_UNODate( const Any& rAny )
112 {
113 css::util::Date aDate;
114 OSL_VERIFY( rAny >>= aDate );
115 return lcl_toXSD_UNODate_typed( aDate );
116 }
117
118
119 css::util::Date lcl_toUNODate( std::u16string_view rString )
120 {
121 css::util::Date aDate( 1, 1, 1900 );
122
123 bool bWellformed = ISO8601parseDate(rString, aDate);
124
125 // sanity checks
126 if ( ( aDate.Year > 9999 ) || ( aDate.Month < 1 ) || ( aDate.Month > 12 ) || ( aDate.Day < 1 ) || ( aDate.Day > 31 ) )
127 bWellformed = false;
128 else
129 {
130 ::Date aDateCheck( 1, aDate.Month, aDate.Year );
131 if ( aDate.Day > aDateCheck.GetDaysInMonth() )
132 bWellformed = false;
133 }
134
135 // all okay?
136 if ( !bWellformed )
137 throw com::sun::star::lang::IllegalArgumentException();
138
139 return aDate;
140 }
141
142
143 Any lcl_toAny_UNODate( const OUString& rString )
144 {
145 return Any( lcl_toUNODate( rString ) );
146 }
147
148
149 OUString lcl_toXSD_UNOTime_typed( const css::util::Time& rTime )
150 {
151
152 OUStringBuffer sInfo;
153 lcl_appendInt32ToBuffer( rTime.Hours, sInfo, 2 );
154 sInfo.append( ":" );
155 lcl_appendInt32ToBuffer( rTime.Minutes, sInfo, 2 );
156 sInfo.append( ":" );
157 lcl_appendInt32ToBuffer( rTime.Seconds, sInfo, 2 );
158 if ( rTime.NanoSeconds != 0 )
159 {
160 OSL_ENSURE(rTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999");
161 sInfo.append('.');
162 std::ostringstream ostr;
163 ostr.fill('0');
164 ostr.width(9);
165 ostr << rTime.NanoSeconds;
166 sInfo.appendAscii(ostr.str().c_str());
167 }
168
169 return sInfo.makeStringAndClear();
170 }
171
172
173 OUString lcl_toXSD_UNOTime( const Any& rAny )
174 {
175 css::util::Time aTime;
176 OSL_VERIFY( rAny >>= aTime );
177 return lcl_toXSD_UNOTime_typed( aTime );
178 }
179
180
181 css::util::Time lcl_toUNOTime( std::u16string_view rString )
182 {
183 css::util::Time aTime;
184
185 bool bWellformed = ISO8601parseTime(rString, aTime);
186
187 // sanity checks
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 )
193 )
194 bWellformed = false;
195
196 if ( bWellformed
197 && ( aTime.Hours == 24 )
198 && ( ( aTime.Minutes != 0 )
199 || ( aTime.Seconds != 0 )
200 || ( aTime.NanoSeconds != 0 )
201 )
202 )
203 bWellformed = false;
204
205 // all okay?
206 if ( !bWellformed )
207 throw com::sun::star::lang::IllegalArgumentException();
208
209 return aTime;
210 }
211
212
213 Any lcl_toAny_UNOTime( const OUString& rString )
214 {
215 return Any( lcl_toUNOTime( rString ) );
216 }
217
218
219 OUString lcl_toXSD_UNODateTime( const Any& rAny )
220 {
221 css::util::DateTime aDateTime;
222 OSL_VERIFY( rAny >>= aDateTime );
223
224 css::util::Date aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year );
225 OUString sDate = lcl_toXSD_UNODate_typed( aDate );
226
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 );
230
231 OUString sRet = sDate + "T" + sTime;
232 return sRet;
233 }
234
235
236 Any lcl_toAny_UNODateTime( const OUString& rString )
237 {
238 // separate the date from the time part
239 sal_Int32 nDateTimeSep = rString.indexOf( 'T' );
240 if ( nDateTimeSep == -1 )
241 nDateTimeSep = rString.indexOf( 't' );
242
243 css::util::Date aDate;
244 css::util::Time aTime;
245 if ( nDateTimeSep == -1 )
246 { // no time part
247 aDate = lcl_toUNODate( rString );
248 }
249 else
250 {
251 aDate = lcl_toUNODate( rString.subView( 0, nDateTimeSep ) );
252 aTime = lcl_toUNOTime( rString.subView( nDateTimeSep + 1 ) );
253 }
254 css::util::DateTime aDateTime(
255 aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
256 aDate.Day, aDate.Month, aDate.Year, aTime.IsUTC
257 );
258 return Any( aDateTime );
259 }
260}
261
262
264{
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 );
271}
272
273
275{
276 // create our Singleton instance on demand
277 static Convert aConvert;
278 return aConvert;
279}
280
281bool Convert::hasType( const css::uno::Type& rType )
282{
283 return maMap.find( rType ) != maMap.end();
284}
285
286css::uno::Sequence<css::uno::Type> Convert::getTypes() const
287{
289}
290
291OUString Convert::toXSD( const css::uno::Any& rAny )
292{
293 Map_t::iterator aIter = maMap.find( rAny.getValueType() );
294 return aIter != maMap.end() ? aIter->second.first( rAny ) : OUString();
295}
296
297css::uno::Any Convert::toAny( const OUString& rValue,
298 const css::uno::Type& rType )
299{
300 Map_t::iterator aIter = maMap.find( rType );
301 return aIter != maMap.end() ? aIter->second.second( rValue ) : css::uno::Any();
302}
303
304
305OUString Convert::collapseWhitespace( const OUString& _rString )
306{
307 sal_Int32 nLength = _rString.getLength();
308 OUStringBuffer aBuffer( nLength );
309 const sal_Unicode* pStr = _rString.getStr();
310 bool bStrip = true;
311 for( sal_Int32 i = 0; i < nLength; i++ )
312 {
313 sal_Unicode c = pStr[i];
314 if( c == u'\x0008' ||
315 c == u'\x000A' ||
316 c == u'\x000D' ||
317 c == u' ' )
318 {
319 if( ! bStrip )
320 {
321 aBuffer.append( u' ' );
322 bStrip = true;
323 }
324 }
325 else
326 {
327 bStrip = false;
328 aBuffer.append( c );
329 }
330 }
331 if( aBuffer[ aBuffer.getLength() - 1 ] == u' ' )
332 aBuffer.setLength( aBuffer.getLength() - 1 );
333 return aBuffer.makeStringAndClear();
334}
335
336/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Type const & get()
css::uno::Sequence< css::uno::Type > getTypes() const
get list of convertible types
Definition: convert.cxx:286
static OUString collapseWhitespace(const OUString &_rString)
replace all sequences of 0x08, 0x0A, 0x0D, 0x20 with a single 0x20.
Definition: convert.cxx:305
std::pair< fn_toXSD, fn_toAny > Convert_t
Definition: convert.hxx:46
bool hasType(const css::uno::Type &)
can we convert this type?
Definition: convert.cxx:281
static Convert & get()
get/create Singleton class
Definition: convert.cxx:274
css::uno::Any toAny(const OUString &, const css::uno::Type &)
convert XML representation to Any of given type
Definition: convert.cxx:297
OUString toXSD(const css::uno::Any &rAny)
convert any to XML representation
Definition: convert.cxx:291
float u
css::uno::Sequence< typename M::key_type > mapKeysToSequence(M const &map)
int i
bool ISO8601parseDate(std::u16string_view aDateStr, css::util::Date &rDate)
bool ISO8601parseTime(std::u16string_view aTimeStr, css::util::Time &rTime)
sal_uInt16 sal_Unicode
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength