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 #include "datefunc.hxx" 21 #include <datefunc.hrc> 22 #include <strings.hrc> 23 #include <com/sun/star/util/Date.hpp> 24 #include <cppuhelper/factory.hxx> 25 #include <cppuhelper/supportsservice.hxx> 26 #include <cppuhelper/weak.hxx> 27 #include <rtl/ustrbuf.hxx> 28 #include <unotools/resmgr.hxx> 29 #include <i18nlangtag/languagetag.hxx> 30 #include <algorithm> 31 #include <cmath> 32 #include "deffuncname.hxx" 33 34 using namespace ::com::sun::star; 35 36 constexpr OUStringLiteral ADDIN_SERVICE = u"com.sun.star.sheet.AddIn"; 37 constexpr OUStringLiteral MY_SERVICE = u"com.sun.star.sheet.addin.DateFunctions"; 38 constexpr OUStringLiteral MY_IMPLNAME = u"com.sun.star.sheet.addin.DateFunctionsImpl"; 39 40 #define UNIQUE false // function name does not exist in Calc 41 42 #define STDPAR false // all parameters are described 43 #define INTPAR true // first parameter is internal 44 45 #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \ 46 { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar } 47 48 const ScaFuncDataBase pFuncDataArr[] = 49 { 50 FUNCDATA( DiffWeeks, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), 51 FUNCDATA( DiffMonths, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), 52 FUNCDATA( DiffYears, 3, ScaCategory::DateTime, UNIQUE, INTPAR ), 53 FUNCDATA( IsLeapYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), 54 FUNCDATA( DaysInMonth, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), 55 FUNCDATA( DaysInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), 56 FUNCDATA( WeeksInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ), 57 FUNCDATA( Rot13, 1, ScaCategory::Text, UNIQUE, STDPAR ) 58 }; 59 60 #undef FUNCDATA 61 62 ScaFuncData::ScaFuncData(const ScaFuncDataBase& rBaseData) : 63 aIntName( OUString::createFromAscii( rBaseData.pIntName ) ), 64 pUINameID( rBaseData.pUINameID ), 65 pDescrID( rBaseData.pDescrID ), 66 nParamCount( rBaseData.nParamCount ), 67 eCat( rBaseData.eCat ), 68 bDouble( rBaseData.bDouble ), 69 bWithOpt( rBaseData.bWithOpt ) 70 { 71 aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[0])); 72 aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[1])); 73 } 74 75 sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const 76 { 77 if( !bWithOpt ) 78 nParam++; 79 return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2); 80 } 81 82 static void InitScaFuncDataList(ScaFuncDataList& rList) 83 { 84 for (const auto & nIndex : pFuncDataArr) 85 rList.push_back(ScaFuncData(nIndex)); 86 } 87 88 // entry points for service registration / instantiation 89 90 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* 91 scaddins_ScaDateAddIn_get_implementation( 92 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) 93 { 94 return cppu::acquire(new ScaDateAddIn()); 95 } 96 97 98 // "normal" service implementation 99 ScaDateAddIn::ScaDateAddIn() 100 { 101 } 102 103 static const char* pLang[] = { "de", "en" }; 104 static const char* pCoun[] = { "DE", "US" }; 105 const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang ); 106 107 void ScaDateAddIn::InitDefLocales() 108 { 109 pDefLocales.reset(new lang::Locale[ nNumOfLoc ]); 110 111 for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ ) 112 { 113 pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] ); 114 pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] ); 115 } 116 } 117 118 const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex ) 119 { 120 if( !pDefLocales ) 121 InitDefLocales(); 122 123 return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc; 124 } 125 126 void ScaDateAddIn::InitData() 127 { 128 aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc)); 129 pFuncDataList.reset(); 130 131 pFuncDataList.reset(new ScaFuncDataList); 132 InitScaFuncDataList(*pFuncDataList); 133 134 if( pDefLocales ) 135 { 136 pDefLocales.reset(); 137 } 138 } 139 140 OUString ScaDateAddIn::GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex) 141 { 142 return ScaResId(pResId[nStrIndex - 1]); 143 } 144 145 // XServiceName 146 OUString SAL_CALL ScaDateAddIn::getServiceName() 147 { 148 // name of specific AddIn service 149 return MY_SERVICE; 150 } 151 152 // XServiceInfo 153 OUString SAL_CALL ScaDateAddIn::getImplementationName() 154 { 155 return MY_IMPLNAME; 156 } 157 158 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) 159 { 160 return cppu::supportsService(this, aServiceName); 161 } 162 163 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() 164 { 165 return { ADDIN_SERVICE, MY_SERVICE }; 166 } 167 168 // XLocalizable 169 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) 170 { 171 aFuncLoc = eLocale; 172 InitData(); // change of locale invalidates resources! 173 } 174 175 lang::Locale SAL_CALL ScaDateAddIn::getLocale() 176 { 177 return aFuncLoc; 178 } 179 180 OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) 181 { 182 // not used by calc 183 // (but should be implemented for other uses of the AddIn service) 184 return OUString(); 185 } 186 187 OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) 188 { 189 OUString aRet; 190 191 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 192 FindScaFuncData( aProgrammaticName ) ); 193 if( fDataIt != pFuncDataList->end() ) 194 { 195 aRet = ScaResId(fDataIt->GetUINameID()); 196 if( fDataIt->IsDouble() ) 197 aRet += "_ADD"; 198 } 199 else 200 { 201 aRet = "UNKNOWNFUNC_" + aProgrammaticName; 202 } 203 204 return aRet; 205 } 206 207 OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) 208 { 209 OUString aRet; 210 211 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 212 FindScaFuncData( aProgrammaticName ) ); 213 if( fDataIt != pFuncDataList->end() ) 214 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 ); 215 216 return aRet; 217 } 218 219 OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName( 220 const OUString& aProgrammaticName, sal_Int32 nArgument ) 221 { 222 OUString aRet; 223 224 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 225 FindScaFuncData( aProgrammaticName ) ); 226 if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) ) 227 { 228 sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); 229 if( nStr ) 230 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr ); 231 else 232 aRet = "internal"; 233 } 234 235 return aRet; 236 } 237 238 OUString SAL_CALL ScaDateAddIn::getArgumentDescription( 239 const OUString& aProgrammaticName, sal_Int32 nArgument ) 240 { 241 OUString aRet; 242 243 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 244 FindScaFuncData( aProgrammaticName ) ); 245 if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) ) 246 { 247 sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); 248 if( nStr ) 249 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 ); 250 else 251 aRet = "for internal use only"; 252 } 253 254 return aRet; 255 } 256 257 OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName( 258 const OUString& aProgrammaticName ) 259 { 260 OUString aRet; 261 262 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 263 FindScaFuncData( aProgrammaticName ) ); 264 if( fDataIt != pFuncDataList->end() ) 265 { 266 switch( fDataIt->GetCategory() ) 267 { 268 case ScaCategory::DateTime: aRet = "Date&Time"; break; 269 case ScaCategory::Text: aRet = "Text"; break; 270 case ScaCategory::Finance: aRet = "Financial"; break; 271 case ScaCategory::Inf: aRet = "Information"; break; 272 case ScaCategory::Math: aRet = "Mathematical"; break; 273 case ScaCategory::Tech: aRet = "Technical"; break; 274 } 275 } 276 277 if( aRet.isEmpty() ) 278 aRet = "Add-In"; 279 return aRet; 280 } 281 282 OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName( 283 const OUString& aProgrammaticName ) 284 { 285 return getProgrammaticCategoryName( aProgrammaticName ); 286 } 287 288 // XCompatibilityNames 289 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames( 290 const OUString& aProgrammaticName ) 291 { 292 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(), 293 FindScaFuncData( aProgrammaticName ) ); 294 if( fDataIt == pFuncDataList->end() ) 295 return uno::Sequence< sheet::LocalizedName >( 0 ); 296 297 const std::vector<OUString>& rStrList = fDataIt->GetCompNameList(); 298 sal_uInt32 nCount = rStrList.size(); 299 300 uno::Sequence< sheet::LocalizedName > aRet( nCount ); 301 sheet::LocalizedName* pArray = aRet.getArray(); 302 303 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ ) 304 pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList.at( nIndex ) ); 305 306 return aRet; 307 } 308 309 namespace { 310 311 // auxiliary functions 312 bool IsLeapYear( sal_uInt16 nYear ) 313 { 314 return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0)); 315 } 316 317 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear ) 318 { 319 static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, 320 31, 31, 30, 31, 30, 31 }; 321 322 if ( nMonth != 2 ) 323 return aDaysInMonth[nMonth-1]; 324 else 325 { 326 if ( IsLeapYear(nYear) ) 327 return aDaysInMonth[nMonth-1] + 1; 328 else 329 return aDaysInMonth[nMonth-1]; 330 } 331 } 332 333 /** 334 * Convert a date to a count of days starting from 01/01/0001 335 * 336 * The internal representation of a Date used in this Addin 337 * is the number of days between 01/01/0001 and the date 338 * this function converts a Day , Month, Year representation 339 * to this internal Date value. 340 */ 341 342 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) 343 { 344 sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365; 345 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400); 346 347 for( sal_uInt16 i = 1; i < nMonth; i++ ) 348 nDays += DaysInMonth(i,nYear); 349 nDays += nDay; 350 351 return nDays; 352 } 353 354 /** 355 * Convert a count of days starting from 01/01/0001 to a date 356 * 357 * The internal representation of a Date used in this Addin 358 * is the number of days between 01/01/0001 and the date 359 * this function converts this internal Date value 360 * to a Day , Month, Year representation of a Date. 361 * 362 * @throws lang::IllegalArgumentException 363 */ 364 365 void DaysToDate( sal_Int32 nDays, 366 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear ) 367 { 368 if( nDays < 0 ) 369 throw lang::IllegalArgumentException(); 370 371 sal_Int32 nTempDays; 372 sal_Int32 i = 0; 373 bool bCalc; 374 375 do 376 { 377 nTempDays = nDays; 378 rYear = static_cast<sal_uInt16>((nTempDays / 365) - i); 379 nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365; 380 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400); 381 bCalc = false; 382 if ( nTempDays < 1 ) 383 { 384 i++; 385 bCalc = true; 386 } 387 else 388 { 389 if ( nTempDays > 365 ) 390 { 391 if ( (nTempDays != 366) || !IsLeapYear( rYear ) ) 392 { 393 i--; 394 bCalc = true; 395 } 396 } 397 } 398 } 399 while ( bCalc ); 400 401 rMonth = 1; 402 while ( nTempDays > DaysInMonth( rMonth, rYear ) ) 403 { 404 nTempDays -= DaysInMonth( rMonth, rYear ); 405 rMonth++; 406 } 407 rDay = static_cast<sal_uInt16>(nTempDays); 408 } 409 410 /** 411 * Get the null date used by the spreadsheet document 412 * 413 * The internal representation of a Date used in this Addin 414 * is the number of days between 01/01/0001 and the date 415 * this function returns this internal Date value for the document null date 416 * 417 * @throws uno::RuntimeException 418 */ 419 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions ) 420 { 421 if (xOptions.is()) 422 { 423 try 424 { 425 uno::Any aAny = xOptions->getPropertyValue( "NullDate" ); 426 util::Date aDate; 427 if ( aAny >>= aDate ) 428 return DateToDays( aDate.Day, aDate.Month, aDate.Year ); 429 } 430 catch (uno::Exception&) 431 { 432 } 433 } 434 435 // no null date available -> no calculations possible 436 throw uno::RuntimeException(); 437 } 438 439 } 440 // XDateFunctions 441 442 /** 443 * Get week difference between 2 dates 444 * 445 * new Weeks(date1,date2,mode) function for StarCalc 446 * 447 * Two modes of operation are provided. 448 * mode 0 is just a simple division by 7 calculation. 449 * 450 * mode 1 calculates the difference by week adhering to ISO8601. 451 * 452 * The International Standard IS-8601 states that Monday is the first 453 * day of the week. The Gregorian Calendar is used for all dates, 454 * proleptic in case of dates before 1582-10-15. 455 * 456 * The (consecutive) week number of a date is 457 * std::floor( (date + NullDate - 1), 7.0 ), 458 * with weeks starting on Monday, and week 0 459 * starting on Monday, 0001-01-01 Gregorian. 460 * 461 * Weeks(d2,d1,m) is defined as -Weeks(d1,d2,m). 462 * 463 */ 464 465 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks( 466 const uno::Reference< beans::XPropertySet >& xOptions, 467 sal_Int32 nStartDate, sal_Int32 nEndDate, 468 sal_Int32 nMode ) 469 { 470 if ( nMode == 0 ) 471 { 472 return ( nEndDate - nStartDate ) / 7; 473 } 474 else if ( nMode == 1 ) 475 { 476 sal_Int32 nNullDate = GetNullDate( xOptions ); 477 sal_Int32 nDays1 = nStartDate + nNullDate - 1; 478 sal_Int32 nDays2 = nEndDate + nNullDate - 1; 479 480 return ( std::floor( nDays2 / 7.0 ) - std::floor( nDays1 / 7.0 ) ); 481 } 482 else 483 throw lang::IllegalArgumentException(); 484 } 485 486 /** 487 * Get month difference between 2 dates 488 * =Month(start, end, mode) Function for StarCalc 489 * 490 * two modes are provided 491 * 492 * mode 0 is the interval between the dates in month 493 * 494 * mode 1 is the difference in calendar month 495 */ 496 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths( 497 const uno::Reference< beans::XPropertySet >& xOptions, 498 sal_Int32 nStartDate, sal_Int32 nEndDate, 499 sal_Int32 nMode ) 500 { 501 if (nMode != 0 && nMode != 1) 502 throw lang::IllegalArgumentException(); 503 504 sal_Int32 nNullDate = GetNullDate( xOptions ); 505 506 sal_Int32 nDays1 = nStartDate + nNullDate; 507 sal_Int32 nDays2 = nEndDate + nNullDate; 508 509 sal_uInt16 nDay1,nMonth1,nYear1; 510 sal_uInt16 nDay2,nMonth2,nYear2; 511 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 512 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 513 514 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12; 515 if ( nMode == 1 || nDays1 == nDays2 ) return nRet; 516 517 if ( nDays1 < nDays2 ) 518 { 519 if ( nDay1 > nDay2 ) 520 { 521 nRet -= 1; 522 } 523 } 524 else 525 { 526 if ( nDay1 < nDay2 ) 527 { 528 nRet += 1; 529 } 530 } 531 532 return nRet; 533 } 534 535 /** 536 * Get Year difference between 2 dates 537 * 538 * two modes are provided 539 * 540 * mode 0 is the interval between the dates in years 541 * 542 * mode 1 is the difference in calendar years 543 */ 544 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears( 545 const uno::Reference< beans::XPropertySet >& xOptions, 546 sal_Int32 nStartDate, sal_Int32 nEndDate, 547 sal_Int32 nMode ) 548 { 549 if (nMode != 0 && nMode != 1) 550 throw lang::IllegalArgumentException(); 551 552 if ( nMode != 1 ) 553 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12; 554 555 sal_Int32 nNullDate = GetNullDate( xOptions ); 556 557 sal_Int32 nDays1 = nStartDate + nNullDate; 558 sal_Int32 nDays2 = nEndDate + nNullDate; 559 560 sal_uInt16 nDay1,nMonth1,nYear1; 561 sal_uInt16 nDay2,nMonth2,nYear2; 562 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 563 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 564 565 return nYear2 - nYear1; 566 } 567 568 /** 569 * Check if a Date is in a leap year in the Gregorian calendar 570 */ 571 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear( 572 const uno::Reference< beans::XPropertySet >& xOptions, 573 sal_Int32 nDate ) 574 { 575 sal_Int32 nNullDate = GetNullDate( xOptions ); 576 sal_Int32 nDays = nDate + nNullDate; 577 578 sal_uInt16 nDay, nMonth, nYear; 579 DaysToDate(nDays,nDay,nMonth,nYear); 580 581 return static_cast<sal_Int32>(IsLeapYear(nYear)); 582 } 583 584 /** 585 * Get the Number of Days in the month for a date 586 */ 587 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth( 588 const uno::Reference<beans::XPropertySet>& xOptions, 589 sal_Int32 nDate ) 590 { 591 sal_Int32 nNullDate = GetNullDate( xOptions ); 592 sal_Int32 nDays = nDate + nNullDate; 593 594 sal_uInt16 nDay, nMonth, nYear; 595 DaysToDate(nDays,nDay,nMonth,nYear); 596 597 return DaysInMonth( nMonth, nYear ); 598 } 599 600 /** 601 * Get number of days in the year of a date specified 602 */ 603 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear( 604 const uno::Reference< beans::XPropertySet >& xOptions, 605 sal_Int32 nDate ) 606 { 607 sal_Int32 nNullDate = GetNullDate( xOptions ); 608 sal_Int32 nDays = nDate + nNullDate; 609 610 sal_uInt16 nDay, nMonth, nYear; 611 DaysToDate(nDays,nDay,nMonth,nYear); 612 613 return ( IsLeapYear(nYear) ? 366 : 365 ); 614 } 615 616 /** 617 * Get number of weeks in the year for a date 618 * 619 * Most years have 52 weeks, but years that start on a Thursday 620 * and leap years that start on a Wednesday have 53 weeks 621 * 622 * The International Standard IS-8601 has decreed that Monday 623 * shall be the first day of the week. 624 * 625 * A WeekDay can be calculated by subtracting 1 and calculating the rest of 626 * a division by 7 from the internal date representation 627 * which gives a 0 - 6 value for Monday - Sunday 628 * 629 * @see #IsLeapYear #WeekNumber 630 */ 631 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear( 632 const uno::Reference< beans::XPropertySet >& xOptions, 633 sal_Int32 nDate ) 634 { 635 sal_Int32 nNullDate = GetNullDate( xOptions ); 636 sal_Int32 nDays = nDate + nNullDate; 637 638 sal_uInt16 nDay, nMonth, nYear; 639 DaysToDate(nDays,nDay,nMonth,nYear); 640 641 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7; 642 643 sal_Int32 nRet; 644 if ( nJan1WeekDay == 3 ) /* Thursday */ 645 nRet = 53; 646 else if ( nJan1WeekDay == 2 ) /* Wednesday */ 647 nRet = ( IsLeapYear(nYear) ? 53 : 52 ); 648 else 649 nRet = 52; 650 651 return nRet; 652 } 653 654 /** 655 * Encrypt or decrypt a string using ROT13 algorithm 656 * 657 * This function rotates each character by 13 in the alphabet. 658 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified. 659 */ 660 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) 661 { 662 OUStringBuffer aBuffer( aSrcString ); 663 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ ) 664 { 665 sal_Unicode cChar = aBuffer[nIndex]; 666 if( (cChar >= 'a') && (cChar <= 'z')) 667 { 668 cChar += 13; 669 if (cChar > 'z') 670 cChar -= 26; 671 } 672 else if( (cChar >= 'A') && (cChar <= 'Z') ) 673 { 674 cChar += 13; 675 if (cChar > 'Z') 676 cChar -= 26; 677 } 678 aBuffer[nIndex] = cChar; 679 } 680 return aBuffer.makeStringAndClear(); 681 } 682 683 OUString ScaDateAddIn::ScaResId(TranslateId aId) 684 { 685 return Translate::get(aId, aResLocale); 686 } 687 688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 689
