PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/libreoffice-3.6.0.2/binfilter/bf_svtools/source/numbers/svt_zforfind.cxx

#
C++ | 2764 lines | 2239 code | 232 blank | 293 comment | 740 complexity | 15df23e4228a9e85a566983858944ab7 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, AGPL-1.0, BSD-3-Clause-No-Nuclear-License-2014, GPL-3.0, LGPL-3.0

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

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

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