summaryrefslogtreecommitdiffstats
path: root/forms/source/xforms/convert.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'forms/source/xforms/convert.cxx')
-rw-r--r--forms/source/xforms/convert.cxx346
1 files changed, 346 insertions, 0 deletions
diff --git a/forms/source/xforms/convert.cxx b/forms/source/xforms/convert.cxx
new file mode 100644
index 000000000..55398f8a2
--- /dev/null
+++ b/forms/source/xforms/convert.cxx
@@ -0,0 +1,346 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "convert.hxx"
+
+#include <sstream>
+#include <o3tl/functional.hxx>
+#include <rtl/math.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <tools/date.hxx>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <comphelper/sequence.hxx>
+#include <unotools/datetime.hxx>
+
+using xforms::Convert;
+using com::sun::star::uno::Any;
+using com::sun::star::uno::makeAny;
+using namespace std;
+using namespace o3tl;
+using namespace utl;
+
+Convert::Convert()
+ : maMap()
+{
+ init();
+}
+
+#define ADD_ENTRY(XCONVERT,TYPE) XCONVERT->maMap[ cppu::UnoType<TYPE>::get() ] = Convert_t( &lcl_toXSD_##TYPE, &lcl_toAny_##TYPE )
+
+namespace
+{
+
+ OUString lcl_toXSD_OUString( const Any& rAny )
+ { OUString sStr; rAny >>= sStr; return sStr; }
+
+
+ Any lcl_toAny_OUString( const OUString& rStr )
+ { return Any(rStr); }
+
+
+ OUString lcl_toXSD_bool( const Any& rAny )
+ { bool b = false; rAny >>= b; return b ? OUString("true") : OUString("false"); }
+
+
+ Any lcl_toAny_bool( const OUString& rStr )
+ {
+ bool b = ( rStr == "true" || rStr == "1" );
+ return makeAny( b );
+ }
+
+
+ OUString lcl_toXSD_double( const Any& rAny )
+ {
+ double f = 0.0;
+ rAny >>= f;
+
+ return std::isfinite( f )
+ ? rtl::math::doubleToUString( f, rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, '.',
+ true )
+ : OUString();
+ }
+
+
+ Any lcl_toAny_double( const OUString& rString )
+ {
+ rtl_math_ConversionStatus eStatus;
+ double f = rtl::math::stringToDouble(
+ rString, '.', ',', &eStatus );
+ return ( eStatus == rtl_math_ConversionStatus_Ok ) ? makeAny( f ) : Any();
+ }
+
+
+ void lcl_appendInt32ToBuffer( const sal_Int32 _nValue, OUStringBuffer& _rBuffer, sal_Int16 _nMinDigits )
+ {
+ if ( ( _nMinDigits >= 4 ) && ( _nValue < 1000 ) )
+ _rBuffer.append( '0' );
+ if ( ( _nMinDigits >= 3 ) && ( _nValue < 100 ) )
+ _rBuffer.append( '0' );
+ if ( ( _nMinDigits >= 2 ) && ( _nValue < 10 ) )
+ _rBuffer.append( '0' );
+ _rBuffer.append( _nValue );
+ }
+
+
+ OUString lcl_toXSD_UNODate_typed( const css::util::Date& rDate )
+ {
+
+ OUStringBuffer sInfo;
+ lcl_appendInt32ToBuffer( rDate.Year, sInfo, 4 );
+ sInfo.append( "-" );
+ lcl_appendInt32ToBuffer( rDate.Month, sInfo, 2 );
+ sInfo.append( "-" );
+ lcl_appendInt32ToBuffer( rDate.Day, sInfo, 2 );
+
+ return sInfo.makeStringAndClear();
+ }
+
+
+ OUString lcl_toXSD_UNODate( const Any& rAny )
+ {
+ css::util::Date aDate;
+ OSL_VERIFY( rAny >>= aDate );
+ return lcl_toXSD_UNODate_typed( aDate );
+ }
+
+
+ css::util::Date lcl_toUNODate( const OUString& rString )
+ {
+ css::util::Date aDate( 1, 1, 1900 );
+
+ bool bWellformed = ISO8601parseDate(rString, aDate);
+
+ // sanity checks
+ if ( ( aDate.Year > 9999 ) || ( aDate.Month < 1 ) || ( aDate.Month > 12 ) || ( aDate.Day < 1 ) || ( aDate.Day > 31 ) )
+ bWellformed = false;
+ else
+ {
+ ::Date aDateCheck( 1, aDate.Month, aDate.Year );
+ if ( aDate.Day > aDateCheck.GetDaysInMonth() )
+ bWellformed = false;
+ }
+
+ // all okay?
+ if ( !bWellformed )
+ return css::util::Date( 1, 1, 1900 );
+
+ return aDate;
+ }
+
+
+ Any lcl_toAny_UNODate( const OUString& rString )
+ {
+ return makeAny( lcl_toUNODate( rString ) );
+ }
+
+
+ OUString lcl_toXSD_UNOTime_typed( const css::util::Time& rTime )
+ {
+
+ OUStringBuffer sInfo;
+ lcl_appendInt32ToBuffer( rTime.Hours, sInfo, 2 );
+ sInfo.append( ":" );
+ lcl_appendInt32ToBuffer( rTime.Minutes, sInfo, 2 );
+ sInfo.append( ":" );
+ lcl_appendInt32ToBuffer( rTime.Seconds, sInfo, 2 );
+ if ( rTime.NanoSeconds != 0 )
+ {
+ OSL_ENSURE(rTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999");
+ sInfo.append('.');
+ std::ostringstream ostr;
+ ostr.fill('0');
+ ostr.width(9);
+ ostr << rTime.NanoSeconds;
+ sInfo.append(OUString::createFromAscii(ostr.str().c_str()));
+ }
+
+ return sInfo.makeStringAndClear();
+ }
+
+
+ OUString lcl_toXSD_UNOTime( const Any& rAny )
+ {
+ css::util::Time aTime;
+ OSL_VERIFY( rAny >>= aTime );
+ return lcl_toXSD_UNOTime_typed( aTime );
+ }
+
+
+ css::util::Time lcl_toUNOTime( const OUString& rString )
+ {
+ css::util::Time aTime;
+
+ bool bWellformed = ISO8601parseTime(rString, aTime);
+
+ // sanity checks
+ // note that Seconds == 60 denotes leap seconds. Normally, they're not allowed everywhere,
+ // but we accept them all the time for simplicity reasons
+ if ( ( aTime.Hours > 24 )
+ || ( aTime.Minutes > 59 )
+ || ( aTime.Seconds > 60 )
+ )
+ bWellformed = false;
+
+ if ( bWellformed
+ && ( aTime.Hours == 24 )
+ && ( ( aTime.Minutes != 0 )
+ || ( aTime.Seconds != 0 )
+ || ( aTime.NanoSeconds != 0 )
+ )
+ )
+ bWellformed = false;
+
+ // all okay?
+ if ( !bWellformed )
+ return css::util::Time();
+
+ return aTime;
+ }
+
+
+ Any lcl_toAny_UNOTime( const OUString& rString )
+ {
+ return makeAny( lcl_toUNOTime( rString ) );
+ }
+
+
+ OUString lcl_toXSD_UNODateTime( const Any& rAny )
+ {
+ css::util::DateTime aDateTime;
+ OSL_VERIFY( rAny >>= aDateTime );
+
+ css::util::Date aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year );
+ OUString sDate = lcl_toXSD_UNODate_typed( aDate );
+
+ css::util::Time const aTime( aDateTime.NanoSeconds, aDateTime.Seconds,
+ aDateTime.Minutes, aDateTime.Hours, aDateTime.IsUTC);
+ OUString sTime = lcl_toXSD_UNOTime_typed( aTime );
+
+ OUString sRet = sDate + "T" + sTime;
+ return sRet;
+ }
+
+
+ Any lcl_toAny_UNODateTime( const OUString& rString )
+ {
+ // separate the date from the time part
+ sal_Int32 nDateTimeSep = rString.indexOf( 'T' );
+ if ( nDateTimeSep == -1 )
+ nDateTimeSep = rString.indexOf( 't' );
+
+ css::util::Date aDate;
+ css::util::Time aTime;
+ if ( nDateTimeSep == -1 )
+ { // no time part
+ aDate = lcl_toUNODate( rString );
+ }
+ else
+ {
+ aDate = lcl_toUNODate( rString.copy( 0, nDateTimeSep ) );
+ aTime = lcl_toUNOTime( rString.copy( nDateTimeSep + 1 ) );
+ }
+ css::util::DateTime aDateTime(
+ aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
+ aDate.Day, aDate.Month, aDate.Year, aTime.IsUTC
+ );
+ return makeAny( aDateTime );
+ }
+}
+
+
+void Convert::init()
+{
+ ADD_ENTRY( this, OUString );
+ ADD_ENTRY( this, bool );
+ ADD_ENTRY( this, double );
+ maMap[ cppu::UnoType<css::util::Date>::get() ] = Convert_t( &lcl_toXSD_UNODate, &lcl_toAny_UNODate );
+ maMap[ cppu::UnoType<css::util::Time>::get() ] = Convert_t( &lcl_toXSD_UNOTime, &lcl_toAny_UNOTime );
+ maMap[ cppu::UnoType<css::util::DateTime>::get() ] = Convert_t( &lcl_toXSD_UNODateTime, &lcl_toAny_UNODateTime );
+}
+
+
+Convert& Convert::get()
+{
+ // create our Singleton instance on demand
+ static Convert aConvert;
+ return aConvert;
+}
+
+bool Convert::hasType( const css::uno::Type& rType )
+{
+ return maMap.find( rType ) != maMap.end();
+}
+
+css::uno::Sequence<css::uno::Type> Convert::getTypes() const
+{
+ return comphelper::mapKeysToSequence( maMap );
+}
+
+OUString Convert::toXSD( const css::uno::Any& rAny )
+{
+ Map_t::iterator aIter = maMap.find( rAny.getValueType() );
+ return aIter != maMap.end() ? aIter->second.first( rAny ) : OUString();
+}
+
+css::uno::Any Convert::toAny( const OUString& rValue,
+ const css::uno::Type& rType )
+{
+ Map_t::iterator aIter = maMap.find( rType );
+ return aIter != maMap.end() ? aIter->second.second( rValue ) : css::uno::Any();
+}
+
+
+OUString Convert::collapseWhitespace( const OUString& _rString )
+{
+ sal_Int32 nLength = _rString.getLength();
+ OUStringBuffer aBuffer( nLength );
+ const sal_Unicode* pStr = _rString.getStr();
+ bool bStrip = true;
+ for( sal_Int32 i = 0; i < nLength; i++ )
+ {
+ sal_Unicode c = pStr[i];
+ if( c == u'\x0008' ||
+ c == u'\x000A' ||
+ c == u'\x000D' ||
+ c == u' ' )
+ {
+ if( ! bStrip )
+ {
+ aBuffer.append( u' ' );
+ bStrip = true;
+ }
+ }
+ else
+ {
+ bStrip = false;
+ aBuffer.append( c );
+ }
+ }
+ if( aBuffer[ aBuffer.getLength() - 1 ] == u' ' )
+ aBuffer.setLength( aBuffer.getLength() - 1 );
+ return aBuffer.makeStringAndClear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */