Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1633 lines
47 KiB

  1. #include "private.h"
  2. #include "sapilayr.h"
  3. #include "citn.h"
  4. #include "xstring.h"
  5. #include "winnls.h"
  6. #include "wchar.h"
  7. #define MILLION ((LONGLONG) 1000000)
  8. #define BILLION ((LONGLONG) 1000000000)
  9. #define MILLION_STR (L"million")
  10. #define BILLION_STR (L"billion")
  11. #define MANN ((LONGLONG) 10000)
  12. #define OKU ((LONGLONG) 100000000)
  13. #define CHUU ((LONGLONG) 1000000000000)
  14. #define MANN_STR (L"\x4E07")
  15. #define OKU_STR (L"\x5104")
  16. #define CHUU_STR (L"\x5146")
  17. HRESULT CSimpleITN::InterpretNumberEn
  18. (
  19. const SPPHRASEPROPERTY *pProperties,
  20. const bool fCardinal,
  21. DOUBLE *pdblVal,
  22. WCHAR *pszVal,
  23. UINT cSize,
  24. const bool fFinalDisplayFmt
  25. )
  26. {
  27. if ( !pdblVal || !pszVal || !pProperties)
  28. {
  29. return E_POINTER;
  30. }
  31. *pszVal = 0;
  32. int iPositive = 1;
  33. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  34. // Handle negatives
  35. if ( NEGATIVE == pFirstProp->ulId )
  36. {
  37. // There's no such thing as a negative ordinal
  38. SPDBG_ASSERT( fCardinal );
  39. // There had better be more stuff following
  40. SPDBG_ASSERT( pFirstProp->pNextSibling );
  41. iPositive = -1;
  42. pFirstProp = pFirstProp->pNextSibling;
  43. }
  44. if ( GRID_INTEGER_STANDALONE == pFirstProp->ulId )
  45. {
  46. // This is interger number
  47. TraceMsg(TF_GENERAL, "English Interger Number");
  48. SPDBG_ASSERT( pFirstProp->pFirstChild);
  49. pFirstProp = pFirstProp->pFirstChild;
  50. // Handle the "2.6 million" case, in which case the number
  51. // has already been formatted
  52. if ( GRID_INTEGER_MILLBILL == pFirstProp->ulId )
  53. {
  54. if ( pFirstProp->pszValue == NULL
  55. || cSize < (wcslen( pFirstProp->pszValue ) + 1) )
  56. {
  57. return E_INVALIDARG;
  58. }
  59. *pdblVal = pFirstProp->vValue.dblVal * iPositive;
  60. if ( iPositive < 0 )
  61. {
  62. StringCchCopyW( pszVal, cSize, m_pwszNeg );
  63. }
  64. StringCchCatW( pszVal, cSize, pFirstProp->pszValue );
  65. return S_OK;
  66. }
  67. else
  68. {
  69. BOOL fNegative;
  70. fNegative = (iPositive == -1);
  71. return InterpretIntegerEn(pFirstProp,
  72. fCardinal,
  73. pdblVal,
  74. pszVal,
  75. cSize,
  76. fFinalDisplayFmt,
  77. fNegative);
  78. }
  79. }
  80. else if ( GRID_FP_NUMBER == pFirstProp->ulId )
  81. {
  82. // This is decimal number
  83. TraceMsg(TF_GENERAL, "English Floating point (decimal) Number");
  84. SPDBG_ASSERT( pFirstProp->pFirstChild);
  85. pFirstProp = pFirstProp->pFirstChild;
  86. // todo for decimal number handling.
  87. return InterpretDecimalEn(pFirstProp,
  88. fCardinal,
  89. pdblVal,
  90. pszVal,
  91. cSize,
  92. fFinalDisplayFmt,
  93. (iPositive == -1) );
  94. }
  95. return S_OK;
  96. }
  97. HRESULT CSimpleITN::InterpretIntegerEn
  98. ( const SPPHRASEPROPERTY *pProperties,
  99. const bool fCardinal,
  100. DOUBLE *pdblVal,
  101. WCHAR *pszVal,
  102. UINT cSize,
  103. const bool fFinalDisplayFmt,
  104. BOOL fNegative)
  105. {
  106. HRESULT hr=S_OK;
  107. LONGLONG llValue = 0;
  108. if ( !pdblVal || !pszVal || !pProperties)
  109. {
  110. return E_POINTER;
  111. }
  112. *pszVal = 0;
  113. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  114. // Handle the digit-by-digit case
  115. if ( GRID_DIGIT_NUMBER == pFirstProp->ulId )
  116. {
  117. const SPPHRASEPROPERTY * pProp;
  118. int iNumDigit = 0;
  119. // iNumDigit is 1 means the current property is ONEDIGIT
  120. // iNumDigit is 2 means the current property is TWODIGIT.
  121. // llValue = llValue * ( 10 ^ iNumDigit ) + Value in current property
  122. for (pProp = pFirstProp->pFirstChild; pProp; pProp ? pProp = pProp->pNextSibling : NULL)
  123. {
  124. LONGLONG llValCurrent; // current property's value
  125. const SPPHRASEPROPERTY *pPropValue;
  126. switch ( pProp->ulId)
  127. {
  128. case ONEDIGIT:
  129. {
  130. ASSERT( pProp->pFirstChild );
  131. pPropValue = pProp->pFirstChild;
  132. ASSERT( VT_UI4 == pPropValue->vValue.vt );
  133. llValCurrent = pPropValue->vValue.ulVal;
  134. iNumDigit = 1;
  135. TraceMsg(TF_GENERAL, "ONEDIGIT: %d", llValCurrent);
  136. break;
  137. }
  138. case TWODIGIT :
  139. {
  140. ASSERT( pProp->pFirstChild );
  141. pPropValue = pProp->pFirstChild;
  142. TraceMsg(TF_GENERAL, "TWODIGIT:");
  143. if ( pPropValue->ulId == TENS )
  144. {
  145. const SPPHRASEPROPERTY *pPropOnes;
  146. ASSERT(pPropValue->pFirstChild);
  147. ASSERT( VT_UI4 == pPropValue->pFirstChild->vValue.vt );
  148. llValCurrent = pPropValue->vValue.ulVal * pPropValue->pFirstChild->vValue.ulVal;
  149. TraceMsg(TF_GENERAL, "TENS: %d", llValCurrent);
  150. pPropOnes = pPropValue->pNextSibling;
  151. if ( pPropOnes )
  152. {
  153. ASSERT(pPropOnes->pFirstChild);
  154. ASSERT( VT_UI4 == pPropOnes->pFirstChild->vValue.vt );
  155. llValCurrent += pPropOnes->pFirstChild->vValue.ulVal;
  156. TraceMsg(TF_GENERAL, "TENS: Second: %d", pPropOnes->pFirstChild->vValue.ulVal);
  157. }
  158. }
  159. else if ( pPropValue->ulId == TEENS )
  160. {
  161. ASSERT( pPropValue->pFirstChild );
  162. ASSERT( VT_UI4 == pPropValue->pFirstChild->vValue.vt );
  163. llValCurrent = pPropValue->pFirstChild->vValue.ulVal;
  164. TraceMsg(TF_GENERAL, "One Teens, %d", llValCurrent);
  165. }
  166. else
  167. {
  168. llValCurrent = 0;
  169. TraceMsg(TF_GENERAL, "Wrong ulIds");
  170. ASSERT(false);
  171. }
  172. iNumDigit = 2;
  173. break;
  174. }
  175. default :
  176. {
  177. iNumDigit = 0;
  178. llValCurrent = 0;
  179. TraceMsg(TF_GENERAL, "ulId error!");
  180. ASSERT(false);
  181. }
  182. }
  183. for (int i=0; i<iNumDigit; i++)
  184. llValue = llValue * 10;
  185. llValue += llValCurrent;
  186. TraceMsg(TF_GENERAL, "llValue=%d", llValue);
  187. }
  188. }
  189. else
  190. { for (const SPPHRASEPROPERTY * pProp = pFirstProp; pProp; pProp ? pProp = pProp->pNextSibling : NULL)
  191. {
  192. switch(pProp->ulId)
  193. {
  194. case ONES:
  195. {
  196. SPDBG_ASSERT(pProp->pFirstChild);
  197. llValue += ComputeNum999En( pProp->pFirstChild );
  198. }
  199. break;
  200. case THOUSANDS:
  201. {
  202. llValue += ComputeNum999En( pProp->pFirstChild ) * 1000;
  203. }
  204. break;
  205. case MILLIONS:
  206. {
  207. SPDBG_ASSERT(pProp->pFirstChild);
  208. llValue += ComputeNum999En( pProp->pFirstChild ) * (LONGLONG) 1e6;
  209. }
  210. break;
  211. case BILLIONS:
  212. {
  213. SPDBG_ASSERT(pProp->pFirstChild);
  214. llValue += ComputeNum999En( pProp->pFirstChild ) * (LONGLONG) 1e9;
  215. }
  216. break;
  217. case HUNDREDS:
  218. {
  219. SPDBG_ASSERT( pProp->pFirstChild );
  220. llValue += ComputeNum999En( pProp->pFirstChild ) * 100;
  221. }
  222. break;
  223. case TENS:
  224. default:
  225. SPDBG_ASSERT(false);
  226. }
  227. }
  228. }
  229. if ( fNegative )
  230. llValue *= (-1);
  231. *pdblVal = (DOUBLE) llValue;
  232. DWORD dwDisplayFlags = (fCardinal ? 0 : DF_ORDINAL)
  233. | (fFinalDisplayFmt ? DF_MILLIONBILLION : 0 );
  234. hr = MakeDisplayNumber( *pdblVal, dwDisplayFlags, 0, 0, pszVal, cSize );
  235. return hr;
  236. }
  237. HRESULT CSimpleITN::InterpretDecimalEn
  238. ( const SPPHRASEPROPERTY *pProperties,
  239. const bool fCardinal,
  240. DOUBLE *pdblVal,
  241. WCHAR *pszVal,
  242. UINT cSize,
  243. const bool fFinalDisplayFmt,
  244. BOOL fNegative)
  245. {
  246. HRESULT hr = S_OK;
  247. const SPPHRASEPROPERTY *pPropertiesFpPart = NULL;
  248. const SPPHRASEPROPERTY *pPropertiesPointZero = NULL;
  249. const SPPHRASEPROPERTY *pPropertiesOnes = NULL;
  250. const SPPHRASEPROPERTY *pPropertiesZero = NULL;
  251. const SPPHRASEPROPERTY *pPropertiesPtr;
  252. if ( !pdblVal || !pszVal || !pProperties)
  253. {
  254. return E_POINTER;
  255. }
  256. *pszVal = 0;
  257. for(pPropertiesPtr=pProperties; pPropertiesPtr; pPropertiesPtr=pPropertiesPtr->pNextSibling)
  258. {
  259. if (POINT_ZERO == pPropertiesPtr->ulId )
  260. pPropertiesPointZero = pPropertiesPtr;
  261. else if ( FP_PART == pPropertiesPtr->ulId )
  262. pPropertiesFpPart = pPropertiesPtr;
  263. else if (ONES == pPropertiesPtr->ulId )
  264. pPropertiesOnes = pPropertiesPtr;
  265. else if (ZERO == pPropertiesPtr->ulId )
  266. pPropertiesZero = pPropertiesPtr;
  267. }
  268. // Look for optional ONES (optional because you can say
  269. // "point five"
  270. if ( pPropertiesOnes )
  271. {
  272. SPDBG_ASSERT(pPropertiesOnes->pFirstChild);
  273. hr = InterpretIntegerEn( pPropertiesOnes->pFirstChild,
  274. fCardinal,
  275. pdblVal,
  276. pszVal,
  277. cSize,
  278. fFinalDisplayFmt,
  279. FALSE);
  280. }
  281. else if (pPropertiesZero || m_nmfmtDefault.LeadingZero )
  282. {
  283. // There should be a leading zero
  284. StringCchCopyW( pszVal, cSize, L"0" );
  285. }
  286. SPDBG_ASSERT(pPropertiesFpPart || pPropertiesPointZero);
  287. // Put in a decimal separator
  288. // Set m_nmfmtDefault.lpDecimalSep as L'.'
  289. if ( m_nmfmtDefault.lpDecimalSep )
  290. {
  291. if ( (cSize - wcslen( pszVal )) < (wcslen(m_nmfmtDefault.lpDecimalSep) + 1) )
  292. {
  293. return E_INVALIDARG;
  294. }
  295. StringCchCatW( pszVal, cSize, m_nmfmtDefault.lpDecimalSep);
  296. }
  297. if ( pPropertiesFpPart )
  298. {
  299. // Deal with the FP part, which will also have been ITNed correctly
  300. INT ulSize = cSize - wcslen(pszVal);
  301. if ( ulSize < 0 )
  302. return E_FAIL;
  303. WCHAR *pwszFpValue = new WCHAR[ulSize+1];
  304. DOUBLE dblFPPart;
  305. if (pwszFpValue)
  306. {
  307. hr = InterpretIntegerEn( pPropertiesFpPart->pFirstChild,
  308. fCardinal,
  309. &dblFPPart,
  310. pwszFpValue,
  311. ulSize,
  312. fFinalDisplayFmt,
  313. FALSE);
  314. if ( hr == S_OK )
  315. {
  316. StringCchCatW( pszVal, cSize, pwszFpValue);
  317. for ( UINT ui=0; ui < wcslen(pwszFpValue); ui++ )
  318. {
  319. dblFPPart /= (DOUBLE) 10;
  320. }
  321. *pdblVal += dblFPPart;
  322. }
  323. delete[] pwszFpValue;
  324. }
  325. else
  326. hr = E_OUTOFMEMORY;
  327. }
  328. else
  329. {
  330. // "point oh": The DOUBLE is already right, just add a "0"
  331. if ( (cSize - wcslen( pszVal )) < 2 )
  332. {
  333. return E_INVALIDARG;
  334. }
  335. StringCchCatW( pszVal, cSize, L"0" );
  336. }
  337. // Handle the negative sign
  338. if ( (hr == S_OK) && fNegative)
  339. {
  340. *pdblVal = -*pdblVal;
  341. if ( (cSize = wcslen( pszVal )) < 2 )
  342. {
  343. return E_INVALIDARG;
  344. }
  345. hr = MakeNumberNegative( pszVal, cSize );
  346. }
  347. return hr;
  348. }
  349. HRESULT CSimpleITN::MakeNumberNegative( WCHAR *pwszNumber, UINT cSize )
  350. {
  351. // Create a temporary buffer with the non-negated number in it
  352. if ( (pwszNumber == NULL) || (cSize == 0) )
  353. return E_POINTER;
  354. WCHAR *pwszTemp = _wcsdup( pwszNumber );
  355. if ( !pwszTemp )
  356. {
  357. return E_OUTOFMEMORY;
  358. }
  359. switch ( m_nmfmtDefault.NegativeOrder )
  360. {
  361. case 0:
  362. // (1.1)
  363. StringCchCopyW( pwszNumber, cSize, L"(" );
  364. StringCchCatW( pwszNumber, cSize, pwszTemp );
  365. StringCchCatW( pwszNumber, cSize, L")" );
  366. break;
  367. case 1: case 2:
  368. // 1: -1.1 2: - 1.1
  369. StringCchCopyW( pwszNumber, cSize, m_pwszNeg );
  370. if ( 2 == m_nmfmtDefault.NegativeOrder )
  371. {
  372. StringCchCatW( pwszNumber, cSize, L" " );
  373. }
  374. StringCchCatW( pwszNumber, cSize, pwszTemp );
  375. break;
  376. case 3: case 4:
  377. // 3: 1.1- 4: 1.1 -
  378. StringCchCopyW( pwszNumber, cSize, pwszTemp );
  379. if ( 4 == m_nmfmtDefault.NegativeOrder )
  380. {
  381. StringCchCatW( pwszNumber, cSize, L" " );
  382. }
  383. StringCchCatW( pwszNumber, cSize, m_pwszNeg );
  384. break;
  385. default:
  386. SPDBG_ASSERT( false );
  387. break;
  388. }
  389. free( pwszTemp );
  390. return S_OK;
  391. } /* CTestITN::MakeNumberNegative */
  392. /***********************************************************************
  393. * _EnsureNumberFormatDefaults
  394. *
  395. * Description:
  396. * This finds all of the defaults for formatting numbers for
  397. * this user.
  398. *************************************************************************/
  399. HRESULT CSimpleITN::_EnsureNumberFormatDefaults()
  400. {
  401. LCID lcid = MAKELCID(m_langid, SORT_DEFAULT);
  402. if (m_pwszNeg != NULL) return S_OK;
  403. //
  404. // we use ansi version so we can run on win9x too
  405. //
  406. CHAR szLocaleData[16];
  407. int iRet = GetLocaleInfoA( lcid, LOCALE_IDIGITS, szLocaleData, ARRAYSIZE(szLocaleData) );
  408. if ( !iRet )
  409. {
  410. return E_FAIL;
  411. }
  412. m_nmfmtDefault.NumDigits = atoi( szLocaleData );
  413. iRet = GetLocaleInfoA( lcid, LOCALE_ILZERO, szLocaleData, ARRAYSIZE(szLocaleData) );
  414. if ( !iRet )
  415. {
  416. return E_FAIL;
  417. }
  418. // It's always either 0 or 1
  419. m_nmfmtDefault.LeadingZero = atoi( szLocaleData );
  420. iRet = GetLocaleInfoA( lcid, LOCALE_SGROUPING, szLocaleData, ARRAYSIZE(szLocaleData) );
  421. if ( !iRet )
  422. {
  423. return E_FAIL;
  424. }
  425. // It will look like single_digit;0, or else it will look like
  426. // 3;2;0
  427. UINT uiGrouping = *szLocaleData - '0';
  428. if ( (3 == uiGrouping) && (';' == szLocaleData[1]) && ('2' == szLocaleData[2]) )
  429. {
  430. uiGrouping = 32;
  431. }
  432. m_nmfmtDefault.Grouping = uiGrouping;
  433. iRet = GetLocaleInfoA( lcid, LOCALE_INEGNUMBER, szLocaleData, ARRAYSIZE(szLocaleData) );
  434. if ( !iRet )
  435. {
  436. return E_FAIL;
  437. }
  438. m_nmfmtDefault.NegativeOrder = atoi( szLocaleData );
  439. // Get the negative sign
  440. iRet = GetLocaleInfoA( lcid, LOCALE_SNEGATIVESIGN, NULL, 0);
  441. if ( !iRet )
  442. {
  443. return E_FAIL;
  444. }
  445. CHAR szNeg[16];
  446. Assert(iRet < 8);
  447. int iLenNeg = iRet + 1;
  448. m_pwszNeg = new WCHAR[ iLenNeg ];
  449. if ( m_pwszNeg == NULL )
  450. {
  451. return E_OUTOFMEMORY;
  452. }
  453. iRet = GetLocaleInfoA( lcid, LOCALE_SNEGATIVESIGN, szNeg, iRet );
  454. StringCchCopyW(m_pwszNeg, iLenNeg, AtoW(szNeg));
  455. iRet = GetLocaleInfoA( lcid, LOCALE_SDECIMAL, NULL, 0);
  456. if ( !iRet )
  457. return E_FAIL;
  458. Assert(iRet < 16);
  459. if ( m_nmfmtDefault.lpDecimalSep )
  460. {
  461. delete[] m_nmfmtDefault.lpDecimalSep;
  462. m_nmfmtDefault.lpDecimalSep = NULL;
  463. }
  464. int iDecSepLen = iRet + 1;
  465. m_nmfmtDefault.lpDecimalSep = new WCHAR[ iDecSepLen ];
  466. if ( m_nmfmtDefault.lpDecimalSep == NULL )
  467. {
  468. return E_OUTOFMEMORY;
  469. }
  470. iRet = GetLocaleInfoA( lcid, LOCALE_SDECIMAL, szNeg, iRet );
  471. StringCchCopyW(m_nmfmtDefault.lpDecimalSep, iDecSepLen, AtoW(szNeg));
  472. iRet = GetLocaleInfoA( lcid, LOCALE_STHOUSAND, NULL, 0);
  473. if ( !iRet )
  474. return E_FAIL;
  475. Assert(iRet < 16);
  476. if ( m_nmfmtDefault.lpThousandSep )
  477. {
  478. delete[] m_nmfmtDefault.lpThousandSep;
  479. m_nmfmtDefault.lpThousandSep = NULL;
  480. }
  481. int iThousSepLen = iRet + 1;
  482. m_nmfmtDefault.lpThousandSep = new WCHAR[ iThousSepLen ];
  483. if ( m_nmfmtDefault.lpThousandSep == NULL )
  484. {
  485. return E_OUTOFMEMORY;
  486. }
  487. iRet = GetLocaleInfoA( lcid, LOCALE_STHOUSAND, szNeg, iRet );
  488. StringCchCopyW(m_nmfmtDefault.lpThousandSep, iThousSepLen, AtoW(szNeg));
  489. return iRet ? S_OK : E_FAIL;
  490. }
  491. /***********************************************************************
  492. * MakeDisplayNumber
  493. *
  494. * Description:
  495. * Converts a DOUBLE into a displayable
  496. * number in the range -999,999,999,999 to +999,999,999,999.
  497. * cSize is the number of chars for which pwszNum has space
  498. * allocated.
  499. * If DF_UNFORMATTED is set, all other flags are ignored,
  500. * and the number is passed back as an optional negative
  501. * followed by a string of digits
  502. * If DF_ORDINAL is set in dwDisplayFlags, displays an
  503. * ordinal number (i.e. tacks on "th" or the appropriate suffix.
  504. * If DF_WHOLENUMBER is set, lops off the decimal separator
  505. * and everything after it. If DF_WHOLENUMBER is not set,
  506. * then uses the uiDecimalPlaces parameter to determine
  507. * how many decimal places to display
  508. * If DF_FIXEDWIDTH is set, will display at least uiFixedWidth
  509. * digits; otherwise uiFixedWidth is ignored.
  510. * If DF_NOTHOUSANDSGROUP is set, will not do thousands
  511. * grouping (commas)
  512. *************************************************************************/
  513. HRESULT CSimpleITN::MakeDisplayNumber(DOUBLE dblNum,
  514. DWORD dwDisplayFlags,
  515. UINT uiFixedWidth,
  516. UINT uiDecimalPlaces,
  517. WCHAR *pwszNum,
  518. UINT cSize )
  519. {
  520. SPDBG_ASSERT( pwszNum );
  521. SPDBG_ASSERT( !SPIsBadWritePtr( pwszNum, cSize ) );
  522. *pwszNum = 0;
  523. // Get the default number formatting.
  524. // Note that this gets called every time, since otherwise there
  525. // is no way to pick up changes that the user has made since
  526. // this process has started.
  527. HRESULT hr = _EnsureNumberFormatDefaults();
  528. if ( FAILED( hr ) )
  529. {
  530. return hr;
  531. }
  532. // check for straight millions and straight billions
  533. // This is a workaround for the fact that we can't resolve the ambiguity
  534. // and get "two million" to go through GRID_INTEGER_MILLBILL
  535. if ( m_langid != 0x0411 )
  536. {
  537. if (( dwDisplayFlags & DF_WHOLENUMBER ) && ( dwDisplayFlags & DF_MILLIONBILLION ) && (dblNum > 0))
  538. {
  539. if ( 0 == (( ((LONGLONG) dblNum) % BILLION )) )
  540. {
  541. // e.g. for "five billion" get the "5" and then
  542. // tack on " billion"
  543. hr = MakeDisplayNumber( ( dblNum / ((DOUBLE) BILLION) ),
  544. dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pwszNum, cSize );
  545. if ( SUCCEEDED( hr ) )
  546. {
  547. StringCchCatW( pwszNum, cSize, L" " );
  548. StringCchCatW( pwszNum, cSize, BILLION_STR );
  549. }
  550. return hr;
  551. }
  552. else if (( ((LONGLONG) dblNum) < BILLION ) &&
  553. ( 0 == (( ((LONGLONG) dblNum) % MILLION )) ))
  554. {
  555. hr = MakeDisplayNumber( ( dblNum / ((DOUBLE) MILLION) ),
  556. dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pwszNum, cSize );
  557. if ( SUCCEEDED( hr ) )
  558. {
  559. StringCchCatW( pwszNum, cSize, L" " );
  560. StringCchCatW( pwszNum, cSize, MILLION_STR );
  561. }
  562. return hr;
  563. }
  564. }
  565. }
  566. else
  567. {
  568. if (( dwDisplayFlags & DF_WHOLENUMBER ) && (dblNum > 0))
  569. {
  570. if ( 0 == (( ((LONGLONG) dblNum) % CHUU )) )
  571. {
  572. hr = MakeDisplayNumber( ( dblNum / ((DOUBLE) CHUU) ),
  573. dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pwszNum, cSize);
  574. if ( SUCCEEDED( hr ) )
  575. {
  576. StringCchCatW( pwszNum, cSize, CHUU_STR );
  577. }
  578. return hr;
  579. }
  580. else if (( ((LONGLONG) dblNum) < CHUU ) &&
  581. ( 0 == (( ((LONGLONG) dblNum) % OKU )) ))
  582. {
  583. hr = MakeDisplayNumber( ( dblNum / ((DOUBLE) OKU) ),
  584. dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pwszNum, cSize);
  585. if ( SUCCEEDED( hr ) )
  586. {
  587. StringCchCatW( pwszNum, cSize, OKU_STR );
  588. }
  589. return hr;
  590. }
  591. else if (( ((LONGLONG) dblNum) < OKU ) &&
  592. ( 0 == (( ((LONGLONG) dblNum) % MANN )) ))
  593. {
  594. hr = MakeDisplayNumber( ( dblNum / ((DOUBLE) MANN) ),
  595. dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pwszNum, cSize);
  596. if ( SUCCEEDED( hr ) )
  597. {
  598. StringCchCatW( pwszNum, cSize, MANN_STR );
  599. }
  600. return hr;
  601. }
  602. }
  603. }
  604. // Put in the negative sign if necessary
  605. if ( dblNum < 0 )
  606. {
  607. StringCchCatW( pwszNum, cSize, L"-" );
  608. // From now on we want to deal with the magnitude of the number
  609. dblNum *= -1;
  610. }
  611. SPDBG_ASSERT(m_langid == 0x411 ? dblNum < 1e16 : dblNum < 1e12 );
  612. WCHAR *pwszTemp = new WCHAR[ cSize ];
  613. if ( !pwszTemp )
  614. {
  615. return E_OUTOFMEMORY;
  616. }
  617. *pwszTemp = 0;
  618. LONGLONG llIntPart = (LONGLONG) dblNum;
  619. UINT64 uiDigitsLeftOfDecimal;
  620. if ( dwDisplayFlags & DF_WHOLENUMBER )
  621. {
  622. StringCchPrintfW( pwszTemp, cSize, L"%I64d", llIntPart );
  623. uiDigitsLeftOfDecimal = wcslen( pwszTemp );
  624. }
  625. else
  626. {
  627. StringCchPrintfW( pwszTemp, cSize, L"%.*f", uiDecimalPlaces, dblNum );
  628. WCHAR *pwc = wcschr( pwszTemp, L'.' );
  629. uiDigitsLeftOfDecimal = pwc - pwszTemp;
  630. }
  631. // The following handles the case where the user said something
  632. // like "zero zero zero three" and wants to see "0,003"
  633. BOOL fChangedFirstDigit = false;
  634. const WCHAR wcFakeFirstDigit = L'1';
  635. if ( !(dwDisplayFlags & DF_UNFORMATTED) &&
  636. (dwDisplayFlags & DF_FIXEDWIDTH) && (uiDigitsLeftOfDecimal < uiFixedWidth) )
  637. {
  638. // The following handles the case where the user wants leading
  639. // zeroes displayed
  640. // Need to pad the front with zeroes
  641. for ( UINT ui = 0; ui < (uiFixedWidth - uiDigitsLeftOfDecimal); ui++ )
  642. {
  643. StringCchCatW( pwszNum, cSize, L"0" );
  644. }
  645. // HACK
  646. // In order to force something like "zero zero zero three"
  647. // into the form "0,003", we need to make GetNumberFormat()
  648. // think that the first digit is 1.
  649. WCHAR *pwc = wcschr( pwszNum, L'0' );
  650. SPDBG_ASSERT( pwc );
  651. *pwc = wcFakeFirstDigit;
  652. fChangedFirstDigit = true;
  653. }
  654. // Copy over the unformatted number after the possible negative sign
  655. StringCchCatW( pwszNum, cSize, pwszTemp );
  656. delete[] pwszTemp;
  657. // If we do not want to format the number, then bail here
  658. if ( dwDisplayFlags & DF_UNFORMATTED )
  659. {
  660. return S_OK;
  661. }
  662. // Make a copy so that we can change some fields according to the
  663. // flags param
  664. NUMBERFMTW nmfmt = m_nmfmtDefault;
  665. // How many decimal places to display?
  666. if ( dwDisplayFlags & DF_WHOLENUMBER )
  667. {
  668. nmfmt.NumDigits = 0;
  669. }
  670. else
  671. {
  672. // Use the uiDecimalPlaces value to determine how
  673. // many to display
  674. nmfmt.NumDigits = uiDecimalPlaces;
  675. }
  676. // Leading zeroes?
  677. nmfmt.LeadingZero = (dwDisplayFlags & DF_LEADINGZERO) ? 1 : 0;
  678. // Thousands grouping?
  679. if ( dwDisplayFlags & DF_NOTHOUSANDSGROUP )
  680. {
  681. nmfmt.Grouping = 0;
  682. }
  683. #if 0
  684. if ( m_langid == 0x411)
  685. {
  686. // Format the number string
  687. WCHAR *pwszFormattedNum = new WCHAR[ cSize ];
  688. if ( !pwszFormattedNum )
  689. {
  690. return E_OUTOFMEMORY;
  691. }
  692. *pwszFormattedNum = 0;
  693. int iRet;
  694. do
  695. {
  696. iRet = GetNumberFormatW( m_langid, 0, pwszNum, &nmfmt, pwszFormattedNum, cSize );
  697. if ( !iRet && nmfmt.NumDigits )
  698. {
  699. // Try displaying fewer digits
  700. nmfmt.NumDigits--;
  701. }
  702. } while ( !iRet && nmfmt.NumDigits );
  703. SPDBG_ASSERT( iRet );
  704. // Copy the formatted number into pwszNum
  705. StringCchCopyW( pwszNum, cSize, pwszFormattedNum );
  706. delete[] pwszFormattedNum;
  707. }
  708. #endif
  709. // This undoes the hack of changing the first digit
  710. if ( fChangedFirstDigit )
  711. {
  712. // We need to find the first digit and change it back to zero
  713. WCHAR *pwc = wcschr( pwszNum, wcFakeFirstDigit );
  714. SPDBG_ASSERT( pwc );
  715. *pwc = L'0';
  716. }
  717. if ( dwDisplayFlags & DF_ORDINAL )
  718. {
  719. SPDBG_ASSERT( dwDisplayFlags & DF_WHOLENUMBER ); // sanity
  720. // This is an ordinal number, tack on the appropriate suffix
  721. // The "st", "nd", "rd" endings only happen when you
  722. // don't have something like "twelfth"
  723. if ( ((llIntPart % 100) < 10) || ((llIntPart % 100) > 20) )
  724. {
  725. switch ( llIntPart % 10 )
  726. {
  727. case 1:
  728. StringCchCatW( pwszNum, cSize, L"st" );
  729. break;
  730. case 2:
  731. StringCchCatW( pwszNum, cSize, L"nd" );
  732. break;
  733. case 3:
  734. StringCchCatW( pwszNum, cSize, L"rd" );
  735. break;
  736. default:
  737. StringCchCatW( pwszNum, cSize, L"th" );
  738. break;
  739. }
  740. }
  741. else
  742. {
  743. StringCchCatW( pwszNum, cSize, L"th" );
  744. }
  745. }
  746. return S_OK;
  747. } /* MakeDisplayNumber */
  748. /***********************************************************************
  749. * ComputeNum999
  750. *
  751. * Description:
  752. * Converts a set of SPPHRASEPROPERTYs into a number in
  753. * [-999, 999].
  754. * The way these properties is structured is that the top-level
  755. * properties contain the place of the number (100s, 10s, 1s)
  756. * by having the value 100, 10, or 1.
  757. * The child has the appropriate number value.
  758. * Return:
  759. * Value of the number
  760. *************************************************************************/
  761. ULONG CSimpleITN::ComputeNum999En(const SPPHRASEPROPERTY *pProperties )
  762. {
  763. ULONG ulVal = 0;
  764. if ( pProperties == NULL )
  765. return ulVal;
  766. for (const SPPHRASEPROPERTY * pProp = pProperties; pProp; pProp = pProp->pNextSibling)
  767. {
  768. if ( ZERO != pProp->ulId )
  769. {
  770. SPDBG_ASSERT( pProp->pFirstChild );
  771. SPDBG_ASSERT( VT_UI4 == pProp->vValue.vt );
  772. SPDBG_ASSERT( VT_UI4 == pProp->pFirstChild->vValue.vt );
  773. ulVal += pProp->pFirstChild->vValue.ulVal * pProp->vValue.ulVal;
  774. }
  775. }
  776. return ulVal;
  777. }
  778. // assume that we have only THOUSANDS(qian), HUNDREDS(bai), TENS(shi), and ONES(ge) here!!
  779. ULONG CSimpleITN::ComputeNum9999Ch(const SPPHRASEPROPERTY *pProperties)
  780. {
  781. ULONG ulVal = 0;
  782. if ( !pProperties )
  783. return ulVal;
  784. if (pProperties->pFirstChild)
  785. {
  786. for (const SPPHRASEPROPERTY * pProp = pProperties; pProp; pProp = pProp->pNextSibling)
  787. {
  788. if ( 0 != pProp->ulId )
  789. {
  790. SPDBG_ASSERT( pProp->pFirstChild );
  791. SPDBG_ASSERT( VT_UI4 == pProp->vValue.vt );
  792. SPDBG_ASSERT( VT_UI4 == pProp->pFirstChild->vValue.vt );
  793. ulVal += pProp->pFirstChild->vValue.ulVal * pProp->vValue.ulVal;
  794. }
  795. }
  796. }
  797. return ulVal;
  798. }
  799. ULONG CSimpleITN::ComputeNum10000Ch(const SPPHRASEPROPERTY *pProperties)
  800. {
  801. ULONG ulVal = 0;
  802. WCHAR * pszStopped;
  803. if ( !pProperties )
  804. return ulVal;
  805. ulVal = wcstol(pProperties->pszValue, &pszStopped, 10);
  806. return ulVal;
  807. }
  808. HRESULT CSimpleITN::InterpretNumberCh(const SPPHRASEPROPERTY *pProperties,
  809. const bool fCardinal,
  810. DOUBLE *pdblVal,
  811. WCHAR *pszVal,
  812. UINT cSize,
  813. const bool fFinalDisplayFmt)
  814. {
  815. HRESULT hr = S_OK;
  816. if ( !pdblVal || !pszVal || !pProperties)
  817. {
  818. return E_POINTER;
  819. }
  820. *pszVal = 0;
  821. BOOL fNegative = FALSE;
  822. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  823. // Handle negatives
  824. if ( CHS_NEGATIVE == pFirstProp->ulId )
  825. {
  826. // There had better be more stuff following
  827. SPDBG_ASSERT( pFirstProp->pNextSibling );
  828. fNegative = TRUE;
  829. pFirstProp = pFirstProp->pNextSibling;
  830. TraceMsg(TF_GENERAL, "This is a minus number");
  831. }
  832. if ( pFirstProp->ulId == CHS_GRID_NUMBER )
  833. {
  834. TraceMsg(TF_GENERAL, "Number is interger");
  835. SPDBG_ASSERT(pFirstProp->pFirstChild);
  836. pFirstProp = pFirstProp->pFirstChild;
  837. hr = InterpretIntegerCh(pFirstProp,
  838. fCardinal,
  839. pdblVal,
  840. pszVal,
  841. cSize,
  842. fFinalDisplayFmt,
  843. fNegative);
  844. }
  845. else if ( pFirstProp->ulId == CHS_GRID_DECIMAL )
  846. {
  847. TraceMsg(TF_GENERAL, "Number is floating pointer decimal");
  848. SPDBG_ASSERT(pFirstProp->pFirstChild);
  849. pFirstProp = pFirstProp->pFirstChild;
  850. hr = InterpretDecimalCh(pFirstProp,
  851. fCardinal,
  852. pdblVal,
  853. pszVal,
  854. cSize,
  855. fFinalDisplayFmt,
  856. fNegative);
  857. }
  858. return hr;
  859. }
  860. HRESULT CSimpleITN::InterpretIntegerCh
  861. ( const SPPHRASEPROPERTY *pProperties,
  862. const bool fCardinal,
  863. DOUBLE *pdblVal,
  864. WCHAR *pszVal,
  865. UINT cSize,
  866. const bool fFinalDisplayFmt,
  867. BOOL fNegative)
  868. {
  869. __int64 ulValue = 0;
  870. ULONG ulLength = 0;
  871. HRESULT hr = S_OK;
  872. if ( !pdblVal || !pszVal || !pProperties)
  873. {
  874. return E_POINTER;
  875. }
  876. *pszVal = 0;
  877. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  878. if ( pFirstProp->ulId == CHS_DIGITS )
  879. {
  880. // This must be digit-by-digit case, specially handle it here.
  881. for(const SPPHRASEPROPERTY * pProp=pFirstProp; pProp; pProp=pProp->pNextSibling)
  882. {
  883. ASSERT( pProp->ulId == CHS_DIGITS );
  884. ASSERT( VT_UI4 == pProp->vValue.vt );
  885. ulValue = ulValue * 10 + pProp->vValue.ulVal;
  886. }
  887. }
  888. else
  889. {
  890. for (const SPPHRASEPROPERTY * pProp = pFirstProp; pProp; pProp ? pProp = pProp->pNextSibling : NULL)
  891. {
  892. switch(pProp->ulId)
  893. {
  894. case CHS_TENTHOUSANDS_:
  895. {
  896. __int64 v1 = 0;
  897. _ASSERT(pProp);
  898. SPDBG_ASSERT(pProp);
  899. v1 = (__int64) ComputeNum10000Ch(pProp);
  900. ulValue += v1 * 10000;
  901. }
  902. break;
  903. case CHS_TENTHOUSANDS:
  904. {
  905. __int64 v1 = 0;
  906. _ASSERT(pProp->pFirstChild);
  907. SPDBG_ASSERT(pProp->pFirstChild);
  908. v1 = (__int64) ComputeNum9999Ch(pProp->pFirstChild);
  909. ulValue += v1 * 10000;
  910. }
  911. break;
  912. case CHS_HUNDREDMILLIONS:
  913. {
  914. __int64 v1 = 0;
  915. _ASSERT(pProp->pFirstChild);
  916. SPDBG_ASSERT(pProp->pFirstChild);
  917. v1 = (__int64) ComputeNum9999Ch(pProp->pFirstChild);
  918. ulValue += v1 * 100000000;
  919. }
  920. break;
  921. case CHS_ONES:
  922. {
  923. __int64 v1 = 0;
  924. SPDBG_ASSERT(pProp->pFirstChild);
  925. v1 = (__int64) ComputeNum9999Ch(pProp->pFirstChild);
  926. ulValue += v1;
  927. pProp = NULL;
  928. }
  929. break;
  930. case CHS_ONES_THOUSANDS:
  931. {
  932. SPDBG_ASSERT(pProp->pFirstChild);
  933. ulValue += pProp->pFirstChild->vValue.ulVal;
  934. pProp = NULL;
  935. }
  936. break;
  937. case CHS_THOUSANDS:
  938. case CHS_HUNDREDS:
  939. default:
  940. _ASSERT(false);
  941. SPDBG_ASSERT(false);
  942. }
  943. }
  944. }
  945. if ( fNegative )
  946. ulValue *= (-1);
  947. *pdblVal = (DOUBLE) ulValue;
  948. DWORD dwDisplayFlags = (fCardinal ? 0 : DF_ORDINAL);
  949. return MakeDisplayNumber( *pdblVal, dwDisplayFlags, 0, 0, pszVal, cSize );
  950. }
  951. HRESULT CSimpleITN::InterpretDecimalCh
  952. ( const SPPHRASEPROPERTY *pProperties,
  953. const bool fCardinal,
  954. DOUBLE *pdblVal,
  955. WCHAR *pszVal,
  956. UINT cSize,
  957. const bool fFinalDisplayFmt,
  958. BOOL fNegative)
  959. {
  960. HRESULT hr = S_OK;
  961. const SPPHRASEPROPERTY *pPropertiesInteger = NULL;
  962. const SPPHRASEPROPERTY *pPropertiesPtr;
  963. if ( !pdblVal || !pszVal || !pProperties)
  964. {
  965. return E_POINTER;
  966. }
  967. *pszVal = 0;
  968. pPropertiesPtr = pProperties;
  969. SPDBG_ASSERT( pPropertiesPtr->ulId == CHS_INTEGER);
  970. pPropertiesInteger = pPropertiesPtr;
  971. SPDBG_ASSERT(pPropertiesInteger->pFirstChild);
  972. hr = InterpretIntegerCh( pPropertiesInteger->pFirstChild,
  973. fCardinal,
  974. pdblVal,
  975. pszVal,
  976. cSize,
  977. fFinalDisplayFmt,
  978. FALSE);
  979. if ( hr == S_OK )
  980. {
  981. // Put in a decimal separator
  982. if ( m_nmfmtDefault.lpDecimalSep )
  983. {
  984. if ( (cSize - wcslen( pszVal )) < (wcslen(m_nmfmtDefault.lpDecimalSep) + 1) )
  985. {
  986. return E_INVALIDARG;
  987. }
  988. StringCchCatW( pszVal, cSize, m_nmfmtDefault.lpDecimalSep);
  989. }
  990. // Deal with the FP part, which will also have been ITNed correctly
  991. INT ulSize = cSize - wcslen(pszVal);
  992. if ( ulSize < 0 )
  993. return E_FAIL;
  994. WCHAR *pwszFpValue = new WCHAR[ulSize+1];
  995. if ( pwszFpValue )
  996. {
  997. DOUBLE dblFPPart = 0;
  998. for(pPropertiesPtr=pPropertiesPtr->pNextSibling; pPropertiesPtr; pPropertiesPtr=pPropertiesPtr->pNextSibling)
  999. {
  1000. if ( pPropertiesPtr->ulId == CHS_DIGITS )
  1001. {
  1002. SPDBG_ASSERT( VT_UI4 == pPropertiesPtr->vValue.vt );
  1003. dblFPPart = dblFPPart * 10 + pPropertiesPtr->vValue.ulVal;
  1004. StringCchCatW(pwszFpValue, ulSize + 1, pPropertiesPtr->pszValue);
  1005. }
  1006. }
  1007. StringCchCatW( pszVal, cSize, pwszFpValue);
  1008. for ( UINT ui=0; ui < wcslen(pwszFpValue); ui++ )
  1009. {
  1010. dblFPPart /= (DOUBLE) 10;
  1011. }
  1012. *pdblVal += dblFPPart;
  1013. delete[] pwszFpValue;
  1014. }
  1015. else
  1016. hr = E_OUTOFMEMORY;
  1017. }
  1018. // Handle the negative sign
  1019. if ( (hr == S_OK) && fNegative)
  1020. {
  1021. *pdblVal = -*pdblVal;
  1022. if ( (cSize = wcslen( pszVal )) < 2 )
  1023. {
  1024. return E_INVALIDARG;
  1025. }
  1026. hr = MakeNumberNegative( pszVal, cSize );
  1027. }
  1028. return hr;
  1029. }
  1030. // For Japanese.
  1031. /***********************************************************************
  1032. * CSimpleITN::InterpretNumberJp *
  1033. *-----------------------------*
  1034. * Description:
  1035. * Interprets a number in the range -999,999,999,999 to
  1036. * +999,999,999,999 and sends the properties and
  1037. * replacements to the CFGInterpreterSite as appropriate.
  1038. * The property will be added and the pszValue will be a string
  1039. * with the correct display number.
  1040. * If fCardinal is set, makes the display a cardinal number;
  1041. * otherwise makes it an ordinal number.
  1042. * The number will be formatted only if it was a properly-formed
  1043. * number (not given digit by digit).
  1044. * Result:
  1045. *************************************************************************/
  1046. HRESULT CSimpleITN::InterpretNumberJp(const SPPHRASEPROPERTY *pProperties,
  1047. const bool fCardinal,
  1048. DOUBLE *pdblVal,
  1049. WCHAR *pszVal,
  1050. UINT cSize,
  1051. const bool fFinalDisplayFmt)
  1052. {
  1053. HRESULT hr = S_OK;
  1054. if ( !pdblVal || !pszVal || !pProperties)
  1055. {
  1056. return E_POINTER;
  1057. }
  1058. *pszVal = 0;
  1059. BOOL fNegative = FALSE;
  1060. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  1061. // Handle negatives
  1062. if ( JPN_NEGATIVE == pFirstProp->ulId )
  1063. {
  1064. // There's no such thing as a negative ordinal
  1065. SPDBG_ASSERT( fCardinal );
  1066. // There had better be more stuff following
  1067. SPDBG_ASSERT( pFirstProp->pNextSibling );
  1068. fNegative = TRUE;
  1069. pFirstProp = pFirstProp->pNextSibling;
  1070. }
  1071. if ( pFirstProp->ulId == JPN_GRID_INTEGER_STANDALONE )
  1072. {
  1073. TraceMsg(TF_GENERAL, "Number is Japanese Interger");
  1074. SPDBG_ASSERT(pFirstProp->pFirstChild);
  1075. pFirstProp = pFirstProp->pFirstChild;
  1076. hr = InterpretIntegerJp(pFirstProp,
  1077. fCardinal,
  1078. pdblVal,
  1079. pszVal,
  1080. cSize,
  1081. fFinalDisplayFmt,
  1082. fNegative);
  1083. }
  1084. else
  1085. {
  1086. TraceMsg(TF_GENERAL, "Number is Japanese Floating pointer number");
  1087. SPDBG_ASSERT(pFirstProp->pFirstChild);
  1088. pFirstProp = pFirstProp->pFirstChild;
  1089. hr = InterpretDecimalJp(pFirstProp,
  1090. fCardinal,
  1091. pdblVal,
  1092. pszVal,
  1093. cSize,
  1094. fFinalDisplayFmt,
  1095. fNegative);
  1096. }
  1097. return hr;
  1098. } /* CSimpleITN::InterpretNumberJp */
  1099. /***********************************************************************
  1100. * ComputeNum9999Jp *
  1101. *----------------*
  1102. * Description:
  1103. * Converts a set of SPPHRASEPROPERTYs into a number in
  1104. * [-9999, 9999].
  1105. * The way these properties is structured is that the top-level
  1106. * properties contain the place of the number (100s, 10s, 1s)
  1107. * by having the value 100, 10, or 1.
  1108. * The child has the appropriate number value.
  1109. * Return:
  1110. * Value of the number
  1111. *************************************************************************/
  1112. ULONG CSimpleITN::ComputeNum9999Jp(const SPPHRASEPROPERTY *pProperties )//, ULONG *pVal)
  1113. {
  1114. ULONG ulVal = 0;
  1115. if ( !pProperties )
  1116. return ulVal;
  1117. for (const SPPHRASEPROPERTY * pProp = pProperties; pProp; pProp = pProp->pNextSibling)
  1118. {
  1119. if ( JPN_ZERO != pProp->ulId )
  1120. {
  1121. SPDBG_ASSERT( VT_UI4 == pProp->vValue.vt );
  1122. ulVal += pProp->vValue.ulVal;
  1123. }
  1124. }
  1125. return ulVal;
  1126. } /* ComputeNum9999Jp */
  1127. HRESULT CSimpleITN::InterpretIntegerJp
  1128. ( const SPPHRASEPROPERTY *pProperties,
  1129. const bool fCardinal,
  1130. DOUBLE *pdblVal,
  1131. WCHAR *pszVal,
  1132. UINT cSize,
  1133. const bool fFinalDisplayFmt,
  1134. BOOL fNegative)
  1135. {
  1136. HRESULT hr = S_OK;
  1137. if ( !pdblVal || !pszVal || !pProperties)
  1138. {
  1139. return E_POINTER;
  1140. }
  1141. *pszVal = 0;
  1142. LONGLONG llValue = 0;
  1143. const SPPHRASEPROPERTY *pFirstProp = pProperties;
  1144. // Handle the digit-by-digit case
  1145. if ( JPN_GRID_DIGIT_NUMBER == pFirstProp->ulId )
  1146. {
  1147. UINT uiFixedWidth = 0;
  1148. DOUBLE dblVal = 0;
  1149. for(const SPPHRASEPROPERTY * pPropertiesPtr=pFirstProp->pFirstChild; pPropertiesPtr; pPropertiesPtr=pPropertiesPtr->pNextSibling)
  1150. {
  1151. if ( pPropertiesPtr->ulId == JPN_DIGIT )
  1152. {
  1153. SPDBG_ASSERT( VT_UI4 == pPropertiesPtr->vValue.vt );
  1154. dblVal = dblVal * 10 + pPropertiesPtr->vValue.ulVal;
  1155. uiFixedWidth ++;
  1156. }
  1157. }
  1158. if ( fNegative )
  1159. dblVal *= (-1);
  1160. *pdblVal = dblVal;
  1161. DWORD dwDisplayFlags = DF_WHOLENUMBER | DF_FIXEDWIDTH | DF_NOTHOUSANDSGROUP;
  1162. return MakeDisplayNumber( *pdblVal, dwDisplayFlags,
  1163. uiFixedWidth, 0, pszVal, MAX_PATH);
  1164. }
  1165. for (const SPPHRASEPROPERTY * pProp = pFirstProp; pProp; pProp ? pProp = pProp->pNextSibling : NULL)
  1166. {
  1167. switch(pProp->ulId)
  1168. {
  1169. case JPN_ICHIs:
  1170. {
  1171. SPDBG_ASSERT(pProp->pFirstChild);
  1172. llValue += ComputeNum9999Jp( pProp->pFirstChild );
  1173. }
  1174. break;
  1175. case JPN_MANNs:
  1176. {
  1177. llValue += ComputeNum9999Jp( pProp->pFirstChild ) * 10000;
  1178. }
  1179. break;
  1180. case JPN_OKUs:
  1181. {
  1182. SPDBG_ASSERT(pProp->pFirstChild);
  1183. llValue += ComputeNum9999Jp( pProp->pFirstChild ) * (LONGLONG) 1e8;
  1184. }
  1185. break;
  1186. case JPN_CHOOs:
  1187. {
  1188. SPDBG_ASSERT(pProp->pFirstChild);
  1189. llValue += ComputeNum9999Jp( pProp->pFirstChild ) * (LONGLONG) 1e12;
  1190. }
  1191. break;
  1192. default:
  1193. SPDBG_ASSERT(false);
  1194. }
  1195. }
  1196. if ( fNegative )
  1197. llValue *= (-1);
  1198. *pdblVal = (DOUBLE) llValue;
  1199. DWORD dwDisplayFlags = (fCardinal ? 0 : DF_ORDINAL);
  1200. //Special code to handle minus 0.
  1201. if ((fNegative) && (*pdblVal == 0.0f))
  1202. {
  1203. *pszVal = L'-';
  1204. *(pszVal+1) = 0;
  1205. hr = MakeDisplayNumber( *pdblVal, dwDisplayFlags, 0, 0, pszVal+1, cSize-1);
  1206. }
  1207. else
  1208. {
  1209. hr = MakeDisplayNumber( *pdblVal, dwDisplayFlags, 0, 0, pszVal, cSize);
  1210. }
  1211. return hr;
  1212. }
  1213. HRESULT CSimpleITN::InterpretDecimalJp
  1214. ( const SPPHRASEPROPERTY *pProperties,
  1215. const bool fCardinal,
  1216. DOUBLE *pdblVal,
  1217. WCHAR *pszVal,
  1218. UINT cSize,
  1219. const bool fFinalDisplayFmt,
  1220. BOOL fNegative)
  1221. {
  1222. HRESULT hr = S_OK;
  1223. UINT uiFixedWidth = 0;
  1224. DWORD dwDisplayFlags = 0;
  1225. UINT uiDecimalPlaces = 0;
  1226. BOOL bOverWriteNOTHOUSANDSGROUP = FALSE;
  1227. const SPPHRASEPROPERTY *pPropertiesInteger = NULL;
  1228. const SPPHRASEPROPERTY *pPropertiesPtr;
  1229. if ( !pdblVal || !pszVal || !pProperties)
  1230. {
  1231. return E_POINTER;
  1232. }
  1233. *pszVal = 0;
  1234. pPropertiesPtr = pProperties;
  1235. *pdblVal = 0;
  1236. if (m_nmfmtDefault.LeadingZero)
  1237. {
  1238. dwDisplayFlags |= DF_LEADINGZERO;
  1239. }
  1240. if ( JPN_ICHIs == pPropertiesPtr->ulId )
  1241. {
  1242. pPropertiesInteger = pPropertiesPtr;
  1243. SPDBG_ASSERT(pPropertiesInteger->pFirstChild);
  1244. hr = InterpretIntegerJp( pPropertiesInteger->pFirstChild,
  1245. fCardinal,
  1246. pdblVal,
  1247. pszVal,
  1248. cSize,
  1249. fFinalDisplayFmt,
  1250. FALSE);
  1251. if ( hr == S_OK )
  1252. {
  1253. dwDisplayFlags |= DF_FIXEDWIDTH;
  1254. const WCHAR *pwc;
  1255. for ( uiFixedWidth = 0, pwc = pszVal; *pwc; pwc++ )
  1256. {
  1257. if ( iswdigit( *pwc ) )
  1258. {
  1259. uiFixedWidth++;
  1260. }
  1261. }
  1262. if (!iswdigit( pszVal[wcslen(pszVal) - 1] ))
  1263. {
  1264. //Ends with Mann, Choo,..
  1265. bOverWriteNOTHOUSANDSGROUP = TRUE;
  1266. }
  1267. // This needs to be here in case the user said "zero"
  1268. dwDisplayFlags |= DF_LEADINGZERO;
  1269. // If there is no thousands separator in its string value,
  1270. // then leave out the thousands separator in the result
  1271. if (m_nmfmtDefault.lpThousandSep && (NULL == wcsstr(pszVal, m_nmfmtDefault.lpThousandSep)) && !bOverWriteNOTHOUSANDSGROUP)
  1272. {
  1273. dwDisplayFlags |= DF_NOTHOUSANDSGROUP;
  1274. }
  1275. pPropertiesPtr = pPropertiesPtr->pNextSibling;
  1276. }
  1277. }
  1278. if ( hr == S_OK )
  1279. {
  1280. // Deal with the FP part, which will also have been ITNed correctly
  1281. if ( pPropertiesPtr && (JPN_FP_PART == pPropertiesPtr->ulId) ){
  1282. DOUBLE dblFPPart = 0;
  1283. uiDecimalPlaces = 0;
  1284. for(pPropertiesPtr=pPropertiesPtr->pFirstChild; pPropertiesPtr; pPropertiesPtr=pPropertiesPtr->pNextSibling)
  1285. {
  1286. if ( pPropertiesPtr->ulId == JPN_DIGIT )
  1287. {
  1288. SPDBG_ASSERT( VT_UI4 == pPropertiesPtr->vValue.vt );
  1289. dblFPPart = dblFPPart * 10 + pPropertiesPtr->vValue.ulVal;
  1290. uiDecimalPlaces ++;
  1291. }
  1292. }
  1293. for ( UINT ui=0; ui < uiDecimalPlaces; ui++ )
  1294. {
  1295. dblFPPart /= (DOUBLE) 10;
  1296. }
  1297. *pdblVal += dblFPPart;
  1298. }
  1299. else if ( pPropertiesPtr && (JPN_FP_PART_D == pPropertiesPtr->ulId) ){
  1300. // The user said "point" and one digit
  1301. SPDBG_ASSERT( VT_UI4 == pPropertiesPtr->pFirstChild->vValue.vt );
  1302. uiDecimalPlaces = 1;
  1303. if ( *pdblVal >= 0 )
  1304. {
  1305. *pdblVal += pPropertiesPtr->pFirstChild->vValue.iVal / 10.0;
  1306. }
  1307. else
  1308. {
  1309. *pdblVal -= pPropertiesPtr->pFirstChild->vValue.iVal / 10.0;
  1310. }
  1311. }
  1312. }
  1313. // Handle the negative sign
  1314. if ( (hr == S_OK) && fNegative)
  1315. {
  1316. *pdblVal = -*pdblVal;
  1317. }
  1318. hr = MakeDisplayNumber( *pdblVal, dwDisplayFlags, uiFixedWidth, uiDecimalPlaces, pszVal, cSize);
  1319. return hr;
  1320. }