/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include 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::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::get() ] = Convert_t( &lcl_toXSD_UNODate, &lcl_toAny_UNODate ); maMap[ cppu::UnoType::get() ] = Convert_t( &lcl_toXSD_UNOTime, &lcl_toAny_UNOTime ); maMap[ cppu::UnoType::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 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: */