diff options
Diffstat (limited to 'forms/source/xforms/convert.cxx')
-rw-r--r-- | forms/source/xforms/convert.cxx | 346 |
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: */ |