PageRenderTime 59ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/binfilter/bf_svtools/source/numbers/svt_zforfind.cxx

https://bitbucket.org/mst/ooo340
C++ | 2805 lines | 2279 code | 233 blank | 293 comment | 746 complexity | 27d40d3f12fc44484cdaba84e303b2b0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, BSD-3-Clause-No-Nuclear-License-2014, GPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*************************************************************************
  2. *
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * Copyright 2000, 2010 Oracle and/or its affiliates.
  6. *
  7. * OpenOffice.org - a multi-platform office productivity suite
  8. *
  9. * This file is part of OpenOffice.org.
  10. *
  11. * OpenOffice.org is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Lesser General Public License version 3
  13. * only, as published by the Free Software Foundation.
  14. *
  15. * OpenOffice.org is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License version 3 for more details
  19. * (a copy is included in the LICENSE file that accompanied this code).
  20. *
  21. * You should have received a copy of the GNU Lesser General Public License
  22. * version 3 along with OpenOffice.org. If not, see
  23. * <http://www.openoffice.org/license.html>
  24. * for a copy of the LGPLv3 License.
  25. *
  26. ************************************************************************/
  27. // MARKER(update_precomp.py): autogen include statement, do not remove
  28. #include <ctype.h>
  29. #include <stdlib.h>
  30. #include <float.h>
  31. #include <errno.h>
  32. #ifndef _DATE_HXX //autogen
  33. #include <tools/date.hxx>
  34. #endif
  35. #ifndef _DEBUG_HXX //autogen
  36. #include <tools/debug.hxx>
  37. #endif
  38. #ifndef INCLUDED_RTL_MATH_HXX
  39. #include <rtl/math.hxx>
  40. #endif
  41. #ifndef _UNOTOOLS_CHARCLASS_HXX
  42. #include <unotools/charclass.hxx>
  43. #endif
  44. #ifndef _UNOTOOLS_CALENDARWRAPPER_HXX
  45. #include <unotools/calendarwrapper.hxx>
  46. #endif
  47. #ifndef _UNOTOOLS_LOCALEDATAWRAPPER_HXX
  48. #include <unotools/localedatawrapper.hxx>
  49. #endif
  50. #ifndef _COM_SUN_STAR_I18N_CALENDARFIELDINDEX_HPP_
  51. #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
  52. #endif
  53. #include <bf_svtools/zforlist.hxx> // NUMBERFORMAT_XXX
  54. #include "zforscan.hxx"
  55. #include <bf_svtools/zformat.hxx>
  56. #define _ZFORFIND_CXX
  57. #include "zforfind.hxx"
  58. #undef _ZFORFIND_CXX
  59. #ifndef DBG_UTIL
  60. #define NF_TEST_CALENDAR 0
  61. #else
  62. #define NF_TEST_CALENDAR 0
  63. #endif
  64. #if NF_TEST_CALENDAR
  65. #include <comphelper/processfactory.hxx>
  66. #include <com/sun/star/i18n/XExtendedCalendar.hpp>
  67. #endif
  68. namespace binfilter
  69. {
  70. const BYTE ImpSvNumberInputScan::nMatchedEndString = 0x01;
  71. const BYTE ImpSvNumberInputScan::nMatchedMidString = 0x02;
  72. const BYTE ImpSvNumberInputScan::nMatchedStartString = 0x04;
  73. const BYTE ImpSvNumberInputScan::nMatchedVirgin = 0x08;
  74. const BYTE ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
  75. /* It is not clear how we want timezones to be handled. Convert them to local
  76. * time isn't wanted, as it isn't done in any other place and timezone
  77. * information isn't stored anywhere. Ignoring them and pretending local time
  78. * may be wrong too and might not be what the user expects. Keep the input as
  79. * string so that no information is lost.
  80. * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
  81. * would work, together with the nTimezonePos handling in GetTimeRef(). */
  82. #define NF_RECOGNIZE_ISO8601_TIMEZONES 0
  83. //---------------------------------------------------------------------------
  84. // Konstruktor
  85. ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
  86. :
  87. pUpperMonthText( NULL ),
  88. pUpperAbbrevMonthText( NULL ),
  89. pUpperDayText( NULL ),
  90. pUpperAbbrevDayText( NULL )
  91. {
  92. pFormatter = pFormatterP;
  93. pNullDate = new Date(30,12,1899);
  94. nYear2000 = SvNumberFormatter::GetYear2000Default();
  95. Reset();
  96. ChangeIntl();
  97. }
  98. //---------------------------------------------------------------------------
  99. // Destruktor
  100. ImpSvNumberInputScan::~ImpSvNumberInputScan()
  101. {
  102. Reset();
  103. delete pNullDate;
  104. delete [] pUpperMonthText;
  105. delete [] pUpperAbbrevMonthText;
  106. delete [] pUpperDayText;
  107. delete [] pUpperAbbrevDayText;
  108. }
  109. //---------------------------------------------------------------------------
  110. // Reset
  111. void ImpSvNumberInputScan::Reset()
  112. {
  113. #if 0
  114. // ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision,
  115. // wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht
  116. // gebraucht wird..
  117. for (USHORT i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
  118. {
  119. sStrArray[i].Erase();
  120. nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1;
  121. IsNum[i] = FALSE;
  122. }
  123. #endif
  124. nMonth = 0;
  125. nMonthPos = 0;
  126. nTimePos = 0;
  127. nSign = 0;
  128. nESign = 0;
  129. nDecPos = 0;
  130. nNegCheck = 0;
  131. nAnzStrings = 0;
  132. nAnzNums = 0;
  133. nThousand = 0;
  134. eScannedType = NUMBERFORMAT_UNDEFINED;
  135. nAmPm = 0;
  136. nPosThousandString = 0;
  137. nLogical = 0;
  138. nStringScanNumFor = 0;
  139. nStringScanSign = 0;
  140. nMatchedAllStrings = nMatchedVirgin;
  141. nMayBeIso8601 = 0;
  142. nTimezonePos = 0;
  143. }
  144. //---------------------------------------------------------------------------
  145. //
  146. // static
  147. inline BOOL ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
  148. {
  149. // If the input string wouldn't be converted using TransformInput() we'd
  150. // to use something similar to the following and to adapt many places.
  151. #if 0
  152. // use faster isdigit() if possible
  153. if ( c < 128 )
  154. return isdigit( (unsigned char) c ) != 0;
  155. if ( c < 256 )
  156. return FALSE;
  157. String aTmp( c );
  158. return pFormatter->GetCharClass()->isDigit( aTmp, 0 );
  159. #else
  160. return c < 128 && isdigit( (unsigned char) c );
  161. #endif
  162. }
  163. //---------------------------------------------------------------------------
  164. //
  165. void ImpSvNumberInputScan::TransformInput( String& rStr )
  166. {
  167. xub_StrLen nPos, nLen;
  168. for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos )
  169. {
  170. if ( 256 <= rStr.GetChar( nPos ) &&
  171. pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
  172. break;
  173. }
  174. if ( nPos < nLen )
  175. rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
  176. pFormatter->GetLocale(), 0 );
  177. }
  178. //---------------------------------------------------------------------------
  179. // StringToDouble
  180. //
  181. // Only simple unsigned floating point values without any error detection,
  182. // decimal separator has to be '.'
  183. double ImpSvNumberInputScan::StringToDouble( const String& rStr, BOOL bForceFraction )
  184. {
  185. double fNum = 0.0;
  186. double fFrac = 0.0;
  187. int nExp = 0;
  188. xub_StrLen nPos = 0;
  189. xub_StrLen nLen = rStr.Len();
  190. BOOL bPreSep = !bForceFraction;
  191. while (nPos < nLen)
  192. {
  193. if (rStr.GetChar(nPos) == '.')
  194. bPreSep = FALSE;
  195. else if (bPreSep)
  196. fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0');
  197. else
  198. {
  199. fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0');
  200. --nExp;
  201. }
  202. nPos++;
  203. }
  204. if ( fFrac )
  205. return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
  206. return fNum;
  207. }
  208. //---------------------------------------------------------------------------
  209. // NextNumberStringSymbol
  210. //
  211. // Zerlegt die Eingabe in Zahlen und Strings fuer die weitere
  212. // Verarbeitung (Turing-Maschine).
  213. //---------------------------------------------------------------------------
  214. // Ausgangs Zustand = GetChar
  215. //---------------+-------------------+-----------------------+---------------
  216. // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
  217. //---------------+-------------------+-----------------------+---------------
  218. // GetChar | Ziffer | Symbol=Zeichen | GetValue
  219. // | Sonst | Symbol=Zeichen | GetString
  220. //---------------|-------------------+-----------------------+---------------
  221. // GetValue | Ziffer | Symbol=Symbol+Zeichen | GetValue
  222. // | Sonst | Dec(CharPos) | Stop
  223. //---------------+-------------------+-----------------------+---------------
  224. // GetString | Ziffer | Dec(CharPos) | Stop
  225. // | Sonst | Symbol=Symbol+Zeichen | GetString
  226. //---------------+-------------------+-----------------------+---------------
  227. enum ScanState // States der Turing-Maschine
  228. {
  229. SsStop = 0,
  230. SsStart = 1,
  231. SsGetValue = 2,
  232. SsGetString = 3
  233. };
  234. BOOL ImpSvNumberInputScan::NextNumberStringSymbol(
  235. const sal_Unicode*& pStr,
  236. String& rSymbol )
  237. {
  238. BOOL isNumber = FALSE;
  239. sal_Unicode cToken;
  240. ScanState eState = SsStart;
  241. register const sal_Unicode* pHere = pStr;
  242. register xub_StrLen nChars = 0;
  243. while ( ((cToken = *pHere) != 0) && eState != SsStop)
  244. {
  245. pHere++;
  246. switch (eState)
  247. {
  248. case SsStart:
  249. if ( MyIsdigit( cToken ) )
  250. {
  251. eState = SsGetValue;
  252. isNumber = TRUE;
  253. }
  254. else
  255. eState = SsGetString;
  256. nChars++;
  257. break;
  258. case SsGetValue:
  259. if ( MyIsdigit( cToken ) )
  260. nChars++;
  261. else
  262. {
  263. eState = SsStop;
  264. pHere--;
  265. }
  266. break;
  267. case SsGetString:
  268. if ( !MyIsdigit( cToken ) )
  269. nChars++;
  270. else
  271. {
  272. eState = SsStop;
  273. pHere--;
  274. }
  275. break;
  276. default:
  277. break;
  278. } // switch
  279. } // while
  280. if ( nChars )
  281. rSymbol.Assign( pStr, nChars );
  282. else
  283. rSymbol.Erase();
  284. pStr = pHere;
  285. return isNumber;
  286. }
  287. //---------------------------------------------------------------------------
  288. // SkipThousands
  289. BOOL ImpSvNumberInputScan::SkipThousands(
  290. const sal_Unicode*& pStr,
  291. String& rSymbol )
  292. {
  293. BOOL res = FALSE;
  294. sal_Unicode cToken;
  295. const String& rThSep = pFormatter->GetNumThousandSep();
  296. register const sal_Unicode* pHere = pStr;
  297. ScanState eState = SsStart;
  298. xub_StrLen nCounter = 0; // counts 3 digits
  299. while ( ((cToken = *pHere) != 0) && eState != SsStop)
  300. {
  301. pHere++;
  302. switch (eState)
  303. {
  304. case SsStart:
  305. if ( StringPtrContains( rThSep, pHere-1, 0 ) )
  306. {
  307. nCounter = 0;
  308. eState = SsGetValue;
  309. pHere += rThSep.Len()-1;
  310. }
  311. else
  312. {
  313. eState = SsStop;
  314. pHere--;
  315. }
  316. break;
  317. case SsGetValue:
  318. if ( MyIsdigit( cToken ) )
  319. {
  320. rSymbol += cToken;
  321. nCounter++;
  322. if (nCounter == 3)
  323. {
  324. eState = SsStart;
  325. res = TRUE; // .000 combination found
  326. }
  327. }
  328. else
  329. {
  330. eState = SsStop;
  331. pHere--;
  332. }
  333. break;
  334. default:
  335. break;
  336. } // switch
  337. } // while
  338. if (eState == SsGetValue) // break witth less than 3 digits
  339. {
  340. if ( nCounter )
  341. rSymbol.Erase( rSymbol.Len() - nCounter, nCounter );
  342. pHere -= nCounter + rThSep.Len(); // put back ThSep also
  343. }
  344. pStr = pHere;
  345. return res;
  346. }
  347. //---------------------------------------------------------------------------
  348. // NumberStringDivision
  349. void ImpSvNumberInputScan::NumberStringDivision( const String& rString )
  350. {
  351. const sal_Unicode* pStr = rString.GetBuffer();
  352. const sal_Unicode* const pEnd = pStr + rString.Len();
  353. while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
  354. {
  355. if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
  356. { // Zahl
  357. IsNum[nAnzStrings] = TRUE;
  358. nNums[nAnzNums] = nAnzStrings;
  359. nAnzNums++;
  360. if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
  361. nPosThousandString == 0) // nur einmal
  362. if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
  363. nPosThousandString = nAnzStrings;
  364. }
  365. else
  366. {
  367. IsNum[nAnzStrings] = FALSE;
  368. }
  369. nAnzStrings++;
  370. }
  371. }
  372. //---------------------------------------------------------------------------
  373. // Whether rString contains rWhat at nPos
  374. BOOL ImpSvNumberInputScan::StringContainsImpl( const String& rWhat,
  375. const String& rString, xub_StrLen nPos )
  376. {
  377. if ( nPos + rWhat.Len() <= rString.Len() )
  378. return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos );
  379. return FALSE;
  380. }
  381. //---------------------------------------------------------------------------
  382. // Whether pString contains rWhat at nPos
  383. BOOL ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat,
  384. const sal_Unicode* pString, xub_StrLen nPos )
  385. {
  386. if ( rWhat.Len() == 0 )
  387. return FALSE;
  388. register const sal_Unicode* pWhat = rWhat.GetBuffer();
  389. register const sal_Unicode* const pEnd = pWhat + rWhat.Len();
  390. register const sal_Unicode* pStr = pString + nPos;
  391. while ( pWhat < pEnd )
  392. {
  393. if ( *pWhat != *pStr )
  394. return FALSE;
  395. pWhat++;
  396. pStr++;
  397. }
  398. return TRUE;
  399. }
  400. //---------------------------------------------------------------------------
  401. // SkipChar
  402. //
  403. // ueberspringt genau das angegebene Zeichen
  404. inline BOOL ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString,
  405. xub_StrLen& nPos )
  406. {
  407. if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c))
  408. {
  409. nPos++;
  410. return TRUE;
  411. }
  412. return FALSE;
  413. }
  414. //---------------------------------------------------------------------------
  415. // SkipBlanks
  416. //
  417. // Ueberspringt Leerzeichen
  418. inline void ImpSvNumberInputScan::SkipBlanks( const String& rString,
  419. xub_StrLen& nPos )
  420. {
  421. if ( nPos < rString.Len() )
  422. {
  423. register const sal_Unicode* p = rString.GetBuffer() + nPos;
  424. while ( *p == ' ' )
  425. {
  426. nPos++;
  427. p++;
  428. }
  429. }
  430. }
  431. //---------------------------------------------------------------------------
  432. // SkipString
  433. //
  434. // jump over rWhat in rString at nPos
  435. inline BOOL ImpSvNumberInputScan::SkipString( const String& rWhat,
  436. const String& rString, xub_StrLen& nPos )
  437. {
  438. if ( StringContains( rWhat, rString, nPos ) )
  439. {
  440. nPos = nPos + rWhat.Len();
  441. return TRUE;
  442. }
  443. return FALSE;
  444. }
  445. //---------------------------------------------------------------------------
  446. // GetThousandSep
  447. //
  448. // erkennt genau .111 als Tausenderpunkt
  449. inline BOOL ImpSvNumberInputScan::GetThousandSep(
  450. const String& rString,
  451. xub_StrLen& nPos,
  452. USHORT nStringPos )
  453. {
  454. const String& rSep = pFormatter->GetNumThousandSep();
  455. // Is it an ordinary space instead of a non-breaking space?
  456. bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 &&
  457. rSep.Len() == 1 && rString.Len() == 1;
  458. if ( (rString == rSep || bSpaceBreak) // nothing else
  459. && nStringPos < nAnzStrings - 1 // safety first!
  460. && IsNum[nStringPos+1] // number follows
  461. && ( sStrArray[nStringPos+1].Len() == 3 // with 3 digits
  462. || nPosThousandString == nStringPos+1 ) ) // or concatenated
  463. {
  464. nPos = nPos + rSep.Len();
  465. return TRUE;
  466. }
  467. return FALSE;
  468. }
  469. //---------------------------------------------------------------------------
  470. // GetLogical
  471. //
  472. // Umwandlung Text in logischen Wert
  473. // "TRUE" => 1:
  474. // "FALSE"=> -1:
  475. // sonst => 0:
  476. short ImpSvNumberInputScan::GetLogical( const String& rString )
  477. {
  478. short res;
  479. if (rString.Len() < 4) // kein Platz fuer mind 4 Buch.
  480. res = 0;
  481. else
  482. {
  483. const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
  484. if ( rString == pFS->GetTrueString() )
  485. res = 1;
  486. else if ( rString == pFS->GetFalseString() )
  487. res = -1;
  488. else
  489. res = 0;
  490. }
  491. return res;
  492. }
  493. //---------------------------------------------------------------------------
  494. // GetMonth
  495. //
  496. // Converts a string containing a month name (JAN, January) at nPos into the
  497. // month number (negative if abbreviated), returns 0 if nothing found
  498. short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos )
  499. {
  500. // #102136# The correct English form of month September abbreviated is
  501. // SEPT, but almost every data contains SEP instead.
  502. static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
  503. static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
  504. short res = 0; // no month found
  505. if (rString.Len() > nPos) // only if needed
  506. {
  507. if ( !bTextInitialized )
  508. InitText();
  509. sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
  510. for ( sal_Int16 i = 0; i < nMonths; i++ )
  511. {
  512. if ( StringContains( pUpperMonthText[i], rString, nPos ) )
  513. { // full names first
  514. nPos = nPos + pUpperMonthText[i].Len();
  515. res = i+1;
  516. break; // for
  517. }
  518. else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) )
  519. { // abbreviated
  520. nPos = nPos + pUpperAbbrevMonthText[i].Len();
  521. res = sal::static_int_cast< short >(-(i+1)); // negative
  522. break; // for
  523. }
  524. else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
  525. StringContains( aSepShortened, rString, nPos ) )
  526. { // #102136# SEPT/SEP
  527. nPos = nPos + aSepShortened.Len();
  528. res = sal::static_int_cast< short >(-(i+1)); // negative
  529. break; // for
  530. }
  531. }
  532. }
  533. return res;
  534. }
  535. //---------------------------------------------------------------------------
  536. // GetDayOfWeek
  537. //
  538. // Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
  539. // DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
  540. int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos )
  541. {
  542. int res = 0; // no day found
  543. if (rString.Len() > nPos) // only if needed
  544. {
  545. if ( !bTextInitialized )
  546. InitText();
  547. sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
  548. for ( sal_Int16 i = 0; i < nDays; i++ )
  549. {
  550. if ( StringContains( pUpperDayText[i], rString, nPos ) )
  551. { // full names first
  552. nPos = nPos + pUpperDayText[i].Len();
  553. res = i + 1;
  554. break; // for
  555. }
  556. if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) )
  557. { // abbreviated
  558. nPos = nPos + pUpperAbbrevDayText[i].Len();
  559. res = -(i + 1); // negative
  560. break; // for
  561. }
  562. }
  563. }
  564. return res;
  565. }
  566. //---------------------------------------------------------------------------
  567. // GetCurrency
  568. //
  569. // Lesen eines Waehrungssysmbols
  570. // '$' => TRUE
  571. // sonst => FALSE
  572. BOOL ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos,
  573. const SvNumberformat* pFormat )
  574. {
  575. if ( rString.Len() > nPos )
  576. {
  577. if ( !aUpperCurrSymbol.Len() )
  578. { // if no format specified the currency of the initialized formatter
  579. LanguageType eLang = (pFormat ? pFormat->GetLanguage() :
  580. pFormatter->GetLanguage());
  581. aUpperCurrSymbol = pFormatter->GetCharClass()->upper(
  582. SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
  583. }
  584. if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
  585. {
  586. nPos = nPos + aUpperCurrSymbol.Len();
  587. return TRUE;
  588. }
  589. if ( pFormat )
  590. {
  591. String aSymbol, aExtension;
  592. if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
  593. {
  594. if ( aSymbol.Len() <= rString.Len() - nPos )
  595. {
  596. pFormatter->GetCharClass()->toUpper( aSymbol );
  597. if ( StringContains( aSymbol, rString, nPos ) )
  598. {
  599. nPos = nPos + aSymbol.Len();
  600. return TRUE;
  601. }
  602. }
  603. }
  604. }
  605. }
  606. return FALSE;
  607. }
  608. //---------------------------------------------------------------------------
  609. // GetTimeAmPm
  610. //
  611. // Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe
  612. //
  613. // Rueckgabe:
  614. // "AM" od. "PM" => TRUE
  615. // sonst => FALSE
  616. //
  617. // nAmPos:
  618. // "AM" => 1
  619. // "PM" => -1
  620. // sonst => 0
  621. BOOL ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos )
  622. {
  623. if ( rString.Len() > nPos )
  624. {
  625. const CharClass* pChr = pFormatter->GetCharClass();
  626. const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
  627. if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) )
  628. {
  629. nAmPm = 1;
  630. nPos = nPos + pLoc->getTimeAM().Len();
  631. return TRUE;
  632. }
  633. else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) )
  634. {
  635. nAmPm = -1;
  636. nPos = nPos + pLoc->getTimePM().Len();
  637. return TRUE;
  638. }
  639. }
  640. return FALSE;
  641. }
  642. //---------------------------------------------------------------------------
  643. // GetDecSep
  644. //
  645. // Lesen eines Dezimaltrenners (',')
  646. // ',' => TRUE
  647. // sonst => FALSE
  648. inline BOOL ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos )
  649. {
  650. if ( rString.Len() > nPos )
  651. {
  652. const String& rSep = pFormatter->GetNumDecimalSep();
  653. if ( rString.Equals( rSep, nPos, rSep.Len() ) )
  654. {
  655. nPos = nPos + rSep.Len();
  656. return TRUE;
  657. }
  658. }
  659. return FALSE;
  660. }
  661. //---------------------------------------------------------------------------
  662. // read a hundredth seconds separator
  663. inline BOOL ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos )
  664. {
  665. if ( rString.Len() > nPos )
  666. {
  667. const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
  668. if ( rString.Equals( rSep, nPos, rSep.Len() ) )
  669. {
  670. nPos = nPos + rSep.Len();
  671. return TRUE;
  672. }
  673. }
  674. return FALSE;
  675. }
  676. //---------------------------------------------------------------------------
  677. // GetSign
  678. //
  679. // Lesen eines Vorzeichens, auch Klammer !?!
  680. // '+' => 1
  681. // '-' => -1
  682. // '(' => -1, nNegCheck = 1
  683. // sonst => 0
  684. int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos )
  685. {
  686. if (rString.Len() > nPos)
  687. switch (rString.GetChar(nPos))
  688. {
  689. case '+':
  690. nPos++;
  691. return 1;
  692. case '(': // '(' aehnlich wie '-' ?!?
  693. nNegCheck = 1;
  694. //! fallthru
  695. case '-':
  696. nPos++;
  697. return -1;
  698. default:
  699. break;
  700. }
  701. return 0;
  702. }
  703. //---------------------------------------------------------------------------
  704. // GetESign
  705. //
  706. // Lesen eines Vorzeichens, gedacht fuer Exponent ?!?
  707. // '+' => 1
  708. // '-' => -1
  709. // sonst => 0
  710. short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos )
  711. {
  712. if (rString.Len() > nPos)
  713. switch (rString.GetChar(nPos))
  714. {
  715. case '+':
  716. nPos++;
  717. return 1;
  718. case '-':
  719. nPos++;
  720. return -1;
  721. default:
  722. break;
  723. }
  724. return 0;
  725. }
  726. //---------------------------------------------------------------------------
  727. // GetNextNumber
  728. //
  729. // i counts string portions, j counts numbers thereof.
  730. // It should had been called SkipNumber instead.
  731. inline BOOL ImpSvNumberInputScan::GetNextNumber( USHORT& i, USHORT& j )
  732. {
  733. if ( i < nAnzStrings && IsNum[i] )
  734. {
  735. j++;
  736. i++;
  737. return TRUE;
  738. }
  739. return FALSE;
  740. }
  741. //---------------------------------------------------------------------------
  742. // GetTimeRef
  743. void ImpSvNumberInputScan::GetTimeRef(
  744. double& fOutNumber,
  745. USHORT nIndex, // j-value of the first numeric time part of input, default 0
  746. USHORT nAnz ) // count of numeric time parts
  747. {
  748. USHORT nHour;
  749. USHORT nMinute = 0;
  750. USHORT nSecond = 0;
  751. double fSecond100 = 0.0;
  752. USHORT nStartIndex = nIndex;
  753. if (nTimezonePos)
  754. {
  755. // find first timezone number index and adjust count
  756. for (USHORT j=0; j<nAnzNums; ++j)
  757. {
  758. if (nNums[j] == nTimezonePos)
  759. {
  760. // nAnz is not total count, but count of time relevant strings.
  761. if (nStartIndex < j && j - nStartIndex < nAnz)
  762. nAnz = j - nStartIndex;
  763. break; // for
  764. }
  765. }
  766. }
  767. if (nDecPos == 2 && (nAnz == 3 || nAnz == 2)) // 20:45.5 or 45.5
  768. nHour = 0;
  769. else if (nIndex - nStartIndex < nAnz)
  770. nHour = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
  771. else
  772. {
  773. nHour = 0;
  774. DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index");
  775. }
  776. if (nDecPos == 2 && nAnz == 2) // 45.5
  777. nMinute = 0;
  778. else if (nIndex - nStartIndex < nAnz)
  779. nMinute = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
  780. if (nIndex - nStartIndex < nAnz)
  781. nSecond = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
  782. if (nIndex - nStartIndex < nAnz)
  783. fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], TRUE );
  784. if (nAmPm == -1 && nHour != 12) // PM
  785. nHour += 12;
  786. else if (nAmPm == 1 && nHour == 12) // 12 AM
  787. nHour = 0;
  788. fOutNumber = ((double)nHour*3600 +
  789. (double)nMinute*60 +
  790. (double)nSecond +
  791. fSecond100)/86400.0;
  792. }
  793. //---------------------------------------------------------------------------
  794. // ImplGetDay
  795. USHORT ImpSvNumberInputScan::ImplGetDay( USHORT nIndex )
  796. {
  797. USHORT nRes = 0;
  798. if (sStrArray[nNums[nIndex]].Len() <= 2)
  799. {
  800. USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
  801. if (nNum <= 31)
  802. nRes = nNum;
  803. }
  804. return nRes;
  805. }
  806. //---------------------------------------------------------------------------
  807. // ImplGetMonth
  808. USHORT ImpSvNumberInputScan::ImplGetMonth( USHORT nIndex )
  809. {
  810. // preset invalid month number
  811. USHORT nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
  812. if (sStrArray[nNums[nIndex]].Len() <= 2)
  813. {
  814. USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
  815. if ( 0 < nNum && nNum <= nRes )
  816. nRes = nNum - 1; // zero based for CalendarFieldIndex::MONTH
  817. }
  818. return nRes;
  819. }
  820. //---------------------------------------------------------------------------
  821. // ImplGetYear
  822. //
  823. // 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ...
  824. USHORT ImpSvNumberInputScan::ImplGetYear( USHORT nIndex )
  825. {
  826. USHORT nYear = 0;
  827. if (sStrArray[nNums[nIndex]].Len() <= 4)
  828. {
  829. nYear = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
  830. nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
  831. }
  832. return nYear;
  833. }
  834. //---------------------------------------------------------------------------
  835. bool ImpSvNumberInputScan::MayBeIso8601()
  836. {
  837. if (nMayBeIso8601 == 0)
  838. {
  839. if (nAnzNums >= 3 && nNums[0] < nAnzStrings &&
  840. sStrArray[nNums[0]].ToInt32() > 31)
  841. nMayBeIso8601 = 1;
  842. else
  843. nMayBeIso8601 = 2;
  844. }
  845. return nMayBeIso8601 == 1;
  846. }
  847. //---------------------------------------------------------------------------
  848. // GetDateRef
  849. BOOL ImpSvNumberInputScan::GetDateRef( double& fDays, USHORT& nCounter,
  850. const SvNumberformat* pFormat )
  851. {
  852. using namespace ::com::sun::star::i18n;
  853. NfEvalDateFormat eEDF;
  854. int nFormatOrder;
  855. if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) )
  856. {
  857. eEDF = pFormatter->GetEvalDateFormat();
  858. switch ( eEDF )
  859. {
  860. case NF_EVALDATEFORMAT_INTL :
  861. case NF_EVALDATEFORMAT_FORMAT :
  862. nFormatOrder = 1; // only one loop
  863. break;
  864. default:
  865. nFormatOrder = 2;
  866. if ( nMatchedAllStrings )
  867. eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
  868. // we have a complete match, use it
  869. }
  870. }
  871. else
  872. {
  873. eEDF = NF_EVALDATEFORMAT_INTL;
  874. nFormatOrder = 1;
  875. }
  876. BOOL res = TRUE;
  877. const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
  878. CalendarWrapper* pCal = pFormatter->GetCalendar();
  879. for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
  880. {
  881. pCal->setGregorianDateTime( Date() ); // today
  882. String aOrgCalendar; // empty => not changed yet
  883. DateFormat DateFmt;
  884. BOOL bFormatTurn;
  885. switch ( eEDF )
  886. {
  887. case NF_EVALDATEFORMAT_INTL :
  888. bFormatTurn = FALSE;
  889. DateFmt = pLoc->getDateFormat();
  890. break;
  891. case NF_EVALDATEFORMAT_FORMAT :
  892. bFormatTurn = TRUE;
  893. DateFmt = pFormat->GetDateOrder();
  894. break;
  895. case NF_EVALDATEFORMAT_INTL_FORMAT :
  896. if ( nTryOrder == 1 )
  897. {
  898. bFormatTurn = FALSE;
  899. DateFmt = pLoc->getDateFormat();
  900. }
  901. else
  902. {
  903. bFormatTurn = TRUE;
  904. DateFmt = pFormat->GetDateOrder();
  905. }
  906. break;
  907. case NF_EVALDATEFORMAT_FORMAT_INTL :
  908. if ( nTryOrder == 2 )
  909. {
  910. bFormatTurn = FALSE;
  911. DateFmt = pLoc->getDateFormat();
  912. }
  913. else
  914. {
  915. bFormatTurn = TRUE;
  916. DateFmt = pFormat->GetDateOrder();
  917. }
  918. break;
  919. default:
  920. DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
  921. DateFmt = YMD;
  922. bFormatTurn = FALSE;
  923. }
  924. if ( bFormatTurn )
  925. {
  926. #if 0
  927. /* TODO:
  928. We are currently not able to fully support a switch to another calendar during
  929. input for the following reasons:
  930. 1. We do have a problem if both (locale's default and format's) calendars
  931. define the same YMD order and use the same date separator, there is no way
  932. to distinguish between them if the input results in valid calendar input for
  933. both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
  934. it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
  935. calendar be preferred? This could be confusing if a Calc cell was formatted
  936. different to the locale's default and has no content yet, then the user has
  937. no clue about the format or calendar being set.
  938. 2. In Calc cell edit mode a date is always displayed and edited using the
  939. default edit format of the default calendar (normally being Gregorian). If
  940. input was ambiguous due to issue #1 we'd need a mechanism to tell that a
  941. date was edited and not newly entered. Not feasible. Otherwise we'd need a
  942. mechanism to use a specific edit format with a specific calendar according
  943. to the format set.
  944. 3. For some calendars like Japanese Gengou we'd need era input, which isn't
  945. implemented at all. Though this is a rare and special case, forcing a
  946. calendar dependent edit format as suggested in item #2 might require era
  947. input, if it shouldn't result in a fallback to Gregorian calendar.
  948. 4. Last and least: the GetMonth() method currently only matches month names of
  949. the default calendar. Alternating month names of the actual format's
  950. calendar would have to be implemented. No problem.
  951. */
  952. if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
  953. pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
  954. else
  955. pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
  956. nStringScanNumFor );
  957. #endif
  958. }
  959. res = TRUE;
  960. nCounter = 0;
  961. // For incomplete dates, always assume first day of month if not specified.
  962. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
  963. switch (nAnzNums) // count of numbers in string
  964. {
  965. case 0: // none
  966. if (nMonthPos) // only month (Jan)
  967. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  968. else
  969. res = FALSE;
  970. break;
  971. case 1: // only one number
  972. nCounter = 1;
  973. switch (nMonthPos) // where is the month
  974. {
  975. case 0: // not found => only day entered
  976. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  977. break;
  978. case 1: // month at the beginning (Jan 01)
  979. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  980. switch (DateFmt)
  981. {
  982. case MDY:
  983. case YMD:
  984. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  985. break;
  986. case DMY:
  987. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  988. break;
  989. default:
  990. res = FALSE;
  991. break;
  992. }
  993. break;
  994. case 3: // month at the end (10 Jan)
  995. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  996. switch (DateFmt)
  997. {
  998. case DMY:
  999. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1000. break;
  1001. case YMD:
  1002. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1003. break;
  1004. default:
  1005. res = FALSE;
  1006. break;
  1007. }
  1008. break;
  1009. default:
  1010. res = FALSE;
  1011. break;
  1012. } // switch (nMonthPos)
  1013. break;
  1014. case 2: // 2 numbers
  1015. nCounter = 2;
  1016. switch (nMonthPos) // where is the month
  1017. {
  1018. case 0: // not found
  1019. {
  1020. bool bHadExact;
  1021. sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
  1022. if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff )
  1023. { // formatted as date and exactly 2 parts
  1024. bHadExact = true;
  1025. switch ( (nExactDateOrder >> 8) & 0xff )
  1026. {
  1027. case 'Y':
  1028. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1029. break;
  1030. case 'M':
  1031. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
  1032. break;
  1033. case 'D':
  1034. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1035. break;
  1036. default:
  1037. bHadExact = false;
  1038. }
  1039. switch ( nExactDateOrder & 0xff )
  1040. {
  1041. case 'Y':
  1042. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1043. break;
  1044. case 'M':
  1045. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
  1046. break;
  1047. case 'D':
  1048. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1049. break;
  1050. default:
  1051. bHadExact = false;
  1052. }
  1053. }
  1054. else
  1055. bHadExact = false;
  1056. if ( !bHadExact || !pCal->isValid() )
  1057. {
  1058. if ( !bHadExact && nExactDateOrder )
  1059. pCal->setGregorianDateTime( Date() ); // reset today
  1060. switch (DateFmt)
  1061. {
  1062. case MDY:
  1063. // M D
  1064. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1065. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
  1066. break;
  1067. case DMY:
  1068. // D M
  1069. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1070. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
  1071. if ( !pCal->isValid() ) // 2nd try
  1072. { // M Y
  1073. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
  1074. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
  1075. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1076. }
  1077. break;
  1078. case YMD:
  1079. // M D
  1080. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1081. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
  1082. if ( !pCal->isValid() ) // 2nd try
  1083. { // Y M
  1084. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
  1085. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
  1086. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1087. }
  1088. break;
  1089. default:
  1090. res = FALSE;
  1091. break;
  1092. }
  1093. }
  1094. }
  1095. break;
  1096. case 1: // month at the beginning (Jan 01 01)
  1097. {
  1098. // The input is valid as MDY in almost any
  1099. // constellation, there is no date order (M)YD except if
  1100. // set in a format applied.
  1101. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  1102. sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
  1103. if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
  1104. {
  1105. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1106. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1107. }
  1108. else
  1109. {
  1110. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1111. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1112. }
  1113. }
  1114. break;
  1115. case 2: // month in the middle (10 Jan 94)
  1116. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  1117. switch (DateFmt)
  1118. {
  1119. case MDY: // yes, "10-Jan-94" is valid
  1120. case DMY:
  1121. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1122. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1123. break;
  1124. case YMD:
  1125. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1126. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1127. break;
  1128. default:
  1129. res = FALSE;
  1130. break;
  1131. }
  1132. break;
  1133. default: // else, e.g. month at the end (94 10 Jan)
  1134. res = FALSE;
  1135. break;
  1136. } // switch (nMonthPos)
  1137. break;
  1138. default: // more than two numbers (31.12.94 8:23) (31.12. 8:23)
  1139. switch (nMonthPos) // where is the month
  1140. {
  1141. case 0: // not found
  1142. {
  1143. nCounter = 3;
  1144. if ( nTimePos > 1 )
  1145. { // find first time number index (should only be 3 or 2 anyway)
  1146. for ( USHORT j = 0; j < nAnzNums; j++ )
  1147. {
  1148. if ( nNums[j] == nTimePos - 2 )
  1149. {
  1150. nCounter = j;
  1151. break; // for
  1152. }
  1153. }
  1154. }
  1155. // ISO 8601 yyyy-mm-dd forced recognition
  1156. DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt);
  1157. switch (eDF)
  1158. {
  1159. case MDY:
  1160. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1161. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
  1162. if ( nCounter > 2 )
  1163. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
  1164. break;
  1165. case DMY:
  1166. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1167. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
  1168. if ( nCounter > 2 )
  1169. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
  1170. break;
  1171. case YMD:
  1172. if ( nCounter > 2 )
  1173. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
  1174. pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
  1175. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1176. break;
  1177. default:
  1178. res = FALSE;
  1179. break;
  1180. }
  1181. }
  1182. break;
  1183. case 1: // month at the beginning (Jan 01 01 8:23)
  1184. nCounter = 2;
  1185. switch (DateFmt)
  1186. {
  1187. case MDY:
  1188. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1189. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  1190. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1191. break;
  1192. default:
  1193. res = FALSE;
  1194. break;
  1195. }
  1196. break;
  1197. case 2: // month in the middle (10 Jan 94 8:23)
  1198. nCounter = 2;
  1199. pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
  1200. switch (DateFmt)
  1201. {
  1202. case DMY:
  1203. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
  1204. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
  1205. break;
  1206. case YMD:
  1207. pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
  1208. pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
  1209. break;
  1210. default:
  1211. res = FALSE;
  1212. break;
  1213. }
  1214. break;
  1215. default: // else, e.g. month at the end (94 10 Jan 8:23)
  1216. nCounter = 2;
  1217. res = FALSE;
  1218. break;
  1219. } // switch (nMonthPos)
  1220. break;
  1221. } // switch (nAnzNums)
  1222. if ( res && pCal->isValid() )
  1223. {
  1224. double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
  1225. fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
  1226. fDays -= fDiff;
  1227. nTryOrder = nFormatOrder; // break for
  1228. }
  1229. else
  1230. res = FALSE;
  1231. if ( aOrgCalendar.Len() )
  1232. pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() ); // restore calendar
  1233. #if NF_TEST_CALENDAR
  1234. {
  1235. using namespace ::com::sun::star;
  1236. struct entry { const char* lan; const char* cou; const char* cal; };
  1237. const entry cals[] = {
  1238. { "en", "US", "gregorian" },
  1239. { "ar", "TN", "hijri" },
  1240. { "he", "IL", "jewish" },
  1241. { "ja", "JP", "gengou" },
  1242. { "ko", "KR", "hanja_yoil" },
  1243. { "th", "TH", "buddhist" },
  1244. { "zh", "TW", "ROC" },
  1245. 0
  1246. };
  1247. lang::Locale aLocale;
  1248. sal_Bool bValid;
  1249. sal_Int16 nDay, nMonth, nYear, nHour, nMinute, nSecond;
  1250. sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
  1251. sal_Int16 nZO, nDST1, nDST2, nDST;
  1252. uno::Reference< lang::XMultiServiceFactory > xSMgr =
  1253. ::comphelper::getProcessServiceFactory();
  1254. uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal(
  1255. xSMgr->createInstance( ::rtl::OUString(
  1256. RTL_CONSTASCII_USTRINGPARAM(
  1257. "com.sun.star.i18n.LocaleCalendar" ) ) ),
  1258. uno::UNO_QUERY );
  1259. for ( const entry* p = cals; p->lan; ++p )
  1260. {
  1261. aLocale.Language = ::rtl::OUString::createFromAscii( p->lan );
  1262. aLocale.Country = ::rtl::OUString::createFromAscii( p->cou );
  1263. xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ),
  1264. aLocale );
  1265. double nDateTime = 0.0; // 1-Jan-1970 00:00:00
  1266. nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
  1267. nDST1 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
  1268. nDateTime -= (double)(nZO + nDST1) / 60.0 / 24.0;
  1269. xCal->setDateTime( nDateTime );
  1270. nDST2 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
  1271. if ( nDST1 != nDST2 )
  1272. {
  1273. nDateTime = 0.0 - (double)(nZO + nDST2) / 60.0 / 24.0;
  1274. xCal->setDateTime( nDateTime );
  1275. }
  1276. nDaySet = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
  1277. nMonthSet = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
  1278. nYearSet = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
  1279. nHourSet = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
  1280. nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
  1281. nSecondSet = xCal->getValue( i18n::CalendarFieldIndex

Large files files are truncated, but you can click here to view the full file