Line data Source code
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 <com/sun/star/util/Date.hpp>
23 : #include <cppuhelper/factory.hxx>
24 : #include <cppuhelper/supportsservice.hxx>
25 : #include <osl/diagnose.h>
26 : #include <rtl/ustrbuf.hxx>
27 : #include <tools/rcid.h>
28 : #include <tools/resmgr.hxx>
29 :
30 : using namespace ::com::sun::star;
31 :
32 : #define ADDIN_SERVICE "com.sun.star.sheet.AddIn"
33 : #define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions"
34 : #define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl"
35 :
36 : #define STR_FROM_ANSI( s ) OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 )
37 :
38 : const sal_uInt32 ScaList::nStartSize = 16;
39 : const sal_uInt32 ScaList::nIncrSize = 16;
40 :
41 171 : ScaList::ScaList() :
42 171 : pData( new void*[ nStartSize ] ),
43 : nSize( nStartSize ),
44 : nCount( 0 ),
45 342 : nCurr( 0 )
46 : {
47 171 : }
48 :
49 90 : ScaList::~ScaList()
50 : {
51 90 : delete[] pData;
52 90 : }
53 :
54 0 : void ScaList::_Grow()
55 : {
56 0 : nSize += nIncrSize;
57 :
58 0 : void** pNewData = new void*[ nSize ];
59 0 : memcpy( pNewData, pData, nCount * sizeof( void* ) );
60 :
61 0 : delete[] pData;
62 0 : pData = pNewData;
63 0 : }
64 :
65 160 : ScaStringList::~ScaStringList()
66 : {
67 240 : for( OUString* pStr = First(); pStr; pStr = Next() )
68 160 : delete pStr;
69 80 : }
70 :
71 2660 : ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) :
72 2660 : ResId( nId, rResMgr )
73 : {
74 2660 : }
75 :
76 : #define UNIQUE false // function name does not exist in Calc
77 :
78 : #define STDPAR false // all parameters are described
79 : #define INTPAR true // first parameter is internal
80 :
81 : #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
82 : { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
83 :
84 : const ScaFuncDataBase pFuncDataArr[] =
85 : {
86 : FUNCDATA( DiffWeeks, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
87 : FUNCDATA( DiffMonths, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
88 : FUNCDATA( DiffYears, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
89 : FUNCDATA( IsLeapYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
90 : FUNCDATA( DaysInMonth, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
91 : FUNCDATA( DaysInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
92 : FUNCDATA( WeeksInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
93 : FUNCDATA( Rot13, 1, ScaCat_Text, UNIQUE, STDPAR )
94 : };
95 :
96 : #undef FUNCDATA
97 :
98 152 : ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) :
99 : aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
100 : nUINameID( rBaseData.nUINameID ),
101 : nDescrID( rBaseData.nDescrID ),
102 : nCompListID( rBaseData.nCompListID ),
103 : nParamCount( rBaseData.nParamCount ),
104 : eCat( rBaseData.eCat ),
105 : bDouble( rBaseData.bDouble ),
106 152 : bWithOpt( rBaseData.bWithOpt )
107 : {
108 152 : ScaResStringArrLoader aArrLoader( RID_DATE_DEFFUNCTION_NAMES, nCompListID, rResMgr );
109 152 : const ResStringArray& rArr = aArrLoader.GetStringArray();
110 :
111 456 : for( sal_uInt32 nIndex = 0; nIndex < rArr.Count(); nIndex++ )
112 456 : aCompList.Append( rArr.GetString( nIndex ) );
113 152 : }
114 :
115 160 : ScaFuncData::~ScaFuncData()
116 : {
117 160 : }
118 :
119 532 : sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
120 : {
121 532 : if( !bWithOpt )
122 38 : nParam++;
123 532 : return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
124 : }
125 :
126 :
127 19 : ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) :
128 19 : nLast( 0xFFFFFFFF )
129 : {
130 171 : for( sal_uInt16 nIndex = 0; nIndex < SAL_N_ELEMENTS(pFuncDataArr); nIndex++ )
131 152 : Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) );
132 19 : }
133 :
134 30 : ScaFuncDataList::~ScaFuncDataList()
135 : {
136 90 : for( ScaFuncData* pFData = First(); pFData; pFData = Next() )
137 80 : delete pFData;
138 20 : }
139 :
140 1012 : const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const
141 : {
142 1012 : if( aLastName == rProgrammaticName )
143 836 : return Get( nLast );
144 :
145 792 : for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ )
146 : {
147 792 : const ScaFuncData* pCurr = Get( nIndex );
148 792 : if( pCurr->Is( rProgrammaticName ) )
149 : {
150 176 : const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName;
151 176 : const_cast< ScaFuncDataList* >( this )->nLast = nIndex;
152 176 : return pCurr;
153 : }
154 : }
155 0 : return NULL;
156 : }
157 :
158 684 : ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) :
159 684 : Resource( rResId )
160 : {
161 684 : rRet = ScaResId(nIndex, rResMgr).toString();
162 684 : FreeResource();
163 684 : }
164 :
165 : // entry points for service registration / instantiation
166 20 : uno::Reference< uno::XInterface > SAL_CALL ScaDateAddIn_CreateInstance(
167 : const uno::Reference< lang::XMultiServiceFactory >& )
168 : {
169 20 : return static_cast<cppu::OWeakObject*>(new ScaDateAddIn());
170 : }
171 :
172 : extern "C" {
173 :
174 20 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL date_component_getFactory(
175 : const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
176 : {
177 20 : void* pRet = 0;
178 :
179 100 : if ( pServiceManager &&
180 100 : OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
181 : {
182 : uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
183 : static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
184 : ScaDateAddIn::getImplementationName_Static(),
185 : ScaDateAddIn_CreateInstance,
186 20 : ScaDateAddIn::getSupportedServiceNames_Static() ) );
187 :
188 20 : if (xFactory.is())
189 : {
190 20 : xFactory->acquire();
191 20 : pRet = xFactory.get();
192 20 : }
193 : }
194 :
195 20 : return pRet;
196 : }
197 :
198 : } // extern C
199 :
200 : // "normal" service implementation
201 20 : ScaDateAddIn::ScaDateAddIn() :
202 : pDefLocales( NULL ),
203 : pResMgr( NULL ),
204 20 : pFuncDataList( NULL )
205 : {
206 20 : }
207 :
208 33 : ScaDateAddIn::~ScaDateAddIn()
209 : {
210 11 : delete pFuncDataList;
211 11 : delete pResMgr;
212 11 : delete[] pDefLocales;
213 22 : }
214 :
215 : static const sal_Char* pLang[] = { "de", "en" };
216 : static const sal_Char* pCoun[] = { "DE", "US" };
217 : static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
218 :
219 3 : void ScaDateAddIn::InitDefLocales()
220 : {
221 3 : pDefLocales = new lang::Locale[ nNumOfLoc ];
222 :
223 9 : for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
224 : {
225 6 : pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
226 6 : pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
227 : }
228 3 : }
229 :
230 48 : const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
231 : {
232 48 : if( !pDefLocales )
233 3 : InitDefLocales();
234 :
235 48 : return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
236 : }
237 :
238 2204 : ResMgr& ScaDateAddIn::GetResMgr() throw( uno::RuntimeException )
239 : {
240 2204 : if( !pResMgr )
241 : {
242 0 : InitData(); // try to get resource manager
243 0 : if( !pResMgr )
244 0 : throw uno::RuntimeException();
245 : }
246 2204 : return *pResMgr;
247 : }
248 :
249 19 : void ScaDateAddIn::InitData()
250 : {
251 19 : delete pResMgr;
252 19 : pResMgr = ResMgr::CreateResMgr("date", LanguageTag(aFuncLoc));
253 19 : delete pFuncDataList;
254 :
255 19 : pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL;
256 :
257 19 : if( pDefLocales )
258 : {
259 0 : delete pDefLocales;
260 0 : pDefLocales = NULL;
261 : }
262 19 : }
263 :
264 152 : OUString ScaDateAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException )
265 : {
266 152 : return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString();
267 : }
268 :
269 684 : OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException )
270 : {
271 684 : OUString aRet;
272 :
273 1368 : ScaResPublisher aResPubl( ScaResId( RID_DATE_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
274 684 : ScaResId aResId( nResId, GetResMgr() );
275 684 : aResId.SetRT( RSC_RESOURCE );
276 :
277 684 : if( aResPubl.IsAvailableRes( aResId ) )
278 684 : ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet );
279 :
280 684 : aResPubl.FreeResource();
281 1368 : return aRet;
282 : }
283 :
284 41 : OUString ScaDateAddIn::getImplementationName_Static()
285 : {
286 41 : return OUString( MY_IMPLNAME );
287 : }
288 :
289 21 : uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
290 : {
291 21 : uno::Sequence< OUString > aRet( 2 );
292 21 : OUString* pArray = aRet.getArray();
293 21 : pArray[0] = ADDIN_SERVICE;
294 21 : pArray[1] = MY_SERVICE;
295 21 : return aRet;
296 : }
297 :
298 : // XServiceName
299 19 : OUString SAL_CALL ScaDateAddIn::getServiceName() throw( uno::RuntimeException, std::exception )
300 : {
301 : // name of specific AddIn service
302 19 : return OUString( MY_SERVICE );
303 : }
304 :
305 : // XServiceInfo
306 1 : OUString SAL_CALL ScaDateAddIn::getImplementationName() throw( uno::RuntimeException, std::exception )
307 : {
308 1 : return getImplementationName_Static();
309 : }
310 :
311 0 : sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException, std::exception )
312 : {
313 0 : return cppu::supportsService(this, aServiceName);
314 : }
315 :
316 1 : uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() throw( uno::RuntimeException, std::exception )
317 : {
318 1 : return getSupportedServiceNames_Static();
319 : }
320 :
321 : // XLocalizable
322 19 : void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException, std::exception )
323 : {
324 19 : aFuncLoc = eLocale;
325 19 : InitData(); // change of locale invalidates resources!
326 19 : }
327 :
328 0 : lang::Locale SAL_CALL ScaDateAddIn::getLocale() throw( uno::RuntimeException, std::exception )
329 : {
330 0 : return aFuncLoc;
331 : }
332 :
333 0 : OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException, std::exception )
334 : {
335 : // not used by calc
336 : // (but should be implemented for other uses of the AddIn service)
337 0 : return OUString();
338 : }
339 :
340 152 : OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
341 : {
342 152 : OUString aRet;
343 :
344 152 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
345 152 : if( pFData )
346 : {
347 152 : aRet = GetDisplFuncStr( pFData->GetUINameID() );
348 152 : if( pFData->IsDouble() )
349 0 : aRet += STR_FROM_ANSI( "_ADD" );
350 : }
351 : else
352 : {
353 0 : aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" );
354 0 : aRet += aProgrammaticName;
355 : }
356 :
357 152 : return aRet;
358 : }
359 :
360 152 : OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
361 : {
362 152 : OUString aRet;
363 :
364 152 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
365 152 : if( pFData )
366 152 : aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 );
367 :
368 152 : return aRet;
369 : }
370 :
371 266 : OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
372 : const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException, std::exception )
373 : {
374 266 : OUString aRet;
375 :
376 266 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
377 266 : if( pFData && (nArgument <= 0xFFFF) )
378 : {
379 266 : sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
380 266 : if( nStr )
381 266 : aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr );
382 : else
383 0 : aRet = STR_FROM_ANSI( "internal" );
384 : }
385 :
386 266 : return aRet;
387 : }
388 :
389 266 : OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
390 : const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException, std::exception )
391 : {
392 266 : OUString aRet;
393 :
394 266 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
395 266 : if( pFData && (nArgument <= 0xFFFF) )
396 : {
397 266 : sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
398 266 : if( nStr )
399 266 : aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 );
400 : else
401 0 : aRet = STR_FROM_ANSI( "for internal use only" );
402 : }
403 :
404 266 : return aRet;
405 : }
406 :
407 152 : OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
408 : const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
409 : {
410 152 : OUString aRet;
411 :
412 152 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
413 152 : if( pFData )
414 : {
415 152 : switch( pFData->GetCategory() )
416 : {
417 133 : case ScaCat_DateTime: aRet = STR_FROM_ANSI( "Date&Time" ); break;
418 19 : case ScaCat_Text: aRet = STR_FROM_ANSI( "Text" ); break;
419 0 : case ScaCat_Finance: aRet = STR_FROM_ANSI( "Financial" ); break;
420 0 : case ScaCat_Inf: aRet = STR_FROM_ANSI( "Information" ); break;
421 0 : case ScaCat_Math: aRet = STR_FROM_ANSI( "Mathematical" ); break;
422 0 : case ScaCat_Tech: aRet = STR_FROM_ANSI( "Technical" ); break;
423 : // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
424 : default:
425 0 : break;
426 : }
427 : }
428 :
429 152 : if( aRet.isEmpty() )
430 0 : aRet = STR_FROM_ANSI( "Add-In" );
431 152 : return aRet;
432 : }
433 :
434 0 : OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
435 : const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
436 : {
437 0 : return getProgrammaticCategoryName( aProgrammaticName );
438 : }
439 :
440 : // XCompatibilityNames
441 24 : uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
442 : const OUString& aProgrammaticName ) throw( uno::RuntimeException, std::exception )
443 : {
444 24 : const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
445 24 : if( !pFData )
446 0 : return uno::Sequence< sheet::LocalizedName >( 0 );
447 :
448 24 : const ScaStringList& rStrList = pFData->GetCompNameList();
449 24 : sal_uInt32 nCount = rStrList.Count();
450 :
451 24 : uno::Sequence< sheet::LocalizedName > aRet( nCount );
452 24 : sheet::LocalizedName* pArray = aRet.getArray();
453 :
454 72 : for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
455 48 : pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) );
456 :
457 24 : return aRet;
458 : }
459 :
460 : namespace {
461 :
462 : // auxiliary functions
463 0 : bool IsLeapYear( sal_uInt16 nYear )
464 : {
465 0 : return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
466 : }
467 :
468 0 : sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
469 : {
470 : static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
471 : 31, 31, 30, 31, 30, 31 };
472 :
473 0 : if ( nMonth != 2 )
474 0 : return aDaysInMonth[nMonth-1];
475 : else
476 : {
477 0 : if ( IsLeapYear(nYear) )
478 0 : return aDaysInMonth[nMonth-1] + 1;
479 : else
480 0 : return aDaysInMonth[nMonth-1];
481 : }
482 : }
483 :
484 : /**
485 : * Convert a date to a count of days starting from 01/01/0001
486 : *
487 : * The internal representation of a Date used in this Addin
488 : * is the number of days between 01/01/0001 and the date
489 : * this function converts a Day , Month, Year representation
490 : * to this internal Date value.
491 : */
492 :
493 0 : sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
494 : {
495 0 : sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
496 0 : nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
497 :
498 0 : for( sal_uInt16 i = 1; i < nMonth; i++ )
499 0 : nDays += DaysInMonth(i,nYear);
500 0 : nDays += nDay;
501 :
502 0 : return nDays;
503 : }
504 :
505 : /**
506 : * Convert a count of days starting from 01/01/0001 to a date
507 : *
508 : * The internal representation of a Date used in this Addin
509 : * is the number of days between 01/01/0001 and the date
510 : * this function converts this internal Date value
511 : * to a Day , Month, Year representation of a Date.
512 : */
513 :
514 0 : void DaysToDate( sal_Int32 nDays,
515 : sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
516 : throw( lang::IllegalArgumentException )
517 : {
518 0 : if( nDays < 0 )
519 0 : throw lang::IllegalArgumentException();
520 :
521 : sal_Int32 nTempDays;
522 0 : sal_Int32 i = 0;
523 : bool bCalc;
524 :
525 0 : do
526 : {
527 0 : nTempDays = nDays;
528 0 : rYear = (sal_uInt16)((nTempDays / 365) - i);
529 0 : nTempDays -= ((sal_Int32) rYear -1) * 365;
530 0 : nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
531 0 : bCalc = false;
532 0 : if ( nTempDays < 1 )
533 : {
534 0 : i++;
535 0 : bCalc = true;
536 : }
537 : else
538 : {
539 0 : if ( nTempDays > 365 )
540 : {
541 0 : if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
542 : {
543 0 : i--;
544 0 : bCalc = true;
545 : }
546 : }
547 : }
548 : }
549 : while ( bCalc );
550 :
551 0 : rMonth = 1;
552 0 : while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
553 : {
554 0 : nTempDays -= DaysInMonth( rMonth, rYear );
555 0 : rMonth++;
556 : }
557 0 : rDay = (sal_uInt16)nTempDays;
558 0 : }
559 :
560 : /**
561 : * Get the null date used by the spreadsheet document
562 : *
563 : * The internal representation of a Date used in this Addin
564 : * is the number of days between 01/01/0001 and the date
565 : * this function returns this internal Date value for the document null date
566 : *
567 : */
568 0 : sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
569 : throw( uno::RuntimeException )
570 : {
571 0 : if (xOptions.is())
572 : {
573 : try
574 : {
575 0 : uno::Any aAny = xOptions->getPropertyValue(
576 0 : OUString( "NullDate" ) );
577 0 : util::Date aDate;
578 0 : if ( aAny >>= aDate )
579 0 : return DateToDays( aDate.Day, aDate.Month, aDate.Year );
580 : }
581 0 : catch (uno::Exception&)
582 : {
583 : }
584 : }
585 :
586 : // no null date available -> no calculations possible
587 0 : throw uno::RuntimeException();
588 : }
589 :
590 : }
591 : // XDateFunctions
592 :
593 : /**
594 : * Get week difference between 2 dates
595 : *
596 : * new Weeks(date1,date2,mode) function for StarCalc
597 : *
598 : * Two modes of operation are provided.
599 : * The first is just a simple division by 7 calculation.
600 : *
601 : * The second calculates the diffence by week of year.
602 : *
603 : * The International Standard IS-8601 has decreed that Monday
604 : * shall be the first day of the week.
605 : *
606 : * A week that lies partly in one year and partly in annother
607 : * is assigned a number in the year in which most of its days lie.
608 : *
609 : * That means that week 1 of any year is the week that contains the 4. January
610 : *
611 : * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
612 : *
613 : * A WeekDay can be then calculated by subtracting 1 and calculating the rest of
614 : * a division by 7, which gives a 0 - 6 value for Monday - Sunday
615 : *
616 : * Using the 4. January rule explained above the formula
617 : *
618 : * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
619 : *
620 : * calculates a number between 0-53 for each day which is in the same year as nJan4
621 : * where 0 means that this week belonged to the year before.
622 : *
623 : * If a day in the same or another year is used in this formula this calculates
624 : * an calendar week offset from a given 4. January
625 : *
626 : * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
627 : *
628 : * The 4.January of first Date Argument can thus be used to calculate
629 : * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
630 : *
631 : * which can be optimized to
632 : *
633 : * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
634 : *
635 : * Note: All calculations are operating on the long integer data type
636 : * % is the modulo operator in C which calculates the rest of an Integer division
637 : *
638 : *
639 : * mode 0 is the interval between the dates in month, that is days / 7
640 : *
641 : * mode 1 is the difference by week of year
642 : *
643 : */
644 :
645 0 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
646 : const uno::Reference< beans::XPropertySet >& xOptions,
647 : sal_Int32 nStartDate, sal_Int32 nEndDate,
648 : sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
649 : {
650 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
651 :
652 0 : sal_Int32 nDays1 = nStartDate + nNullDate;
653 0 : sal_Int32 nDays2 = nEndDate + nNullDate;
654 :
655 : sal_Int32 nRet;
656 :
657 0 : if ( nMode == 1 )
658 : {
659 : sal_uInt16 nDay,nMonth,nYear;
660 0 : DaysToDate( nDays1, nDay, nMonth, nYear );
661 0 : sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
662 :
663 0 : nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
664 : }
665 : else
666 : {
667 0 : nRet = (nDays2 - nDays1) / 7;
668 : }
669 0 : return nRet;
670 : }
671 :
672 : /**
673 : * Get month difference between 2 dates
674 : * =Month(start, end, mode) Function for StarCalc
675 : *
676 : * two modes are provided
677 : *
678 : * mode 0 is the interval between the dates in month
679 : *
680 : * mode 1 is the difference in calendar month
681 : */
682 0 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
683 : const uno::Reference< beans::XPropertySet >& xOptions,
684 : sal_Int32 nStartDate, sal_Int32 nEndDate,
685 : sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
686 : {
687 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
688 :
689 0 : sal_Int32 nDays1 = nStartDate + nNullDate;
690 0 : sal_Int32 nDays2 = nEndDate + nNullDate;
691 :
692 : sal_uInt16 nDay1,nMonth1,nYear1;
693 : sal_uInt16 nDay2,nMonth2,nYear2;
694 0 : DaysToDate(nDays1,nDay1,nMonth1,nYear1);
695 0 : DaysToDate(nDays2,nDay2,nMonth2,nYear2);
696 :
697 0 : sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
698 0 : if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
699 :
700 0 : if ( nDays1 < nDays2 )
701 : {
702 0 : if ( nDay1 > nDay2 )
703 : {
704 0 : nRet -= 1;
705 : }
706 : }
707 : else
708 : {
709 0 : if ( nDay1 < nDay2 )
710 : {
711 0 : nRet += 1;
712 : }
713 : }
714 :
715 0 : return nRet;
716 : }
717 :
718 : /**
719 : * Get Year difference between 2 dates
720 : *
721 : * two modes are provided
722 : *
723 : * mode 0 is the interval between the dates in years
724 : *
725 : * mode 1 is the difference in calendar years
726 : */
727 0 : sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
728 : const uno::Reference< beans::XPropertySet >& xOptions,
729 : sal_Int32 nStartDate, sal_Int32 nEndDate,
730 : sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
731 : {
732 0 : if ( nMode != 1 )
733 0 : return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
734 :
735 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
736 :
737 0 : sal_Int32 nDays1 = nStartDate + nNullDate;
738 0 : sal_Int32 nDays2 = nEndDate + nNullDate;
739 :
740 : sal_uInt16 nDay1,nMonth1,nYear1;
741 : sal_uInt16 nDay2,nMonth2,nYear2;
742 0 : DaysToDate(nDays1,nDay1,nMonth1,nYear1);
743 0 : DaysToDate(nDays2,nDay2,nMonth2,nYear2);
744 :
745 0 : return nYear2 - nYear1;
746 : }
747 :
748 : /**
749 : * Check if a Date is in a leap year in the Gregorian calendar
750 : */
751 0 : sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
752 : const uno::Reference< beans::XPropertySet >& xOptions,
753 : sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
754 : {
755 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
756 0 : sal_Int32 nDays = nDate + nNullDate;
757 :
758 : sal_uInt16 nDay, nMonth, nYear;
759 0 : DaysToDate(nDays,nDay,nMonth,nYear);
760 :
761 0 : return (sal_Int32)IsLeapYear(nYear);
762 : }
763 :
764 : /**
765 : * Get the Number of Days in the month for a date
766 : */
767 0 : sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
768 : const uno::Reference<beans::XPropertySet>& xOptions,
769 : sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
770 : {
771 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
772 0 : sal_Int32 nDays = nDate + nNullDate;
773 :
774 : sal_uInt16 nDay, nMonth, nYear;
775 0 : DaysToDate(nDays,nDay,nMonth,nYear);
776 :
777 0 : return DaysInMonth( nMonth, nYear );
778 : }
779 :
780 : /**
781 : * Get number of days in the year of a date specified
782 : */
783 0 : sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
784 : const uno::Reference< beans::XPropertySet >& xOptions,
785 : sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
786 : {
787 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
788 0 : sal_Int32 nDays = nDate + nNullDate;
789 :
790 : sal_uInt16 nDay, nMonth, nYear;
791 0 : DaysToDate(nDays,nDay,nMonth,nYear);
792 :
793 0 : return ( IsLeapYear(nYear) ? 366 : 365 );
794 : }
795 :
796 : /**
797 : * Get number of weeks in the year for a date
798 : *
799 : * Most years have 52 weeks, but years that start on a Thursday
800 : * and leep years that start on a Wednesday have 53 weeks
801 : *
802 : * The International Standard IS-8601 has decreed that Monday
803 : * shall be the first day of the week.
804 : *
805 : * A WeekDay can be calculated by subtracting 1 and calculating the rest of
806 : * a division by 7 from the internal date represention
807 : * which gives a 0 - 6 value for Monday - Sunday
808 : *
809 : * @see #IsLeapYear #WeekNumber
810 : */
811 0 : sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
812 : const uno::Reference< beans::XPropertySet >& xOptions,
813 : sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
814 : {
815 0 : sal_Int32 nNullDate = GetNullDate( xOptions );
816 0 : sal_Int32 nDays = nDate + nNullDate;
817 :
818 : sal_uInt16 nDay, nMonth, nYear;
819 0 : DaysToDate(nDays,nDay,nMonth,nYear);
820 :
821 0 : sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
822 :
823 : sal_Int32 nRet;
824 0 : if ( nJan1WeekDay == 3 ) /* Thursday */
825 0 : nRet = 53;
826 0 : else if ( nJan1WeekDay == 2 ) /* Wednesday */
827 0 : nRet = ( IsLeapYear(nYear) ? 53 : 52 );
828 : else
829 0 : nRet = 52;
830 :
831 0 : return nRet;
832 : }
833 :
834 : /**
835 : * Encrypt or decrypt a string using ROT13 algorithm
836 : *
837 : * This function rotates each character by 13 in the alphabet.
838 : * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
839 : */
840 3 : OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) throw( uno::RuntimeException, lang::IllegalArgumentException, std::exception )
841 : {
842 3 : OUStringBuffer aBuffer( aSrcString );
843 18 : for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
844 : {
845 15 : sal_Unicode cChar = aBuffer[nIndex];
846 21 : if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) ||
847 9 : ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) )
848 6 : cChar -= 26;
849 15 : aBuffer[nIndex] = cChar;
850 : }
851 3 : return aBuffer.makeStringAndClear();
852 : }
853 :
854 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|